Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (539)
Games in Android Showcase (132)
games submitted by our members
Games in WIP (603)
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  
  Smooth movement in 2d platformer  (Read 3055 times)
0 Members and 1 Guest are viewing this topic.
Offline notk0

Senior Newbie





« Posted 2013-05-17 21:10:16 »

Hello
I am new to game dev and most stuff I learn is from online tutorials or finding it out myself.
I have a 2d platformer with a camera system, the problem is since I move in lets say 4 pixels per frame, even if I have 60 fps movement is not particularly smooth.
I think this is a movement speed issue rather than a camera issue.
One of the solutions I could think of: move in floats, and use AffineTransform when drawing images, problem is my collision system uses ints, I could cast or approximate.
Another solution is to interpolate movement, but that means making a more complex game engine, right now I do update render draw per cycle 60 times per second, and in case of overtime I update without rendering a few times (frame skip)

Are there other solutions?

Edit 1: Here is a demo: http://filebin.ca/iESvMvnv9Cc/Main.jar
Edit 2: I have added a scrollable background layer (sort of paralax scrolling) and the movement issue isn't as noticeable now.
Offline notk0

Senior Newbie





« Reply #1 - Posted 2013-05-22 06:48:32 »

anyone guys?
Offline HeroesGraveDev

JGO Kernel


Medals: 310
Projects: 11
Exp: 3 years


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


« Reply #2 - Posted 2013-05-22 07:18:31 »

If it actually is rendering @ 60 fps, you don't have a problem.

Just make it move faster or slower.

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

Senior Newbie





« Reply #3 - Posted 2013-05-22 21:31:19 »

but in that case I don't get the movement speed I want?
I also have read and think part of my problem might be related to windowed mode as frames don't sync with the display.
Offline alaslipknot
« Reply #4 - Posted 2013-05-23 09:02:44 »

i don't think your problem is a performance issue, i faced the same thing before, and what i noticed is 1st that the game run more "smoothly" outside of eclipse (exported jar) but more importantly the problem was because i didn't write a good "smooth" movement,
if(right){ x+=4;} doesn't gave me the result i was looking for, so i had to add more things to simulate "real" movements in a platformer game, i always tried to make the movement as close as possible to game like super meat boy (SkullBoy is my favorite, it's free) and if you try my 1st WIP release and compare it with the 2nd one, you will absolutely know the difference by your self, here.
one last thing, make sure that you are not losing any frame rate, print it on console or in game just to keep track of what is happening.
i hope i helped, good luck    

"It's not at all important to get it right the first time. It's vitally important to get it right the last time."
Offline philfrei
« Reply #5 - Posted 2013-05-23 15:59:03 »

4 pixels at 60 fps means covering 240 pixels in one second.

Usually that would be okay, it seems to me. However, if you find you are skipping more than one frame, or even skipping a single frame frequently, then I would look to try and figure out what is consuming the most cpu's per frame.

One way to do that would be to put in some System.nanoTime() tests into the game loop that report if a section of code takes longer than expected. There are also profiler tools.

"It's after the end of the world! Don't you know that yet?"
Offline notk0

Senior Newbie





« Reply #6 - Posted 2013-05-23 17:03:11 »

4 pixels at 60 fps means covering 240 pixels in one second.

Usually that would be okay, it seems to me. However, if you find you are skipping more than one frame, or even skipping a single frame frequently, then I would look to try and figure out what is consuming the most cpu's per frame.

One way to do that would be to put in some System.nanoTime() tests into the game loop that report if a section of code takes longer than expected. There are also profiler tools.

that may be a bit too much maybe as I am not fullscreen, I am in a window with about ~600-700 width
Offline notk0

Senior Newbie





« Reply #7 - Posted 2013-05-23 17:05:51 »

i don't think your problem is a performance issue, i faced the same thing before, and what i noticed is 1st that the game run more "smoothly" outside of eclipse (exported jar) but more importantly the problem was because i didn't write a good "smooth" movement,
if(right){ x+=4;} doesn't gave me the result i was looking for, so i had to add more things to simulate "real" movements in a platformer game, i always tried to make the movement as close as possible to game like super meat boy (SkullBoy is my favorite, it's free) and if you try my 1st WIP release and compare it with the 2nd one, you will absolutely know the difference by your self, here.
one last thing, make sure that you are not losing any frame rate, print it on console or in game just to keep track of what is happening.
i hope i helped, good luck    

I will take a look at the second one. Did you use float numbers for movement? cause I use integers so I am forced to move in 1 pixel.

I noticed you have the same bug I have, that is if you hold space/jump below a block you will get stuck to the ceiling as on collision you reset the jump flag,. In my case I do if falling and collision then reset but it still doesn't work, I plan to improve my collision system so I notify the direction of the collision. I had another idea so the player includes multiple collision boxes, one say for feet, another for head and use that, but that would increase the complexity of collisions with enemies and so on.
Did you fix this bug?
Offline alaslipknot
« Reply #8 - Posted 2013-05-23 18:07:37 »

I will take a look at the second one. Did you use float numbers for movement? cause I use integers so I am forced to move in 1 pixel.

I noticed you have the same bug I have, that is if you hold space/jump below a block you will get stuck to the ceiling as on collision you reset the jump flag,. In my case I do if falling and collision then reset but it still doesn't work, I plan to improve my collision system so I notify the direction of the collision. I had another idea so the player includes multiple collision boxes, one say for feet, another for head and use that, but that would increase the complexity of collisions with enemies and so on.
Did you fix this bug?
yes i use float, and in the second one i almost fixed all the collision bugs (except when it jump and hit something from above)
question :
is your main problem is that your player get into the ground or other things sometimes ??

"It's not at all important to get it right the first time. It's vitally important to get it right the last time."
Offline Jimmt
« League of Dukes »

JGO Kernel


Medals: 139
Projects: 4
Exp: 3 years



« Reply #9 - Posted 2013-05-23 22:04:02 »

Float or not, there's no way to move in half pixels. Roll Eyes
Using a float is just more useful - say you want something to move 1 pixel per 2 frames - using floats it's just 0.5 pixels per frame, can't do that with ints because it'll just round.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DrZoidberg

Senior Devvie


Medals: 17



« Reply #10 - Posted 2013-05-23 22:46:06 »

It would help if you would post a simple example program that demonstrates the problem. There could be several reasons. e.g lack of double buffering, rounding from float to int, etc.

Here is an example that shows movement interpolation. Java has support for that built in. But it can only be used when drawing Shape objects.
This draws two moving circles, the one at the bottom has it's movement interpolated automatically, the other does not.

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  
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.Ellipse2D;

public class Ball extends JPanel {
    static final int WIDTH = 800, HEIGHT = 600;
    BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
    volatile double x1, y1;
    volatile double x2, y2;
   
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Ball panel = new Ball();
        panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
        frame.add(panel);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        panel.start();
    }
   
    public void start() {
        x1 = 0; y1 = 0;
        x2 = 0; y2 = 100;
        while(true) {
            x1 += 0.43;
            x2 += 0.43;
            y1 += 0.07;
            y2 += 0.07;
            repaint();
            try {
                Thread.sleep(16);
            } catch(Exception e) {
            }
        }
    }
   
    public void paint(Graphics _g) {
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
       
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.setColor(Color.BLACK);
        g.fillOval((int)x1, (int)y1, 50, 50);
        g.fill(new Ellipse2D.Double(x2, y2, 50, 50));
        _g.drawImage(image, 0, 0, null);
    }
}


However this kind of movement interpolation is not the same as the interpolation used when scaling images.
If you want to interpolate the movement of images it get's slightly more complicated since Graphics2D does not have a drawImage method that takes in floats or doubles. But it should be doable by scaling the graphics object e.g. by a factor of 0.1 and scaling the image you want to draw by 10 using scaling interpolation. That way you can specify the location to draw the image to 0.1 pixels.
Offline notk0

Senior Newbie





« Reply #11 - Posted 2013-05-24 18:43:28 »

It would help if you would post a simple example program that demonstrates the problem. There could be several reasons. e.g lack of double buffering, rounding from float to int, etc.

Here is an example that shows movement interpolation. Java has support for that built in. But it can only be used when drawing Shape objects.
This draws two moving circles, the one at the bottom has it's movement interpolated automatically, the other does not.

However this kind of movement interpolation is not the same as the interpolation used when scaling images.
If you want to interpolate the movement of images it get's slightly more complicated since Graphics2D does not have a drawImage method that takes in floats or doubles. But it should be doable by scaling the graphics object e.g. by a factor of 0.1 and scaling the image you want to draw by 10 using scaling interpolation. That way you can specify the location to draw the image to 0.1 pixels.

How about AffineTransform translate on an image ? I read on stackoverflow that it can be used to do that or is it wrong?
Also I have edited my first post to include a demo as you asked ( http://filebin.ca/iESvMvnv9Cc/Main.jar )
Offline DrZoidberg

Senior Devvie


Medals: 17



« Reply #12 - Posted 2013-05-24 21:26:07 »

Yes, a Graphics2D object uses AffineTransform internally.
I tried it out with a moving image and it works if you use the Graphics2D.translate method.

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  
import javax.swing.*;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.Ellipse2D;
import javax.imageio.ImageIO;
import java.io.File;

public class Ball extends JPanel {
    static final int WIDTH = 800, HEIGHT = 600;
    BufferedImage image = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
    BufferedImage sprite;
    volatile double x, y;
   
    public static void main(String[] args) {
        JFrame frame = new JFrame();
        Ball panel = new Ball();
        panel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
        frame.add(panel);
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        panel.start();
    }
   
    public void start() {
        try {
            sprite = ImageIO.read(new File("c:/sprite.jpg"));
        } catch(Exception e) {
        }
        x = 0; y = 0;
        while(true) {
            x += 0.43;
            y += 0.07;
            repaint();
            try {
                Thread.sleep(16);
            } catch(Exception e) {
            }                                                            
        }
    }
   
    public void paint(Graphics _g) {
        Graphics2D g = image.createGraphics();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
       
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        g.translate(x, y);
        g.drawImage(sprite, 0, 0, null);
        _g.drawImage(image, 0, 0, null);
    }
}


x and y have to be double or float. Also interpolation needs to be turned on explicitely. Try removing the line "g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);" and see what happens.

Quote
Also I have edited my first post to include a demo as you asked ( http://filebin.ca/iESvMvnv9Cc/Main.jar )
The movement looks smooth enough to me.
Offline notk0

Senior Newbie





« Reply #13 - Posted 2013-05-25 09:00:29 »

Yes, a Graphics2D object uses AffineTransform internally.
I tried it out with a moving image and it works if you use the Graphics2D.translate method.

x and y have to be double or float. Also interpolation needs to be turned on explicitely. Try removing the line "g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);" and see what happens.

Quote
Also I have edited my first post to include a demo as you asked ( http://filebin.ca/iESvMvnv9Cc/Main.jar )
The movement looks smooth enough to me.

Well if you don't look at the character  in the center of the screen but at the blocks before him and focus on them, it looks as if they're shaking since they move in fixed intervals.
I tried to play super mario bros as a comparison and it seems smother to me, but I think he moves slower as well not sure.
If you say it's smooth I guess I am looking too much into it.
I'll try to migrate everything to float/double movements and use AffineTransform instead as I really need subpixel movements and I don't think casting to int is a good solution.
Offline DrZoidberg

Senior Devvie


Medals: 17



« Reply #14 - Posted 2013-05-25 10:06:16 »

Yes, if you look closely you can see a slight shaking.
Anyway using doubles for movement is certainly better than ints, also you don't need to use AffineTransform directly. It's sufficient to use the Graphics2D.translate method as in my example.
Offline notk0

Senior Newbie





« Reply #15 - Posted 2013-05-25 10:18:55 »

Yes, if you look closely you can see a slight shaking.
Anyway using doubles for movement is certainly better than ints, also you don't need to use AffineTransform directly. It's sufficient to use the Graphics2D.translate method as in my example.

I am wondering if my camera calculations are not wrong, since sprite movement looks good if you stay still.
Offline DrZoidberg

Senior Devvie


Medals: 17



« Reply #16 - Posted 2013-05-25 10:32:57 »

I'm guessing your camera movement uses ints too. So it may be a rounding issue.
Offline notk0

Senior Newbie





« Reply #17 - Posted 2013-05-25 10:51:41 »

I'm guessing your camera movement uses ints too. So it may be a rounding issue.

What I do is use division to find out the position inside the tile map  so I know where to grab the tiles from, then I use modulo/% tile size to obtain the remainder and I draw all the tiles in the view and their position on screen I add the remainder player_position % tile size or substract it.
Offline DQQAYME

Junior Devvie


Medals: 1
Projects: 1



« Reply #18 - Posted 2013-05-25 11:25:01 »

IMHO
Make movement by float
With synchronize per frame

1  
2  
3  
4  
5  
float pos_X = 10;

pos_X += 4f * frame_SYN;// 60 fps base then if we have 30 frame_SYN = 0.5

Draw((int) pos_X, (int) pos_Y)


for collision system use (int)pos_X =)

Offline notk0

Senior Newbie





« Reply #19 - Posted 2013-05-25 11:32:38 »

IMHO
Make movement by float
With synchronize per frame

1  
2  
3  
4  
5  
float pos_X = 10;

pos_X += 4f * frame_SYN;// 60 fps base then if we have 30 frame_SYN = 0.5

Draw((int) pos_X, (int) pos_Y)


for collision system use (int)pos_X =)

I am sorry, what is frame synchronization ? I have never heard of this before.
Offline alaslipknot
« Reply #20 - Posted 2013-05-25 13:01:34 »

I am sorry, what is frame synchronization ? I have never heard of this before.
it's "Delta" and i think this will definitely solve your problem, look to the "variable timestep" example, you will notice that he multiply the velocity by "delta",
1  
2  
s.velocity += Gravity.VELOCITY * delta;
s.position += s.velocity * delta;
 
it's because in case the framerate changes your speed should also change with it, like that your object is ALWAYS gonna be moving in the same speed, (by same speed i mean that no matter how low the framerate is, the time to travel from point A to point B gonna always be the same)  

PS :
it's one of the most helpful article here (if not the best) you should read it if you didn't already

i hope it helped, good luck  

"It's not at all important to get it right the first time. It's vitally important to get it right the last time."
Offline notk0

Senior Newbie





« Reply #21 - Posted 2013-05-25 14:07:07 »

I am sorry, what is frame synchronization ? I have never heard of this before.
it's "Delta" and i think this will definitely solve your problem, look to the "variable timestep" example, you will notice that he multiply the velocity by "delta",
1  
2  
s.velocity += Gravity.VELOCITY * delta;
s.position += s.velocity * delta;
 
it's because in case the framerate changes your speed should also change with it, like that your object is ALWAYS gonna be moving in the same speed, (by same speed i mean that no matter how low the framerate is, the time to travel from point A to point B gonna always be the same)  

PS :
it's one of the most helpful article here (if not the best) you should read it if you didn't already

i hope it helped, good luck  

Actually I am using fixed timesteps I may add interpolation to my game but I don't wish to change to variable timestemps.
When I get some free time today I will recheck my camera algorithm by hand on a piece of paper, since I may have figured it out wrong the first time.
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.

rwatson462 (30 views)
2014-12-15 09:26:44

Mr.CodeIt (23 views)
2014-12-14 19:50:38

BurntPizza (50 views)
2014-12-09 22:41:13

BurntPizza (84 views)
2014-12-08 04:46:31

JscottyBieshaar (45 views)
2014-12-05 12:39:02

SHC (59 views)
2014-12-03 16:27:13

CopyableCougar4 (57 views)
2014-11-29 21:32:03

toopeicgaming1999 (123 views)
2014-11-26 15:22:04

toopeicgaming1999 (114 views)
2014-11-26 15:20:36

toopeicgaming1999 (32 views)
2014-11-26 15:20:08
Resources for WIP games
by kpars
2014-12-18 10:26:14

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