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.
Related
I am currently developing a Catch the Falling Object-type game but the problem for now is the player (aka the one who catches the objects). When I move through the left side and hit the bounds of the window, it is sending the player to x - 1, but when I go to the right side (even though I put the code as if (x > windowBoundRight){ x = x - 1 } though it is still moving outside the window bounds. Can anyone help me? (Note: there are no errors btw)
This is the code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Game extends JPanel implements ActionListener, KeyListener {
public int x = 0, y = 0, velx = 0, vely = 0;
public boolean hitAnObject = false;
public Color c = Color.BLACK;
Timer timer = new Timer(5, this);
public Game() {
timer.start();
setBackground(Color.CYAN);
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
#Override
public void paint(Graphics g){
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.fillRect(x, y, 50, 50);
g.drawString("X = " + x + "Y = " + y, 0, 0);
}
public void actionPerformed(ActionEvent ae) {
repaint();
x += velx;
y += vely;
}
public void left() {
velx = -5;
vely = vely + 0;
}
public void right() {
velx = 5;
vely = vely + 0;
}
public void up() {
vely = -5;
velx = velx + 0;
}
public void down() {
vely = 5;
velx = velx + 0;
}
public void stopMovement_UP() {
vely = 0;
velx = velx + 0;
}
public void stopMovement_DOWN() {
vely = 0;
velx = velx + 0;
}
public void stopMovement_LEFT() {
velx = 0;
vely = vely + 0;
}
public void stopMovement_RIGHT() {
velx = 0;
vely = vely + 0;
}
#Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A) {
left();
if (x < 0) {
x = 0;
}
}
else if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_D) {
right();
//checck if the graphic aka player moves out of the boundary
}
else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) {
down();
}
else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) {
up();
if (y < 0) {
y = 0;
}
}
}
#Override
public void keyTyped(KeyEvent e) { }
#Override
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_A) {
stopMovement_LEFT();
if (x < 0) {
x = 0;
}
}
else if (keyCode == KeyEvent.VK_RIGHT || keyCode == KeyEvent.VK_D) {
stopMovement_RIGHT();
if (x > 436) {
x = x + 2;
}
}
else if (keyCode == KeyEvent.VK_DOWN || keyCode == KeyEvent.VK_S) {
stopMovement_DOWN();
}
else if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_W) {
stopMovement_UP();
if (y < 0) {
y = 0;
}
}
}
public static void main(String[] args) {
Game game = new Game();
game.getBackground();
}
}
In method actionPerformed, you are changing values of x and y but you are not checking whether the calculated values are within the bounds of the Game panel.
In method paint (in class Game) the x and y coordinates are within the coordinate space of the panel, i.e. Game. The x coordinate of the left edge of Game is 0 (zero). The x coordinate of the right edge is the width of Game which you can retrieve via method getWidth.
Similarly, the y coordinate of the top edge (of Game) is zero and the y coordinate of the bottom edge is the height of Game which you can retrieve via method getHeight.
Hence you compare the calculated value of variables x and y (in method actionPerformed) with the width and height (of Game) to see whether they are outside the bounds of Game.
public void actionPerformed(ActionEvent ae) {
x += velx;
if (x > getWidth() || x < 0) {
// 'x' is outside of the bounds
}
y += vely;
if (y > getHeight() || y < 0) {
// 'y' is outside of the bounds
}
repaint();
}
I think that you should call method repaint after you have calculated the new values for x and y (and not before, as in the code in your question).
I don't know how you want the player to move once he hits one of the edges (of Game) so I only wrote a comment in the if conditions in the above code.
If you haven't already done so, I recommend reading Performing Custom Painting lesson in Creating a GUI With Swing trail of Oracle's Java tutorials.
I'm a newbie in Java and I'm trying to make a ship fire a bullet. What I want is actually make the ship fire bullets as long as the Spacebar button is being held down.
I've successfully made the ship move here and there and also fire the bullet. However the bullet just won't go up. Here's my code -
package learningPackage;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
public class Draw extends JFrame implements Runnable {
//Variables for the x and y coordinates, xDirection for modifying the values of x only.
int x, y, xDirection;
int bx, by;
Image dbImage;
Graphics dbGraphics;
boolean shot;
Rectangle bullet;
//Thread run
public void run() {
try {
while (true) {
move();
shoot();
//Setting sleep to 0 will make it light-speed!
Thread.sleep(5);
}
}
catch (Exception e) {
System.out.println("Error!");
}
}
//Ship move
//Ship moves only in one direction, x - axis
public void move() {
x += xDirection;
//Collision detection
if (x <= 10) {
x = 10;
}
if (x >= 415) {
x = 415;
}
}
//KeyListeners
public class AL extends KeyAdapter {
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
xDirection = -2;
}
if (keyCode == e.VK_RIGHT) {
xDirection = 2;
}
if (keyCode == e.VK_SPACE) {
shot = true;
}
}
public void keyReleased(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == e.VK_LEFT) {
xDirection = 0;
}
if (keyCode == e.VK_RIGHT) {
xDirection = 0;
}
if (keyCode == e.VK_SPACE) {
shot = false;
}
}
}
//Constructor for the game frame
public Draw() {
super("Game");
setSize(500, 500);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
addKeyListener(new AL());
x = 200;
y = 465;
setVisible(true);
}
//Double - buffering
public void paint(Graphics g) {
dbImage = createImage(getWidth(), getHeight());
dbGraphics = dbImage.getGraphics();
paintComponent(dbGraphics);
g.drawImage(dbImage, 0, 0, this);
}
//All the graphics
public void paintComponent(Graphics g) {
bullet = new Rectangle(bx, by, 10, 10);
g.setColor(Color.RED);
//Ship rectangle
g.fillRect(x, y, 75, 25);
//Gun rectangle
g.fillRect(x + 32, y - 15, 10, 15);
//Setting the same values for bx and by as x and y so that the bullet will start from the Gun rectangle
bx = x + 32;
by = y - 15;
if (shot == true) {
g.setColor(Color.BLACK);
g.fillRect(bx, by, bullet.width, bullet.height);
}
repaint();
}
public void shoot() {
if (shot == true) {
by = by - 2;
}
if (by <= -5) {
//Resetting values
bx = x + 32;
by = y - 15;
bullet = new Rectangle(bx, by, 10, 10);
shot = false;
}
}
//Main method
public static void main(String[] args) {
Draw gameTry = new Draw();
Thread t1 = new Thread(gameTry);
t1.start();
}
}
Here's what happens when I just move the ship, working perfectly fine -
Here's what happens when I hold down space -
(Sorry for not being able to embed pics in the post itself, I'm new to Stack Overflow as well!)
I was actually coping this code from a tutorial but since the tutorial-code wasn't working out, I decided to do this on my own, but I can't do it on my own as well!
Help will definitely be appreciated!
The reason for the bullet not moving becomes appearant when you compare your shoot() method, and the paintComponent method.
Shoot checks if you have the shot boolean set, and if so, moves the bullet y position up by 2.
When the bullet leaves the top of the screen, it resets the "bullet".
This is all fine, it does what it's supposed to.
public void shoot() {
if (shot == true) {
by = by - 2; //this is fine, it moves the bullet up
}
if (by <= -5) {
//Resetting values
bx = x + 32;
by = y - 15;
bullet = new Rectangle(bx, by, 10, 10);
shot = false;
}
}
Then comes paintComponent, which is executed time your game is "painted" to the screen.
It defines a rectangle for the bullet at its current position,
draws the ship,
Then overwrites the bullet's x and y position so it sits on top of the ship.
That is where your problem is
public void paintComponent(Graphics g) {
bullet = new Rectangle(bx, by, 10, 10);
g.setColor(Color.RED);
g.fillRect(x, y, 75, 25);
g.fillRect(x + 32, y - 15, 10, 15);
//you are messing with bx and by here.
//probably because you wanted the bullet to be in the
//same position as the ship.
//this means they will be put back into the same position
//for every time your game is painted to the screen.
//my advice is, do *not* do this here.
bx = x + 32;
by = y - 15;
if (shot == true) {
g.setColor(Color.BLACK);
g.fillRect(bx, by, bullet.width, bullet.height);
}
repaint();
}
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!
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.
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();
}
}