Reputation: 23
I have key events and everything by my character(a circle) just refuses to move. I have searched all over for this and adapted people's solutions but it doesn't work. Just in case, I will post my full code here, so please help.
Main.java
package minwoo.main;
import javax.swing.JFrame;
public class Main extends JFrame {
// just to set up the game
public static void main(String[] args) {
JFrame start = new JFrame("space game");
start.setVisible(true);
start.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
start.setContentPane(new GamePanel());
start.pack();
start.setLocationRelativeTo(null);
}
}
GamePanel.java
package minwoo.main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable, KeyListener {
// size
public final static int WIDTH = 400;
public final static int HEIGHT = 400;
//player
Player player;
//the loop variables
private Thread thread;
private boolean running = false;
//image
BufferedImage image;
Graphics2D g;
int FPS = 30;
double avFPS;
//the constructor
public GamePanel() {
addKeyListener(this);
setPreferredSize(new Dimension(WIDTH,HEIGHT ));
setFocusable(true);
requestFocus();
player = new Player();
}
//functions
public void addNotify() {
super.addNotify();
if(thread == null) {
thread = new Thread(this); // declares the thread.
thread.start();
}
}
public void run() {
running = true;
image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_RGB);
g = (Graphics2D) image.getGraphics();
long startTime;
long waitTime;
long ms;
long targetTime = 1000/30; // shows how much is needed to get 30 ticks
long frameCount = 0;
long max_Frame = 30; // maximum amount of frames you are allowed to reach.
long totalTime = 0;
while(running) { // start of the game loop
startTime = System.nanoTime(); // takes note of the current time
update();
render();
draw();
// System.nanoTime() at this point takes note of current time, which
//is different from what it was few nanoseconds ago.
ms = (System.nanoTime() - startTime) / 1000000;
// shows how much time has passed, and it is converted to miliseconds.
waitTime = targetTime - ms;
/**
* let me give you an example.
* ms is 25 milliseconds, but my target is 30 seconds. To get to
* that target time, we have to give up 5 seconds.
* **/
if(waitTime < 0) { waitTime = 5; } //sets default if waitTime is
// negative.
try {
Thread.sleep(waitTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
totalTime += System.nanoTime() - startTime; // accumulates
// total time it took for the whole process.
frameCount++; // frame is counted
if(frameCount == max_Frame) {
avFPS = 1000.0 / ((totalTime / frameCount) / 1000000);
frameCount = 0;
totalTime =0;
}
}// end of the game loop
} // end of run()
@Override
public void keyTyped(KeyEvent e) {
}
private void update() {
player.update();
} // end of update()
private void render() {
g.setColor(Color.WHITE);
g.fillRect(0, 0,WIDTH,HEIGHT);
g.setColor(Color.BLACK);
g.drawString("FPS: " + avFPS,150,100);
player.draw(g);
}// end of render()
@Override
public void keyPressed(KeyEvent e) {
int Key = e.getKeyCode();
if(Key == KeyEvent.VK_RIGHT) {
player.Direction_X(Player.SPEED);
}
if(Key == KeyEvent.VK_LEFT) {
player.Direction_X(Player.SPEED);
}
if(Key == KeyEvent.VK_UP) {
player.Direction_Y(Player.SPEED);
}
if(Key == KeyEvent.VK_DOWN) {
player.Direction_Y(Player.SPEED);
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
if(e.getKeyCode() == KeyEvent.VK_RIGHT) {
player.Direction_X(Player.SPEED);
}
if(e.getKeyCode() == KeyEvent.VK_LEFT) {
player.Direction_X(-Player.SPEED);
}
if(e.getKeyCode() == KeyEvent.VK_UP) {
player.Direction_Y(Player.SPEED);
}
if(e.getKeyCode() == KeyEvent.VK_DOWN) {
player.Direction_Y(-Player.SPEED);
}
}
//draw()
private void draw() {
Graphics g2 = this.getGraphics();
g2.drawImage(image,0,0,null);
g2.dispose();
}// end of draw()
}// end of GamePanel class
Player.java
package minwoo.main;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
public class Player {
//fields
private int x;
private int y;
private int r;
private int dx;
private int dy;
public static final int SPEED = 5;
private int lives;
private Color character_Color = Color.WHITE;
private Color hit_Color = Color.RED;
// constructor
public Player() {
x = GamePanel.WIDTH / 2;
y = GamePanel.HEIGHT / 2;
r = 5;
dx = 0;
dy = 0;
lives = 3;
} // end of constructor
//movements
public void Direction_X(int speed) {
dx = speed;
}
public void Direction_Y(int speed)
{
dy = speed;}
//functions
public void update() {
move();
//to keep the bounds
if(x < r) { x = r;}
if(y < r) {y = r;}
if(x > GamePanel.WIDTH - r) { x = GamePanel.WIDTH - r;
}
if(y > GamePanel.HEIGHT - r) { y = GamePanel.HEIGHT - r; }
}// end of update()
private void move() {
x += dx;
y += dy;
}
public void draw(Graphics2D g) {
g.setColor(character_Color);
g.fillOval(dx, dy,2*r,2*r); // circle in the centre.
g.setStroke(new BasicStroke(3));
g.setColor(character_Color.darker());
g.drawOval(dx, dy,2*r,2*r);
g.setStroke(new BasicStroke(1));
}
}
Upvotes: 0
Views: 210
Reputation: 347204
Your basic problem is you're painting the delta values not the position values...
g.fillOval(dx, dy, 2 * r, 2 * r);
^---^---These are the deltas, not the position...
Other problems you will/may have...
getGraphics
instead of overriding paintComponent
. getGraphics
can return null
and anything you paint to it will be wiped clean the next time a paint cycle occurs. Swing uses a passive painting system and can trigger repaints without your interactionsKeyListener
. You will, generally, find it easier to use the Key Bindings API which doesn't suffer from the same focus issues that KeyListener
suffers fromThread
to update the game state, as it's possible that a repaint may occur while you're modifying the state and you will end up with a dirty paint.GamePanel.WIDTH
). If I change the size of the window, these value will have no meaning. Use empirical values instead, pass the actual width and height of the container to the move
methodkeyPressed
and keyReleased
calls are screwing with your movement code. It's possible to press Left and have the ball bounce right...same goes for the other directions, it's possible to have the ball bounce in the opposite direction before moving in the correct direction. As another example, if I hold down Left, the ball will move right...Take a look at
Upvotes: 1