Moving something on an angle.

My previous question asked was about setting the rotation of an sprite to face the Mouse at all times, with help of a member here I managed to get that workng, now that I have done that, I have created a Bullet class, and great knews, I’ve got everything set up just the way I want it, minus one thing. The movement. I have no idea how to go about moving this properly, I’ve tried a few things, but I can’t get it the move in a straight line.

What I’m Trying to do: Instantiate a sprite to move in a certain direction.

I’m just not sure on what needs to be done for the logic calculations, once again. I’ve done some research and I was brought to a topic on GameDev forums that provided a solution, however it was giving me the same issue that I had to begin with. There is not a “target point” for this object, it’s just supposed to move along an angle.

This angle is the same angle that the sprite it rotated by, fortunately, so getting the angle wasn’t a problem.

But how would I move it?

Currently I’m using a Vector2 for my positioning and just using a standard system for movement.


void moveLeft() { 
    setX(getX() - playerSpeed);
}

^This is to give you an example.

While I was developing in Unity a few years ago, this was called “adding force” to an object, but I’m not exactly sure how it all worked, but it caused it object to move forward constantly.

Suggestions? Psuedo?

Use rise over run. Slope is OP.
((mouse y - player y) / (mouse x - player x))
Bam, you have the slope the bullet needs to move at, now for every 1 x you move, you move slope * 1 y.

Couldn’t you solve this problem using the slope formula. You can pick an arbitrary target point along your projected line. In 3D applications this is done by assuming a vector length of one. It seems to me that if you can determine the rise/slope over one pixel then calculating your vertical position at any point along a horizontal plane/run should be trivial. I’m assuming this is 2D we’re talking about, so feel free to disregard this if that’s not the case. You’d have to account for the edge cases of 0, 45, 90, and 180 degrees.

As for moving forward, determine the direction you’re moving in (-1 left or +1 right), and multiply that value times your speed and add it to your current X position, then determine the Y position based off of the previous formula.

Edit: Doh! Looks like Biznatch beat me to it. :point:

So, from what you told me, this is what I had come up with

		setX(getX() + bulletSpeed);
		setX(slope * ( getY() + bulletSpeed ));

However, this causes no motion.

		setX(getX() + bulletSpeed);
		setX(getY() + (bulletSpeed * slope));

^This one causes motion, however it’s innacurate (Probably because I’m just making it add to the Y Axis and multiplying the speed by the slope(Is what I assume is going on here)

Here’s my Bullet Class

package com.chris.spaceshooter.entities;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;

public class Bullet extends Entity
{
	private Vector2 startPosition, targetPosition, position;
	
	private float rotation;
	
	private Sprite sprite;
	
	private float bulletSpeed = 1.0f;
	
	private float slope;
	
	public Bullet(Texture texture, Vector2 startPosition, float rotation, Vector2 targetPosition)
	{
		this.startPosition = startPosition;
		this.targetPosition = targetPosition;
		this.position = startPosition;
		this.rotation = rotation;
		this.sprite = new Sprite(texture);
		setX(position.x);
		setY(position.y);
		
		this.slope = ((targetPosition.y - startPosition.y) / (targetPosition.x - startPosition.x));
		System.out.println(slope);
	}
	
	public void update() 
	{
		setX(getX() + bulletSpeed);
		setX(slope * ( getY() + bulletSpeed ));
		sprite.setPosition(getX(), getY());
	}
	
	public void draw(SpriteBatch batch, float delta)
	{
		sprite.draw(batch);
	}
	
	private boolean offScreen() 
	{
		if(getX() < 0) return true;
		if(getY() < 0) return true;
		if(getX() > Gdx.graphics.getWidth()) return true;
		if(getY() > Gdx.graphics.getHeight()) return true;
		return false;
	}
	
	public boolean destroy()
	{
		if(offScreen()) return true;
		return false;
	}
	
}

you’re setting X twice, but not ever setting Y. That’d be the inaccuracy.

Shouldn’t that be:


public void update() 
{
        setY(getY() + (slope * ((getX() + bulletSpeed) - getX()));
        setX(getX() + bulletSpeed);
        sprite.setPosition(getX(), getY());
}

Ideally you should have some sort of time delta passed to your update method that would be used in the calculation along with bullet speed to achieve FPS independent movement.

Slope is very bad to use, partly because the slope of a vertical line is infinite. Use vectors:
vel_x = bullet_speedcos(angle)
vel_y = bullet_speed
sin(angle)
(vel means velocity)

Then every frame just update position by the velocity (or if you’re using delta times update position by velocity*delta):
pos_x += vel_x
pos_y += vel_y

This way the bullet travels at the same speed in any direction.

btw the vector [cos(angle),sin(angle)] is a unit vector (length of 1) in the direction of the angle, so it moves the bullet by 1 unit in that direction. Multiplying by bullet_speed makes the bullet move bullet_speed units in that direction, which is what you want. It’s probably worth learning a bit of linear algebra for this stuff.

Learn something new everyday. Totally forgot about slope being bad for cases where you need to cover all the possibilities, because ya know, slope can be undefined after all. Did not know that cosine and sine were so useful for that either.

I created a Vector for this and got it all setup, however it’s still inaccurate.

Here’s the Bullet code

package com.chris.spaceshooter.entities;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;

public class Bullet extends Entity
{
	private Vector2 startPosition, targetPosition, position;
	
	private class Velocity {
		private double x, y;
		
		public Velocity(double x, double y) {
			this.x = x;
			this.y = y;
		}
		
		public double getX() { return x; }
		public double getY() { return y; }
	}
	
	private Velocity velocity;
	private float rotation;
	
	private Sprite sprite;
	
	private float bulletSpeed = 1.0f;
	
	private float slope;
	
	public Bullet(Texture texture, Vector2 startPosition, float rotation, Vector2 targetPosition, float speed)
	{
		this.startPosition = startPosition;
		this.targetPosition = targetPosition;
		this.position = startPosition;
		this.rotation = rotation;
		this.sprite = new Sprite(texture);
		this.bulletSpeed = speed;
		setX(position.x);
		setY(position.y);
		this.velocity = new Velocity(bulletSpeed * Math.cos(rotation), bulletSpeed * Math.sin(rotation));
	}
	
	public void update() 
	{
		setX((float)(getX() + velocity.x));
		setY((float)(getY() + velocity.y));
		
		sprite.setPosition(getX(), getY());
	}
	
	public void draw(SpriteBatch batch, float delta)
	{
		sprite.draw(batch);
	}
	
	private boolean offScreen() 
	{
		if(getX() < 0) return true;
		if(getY() < 0) return true;
		if(getX() > Gdx.graphics.getWidth()) return true;
		if(getY() > Gdx.graphics.getHeight()) return true;
		return false;
	}
	
	public boolean destroy()
	{
		if(offScreen()) return true;
		return false;
	}
	
}

Here’s the code that calls the Bullet

		float xOffset = (Gdx.graphics.getWidth() / 2) - (playerSprite.getX() + (playerSprite.getWidth() / 2));
	    float yOffset =  (Gdx.graphics.getHeight() / 2)  - (playerSprite.getY() + (playerSprite.getHeight() / 2));
	    float mouseX = Gdx.input.getX() + xOffset;
	    float mouseY = (Gdx.graphics.getHeight() - Gdx.input.getY()) + yOffset;
	      
	    float radiansToMouse = (float) Math.atan2(mouseX -  (Gdx.graphics.getWidth() / 2) ,  (Gdx.graphics.getHeight() / 2)  - mouseY);
	    float degreesToMouse = 57.2957795f*radiansToMouse;
	 
	    playerSprite.setRotation(setRotation(degreesToMouse - 180));
	    
		if(keyPressed(Keys.SPACE)) { 
			shootBullet(new Texture("bullet.png"), new Vector2(getX(), getY()), getRotation(), new Vector2(mouseX, mouseY), 1.0f);
		}

It’s really inaccurate, to give you an example of what I mean, here are a few images, with the mouse in the position i clicked, and the direction the bullet is travelling.

Here’s the Runnable Jar File

http://up.ht/JgFNlU

For Math.sin and Math.cos I’m fairly sure the angle needs to be in radians, not degrees. Using radians everywhere would make the code simpler, but if you really don’t like radians I guess you can use degrees, just be careful.

I’m honestly not sure what I’m doing, I’m just trying to figure everything out and learn. I’ll switch it to radians and let you know the outcome.

EDIT: Did this and it seems like it’s off by about 90degrees.

What is in getRotation()?

Get the difference vector.
Normalize it.
Multiply it by the speed.

The result is the movement vector.

No need for all these expensive sine/cosine calls.

getRotation() was replaced with ‘radiansToMouse’

 float radiansToMouse = (float) Math.atan2(mouseX -  (Gdx.graphics.getWidth() / 2) ,  (Gdx.graphics.getHeight() / 2)  - mouseY);

This is a method I grabbed from somewhere for “normalizing”

public static Vector2 normalize(Vector2 vector) 
	{
		float formatted = (float) Math.sqrt(vector.x * vector.x + vector.y * vector.y);
		
		if(formatted > 0.0f)
			formatted = 1.0f/formatted;
		else 
			formatted = 0.0f;
		
		Vector2 out = new Vector2(vector.x * formatted, vector.y * formatted);
		return out;
	}

What would I pass through to it?

the difference of the startPoint and the endPoint?

EDIT: My problem isn’t the speed of movement, it’s getting it to move in the correct direction.
The way you guys are explaining things is helping a bit, however I’m the kind of person that learns from code that I see.
I don’t mind trying to figure it out, but it’s difficult for me when I don’t exactly understand what you guys are telling me I need to do…

((( Basic N-E-S-W movement was soooo much easier, lol. )))

EDIT2: What I tried

 this.normalized = Misc.normalize(new Vector2(startPosition.x - targetPosition.x, startPosition.y - targetPosition.y));

and

		setX((float)(getX() + (normalized.x * bulletSpeed)));
		setY((float)(getY() + (normalized.y * bulletSpeed))); 

but it didn’t work correctly.

I also tried switching the normalize code to this

this.normalized = Misc.normalize(new Vector2(targetPosition.x - startPosition.x, targetPosition.y - startPosition.y ));

but no luck.

Try this:


float x = (float) (Math.sin(rotation * Math.PI / 180)) * speed;
		float y = -(float) (Math.cos(rotation * Math.PI / 180)) * speed;

x is the amount you need to add to x-axis.
y is the amount you need to add to y-axis.
speed is just a multiplier.

Math.atan2 is meant to have y as the first input and x as the second.

This is code that was given to me, which worked, so I left it alone.
I’ll check it out.

Tried this, it moved, but it was always moving in the same direction. (Straight Down, maybe angled to the left about 2-3 degrees)

EDIT: Got it, error on my part. Thanks!

When I try to switch this around, I can’t seem to get the rotation correct.

 float radiansToMouse = (float) Math.atan2((Gdx.graphics.getHeight() / 2)  - mouseY, mouseX -  (Gdx.graphics.getWidth() / 2));
	    float degreesToMouse = 57.2957795f*radiansToMouse;
	 
	    playerSprite.setRotation(setRotation(degreesToMouse - 180));

I’ve been tinkering with the following line

 playerSprite.setRotation(setRotation(degreesToMouse - 180));

but can’t get it correct.