Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (537)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  Moving something on an angle.  (Read 1194 times)
0 Members and 1 Guest are viewing this topic.
Offline CTucker1327
« Posted 2013-12-12 03:32:03 »

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.

1  
2  
3  
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?
Offline bilznatch

Senior Member


Medals: 8
Projects: 2
Exp: 1 year


I'm bad, I'm bad, I'm really... really bad T_T


« Reply #1 - Posted 2013-12-12 04:23:38 »

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.
Offline CodeHead

JGO Coder


Medals: 40


From rags to riches...to rags.


« Reply #2 - Posted 2013-12-12 04:26:35 »

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. Pointing

Arthur: Are all men from the future loud-mouthed braggarts?
Ash: Nope. Just me baby...Just me.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline CTucker1327
« Reply #3 - Posted 2013-12-12 04:52:48 »

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.

So, from what you told me, this is what I had come up with
1  
2  
      setX(getX() + bulletSpeed);
      setX(slope * ( getY() + bulletSpeed ));


However, this causes no motion.

1  
2  
      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

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
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;
   }
   
}



Offline bilznatch

Senior Member


Medals: 8
Projects: 2
Exp: 1 year


I'm bad, I'm bad, I'm really... really bad T_T


« Reply #4 - Posted 2013-12-12 05:12:21 »

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

JGO Coder


Medals: 40


From rags to riches...to rags.


« Reply #5 - Posted 2013-12-12 05:21:36 »

Shouldn't that be:
1  
2  
3  
4  
5  
6  
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.

Arthur: Are all men from the future loud-mouthed braggarts?
Ash: Nope. Just me baby...Just me.
Offline kramin42
« Reply #6 - Posted 2013-12-12 05:22:31 »

Slope is very bad to use, partly because the slope of a vertical line is infinite. Use vectors:
vel_x = bullet_speed*cos(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.

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Offline bilznatch

Senior Member


Medals: 8
Projects: 2
Exp: 1 year


I'm bad, I'm bad, I'm really... really bad T_T


« Reply #7 - Posted 2013-12-12 05:33:32 »

Snip

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.
Offline CTucker1327
« Reply #8 - Posted 2013-12-12 07:02:15 »

Slope is very bad to use, partly because the slope of a vertical line is infinite. Use vectors:
vel_x = bullet_speed*cos(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.

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

Here's the Bullet code

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
55  
56  
57  
58  
59  
60  
61  
62  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
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

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
      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


Offline kramin42
« Reply #9 - Posted 2013-12-12 07:26:11 »

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.

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline CTucker1327
« Reply #10 - Posted 2013-12-12 07:39:41 »

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. 
Offline kramin42
« Reply #11 - Posted 2013-12-12 07:46:53 »

What is in getRotation()?

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Offline HeroesGraveDev

JGO Kernel


Medals: 239
Projects: 11
Exp: 2 years


┬─┬ノ(ಠ_ಠノ)(╯°□°)╯︵ ┻━┻


« Reply #12 - Posted 2013-12-12 08:52:01 »

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.

Offline CTucker1327
« Reply #13 - Posted 2013-12-12 09:03:16 »

What is in getRotation()?

getRotation() was replaced with 'radiansToMouse'

1  
 float radiansToMouse = (float) Math.atan2(mouseX -  (Gdx.graphics.getWidth() / 2) ,  (Gdx.graphics.getHeight() / 2)  - mouseY);
Offline CTucker1327
« Reply #14 - Posted 2013-12-12 09:04:58 »

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.

This is a method I grabbed from somewhere for "normalizing"

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
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

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


and

1  
2  
      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

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


but no luck.
Online trollwarrior1
« Reply #15 - Posted 2013-12-12 09:30:46 »

Try this:
1  
2  
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.
Offline kramin42
« Reply #16 - Posted 2013-12-12 09:47:21 »

What is in getRotation()?

getRotation() was replaced with 'radiansToMouse'

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


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

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Offline CTucker1327
« Reply #17 - Posted 2013-12-12 11:00:12 »

What is in getRotation()?

getRotation() was replaced with 'radiansToMouse'

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


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.
Offline CTucker1327
« Reply #18 - Posted 2013-12-12 11:02:47 »

Try this:
1  
2  
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.

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!
Offline CTucker1327
« Reply #19 - Posted 2013-12-12 11:12:18 »

What is in getRotation()?

getRotation() was replaced with 'radiansToMouse'

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


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


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

1  
2  
3  
4  
 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

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


but can't get it correct.
Offline kramin42
« Reply #20 - Posted 2013-12-12 21:12:27 »

I think the real problem is that you're not keeping a consistent definition of an angle. The usual definition is that the +x axis is 0 degrees and the +y axis is 90 degrees. Math.atan2(y,x) will give you an angle according to this definition, so you need to make sure all of your code is consistent with this.

You have the y input in atan2 negated, it should be:
1  
float radiansToMouse = (float) Math.atan2(mouseY - (Gdx.graphics.getHeight() / 2), mouseX -  (Gdx.graphics.getWidth() / 2));


I'm guessing the player sprite image is orientated upwards and you're using the axes for 2D where the top left corner is (0,0)? in this case if the sprite is drawn without rotation it will face in the -90 direction so there needs to be an offset of +90 added to the rotation when it is actually drawn.

I'm not sure exactly what setRotation and playerSprite.setRotation do, or why you are calling one inside the other, but try (with the above modification as well):
1  
playerSprite.setRotation(setRotation(degreesToMouse) + 90);

(as long as that setRotation only changes the actual sprite's rotation and not the rotation used for the bullet calculations, otherwise remove the +90 from here and move it to where the sprite is drawn)

"All science is either physics or stamp collecting." - Ernest Rutherford.
CodeGolf4k
M4nkala
Offline CTucker1327
« Reply #21 - Posted 2013-12-13 01:34:59 »

I think the real problem is that you're not keeping a consistent definition of an angle. The usual definition is that the +x axis is 0 degrees and the +y axis is 90 degrees. Math.atan2(y,x) will give you an angle according to this definition, so you need to make sure all of your code is consistent with this.

You have the y input in atan2 negated, it should be:
1  
float radiansToMouse = (float) Math.atan2(mouseY - (Gdx.graphics.getHeight() / 2), mouseX -  (Gdx.graphics.getWidth() / 2));


I'm guessing the player sprite image is orientated upwards and you're using the axes for 2D where the top left corner is (0,0)? in this case if the sprite is drawn without rotation it will face in the -90 direction so there needs to be an offset of +90 added to the rotation when it is actually drawn.

I'm not sure exactly what setRotation and playerSprite.setRotation do, or why you are calling one inside the other, but try (with the above modification as well):
1  
playerSprite.setRotation(setRotation(degreesToMouse) + 90);

(as long as that setRotation only changes the actual sprite's rotation and not the rotation used for the bullet calculations, otherwise remove the +90 from here and move it to where the sprite is drawn)

My Player Extends the Entity Class, setRotation is an float that sets the rotation value of the Entity, and returns the value set, allowing me to set both in a single line.

1  
protected float setRotation(float rot) { this.rotation = rot; return this.rotation; }


The code you provided is also not rotating correctly, however the original one that had the x,y switched was working.
Offline CTucker1327
« Reply #22 - Posted 2013-12-13 10:29:19 »

Finally got this working, but the offset was 270 instead of 90.

1  
playerSprite.setRotation(setRotation(degreesToMouse + 270));
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (17 views)
2014-08-01 22:53:16

CogWheelz (15 views)
2014-08-01 22:51:43

CopyableCougar4 (20 views)
2014-08-01 19:37:19

CogWheelz (19 views)
2014-07-30 21:08:39

Riven (27 views)
2014-07-29 18:09:19

Riven (16 views)
2014-07-29 18:08:52

Dwinin (14 views)
2014-07-29 10:59:34

E.R. Fleming (42 views)
2014-07-29 03:07:13

E.R. Fleming (13 views)
2014-07-29 03:06:25

pw (44 views)
2014-07-24 01:59:36
Resources for WIP games
by CogWheelz
2014-08-01 18:20:17

Resources for WIP games
by CogWheelz
2014-08-01 18:19:50

List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!