So I'm trying to implement implement a game where overtime the player is hit by an asteroid, they loose a life. all i want to do is create an array of square that removes one square overtime the player is hit. for some reason i keep getting a "cannot find symbol error" when i try to x.draw the rectangle in the paintComponent method, and I don't understand why. Can anyone explain this?
package lightrunner;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import javax.swing.*;
import java.util.Random;
import java.awt.geom.Area;
import java.util.ArrayList;
import javax.swing.JMenuBar;
import javax.swing.Timer;
import java.util.Iterator;
import java.awt.geom.Rectangle2D;
class LightRunner
{
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600,520);
frame.setTitle("Light Runner");
frame.add(new GamePanel());
frame.setVisible(true);
}
public static class GamePanel extends JPanel
{
public java.util.List<Rectangle> lives;
Ship ship;
Asteroid asteroid;
Asteroid asteroid2;
Timer timer;
Graphics g;
// private final int MILLESECONDS_BETWEEN_FRAMES = 10;
Asteroid[] ast_array;
boolean isStar;
public GamePanel()
{
super();
setBackground(Color.black);
// menu();
initializeGameObjects();
addKeyListener(new ShipMover());
setFocusable(true);
}
public void initializeGameObjects()
{
ast_array = new Asteroid[8];
//asteroid = new Asteroid(250,250, "/Users/nicholascerillo/Desktop/asteroid.png");
// asteroid2 = new Asteroid(300,300, "/Users/nicholascerillo/Desktop/asteroid.png");
ship = new Ship(10, 164, "/Users/nicholascerillo/Desktop/ship.png");
timer = new Timer(10, new GameMotion());
//
for (int i = 0; i <= 7; i++)
{
Random rand = new Random();
int Astx = WIDTH + (i*200) + 200;
int Asty = rand.nextInt((600-0)) + 0;
// int star = rand.nextInt((10-0)) + 0;
ast_array[i] = new Asteroid(Astx,Asty);
}
lives = new ArrayList<Rectangle>();
lives.add(new Rectangle( 10, 10, 10, 10));
lives.add(new Rectangle( 10, 25, 10, 10));
lives.add(new Rectangle( 10, 30, 10, 10));
// GameMotion();
timer.start();
}
#Override
public void paintComponent(Graphics x)
{
//super();//paintComponent(x);
Graphics2D g2 = (Graphics2D)x;
ship.paint(g2);
g2.drawImage(ship.getShip(),ship.getX1(), ship.getY1(),this);
for(int r = 0; r < 7; r++)
{
g2.drawImage(ast_array[r].getImage(), ast_array[r].getX(), ast_array[r].getY(),null);
}
x.setColor(Color.RED);
for (Rectangle life : lives)
{
x.draw(life);
}
//asteroid.paint(g2);
}
private class GameMotion implements ActionListener
{
public GameMotion()
{
// light = new Timer(20,this);
}
public void actionPerformed(ActionEvent evt)
{
// light.start();
//checkBounds();
Iterator<Rectangle> it = lives.iterator();
// ship.BoundedY();
ship.move();
ast_array[0].moveAsteroid();
ast_array[1].moveAsteroid();
ast_array[2].moveAsteroid();
ast_array[3].moveAsteroid();
ast_array[4].moveAsteroid();
ast_array[5].moveAsteroid();
ast_array[6].moveAsteroid();
ast_array[7].moveAsteroid();
while(it.hasNext())
{
Rectangle life = it.next();
for(int p = 0; p < 7; p++)
{
ship.isHit(ast_array[p]);
if(ship.getHit())
{
it.remove();
}
}
}
repaint();
}
}
private class ShipMover implements KeyListener
{
public void keyPressed(KeyEvent evt) {
int key = evt.getKeyCode();
if (key == KeyEvent.VK_RIGHT )
{
ship.setSpeedX(5);
}
else if (key == KeyEvent.VK_LEFT)
{
ship.setSpeedX(-5);
}
else if(key == KeyEvent.VK_UP /*&& (ship.BoundedY())*/){
ship.setSpeedY(-5);
}
else if(key == KeyEvent.VK_DOWN /*&& (ship.BoundedY())*/){
ship.setSpeedY(5);
}
}
public void keyReleased(KeyEvent evt) {
int key = evt.getKeyCode();
if ((key == KeyEvent.VK_LEFT) || (key == KeyEvent.VK_RIGHT) ) {
ship.setSpeedX(0);
}
else if((key == KeyEvent.VK_UP) || (key == KeyEvent.VK_DOWN))
{
ship.setSpeedY(0);
}
}
public void keyTyped(KeyEvent evt) {
}
}
}
}
Related
When the code runs I get no errors. It runs all parts except for my keypress. Where something is going wrong.
import javax.swing.*;
import java.awt.event.*;
import java.util.Scanner;
// Inheriting the JFrame class
public class Main extends JFrame {
Scanner d = new Scanner(System.in);
//Defining the Frame
JFrame f;
char input;
int x = 250;
int y = 100;
//Constructor
Main()
{
ImageIcon p = new ImageIcon("Player.png");
JLabel b = new JLabel(p);
b.setBounds(x, y, 50, 50);
add(b);
System.out.println("started");
b.addKeyListener(new KeyListener() {
public void keyPressed(KeyEvent e) {
System.out.println("*Event Listener Run*");
input = e.getKeyChar();
if (input == 'w')
{
y-=50;
}
else if (input == 'a')
{
x-=50;
}
else if (input == 's')
{
y+=50;
}
else if (input == 'd')
{
x+=50;
}
System.out.println("Cords: "+x+","+y);
b.setBounds(x, y, 50, 50);
}
public void keyTyped(KeyEvent e){
}
public void keyReleased(KeyEvent e){
System.out.println("keyReleased");
}
});
//Set up Window
System.out.println("*setup window*");
setSize(800, 600);
setLayout(null);
setVisible(true);
System.out.println("*setup window done*");
}
public static void main(String[] args){
// Create the window
new Main();
}
}
I added error println's to see if some of the code isn't running, however it all is.
As #this_is_cat explained earlier, the listener needs to be on the JFrame and not on the JLabel.
Also, the use of setLayout(null) is not good practice, but was used here because we only have one component with which to work.
package keylistener1;
import java.awt.Dimension;
import java.awt.HeadlessException;
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
// Inheriting the JFrame class
public class KeyListener1 extends JFrame {
private static final String ICON_FILE_PATH = "btn_home.gif";
// Scanner d = new Scanner(System.in);
private JLabel label = new JLabel("image not found");
private JFrame jframe = new JFrame();
private int xpos = 250;
private int ypos = 250;
public KeyListener1() throws HeadlessException {
initFrame();
}
private JFrame initFrame() {
jframe.setLayout(null);
jframe.setPreferredSize(new Dimension(525, 525));
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setVisible(true);
jframe.setTitle("Key Listener");
// set up image icon
Class cls = this.getClass();
try (InputStream imageSource = cls.getResourceAsStream(ICON_FILE_PATH)) {
BufferedImage bi = ImageIO.read(imageSource);
ImageIcon p = new ImageIcon(bi);
setLabel(new JLabel(p));
getLabel().setBounds(getXpos(), getYpos(), 50, 50);
} catch (IOException ex) {
Logger.getLogger(KeyListener1.class.getName()).log(Level.SEVERE, null, ex);
}
initKeyListener();
jframe.add(getLabel());
jframe.pack();
System.out.println("Starting coordinates: " + getXpos() + "," + getYpos());
return jframe;
}
private void initKeyListener() {
getJframe().addKeyListener(new KeyAdapter() {
#Override
public void keyTyped(KeyEvent e) {
System.out.println("jf: " + e.getKeyChar());
char input = e.getKeyChar();
if (input == 'w') {
// ypos -= 50;
setYpos(getYpos() - 50);
} else if (input == 'a') {
// xpos -= 50;
setXpos(getXpos() - 50);
} else if (input == 's') {
// ypos += 50;
setYpos(getYpos() + 50);
} else if (input == 'd') {
// xpos += 50;
setXpos(getXpos() + 50);
}
System.out.println("New Coordinates: " + getXpos() + "," + getYpos());
getLabel().setBounds(getXpos(), getYpos(), 50, 50);
}
});
}
public JLabel getLabel() {
return label;
}
public void setLabel(JLabel label) {
this.label = label;
}
public int getXpos() {
return xpos;
}
public void setXpos(int xpos) {
this.xpos = xpos;
}
public int getYpos() {
return ypos;
}
public void setYpos(int ypos) {
this.ypos = ypos;
}
public JFrame getJframe() {
return jframe;
}
public void setJframe(JFrame jframe) {
this.jframe = jframe;
}
public static void main(String[] args) {
new KeyListener1();
}
}
When I use this code my screen will be empty. So that means
something is wrong with my paintComponent method. But what is wrong? And how do I fix it? My expected output was a dark gray rectangle, and an image.
Code:
package _47b3n.seg.main.engine;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import _47b3n.seg.main.frame.Frame;
public class Engine extends JPanel {
public int xOff;
public int yOff;
public int x;
public int y;
public int fpsInt = 199;
public boolean isRunning = true;
public FPS fps = new FPS();
public static void main(String [] args) {
Frame frame = new Frame();
frame.setFrame(800, 600, "Super easy game", "0.0.1");
new Engine();
}
public Engine() {
start();
}
public void move() {
x+=xOff;
y+=yOff;
}
public void start() {
Thread loop = new Thread () {
public void run() {
gameLoop();
addKeyListener(new keyInput());
}
};
loop.start();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(10, 10, 10, 10);
g.drawImage(new ImageIcon("Poppetje.jpg").getImage(), x, y, null);
}
public void gameLoop() {
while(isRunning) {
move();
repaint();
fps.update();
fpsInt++;
if (fpsInt == 200) {
System.out.println("[Console] " + fps.getFPS() + " FPS");
fpsInt = 0;
}
try {Thread.sleep(17);} catch (InterruptedException e) {e.printStackTrace();}
}
}
public class keyInput extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_W) {
yOff = -1;
}
if (key == KeyEvent.VK_S) {
yOff = 1;
}
if (key == KeyEvent.VK_A) {
yOff = -1;
}
if (key == KeyEvent.VK_D) {
xOff = 1;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_W) {
yOff = 0;
}
if (key == KeyEvent.VK_S) {
yOff = 0;
}
if (key == KeyEvent.VK_A) {
xOff = 0;
}
if (key == KeyEvent.VK_D) {
xOff = 0;
}
}
}
}
Thanks
Don't know if it is the only problem, but you never add the panel to the frame:
//new Engine();
Engine engine = new Engine();
frame.add(engine);
frame.setVisible(true);
I have the following code to show you:
public class Test extends JPanel implements ActionListener, KeyListener
{
Timer tm = new Timer(5, this);
int x = 0, y = 0, velX = 0, velY = 0;
public Test()
{
tm.start(); //starts the timer
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paint(Graphics g)
{
super.paint(g);
ImageIcon s = new ImageIcon("C:\\Users\\Owner\\Pictures\\Stick.jpg");
s.paintIcon(this,g,x,y);
}
public void actionPerformed(ActionEvent e)
{
if (x < 0)
{
velX = 0;
x = 0;
}
if (x > 630)
{
velX = 0;
x = 630;
}
if(y < 0)
{
velY = 0;
y = 0;
}
if(y > 430)
{
velY = 0;
y = 430;
}
x = x + velX;
y = y + velY;
repaint();
}
public void keyPressed(KeyEvent e)
{
int c = e.getKeyCode();
if (c == KeyEvent.VK_LEFT)
{
velX = -1;
velY = 0;
}
if(c == KeyEvent.VK_UP)
{
velX = 0;
velY = -1;
}
if(c == KeyEvent.VK_RIGHT)
{
velX = 1;
velY = 0;
}
if(c == KeyEvent.VK_DOWN)
{
velX = 0;
velY = 1;
}
}
public void keyTyped(KeyEvent e){}
public void keyReleased(KeyEvent e)
{
velX = 0;
velY = 0;
}
public static void main(String[] args)
{
Test t = new Test();
JFrame jf = new JFrame();
jf.setTitle("Tutorial");
jf.setSize(700, 600);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(t);
jf.setVisible(true);
}
My problem is I whenever the user holds the right arrow on the keyboard it changes an image, when the user lets go it goes back the the default image. Please tell me how to do that. I think it is a series of if statements in the Graphics class then calling them to the key input but I'm not quite sure. I am also using Eclipse. Thank You.
Override paintComponent instead of paint. See Performing Custom Painting and Painting in AWT and Swing for more details
Use the key bindings API instead of KeyListener, it will cause you less issues. See How to Use Key Bindings for more details
Essentially, you could just have a Image as a class instance field, which was painted by the paintComponent method. When the key was pressed, you would change the image to the "move image" and when it was released, change it back to the "default image"
Updated with example
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.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
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 Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface Mover {
public enum Direction {
LEFT, RIGHT, NONE;
}
public void setDirection(Direction direction);
public Direction getDirection();
}
public class TestPane extends JPanel implements Mover {
private BufferedImage left;
private BufferedImage right;
private BufferedImage stand;
private BufferedImage current;
private Direction direction = Direction.NONE;
private int xPos;
private int yPos;
public TestPane() {
try {
left = ImageIO.read(getClass().getResource("/Left.png"));
right = ImageIO.read(getClass().getResource("/Right.png"));
stand = ImageIO.read(getClass().getResource("/Stand.png"));
current = stand;
xPos = 100 - (current.getWidth() / 2);
yPos = 100 - (current.getHeight() / 2);
} catch (IOException exp) {
exp.printStackTrace();
}
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(this, Direction.LEFT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.left", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true), new MoveAction(this, Direction.NONE));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "move.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(this, Direction.RIGHT));
bindKeyStrokeTo(WHEN_IN_FOCUSED_WINDOW, "stop.right", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true), new MoveAction(this, Direction.NONE));
Timer timer = new Timer(40, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
updatePosition();
repaint();
}
});
timer.start();
}
protected void bindKeyStrokeTo(int condition, String name, KeyStroke keyStroke, Action action) {
InputMap im = getInputMap(condition);
ActionMap am = getActionMap();
im.put(keyStroke, name);
am.put(name, action);
}
#Override
public Direction getDirection() {
return direction;
}
#Override
public void setDirection(Direction direction) {
this.direction = direction;
}
protected void updatePosition() {
switch (getDirection()) {
case LEFT:
current = left;
xPos -= 1;
break;
case RIGHT:
current = right;
xPos += 1;
break;
case NONE:
current = stand;
break;
}
if (xPos < 0) {
xPos = 0;
current = stand;
} else if (xPos + current.getWidth() > getWidth()) {
current = stand;
xPos = getWidth() - current.getWidth();
}
}
#Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.drawImage(current, xPos, yPos, this);
g2d.dispose();
}
}
public class MoveAction extends AbstractAction {
private Mover mover;
private Mover.Direction direction;
public MoveAction(Mover mover, Mover.Direction direction) {
this.mover = mover;
this.direction = direction;
}
#Override
public void actionPerformed(ActionEvent e) {
mover.setDirection(direction);
}
}
}
So i have created an extended version of JPanel and unfortunately it doesn't respond to any key typing. Could you tell me what the problem is? I searched all the others posts but i couldn't find my error.
public class MyPanel extends JPanel implements ActionListener,KeyListener{
Timer tm=new Timer(5,this);
int x=0,y=0 ,velX=0, velY=0;
public MyPanel(){
tm.start();
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.fillRect(0,0,this.getWidth(),this.getHeight());
g.setColor(Color.RED);
g.fillRect(x,30,50,30);
}
public void actionPerformed(ActionEvent e){
if(x<0||x>370)
velX=-velX;
if(y<0||y>370)
velY=-velY;
y=y+velY;
x=x+velX;
repaint();
}
public void keyPressed(KeyEvent e){
int c=e.getKeyCode();
System.out.println("Cascsadas");
if(c==KeyEvent.VK_LEFT){
velX=-1;
velY=0;
}
if(c==KeyEvent.VK_UP){
velX=0;
velY=-1;
}
if(c==KeyEvent.VK_RIGHT){
velX=1;
velY=0;
}
if(c==KeyEvent.VK_DOWN){
velX=0;
velY=1;
}
}
public void keyTyped(KeyEvent e){};
public void keyReleased(KeyEvent e){};
}
And the class where i am using this JPanel is:
public class Tester
{
public static void main(String[] args){
MyPanel t=new MyPanel();
JFrame jf=new JFrame();
jf.setTitle("Tutorial");
jf.setVisible(true);
jf.setSize(600,400);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().add(t,BorderLayout.CENTER);
}
}
Your code doesn't work because your panel doesn't have focus.
The requestFocusInWindow() method only works when the panel is displayed on GUI is visible. Invoking the method in the constructor has no effect (and is not needed).
However, the real problem is that you add the panel to the frame AFTER the frame is visible. Your code should be something like:
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.getContentPane().add(t,BorderLayout.CENTER);
jf.setSize(600,400);
jf.setVisible(true);
The key is adding the panel to the content pane before the frame is made visible. It also doesn't make sense to make the frame visible and then change its size, so I always make the frame visiable as the last statement.
I searched all the others posts but i couldn't find my error
I find that hard to believe. This question is asked daily and we always recommend to use Key Bindings, so why are you still trying to use a KeyListener?
Swing was designed to be used with Key Bindings. See Motion Using the Keyboard for more information and an approach that does use Key Bindings.
I have posted an answer in the same context here
Diagonal movement of a simple sprite (up-down-left-right movement already done).
This post about KeyListener will help you to understand it more.
Here is the sample code to start:
(moving in all the direction left,right,top,bottom and diagonally also)
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 java.util.Set;
import java.util.TreeSet;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Apple extends JPanel implements ActionListener, KeyListener {
Timer timer = new Timer(5, this); // this refers to actionListener
int x = 0, velx = 0;
int y = 0, vely = 0;
public Apple() {
timer.start();
addKeyListener(this); // this refers to keylistener
setFocusable(true);
setFocusTraversalKeysEnabled(false); // because we are not using the shift or ctrl key
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
// outer rectangle
g.setColor(Color.BLUE);
g.fillRect(x, y, 50, 50);
}
public static void main(String[] args) {
Apple apple = new Apple();
apple.setSize(500, 500);
JFrame frame = new JFrame();
frame.add(apple);
frame.setLayout(null);
frame.setTitle("The Game");
frame.setSize(500, 500);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
#Override
// animates rectangle
public void actionPerformed(ActionEvent arg0) {
if (x < 0) {
velx = 0;
x = 0;
}
if (x > 450) {
velx = 0;
x = 450;
}
if (y < 0) {
vely = 0;
y = 0;
}
if (y > 450) {
vely = 0;
y = 450;
}
x = x + velx;
y = y + vely;
repaint();
}
// Set of currently pressed keys
private final Set<Integer> pressed = new TreeSet<Integer>();
#Override
public void keyPressed(KeyEvent arg0) {
System.out.println(KeyEvent.VK_LEFT + "-" + KeyEvent.VK_RIGHT + "-" + KeyEvent.VK_UP + "-"
+ KeyEvent.VK_DOWN);
int c = arg0.getKeyCode();
pressed.add(c);
if (pressed.size() > 1) {
Integer[] array = pressed.toArray(new Integer[] {});
if (array[0] == KeyEvent.VK_LEFT && array[1] == KeyEvent.VK_UP) {
velx = -4;
vely = -4;
} else if (array[0] == KeyEvent.VK_UP && array[1] == KeyEvent.VK_RIGHT) {
velx = 4;
vely = 4;
} else if (array[0] == KeyEvent.VK_RIGHT && array[1] == KeyEvent.VK_DOWN) {
velx = 4;
vely = -4;
} else if (array[0] == KeyEvent.VK_LEFT && array[1] == KeyEvent.VK_DOWN) {
velx = -4;
vely = 4;
}
} else {
if (c == KeyEvent.VK_LEFT) {
velx = -4;
vely = 0;
} else if (c == KeyEvent.VK_RIGHT) {
velx = 4;
vely = 0;
} else if (c == KeyEvent.VK_UP) {
velx = 0;
vely = -4;
} else if (c == KeyEvent.VK_DOWN) {
velx = 0;
vely = 4;
}
}
}
#Override
public void keyReleased(KeyEvent arg0) {
velx = 0;
vely = 0;
pressed.remove(Integer.valueOf(arg0.getKeyCode()));
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
Hi, I'm developing a snake game. To create the snake I'm using ArrayList. While moving the snake I'm getting the following error: "java.lang.IndexOutOfBoundsException: Index: 3, Size: 3". Below is my program. In Snake.update() method I have problem.
Game.java:
import javax.swing.JFrame;
#SuppressWarnings("serial")
public class Game extends JFrame {
public Game(){
add(new GamePanel());
setTitle("Game Test3");
setVisible(true);
setAlwaysOnTop(true);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
pack();
}
public static void main(String[] args) {
new Game();
}
}
GamePanel.java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class GamePanel extends JPanel implements Runnable, KeyListener {
public static int width = 300;
public static int height = 400;
private Thread thread;
private Image image;
private Graphics2D g;
private Food food;
private Snake snake;
public GamePanel() {
setPreferredSize(new Dimension(width, height));
setFocusable(true);
}
public void addNotify() {
super.addNotify();
if (thread == null) {
thread = new Thread(this);
thread.start();
}
addKeyListener(this);
}
public void run() {
image = createImage(width, height);
g = (Graphics2D) image.getGraphics();
RenderingHints reneringHints = new RenderingHints(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHints(reneringHints);
food = new Food();
snake = new Snake();
while (true) {
gameRender();
gameUpdate();
gameDraw();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void gameDraw() {
Graphics2D g2 = (Graphics2D) getGraphics();
g2.drawImage(image, 0, 0, this);
g2.dispose();
}
private void gameRender() {
g.setColor(Color.black);
g.fillRect(0, 0, width, height);
// food drawing
food.draw(g);
// snake drawing
snake.draw(g);
}
private void gameUpdate() {
food.update();
snake.update();
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
snake.setLeft(true);
}
if (key == KeyEvent.VK_RIGHT) {
snake.setRight(true);
}
if (key == KeyEvent.VK_UP) {
snake.setUp(true);
}
if (key == KeyEvent.VK_DOWN) {
snake.setDown(true);
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
snake.setLeft(false);
}
if (key == KeyEvent.VK_RIGHT) {
snake.setRight(false);
}
if (key == KeyEvent.VK_UP) {
snake.setUp(false);
}
if (key == KeyEvent.VK_DOWN) {
snake.setDown(false);
}
}
public void keyTyped(KeyEvent e) {
}
}
//snake body
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.util.ArrayList;
public class Snake {
private int x;
private int y;
private int r;
int body;
Rectangle rectangle;
ArrayList<Rectangle> rc = new ArrayList<Rectangle>();
private boolean left;
private boolean right;
private boolean up;
private boolean down;
public Snake() {
x = 150;
y = 150;
r = 4;
body = 3;
for (int i = 0; i < body; i++) {
rc.add(new Rectangle(x - i * r * 3, y, r * 3, r * 3));
}
}
public void draw(Graphics2D g) {
for (int i = 0; i < body; i++) {
if (i == 0) {
g.setColor(Color.red);
} else {
g.setColor(Color.green);
}
g.fillOval(rc.get(i).x, rc.get(i).y, rc.get(i).width,
rc.get(i).height);
}
}
public void update() {
for (int i = body; i > 0; i--) {
rc.set(i, rc.get(i - 1));
}
if (left) {
rc.get(0).x -= 1;
System.out.println("vbnv");
}
if (right) {
rc.get(0).x += 1;
}
if (up) {
rc.get(0).y -= 1;
}
if (down) {
rc.get(0).y += 1;
}
}
public void setLeft(boolean b) {
left = b;
}
public void setRight(boolean b) {
right = b;
}
public void setUp(boolean b) {
up = b;
}
public void setDown(boolean b) {
down = b;
}
}
Without reading the code I can tell that somewhere you are trying to get non-existent element. Read the message of exception, it tells you that your ArrayList consist of three elements (which means that the last element has index of 2) while you try to get the element with index of 3.
Update: yes, the problem is here:
for (int i = body; i > 0; i--) {
rc.set(i, rc.get(i - 1));
}
body equals to 3, and rc after the constructor invocation has the size of 3. set method replaces already existing element with the specified index (see the documentation), but element with index of 3 doesn't exist. That's the cause of an exception.
Your problem is in this loop:
for (int i = body; i > 0; i--) {
rc.set(i, rc.get(i - 1));
}
During the first iteration around this loop, you will be calling:
rc.set(3, <someValue>);
3 is not a valid index in a list of length 3. The largest valid index is 2.
for (int i = body; i > 0; i--)
In this for, i is assigned with the value of body(which is 3) and it looks like your ArrayList rc has only 3 elements in it. Therefore, when you try to access the index 3 using rc.set(3, something), its giving the IndexOutOfBoundsException.
Always remember, whether it is Arrays or ArrayList, the max possible index accessible in them is always array.length - 1 and ArrayList.size() - 1.