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.
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
anddiffTouchSpriteY
variables and settouchingScreen
totrue
when the user touches the screen, updatediffTouchSpriteX
anddiffTouchSpriteY
values when the user moves its finger on the screen and finally settouchingScreen
tofalse
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). TherunAction()
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With