Всем добро. Сегодня расскажу как сделать джойстик на cocos2d 2.0b.

И с чего состоит джостик:

  1. Окружность – для ограничение движения джойстика.
  2. Контроллер – то что будем двигать в окружности.

План действия:

  1. Проверить прикоснулись ли к джойстику.
  2. Следить за движением пальца и двигать контролер.
  3. Если палец  вышел за окружность решить что делать.
  4. Если палец убран вернуть контролер в центр.

Ну что ? Поехали!

#import "CCLayer.h"
#import "CCSprite.h"

@protocol GGJoystickDelegate -(void)joystickControlBegan:(CGPoint)Point; -(void)joystickControlMoved:(CGPoint)Point; -(void)joystickControlEnded:(CGPoint)Point; -(CGFloat)joystickControlSpeedMultiplier; -(void)joystickControlDidUpdate:(CGFloat)xSpeedRatio toYSpeedRatio:(CGFloat)ySpeedRatio; @end

@interface GGJoystick : CCSprite {
CGFloat _radius;
CGFloat _speedMultiplier;
BOOL _isJoystickEnabled;
BOOL _isBlock;
CCSprite *controller;
CGPoint actualPoint;
id _delegate;
int fx;
int fy;
}

-(id)initWithFile:(NSString *)filename controller:(CCSprite*)controllerS; @property (nonatomic,readwrite,retain) id delegate; @property (nonatomic,readwrite) BOOL isBlock; @property (nonatomic,readwrite) CGFloat radius; @property (nonatomic,readwrite) CGFloat speedMultiplier; @property (nonatomic,readonly) BOOL isJoystickEnabled; @end

Из чего состоит интерфейс:

  1. CGFloat _radius; -радиус окружности.
  2. BOOL _isJoystickEnabled;  — активирован ли джостик.
  3. CCSprite *controller; контроллер и в Африке контроллер;
  4.  id<GGJoystickDelegate> _delegate; вкусный делегат.
  5. Int fx,fy –коэффицент четвертей окружностей
  6. CGFloat speedMultiplier – множитель скорости
  7. CGPoint actualPoint — запоминаем точку при прикосновение относительно оси координат джойстика.

Делегат GGJoystickDelegate:

  1. -(void)joystickControlBegan:(CGPoint)Point; — когда контролер стартует.
  2. -(void)joystickControlMoved:(CGPoint)Point; — когда контролер двигается.
  3. -(void)joystickControlEnded:(CGPoint)Point;  -когда пальчик отжали от контролера.
  4. -(void)joystickControlDidUpdate:(CGFloat)xSpeedRatio toYSpeedRatio:(CGFloat)ySpeedRatio; дает коээфиценты для прироста кординат у обьекта или обьектов( допусти для управление главного персонажа (пвсевдо код) hero.x + xSpeedRatio , hero.y +ySpeedRatio и т  д.
  5. -(CGFloat)joystickControlSpeedMultiplier; — вкусный метод вызращаем множитель скорости , для чего нужно? ну… думайте мне нужен)

Реализация:

Разжевываем тут!

Метод: 

-(id)initWithFile:(NSString *)filename controller:(CCSprite*)controllerS

Инициализирует спрайт джостика ,а также передает спрайт контролера.

Метод: 

-(CGFloat)distanceBetweenTwoPoints:(CGPoint)point1 pointTwo:(CGPoint)point2

Узнаем расстояние между двумя точками по теореме Пифагора.

формула

Метод:

-(CGFloat)slopeBetweenTwoPoints:(CGPoint)point1 pointTwo:(CGPoint)point2

Узнаем угловой коэффициент прямой, проходящей через две данные точки.

Угловой коэффициент

Метод: 

-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

Если джойстик активен выходим из обработки прикосновения

if (_isJoystickEnabled) {
return;
}

Находи точку со прикосновением экрана.

UITouch *touch = [touches anyObject];

Получем координаты прикосновение экрана

CGPoint location = [touch locationInView:touch.view];

Переводим координаты с UI на GL.

location =[[CCDirector sharedDirector]  convertToGL:location];

Находим дистанцию между двумя точками при помощи теоремы Пифагора . 1 точка  начал координат от джойстика (0.0) до точки соприкосновения.

CGFloat distance =[self distanceBetweenTwoPoints:self.position pointTwo:location];

Если найденная дистанция меньше или равна радиуса  окружности тогда выполняем код ниже.

if (distance<=self.radius) {
Активируем джойстик.
_isJoystickEnabled = true;

Находим актуальную точку от оси координат джойстика. Что это значит?

У нас две оси координат 1) Экрана 2) это центра спрайта джойстика) При прикосновения к экрану нам дает координаты относительно оси экрана, чтоб высчитать относительно джойстика, нам нужно точки прикосновения относительно оси координат экрана вычесть точки спрайта джойстика относительно оси координат экрана.

actualPoint = CGPointMake(location.x-self.position.x, location.y -self.position.y);

Так как точки спрайта джойстика это его половинки, то есть начала координат начинается в центре спрайта на нужно прибавить к найденной точки еще половинку спрайта джойстика , тогда мы найдем нужную точку.

CGPoint point = CGPointMake(self.boundingBox.size.width/2 +actualPoint.x, self.boundingBox.size.height/2+actualPoint.y);

Вызываем делегат и передает точку .(зачем не знаю, пригодиться).

if ([self.delegate respondsToSelector:@selector(joystickControlBegan:)]) {
[self.delegate joystickControlBegan:point];
}

Меняем положение контролера.

[controller setPosition:point];

Создаем цикл который будет обрабатывать движения контролера и давать коэффициенты передвижения.

[[[CCDirector sharedDirector]scheduler]scheduleSelector:@selector(update1:) forTarget:self interval:0 paused:false];
}

Метод: 

-(void)ccTouchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

Находит точку со прикосновением экрана.

UITouch *touch = [touches anyObject];

Получаем координаты прикосновение экрана

CGPoint location = [touch locationInView:touch.view];

Переводим координаты с UI на GL.

location =[[CCDirector sharedDirector]  convertToGL:location];

Находим дистанцию между двумя точками при помощи теоремы Пифагора . 1 точка  начал координат от джойстика (0.0) до точки соприкосновения.

CGFloat distance =[self distanceBetweenTwoPoints:self.position pointTwo:location];

Сразу же получаем актуальные координаты прикосновения относительно оси джойстика

actualPoint= CGPointMake(location.x-self.position.x, location.y -self.position.y);

Если джойстик был активирован идем дальше

if (self.isJoystickEnabled) { 

Чистая и вкусная точка.

CGPoint point;

Находим в какой четверти окружности находимся

  • I) x+ y+
  • II) x- y+
  • III) x- y-
  • IV) x+ y —

Закономерность  если x <=0 , то x- ,если y <= 0 ,то y-fx и fy  —  это коэффиценты в какой четверти будут х и y на окружности. Помните тригонометрию ?

if (actualPoint.x <=0) {
fx =-1;
}else{
fx =1;
}
if (actualPoint.y <=0) {
fy = -1;
}else{
fy = 1;
}

Если найденная дистанция меньше или равна радиуса  окружности тогда выполняем код ниже.

if (distance<=self.radius) {

Находим точку я вам уже говорил что это за точка.Не помните ? Нужно читать внимательно!

point = CGPointMake(self.boundingBox.size.width/2 +actualPoint.x, self.boundingBox.size.height/2+actualPoint.y);

Передвигаем контролер!

[controller setPosition:point];
}else{

Здесь читать внимательно!

Если палец был не убран а передвижения не прекращаются и палец выпал(вышел) за приделы радиуса , то тогда мы рассчитываем чтоб контролер следил за пальцем.

Узнаем угловой коэффициент прямой, проходящей через две данные точки. 1 точка начала координат относительно джойстика , вторая точка точка прикосновения относительно оси координат джойстика.

CGFloat slope = [self slopeBetweenTwoPoints:CGPointMake(0, 0) pointTwo:actualPoint];

Если угол на клона равен ±∞ ,то тогда точка  будет равна (0,R) , где R — радиус

Почему так происходит? Честно не помню . Единственное что приходит в голову когда прямая не под наклоном .

if (slope == (-INFINITY || INFINITY)) {
point = CGPointMake(0, _radius);
}else{

Иначе мы выключаем силу тьмы и вспоминаем тригонометрию.

  • Уравнение прямой с угловым коэффициентом имеет вид y = kx+b, где k — угловой коэффициент прямой. Этот коэффициент и определяет угол наклона прямой. Этот коэффициент равен k = tgφ, где φ — угол между лучом прямой, расположенным выше оси абцисс и положительным направлением оси абцисс. Это и есть угол наклона прямой. Он равен φ = arctg(k).
  • Абсцисса X, Ордината Y,R — радиус,Уголь альфа  — это угловой коэффицент ,у нас slope;

cos

Нам нужно узнать точку абсциссу X , мы знаем угловой коэффицент и радиус . А это значит x =  cos(Å)*R; Следовательно x = cos(arctg(Å))*R;

sin

Тоже самое для любимой ординаты   sin(альфа)  =Y/R  Y = sin(arctg(альфа)) *R;

Не забываем нам нужен модуль X и Y для того чтоб в каждой части окружности делал свой поворот , тоесть направление против часовой стрелки считается положительным, по часовой стрелке отрицательным.

CGFloat newX = cosf(atanf(slope))*_radius;
CGFloat newY = sinf(atanf(slope))*_radius;

Создаем точку

point =CGPointMake(ABS(newX), ABS(newY));
}

Мы  умножаем на коэффициент четверти окружности .

point =CGPointMake(point.x*fx, point.y*fy);

Вспоминаем то что нам надо добавить еще половинку спрайта джойстика.

point = CGPointMake(self.boundingBox.size.width/2 +point.x,self.boundingBox.size.height/2+point.y);

Перемещаем контролер.

[controller setPosition:point];
}
if ([self.delegate respondsToSelector:@selector(joystickControlMoved:)]) {
[self.delegate joystickControlMoved:point];
}
}

Метод: 

-(void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

Здесь вызываем метод 

[self ccTouchesCancelled:touches withEvent:event];

Мой совет лучше всего завершения прикосновения реализовать в ccTouchesCancelled , а в ccTouchesEnded вызывать ccTouchesCancelled.

Так надежнее ,если что нибудь случиться вызовется ccTouchesCancelled и корректно сбросит прикосновение.

Метод:

-(void)ccTouchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
if (self.isJoystickEnabled) {

Выключаем джойстик.

_isJoystickEnabled = false;

Вызываем метод делегата

if ([self.delegate respondsToSelector:@selector(joystickControlEnded:)]) {
[self.delegate joystickControlEnded:controller.position];
}

Меняем позицию контролера на середину спрайта джойстика.

[controller setPosition:CGPointMake(self.boundingBox.size.width/2, self.boundingBox.size.height/2)];

Выключаем цикл который будет обрабатывать движения контролера и давать коэффициенты передвижения.

[[[CCDirector sharedDirector]scheduler]unscheduleSelector:@selector(update1:) forTarget:self];
}
}

Метод:

-(void)onEnter
[super onEnter];

Включаем обработчик прикосновения.

CCTouchDispatcher *touchDis= [[CCDirectorIOS sharedDirector] touchDispatcher];
[touchDis addStandardDelegate:self priority:0];

Метод:

-(void)onExit
[super onExit];

Выключаем обработчик прикосновения.

CCTouchDispatcher *touchDis= [[CCDirectorIOS sharedDirector] touchDispatcher];
[touchDis removeDelegate:self];

Метод:

-(void)dealloc

[controller release]; [self.delegate release]; [super dealloc];

Я думаю тут все понятно.

Метод:

-(void)update1:(ccTime)time{

Реализация проста здесь вызывается метод делегата и возращает множитель скорости.

if ([self.delegate respondsToSelector:@selector(joystickControlSpeedMultiplier)]) {
[self setSpeedMultiplier:[self.delegate joystickControlSpeedMultiplier]];
}

Находим коэффициент прироста координат для изменение положения объекта Х и Y .

Косинусом угла α называется отношение ОА/OB (отношение прилежащего катета к гипотенузе).

cos Тогда получаем cos * умножаем на множитель скорости все это в модуле и умножаем на коэффициент четверти окружности .

|X/R*speedMultiplier| *fx ;

float xSpeedRatio = ABS(actualPoint.x /_radius*_speedMultiplier)*fx;

sin

float ySpeedRatio = ABS(actualPoint.y/_radius*_speedMultiplier)*fy;

Здесь вызываем делегат и передаем коэффициент прироста координат.

if ([self.delegate respondsToSelector:@selector(joystickControlDidUpdate:toYSpeedRatio:)]) {
[self.delegate joystickControlDidUpdate:xSpeedRatio toYSpeedRatio:ySpeedRatio];
}

Ну что думаю на этом все. Это моя 1 статья, надеюсь не последняя и не худшая. Всем удачи , и спасибо .

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *