setBackground is messing up Thread.sleep - java

I Have tried different ways to make two backgrounds for this snake game, one black for the menu and one white for the lines of the game. The best solution I found for this was using setBackground. But when I ran the game the the Thread.sleep got messed up and now the snake goes extremely fast. To try and trouble shoot this problem I put in multiple values into Thread.sleep but the snake travels at the same speed regardless of the values.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.lang.Thread;
import java.util.Random;
public class Snake extends JPanel implements KeyListener, MouseListener{
public boolean right = false;
public boolean left = false;
public boolean up = false;
public boolean down = false;
public int snakex[] = new int[10000000];
public int snakey[] = new int[10000000];
public int snakeLength = 0;
public int applex;
public int appley;
public int buttonX = 150;
public int buttonY = 125;
public boolean appleEaten = true;
public static boolean reset = false;
public static boolean ingame = false;
public static boolean menu = true;
public static int speed = 200;
public void forLogic(){
for(int i = snakeLength; i > 1; i--){
if(snakeLength > 4 && snakex[0] == snakex[i] && snakey[0] == snakey[i]){
System.out.println("You Loose \n Your Score was: " + snakeLength);
ingame = false;
}
}
Movement();
if(snakex[0] >= 30*20){
snakex[0] = 0;
}
if(snakex[0] < 0){
snakex[0] = 29*20;
}
if(snakey[0] >= 25*20){
snakey[0] = 0;
}
if(snakey[0] < 0){
snakey[0] = 24*20;
}
if(snakex[0] == applex*20 && snakey[0] == appley*20) {
appleEaten = true;
snakeLength++;
//System.out.println(snakeLength);
}
if(appleEaten){
appleLocation();
appleEaten = false;
}
}
public void appleLocation(){
boolean goodToGo = false;
Random rand = new Random();
while(!goodToGo){
applex = rand.nextInt(30);
appley = rand.nextInt(25);
boolean checker = false;
for(int i = snakeLength; i > 0; i--) {
if (applex == snakex[i]||appley == snakey[i]) {
checker = true;
}
}
if(!checker){goodToGo = true;}
}
}
public void Movement(){
if(reset){
left = false;
right = false;
up = false;
down = false;
snakex[0] = 0;
snakey[0] = 0;
snakeLength = 1;
appleLocation();
reset = false;
}
if(right){
snakex[0] += 20;
}
if(left){
snakex[0] -= 20;
}
if(up){
snakey[0] -= 20;
}
if(down){
snakey[0] += 20;
}
}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){
int mouseX = e.getX();
int mouseY = e.getY();
if(mouseX > buttonX && mouseX < buttonX + 300 && mouseY > buttonY && mouseY < buttonY + 75){
ingame = true;
}
}
public void mouseReleased(MouseEvent e){}
public void mouseClicked(MouseEvent e){}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == 39 && !left) {
right = true;
up = false;
down = false;
}
if(key == 37 && !right){
left = true;
up = false;
down = false;
}
if(key == 38 && !down){
up = true;
left = false;
right = false;
}
if(key == 40 && !up){
down = true;
left = false;
right = false;
}
if(key == 82){
reset = true;
}
}
public void keyReleased(KeyEvent e) {}
#SuppressWarnings("serial")
public void paint(Graphics g) {
super.paintComponent(g);
if(menu){
setBackground(Color.BLACK);
g.setColor(Color.green);
g.setFont(new Font("Courier New", Font.BOLD, 50));
g.drawString("Snake Game", 150, 50);
g.drawRect(buttonX, buttonY, 300, 75);
g.setFont(new Font("Courier New", Font.BOLD, 40));
g.drawString("PLAY", 250, 175);
}
if(ingame) {
setBackground(Color.WHITE);
int x = 0;
int y = 0;
for (x = 0; x < 30; x++) {
for (y = 0; y < 25; y++) {
g.setColor(Color.black);
g.fillRect(x * 20, y * 20, 19, 19);
}
}
g.setColor(Color.red);
g.fillOval(applex * 20, appley * 20, 19, 19);
forLogic();
g.setColor(Color.green);
for (int i = snakeLength; i > 0; i--) {
snakex[i] = snakex[(i - 1)];
snakey[i] = snakey[(i - 1)];
g.fillRect(snakex[i], snakey[i], 19, 19);
}
}
}
public static void main(String[] args) throws InterruptedException {
JFrame jframe = new JFrame("Snake Game");
Snake snake = new Snake();
jframe.add(snake);
snake.addMouseListener(snake);
snake.addKeyListener(snake);
jframe.setSize(615, 540);
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jframe.setFocusable(true);
jframe.setVisible(true);
snake.requestFocusInWindow();
jframe.setLocationRelativeTo(null);
while(true) {
if (!menu) {
ingame = true;
}
if (menu == ingame) {
ingame = false;
}
if (menu) {
snake.repaint();
}
if (ingame) {
while (true) {
Thread.sleep(200);
snake.repaint();
}
}
}
}
}

I'm sorry for being blunt, but there is just so many problems with this code, it's hard to know where to begin.
Problems:
First off, you're calling setBackground(...) within a painting method, which is potentially triggering a repaint, which normally wouldn't be much of a problem...
But you have your program logic being called from within your paint mehtod override, and this is a major problem. As you're finding out you don't have full or even partial control over when or even if a paint method is called or how often, and so having program logic within it is potentially deadly, and is likely causing your program to completely malfunction due to the setBackground call.
You're also while (true) loops and Thread.sleep(...) calls in your Swing code, code that could completely freeze your GUI if the Swing code were initiated (as is supposed to be done) on the Swing event thread.
You're overriding the paint method and yet calling the super paintComponent, a non-matching super method, within it, and this will break the Swing graphics chain, potentially resulting in significant painting irregularities.
Suggestions:
First and foremost, get all program logic outside of any and all painting methods.
Remove all Thread.sleep(...) calls and while (true) loops.
Use a Swing Timer, and advance your game "tick" within your Timer's ActionListener.
Within this "tick", update the state of key fields in your program
And then call repaint();.
Override the paintComponent method only
And within this override, call the same super method.
Within paintComponent, use the modified fields to change what is painted and how.
Call setBackground(...) once, in your class's constructor.
having game logic within a painting method. This suggests that a re-write using first principles would be very beneficial: use a Swing Timer for your game loop, use no other delaying code within your Swing code, override paintComponent and call the same super method within the override, separating painting from logic.
Read the tutorials. You're guessing which won't work here (as you're finding out).
More
Consider creating some non-GUI logic class.
This can include, GridPoint for x and y position of each point on the grid
Grid class a 2-dimensional array of GridPoint, the logical grid that holds the universe where the snake moves.
SnakePoints which can include an ArrayList<GridPoint> that holds the logical position of the points on the snake.
This last class can also have methods for adding a point, for moving the snake, for eating an apple.
A Timer which would tell SnakePoints to advance one square

public void paint(Graphics g) {
super.paintComponent(g);
Don't override paint(). Custom painting is done by overriding paintComponent(). Then you would still invoke super.paintComponent(g);
if(key == 39 && !left) {
Don't use magic numbers. The API will have variable for you to use. I'm guessing you want KeyEvent.VK_LEFT.
if(key == 82){
but I have no idea what that magic number is.
if(ingame) {
setBackground(Color.WHITE);
Don't change properties of the component in a painting method. Painting methods are for painting only.
Maybe you need a method like setPlayingGame(Boolean). Then when true you set the properties for playing the game. When false you set the menu properties.
Or maybe even better you have two panels. One for the menu and one for the game. Then you use a CardLayout and swap panels depending on whether you want to paint the menu or the game.
You have too much game logic for me to debug what might be your problem.

The snake is moving too fast because the method that "moves" the snake is being called too frequently. You are repainting every 200 milliseconds, but there is no sleep for the logic of the program. Your Thread.sleep should be in the logic part of the program:
public void forLogic(){
for(int i = snakeLength; i > 1; i--){
if(snakeLength > 4 && snakex[0] == snakex[i] && snakey[0] == snakey[i]){
System.out.println("You Loose \n Your Score was: " + snakeLength);
ingame = false;
}
}
Movement();
if(snakex[0] >= 30*20){
snakex[0] = 0;
}
if(snakex[0] < 0){
snakex[0] = 29*20;
}
if(snakey[0] >= 25*20){
snakey[0] = 0;
}
if(snakey[0] < 0){
snakey[0] = 24*20;
}
if(snakex[0] == applex*20 && snakey[0] == appley*20) {
appleEaten = true;
snakeLength++;
//System.out.println(snakeLength);
}
if(appleEaten){
appleLocation();
appleEaten = false;
}
try {
Thread.sleep(speed);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Related

How do I make my game slower (slower FPS)?

So I wrote this code for a game and now that game is very speeded up. I want to lower the FPS so that the game slows down a bit.
I thought the only way out for me is to make a timer. But I'm finding it difficult to locate where to place the timer? Can anyone help me with this?
So I wrote this code for a game and now that game is very speeded up. I want to lower the FPS so that the game slows down a bit.
I thought the only way out for me is to make a timer. But I'm finding it difficult to locate where to place the timer? Can anyone help me with this?
public class Gamepanel extends JPanel implements Runnable, KeyListener {
private static final long serialVersionUID = 1L;
public static final int WIDTH = 500, HEIGHT = 500;
private Thread thread;
private boolean running;
private boolean right = false, left = false, up = false, down= false;
private BodyPart b;
private ArrayList<BodyPart> snake;
private Apple apple;
private ArrayList<Apple> apples;
private Random r;
private int xCoor = 10, yCoor = 10, size = 1;
private int ticks = 0;
public Gamepanel(){
setFocusable(true);
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addKeyListener(this);
snake = new ArrayList<BodyPart>();
apples = new ArrayList<Apple>();
r = new Random();
start();
}
public void start () {
running = true;
thread = new Thread(this);
thread.start();
}
public void stop() {
running = false;
try {
thread.join();
} catch(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void tick() {
if(snake.size()==0) {
b= new BodyPart(xCoor, yCoor, 10);
snake.add(b);
}
ticks++;
if(ticks > 250000) {
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);
}
}
if(apples.size()==0) {
int xCoor = r.nextInt(49);
int yCoor = r.nextInt(49);
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++;
}
}
//COLLISION ON SNAKE BODY
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");
stop();
}
}
//COLLISION ON BORDER
if(xCoor < 0 || xCoor > 49 || yCoor < 0 || yCoor > 49) {
System.out.print("Game Over" + '\n');
System.out.println("Your Score is: " + snake.size());
stop();
}
}
}
public void paint(Graphics g) {
g.clearRect(0, 0, WIDTH, HEIGHT);
g.setColor(Color.BLACK);
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< apples.size(); i++) {
apples.get(i).draw(g);
}
}
#Override
public void run() {
while(running) {
tick();
repaint();
}
}
#Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if(key == KeyEvent.VK_D && !left) {
right = true;
up = false;
down=false;
}
if(key == KeyEvent.VK_A && !right) {
left = true;
up = false;
down = false;
}
if(key == KeyEvent.VK_W && !down) {
up=true;
left=false;
right=false;
}
if(key == KeyEvent.VK_S && !up) {
down=true;
left=false;
right=false;
}
}
#Override
public void keyReleased(KeyEvent e) {
}
}
The problem with your code is that now, game speed won't be the same on different machines, as some computers may execute your code faster and some may execute slower.
If you want your game to execute on every computer with the same speed you need define some kind of speed for your snake (unit per second) and then in game loop update your snake position based on how much time elapsed from last frame (last call of tick method)
// snake speed
double speed = 1.0; // units per second
// in game loop (your tick method)
position = speed * deltaTime;
now your position is not anymore depended on game framerate. On faster devices game will update snake position more often but deltaTime will be smaller as well as changes of position, on the other hand on slower devices tick method will be called less frequent but deltaTime will be higher

Fluent movement in a single keypress

Well, i am making a game right now. It is basically a "shooting game", where you shoot the other player. Well, everything is fine but the movement of the characters bugs me a lot. Don't understand me wrong here, I can program the movement of the characters and it's working kinda... but not fluent. Let me explain the word "fluent". Right now, the movement of my characters are like this; If I press "right arrow" to move the character to the right, it keeps going until i don't press the key anymore. I want to get rid of that, instead I want to move my characters in a single KeyPress to the right and it should keep going to the right until i press the "left arrow".
public class Character extends Main implements KeyListener {
int x;
int y;
int width;
int height;
public Character() {
this.x = 250;
this.y = 400;
this.width = 30;
this.height = 30;
addKeyListener(this);
setFocusable(true);
setVisible(true);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D mainGraphics = (Graphics2D) g;
mainGraphics.setColor(Color.BLUE);
mainGraphics.fillRect(this.x, this.y, this.width, this.height);
mainGraphics.setColor(Color.GREEN);
mainGraphics.fillRect(Enemy.xEnemy, Enemy.yEnemy, Enemy.widthEnemy, Enemy.heightEnemy);
mainGraphics.setColor(Color.RED);
mainGraphics.fillRect(Fire.xFire, Fire.yFire, Fire.widthFire, Fire.heightFire);
mainGraphics.setColor(Color.RED);
mainGraphics.fillRect(FireEnemy.xFireEnemy, FireEnemy.yFireEnemy, FireEnemy.widthFireEnemy, FireEnemy.heightFireEnemy);
}
public void keyReleased(KeyEvent arg0) {
}
public void keyTyped(KeyEvent arg0) {
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == e.VK_LEFT) {
this.x = this.x - 10;
Fire.xFire -= 10;
}
else if(keyCode == e.VK_RIGHT) {
this.x = this.x + 10;
Fire.xFire += 10;
}
else if(keyCode == e.VK_A) {
Enemy.xEnemy -= 10;
FireEnemy.xFireEnemy -= 10;
}
else if(keyCode == e.VK_D) {
Enemy.xEnemy += 10;
FireEnemy.xFireEnemy += 10;
}
else if(keyCode == e.VK_P) {
Fire.xFire = this.x;
Fire.yFire = Fire.yFire - 45;
if(this.x == Enemy.xEnemy && Fire.yFire <= Enemy.yEnemy) {
System.out.println("Player 1 won");
}
}
else if(keyCode == e.VK_W) {
FireEnemy.xFireEnemy = FireEnemy.xFireEnemy + 0;
for(int i = 0; i<2; i++) {
FireEnemy.yFireEnemy = FireEnemy.yFireEnemy + 45;
}
if(Enemy.xEnemy == this.x && FireEnemy.yFireEnemy >= this.y) {
System.out.println("Player 2 won");
}
}
repaint();
}
}
My main class
public class Main extends JPanel {
public static void main(String[] args) {
JFrame window = new JFrame();
Character character = new Character();
Enemy enemy = new Enemy();
Fire fire = new Fire();
FireEnemy fireEnemy = new FireEnemy();
window.setBounds(10, 10, 500, 500);
window.setBackground(Color.DARK_GRAY);
window.setResizable(false);
window.setVisible(true);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.add(character);
}
}
Fire, FireEnemy, Enemy are just classes that are Empty, i just put "static int..." and a constructor in it. Nothing important are in those.
Store the last pressed key. Then keyPressed is called, check if the key is the same as the last stored. If so, just return, otherwise process it.
In the Character class, create this member:
int lastKeyCode;
In your keyPressed method, add something like this:
int keyCode = e.getKeyCode();
if (keyCode == lastKeyCode) return;
else lastKeyCode = keyCode ;
and use the code you alrady have.
Note: I will not write your program for you, just point you in the right direction. Since you are a beginner it will help you better in the long run.

How to have recursive maze generator draw each step?

I finished writing a program that creates a maze recursively but have not been able to figure out how to have it draw the maze after each step. Any changes to the maze happen before the next recursive call. The maze is prerendered onto a JPanel as a grid of squares, and I have attempted to have the program render each step, by using JPanel.repaint before the next recursive call (I have comments within my generate method where I have previously tried to repaint. No matter what I try, the maze just simply renders the finished product (maze with all of the paths, walls, etc) all at once at the end. Attached is my recursive generate method.
private static boolean generate(int x, int y) {
System.out.println("xcord: " + x + ", ycord: " + y);
//panel.repaint(); when i have repaint here, it renders the entire maze at the end
a[x][y].visited = true;
if (unvisitedCells == 0) { // if you have visited all of the cells, maze is done generating
System.out.println("done");
return true;
}
int movesTried = 0; // keeps track of which directions have been tried
int currentMove = (int) (Math.random() * 4); // try moving a random direction first (0 = north, 1 = east, etc.)
while (movesTried < 4) { // continue as long as all four moves havent been tried
// north move
if (a[x][y].northCell != null && a[x][y].northCell.visited != true && currentMove == 0) {
a[x][y].northCell.visited = true;
a[x][y].northWall = false;
a[x][y].northCell.southWall = false;
unvisitedCells -= 1;
// tried repainting here, but had no effect
if (generate(x, y - 1)) {
return true; // move successful
}
}
// east move
if (a[x][y].eastCell != null && a[x][y].eastCell.visited != true && currentMove == 1) {
a[x][y].eastCell.visited = true;
a[x][y].eastWall = false;
a[x][y].eastCell.westWall = false;
unvisitedCells -= 1;
// tried repainting here, but had no effect
if (generate(x + 1, y)) {
return true; // move successful
}
}
// south move
if (a[x][y].southCell != null && a[x][y].southCell.visited != true && currentMove == 2) {
a[x][y].southCell.visited = true;
a[x][y].southWall = false;
a[x][y].southCell.northWall = false;
unvisitedCells -= 1;
// tried repainting here, but had no effect
if (generate(x, y + 1)) {
return true; // move successful
}
}
// west move
if (a[x][y].westCell != null && a[x][y].westCell.visited != true && currentMove == 3) {
a[x][y].westCell.visited = true;
a[x][y].westWall = false;
a[x][y].westCell.eastWall = false;
unvisitedCells -= 1;
// tried repainting here, but had no effect
if (generate(x - 1, y)) {
return true; // move successful
}
}
movesTried++; // another move has been tried
if (currentMove == 3 && movesTried < 4) {
currentMove = 0; // wraps back to north move if maze started at a move greater than 0, and you
// have more moves to try
} else {
currentMove++;
}
}
// at this point, all 4 moves have been tried, and there are no possible moves
// from the current maze cell
return false;
}
Each cell is rendered individually onto a JPanel, using information kept in a MazeCell class.
public class MazeCell {
public boolean northWall = true;
public boolean eastWall = true;
public boolean southWall = true;
public boolean westWall = true;
public MazeCell northCell = null;
public MazeCell eastCell = null;
public MazeCell southCell = null;
public MazeCell westCell = null;
public boolean visited = false;
}
Here I have set up a JPanel which draws each cell individually, based on whether there is a wall in each of 4 directions.
panel = new JPanel() {
private static final long serialVersionUID = 1L;
public void paintComponent(Graphics g) {
super.paintComponent(g);
a[0][0].northWall = false;
a[mazeSize - 1][mazeSize - 1].southWall = false;
for (int y = 0; y < mazeSize; y++) {
for (int x = 0; x < mazeSize; x++) {
if (a[x][y].northWall) {
g.drawLine(100 + (x * 25), 100 + (y * 25), 100 + (x * 25) + 25, 100 + (y * 25));
}
if (a[x][y].eastWall) {
g.drawLine(100 + (x * 25) + 25, 100 + (y * 25), 100 + (x * 25) + 25, 100 + (y * 25) + 25);
}
if (a[x][y].southWall) {
g.drawLine(100 + (x * 25), 100 + (y * 25) + 25, 100 + (x * 25) + 25, 100 + (y * 25) + 25);
}
if (a[x][y].westWall) {
g.drawLine(100 + (x * 25), 100 + (y * 25), 100 + (x * 25), 100 + (y * 25) + 25);
}
}
}
}
};
Warp the long process (generate(int x, int y)) with a SwingWorker, and let it update the GUI. Here is an example:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.GridLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
public class RecursiveGuiUpdate extends JFrame {
private final int SIZE = 4;
JLabel[][] grid = new JLabel[SIZE][SIZE];
RecursiveGuiUpdate() {
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
add(getGrid(), BorderLayout.NORTH);
JButton paint = new JButton("Paint");
paint.addActionListener(a -> updateGui());
add(paint, BorderLayout.SOUTH);
pack();
setVisible(true);
}
private void updateGui() {
new Task().execute();
}
private Component getGrid() {
JPanel panel = new JPanel(new GridLayout(SIZE, SIZE));
for(int i=0; i<=(SIZE-1); i++) {
for(int j=0; j<=(SIZE-1); j++) {
JLabel l = new JLabel(i+"-"+j, JLabel.CENTER);
l.setOpaque(true);
panel.add(l);
grid[i][j] = l;
}
}
return panel;
}
class Task extends SwingWorker<Void,Void> {
#Override
public Void doInBackground() {
updateGui(0, 0);
return null;
}
#Override
public void done() { }
//recursively set labels background
void updateGui(int i, int j) {
System.out.println(i+"-"+j);
//set random, background color
grid[i][j].setBackground(new Color((int)(Math.random() * 0x1000000)));
try {
Thread.sleep(500); //simulate long process
} catch (InterruptedException ex) { ex.printStackTrace();}
if((i==(SIZE-1))&&(j==(SIZE-1))) { return; }
if(i<(SIZE-1)) {
updateGui(++i, j);
}else {
i=0;
updateGui(i, ++j);
}
}
}
public static void main(String[] args) {
new RecursiveGuiUpdate();
}
}
If needed, you can override process(java.util.List) to get and process interim results.
If you need help with adapting such solution to your code, please post another question with mcve.

Processing 3.06b merging programs

i have been working on some code and merging two programs I have created but I understand I am missing a lot of information as I have many errors but I can't seem to fix the error. Below I have included the whole code which has been separated into classes. I am producing a version of space invaders.
Main class:
Bullets [] bullets = new Bullets[10];
Player player = new Player();
Boolean keyLftPressed = false, keyRghtPressed = false;
//Enemies[] enemies = new Enemies();
int state;
String gameLevel = "Main menu";
Boolean startTime = false;
void setup() {
for(int i=0; i<bullets.length; i++)
{
// if(i%2==0)
// bullets[i] = new Bullets();
// else
// bullets[i] = new Bullets(i);
}
size(800, 600);
state = 0;
}
void draw() {
background(255);
gameState();
player1.display();
movePlayer1();
handleEnemies();
handleBullets();
gamewon();
}
void gameState() {
if (gameLevel == "Main menu") {
background(0);
fill(255, 255, 255);
rect(270, 270, 280, 50, 20, 20, 20, 20);
//Draws rectangle for play game
fill(0);
textSize(30);
text("Play Game", 330, 305);
fill(255, 0, 0);
textSize(50);
text("Space Invaders", 220, 120);
if (mousePressed && mouseX > 250 && mouseX < 250 + 280 && mouseY > 270 && mouseY < 270 + 50)
{
gameLevel = "Level 1";
}
} else if (gameLevel == "Level 1")
{
background (255, 2555 , 255);
}
}
Bullets Class:
class Bullets {
class Bullet {
float x, y;
float velocity;
Bullet(float x, float y, float velocity) {
this.x = x;
this.y = y;
this.velocity = velocity;
}
void display(){
fill(80);
rect(this.x, this.y, 5,15);
}
void move(){
this.y+=this.velocity;
if (this.y > height || this.y < 0){
bullets.remove(this);
}
}
Class Enemies:
class Enemies {
float x, y;
float velocity;
Enemy(float x, float y) {
this.x = x;
this.y = y;
this.velocity = 3;
}
void display() {
fill(0,255,0);
ellipse(this.x, this.y, 30, 30);
noFill();
}
void move() {
this.x+=this.velocity;
if (this.x > width*.9) {
this.x = width*.9;
this.velocity *= -1;
this.y+=30;
}
if (this.x < width*.1) {
this.velocity*=-1;
this.x = width*.1;
this.y+=30;
}
}
void hitCheck() {
for (int i = 0; i < bullets.size(); i++){
Bullet b = (Bullet) bullets.get(i);
float distBetween = dist(b.x, b.y, this.x, this.y);
if (distBetween < 15 && b.velocity < 0){
score++;
enemies.remove(this);
float x = width*.1 + i%numCol*50;
float y = 60 + int(i/numCol)*60 ;
enemies.add(new Enemy(x, y));
}
}
}
}
Class Player:
class Player {
void movePlayer1() {
if (keyLftPressed) {
player1.x -=10;
}
if (keyRghtPressed) {
player1.x +=10;
}
}
void keyPressed() {
if (keyCode == LEFT) {
keyLftPressed = true;
}
else {
if (keyCode == RIGHT) {
keyRghtPressed = true;
}
else {
if (key == 'f') {
player1.shoot();
}
}
}
}
void keyReleased() {
if (keyCode == LEFT) {
keyLftPressed = false;
}
else {
if (keyCode == RIGHT) {
keyRghtPressed = false;
}
}
}
Class Score:
void gameFinish() {
{
for (int i = 0; i < 3; i++)
{
fill(color(255,0,0));
fill(255, 0, 0);
textAlign(CENTER);
text("Game over", width/2, height/2 - 50);
text(" Final score : "+ score, width/2, height/2 + 50);
}
}
}
}
void gamewon()
{
if (score == 10)
{
background(0);
fill(color(255,0,0));
fill(255, 0, 0);
textAlign(CENTER);
text("Congratulations you won!", width/2, height/5);
text(" Your final score is : "+ score, width/2, height/5 + 30);
text("Do you wish to continue?",width/2, height/2);
text(" If so press Y to Continue or N to exit ", width/2, height/2+30);
noLoop();
}
}
I don't want to be disheartening, but this code is a mess. You've got a ton of errors here, and asking us to go through all of them is asking quite a bit.
That being said, I'll try to get you started in the right direction.
First of all, you're missing closing curly brackets on several of these classes. Proper indenting will help you narrow this down, or you could consider putting each class in its own tab.
Then in your Player class, you use a variable named player1. Where is that variable defined? Do you mean to use the player variable? For that matter, since you're in the Player class already, why are you referring to a variable at all? Shouldn't you just use the x variables in that instance directly?
Which brings us to the next problem: your Player class doesn't actually define an x variable!
Similarly, your Player class calls a shoot() function, which doesn't seem to exist. You have to define that function.
Then let's see here... your Score class uses a score variable that doesn't seem to be declared anywhere.
Also, your bullets variable is an array, but you're calling functions on it that only work on an ArrayList object. Pick one or the other.
You also call a bunch of functions that don't exist: movePlayer1(), handleEnemies(), handleBullets(), and gameWon() for example. Some of these functions are defined inside of classes, so you need to use an instance of that class to get to the functions. Like this:
Example e = new Example();
e.function();
class Example{
void function(){
println("here");
}
}
Then your Enemies class has a constructor of Enemy, which isn't valid. Choose one or the other.
You're not going to like hearing this, but honestly, your best bet is probably to start from scratch. I would guess that you're trying to copy-paste all of this code from different sources without really understanding what the code is doing, which is a horrible idea. That never works, even for experienced programmers.
Instead, try breaking your problem down into smaller pieces. Get a single rectangle on the screen, then make it move around when you press the arrow keys, then add the ability to shoot. Then try adding some enemies, but only after the previous steps work perfectly!
If you get stuck, post an MCVE that shows the small step you're stuck on- not your entire project!

Error solution and help improving enemie spawn methode

I tried myself on a little "project" . It is basically a survival game. You move by using W,A,S,D and you shoot in different directions by using the arrow keys. You basically have to survive for as long as possible. The enemies follow you and they freeze on hit and start moving again after about 3 seconds.
The code is the following (execute the "window" class)
Window-class
package TestGame;
import java.awt.Graphics;
public class Window extends GameIntern{
public void init(){
setSize(windowX,windowY);
Thread th = new Thread(this);
th.start();
offscreen = createImage(windowX,windowY);
d = offscreen.getGraphics();
addKeyListener(this);
}
public void paint(Graphics g){
d.clearRect(0,0,windowX,windowY);//clear window
d.drawString(numberEnemies.toString(), 10, 10);//"Score" number of enemies displayed
d.drawRect(x, y, playerWidth, playerHeight);//draw player
for(Enemy e : enemies){//draw all enemies
d.drawRect(e.getx(), e.gety(), playerWidth, playerHeight);
}
for(Bullet b : bullets){//draw all bullets
d.drawOval(b.getx(), b.gety(), bulletSize, bulletSize);
}
g.drawImage(offscreen,0,0,this);
}
public void update(Graphics g){
paint(g);
}
}
GameIntern-class
package TestGame;
import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
public class GameIntern extends Applet implements Runnable , KeyListener {
public int windowX = 854;//size of the window in x direction
public int windowY = 460;//size of the window in y direction
public static int x;//x-coordinate of player
public static int y;//y-coordinate of player
public int playerpositionX = x;
public int playerpositionY = y;
public int playerHeight = 20;//player height
public int playerWidth = 20;//player width
public int playerSpeed = 3;//pixel per frame
public int bulletSize = 5;//diameter of bullets
public int spawnTime = 4;//time for new enemies to spawn in seconds
public int enemySleepTime = 180;//Time an enemy does nothing in Frames per second (180 in 60fps = 3sec)
public boolean alive = true;
public Image offscreen;
public Graphics d;
public boolean up,down,left,right;
private int delay;
private Random random= new Random();
public Integer numberEnemies = new Integer(enemies.size());
protected static ArrayList<Enemy> enemies = new ArrayList<Enemy>(); //List of all enemies
protected static ArrayList<Bullet> bullets = new ArrayList<Bullet>();//List of all bullets
protected static ArrayList<PowerUps> pUps = new ArrayList<PowerUps>();//List of all powerUps
public void run() {
this.x = 400;//startingposition x
this.y = 240;//startingposition y
double ns = 1000000000.0 / 60.0; //60 "frames"
double delta = 0;
long lastTime = System.nanoTime();
while (alive) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
while (delta >= 1) {
repaint();
tick();
collisionEnemy();
// collisionPowerUp();
delta--;
}
}
}
/**
* Method to calculate all objects and their positions per frame
*/
private void tick() {
if(left == true){
if(x>=0 + playerSpeed){
x-=playerSpeed;
}else{ x=0;}//Farthest left x-coordinate
repaint();
}
if(right == true){
if(x<=windowX - playerWidth - playerSpeed){
x+=playerSpeed;
}else{ x=windowX - playerWidth;}//Farthest right x-coordinate
repaint();
}
if(up == true){
if(y>=0 + playerSpeed){
y-=playerSpeed;
}else{ y=0;}//Highest y-coordinate
repaint();
}
if(down == true){
if(y<=windowY - playerHeight - playerSpeed){
y+=playerSpeed;
}else{y=windowY - playerHeight;}//Lowest y-coordinate
repaint();
}
for (Enemy e : enemies) { //Tick every enemy
e.tick();
}
for (Bullet b : bullets){ //Tick every bullet
b.tick();
}
if(delay % (60 * spawnTime) == 0){ //Spawn enemy
enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
numberEnemies++;
}
delay++;
for(Enemy e : enemies){ //collision : enemy & bullet
for(Bullet b : bullets){
if(b.getx()+bulletSize >= e.getx() && b.getx() <= e.getx()+20){
if(b.gety()+bulletSize >= e.gety() && b.gety() <= e.gety()+20){
e.setHit();
b.setRemove();
}
}
}
}
for(int i = 0; i< bullets.size(); i++){ //Remove bullets from ArrayList
if(bullets.get(i).remove){
bullets.remove(i);
}
}
}
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == 65){//W
left=true;
}
if(e.getKeyCode() == 87){//A
up=true;
}
if(e.getKeyCode() == 68){//S
right=true;
}
if(e.getKeyCode() == 83){//D
down=true;
}
}
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == 65){//Arrowkey left
left=false;
}
if(e.getKeyCode() == 87){//Arrowkey up
up=false;
}
if(e.getKeyCode() == 68){//Arrowkey right
right=false;
}
if(e.getKeyCode() == 83){//Arrowkey dowm
down=false;
}
if(e.getKeyCode() == 37){//Arrowkey left
bullets.add(new Bullet(x,y,false,false,true,false)); //Direction the bullet has to go
}
if(e.getKeyCode() == 38){//Arrowkey up
bullets.add(new Bullet(x,y,true,false,false,false));//Direction the bullet has to go
}
if(e.getKeyCode() == 39){//Arrowkey right
bullets.add(new Bullet(x,y,false,false,false,true));//Direction the bullet has to go
}
if(e.getKeyCode() == 40){//Arrowkey down
bullets.add(new Bullet(x,y,false,true,false,false));//Direction the bullet has to go
}
}
public void keyTyped(KeyEvent e){}
/**
* Method to see if the player collided with an enemy
*/
public void collisionEnemy(){
for(Enemy e : enemies){
for(int i = 0;i <= playerWidth; i++){
if(GameIntern.x+i >= e.getx() && GameIntern.x+i <= e.getx()+playerWidth){
if(GameIntern.y+i >= e.gety() && GameIntern.y+i <= e.gety()+playerHeight){
alive = false;
}
}
}
}
}
// public void addEnemy(){
// enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
//
// //Spawn enemies inside the filed, not outside the boarder
// if (playerpositionX < playerWidth * 2 || playerpositionX * 2 > windowX - 2*playerWidth || playerpositionY * 2 > windowY - 2*playerHeight || playerpositionY < playerHeight * 2){
// enemies.add(new Enemy(random.nextInt(windowX - 3*playerWidth), random.nextInt(windowY - 3*playerHeight)+3*playerHeight));
// }else {
// int temp1 = random.nextInt(windowX-3*playerWidth);
// if (temp < playerpositionX){
//
// }
// enemies.add(new Enemy(random.nextInt(windowX), random.nextInt(windowY)));
// }
//
// }
}
Bullet-class
package TestGame;
public class Bullet extends GameIntern{
public int x,y;
public boolean up,down,left,right;
public boolean remove;
public Bullet(int x, int y,boolean up,boolean down, boolean left, boolean right){
this.x = x + 8;
this.y = y + 8;
this.up = up;
this.down = down;
this.left = left;
this.right = right;
}
public int getx(){
return this.x;
}
public int gety(){
return this.y;
}
public void setRemove(){
remove=true;
}
public void tick() {
if (up == true) y-=2;
if (down == true) y+=2;
if (left == true) x-=2;
if (right == true) x+=2;
if(x < 0){
remove = true;
}
if(x > 840){
remove = true;
}
if(y < 0){
remove = true;
}
if(y > 470){
remove = true;
}
}
}
Enemy-class
package TestGame;
public class Enemy extends GameIntern {
public int x,y;
public boolean hit = false;
public int counter = 0;
public Enemy(int x, int y) {
this.x = x;
this.y = y;
}
public int getx(){
return this.x;
}
public int gety(){
return this.y;
}
public void setHit(){
hit = true;
counter = enemySleepTime;
}
public void tick() {
if(counter == 0){
if(hit == true){
hit=false;
}
if (x < GameIntern.x) x++;
if (x > GameIntern.x) x--;
if (y < GameIntern.y) y++;
if (y > GameIntern.y) y--;
}else {counter--;}
}
}
After playing for a while i get a
java.util.ConcurrentModificationException
What does that mean?
Also, I struggle to improve the enemy spawn prcess. Right now it sometimes happens, that enemies spawn inside the player. I want to have an imaginary box around the player where enemies dont spawn inside and enemies should always spawn inside the window.
If you have any questions, please feeld free to ask :)
sincerely
Viktor
From the JavaDocs:
The iterators returned by this class's iterator and listIterator methods are fail-fast: if the list is structurally modified at any time after the iterator is created, in any way except through the iterator's own remove or add methods, the iterator will throw a ConcurrentModificationException.
The problem is likely caused because you're removing bullets from the ArrayList while trying to paint them in a separate thread. The issue is that the two threads are iterating over the bullets list simultaneously.
//The following for loop is likely the cause
for(int i = 0; i< bullets.size(); i++){
if(bullets.get(i).remove){
bullets.remove(i); // <-- this is the problem
}
}
Instead, try using a thread-safe implementation, e.g.
protected static List<Enemy> enemies =
Collections.synchronizedList(new ArrayList<Enemy>()); //List of all enemies
protected static List<Bullet> bullets =
Collections.synchronizedList(new ArrayList<Bullet>());//List of all bullets
Furthermore, you should change the remove code to avoid an IndexOutOfBoundsException:
LinkedList<Bullet> bulletsToRemove = new LinkedList<>();
for(Enemy e : enemies){ //collision : enemy & bullet
for(Bullet b : bullets){
if(b.getx()+bulletSize >= e.getx() && b.getx() <= e.getx()+20){
if(b.gety()+bulletSize >= e.gety() && b.gety() <= e.gety()+20){
e.setHit();
bulletsToRemove.add(b);
}
}
}
}
for(Bullet b : bulletsToRemove){ //Remove bullets from ArrayList
bullets.remove(b);
}
Regarding the spawning process, a simplistic approach is to just define a minimum distance from the player, call it minDist. Now just pick a random location anywhere on the screen, call it p1. If p1 is less than minDist away from the player, pick a new random location. As long as the player and enemy sprites are relatively small compared to the screen area, this approach should work well.

Categories