When I try to control my character with the arrow keys, everything works fine but after a while I get this error:
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
and then
at java.awt.AWTEventMulticaster.keyPressed(AWTEventMulticaster.java:249)
multiple times. The class that I have isn't even 249 lines of code long so I don't know where to look for the problem. My code is very messy right now but I'll post it if it helps anyone come up with the answer.
import javax.swing.JButton;
import javax.swing.JComponent;
import java.awt.Graphics;
import javax.swing.JFrame;
import java.awt.image.*;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
public class mainFrame extends JPanel implements Runnable, KeyListener {
static boolean gameIsRunning = false;
static final int TARGET_FPS = 1;
static int x = 100;
static int y = 100;
static long startTime = 0;
static long elapsedTime = 0;
static long waitTime = 0;
JFrame window = new JFrame("Out from Eden");
JPanel panel = new JPanel();
getResources get = new getResources();
BufferedImage player = get.getImg("player");
static int playerVal = 0;
static int i = 0;
static String currentState = "";
static int lastFacing = 0;
public void createFrame() {
gameIsRunning = true;
gameStart();
}
public void setGame(boolean game) {
gameIsRunning = game;
}
public void gameStart() {
(new Thread(new mainFrame())).start();
}
public void run() {
while (gameIsRunning == true) {
startTime = System.nanoTime();
updateGame();
renderGame();
elapsedTime = System.nanoTime() - startTime;
waitTime = (TARGET_FPS * 10) - (elapsedTime / 1000000);
if (waitTime < 0) {
waitTime = 5;
}
try {
Thread.sleep(waitTime);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void updateGame() {
if (x > 800) {
x = 0;
}
if (currentState == "left") {
x--;
}
if (currentState == "right") {
x++;
}
player = royImage();
}
public BufferedImage royImage() {
if (currentState == "right") {
lastFacing = 2;
i++;
if (playerVal == 0) {
playerVal = 1;
i = 0;
player = get.getImg("royWalk1");
}
if (playerVal == 1 && i > 20) {
playerVal = 2;
i = 0;
return get.getImg("royWalk2");
}
if (playerVal == 2 && i > 20) {
playerVal = 3;
i = 0;
player = get.getImg("royWalk3");
}
if (playerVal == 3 && i > 20) {
playerVal = 4;
i = 0;
player = get.getImg("royWalk4");
}
if (playerVal == 4 && i > 20) {
playerVal = 0;
i = 0;
player = get.getImg("royWalk1");
}
}
if (currentState == "left") {
lastFacing = 1;
i++;
if (playerVal == 0) {
playerVal = 1;
i = 0;
player = get.getImg("royWalkL1");
}
if (playerVal == 1 && i > 20) {
playerVal = 2;
i = 0;
player = get.getImg("royWalkL2");
}
if (playerVal == 2 && i > 20) {
playerVal = 3;
i = 0;
player = get.getImg("royWalkL3");
}
if (playerVal == 3 && i > 20) {
playerVal = 4;
i = 0;
player = get.getImg("royWalkL4");
}
if (playerVal == 4 && i > 20) {
playerVal = 0;
i = 0;
player = get.getImg("royWalkL1");
}
}
if (currentState == "null") {
i = 0;
playerVal = 0;
if (lastFacing == 1) {
player = get.getImg("playerL");
}
if (lastFacing == 2) {
player = get.getImg("player");
}
}
return player;
}
public void renderGame() {
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setBounds(30, 30, 700, 500);
panel.setLayout(new BorderLayout());
window.getContentPane().add(panel);
panel.add(this);
window.setFocusable(true);
window.setFocusTraversalKeysEnabled(false);
window.setVisible(true);
window.addKeyListener(this);
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.drawString("Hello", x, y);
g2.drawLine(0, 63, 700, 63);
g2.drawImage(player, x - 100, y - 100, null);
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int code = e.getKeyCode();
if (code == KeyEvent.VK_UP) {
currentState = "up";
}
if (code == KeyEvent.VK_DOWN) {
currentState = "down";
}
if (code == KeyEvent.VK_LEFT) {
currentState = "left";
}
if (code == KeyEvent.VK_RIGHT) {
currentState = "right";
}
}
public void keyReleased(KeyEvent e) {
currentState = "null";
}
}
Could anyone help me figure out why I am getting the stack overflow error and how to avoid it?
Your while true loop is shooting you in the foot as you're adding a KeyListener umpteen thousand times within that loop. Don't do that, in particular your renderGame() method. Why would you even want to call a method that is for setting the GUI that many times? It would make much more sense to call that method once.
Also, instead use a Swing Timer (Google the tutorial) in place of your while loop, avoid KeyListeners in favor of Key Binding (Google the tutorial, and have a look at this example) and do your set-up code only once.
Also, your code is at risk of causing Swing threading errors as you're calling Thread.sleep(...) and while (true) in a non-background thread. For safety's sake, use a Swing Timer instead.
Also, you're comparing Strings wrong. Don't compare Strings using == or !=. Use the equals(...) or the equalsIgnoreCase(...) method instead. Understand that == checks if the two object references are the same which is not what you're interested in. The methods on the other hand check if the two Strings have the same characters in the same order, and that's what matters here. So instead of
if (fu == "bar") {
// do something
}
do,
if ("bar".equals(fu)) {
// do something
}
or,
if ("bar".equalsIgnoreCase(fu)) {
// do something
}
Related
I am new to java, and after attempting to create a small snake type game, and error occurred
Error: Main method not found in class Game.GamePanel, please define the main method as: public static void main(String[] args)"
Could someone please help me as to fixing the error? It would be a big help as a beginner to java. Im using Eclipse latest version
package Game;
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 java.util.ArrayList;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable, KeyListener {
public static final int WIDTH = 1000;
public static final int HEIGHT = 1000;
//Render
private Graphics2D g2d;
private BufferedImage image;
//GameLoop
private Thread thread;
private boolean running;
private long targetTime;
//Game Stuff
private final int SIZE = 10;
Entity head;
ArrayList<Entity> snake;
//movement
private int dx, dy;
//key input
private boolean up,down,right,left,start;
public GamePanel() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
setFocusable(true);
requestFocus();
addKeyListener(this);
}
public void addNotify() {
super.addNotify();
thread = new Thread(this);
thread.start();
}
private void setFPS(int fps) {
targetTime = 1000 / fps;
}
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
int k = e.getKeyCode();
if(k == KeyEvent.VK_UP) up = true;
if(k == KeyEvent.VK_DOWN) down = true;
if(k == KeyEvent.VK_LEFT) left = true;
if(k == KeyEvent.VK_RIGHT) right = true;
if(k == KeyEvent.VK_ENTER) start = true;
}
#Override
public void keyReleased(KeyEvent e) {
int k = e.getKeyCode();
if(k == KeyEvent.VK_UP) up = false;
if(k == KeyEvent.VK_DOWN) down = false;
if(k == KeyEvent.VK_LEFT) left = false;
if(k == KeyEvent.VK_RIGHT) right = false;
if(k == KeyEvent.VK_ENTER) start = false;
}
#Override
public void run() {
if(running) return;
init();
long startTime;
long elapsed;
long wait;
while(running){
startTime = System.nanoTime();
update();
requestRender();
elapsed = System.nanoTime() - startTime;
wait = targetTime - elapsed / 1000000;
if(wait > 0) {
try {
Thread.sleep(wait);
}catch(Exception e) {
e.printStackTrace();
}
}
}
}
private void init() {
image = new BufferedImage(WIDTH,HEIGHT,BufferedImage.TYPE_INT_ARGB);
g2d = image.createGraphics();
running = true;
setUplevel();
setFPS (10);
}
private void setUplevel() {
snake = new ArrayList<Entity>();
head = new Entity(SIZE);
head.setPosition(WIDTH / 2, HEIGHT / 2);
snake.add(head);
for(int i = 1;i < 10;i++) {
Entity e = new Entity(SIZE);
e.setPosition(head.getX() + (i * SIZE), head.getY());
snake.add(e);
}
}
private void requestRender() {
render(g2d);
Graphics g = getGraphics();
g.drawImage(image, 0,0,null);
g.dispose();
}
private void update() {
if(up && dy == 0) {
dy = -SIZE;
dx = 0;
}
if(down && dy == 0) {
dy = SIZE;
dx = 0;
}
if(left && dx == 0) {
dy = 0;
dx = -SIZE;
}
if(right && dx == 0) {
dy = 0;
dx = SIZE;
}
if(dx != 0 || dy != 0) {
for(int i = snake.size() - 1;i > 0;i--) {
snake.get(i).setPosition(
snake.get(i - 1).getX(),
snake.get(i - 1).getY()
);
}
head.move(dx, dy);
}
if(head.getX() < 0 ) head.getX(WIDTH);
if(head.getY() < 0 ) head.getY(HEIGHT);
if(head.getX() > WIDTH ) head.getX(0);
if(head.getY() > HEIGHT ) head.getY (0);
}
public void render(Graphics2D g2d) {
g2d.clearRect(0, 0, WIDTH, HEIGHT);
g2d.setColor(Color.GREEN);
for(Entity e : snake) {
e.render(g2d);
}
}
}
You can add it to GamePanel, but you need to create a JFrame and you want to add an instance of your GamePanel to it. Something like,
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.add(new GamePanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
});
}
I have been working on a snake game, but an improvement I wanted to make was adding text to the game, giving instructions and keeping track of points. I messed around with JPanel and a few other things that all open a new, mini window that displays the text rather than printing it on the primary window
EDIT:
Thanks to several helpful people, I understand the correct use, but when I use it while attempting to change the color, it changes the color of the background as well. I was under the assumption this is because it's in the same class as the background, so when I put g.setColor under the background's color, it changed it.
I tried making a new object using paintComponent() while the background was in paint(), and the text didn't show up.
Any advice?
Here is the main java file:
import javax.swing.JPanel;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
public class Gamepanel extends JPanel implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 500, HEIGHT = 500; //window size
private Thread thread;
private boolean running; //allows the game to be started/stopped
private boolean right = true, left = false, up = false, down = false; //setting default movement
private BodyPart b;
private ArrayList<BodyPart> snake;
private Food food;
private ArrayList<Food> foods;
private Random r; //creating random integer for food spawn
private int xCoor = 10, yCoor = 10, size = 5; //setting location and coordinate size, along with snake length
private int ticks = 0;
private int points = 0;
public Gamepanel() {
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT)); //window size
addKeyListener(this); //allows key input from user
snake = new ArrayList <BodyPart>();
foods = new ArrayList <Food>();
r = new Random(); //random integer
}
public void start() {
running = true; //allows the game to start
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false; //stops the game from running
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void tick() {
if(snake.size() == 0) { //sets location
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++; //constant tick increase
if(ticks > 750000) { //sets speed (higher = slower)
if(right) xCoor ++;
if(left) xCoor --;
if(up) yCoor --;
if(down) yCoor ++;
ticks = 0;
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
if(snake.size() > size) {
snake.remove(0); //removes earliest value in snake size
}
}
if(foods.size() == 0) { //sets food in window range(multiplies by 10)
int xCoor = r.nextInt(48);
int yCoor = r.nextInt(48);
points++;
food = new Food(xCoor, yCoor, 10);
foods.add(food);
}
for (int i = 0 ; i < foods.size(); i++) { //spawns new food when old food is eaten
if(xCoor == foods.get(i).getxCoor() && yCoor == foods.get(i).getyCoor()) {
size ++;
foods.remove(i);
i++;
}
}
//player body collision
for(int i = 0 ; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
System.out.print("Game Over! " + "Points: " + points);
stop();
}
}
}
//border collision
if(xCoor < 0 || xCoor > 49 || yCoor < 0 || yCoor > 49) {
System.out.println("Game Over! " + "Points: " + points);
stop();
}
}
public void paint(Graphics g) { //background color/size setter
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK); //background color
g.fillRect(0, 0, WIDTH, HEIGHT);
for(int i = 0; i < WIDTH/10 ; i++) {
g.drawLine(i * 10, 0, i * 10, HEIGHT);
}
for(int i = 0; i < HEIGHT/10 ; i++) {
g.drawLine(0, i * 10, HEIGHT, i * 10);
}
for(int i = 0 ; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for(int i = 0 ; i < foods.size(); i++) {
foods.get(i).draw(g);
}
}
#Override
public void run() {
while(running) {
tick(); //runs ticks while running is true
repaint();
}
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT && !left) { //right key = right movement
right = true;
up = false;
down = false;
}
if(key == KeyEvent.VK_LEFT && !right) { //left key = left movement
left = true;
up = false;
down = false;
}
if(key == KeyEvent.VK_UP && !down) { //up key = up movement
up = true;
right = false;
left = false;
}
if(key == KeyEvent.VK_DOWN && !up) { //down key = down movement
down = true;
right = false;
left = false;
}
if(key == KeyEvent.VK_SPACE) {
snake.clear();
start();
size = 5;
points = 0;
xCoor = 10;
yCoor = 10;
}
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
}
}
Did you try this ?
public void paintComponent(Graphics g) {
super.paintComponent(g);
Font font = new Font("Verdana", Font.BOLD, 14);
g.setFont(font);
g.setColor(Color.black);
g.drawString("instructions", 75, 75);
}
as noted by #Hovercraft maybe you should be overriding the paintComponent() method instead of paint()
I have this small project that upon running the program it will automatically animate. In this case an oval shape should continuously animate using a thread. However in my program it will stop for the fifth direction - meaning following a certain path. Can anyone suggest me a better solution or help me let the oval shape continuously move until the user closes the program.
package movingball;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MovingBall extends JPanel{
private int ballX = 30;
private int ballY = 30;
private int pattern = 1;
private int limitHeight;
private int limitWidth;
boolean horizontalBoundary = true;
boolean verticalBoundary = true;
public MovingBall(){
setBackground(Color.BLACK);
}
public MovingBall(int x, int y){
x = this.ballX;
y = this.ballY;
repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(500,700);
MovingBall movingBall = new MovingBall();
frame.add(movingBall);
frame.setVisible(true);
BallUsingThread ball = new BallUsingThread(movingBall);
Thread first = new Thread(ball);
first.start();
}
#Override
public void paintComponent(Graphics canvas){
super.paintComponent(canvas);
canvas.setColor(Color.BLUE);
canvas.fillOval(ballX, ballY, 100, 100);
}
public void animateBall(){
if(horizontalBoundary && verticalBoundary){
if(pattern == 1){
diagonalDown(getWidth()-100,365);
}else if(pattern == 2){
diagonalDown(getWidth(),150);
}
}
if(!horizontalBoundary && !verticalBoundary){
diagonalDownLeft(150, getHeight());
pattern = 4;
}
if(horizontalBoundary && !verticalBoundary){
if(pattern == 4){
diagonalUp(0, 490);
}
if(pattern == 5){
System.out.print("helo");
diagonalUp(500,10);
}
System.out.print("last move" + pattern);
}
if(!horizontalBoundary && verticalBoundary){
diagonalUpRight(getWidth(),100);
pattern = 5;
System.out.print(pattern);
}
repaint();
}
public void diagonalDown(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX += 30) >= limitWidth){
horizontalBoundary = false;
}
if((ballY += 30) >= limitHeight){
verticalBoundary = false;
}
}
public void diagonalUp(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX -= 30) <= limitWidth) {
horizontalBoundary = false;
}
if((ballY -= 30) <= limitHeight){
verticalBoundary = true;
}
}
public void diagonalUpRight(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX += 30) >= limitWidth) {
horizontalBoundary = true;
}
if((ballY -= 30) <= limitHeight){
verticalBoundary = false;
}
}
public void diagonalDownLeft(int limitWidth, int limitHeight){
this.limitWidth = limitWidth;
this.limitHeight = limitHeight;
if((ballX -= 30) <= limitWidth){
horizontalBoundary = true;
}
if((ballY += 30) >= limitHeight){
verticalBoundary = false;
}
//System.out.print("downleft");
}
}
class BallUsingThread implements Runnable{
private final MovingBall movingBall;
public BallUsingThread(MovingBall mb){
movingBall = mb;
}
#Override
public void run() {
for(;;){
movingBall.animateBall();
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
System.out.printf("Error",ex);
}
}
}
}
It is not the problem with loop, if you System.out.println("loop running"); you will see that the loop is running, but that there is the problem with your draw ball logic that in this part of your code
if(!horizontalBoundary && verticalBoundary){
diagonalUpRight(getWidth(),100);
pattern = 5;
System.out.print(pattern);
}
You are trying to diagonalUpRight() so after some calling to this method, then the none of the if clause will executed, because the conditions are not satisfied, so the ball remains in the same place at every loop, and seems that the loop stopped working.
A small suggestion: It is better to use while(tru /*some condition*/) loop instead of for(;;) in such cases.
Solution: If you carefully check the logic you will see that there is no an if clause which is used for the condition below:
horizontalBoundary = true
verticalBoundary = true
When pattern = 5 So when these two variables become true andpattern = 5 then nothing will happen to the ball position, so you can write a condition which is used to check these two variables for true value.
Eidt Eidt the below part of you code and you will see the result which loop is not stopping, I just initialized the position of ball the values become true and the pattern = 5.
if(horizontalBoundary && verticalBoundary){
if(pattern == 1){
diagonalDown(getWidth()-100,365);
}else if(pattern == 2){
diagonalDown(getWidth(),150);
} else { // added this else block
ballX = 30;
ballY = 30;
pattern = 1;
}
}
Override paintComponent(Graphics) and implement all painting inside this method (but not animations).
Then use Swing timer to schedule periodic events each 100 ms, implement everything that changes the picture in the handler of this event and call repaint() from there at the end to refresh the picture.
I want to be able to display the score to players, and have the score go up by 10 every time you get an apple. To do this though, I need to add extra space on the window to allow room for the score counter, but I can't find where to do that in my code.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class Screen extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 800, HEIGHT = 900;
private Thread thread;
private boolean running = false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 20, yCoor = 20;
private int size = 10;
private boolean right = true, left = false, up = false, down = false;
private int ticks = 0;
private Key key;
public Screen() {
setFocusable(true);
key = new Key();
addKeyListener(key);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
r = new Random();
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
start();
}
public void reset() {
snake.clear();
apples.clear();
xCoor = 20;
yCoor = 20;
size = 10;
running = true;
}
public void tick() {
if(snake.size() == 0) {
b = new BodyPart(xCoor, yCoor, 20);
snake.add(b);
}
if(apples.size() == 0) {
int xCoor = r.nextInt(40);
int yCoor = r.nextInt(40);
apple = new Apple(xCoor, yCoor, 20);
apples.add(apple);
}
for(int i = 0; i < apples.size(); i++) {
if(xCoor == apples.get(i).getxCoor() && yCoor == apples.get(i).getyCoor()) {
size++;
apples.remove(i);
i--;
}
}
for(int i = 0; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
reset();
}
}
}
if(xCoor < 0) xCoor = 40;
if(xCoor > 40) xCoor = 0;
if(yCoor < 0) yCoor = 40;
if(yCoor > 40) yCoor = 0;
ticks++;
if(ticks > 250000) {
if(right) xCoor++;
if(left) xCoor--;
if(up) yCoor--;
if(down) yCoor++;
ticks = 185000;
b = new BodyPart(xCoor, yCoor, 20);
snake.add(b);
if(snake.size() > size) {
snake.remove(0);
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(new Color(20, 50, 0));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
for(int i = 0; i < WIDTH / 20; i++) {
g.drawLine(i * 20, 0, i * 20, HEIGHT);
}
for(int i = 0; i < HEIGHT / 20; i++) {
g.drawLine(0, i * 20, WIDTH, i * 20);
}
for(int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for(int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
public void start() {
running = true;
thread = new Thread(this, "Game Loop");
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while(running) {
tick();
repaint();
}
}
private class Key implements KeyListener {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if(key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if(key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if(key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
Add a label on the jPanel
or add string inside your paint() method
g.drawString("Score: " + intScore, 10, 10);
I want players to be able to press "r" after dying and be able to restart. I think I'm supposed to put my entire code into a reset method, but I am only a beginner, and I'm not quite there yet.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JPanel;
public class Screen extends JPanel implements Runnable {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 800, HEIGHT = 800;
private Thread thread;
private boolean running = false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 10, yCoor = 10;
private int size = 20;
private boolean right = true, left = false, up = false, down = false;
private int ticks = 0;
private Key key;
public Screen() {
setFocusable(true);
key = new Key();
addKeyListener(key);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
r = new Random();
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
start();
}
public void tick() {
if(snake.size() == 0) {
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
if(apples.size() == 0) {
int xCoor = r.nextInt(80);
int yCoor = r.nextInt(80);
apple = new Apple(xCoor, yCoor, 10);
apples.add(apple);
}
for(int i = 0; i < apples.size(); i++) {
if(xCoor == apples.get(i).getxCoor() && yCoor == apples.get(i).getyCoor()) {
size++;
apples.remove(i);
i--;
}
}
for(int i = 0; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
stop();
}
}
}
if(xCoor < -1) xCoor = 80;
if(xCoor > 80) xCoor = -1;
if(yCoor < -1) yCoor = 80;
if(yCoor > 80) yCoor = -1;
ticks++;
if(ticks > 250000) {
if(right) xCoor++;
if(left) xCoor--;
if(up) yCoor--;
if(down) yCoor++;
ticks = 185000;
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
if(snake.size() > size) {
snake.remove(0);
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(new Color(10, 50, 0));
g.fillRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
for(int i = 0; i < WIDTH / 10; i++) {
g.drawLine(i * 10, 0, i * 10, HEIGHT);
}
for(int i = 0; i < HEIGHT / 10; i++) {
g.drawLine(0, i * 10, WIDTH, i * 10);
}
for(int i = 0; i < snake.size(); i++) {
snake.get(i).draw(g);
}
for(int i = 0; i < apples.size(); i++) {
apples.get(i).draw(g);
}
}
public void start() {
running = true;
thread = new Thread(this, "Game Loop");
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void run() {
while(running) {
tick();
repaint();
}
}
private class Key implements KeyListener {
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_RIGHT && !left) {
up = false;
down = false;
right = true;
}
if(key == KeyEvent.VK_LEFT && !right) {
up = false;
down = false;
left = true;
}
if(key == KeyEvent.VK_UP && !down) {
left = false;
right = false;
up = true;
}
if(key == KeyEvent.VK_DOWN && !up) {
left = false;
right = false;
down = true;
}
}
#Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
}
Any help is greatly appreciated!
You can modify your code as follows:
I've added comments to explain my modifications
//this resets the position/size of the snake and clears the array
public void reset() {
snake.clear();
apples.clear();
xCoor = 10;
yCoor = 10;
size = 20;
running = true;
}
private class Key implements KeyListener {
//reset when you are dead and the user presses r
if (!running && (e.getKeyChar() == 'r' || e.getKeyChar() == 'R')){
reset();
}
}
public void tick() {
while (running){
//prev code
for(int i = 0; i < snake.size(); i++) {
if(xCoor == snake.get(i).getxCoor() && yCoor == snake.get(i).getyCoor()) {
if(i != snake.size() - 1) {
//don't kill the process, just stop the game and wait for the user to press 'r'
//you may need to do additional stuff here
running = false;
}
}
}
//remaining code
}
}
First of all, yes you are on the right track. The best way is to put the initilization code (setting all variables to their initial values) in a seperate method. Then when you press 'r' you simply call this method and it will 'reset' itself.
To make this happen you should do ALL variable initializations at the start. Currently you initialize b = new BodyPart(xCoor, yCoor, 10); in tick(). Since this only ever happens once (when the game started) this is better to put in your initilization method.
A rough proposal of an initilization method:
public void initialize() {
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
b = new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
This method initializes all variables that are 'resettable'. You can then call this method when the int key = e.getKeyCode(); is KeyCode.R.