Movement Speed

I fixed the second part, but the first part seems redundant I am subtracting timeDiff from DELAY and setting that to sleep. if you look above that, timeDiff in fact is (System.currentTimeMillis - befireTime). So in effect arent I already doing
sleep = DELAY - (System.currentTimeMillis() - beforeTime) ?

No timeDiff includes the time spent sleeping. sleep = DELAY - (int)(System.currentTimeMillis()-beforeTime) only takes off the time spent in game code so your loop would run smoothly.

Ok fixed that, made it a lot smoother. THANKS! But it also completely screwed my player movement. I printed out his xPositions and all it does is move between 2 and five hundred something. He just disappears most of the time. I want to post all of the code with the images so that you guys can run it and see what I mean. Im going to post the code anyway, I guess you can fill in the images to make it run. Thanks so much for this debugging help!

package platformer;

import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;

import javax.swing.ImageIcon;


public class Player implements Entity {

	private String player = "player.png";

	//x and y positions for the player
	private double xPosition;
	private double yPosition;

	//x and y speeds for the player
	private double xSpeed;
	private double ySpeed;

	//width and height of the player
	private int width;
	private int height;

	private Image image;

	private boolean wPressed;
	private boolean sPressed;
	private boolean aPressed;
	private boolean dPressed;

	private boolean visible;

	private boolean jumping;
	private double gravity;
	private double jumpVel;



	public Player() {

		ImageIcon playerIcon = new ImageIcon(this.getClass().getResource(player));
		image = playerIcon.getImage();

		//setting the players dimensions
		width = image.getWidth(null);
		height = image.getHeight(null);


		//setting the initial player position and speed
		xPosition = 500;
		yPosition = 340;


		xSpeed = 1;
		ySpeed = 1;


		//setting visible
		visible = true;

		jumping = false;
		gravity = 6;
		jumpVel = 2;
	}

	@Override
	public void move(long timeDiff) {



		if(dPressed && xPosition < 760) {

			xPosition = (xPosition + ((xSpeed * timeDiff) / 1000));

		}
		if(aPressed && xPosition > 0) {
			xPosition = (xPosition - ((xSpeed * timeDiff) / 1000));

		}

		//jumping
		if(wPressed && !jumping) {

			jumping = true;

		}
		if(jumping) {

			yPosition = (yPosition - ((jumpVel * timeDiff) / 1000));
			jumpVel -= gravity;
		}
		if(yPosition > 340) {
			jumping = false;
			jumpVel = 2;
		}

	}


	@Override
	public void update(long timeDiff) {

		move(timeDiff);
	}

	@Override
	public Image getImage() {
		// TODO Auto-generated method stub
		return image;
	}

	@Override
	public double getXPosition() {
		// TODO Auto-generated method stub
		return xPosition;
	}

	@Override
	public double getYPosition() {
		// TODO Auto-generated method stub
		return yPosition;
	}

	@Override
	public boolean isVisible() {
		// TODO Auto-generated method stub
		return visible;
	}

	@Override
	public Rectangle getBounds() {
		// TODO Auto-generated method stub
		return new Rectangle((int)getXPosition(),(int)getYPosition(), width, height);
	}

	public void keyPressed(KeyEvent e) {

		int key = e.getKeyCode();

		if(key == KeyEvent.VK_W) {

			wPressed = true;

		}

		if(key == KeyEvent.VK_S) {

			sPressed = true;

		}

		if(key == KeyEvent.VK_A) {

			aPressed = true;

		}

		if(key == KeyEvent.VK_D) {

			dPressed = true;

		}


	}

	public void keyReleased(KeyEvent e) {

		int key = e.getKeyCode();

		if(key == KeyEvent.VK_W) {

			wPressed = false;
		}

		if(key == KeyEvent.VK_S) {

			sPressed = false;

		}

		if(key == KeyEvent.VK_A) {

			aPressed = false;

		}

		if(key == KeyEvent.VK_D) {

			dPressed = false;

		}
	}
}

package platformer;

import java.applet.AudioClip;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.util.ArrayList;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class Game extends Canvas implements Runnable {

	private BufferStrategy bufferStrategy;

	private Thread animator;

	private Player player;
	private ArrayList<Bomb> bombs;

	private final int DELAY = 20;

	private boolean gamePlaying;
	private boolean gameOver;
	private boolean introScreen;

	private Image grass;

	private AudioClip jumpSound;


	public Game() {

		JFrame container = new JFrame("Platformer");



		JPanel panel = (JPanel)container.getContentPane();
		panel.setPreferredSize(new Dimension(800,400));
		panel.setLayout(null);



		setBounds(0,0,800,600);
		panel.add(this);

		//stop AWT from calling repaint (im painting myself!)
		setIgnoreRepaint(true);


		container.pack();
		container.setResizable(false);
		container.setVisible(true);


		//add the listener so we can get key presses
		addKeyListener(new KAdapter());



		requestFocus();

		player = new Player();
		initBombs();


		gamePlaying = true;
		gameOver = false;
		introScreen = false;

		//create 2 buffers and get the painting strategy
		createBufferStrategy(2);
		bufferStrategy = getBufferStrategy();

		//create and start the animation thread
		animator = new Thread(this);
		animator.start();

		//make sure the program exits when the window is closed
		container.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});

		ImageIcon ii = new ImageIcon(this.getClass().getResource("grass.png"));
		grass = ii.getImage();



	}

	private void initBombs() {

		bombs = new ArrayList<Bomb>();

		for (int i=0; i<BombLocations.bombPositions.length; i++ ) {
			bombs.add(new Bomb(BombLocations.bombPositions[i][0], BombLocations.bombPositions[i][1]));
		}

	}

	@Override
	public void run() {

		while(true) {

			long beforeTime = 0, timeDiff, sleep;



			if(gamePlaying) {

				timeDiff = System.currentTimeMillis() - beforeTime;
				beforeTime = System.currentTimeMillis();


				player.update(timeDiff);

				for(Bomb bomb : bombs) {
					bomb.update(timeDiff);
				}

				collisionDetection();
				renderGame();


				sleep = DELAY - (System.currentTimeMillis() - beforeTime);

				if (sleep < 0)
					continue;
				try {
					Thread.sleep(sleep);
				} catch (InterruptedException e) {
					System.out.println("interrupted");
				}
			}

			if(introScreen) {

				renderIntroScreen();

			}

			if(gameOver) {

				gameOver();
			}
		}
	}

	public void renderGame() {

		Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
		g.setColor(Color.gray);
		g.fillRect(0,0,800,400);



		if(player.isVisible()) {
			g.drawImage(player.getImage(), (int)player.getXPosition(),(int) player.getYPosition(), null);
		}
		for(Bomb bomb : bombs ) {
			if(bomb.isVisible()) {
				g.drawImage(bomb.getImage(), (int)bomb.getXPosition(), (int)bomb.getYPosition(), null);
			}
		}

		g.drawImage(grass, 0, 350, null);

		g.dispose();
		bufferStrategy.show();


	}

	public void gameOver() {

		Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
		g.setColor(Color.black);
		g.fillRect(0,0,800,400);

		g.setFont(new Font("Courier", Font.BOLD, 25));
		g.setColor(Color.white);
		g.drawString("GAME OVER", 325, 200);

		g.dispose();
		bufferStrategy.show();


	}

	public void renderIntroScreen() {

		String introMessage = "Avoid the bombs!" + "\nUse A to go left" + "\nUse D to go right" +
				"\nUse W to Jump" + "\n\nPress ENTER to begin!";
		

		Graphics2D g = (Graphics2D) bufferStrategy.getDrawGraphics();
		g.setColor(Color.black);
		g.fillRect(0,0,800,400);

		g.setFont(new Font("Courier", Font.BOLD, 25));
		g.setColor(Color.white);
		g.drawString(introMessage, 325, 200);

		g.dispose();
		bufferStrategy.show();




	}

	public void collisionDetection() {

		Rectangle playerBounds = player.getBounds();

		for(Bomb bomb : bombs) {

			Rectangle bombBounds = bomb.getBounds();
			if(bombBounds.intersects(playerBounds)) {
				gamePlaying = false;
				gameOver = true;
			}

		}

	}

	private class KAdapter extends KeyAdapter {

		public void keyPressed(KeyEvent e) {

			player.keyPressed(e);


		}
		public void keyReleased(KeyEvent e) {

			player.keyReleased(e);


		}
		
	}
}



package platformer;

import java.awt.Image;
import java.awt.Rectangle;

import javax.swing.ImageIcon;

public class Bomb implements Entity {

	private String bomb = "bomb.png";

	//x and y positions for the bomb
	private double xPosition;
	private double yPosition;

	//x and y speeds for the bomb
	private double xSpeed;
	private double ySpeed;
	
	private int BOMB_VELOCITY;

	//width and height of the bomb
	private int width;
	private int height;

	private Image image;

	private boolean visible;

	private boolean jumping;
	private double gravity;
	private double jumpVel;

	public Bomb(double xPosition, double yPosition) {

		ImageIcon bombIcon = new ImageIcon(this.getClass().getResource(bomb));
		image = bombIcon.getImage();

		//setting the bomb dimensions
		width = image.getWidth(null);
		height = image.getHeight(null);


		//setting the initial bomb position and speed
		this.xPosition = xPosition;
		this.yPosition = yPosition;


		xSpeed = 1;
		ySpeed = 100;
		
		BOMB_VELOCITY = 2;


		//setting visible
		visible = true;

		jumping = false;
		gravity = 6;
		jumpVel = 750;
	}


	@Override
	public void move(long timeDiff) {
		
		if(xPosition > 740) {

			xSpeed = -(BOMB_VELOCITY);
				
		}
		if(xPosition < 0) {

			xSpeed = BOMB_VELOCITY;
				
		}
		
		xPosition += xSpeed;
		
			

		if(!jumping) {

			jumping = true;

		}
		if(jumping) {

			yPosition = (yPosition - (jumpVel/250));
			jumpVel -= gravity;
		}
		if(yPosition > 350) {
			jumping = false;
			jumpVel = 750;
		}

	

	}

	@Override
	public void update(long timeDiff) {
		move(timeDiff);

	}

	@Override
	public Image getImage() {
		// TODO Auto-generated method stub
		return image;
	}

	@Override
	public double getXPosition() {
		// TODO Auto-generated method stub
		return xPosition;
	}

	@Override
	public double getYPosition() {
		// TODO Auto-generated method stub
		return yPosition;
	}

	@Override
	public boolean isVisible() {
		// TODO Auto-generated method stub
		return visible;
	}

	@Override
	public Rectangle getBounds() {
		// TODO Auto-generated method stub
		return new Rectangle((int)xPosition, (int)yPosition, width, height);
	}

}

package platformer;

public class BombLocations {
	
	protected static double[][] bombPositions = 
		
	{ {-50.0, 200.0}, {850.0, 175.0}};

}

The idea is to have an array of bombs and repeatedly add more every 10 seconds or so, when you get hit its over. What frustrates me is that I had the move methods for all my entities taking in the delta from the update loop and moving based on that. That worked well for the player but for the bombs jumping it totally broke, so I just hard coded in a value of 250 to get it to work. I think Im just still getting tripped up on the update times in the run method. I fixed what you said, now the bombs move nice and smooth, but the players broken.

I tested the value of timeDiff, and it winds up being a HUGE number. So when I pass it to the updates, multiply it by the speed, and divide that by 1000, I still get a gigantic number. Which explains why my movement is broken. So am I calculating timeDiff incorrectly? Or even more importantly, is timeDiff the value I should be giving to my update methodS?

Hahaha your mistake was re-initializing beforeTime, timeDiff, and sleep inside your while loop.
Put


long beforeTime = 0, timeDiff, sleep;

right before while(true) {
:stuck_out_tongue:

EDIT: Running your code, the player still didn’t move. Looking through the code, I found the problem to be in your move() in your Player class. Because timeDiff is a long, diving that by 1000 (an int) will return a long. timeDiff will be well below 1000 so dividing that by 1000 will return 0. You need to cast timeDiff into a double before dividing by 1000.


xPosition += xSpeed * ((double)timeDiff/1000);

AHHH Gothca… Ok so should it be

xPosition = (xPosition + ((xSpeed * (double)timeDiff) / 1000 ));

or

xPosition = (xPosition + (xSpeed * ((double)timeDiff) / 1000));

basically, should I multiply xSpeed and timediff then divide that result by 1000, or should I divide timediff by 1000, then multiply that result by xSpeed?

Both are the same thing but stick with dividing first.

If your xPosition is already defined as double, them both are the same. However if not and you cast it with (double) to keep the value, divide first then cast it to double and multiply it. That what I do to keep the line easy to read by other.

Thanks guys. Its working pretty well now. I just seem to be having an issue where when I run it from eclipse it looks ok. But I exported it as a Runnable jar to put on my website and opened it on another computer, the painting was off by about 10 pixels. Basically the right and bottom of the screen wasnt getting painted, it seemed like the rectangle that I was blanking the screen out with every loop was offset by a bit. Im guessing this is because Im using hard coded coordinates 800X400, and instead I should be using some sort of method that gets the size directly from the component? Im thinking this has to do with differences in the Frames on different operating systems.

Other than that, I just need to figure out how to get a sound clip to play when I press a button, and Im good to go

Could you show us your example of that painting offset?

There is a getAudioClip(URL url) method in Applet :slight_smile:
http://ra4king.is-a-geek.net/javadocs/java/applet/Applet.html

So can I just import applet and use the method?? Or does my actual game need to be an applet?

Also, I will post a screenshot of the painting problem once I get on another computer. Thanks again for all of this help. I am learning SO MUCH

Well if your game is not an Applet and you need a quick and dirty way of getting a sound file, there is a static method newAudioClip(URL url) in Applet so you can use that :slight_smile:

Glad to help ;D

Hey, Heres the screenshot of the game. See the unpainted bottom and right? The character kind of leaves a trail on it when walking…

crap, how do I post an image thats local on my pc?

http://file:///C:/Documents%20and%20Settings/wtsnadv/Desktop/scrn.bmp

You can’t insert local images. Try www.tinypic.com