Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sprite tracking touch

Tags:

c++

cocos2d-x

I want to implement tracking (following) touch by a sprite with rotation in cocos2d-x. You can see this effect here: https://www.youtube.com/watch?v=RZouMyyNGG8 (2:10).

Here's my code in touchMove:

_destinationX = touchPoint.x;
_destinationY = touchPoint.y;

_dx = _destinationX - draggedItem->getPositionX();
_dy = _destinationY - draggedItem->getPositionY();

_vx = _dx;
_vy = _dy;

float d = sqrtf((_dx*_dx)+(_dy*_dy));

//nice easing when near destination
if (d < 50 && d > 3){
    _vx *= d / 50.0f;
    _vy *= d / 50.0f;
}
else if(d <= 3){
    _vx = _vy = 0;
}

draggedItem->setPosition(draggedItem->getPosition() + Point(_vx, _vy));

float rad = atan2(_dy, _dx);
float rotateTo = CC_RADIANS_TO_DEGREES(-rad);
if (rotateTo > draggedItem->getRotation() + 180) rotateTo -= 360;
if (rotateTo < draggedItem->getRotation() - 180) rotateTo += 360;

draggedItem->setRotation(rotateTo);

It works, but sprite destination point is on it's center, so if I on touchBegin won't start from it's center it's not looking too well.

So I'm calculating offset in touch begin as well as initial rotation:

offsetPoint = Point(touchPoint.x - draggedItem->getPositionX(), touchPoint.y - draggedItem->getPositionY());
offsetRotation = atan2(offsetPoint.y, offsetPoint.x);

I also added these lines in touch move (on the top):

float alfa = offsetRotation;
float beta = CC_DEGREES_TO_RADIANS(draggedItem->getRotation());
float gamma = alfa + beta;

float radius = offsetPoint.length();
float ax = cosf(gamma) * radius;
float ay = sinf(gamma) * radius;

so destination would be:

_destinationX = touchPoint.x + ax;
_destinationY = touchPoint.y + ay;

But it doesn't work, where's an issue? Sprite is jumping all around.

like image 314
Makalele Avatar asked Oct 30 '22 23:10

Makalele


1 Answers

As I'm not familiar at all with Obj-C or C++, I'm gonna give you the answer in Swift. Then, you'll be able to either insert it into your project or 'translate' to Obj-C/C++. Anyway:

Inside the file that represents your gameplay scene, declare a variable that keeps track of whether the user is currently touching the screen or not. I'll also assume the sprite you want to follow the touch is represented by some variable (named 'sprite' here):

var touchingScreen:Bool = false // needs 'false' as initial value.
weak var sprite:CCSprite!; // represents a connection to the sprite.

Then, you'll also want a variable that represents the difference between the value of the point currently being touched and the point your sprite is located in the x and y axises:

var diffTouchSpriteX:CGFloat!; // not necessary to initialize it with any default value.
var diffTouchSpriteY:CGFloat!; // same.

The next step is to update these two variables' values when necessary. Lets create a method for that:

func updateDiff(touchX: CGFloat, touchY: CGFloat) {
  self.diffTouchSpriteX = touchX - self.sprite.position.x;
  self.diffTouchSpriteY = touchY - self.sprite.position.y;
}

Now it's time to make use of the touch methods provided for handling the touch input at specific moments. Let's assign a value to diffTouchSpriteX and diffTouchSpriteY variables and set touchingScreen to true when the user touches the screen, update diffTouchSpriteX and diffTouchSpriteY values when the user moves its finger on the screen and finally set touchingScreen to false once the touch is interrupted:

override func touchBegan(touch: CCTouch!, withEvent event: CCTouchEvent!) {
  self.updateDiff(touch.locationInWorld().x, touch.locationInWorld().y);
  self.touchingScreen = true;
}

override func touchMoved(touch: CCTouch!, withEvent event: CCTouchEvent!) {
  self.updateDiff(touch.locationInWorld().x, touch.locationInWorld().y);
}

override func touchEnded(touch: CCTouch!, withEvent event: CCTouchEvent!) {
  self.touchingScreen = false;
}

override func touchCancelled(touch: CCTouch!, withEvent event: CCTouchEvent!) {
  self.touchingScreen = false;
}

Finally, the last step. Inside the Cocos2d method fixedUpdate(), add a conditional to move the character if the screen is being currently touched:

override func fixedUpdate(delta: CCTime) {
  if (self.touchingScreen) {
    self.sprite.runAction(CCActionMoveBy(duration: 1/ 60, position: CGPoint(x: self.diffTouchSpriteX / 60, y: self.diffTouchSpriteY / 60)));
  }
}

The fixedUpdate() cocos2d method runs at a constant rate (1 time each second, if I remember well). The runAction() method here will update the sprite position by adding 'x' to its 'x' value of its current position and 'y' to its 'y' value of its current position. So, at this rate it would take one second for the sprite to reach the current touch location, but this of course is something you can easily manipulate.

like image 73
Otávio Monteagudo Avatar answered Nov 15 '22 03:11

Otávio Monteagudo