Java-Gaming.org    
Featured games (81)
games approved by the League of Dukes
Games in Showcase (491)
Games in Android Showcase (112)
games submitted by our members
Games in WIP (556)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: 1 2 [3]
  ignore  |  Print  
  Car rotation problem in top down  (Read 8907 times)
0 Members and 1 Guest are viewing this topic.
Offline deadly72

Junior Member





« Reply #60 - Posted 2011-03-06 08:23:45 »

InputController should be a private inner class of Game so it can use Game's instance variables and methods.

Hahahahaha I actually thought about this in the beginning, seeing as it is how it is done in one of my Java books that I own and occasionally use as a reference.  I guess I just really wanted to see if I could have used a separate file as it seems like my game class will be huge with the controller included inside it.  Also having made the change I feel like the code really IS much neater and easier to understand with the usage of the entity class of course.

On a side note:  I really hate going back to the move function but to be totally honest I really need clarity.  I was playing around with it and I just want to know if you guys can tell me why it isn't working the way I want it to.  Easy example is I want the to travel 100 pixels in 4 seconds.  This is the current way that its being done, and odviously the wrong way.  It is really making me angry as to why I can not get such a simple concept through my head.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
double oldTime = 0;
private void move(int deltaTime) {
        double deltaSeconds = deltaTime / 1000.0; // seconds since last update
     
   if (up)
      acceleration = (100/4) * deltaSeconds;
   if (down)
      acceleration = (100/4) * deltaSeconds;
   if (right)
      carAngle += rotationStep * (vx/topspeed);
   if (left)
      carAngle -= rotationStep * (vy/topspeed);
     
   vx = Math.min((vx + acceleration) * ( 1 - friction),6);
   vx = Math.abs(vx) < 0.09? 0 : vx;
   vy = Math.min((vy + acceleration) * ( 1 - friction),6);
   vy = Math.abs(vy) < 0.09? 0 : vy;
     
         
   double ax = Math.sin(Math.toRadians(carAngle));
   double ay = -Math.cos(Math.toRadians(carAngle));
   x += ax * vx;
   y += ay * vy;
}


To my knowledge acceleration = deltavelocity / deltatime. So (100/4) * deltaTime should be the correct formula.
Offline dishmoth
« Reply #61 - Posted 2011-03-06 10:58:17 »

Easy example is I want the to travel 100 pixels in 4 seconds.
Do you mean that you want the car to cruise at a maximum speed of (100/4=)25 pixels per second?  Or that you want the car to accelerate from zero to its maximum speed in 4 seconds, and to have travelled 100 pixels while doing so?

Quote
To my knowledge acceleration = deltavelocity / deltatime. So (100/4) * deltaTime should be the correct formula.
The first statement is correct.  But I don't know what you mean by the second statement.  If (100/4) is the speed, then (100/4)*deltaTime is the distance travelled...?

I'm going to claim that the following code will do what you want if you set the correct values for acceleration, topSpeed and rotationSpeed.  I think you should probably convince yourself that everything else is working before including friction, etc.  (Two specific problems with your old code.  First, the two separate speed variables vx and vy didn't make sense.  Second, if your function is using the time step length deltaTime, then when that equals zero the function should do nothing - your code was failing that sanity check.)

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  
final private static double acceleration = ???; // (pixels per second per second)
final private static double topSpeed = ???; // (pixels per second)
final private static double rotationSpeed = ???; // (degrees per second)

private double x, y; // position (pixels)
private double v; // speed (pixels per second)
private double carAngle; // direction (degrees)

private void move(int deltaTime) {
  double deltaSeconds = deltaTime / 1000.0; // seconds since last update

  if (up)
    v = Math.min(+topSpeed, v + acceleration*deltaSeconds);
  if (down)
    v = Math.max(-topSpeed, v - acceleration*deltaSeconds);

  if (right)
    carAngle += rotationSpeed * deltaSeconds * (v/topSpeed);
  if (left)
    carAngle -= rotationSpeed * deltaSeconds * (v/topSpeed);

  double ax = Math.sin(Math.toRadians(carAngle));
  double ay = -Math.cos(Math.toRadians(carAngle));
  x += ax * v * deltaSeconds;
  y += ay * v * deltaSeconds;
}


Simon

Offline deadly72

Junior Member





« Reply #62 - Posted 2011-03-07 01:02:25 »

Alright finally that really clears it up.  I guess I was just being confused all around with friction and multiple velocities instead of just using a single velocity for both x and y.  Here is what it comes out to.  Note that I did add friction Grin.  I am really pleased with how that turned out, and hopefully it is done the correct way Huh.  I'm glad to say I understand what is actually happening now that its done step by step.

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  
private double friction = 0.3;
   
private double acceleration = 100/2.5; // (pixels per second)
private double currentSpeed = 0.0; //speed (pixels per second)
private double topspeed = 220;
private double rotationSpeed = 90;

private double carAngle = 0;
   
private void move(int deltaTime) {
   double deltaSeconds = deltaTime / 1000.0;// seconds since last update
     
   if (up) {
      currentSpeed = Math.min(+topspeed, currentSpeed + acceleration * deltaSeconds);
   }
   if (down) {
      currentSpeed = Math.max(-topspeed, currentSpeed - acceleration * deltaSeconds);
   }
   if (right)
     carAngle += rotationSpeed * deltaSeconds * (currentSpeed/topspeed);
   if (left)
     carAngle -= rotationSpeed * deltaSeconds * (currentSpeed/topspeed);
     
     
   currentSpeed *= Math.max(0.0, (1 - friction * deltaSeconds));
   currentSpeed = Math.abs(currentSpeed) < 0.9 ? 0 : currentSpeed;
     
   double ax = Math.sin(Math.toRadians(carAngle));
   double ay = -Math.cos(Math.toRadians(carAngle));
   x += ax * currentSpeed * deltaSeconds;
   y += ay * currentSpeed * deltaSeconds;
}


To me it does seem strange though that I need to have a rotationSpeed of 90 for it to rotate at a decent rate.  I suppose it is one of those constants that you just have to be comfortable with?

And on a kind of related note, I'm having troubles with collision detection because of the rotation.  I have taken a look at http://www.java-gaming.org/topics/rotating-a-rectangle-object/23694/view.html and http://www.java-gaming.org/index.php?topic=23741.0 but I'm not totally sure if I need to use a shape or if there is anyway to rotate the rectangle around my image.  For example to get the bounds of my image I use

1  
2  
3  
public Rectangle getBounds() {
   return new Rectangle((int)Math.round(x), (int) Math.round(y), carImage.getWidth(null), carImage.getHeight(null));
}


and I bet that in itself this is the problem because we can't rotate the bounds of the object?  My render function for the car class is as follows.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
   
public void render(Graphics2D g) {
   g.setColor(Color.WHITE);
   g.drawRect(Map.getGameArea().x, Map.getGameArea().y, Map.getGameArea().width, Map.getGameArea().height);
     
   g.setColor(Color.GRAY);
   g.drawRect(getBounds().x, getBounds().y, getBounds().width, getBounds().height);
   g.rotate(Math.toRadians(carAngle),x,y);
   g.drawImage(carImage, (int) Math.round(x), (int)Math.round(y), null);
     
}


I would also appreciate it if anyone could tell me exactly what the difference is between using the graphics object or using an AffineTranform object.  Lastly I would like to say that I apologize for all the jumping around between the code I've been doing.  Can't seem to stick around one area long enough to complete it!  I guess once I get confirmation that the move method is now correct I can say at least one task is complete.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline SimonH
« Reply #63 - Posted 2011-03-07 01:32:33 »

I would also appreciate it if anyone could tell me exactly what the difference is between using the graphics object or using an AffineTranform object.
The Graphics2D object is where you put the graphics (think bitmap) and the AffineTranform says how you put them there.
So you load an image, rotate it (AffineTranform) and draw it on a piece of paper (Graphics).
I doubt using Graphics2D.rotate() is very efficient - I'd use Graphics2D.drawImage(image, affineTrans... instead.
Also, ditch all the toRadians() stuff! Work in radians: 360 degrees = 2PI radians, 90'=1.571 rad . (*blush* I still have a circular chart on my wall showing degrees/radians conversion).

People make games and games make people
Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #64 - Posted 2011-03-07 01:36:33 »

Also, ditch all the toRadians() stuff! Work in radians: 360 degrees = 2PI radians, 90'=1.571 rad . (*blush* I still have a circular chart on my wall showing degrees/radians conversion).
Nah toRadians() is simpler Grin

Offline dishmoth
« Reply #65 - Posted 2011-03-07 09:43:19 »

To me it does seem strange though that I need to have a rotationSpeed of 90 for it to rotate at a decent rate.
A rotation speed of 90 degrees per second means it will take 4 second for the car to turn all the way around (360 degrees).  Which doesn't seem unreasonable.

Quote
And on a kind of related note, I'm having troubles with collision detection because of the rotation.
Start with a Rectangle2D object.  Create an Area object from it.  Apply an AffineTransform (rotation) to that object.  (You may need to browse the JDK documentation for some of this...)  Then use it to check for collisions.

Here's the important bit:  Use Graphics2D.draw() to display the Area object each frame, or you won't have a clue what's going on.  (I guess I didn't need to say that though, because you're doing it already with the bounding boxes.)

Quote
I guess once I get confirmation that the move method is now correct I can say at least one task is complete.
If you're happy with it, then I think everyone's happy with it. Smiley
Simon

Offline deadly72

Junior Member





« Reply #66 - Posted 2011-03-07 18:41:10 »

Alright so I mostly did what you told me with a few modifications I suppose?  I know it's probably done the wrong way but it works! Smiley.  I would like to perfect it though.

Initialize the shape with the car constructor
1  
2  
3  
4  
5  
6  
private Area carArea;

public Car(String name, String imagePath) {
   ...
   carArea = new Area(getBounds());
}


This is the part I'm not too sure if it is done the right way
1  
2  
3  
4  
5  
6  
7  
public void update(int deltaTime) {
   if ((Map.getGameArea().contains(carArea.getBounds()))) {
      move(deltaTime);
   }

        ...
        car = new Area(getBounds());


I'm not sure why you said to use a Rectangle2D while Rectangle could do the same Huh
1  
2  
3  
public Rectangle getBounds() {
   return new Rectangle((int)Math.round(x), (int) Math.round(y), carImage.getWidth(null), carImage.getHeight(null));
}


And finally the render which I'm pretty sure there is something wrong with too - efficiency wise?
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
public void render(Graphics2D g) {
      ...

      AffineTransform savedAT = new AffineTransform();
      savedAT = g.getTransform();
      AffineTransform newAT = new AffineTransform();
      newAT.rotate(Math.toRadians(carAngle),x,y);
      carArea.transform(newAT);
      g.draw(carArea);
     
     
      g.setColor(Color.GRAY);
      g.setTransform(newAT);
      g.drawImage(carImage, (int) Math.round(x), (int)Math.round(y), null);
      g.setTransform(savedAT);
     
}


As I mentioned the above works, but I would like to perfect / do it the right way?  To me it seems that creating a new area object each update isn't the way to go?
Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #67 - Posted 2011-03-07 19:11:14 »

You don't need to create a new Area object each time, just rotate it when you rotate the car.

Quote
I'm not sure why you said to use a Rectangle2D while Rectangle could do the same Huh

Rectangle2D is more accurate (uses double instead of int) and the API is less painful to look at. Grin

Offline dishmoth
« Reply #68 - Posted 2011-03-07 21:18:49 »

I'd suggest creating (and rotating) a new Area object each frame.  The cost in terms of efficiency is negligible (unless your game features a very large number of cars Wink).  And it's better to always transform from fresh each time, rather than accumulating transforms, because otherwise numerical rounding errors will mean that the Area will slowly (admittedly very slowly, but let's not risk it) drift away from the car's true (x,y,carAngle) location.

Something like:
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  
public Car(...) {
  ...
  carArea = makeArea();
}

private void move(...) {
  ...
  carArea = makeArea();
}

private Area makeArea() {
  Area a = new Area( getBounds() );
  AffineTransform tr = AffineTransform.getRotateInstance( Math.toRadians(carAngle), x, y );
  a.transform(tr);
  return a;
}

private static final boolean debugMode = true;
public void render(Graphics2D g) {
  ...
  if (debugMode) {
    g.setColor(Color.MAGENTA);
    g.draw(carArea);  
  }
}


So you rotate the Area (rectangle) object when you create it, not just when you draw it.  And you can see that everything is working because (fingers crossed!) the rotated rectangle will follow the car around the screen.  (Obviously you'd disable that effect in the released version of the game.)

Does that make some kind of sense?
Simon

Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #69 - Posted 2011-03-07 22:52:58 »

I'd suggest creating (and rotating) a new Area object each frame.  The cost in terms of efficiency is negligible (unless your game features a very large number of cars Wink).  And it's better to always transform from fresh each time, rather than accumulating transforms, because otherwise numerical rounding errors will mean that the Area will slowly (admittedly very slowly, but let's not risk it) drift away from the car's true (x,y,carAngle) location.
Ah yes good point.

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #70 - Posted 2011-03-08 18:25:22 »

You can also use a bunch of Polygon objects for your collision. I typically know where the 4 vertices are so it's easy for me.

Even better, if your car isn't super long compared to its width, you can just use a single radius collision for everything. That is almost always what I do in games that are not meant to be physics-heavy. It's the cheapest check possible and conceptually it's easy to think about. None of this dealing with Polygons or Areas or anything. A cartoony-looking car usually would have a bounding box where the height is about 1.5 times the width, or less. That means a bounding circle with a radius of about 1.25 times the width will work great, and just making it the height also works great too (you don't usually want a car to be exactly next to another one anyway).

I can say this works from experience, because I took this exact approach for cars in a professional game.

See my work:
OTC Software
Offline deadly72

Junior Member





« Reply #71 - Posted 2011-03-09 03:47:30 »

Thanks dishmoth, that fixed the problem with the rotation and now collision detection will be much simpler to handle as I have a rotating bounding box! Grin.

You can also use a bunch of Polygon objects for your collision. I typically know where the 4 vertices are so it's easy for me.

Even better, if your car isn't super long compared to its width, you can just use a single radius collision for everything. That is almost always what I do in games that are not meant to be physics-heavy. It's the cheapest check possible and conceptually it's easy to think about. None of this dealing with Polygons or Areas or anything. A cartoony-looking car usually would have a bounding box where the height is about 1.5 times the width, or less. That means a bounding circle with a radius of about 1.25 times the width will work great, and just making it the height also works great too (you don't usually want a car to be exactly next to another one anyway).

I was actually thinking of using polygons for all my objects that way I can have any shape really, but it isn't really a necessity right now.  I will definitely keep it in mind though!

Thanks for all the help everybody! on to collision detection! Wink
Offline ra4king

JGO Kernel


Medals: 345
Projects: 3
Exp: 5 years


I'm the King!


« Reply #72 - Posted 2011-03-09 04:17:56 »

Glad to help Grin

Offline dishmoth
« Reply #73 - Posted 2011-03-09 09:33:00 »

Even better, if your car isn't super long compared to its width, you can just use a single radius collision for everything. That is almost always what I do in games that are not meant to be physics-heavy. It's the cheapest check possible and conceptually it's easy to think about. None of this dealing with Polygons or Areas or anything. A cartoony-looking car usually would have a bounding box where the height is about 1.5 times the width, or less. That means a bounding circle with a radius of about 1.25 times the width will work great, and just making it the height also works great too (you don't usually want a car to be exactly next to another one anyway).

Agreed.  Generally, bounding circles or axis-aligned (unrotated) bounding boxes are the best place to start.  I was probably a bit hasty jumping in with the stuff about Areas.  Ah well, so long as it works.
Simon

Pages: 1 2 [3]
  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.

Nickropheliac (15 views)
2014-08-31 22:59:12

TehJavaDev (23 views)
2014-08-28 18:26:30

CopyableCougar4 (29 views)
2014-08-22 19:31:30

atombrot (41 views)
2014-08-19 09:29:53

Tekkerue (39 views)
2014-08-16 06:45:27

Tekkerue (35 views)
2014-08-16 06:22:17

Tekkerue (25 views)
2014-08-16 06:20:21

Tekkerue (36 views)
2014-08-16 06:12:11

Rayexar (72 views)
2014-08-11 02:49:23

BurntPizza (49 views)
2014-08-09 21:09:32
List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

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

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

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

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

HotSpot Options
by dleskov
2014-07-08 01:59:08
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!