Turn the arrow while it is in motion on some path

I am defining my random curve using cardinal spline or catmull roll… Now my problem is I want to keep turning my arrow sprite while it is moving on that path…

This body is moving on a path(not straight) and on collision with some body I’ll invoke some event…(This description is not required but just to give you an idea of what I am doing).

For eg: easy case would be an arrow moving on parabola… but this would be simple as I know the equation of parabola… Isn’t it !!..
I want to apply it on some more complex path like path defined in cardinal spline action or some sin curve, where I could like to move my arrow on sin curve while turning it on the path…

You can explain using simple sprite/ physics sprite(created using inbuilt physics or box2d)

Any ideas?

Thanks :wink:

Just idea…

How about to save point of previous frame.
And on current frame, you can get previous & current point.
Then you can easily get the angle of two points.

@hzlov

Haha, angle is all what I want…

How can I find angle by just 1 vector which is joining my current and previous point…
See, I could have I find this angle if there was some center point, which in case my arrow would be moving on a circle…
I would have calculated normal to the previous position and so on…

Are you getting whats the problem in what you suggested :stuck_out_tongue:

I don’t get it why you can’t find angle with 1 vector.

Find angle between two points.

https://www.google.com/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&q=get%20angle%20between%20two%20points

I meant that at what angle to rotate the arrow, that is why I can’t find that angle…
What you’re saying is the inclination of the vector which is also an angle but this angle is not same as that angle which I need to rotate the arrow…
In fact, what you’re saying will giving me inclination with x axis(horizontal axis). So, what I will do with this angle…
I want an angle at which I can rotate my arrow so that it always head towards the path it is moving…

Treat previous point as (0,0).
Let’s assume previous point as (100,100) and current point as (150,200).
And treat previous point as (0,0).
then you can set current point as (50,100).
This vector (0,0)->(50,100) has angle and distance.
You can get angle to rotate with Point class provided by cocos2d-x team.

Oh I see… :smile:
Let me check and get back…

Hi…

Here is the reason why it won’t work :smiley:

You’re saying me to find the angle of the vector joining the current and next position right?
According to the original ques. that I asked I won’t be knowing my next position. I mean, when you give, suppose 4 points, in the catmull roll/ cardinal spline action then those 4 points doesnot make rectangle, infact it is some figure that is guided by tension factor between the points… So, I don’t know the next position :smiley:

@hzlov
Your Solution only works when we know the next point… But that is not happening with my case…

Does anybody know the solution !

Thanks

You don’t need to know the next point, you need to know the current point and the previous point.

Hi… what I could understand is… the current point you are talking about is the same as what I am talking about as next point…

Your current point is a point on which the arrow will be setPosition in just the next frame right!!

What if I say I don’t know the that current position…
I mean…see my original question in the first post…
If i am using catmull roll or cardinal spline then i give certain sets of points and then it automatically creates the path…
Now, this is the situation for you then what are you gonna do to change the angle of arrow when you don’t know the points explicitly…

Are you getting the scenario…

Or if not… try to think the solution for suppose… I want to move my rocket in sin curve…
So, since there isn’t any default curve for this… So, I need to manually give points… Suppose 8 points for one-half sin wave.
For, 0 deg, 30 deg,60 deg,90,120,150,180… Middle points will be connected automatically if I am using cardinal spline for it… So, for horizontal sin curve, i can calculate my Vec2-x and y according to these angles and give the set of all those points to my cardinal spline…

So the final motion path would be similar to sin curve like and I am not bothering about the exact sin curve…

So, assume whatever size of the arrow as long as we can see the angle change as it moves along the path…
Now, what to be done…

Let’s say it is in a sin curve, moving from left to right.

At any point X,Y on the curve, the slope of the curve is Cos(x)

so the angle at that point is ATan(Cos(x))

e.g. at position on the sine 90, the angle is ATan(Cos(90)) = ATan(0) = 0 degrees so your ship will face left-right (0 degrees rotation)

At position on the sine 180, the angle is ATan(Cos(180)) = ATan(-1) = -45 degrees so your ship will be facing down to the right

That is fine… I can calculate for those points that I know …
but I don’t know the value ‘x’ to calculated that angle FOR all the points on the path…!!!
This is the main motive of creating this post…

Do you know cardinal spline or catmull roll…?

Just see it under the test… I think in the cpp tests they’ve given this cardinal spline action only 4 or 5 points but it creates the whole path… And try to understand that it has created the WHOLE PATH… so I definitely know those 4 or 5 points I’ve passed but what about the points on the rest of the path!!!

I guess you want to know what angle it should be at any moment on the path by mathematical way.

What I suggested before, and what @Maxxx Max said is I guess…
how about create a visible node class extends Node or Sprite?
Then use scheduleUpdate to catch moving point at every frame, and calculate angle with previous point & current point.

Isn’t that enough?

This is kind of giving me some idea…
You mean creating a dummy node which goes faster than my arrow so that what is happening in the current frame of that node should happen in the next frame of my arrow… and so I can use the current position of the arrow and current position of the node(which is actually gonna be next position of arrow) and then subtracting those 2 vectors and then use that angle to turn the arrow…

If this is what you are suggesting, then theoritically it it seeming to be possible but I think I need to be careful about synchronizing that node and arrow in a way that node is always a frame or two ahead of arrow and not more…

I think we are now on the same idea finally. :slight_smile:

I don’t think that was what was suggested.
In your node that is the arrow, it must be physically positioned and drawn every frame

So, in the update method of the node, you can capture its current position
next frame store its previous position and get its current positions
Then use the two to calculate the angle.

I didn’t realise from your explanation that you were using actions to move your sprite - the way I would personally approach the problem is to calculate any path myself - the various curves are well documented - so I have a list of points to position my sprite, then I can know the angle simply and in advance.

That said, extending the sprite class to add ‘point along path’ functionality would be quite useful, I think.

You will probably need to use some ‘damping’ to avoid the ship turning too quickly and unrealistically (e.g. allow only rotation of x degrees every dt seconds, so you calculate a ‘desired angle’ , then rotate towards that angle only up to x degrees.

There is irony in the lines…

hahaha :smiley:
Nevermind…

Yeah, this is the usual way when we know the points… But as I stated I don’t know the points… and you got my reason correctly
of asking this doubt.

@Maxxx

Can you give me link of

I haven’t come across any such curve which are pre-defined in cocos2d-x…
By this hope you’re not talking about simple maths functions like sin or tan…

I’ve given this thing in wish list that if I want to make move a body on a certain path like sin curve…
Then I can give some parameters inside that functions that decides it starting, ending points, axis elevation, Height of highest point on sin curve from the axis… so that moving a sprite/node on a well defined path becomes easy…
Anyways… its not in cocos2d-x as of now…

Yes, problem is highly simplified if I already know the points…
but your path can never be smooth enough… I mean it will be kind of joining dots to dots and hence giving multiple straight line paths… Isn’t it… But I wanted something coombination of straight and curve or simple curve would do …(NOT CIRCLE :smiley: BECAUSE ITS EASY AND STRAIGHT FORWARD)

I didn’t understand this thing… If I were to implement your way of knowing the points prehand… Then I would have stored all the points in the array and then iterate accordingly…
I think you’re saying the same about having an array but for each sprite which has different kind of curve on which they want to move!!

yeah, I think so… but first I should be able to move it along some random curve…

I DIDN’T GOT THE SATISFACTORY SOLUTION… because I think your suggestion will make my arrow move on multiples straight lines which are connected end to end and not on curvilinear kind of a path and not rectilinear

Laugh - yes!
There seems to be a lot of misunderstanding
So I wrote the solution for you.

Here’s the sprite class

//
//  mySprite.h
//  MultiRes
//
//  Created by Maxxx on 4/12/2014.
//
//

#ifndef __MultiRes__mySprite__
#define __MultiRes__mySprite__
#include "cocos2d.h"

USING_NS_CC;

class MySprite : public Sprite
{
private:
    Vec2 lastPos;
    
    float CalculateAngleBetweenPoints(Vec2 p1, Vec2 p2);

  
public:
    CREATE_FUNC(MySprite)
    static MySprite* create(const std::string& filename);
    MySprite();
    ~MySprite();
    
    
    virtual void update(float dt) override;

    
};




#endif /* defined(__MultiRes__mySprite__) */

//
//  mySprite.cpp
//  MultiRes
//
//  Created by Maxxx on 4/12/2014.
//
//

#include "mySprite.h"
#include "math.h"



MySprite::MySprite()
{
    lastPos = Vec2(-1,-1); // Initialise as something silly
   	this->scheduleUpdate();
}
MySprite::~MySprite()
{}

MySprite* MySprite::create(const std::string& filename)
{
    
    MySprite* sprite = new MySprite();
    
    if (sprite->initWithFile(filename))
    {
        sprite->autorelease();
        
        return sprite;
    }
    
    CC_SAFE_DELETE(sprite);
    return NULL;
}


void MySprite::update(float dt)
{
    if (lastPos != Vec2(-1,-1))
    {
        this->setRotation(CalculateAngleBetweenPoints(lastPos, getPosition()));
    }
    lastPos = getPosition();
}

float MySprite::CalculateAngleBetweenPoints(Vec2 p1, Vec2 p2)
{
    float xDiff = p2.x - p1.x;
    float yDiff = p2.y - p1.y;
    return -atan2(yDiff, xDiff) * (180 / M_PI);
}

Then, somewhere in your prog…

    auto sprite = MySprite::create("CloseNormal.png");
    sprite->setAnchorPoint(Vec2(0.5,0.5));
    sprite->setPosition(Vec2(visibleSize.width/2 ,visibleSize.height/2));
    this->addChild(sprite, 0);
    
    
    
    ccBezierConfig bezier;
    bezier.controlPoint_1 = Vec2(0, 380);
    bezier.controlPoint_2 = Vec2(300, 380);
    bezier.endPosition = Vec2(300,100);
    
    ActionInterval* bezierForward = CCBezierBy::create(3, bezier);
    ActionInterval* bezierBack = bezierForward->reverse();
    Action* rep = CCRepeatForever::create(CCSequence::create( bezierForward, bezierBack, NULL));
    
    sprite->runAction(rep);

This runs the sprite over a bezier and back, pointing along the path at all times.

Doing it like this you effectively have a sprite that always faces where it is going.

You can obviously improve it (as I mentioned before, a maximum rotation angle will avoid some jerkiness, for example) but hopefully you see the idea?

Hmm this is what I was actually referring when you told your solution theoretically in your last post…
I got your idea theoretically and by the code.
Let me see if it works… Tweaking to make it perfect I can do later…

I’ll definitely try this…
But still the same things… the

in

is the position that is player is gonna be in the next frame?
How is it… I mean I am doubting because the update for layer(scene/game) is running independently of update of sprite.

So, this getPosition() will always get me the current position… I understand that it would be different than the lastPos… but wait… I think I got what is the problem … I think I got my doubt resolved… I think I will get the correct rotation angle because those portions of code will be executed nearly on the same frame…

So, do I even need to create separate update method for sprite!! bcoz as I just stated “nearly on the same frame…”
but it won’t be on the same frame…
I think I can put that portion of code in the update method of layer(scene/game)…

Let me try your solution… :smiley:

Thanks