Jake B
Jake B

Reputation: 35

Offset sprite along a path vector in LibGDX

I currently have a sprite following a path...all is working well from a steering perspective, however I am trying to make it so the center of the sprite tracks along the path, rather than the corner (0,0) tracing along the path. Essentially, I would like the center of the fish to follow the line.

Below is an image of what I have implemented, and what I would like to achieve.

enter image description here

The core implementation of this mechanic lies within my update() method; as follows;

private void update(float deltaTime) {
        float angle = (float) Math.atan2(path.get(waypoint).y - getY(),  path.get(waypoint).x - getX());
        velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);

        velocity_normal = new Vector2(-velocity.y, velocity.x).nor();

        setPosition(
                getX() + (velocity.x * deltaTime),
                getY() + (velocity.y * deltaTime)
        );
        setRotation(angle * MathUtils.radiansToDegrees);

        if(isWayPointReached()){
            setPosition(path.get(waypoint).x, path.get(waypoint).y);
            if(waypoint + 1 >= path.size){
                waypoint = 0;
            } else {
                waypoint++;
            }
        }
    }

In particular the setPosition call. My initial thoughts were to calculate the normal vector to the velocity vector, normalize, and multiply the x and y components respectively by the fish height... to my mind this would offset the fish by its height (150px). The code attempted is as follows;

velocity_normal = new Vector2(-velocity.y, velocity.x).nor();

setPosition(
                getX() + (velocity.x * deltaTime) + velocity_normal.x * getHeight() * deltaTime,
                getY() + (velocity.y * deltaTime) + velocity_normal.y * getHeight() * deltaTime
        );

The results in some odd behavior, the fish gets progressively further from the line, it seems the vector is getting compounded and added each frame.

I have also tried to update the normal vector once each way-point has been reached, however this does not work either.

I think the above logic is correct, however have I made a fundamental error in my vector maths?

Your assistance would be greatly appreciated.

EDIT:

Added to constructor:

setPosition(
                path.get(waypoint).x  - 0.5f * getWidth() ,
                path.get(waypoint).y - 0.5f * getHeight()
        );

Amended update() method;

private void update(float deltaTime) {
        float angle = (float) Math.atan2(path.get(waypoint).y - getY(),  path.get(waypoint).x - getX());
        velocity.set((float) Math.cos(angle) * speed, (float) Math.sin(angle) * speed);


        Vector2 velocity_normal = new Vector2();
        velocity_normal.set(velocity).nor().scl( speed * deltaTime ); // multiply the speed to scale the unit vector up

        translate( velocity_normal.x, velocity_normal.y );




        setRotation(angle * MathUtils.radiansToDegrees);

        if(isWayPointReached()){
            setPosition(path.get(waypoint).x, path.get(waypoint).y);
            if(waypoint + 1 >= path.size){
                waypoint = 0;
            } else {
                waypoint++;
            }
        }
    }

Note the omission of the setPosition call, and the replacement with;

Vector2 velocity_normal = new Vector2();
velocity_normal.set(velocity).nor().scl( speed * deltaTime );        
translate( velocity_normal.x, velocity_normal.y );

How would I influence the pointA / pointB as mentioned below?

Thanks.

Upvotes: 0

Views: 373

Answers (2)

Tejay
Tejay

Reputation: 236

The Sprite position is from the left bottom corner and the origin (where the sprite rotates around) is already set to the center of the sprite. So only the local offset is wrong. You have to substract half the size from the position and then the sprite can move relatively from that offset.

Where you set the sprite:

setPosition(
        path.get(waypoint).x - 0.5f * getWidth(),
        path.get(waypoint).y - 0.5f * getHeight()
);

In the update method. Because you are adding the velocity every frame you can translate the sprite.

void update(float deltaTime){

    // directional global vector
    Vector2 velocity = tmp.set(path.get(waypoint)).sub(path.get(waypoint - 1)).nor().scl(speed * deltaTime);
    // reference angle is relative to the right vector(1, 0)
    float angle = velocity.angle();

    setRotation(angle);
    translate(velocity.x, velocity.y);

    if (isWayPointReached()){
        setPosition(
                path.get(waypoint).x - 0.5f * getWidth(),
                path.get(waypoint).y - 0.5f * getHeight()
        );
        if(waypoint + 1 >= path.size){
            waypoint = 1;
        } else {
            waypoint++;
        }
    }
}

Upvotes: 1

MilanG
MilanG

Reputation: 7124

There is setCenter() method in Sprite class:

https://libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/graphics/g2d/Sprite.html#setCenter-float-float-

Try setting center like that instead of calculating it additionally.

Upvotes: 0

Related Questions