Java-Gaming.org Hi !
Featured games (81)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (119)
games submitted by our members
Games in WIP (577)
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  
  Basic platform movement and gravity  (Read 7181 times)
0 Members and 1 Guest are viewing this topic.
Offline Dals

Senior Newbie


Projects: 1



« Posted 2012-02-22 21:13:55 »

Hello!

I'm working on a very basic platform engine. This is my first attempt so please excuse me for sloppy programming pratice and such  Tongue
I've got a working platform engine. A player that moves and a "world" loaded from a file.

My problem is that the movement and physics isn't that good and i really don't like how it looks.
I'd like to know what to do with the code to get a smooth movement and physics that works properly!
I've implemented collision detecion, which I think works okay but if someone thinks diffrently please explain what I should do to make it better.

If someone helps me out with this it would help my out alot Cheesy


So time for some code Smiley

My Frame class (The main 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  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
97  
98  
99  
100  
101  
102  
103  
104  
105  
106  
107  
108  
109  
110  
111  
112  
113  
114  
115  
116  
117  
118  
119  
120  
121  
122  
123  
124  
125  
126  
127  
128  
129  
130  
131  
132  
133  
134  
135  
136  
137  
138  
139  
140  
141  
142  
143  
144  
145  
146  
147  
148  
149  
150  
151  
152  
153  
154  
155  
156  
157  
158  
159  
160  
161  
162  
163  
164  
165  
166  
167  
168  
169  
170  
171  
172  
173  
174  
175  
176  
177  
178  
179  
180  
181  
182  
183  
184  
185  
186  
187  
188  
189  
190  
191  
192  
193  
194  
195  
196  
197  
198  
199  
200  
201  
202  
203  
204  
205  
206  
207  
208  
209  
210  
211  
212  
213  
214  
215  
216  
217  
218  
219  
220  
221  
222  
223  
224  
225  
226  
227  
228  
229  
230  
231  
232  
233  
234  
235  
236  
237  
238  
239  
240  
241  
242  
243  
244  
245  
246  
247  
248  
249  
250  
251  
252  
253  
254  
255  
256  
257  
258  
259  
260  
261  
262  
263  
264  
265  
266  
267  
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;

import javax.swing.JFrame;


public class Frame extends JFrame implements Runnable,KeyListener {

   
   private static final long serialVersionUID = 1L;
   
   // SCREEN VARIABLES
   int screenWidth  =640;
   int screenHeight =480;
   
   // world objeccts and variables
   
   Map map;
    Block blocks;
   
   
   // Graphicsh
   BufferedImage backBuffer;
   ImageEntity background;
   Graphics2D g2d;
   
   // animated sprite variable
   //AnimatedSprite player;
   
   // Hero variables
   AnimatedSprite hero;
   Hero player;
   
   
   int playerX = 320;
   int playerY = 100;
   int moveX,moveY;
   
   boolean collision = false;
   int  test = 0;
   // world physics variables
   long TimeStart,TimeEnd;
   
   
   // Fps variables
   int frameCount = 0;
   int frameRate = 0;
   long startTime = System.currentTimeMillis();
   int desierdRate = 60;
   
   // Threads
   Thread gameloop;
   
   
   public static void main(String[] args) {
      new Frame();
   }
   
    Frame () {
       
       // Basic GUI STUFF
       super ("The Diary");
       setSize (screenWidth,screenHeight);
       setVisible (true);
       setResizable (false);
       setDefaultCloseOperation (3);
       
   
       
       // Create a backbuffer so the screen wont flicker like hell!
       backBuffer = new BufferedImage (screenWidth,screenHeight,BufferedImage.TYPE_INT_RGB);
        g2d = backBuffer.createGraphics();
        background = new ImageEntity (this);
        background.load("bluespace.png");


        // Hero
        player = new Hero (32,32);
        player.showBounds(true);
       // player.setGravity(5);
       
        //map
        map = new Map("maze.txt");
       
     
           
       
         
       
        // skapar och startar min tråd
        gameloop = new Thread (this);
        gameloop.start();
        addKeyListener (this);
   
               
       

     }
   
    public void run () {
       Thread t = Thread.currentThread();
       
        try {
         map.createMap();
      } catch (IOException e) {
         
         e.printStackTrace();
      }
   
       
       
       while (t == gameloop) {
          try {
             Thread.sleep(1000 / desierdRate);
          } catch (InterruptedException e) {
             e.printStackTrace();
          }
         
          gameUpdate ();
          repaint ();
       }
    }
   

    // Game update here is it where the magics happends
   
    void gameUpdate ()  {
   
       // räknar ut FPS
       log ("FPS :"+ frameRate);
       frameCount++;
       if (System.currentTimeMillis() > startTime + 1000) {
          startTime = System.currentTimeMillis();
          frameRate = frameCount;
          frameCount = 0;
       }
       
       
       // backgrouunds bilden
       g2d.setColor(Color.GRAY);
       g2d.fill(new Rectangle (0,0,screenWidth-1,screenHeight-1));
       
        // rita ut alla blocks
       
       for (Block b : map.getBlocks()) {
         b.draw(g2d);
         
      }
     
       checkCollision () ;
       player.draw(g2d);
       player.move();
       
   
       
       // Draw debug info
       g2d.setColor(Color.WHITE);
       g2d.drawString("FPS: "+ frameRate, 50, 50);
       g2d.drawString("Player X" + player.positionX, 50,70);
        g2d.drawString("Player Y"+ player.positionY, 50, 80);
        g2d.drawString ("Collison:" + player.collision,50,100);
        g2d.drawString("Falling: " +  player.falling, 50, 110);
       
       
         
    }
   
   
   
    private boolean checkCollision() {
   
       for (int n = 0; n < map.getBlocks().size();n++) {
         
          if (player.getBounds().intersects(map.getBlocks().get(n).getBounds())) {
         

             return player.collision = true;
          }
        }
       
        return player.collision = false;
       
    }


   
   public void paint (Graphics g) {
        //paint the backBuffer
       g.drawImage(backBuffer, 0, 0, this);
    }

   

     


   public void keyPressed(KeyEvent e) {
      switch (e.getKeyCode()) {
      case KeyEvent.VK_LEFT:
         player.setX(-5);
         
         break;
     
      case KeyEvent.VK_RIGHT:
         player.setX(5);
   
         break;
      case KeyEvent.VK_UP :
     
      player.setGravity(0);
       player.setY(-50);
         
         break;
   
      case KeyEvent.VK_SPACE:
         player.positionX = 150;
         player.positionY = 150;
         break;
     
   
      }
     
     
   }

   
   public void keyReleased(KeyEvent e) {
      switch (e.getKeyCode()) {
      case KeyEvent.VK_LEFT:
        player.setX(0);
        //player.setGravity(5);
         break;
      case KeyEvent.VK_RIGHT:
        player.setX(0);
        //player.setGravity(5);
         break;
      case KeyEvent.VK_UP:
         player.setY(0);
         player.setGravity(5);
         break;
           
     
     
      }
     
   }
   public void keyTyped(KeyEvent e) {
     
     
   }
   
   public void log(String s) {
      //System.out.println (s);
   }
   
   
   


}


My Hero 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  
63  
64  
65  
66  
67  
68  
69  
70  
71  
72  
73  
74  
75  
76  
77  
78  
79  
80  
81  
82  
83  
84  
85  
86  
87  
88  
89  
90  
91  
92  
93  
94  
95  
96  
import java.awt.*;


public class Hero {

   int positionX,positionY,x,y;
   int width,height;
   int gravity;
    boolean drawBounds;
    boolean collision,falling ;
   Map m;
   
   
   // konstruktör
   Hero (int width,int height) {
      positionX = 150;
      positionY = 150;
      this.width = width;
      this.height = height;
      drawBounds = false;
   }
   
   // riitar ut objectet
   public void draw (Graphics2D g2d) {
      g2d.setColor(Color.BLACK);
      g2d.fillRect(positionX, positionY, width, height);
     
      if (drawBounds == true) {
         g2d.setColor(Color.RED);
         g2d.drawRect(positionX + x , positionY +y, width, height);
      }
   }
   
   // collision detections rectangle som är en aning före obejctet!
    public Rectangle getBounds () {
       Rectangle r ;
       r = new Rectangle (positionX +x ,positionY +y ,width,height);
       return r;
    }
   
   
   // en setter som talar om om man vill visa collsionrectangle
   public void showBounds(boolean b) {
      drawBounds = b;
   }
   


   
   public void setX (int x) {
      this.x = x;
   }
   public void setY (int y) {
      this.y = y;
   
   }
   
   
   public void move () {
      if (collision == true) {
            setGravity (0);
            x = 0;
            y = 0;
      }
     
      if (y > 0) {
         falling = true;
      } else  {
         falling = false;
      }
     
      if (x > 0 || x< 0 && collision == false) {
         setGravity (5);
      }
     
     
      positionX +=x;
      positionY +=y;
      gravity();
     
     
     
   }

   public void setGravity (int gravity){
      this.gravity = gravity;
   }
   
   private void gravity () {
         setY (gravity);
   
    }
       
         
   }
   


If needed my block class and world 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  
import java.awt.*;

import javax.swing.ImageIcon;
public class Block {

   int width,height,x,y;
   Image BLOCK_WALL;
   
   public Block (int x, int y) {
      this.x = x;
      this.y = y;
      width  = 20;
      height = 20;
       BLOCK_WALL = new ImageIcon ("D:/Programmering/Projekt/Workspace/Framework/src/block_wall.png").getImage();
   }
   
   public void draw (Graphics2D g2d) {
      g2d.drawImage(BLOCK_WALL, x, y, width,height,null);
      g2d.setColor(Color.RED);
      g2d.drawRect(x, y, width, height);
   }
   public Rectangle getBounds() {
      Rectangle r;
      r = new Rectangle  (x,y,width,height);
       return r;
   }

}


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  
import java.util.*;
import java.io.*;

public class Map {

   ArrayList <Block> blocks;
   String filePath;
   
   
   public Map (String path) {
      filePath= path;
      blocks = new ArrayList<Block>();
   }
   public void createMap () throws IOException {
     
      ArrayList <String> lines = new ArrayList <String>();
     
      BufferedReader r= new BufferedReader (new FileReader (filePath));
     
      while (true) {
         String line = r.readLine();
         
         if (line == null) {
            r.close();
            break;
         }
         else {
            lines.add(line);
         }
      }
     
      for (int y = 0; y < lines.size(); y++) {
         for (int x = 0; x<lines.get(y).length();x++) {
            // laddar in mapppen med x och y värden
           
            char mark = lines.get(y).charAt(x);
           
           
           
            if (mark == '#') {
               blocks.add(new Block (x*20,(y*20)+25));
            }
         }
        }
      }
   
      public ArrayList <Block> getBlocks () {
         return blocks;
      }
     
     
     
   
}


I'm new to this fourm so please excuse me if I've posted in the wrong forum and for my unbelievable long post x)

Thank in advance!
Offline ra4king

JGO Kernel


Medals: 350
Projects: 3
Exp: 5 years


I'm the King!


« Reply #1 - Posted 2012-02-23 00:22:55 »

Your movement code looks fine, but try to call move before you paint it or else there will be a lag effect.

Could you be a bit more specific on how your movement isn't "good"?

Offline Dals

Senior Newbie


Projects: 1



« Reply #2 - Posted 2012-02-23 17:08:16 »

call move before you paint it or else there will be a lag effect.
Could you be a bit more specific on how your movement isn't "good"?

Hi, thanks for your replay!

I've changed the code so the move method is before the draw method in my gameUpdate but I didn't notice something.

Well what I ment was that the movement fells very choppy and unnatural... do you have any advice?

Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline UprightPath
« Reply #3 - Posted 2012-02-23 17:17:48 »

It seems like the choppiness is more because of the way you're performing the movement than because of the way you're drawing.

A 32x32 character jumping 50 pixels upwards instantly? This will make it look choppy because motion is not instant. Typically, a jump will follow some sort of parabolic arch which follows a height = velocity + time * acceleration formula. This makes it so that as time passes the jump will go from quickly going upwards, to slowing, before peaking out and starting to fall.

If you want to make it so that the jumper will go a maximum of 50 pixels upwards in say 5 time steps you just do:

50 = velocity + 5 * gravity
50 - 5 * gravity = velocity

Offline Dals

Senior Newbie


Projects: 1



« Reply #4 - Posted 2012-02-23 18:02:02 »

Okay! Yeah that sounds pretty logic.. do you think I should change the code for the left and right movement aswell?
I'm not completly sure how to implement the velocity for the movement so if you could point me in the direction (I know that you already given my a hint) Cheesy
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #5 - Posted 2012-02-23 19:03:01 »

1) Make all your ints float, and then cast them to int when you need to do drawing and such. This will make things much smoother.
2) Rethink your logic to be more like real physics. In other words, as a person in the real world your downward velocity is not just "gravity." It could be ana accumulation of any number of forces. Each movable object in the world has 3 components:
• Position
• Velocity
• Acceleration(s) applied to velocity
In the real world, there is no way for your position to just magically change. Your position only changes when your velocity is nonzero, and its your velocity that changes your position. Similarly, there is no way for your velocity to instantly change. It can only be changed by accelerations. You can however cause all sorts of accelerations. When you jump, your legs are applying a single large acceleration upwards. Meanwhile gravity is constantly applying a downward acceleration to you, so eventually it overcomes that single up acceleration and you come back down.

In simple code terms:
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  
public class Vector2
{
    public float x;
    public float y;
    public Vector2(float xPos, float yPos)
    {
        x = xPos;
        y = yPos;
    }
}

public class PhysicalEntity
{
    private Vector2 position;
    private Vector2 velocity;
    private boolean isOnGround;
    public static final float GROUND_FRICTION = 0.9f;
    public static final float AIR_FRICTION = 0.99f;

    public PhysicalEntity(Vector2 pos)
    {
        position = pos;
        velocity = new Vector2(0,0);
        isOnGround = false;
    }

    public void update(float delta)
    {
        //apply friction
        if (isOnGround)
        {
            velocity.x *= 1.0f - ((1.0f - GROUND_FRICTION) * delta);
            velocity.y *= 1.0f - ((1.0f - GROUND_FRICTION) * delta);
        }
        else
        {
            velocity.x *= 1.0f - ((1.0f - AIR_FRICTION) * delta);
            velocity.y *= 1.0f - ((1.0f - AIR_FRICTION) * delta);
        }

        //change position by velocity
        position.x += velocity.x * delta;
        position.y += velocity.y * delta;
    }

    public void applyAcceleration(Vector2 acceleration)
    {
        velocity.x += acceleration.x;
        velocity.y += acceleration.y;
    }
}

public class World
{
    public static final Vector2 GRAVITY = new Vector2(0.0f, -9.8f);
    private ArrayList<PhysicalEntity> entities;

    public World()
    {
        entities = new ArrayList<PhysicalEntity>();
    }

    public void update(float delta)
    {
        Vector2 frameGravity = new Vector2(GRAVITY.x * delta, GRAVITY.y * delta);
        for (int i = 0; i < entities.size(); i++)
        {
            entities.get(i).applyAcceleration(frameGravity);
            entities.get(i).update(delta);
        }
    }
}


That should get you started. Then when you press left you apply a negative X acceleration, right you apply a positive, etc. When you jump you apply a positive Y acceleration. Pretty easy. The big thing is that in most platformers you want the ground friction amount to be very high (that means a very low value in that GROUND_FRICTION coefficient) as sliding can be really annoying. But you notice if you play Mario he actually has momentum, which is what you get without too much friction.

See my work:
OTC Software
Offline UprightPath
« Reply #6 - Posted 2012-02-23 19:19:30 »

Ah, just a quick note about that big post there!

While it is correct for all intents and purposes, due to the fact that most graphical positional systems do not follow the Cartesian Coordinate system, you have to make a decision between using the same system as your graphics do or writing some form of translation between the two. Typically, people go with changing their system instead of having the translation.

Graphical representation
0123
0
1
2
3

Cartesian (Described above)
0123
3
2
1
0

Basically, you either have to use a inversed accelerations and a Y-Position system where small values appear higher up, or you'll need to write a translation system for your game that will convert the Cartesian to the Graphical (Typically by having something like screenPosY = screen.height - object.position, every time you want to draw something). Where as, just writing your game's physics from the other view point feels more much intuitive (At least for people like me.)

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #7 - Posted 2012-02-23 19:40:08 »

Ah, just a quick note about that big post there!

While it is correct for all intents and purposes, due to the fact that most graphical positional systems do not follow the Cartesian Coordinate system, you have to make a decision between using the same system as your graphics do or writing some form of translation between the two. Typically, people go with changing their system instead of having the translation.

Graphical representation
0123
0
1
2
3

Cartesian (Described above)
0123
3
2
1
0

Basically, you either have to use a inversed accelerations and a Y-Position system where small values appear higher up, or you'll need to write a translation system for your game that will convert the Cartesian to the Graphical (Typically by having something like screenPosY = screen.height - object.position, every time you want to draw something). Where as, just writing your game's physics from the other view point feels more much intuitive (At least for people like me.)
Yes good point. I neglected to mention this. Smiley If you're using Java2D you are probably using the graphical representation, which means reversing gravity to cause a positive Y (because up is down, as UprightPath said).

See my work:
OTC Software
Offline Dals

Senior Newbie


Projects: 1



« Reply #8 - Posted 2012-02-23 20:36:30 »

Ohh, well! loads of new code to understand and learn Cheesy Thanks alot guys for trying to help me out!
If I get stuck I'll ask away Smiley

Thanks again!
Offline UprightPath
« Reply #9 - Posted 2012-02-23 21:06:06 »

Even things like Slick2D use this system (Which, since it's meant to be sort of analogous to Java2D is understandable).

Another thing to note, about his example is the idea of the 'Delta', which appears in the World.update(float delta) class. If I'm correct (And I'm not sure, heh) this delta refers to the amount of time since the last update was called. In some cases, this will always be the same or close enough not to matter (Especially if you have something managing your update rate), in other cases this will vary enough that your objects might seem to move in a more "jerky" method, as you'd described earlier. This really only happens when you go from having very small deltas to suddenly having a very large one.

Correct me if I'm wrong there.

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 #10 - Posted 2012-02-23 21:41:21 »

I included the delta because he mentioned he's using variable timestep.

Delta is usually how many seconds the last update took. That way you can express everything in terms of meters or pixels per second, and if you multiply times delta that's what you get. If you're using fixed timestep, you don't have a delta. I've also just made a delta of 1.0 mean it was the target update time (like if I want it to run at 60fps and the last frame took 1/60th of a second). Either way works as long as you're consistent.

EDIT - I'm mistaken, someone else said they were using variable timestep. You can have a look at that info here:
http://www.java-gaming.org/topics/game-loops/24220/view.html

See my work:
OTC Software
Offline ReBirth
« Reply #11 - Posted 2012-02-24 06:53:04 »

^
Quote
Your position only changes when your velocity changes is not zero
FTFY

Offline Dals

Senior Newbie


Projects: 1



« Reply #12 - Posted 2012-02-25 02:28:11 »

Hey again! I was able to implement the physics and it workes fine!
But what would progaming be whiteout some problem! Tongue
As I said the movement is perfect but now my collision detecion get screwed up by using this new vector class that you wrote for me.

My bounding rectangle before was created like this:
1  
2  
3  
4  
5  
   public Rectangle getBounds () {
       Rectangle r ;
       r = new Rectangle (positionX +x ,positionY +y ,width,height);
       return r;
    }

This worked like a charm because the bounding rectangle would move before the player which would make the collision perfect.

I've tried to implement this this collision detecion with the new physics code like this :

1  
2  
3  
4  
5  
  public Rectangle getBounds () {
       Rectangle r ;
       r = new Rectangle ((int)position.x + (int) velocity.x,(int) position.y + (int)velocity.y, width, height);
       return r;
    }


but I'm not able to get it to work! Do you have any suggestion on how I should do this insteed?

p.s sorry about my grammar, it's kinda late xD


Offline UprightPath
« Reply #13 - Posted 2012-02-25 02:43:48 »

Ah, for collision detection?

You'd put a check where the comment "//change position by velocity" is in the prior code. Otherwise you're moving the character twice (I'm assuming that you're checking after you've run the update code, which means you're adding velocity.x/y twice, and the second time without applying the delta.)

Offline Dals

Senior Newbie


Projects: 1



« Reply #14 - Posted 2012-02-25 12:46:09 »

Ah, for collision detection?

You'd put a check where the comment "//change position by velocity" is in the prior code. Otherwise you're moving the character twice (I'm assuming that you're checking after you've run the update code, which means you're adding velocity.x/y twice, and the second time without applying the delta.)


Well this is how I've done it this far:

in my frame class I've the detection of collision... (It has to be here due to the way I draw my world.)

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
 private boolean checkCollision () {
       
        for (int n = 0; n < map.getBlocks().size();n++) {
           
            if (player.getBounds().intersects(map.getBlocks().get(n).getBounds())) {
           

               return player.collision = true;
            }
          }
         
          return player.collision = false;
         
      }


      Then I my hero class I have:
   
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
 public void setIsOnGround ()  {
     
      if (collision == true) {
         isOnGround = true;
         
         
      } else {
         updateGravity (0.5f); //<- stops the player from falling trhough blokcs in some way!
         isOnGround = false;
         
         
      }  
   }

 
   


   And in my gameUpdate method I have this
1  
2  
3  
4  
5  
6  
7  
8  
9  
// updates the game
       
       
       checkCollision ();
       player.setIsOnGround();
       player.update(0.5f);
       
       
       gameRender ();



The overrided physical entity method in my hero 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  
   @Override
   public void update (float delta) {
     
      //apply friction
        if (isOnGround){
            velocity.x *= 1.0f - ((1.0f - GROUND_FRICTION) * delta);
            velocity.y *= 1.0f - ((1.0f - GROUND_FRICTION) * delta);
        }
        else{
            velocity.x *= 1.0f - ((1.0f - AIR_FRICTION) * delta);
            velocity.y *= 1.0f - ((1.0f - AIR_FRICTION) * delta);
        }
       
       
       
        if (collision == true )  {
           velocity.x = 0;
           velocity.y = 0;
           //GRAVITY.x = 0;
           //GRAVITY.y = 0;
        }
       
       
       

        position.x += velocity.x * delta;
        position.y += velocity.y * delta;
        }









With this code I've managed to get it to stop when it hits a block from above due to the gravity... but when I hit a block I get stuck and can't move. What should happen to the gravity and the two booleans (collision,isOnGround) when the object hit a block?



 Any suggestions? Smiley









Offline UprightPath
« Reply #15 - Posted 2012-02-25 13:32:29 »

Check both directions. This means that you'll have to figure out whether the collision is occurring due to your horizontal or vertical velocity.

This can be a little difficult, since I'm not sure how your map is being implemented. However, basically you have three cases:

Collision Up: velocity.y = 0, isFalling = true
Collision Down: velocity.y = 0, isFalling = false
Collision Left/Right: velocity.x = 0, isFalling = true

You'd check for these in the direction you're moving. So, if your velocity.y is of the same sign as your gravity, then you're obviously falling down, and only have to check up. If your velocity is the opposite sign of gravity, then you check up.

This takes a bit of math, really. And a bit more information. But, if you can write something that figures out which is closer, the X or the Y collision you might~

Offline Dals

Senior Newbie


Projects: 1



« Reply #16 - Posted 2012-02-26 12:43:17 »

Hmm, the way that my world is implemented is on the first post.
You mean that  I should check this every time I move?
I'll will have to think about how I should implement this collision testing but if you could help me I would be very glad Cheesy
TIA!
Offline UprightPath
« Reply #17 - Posted 2012-02-26 15:47:46 »

Actually, looking now, what I said was somewhat wrong. Collision Left/Right should not affect the isFalling flag. Only a downward collision should if you're using simple collision physics.

I'll have to think about the collision system, because the only system I've really done using it is using another method than the rectangle1.intersets(rectangle2). However, if you get a collision, you can probably figure out which edge the collision would have occurred on.

Say, you have...

Player and Block. Player has a velocity vector. Player and Block have a distance vector (distance.x = player.x - block.x, distance.y = player.y - block.y). From that distance vector, we can figure out which corners are important in figuring out the collision. Top left, top right, bottom left, bottom right. From there, you just follow the the player's velocity vector, plotted from the important corner, to see whether it bumps into the vertically or horizontally.

Sorry, I can't provide a better explanation of it, I can see it in my head, but this math is beyond me this morning.

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #18 - Posted 2012-02-27 07:27:02 »

^
Quote
Your position only changes when your velocity changes is not zero
FTFY
Thank you. Smiley

For collision detection I typically just do a raycast in the direction of my velocity and if I hit anything then I clamp the position change to only be as far as the distance to the item the raycast hits. If it doesn't hit anything, move the position the full velocity distance.

See my work:
OTC Software
Offline UprightPath
« Reply #19 - Posted 2012-02-27 08:13:54 »

Yeah, this is where it goes from merely writing the physics engine to actually deciding how you want your physics engine to work.

For Raycasting, I'm not completely sure how well that will work. I'm only passingly knowledgeable about the subject, but it seems to me that using such a method can result in missed collisions if the objects in question are greatly different in size (Such as player being much larger than the object). Like, allowing a player to pass through a bar because it's not in the raycast path.

If you can figure out where the closest collision occurs, you can figure out which of the velocities need to be changed and stuff like that.

I just looked back at your code, which I must admit I didn't do initially, it seems as though it'd be difficult to figure out collision direction, because it will always find the first object that you'd collide with from the TOP-LEFT side of the screen. Instead of finding the closest object in the direction of your velocity. This means that if you're moving fast enough that you might land on several objects (velocity.X > 20, or velocity.y > 25), you'll always get the one that's further from you if you're moving left, up or up-and-left, which will make figuring out where the closest collision is happening difficult.

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #20 - Posted 2012-02-28 02:16:48 »

For Raycasting, I'm not completely sure how well that will work. I'm only passingly knowledgeable about the subject, but it seems to me that using such a method can result in missed collisions if the objects in question are greatly different in size (Such as player being much larger than the object). Like, allowing a player to pass through a bar because it's not in the raycast path.
If that's happening to you then your raycast is not written correctly, or you have very funkily shaped collision areas.

I've done my mentioned approach loads of time and it works great. Granted I usually use circle colliders so that makes it easy, but still.

See my work:
OTC Software
Offline Dals

Senior Newbie


Projects: 1



« Reply #21 - Posted 2012-02-28 19:19:18 »

Okey guys! I feel a little lost now! You talking about some funky raycasting and stuff Smiley
Of what I understood from your replays was that it was difficult to calculate the collisions and when to stop which velocity due to my world implementation? Have I understood you right? Smiley

What I want is a simple platformer with the basic movement and physics Smiley
Offline UprightPath
« Reply #22 - Posted 2012-02-28 19:26:07 »

Someone correct me if I'm wrong, but...

In the Platformer I'm working on right now, instead of using a List<Block> style thing, I'm using a Block[][]. This means that I can customize my iterator so that I can control the direction of consideration. This allows me to find the point of first collision rather easily. From there, I can figure out where the collisions will occur.

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #23 - Posted 2012-02-28 23:22:48 »

The simplest way to raycast would just be to iterate over each pixel looking for collisions each time. Here is a more correct way to do it. As I see it that's the best way to do collision - because it's not discrete (therefore you can't be moving so fast you pass over things).

http://www.codeproject.com/Articles/15604/Ray-casting-in-a-2D-tile-based-environment

But it may be beyond your skill level, sure. For now I'd just do pixel-by-pixel movement, i.e.

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
public void move()
{
    float magnitude = Math.sqrt(velocity.x*velocity.x + velocity.y*velocity.y);
    float normalizedVelocity = new Vector2(velocity.x / magnitude, velocity.y / magnitude);
    Vector2 newPosition = new Vector2(position.x, position.y);
    for (int i = 0; i < magnitude; i++)
    {
        if (!collidesWithStuff(position.x + normalizedVelocity.x * i, position.y + normalizedVelocity.y * i))
        {
            newPosition = new Vector2(position.x + normalizedVelocity.x * i, position.y + normalizedVelocity.y * i);
        }
        else
        {
            break;
        }
    }
    position = newPosition;
}

See my work:
OTC Software
Offline Dals

Senior Newbie


Projects: 1



« Reply #24 - Posted 2012-02-28 23:42:35 »

Thanks for the link! It seems like a valuable resaure. Also thans for the exemple! I'll have to try to implement this into my game Smiley
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.

Longarmx (49 views)
2014-10-17 03:59:02

Norakomi (38 views)
2014-10-16 15:22:06

Norakomi (31 views)
2014-10-16 15:20:20

lcass (34 views)
2014-10-15 16:18:58

TehJavaDev (65 views)
2014-10-14 00:39:48

TehJavaDev (65 views)
2014-10-14 00:35:47

TehJavaDev (55 views)
2014-10-14 00:32:37

BurntPizza (72 views)
2014-10-11 23:24:42

BurntPizza (43 views)
2014-10-11 23:10:45

BurntPizza (84 views)
2014-10-11 22:30:10
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

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
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!