So I have this little project where I make the mario jump. But I can't figure out how to repaint it. If I do it in the Main class after a click, then the whole jumping will be very jerky.
I tried to do it at the end of my jump function but that did not work too.
Here is my code:
Main:
package klassid;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
public class Main extends JComponent implements KeyListener, ActionListener{
static Hero hero;
Timer t = new Timer(500,this);
public static void main(String[] args) {
JFrame aken = new JFrame("Simple jumping simulator");
aken.setSize(600, 600);
aken.getContentPane().setBackground(new Color(255,255,255));
aken.getContentPane().add(new Main());
aken.setVisible(true);
aken.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
hero.the_jump();
}
public Main(){
addKeyListener(this);
setFocusable(true);
t.start();
hero = new Hero(0, 320);
}
public void paintComponent(Graphics g){
hero.render(g, this);
g.setColor(Color.GREEN);
g.fillRect(0, 550, 600, 2);
}
#Override
public void keyPressed(KeyEvent e) {
hero.move(e.getKeyCode());
}
public void keyReleased(KeyEvent e) {
hero.move2(e.getKeyCode());
}
public void keyTyped(KeyEvent e) {}
public void actionPerformed(ActionEvent e) {}
}
And my Hero class:
package klassid;
import java.awt.Toolkit;
import java.awt.Image;
import java.awt.Graphics;
public class Hero {
static Main main;
int y;
Image pilt = Toolkit.getDefaultToolkit().getImage("../mario.png");
private double height = 0, speed = 4;
public static final double gravity = 9.81;
private double x = 25;
private boolean left = false, right = false, up = false;
public Hero(int x, int y){
this.x = x;
this.y = y;
}
public void render(Graphics g, Main pohiKlass){
g.drawImage(pilt, (int) (x), (int) (500-(height*100)), 50, 50, pohiKlass);
}
public void the_jump() {
long previous = 0, start = 0;
while(true){
start= System.nanoTime();
if(previous != 0 && up){
double delta = start - previous;
height += (delta/1000000000) * speed;
speed -= (delta/1000000000) * gravity;
}
if(left)
x -= 3;
if(right)
x += 3;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(height < 0){
height = 0;
speed = 4;
up = false;
}
previous = start;
repaint();
}
}
public void move(int i){
if(i == 38)
up=true;
if(i == 37)
left=true;
if(i == 39)
right=true;
}
public void move2(int i){
if(i == 37)
left=false;
if(i == 39)
right=false;
}
}
I also tried to access the paintComponent in the_jump function but it did not work as I have no idea what kind of a parameter it expects.
How is this mess solvable?
The first line in your paintComponent method should be:
super.paintComponent(g);
JComponent will do a lot of things for you, but you need to explicitly call the super class method to do so. Take a look at the Oracle Documentation here.
You could call repaint() in your actionPerformed method, if you decrease the timer value to something very low. This will give you "continuous" repainting (as many times a second as you can reasonably perform).
Related
I am new to java code that is fresh code (I used to make minecraft mods) and I am trying to create a simple pong game. I have everything I believe I need for the game to play properly however it seems that the main game class is not calling the other classes when I need it to. Is there anything wrong here that you can see that I am missing? It would be a really great help.
Main Game Class
package crim.pong.main;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class Game extends JPanel{
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
Ball ball = new Ball(this);
Racquet racquet = new Racquet(this);
private void moveBall(){
ball.move();
racquet.move();
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.fillOval(x, y, 30, 30);
ball.paint(g2d);
racquet.paint(g2d);
}
public void gameOver(){
JOptionPane.showMessageDialog(this, "Game Over", "Game Over", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main(String[] args) throws InterruptedException{
JFrame frame = new JFrame("Pong");
Game game = new Game();
frame.add(game);
frame.setSize(300, 400);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while(true){
game.moveBall();
game.repaint();
Thread.sleep(10);
}
}
}
Keyboard class
package crim.pong.main;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class KeyboardInput extends JPanel{
public KeyboardInput(){
KeyListener listener = new MyKeyListener();
addKeyListener(listener);
setFocusable(true);
}
public static void main(String[] args){
JFrame frame = new JFrame("Pong");
KeyboardInput keyboardInput = new KeyboardInput();
frame.add(keyboardInput);
frame.setSize(200, 200);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public class MyKeyListener implements KeyListener{
#Override
public void keyTyped(KeyEvent e){
}
#Override
public void keyPressed(KeyEvent e){
System.out.println("keyPressed="+KeyEvent.getKeyText(e.getKeyCode()));
}
#Override
public void keyReleased(KeyEvent e){
System.out.println("keyReleased="+KeyEvent.getKeyText(e.getKeyCode()));
}
}
}
Ball class
package crim.pong.main;
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Ball {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int xa = 1;
int ya = 1;
private Game game;
public Ball(Game game){
this.game = game;
}
void move(){
if(x + xa < 0)
xa = 1;
if(x + xa > game.getWidth() - DIAMETER)
xa = -1;
if(y + ya < 0)
ya = 1;
if(y + ya > game.getHeight() - DIAMETER)
game.gameOver();
if(collision()){
ya = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x - xa;
y = y - ya;
}
private boolean collision(){
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g){
g.fillOval(x, y, 30, 30);
}
public Rectangle getBounds(){
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
Racquet class
package crim.pong.main;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Racquet {
private static final int Y = 330;
private static final int WIDTH = 60;
private static final int HEIGHT = 20;
int x = 0;
int xa = 0;
private Game game;
public Racquet(Game game){
this.game = game;
}
public void move(){
if(x + xa > 0 && x + xa < game.getWidth() - 60)
x = xa + xa;
}
public void paint(Graphics2D g){
g.fillRect(x, 330, 60, 10);
}
public void keyReleased(KeyEvent e){
xa = 0;
}
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == KeyEvent.VK_LEFT)
xa = -1;
if(e.getKeyCode() == KeyEvent.VK_RIGHT)
xa = 1;
}
public Rectangle getBounds(){
return new Rectangle(x, Y, WIDTH, HEIGHT);
}
public int getTopY(){
return Y;
}
}
As mentioned in the comments you have 2 main class files. This is wrong.
A class with a 'main' function is the entry point of the program and obviously there can be only one entry point and presumably you have set this as 'Game'.
KeyboardInput should also not try to create a new JFrame. You only need one and it should be created by your 'Game' class.
If you want to keep the keyboard input in a seperate class then you want 'KeyboardInput' to implement KeyListener directly and then add it to the jframe created by 'Game', e.g.
(In 'Game')
KeyboardInput listener = new KeyboardInput();
addKeyListener(listener);
(In 'KeyboardInput')
public class KeyboardInput implements KeyListener
{
public void keyTyped(KeyEvent e){
//... etc etc
I have a hard time locating why I am returned a nullpointer on this piece of code:
import java.awt.Graphics2D;
import java.awt.Rectangle;
public class Move {
private static final int DIAMETER = 30;
int x = 0;
int y = 0;
int x_1 = 1;
int y_1 = 1;
private GameStart game;
public void Ball(GameStart game) {
this.game = game;
}
void moveBall() {
if (x + x_1 < 0) {
x_1 = 1;
}
if (x + x_1 > game.getWidth() - DIAMETER) {
x_1 = -1;
}
if (y + y_1 < 0) {
y_1 = 1;
}
if (y + y_1 > game.getHeight() - DIAMETER) {
game.gameOver();
}
if (collision()) {
y_1 = -1;
y = game.racquet.getTopY() - DIAMETER;
}
x = x + x_1;
y = y + y_1;
}
private boolean collision() {
return game.racquet.getBounds().intersects(getBounds());
}
public void paint(Graphics2D g) {
g.fillOval(x, y, 30, 30);
}
public Rectangle getBounds() {
return new Rectangle(x, y, DIAMETER, DIAMETER);
}
}
And the GameStart class is here:
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
#SuppressWarnings("serial")
public class GameStart extends JPanel {
Move move_ball = new Move();
Racquet racquet = new Racquet(this);
public GameStart() {
addKeyListener(new MyKeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
racquet.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
racquet.keyPressed(e);
}
});
setFocusable(true);
}
private void move() {
move_ball.moveBall();
racquet.move();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D graphics = (Graphics2D) g;
graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
move_ball.paint(graphics);
racquet.paint(graphics);
}
public void gameOver() {
JOptionPane.showMessageDialog(this, "Spil slut", "Du tabte", JOptionPane.YES_NO_OPTION);
System.exit(ABORT);
}
public static void main (String[] args) throws InterruptedException {
JFrame mainWindow = new JFrame("Matematikken");
GameStart game = new GameStart();
mainWindow.add(game);
mainWindow.setSize(300, 400);
mainWindow.setVisible(true);
mainWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
while (true) {
game.move();
game.repaint();
Thread.sleep(10);
}
}
}
I am getting a nullpointer on the line if (x + x_1 > game.getWidth() - DIAMETER) {. I am using .getWidth() in the samme manner in another class and it Works fine - but for some reason it wont in this. I've tried printing the result but that is just another nullpointer. I know i am missing something but I cannot locate it.
You are not calling
public void Ball(GameStart game) {
this.game = game;
}
That's why in your Move class, GameStart is still null.
Seems like you wanted that method
public void Ball(GameStart game) { this.game = game; }
to actually be a constructor:
public Move(GameStart game) { this.game = game; }
And then, you must use this constructor (as there is no no-arg constructor anymore) when instantiating a Move:
Move move_ball = new Move(this);
You have not yet set the member variable game of the instance move_ball of the type Move to a value so it is null and therefore throws a NullPointerException.
You'll want to instantiate this member variable, for example by calling move_ball.Ball(<some Game instance>).
Also, please don't let methods which are not constructors start with a capital and please use camelCase throughout instead of switching between name formatting. It makes your code hard to read.
You do not pass GameStart to Move via your Ball method. It is very misleading name. It should be setGame or something else.
You should make a constructor for the Move class, which takes the game as a parameter, and store that parameter in a variable within the class.
Example:
Public Move(GameStart mygame){
game = mygame;
}
This should allow you to use the methods of the game from which you are creating the move. It will basically replace the "Ball" method you have.
I'm trying to make a program in java that involves making an object move constantly from a single key press. Think Pacman, where you press up once and Pacman continues to go up until you press another key. I want to keep the code simple if possible. My original movement (one keypress = one movement) is like this:
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_A){
x -= 5;
}
if(keyCode == e.VK_D){
x += 5;
}
if(keyCode == e.VK_W){
y -= 5;
}
if(keyCode == e.VK_S){
y += 5;
}
}
The x and y in values are the position of an oval. This works perfectly, but I want it to keep moving after I press the key only once, instead of having to hold it to keep the movement going. I tried a while loop with a boolean parameter that moves while true and doesn't while false, but as soon as I activate the loop, it freezes the program. Here's an example of that bit of code:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT && moveL==false){
moveL=true;
moveR=false;
moveU=false;
moveD=false;
while(moveL){
x--;
}
}
Please help me figure this out, I've been trying and looking around for days now. I appreciate any help you guys can give. Thanks.
The basic concept revolves around this idea of a "delta" or "change" value. This value is then applied to the state you want to change by either incrementing or decrementing the state value by it.
Because of the nature of Swing, you can't block the Event Dispatching Thread, otherwise you end up preventing from processing incoming events (such as paint and key events).
Equally, you should never try and update any UI component (or state variable that might effect the UI) from any thread other then the EDT.
While there are tricks you can apply to facilitate these requirements, the simplest is to use a javax.swing.Timer, which triggers a actionPerformed event on a regular bases within the EDT.
When this occurs you "update" all the elements by the prescribed amount and repaint the screen.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacManTest {
public static void main(String[] args) {
new PacManTest();
}
public PacManTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacMan {
private int x;
private int y;
private int deltaX;
private int deltaY;
private BufferedImage sprite;
public PacMan() {
try {
sprite = ImageIO.read(new File("PacMan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void move(int x, int y) {
deltaX = x;
deltaY = y;
}
public void update(MazePane pane) {
x += deltaX;
y += deltaY;
if (x + sprite.getWidth() > pane.getWidth()) {
x = pane.getWidth() - sprite.getWidth();
} else if (x < 0) {
x = 0;
}
if (y + sprite.getHeight() > pane.getHeight()) {
y = pane.getHeight() - sprite.getHeight();
} else if (y < 0) {
y = 0;
}
}
public void paint(MazePane pane, Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
float angle = 0;
if (deltaX != 0) {
angle = deltaX > 0 ? 0 : 180;
} else if (deltaY != 0) {
angle = deltaY > 0 ? 90 : 270;
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2);
g.setTransform(t);
g.drawImage(sprite, 0, 0, pane);
g.dispose();
}
}
public class MazePane extends JPanel {
private PacMan pacMan;
public MazePane() {
pacMan = new PacMan();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pacMan.update(MazePane.this);
repaint();
}
});
timer.start();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
am.put("left", new MoveAction(pacMan, -4, 0));
am.put("right", new MoveAction(pacMan, 4, 0));
am.put("up", new MoveAction(pacMan, 0, -4));
am.put("down", new MoveAction(pacMan, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
pacMan.paint(this, g2d);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int deltaX;
private int deltaY;
private PacMan pacMan;
public MoveAction(PacMan pacMan, int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.pacMan = pacMan;
}
#Override
public void actionPerformed(ActionEvent e) {
pacMan.move(deltaX, deltaY);
}
}
}
}
I would also recommend that you take the time to learn about Key Bindings, KeyListener suffer from focus issues, which key bindings are capable of addressing...
You need to process the move in a separate thread. I.e.:
public class Pacman implements Runnable
{
public void run(){
//moving code, i.e. in a while loop
//every move will notify the EDT:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
//update the Swing here - i.e. move Pacman
}
}
}
public void startMoving(){
new Thread(this).start();
}
//more methods to set speed, direction, etc...
}
Then you keep a reference to an instance of Pacman class in your Gui class and respond to various key presses by changing pacman's parameters:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN...
}
//etc... more logic
}
I'm trying to make a program in java that involves making an object move constantly from a single key press. Think Pacman, where you press up once and Pacman continues to go up until you press another key. I want to keep the code simple if possible. My original movement (one keypress = one movement) is like this:
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_A){
x -= 5;
}
if(keyCode == e.VK_D){
x += 5;
}
if(keyCode == e.VK_W){
y -= 5;
}
if(keyCode == e.VK_S){
y += 5;
}
}
The x and y in values are the position of an oval. This works perfectly, but I want it to keep moving after I press the key only once, instead of having to hold it to keep the movement going. I tried a while loop with a boolean parameter that moves while true and doesn't while false, but as soon as I activate the loop, it freezes the program. Here's an example of that bit of code:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT && moveL==false){
moveL=true;
moveR=false;
moveU=false;
moveD=false;
while(moveL){
x--;
}
}
Please help me figure this out, I've been trying and looking around for days now. I appreciate any help you guys can give. Thanks.
The basic concept revolves around this idea of a "delta" or "change" value. This value is then applied to the state you want to change by either incrementing or decrementing the state value by it.
Because of the nature of Swing, you can't block the Event Dispatching Thread, otherwise you end up preventing from processing incoming events (such as paint and key events).
Equally, you should never try and update any UI component (or state variable that might effect the UI) from any thread other then the EDT.
While there are tricks you can apply to facilitate these requirements, the simplest is to use a javax.swing.Timer, which triggers a actionPerformed event on a regular bases within the EDT.
When this occurs you "update" all the elements by the prescribed amount and repaint the screen.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class PacManTest {
public static void main(String[] args) {
new PacManTest();
}
public PacManTest() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new MazePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PacMan {
private int x;
private int y;
private int deltaX;
private int deltaY;
private BufferedImage sprite;
public PacMan() {
try {
sprite = ImageIO.read(new File("PacMan.png"));
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void move(int x, int y) {
deltaX = x;
deltaY = y;
}
public void update(MazePane pane) {
x += deltaX;
y += deltaY;
if (x + sprite.getWidth() > pane.getWidth()) {
x = pane.getWidth() - sprite.getWidth();
} else if (x < 0) {
x = 0;
}
if (y + sprite.getHeight() > pane.getHeight()) {
y = pane.getHeight() - sprite.getHeight();
} else if (y < 0) {
y = 0;
}
}
public void paint(MazePane pane, Graphics2D g2d) {
Graphics2D g = (Graphics2D) g2d.create();
float angle = 0;
if (deltaX != 0) {
angle = deltaX > 0 ? 0 : 180;
} else if (deltaY != 0) {
angle = deltaY > 0 ? 90 : 270;
}
AffineTransform t = new AffineTransform();
t.translate(x, y);
t.rotate(Math.toRadians(angle), sprite.getWidth() / 2, sprite.getHeight() / 2);
g.setTransform(t);
g.drawImage(sprite, 0, 0, pane);
g.dispose();
}
}
public class MazePane extends JPanel {
private PacMan pacMan;
public MazePane() {
pacMan = new PacMan();
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pacMan.update(MazePane.this);
repaint();
}
});
timer.start();
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
am.put("left", new MoveAction(pacMan, -4, 0));
am.put("right", new MoveAction(pacMan, 4, 0));
am.put("up", new MoveAction(pacMan, 0, -4));
am.put("down", new MoveAction(pacMan, 0, 4));
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
pacMan.paint(this, g2d);
g2d.dispose();
}
public class MoveAction extends AbstractAction {
private int deltaX;
private int deltaY;
private PacMan pacMan;
public MoveAction(PacMan pacMan, int deltaX, int deltaY) {
this.deltaX = deltaX;
this.deltaY = deltaY;
this.pacMan = pacMan;
}
#Override
public void actionPerformed(ActionEvent e) {
pacMan.move(deltaX, deltaY);
}
}
}
}
I would also recommend that you take the time to learn about Key Bindings, KeyListener suffer from focus issues, which key bindings are capable of addressing...
You need to process the move in a separate thread. I.e.:
public class Pacman implements Runnable
{
public void run(){
//moving code, i.e. in a while loop
//every move will notify the EDT:
SwingUtilities.invokeLater(new Runnable(){
public void run(){
//update the Swing here - i.e. move Pacman
}
}
}
public void startMoving(){
new Thread(this).start();
}
//more methods to set speed, direction, etc...
}
Then you keep a reference to an instance of Pacman class in your Gui class and respond to various key presses by changing pacman's parameters:
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT){
pacman.newDirection(LEFT); //for exmaple, enum with direction LEFT, RIGHT, UP, DOWN...
}
//etc... more logic
}
I'm kind of a beginner when it comes to java programming, and I have a project in school where I'm going to create a game much like Icy Tower. And my question is, how am I going to write to make the character stand on the ground and be able to jump up on objects?
Here's my code so far:
Part one
package Sprites;
import java.awt.Image;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class jumper {
private String jump = "oka.png";
private int dx;
private int dy;
private int x;
private int y;
private Image image;
public jumper() {
ImageIcon ii = new ImageIcon(this.getClass().getResource(jump));
image = ii.getImage();
x = 50;
y = 100;
}
public void move() {
x += dx;
y += dy;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Image getImage() {
return image;
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = -5;
ImageIcon ii = new ImageIcon(this.getClass().getResource("oki.png"));
image = ii.getImage();
}
if (key == KeyEvent.VK_RIGHT){
dx = 5;
ImageIcon ii = new ImageIcon(this.getClass().getResource("oka.png"));
image = ii.getImage();
}
if (key == KeyEvent.VK_SPACE) {
dy = -5;
}
if (key == KeyEvent.VK_DOWN) {
dy = 5;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
dx = 0;
}
if (key == KeyEvent.VK_RIGHT){
dx = 0;
}
if (key == KeyEvent.VK_SPACE) {
dy = 0;
}
if (key == KeyEvent.VK_DOWN) {
dy = 0;
}
}
}
Part two
package Sprites;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.JPanel;
import javax.swing.Timer;
public class board extends JPanel implements ActionListener {
private Timer klocka;
private jumper jumper;
public board() {
addKeyListener(new TAdapter());
setFocusable(true);
setBackground(Color.WHITE);
setDoubleBuffered(true);
jumper = new jumper();
klocka = new Timer(5, this);
klocka.start();
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D)g;
g2d.drawImage(jumper.getImage(), jumper.getX(), jumper.getY(), this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void actionPerformed(ActionEvent e) {
jumper.move();
repaint();
}
private class TAdapter extends KeyAdapter {
public void keyReleased(KeyEvent e) {
jumper.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
jumper.keyPressed(e);
}
}
}
Part three
package Sprites;
import javax.swing.JFrame;
public class RType extends JFrame {
public RType() {
add(new board());
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
setTitle("R - type");
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
new RType();
}
}
I really appreciate all the help I can get!
This might help. It's a set of tutorials aimed at helping people make tile-based games. Including side-on platform games. See http://www.tonypa.pri.ee/tbw/tut07.html. By the way, you're doing quite intensive image-loading stuff in the character movement methods. Don't do that. Cache the images first. Also, you can double-buffer your Canvas to make it smooth. See the code here for details.