This question already has answers here:
How to change JFrame icon [duplicate]
(8 answers)
Closed 6 years ago.
How do I add an icon to this snake game and where do I put it, also how do I increase speed of the game after so many points? The code below is the class in which I believe these two pieces of code should go.
import java.awt.BorderLayout;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.IOException;
import java.util.LinkedList;
import java.util.Random;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class SnakeGame extends JFrame {
private static final long FRAME_TIME = 1000L / 50L;
private static final int MIN_SNAKE_LENGTH = 5;
private static final int MAX_DIRECTIONS = 3;
private BoardPanel board;
private SidePanel side;
private Random random;
private Clock logicTimer;
private boolean isNewGame;
private boolean isGameOver;
private boolean isPaused;
private LinkedList<Point> snake;
private LinkedList<Direction> directions;
private int score;
private int foodsEaten;
private int nextFoodScore;
private SnakeGame() {
super("Snake");
setLayout(new BorderLayout());
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
this.board = new BoardPanel(this);
this.side = new SidePanel(this);
add(board, BorderLayout.CENTER);
add(side, BorderLayout.EAST);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch(e.getKeyCode()) {
case KeyEvent.VK_W:
case KeyEvent.VK_UP:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.South && last != Direction.North) {
directions.addLast(Direction.North);
}
}
}
break;
case KeyEvent.VK_S:
case KeyEvent.VK_DOWN:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.North && last != Direction.South) {
directions.addLast(Direction.South);
}
}
}
break;
case KeyEvent.VK_A:
case KeyEvent.VK_LEFT:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.East && last != Direction.West) {
directions.addLast(Direction.West);
}
}
}
break;
case KeyEvent.VK_D:
case KeyEvent.VK_RIGHT:
if(!isPaused && !isGameOver) {
if(directions.size() < MAX_DIRECTIONS) {
Direction last = directions.peekLast();
if(last != Direction.West && last != Direction.East) {
directions.addLast(Direction.East);
}
}
}
break;
case KeyEvent.VK_P:
if(!isGameOver) {
isPaused = !isPaused;
logicTimer.setPaused(isPaused);
}
break;
case KeyEvent.VK_ENTER:
if(isNewGame || isGameOver) {
resetGame();
}
break;
}
}
});
pack();
setLocationRelativeTo(null);
setVisible(true);
}
private void startGame() {
this.random = new Random();
this.snake = new LinkedList<>();
this.directions = new LinkedList<>();
this.logicTimer = new Clock(10.0f);
//////////////////////////////////////////////////////////////////////////////////////////////////
this.isNewGame = true;
logicTimer.setPaused(true);
while(true) {
long start = System.nanoTime();
logicTimer.update();
if(logicTimer.hasElapsedCycle()) {
updateGame();
}
board.repaint();
side.repaint();
long delta = (System.nanoTime() - start) / 1000000L;
if(delta < FRAME_TIME) {
try {
Thread.sleep(FRAME_TIME - delta);
} catch(Exception e) {
e.printStackTrace();
}
}
}
}
private void updateGame() {
TileType collision = updateSnake();
if(collision == TileType.Food) {
foodsEaten++;
score += nextFoodScore;
spawnFood();
} else if(collision == TileType.SnakeBody) {
isGameOver = true;
logicTimer.setPaused(true);
} else if(nextFoodScore > 10) {
}
}
private TileType updateSnake() {
Direction direction = directions.peekFirst();
Point head = new Point(snake.peekFirst());
switch(direction) {
case North:
head.y--;
break;
case South:
head.y++;
break;
case West:
head.x--;
break;
case East:
head.x++;
break;
}
if(head.x < 0 || head.x >= BoardPanel.COL_COUNT || head.y < 0 || head.y >= BoardPanel.ROW_COUNT) {
return TileType.SnakeBody;
}
TileType old = board.getTile(head.x, head.y);
if(old != TileType.Food && snake.size() > MIN_SNAKE_LENGTH) {
Point tail = snake.removeLast();
board.setTile(tail, null);
old = board.getTile(head.x, head.y);
}
if(old != TileType.SnakeBody) {
board.setTile(snake.peekFirst(), TileType.SnakeBody);
snake.push(head);
board.setTile(head, TileType.SnakeHead);
if(directions.size() > 1) {
directions.poll();
}
}
return old;
}
private void resetGame() {
this.score = 0;
this.foodsEaten = 0;
this.isNewGame = false;
this.isGameOver = false;
Point head = new Point(BoardPanel.COL_COUNT / 2, BoardPanel.ROW_COUNT / 2);
snake.clear();
snake.add(head);
board.clearBoard();
board.setTile(head, TileType.SnakeHead);
directions.clear();
directions.add(Direction.North);
logicTimer.reset();
spawnFood();
}
public boolean isNewGame() {
return isNewGame;
}
public boolean isGameOver() {
return isGameOver;
}
public boolean isPaused() {
return isPaused;
}
private void spawnFood() {
this.nextFoodScore = 10;
int index = random.nextInt(BoardPanel.COL_COUNT * BoardPanel.ROW_COUNT - snake.size());
int freeFound = -1;
for(int x = 0; x < BoardPanel.COL_COUNT; x++) {
for(int y = 0; y < BoardPanel.ROW_COUNT; y++) {
TileType type = board.getTile(x, y);
if(type == null || type == TileType.Food) {
if(++freeFound == index) {
board.setTile(x, y, TileType.Food);
break;
}
}
}
}
}
public int getScore() {
return score;
}
public int getFoodsEaten() {
return foodsEaten;
}
public int getNextFoodScore() {
return nextFoodScore;
}
public Direction getDirection() {
return directions.peek();
}
public static void main(String[] args) {
SnakeGame snake = new SnakeGame();
snake.startGame();
}
}
Create a new ImageIcon object like this:
ImageIcon img = new ImageIcon(pathToFileOnDisk);
Then set it to your JFrame with setIconImage():
myFrame.setIconImage(img.getImage());
Also checkout setIconImages() which takes a List instead.
How to change JFrame icon
It 's not my answer !!!!
Related
I have this array of classes extending JButtons, and when one is clicked it registers that.
Then if another one gets clicked, they should 'switch' places. So my question is: How can i implement it that is swiches the buttons (so far i got before) and (the important part) how can i 'refresh' the GUI, so the user can see the chenge visually. Following the code:
import javax.swing.*; import Pieces.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Game extends JFrame {
private static final int width = 8;
private static final int height = 8;
private static Piece clicked;
public static Piece[][] fields = new Piece[width][height];
private JPanel main = new JPanel();
public static void init(JPanel g) {
for (int y = 0; y < fields.length; y++) {
for (int x = 0; x < fields[y].length; x++) {
if (y == 0) {
switch (x) {
case 0,7:
fields[y][x] = new Rook(x,y,1);
break;
case 1,6:
fields[y][x] = new Knight(x,y,1);
break;
case 2,5:
fields[y][x] = new Bishop(x,y,1);
break;
case 3:
fields[y][x] = new Queen(x,y,1);
break;
case 4:
fields[y][x] = new King(x,y,1);
break;
}
}
if (y == 1) fields[y][x] = new Pawn(x, y, 1);
else if (y >= 2 && y <= 5) fields[y][x] = new Empty(x,y,9);
else if (y == 6) fields[y][x] = new Pawn(x, y, 0);
else if(y == 7) {
switch (x) {
case 0,7:
fields[y][x] = new Rook(x,y,0);
break;
case 1,6:
fields[y][x] = new Knight(x,y,0);
break;
case 2,5:
fields[y][x] = new Bishop(x,y,0);
break;
case 3:
fields[y][x] = new Queen(x,y,0);
break;
case 4:
fields[y][x] = new King(x,y,0);
break;
}
}
fields[y][x].addActionListener(e -> {
var p = (Piece) e.getSource();
var pPos = p.getCell();
if(clicked == null) {
clicked = p;
System.out.println(fields[clicked.getCell().y][clicked.getCell().x]);
clicked.setForeground(Color.yellow.darker());
System.out.println("clicked " + pPos);
} else if (pPos == clicked.getCell()) {
clicked.setForeground(Color.white);
System.out.println("deselecting " + pPos);
clicked = null;
} else {
if (clicked.canMoveTo(fields, pPos)) {
fields[p.getCell().y][p.getCell().x] = clicked;
fields[clicked.getCell().y][clicked.getCell().x] = new Empty(clicked.getCell().x, clicked.getCell().y, 9);
System.out.println("moving " + clicked.getCell() + " to " + pPos);
clicked.setForeground(Color.white);
}
else System.out.println("canĀ“t move there, sry");
clicked = null;
}
SwingUtilities.updateComponentTreeUI(g);
});
g.add(fields[y][x]);
}
}
}
public Game() {
main.setBackground(Color.darkGray.darker());
main.setLayout(new GridLayout(8,8));
this.setSize(800,800);
init(main);
this.add(main);
this.setDefaultCloseOperation(EXIT_ON_CLOSE);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public static void main(String[] args) {
var g = new Game();
}
}
package Pieces;
import javax.swing.*;
import java.awt.*;
public abstract class Piece extends JButton {
private final int isWhite; //0 is false, 1 is true, 9 is undefined
private Point cell;
public Piece(int x, int y, int isWhite) {
cell = new Point(x, y);
this.isWhite = isWhite;
this.setForeground(Color.white);
this.setOpaque(false);
//this.setContentAreaFilled(false);
}
public Point getCell() {
return cell;
}
public int isWhite() {
return isWhite;
}
public boolean canMoveTo(Piece[][] fields, Point point) {
return true;
}
}
*all the pieces are setup like this
package Pieces;
public class Bishop extends Piece{
public Bishop(int x, int y, int isWhite) {
super(x, y, isWhite);
this.setText("Bishop");
}
}
(yee, this will hopefully be chess sometimes)
I have the following code:
package myprojectgame.entities.creature;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import myprojectgame.Game;
import myprojectgame.Handler;
import myprojectgame.gfx.Animation;
import myprojectgame.gfx.Assets;
import myprojectgame.input.KeyManager;
import static myprojectgame.input.KeyManager.keys;
public abstract class Player extends Creature {
// Animations ---> while moving
private Animation down;
private Animation up;
private Animation left;
private Animation right;
// Animations --> idle
private Animation down_idle;
private Animation up_idle;
private Animation left_idle;
private Animation right_idle;
// Last pressed boolean variable --> initialize it to down
public boolean lastPressed = handler.getKeyManager().down;
public Player(Handler handler,float x, float y) {
super(handler,x, y,Creature.DEFAULT_CREATURE_WIDTH,Creature.DEFAULT_CREATURE_HEIGHT);
bounds.x = 16;
bounds.y = 14;
bounds.width = 25;
bounds.height = 43;
// Animations --> while moving instantiation
down = new Animation(300,Assets.player_down);
left = new Animation(300,Assets.player_left);
right = new Animation(300,Assets.player_right);
up = new Animation(300,Assets.player_up);
// Animations --> while idle instantiation
down_idle= new Animation(500,Assets.player_down_idle);
right_idle= new Animation(500,Assets.player_right_idle);
left_idle= new Animation(500,Assets.player_left_idle);
up_idle= new Animation(500,Assets.player_up_idle);
}
#Override
public void tick() {
down.tick();
up.tick();
right.tick();
left.tick();
down_idle.tick();
up_idle.tick();
right_idle.tick();
left_idle.tick();
getInput();
move();
handler.getCamera().centerOnEntity(this);
}
private void getInput() {
xMove = 0;
yMove = 0;
if (handler.getKeyManager().up) {
yMove = -speed;
lastPressed = handler.getKeyManager().up;
}
if (handler.getKeyManager().down) {
yMove = speed;
lastPressed = handler.getKeyManager().down;
}
if (handler.getKeyManager().left) {
xMove = -speed;
lastPressed = handler.getKeyManager().left;
}
if (handler.getKeyManager().right) {
xMove = speed;
lastPressed = handler.getKeyManager().right;
}
}
#Override
public void render(Graphics g) {
g.drawImage(getCurrentAnimationFrame(),(int) (x - handler.getCamera().getxOffset()), (int) (y - handler.getCamera().getyOffset()),(width),(height), null);
}
private BufferedImage getCurrentAnimationFrame() {
if (handler.getKeyManager().left && lastPressed == handler.getKeyManager().left) {
return left.getCurrentFrame();
} else if ( !(handler.getKeyManager().left)) {
return left_idle.getCurrentFrame();
}
if (handler.getKeyManager().right && lastPressed == handler.getKeyManager().right) {
return right.getCurrentFrame();
} else if ( !(handler.getKeyManager().right) && lastPressed == handler.getKeyManager().right) {
return right_idle.getCurrentFrame();
}
if (handler.getKeyManager().up && lastPressed == handler.getKeyManager().up) {
return up.getCurrentFrame();
} else if ( !(handler.getKeyManager().up) && lastPressed == handler.getKeyManager().up ) {
return up_idle.getCurrentFrame();
}
if (handler.getKeyManager().down && lastPressed == handler.getKeyManager().down) {
return down.getCurrentFrame();
} else if ( !(handler.getKeyManager().down) && lastPressed ==
handler.getKeyManager().down ) {
return down_idle.getCurrentFrame();
}
return null;
}
}
The problem is that I cannot get my getCurrentAnimationFrame() method to return the proper idle animations(or in this iteration of my code,any other animation besides left and left_idle).
My keys are defined in my KeyManager class like this:
up = keys[KeyEvent.VK_W] || keys[KeyEvent.VK_UP];
down = keys[KeyEvent.VK_S] || keys[KeyEvent.VK_DOWN];
left = keys[KeyEvent.VK_A] || keys[KeyEvent.VK_LEFT];
right = keys[KeyEvent.VK_D] || keys[KeyEvent.VK_RIGHT];
How can I properly implement Key events/strokes to return the right animations on key release/key press?
Your conditions and boolean logic are overcomplicated:
private void getInput() {
xMove = 0;
yMove = 0;
if (handler.getKeyManager().up) {
yMove = -speed;
lastPressed = handler.getKeyManager().up;
}
//...
}
private BufferedImage getCurrentAnimationFrame() {
if (handler.getKeyManager().left && lastPressed == handler.getKeyManager().left) {
return left.getCurrentFrame();
} else if ( !(handler.getKeyManager().left)) {
return left_idle.getCurrentFrame();
}
//...
return null;
}
Is same as:
private void getInput() {
xMove = 0;
yMove = 0;
KeyManager km = handler.getKeyManager();
if (km.up) {
yMove = -speed;
lastPressed = true;
}
//...
}
private BufferedImage getCurrentAnimationFrame() {
KeyManager km = handler.getKeyManager();
if (km.left && lastPressed) {
// replaced lastPressed == handler.getKeyManager().left since km.left must be true
return left.getCurrentFrame();
} else if (!km.left) {
return left_idle.getCurrentFrame();
}
//...
return null;
}
I do not see where are you setting lastPressed to false, looks to me it will be set to true (with first key press) and remains true. Since it is always true, your condition in getCurrentAnimationFrame is effectively:
private BufferedImage getCurrentAnimationFrame() {
KeyManager km = handler.getKeyManager();
if (km.left) {
return left.getCurrentFrame();
} else {
return left_idle.getCurrentFrame();
}
//UNREACHABLE CODE!
return null;
}
Even if it doesn't remain true, your code is like if left, return left animation, if not left return left idle animation. I think your somehow mixed booleans with key codes as you say "lastPressed variable is supposed to store the value of the last pressed key".
I would probably define direction enum:
public enum DirectionEnum {
LEFT, RIGHT, UP, DOWN;
}
And use it like this:
DirectionEnum lastPressed = null;
private void getInput() {
xMove = 0;
yMove = 0;
KeyManager km = handler.getKeyManager();
if (km.up) {
yMove = -speed;
lastPressed = DirectionEnum.UP;
}
//...
}
private BufferedImage getCurrentAnimationFrame() {
KeyManager km = handler.getKeyManager();
if (lastPressed == null) {
if (km.left) {
return left.getCurrentFrame();
}
//...
} else {
switch (lastPressed) {
case DOWN:
if (!km.down){
return down_idle.getCurrentFrame();
}
break;
//...
default:
throw new RuntimeException("Invalid direction " + lastPressed);
}
}
return null;
}
But I do not know if it is correct, because lastPressed will be null only first time (or never), and then you will see only idle animations. So you should probably decide when to set lastPressed back to null?
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 5 years ago.
Everybody!
I'm here to annoy you once more)
So, I was trying to make a game, I described some classes:
GameObject - just an object which has X,Y,Sizes,Name and may be drawn and moved:
package pkg3dgraphics;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
public class GameObject {
protected String name;
protected int xCoord,yCoord,mySizeX = 25,mySizeY = 25;
public GameObject(){
}
public GameObject(String newName, int startXCoord, int startYCoord){
setName(newName);
setX(startXCoord);
setY(startYCoord);
}
public void SetSize(int X, int Y){
mySizeX = X;
mySizeY = Y;
}
public int getXsize(){
return mySizeX;
}
public int getYsize(){
return mySizeY;
}
public String getName(){
return name;
}
public void setName(String newName){
name = newName;
}
public int getX(){
return xCoord;
}
public int getY(){
return yCoord;
}
public void setX(int newXCoord){
xCoord = newXCoord;
}
public void setY(int newYCoord){
yCoord = newYCoord;
}
public void moveTo(int X,int Y){
xCoord = X;
yCoord = Y;
}
public void moveBy(int X,int Y){
xCoord +=X;
yCoord +=Y;
}
public void Draw(GraphicsContext currentContext){
currentContext.setFill(Color.GREEN);
currentContext.setStroke(Color.BLUE);
currentContext.fillOval(xCoord,yCoord, mySizeX,mySizeY );
}
}
And I have Shooter extending previous class and here he goes:
package pkg3dgraphics;
public class Shooter extends GameObject {
public Shooter(){
}
public Shooter(String newName, int startXCoord, int startYCoord){
setName(newName);
setX(startXCoord);
setY(startYCoord);
}
public Bullet shoot(String direction){
Bullet newBullet = new Bullet(direction);
return newBullet;
}
}
Also I've got Bullets which are , you know, bullets:
package pkg3dgraphics;
import javafx.scene.paint.Color;
import javafx.scene.canvas.GraphicsContext;
public class Bullet extends GameObject{
String myDirection;
protected int mySpeed = 5,mySizeX = 5,mySizeY = 5;
boolean goNorth,goSouth,goWest,goEast;
protected boolean active = false;
public void setSpeed(int newSpeed){
mySpeed = newSpeed;
}
public void setDirection(String newDirection){
myDirection = newDirection;
active = true;
if ( myDirection == "North" )
goNorth = true;
if ( myDirection == "South" )
goSouth = true;
if ( myDirection == "West" )
goWest = true;
if ( myDirection == "East" )
goEast = true;
}
Bullet(String direction ){
myDirection = direction;
active = true;
if ( myDirection == "North" )
goNorth = true;
if ( myDirection == "South" )
goSouth = true;
if ( myDirection == "West" )
goWest = true;
if ( myDirection == "East" )
goEast = true;
}
public void advance(int W,int H,GraphicsContext gc){
if (xCoord <= W && xCoord >= 0 && yCoord <= H && yCoord >= 0 ) {
if (goNorth) moveBy(0,mySpeed);
if (goSouth) moveBy(0,mySpeed);
if (goWest) moveBy(mySpeed,0);
if (goEast) moveBy(mySpeed,0);
}else{
active = false;
Vanish(gc);
goNorth = false;
goSouth = false;
goWest = false;
goEast = false;
}
}
public void Vanish(GraphicsContext gc){
gc.setFill(Color.WHITE);
}
}
The purpose was to have this guy shooting in a next way:
When I catch pressed button I use precreated inactive bullet and direct it to go in a several direction.
When this bullet crosses a window's border it becomes inactive and stops.
For this I have an array of Bullets.
When user presses shoot key I seek in the array for an inactive Bullet and if there is none I create additional one which follows the path user wanted.
Well, this way to Implement bullets probably is not the best, but I didn't come up with another.
So I compiled my Main Class:
package pkg3dgraphics;
import java.util.Vector;
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import static javafx.application.Application.launch;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import static javafx.scene.input.KeyCode.DOWN;
import static javafx.scene.input.KeyCode.LEFT;
import static javafx.scene.input.KeyCode.RIGHT;
import static javafx.scene.input.KeyCode.SHIFT;
import static javafx.scene.input.KeyCode.UP;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
public int WINDOWWIDTH = 600;
public int WINDOWHEIGHT = 400;
boolean goNorth,goSouth,goWest,goEast,running,ShootNorth,ShootSouth,ShootWest,ShootEast;
Shooter player = new Shooter("Player",WINDOWWIDTH/2,WINDOWHEIGHT/2);
Bullet bullets[] = new Bullet[500];
int bulletsSize = 0;
Canvas mainCanvas = new Canvas(WINDOWWIDTH,WINDOWHEIGHT);
GraphicsContext mainContext = mainCanvas.getGraphicsContext2D();
#Override
public void start(Stage primaryStage) {
Group root = new Group();
Canvas mainCanvas = new Canvas(WINDOWWIDTH,WINDOWHEIGHT);
GraphicsContext mainContext = mainCanvas.getGraphicsContext2D();
root.getChildren().add(mainCanvas);
Scene scene = new Scene(root,WINDOWWIDTH,WINDOWHEIGHT);
scene.setOnKeyPressed(new EventHandler<KeyEvent> (){
#Override
public void handle(KeyEvent event){
switch(event.getCode()){
case UP: ShootNorth = true; break;
case DOWN: ShootSouth = true; break;
case LEFT: ShootWest = true; break;
case RIGHT: ShootEast = true; break;
case W: goNorth = true; break;
case S: goSouth = true; break;
case A: goWest = true; break;
case D: goEast = true; break;
}
}
});
scene.setOnKeyReleased(new EventHandler <KeyEvent>(){
#Override
public void handle(KeyEvent event){
switch(event.getCode()){
case UP: ShootNorth = false; break;
case DOWN: ShootSouth = false; break;
case LEFT: ShootWest = false; break;
case RIGHT: ShootEast = false; break;
case W: goNorth = false; break;
case S: goSouth = false; break;
case A: goWest = false; break;
case D: goEast = false; break;
}
}
});
primaryStage.setScene(scene);
primaryStage.show();
AnimationTimer Timer = new AnimationTimer(){
#Override
public void handle (long now){
int dx = 0, dy = 0;
if (goNorth) dy = -1;
if (goSouth) dy = 1;
if (goWest) dx = -1;
if (goEast) dx = 1;
if (running) { dx *= 3; dy *= 3;}
mainContext.clearRect(0,0,WINDOWWIDTH,WINDOWHEIGHT);
player.moveBy(dx, dy);
CheckShoot();
player.Draw(mainContext);
}
};
Timer.start();
}
public void CheckShoot(){
String direction = null;
int count = 0;
if (ShootNorth)
{
direction = "North";
}
if (ShootSouth)
{
direction = "South";
}
if (ShootWest)
{
direction = "West";
}
if (ShootEast)
{
direction = "East";
}
for (int i = 0; i < bulletsSize; i ++ )
{
if (bullets[i].active = false ){
bullets[i].setDirection(direction);
bullets[i].moveTo(player.getX(),player.getY());
break;
}else count ++;
}
if ( count == bulletsSize ) {
bulletsSize++;
bullets[bulletsSize] = player.shoot(direction);
}
}
public void advanceAll(){
for (int i = 0; i < bulletsSize; i ++ )
{
bullets[i].advance(WINDOWWIDTH,WINDOWHEIGHT,mainContext);
}
}
}
Application runs but then I get this problem looped untill I close the application:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at pkg3dgraphics.Main.CheckShoot(Main.java:126)
at pkg3dgraphics.Main$3.handle(Main.java:91)
at javafx.animation.AnimationTimer$AnimationTimerReceiver.lambda$handle$483(AnimationTimer.java:57)
at java.security.AccessController.doPrivileged(Native Method)
at javafx.animation.AnimationTimer$AnimationTimerReceiver.handle(AnimationTimer.java:56)
at com.sun.scenario.animation.AbstractMasterTimer.timePulseImpl(AbstractMasterTimer.java:357)
at com.sun.scenario.animation.AbstractMasterTimer$MainLoop.run(AbstractMasterTimer.java:267)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:506)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:490)
at com.sun.javafx.tk.quantum.QuantumToolkit.lambda$runToolkit$403(QuantumToolkit.java:319)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
at java.lang.Thread.run(Thread.java:748)
So, that is all I wanted to complain about.
If someone has any idea why these all occure I would be glad and grateful if you shared the secret with me.(And all others)
You seem to have created the array, without creating each members
Bullet bullets[] = new Bullet[500];
Then you iterate through them, while they are nulls
for (int i = 0; i < bulletsSize; i ++ )
{
if (bullets[i].active = false ){
bullets[i].setDirection(direction);
bullets[i].moveTo(player.getX(),player.getY());
break;
}else count ++;
}
bullets[i] = null, and you try to invoke .active on it.
Solution:
Try to check nulls
if (bullets[i] == null) { bullets[i] = new Bullet(); }
if (bullets[i].active = false ){
bullets[i].setDirection(direction);
bullets[i].moveTo(player.getX(),player.getY());
break;
}else count ++;
Read What is NullPointerException
Hello I'm fairly new to programming and this is my first time posting here so any help would be appreciated so:
my problem is that I"m trying to create some kind of 2D shooter game in java but I don't know if my simple game loop is good because when i shoot a missile it shoots a one every 20 ms and it's too fast and shoots a ton of missiles at once so is there any way to adjust it ? Like to keep some delay between every missile and the other??
and please tell me if i have problems or bad programming in my code !!
this is my game panel where most of the game happens and where my loop and adding missiles method in
public class GamePanel extends JPanel implements KeyListener {
Measurments mesure = new Measurments();
int panel_width = mesure.getUniversalWidth();
int panel_height = mesure.getUniversalHeight();
Timer timer;
Random rand = new Random();
ArrayList<Enemy> enemies = new ArrayList<>();
ArrayList<Missile> missiles = new ArrayList<>();
Player player = new Player(0, 0);
boolean up = false;
boolean down = false;
boolean right = false;
boolean left = false;
boolean isShooting = false;
boolean isRunning = true;
public boolean gameRunning() {
return isRunning;
}
int count = 5;
int missilesCount = 6;
public GamePanel() {
timer = new Timer(20, new ActionListener() {
public void actionPerformed(ActionEvent e) {
StartGame();
repaint();
}
});
setSize(panel_width, panel_height);
addKeyListener(this);
timer.start();
for (int i = 0; i < count; i++) {
addEnemy(new Enemy(rand.nextInt(750), rand.nextInt(500)));
}
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
player.paint(g2d);
for (int i = 0; i < enemies.size(); i++) {
Enemy temp = enemies.get(i);
temp.paint(g2d);
}
for (int i = 0; i < missiles.size(); i++) {
Missile mis = missiles.get(i);
mis.paint(g2d);
mis.behave();
}
}
public void StartGame() {
if (isRunning) {
runGame();
setBackground(Color.YELLOW);
} else {
setBackground(Color.BLACK);
}
}
public void runGame() {
update();
};
public void update() {
player.checkBorders();
checkColls();
if (up) {
player.updateUp();
}
if (down) {
player.updateDown();
}
if (right) {
player.updateRight();
}
if (left) {
player.updateLeft();
}
if (isShooting) {
for (int i = 0; i < 5; i++) {
missiles.add(new Missile(player.getX() + 16, player.getY() + 16));
}
}
for (int i = 0; i < missiles.size(); i++) {
Missile temp = missiles.get(i);
if (temp.getX() == panel_width) {
RemoveMissile(temp);
}
}
}
public void addEnemy(Enemy e) {
enemies.add(e);
}
public void removeEnemy(Enemy e) {
enemies.remove(e);
}
public void addMissile(Missile e) {
missiles.add(e);
}
public void RemoveMissile(Missile e) {
missiles.add(e);
}
public void checkColls() {
for (int i = 0; i < enemies.size(); i++) {
Enemy tempEnm = enemies.get(i);
for (int e = 0; e < missiles.size(); e++) {
Missile tempMis = missiles.get(e);
if (tempMis.missileRect().intersects(tempEnm.enemyRect())) {
enemies.remove(tempEnm);
missiles.remove(tempMis);
}
}
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = true;
}
if (key == e.VK_DOWN) {
down = true;
}
if (key == e.VK_RIGHT) {
right = true;
}
if (key == e.VK_LEFT) {
left = true;
}
if (key == e.VK_ENTER) {
isRunning = true;
}
if (key == e.VK_SPACE) {
isShooting = true;
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == e.VK_UP) {
up = false;
}
if (key == e.VK_DOWN) {
down = false;
}
if (key == e.VK_RIGHT) {
right = false;
}
if (key == e.VK_LEFT) {
left = false;
}
if (key == e.VK_SPACE) {
isShooting = false;
}
}
public void keyTyped(KeyEvent e) {
}
}
Thanks in advance !!
private long fired = 0L;
public void update() {
...
// firing missiles: only if the missile count is less than the max., and the elapsed
// time is more than a limit (100 ms)
if ( isShooting && missiles.size() < missilesCount &&
( System.currentTimeMilis() - this.fired ) > 100 ) {
missiles.add( new Missile( player.getX() + 16, player.getY() + 16 ) );
// time of last firing
this.fired = System.currentTimeMilis();
}
...
}
public void RemoveMissile(Missile e) {
// as Guest is asked in another answer, this method should remove, not add...
missiles.remove(e);
}
I'm currently making a space invaders-esque game for my software engineering course. I've already got everything working that satisfies the requirements, so this isn't a 'solve my homework' kind of question. My problem is that the game will lag (at what seems like random times & intervals) to the point where it becomes too frustrating to play. Some things I think might be causing this - though I'm not positive - are as follows:
Problem with timer event every 10 ms (I doubt this because of the very limited resources required for this game).
Problem with collision detection (checking for collision with every visible enemy every 10 ms seems like it would take up a large chunk of resources)
Problem with repainting? This seems unlikely to me however...
#SuppressWarnings("serial")
public class SIpanel extends JPanel {
private SIpanel panel;
private Timer timer;
private int score, invaderPace, pulseRate, mysteryCount, distanceToEdge;
private ArrayList<SIthing> cast;
private ArrayList<SIinvader> invaders, dead;
private ArrayList<SImissile> missileBase, missileInvader;
private SIinvader[] bottomRow;
private SIbase base;
private Dimension panelDimension;
private SImystery mysteryShip;
private boolean gameOver, left, right, mysteryDirection, space, waveDirection;
private boolean runningTimer;
private Music sound;
private void pulse() {
pace();
processInputs();
if (gameOver) gameOver();
repaint();
}
private void pace() {
// IF invaders still live
if (!invaders.isEmpty()) {
invaderPace++;
// Switch back manager
if (distanceToEdge <= 10) {
switchBack();
pulseRate = (pulseRate >= 16) ? (int) (pulseRate*(0.8)) : pulseRate;
waveDirection = !waveDirection;
distanceToEdge = calculateDistanceToEdge();
}
// Move invaders left/right
else if (invaderPace >= pulseRate) {
invaderPace = 0;
distanceToEdge = calculateDistanceToEdge();
moveAI();
invadersFire();
if (!dead.isEmpty()) removeDead();
if (mysteryCount < 1) tryInitMysteryShip();
}
// All invaders are kill, create new wave
} else if (missileBase.isEmpty() && missileInvader.isEmpty() && !cast.contains(mysteryShip)) {
// System.out.println("New Wave!");
newWave();
}
// Every pace
if (!missileBase.isEmpty()) moveMissileBase();
// Every two paces
if (invaderPace % 2 == 0) {
if (!missileInvader.isEmpty()) moveMissileInvader();
if (mysteryCount > 0) moveMysteryShip();
}
}
private void processInputs() {
if (left) move(left);
if (right) move(!right);
if (space) fireMissile(base, true);
}
protected void fireMissile(SIship ship, boolean isBase) {
if(isBase && missileBase.isEmpty()) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()-(ship.getHeight()/4));
missileBase.add(m);
cast.add(m);
} else if (!isBase && missileInvader.size()<3) {
base.playSound();
SImissile m = new SImissile(ship.getX()+(ship.getWidth()/2), ship.getY()+(ship.getHeight()/4));
missileInvader.add(m);
cast.add(m);
}
}
private void newWave() {
pulseRate = 50;
int defaultY=60, defaultX=120, defaultWidth=30, defaultHeight=24;
for(int i=0; i<5; i++) {
for(int j=0; j<10; j++) {
if (i<1) invaders.add(new SItop((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<3) invaders.add(new SImiddle((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
else if (i<5) invaders.add(new SIbottom((j*defaultWidth)+defaultX, (i*defaultHeight)+defaultY, defaultWidth, defaultHeight));
}
}
for (SIinvader s: invaders) {
cast.add(s);
}
if (!cast.contains(base)) {
cast.add(base);
}
bottomRow = getBottomRow();
}
private void tryInitMysteryShip() {
Random rand = new Random();
int x=rand.nextInt(1000);
if (x<=3) {
mysteryCount = 1;
if (rand.nextBoolean()) {
mysteryDirection = true;
}
if (mysteryDirection) {
mysteryShip = new SImystery(0, 60, 36, 18);
} else {
mysteryShip = new SImystery(480, 60, 36, 18);
}
cast.add(mysteryShip);
}
}
private void moveMysteryShip() {
int distance = 0;
if (mysteryDirection) {
mysteryShip.moveRight(5);
distance = getWidth() - mysteryShip.getX();
} else {
mysteryShip.moveLeft(5);
distance = 30+mysteryShip.getX()-mysteryShip.getWidth();
}
if (distance <= 5) {
dead.add(mysteryShip);
mysteryShip = null;
mysteryCount = 0;
}
}
private void removeDead() {
#SuppressWarnings("unchecked")
ArrayList<SIinvader> temp = (ArrayList<SIinvader>) dead.clone();
dead.clear();
for (SIinvader s : temp) {
invaders.remove(s);
cast.remove(s);
}
bottomRow = getBottomRow();
}
private void invadersFire() {
int[] p = new int[bottomRow.length];
for (int i=0; i<p.length; i++) {
for (int j=0; j<p.length; j++) {
p[j] = j;
}
Random rand = new Random();
int a=rand.nextInt(101);
if (a>=20) {
int b=rand.nextInt(p.length);
fireMissile(bottomRow[b], false);
}
}
}
private int calculateDistanceToEdge() {
int distance = 0;
SIinvader[] outliers = getOutliers();
if (waveDirection) {
distance = getWidth() - outliers[0].getX()-outliers[0].getWidth();
} else {
distance = outliers[1].getX();
}
return distance;
}
private SIinvader[] getOutliers() {
SIinvader leftMost = invaders.get(0), rightMost = invaders.get(0);
for (SIinvader s : invaders) {
if (s.getX() < leftMost.getX()) {
leftMost = s;
}
if (s.getX() > rightMost.getX()) {
rightMost = s;
}
}
return new SIinvader[] { rightMost, leftMost };
}
private SIinvader[] getBottomRow() {
SIinvader[] x = new SIinvader[(invaders.size()>10)?10:invaders.size()];
for (int i=0; i<x.length; i++) {
x[i] = invaders.get(i);
for (SIinvader s:invaders) {
if (s.getX() == x[i].getX()) {
if (s.getY() > x[i].getY()) {
x[i] = s;
}
}
}
}
return x;
}
private void move(boolean b) {
int defaultX = 5;
if (b) base.moveLeft(defaultX);
else base.moveRight(defaultX);
}
private void moveAI() {
for(SIinvader s : invaders) {
s.changeImage();
int defaultX = 5;
if (waveDirection) s.moveRight(defaultX);
else s.moveLeft(defaultX);
}
}
private void moveMissileBase() {
if (invaders.isEmpty()) return;
int movement = -5, bound = 0;
SImissile missile = missileBase.get(0);
missile.moveDown(movement);
SIinvader lowestInvader = getLowestInvader();
if (missile.getY() < (lowestInvader.getY() + lowestInvader.getHeight())) {
for (SIinvader s:bottomRow) {
if (checkCollision(missile, s)) {
s.setHit();
dead.add(s);
cast.remove(missile);
missileBase.clear();
score += s.value;
return;
}
}
if (mysteryCount > 0) {
if (checkCollision(missile, mysteryShip)) {
mysteryShip.setHit();
dead.add(mysteryShip);
cast.remove(missile);
missileBase.clear();
score += mysteryShip.value;
return;
}
}
if (missile.getY() < bound) {
missileBase.remove(missile);
cast.remove(missile);
}
}
}
private SIinvader getLowestInvader() {
SIinvader lowest = bottomRow[0];
for (SIinvader invader : bottomRow) {
if (invader.getY() > lowest.getY()) {
lowest = invader;
}
}
return lowest;
}
private void moveMissileInvader() {
int movement = 5, bound = (int) panelDimension.getHeight();
for (SImissile missile : missileInvader) {
missile.moveDown(movement);
if(missile.getY() >= base.getY()) {
if (checkCollision(missile, base)) {
base.setHit();
gameOver = true;;
missileInvader.remove(missile);
cast.remove(missile);
return;
} else if (missile.getY() >= bound-25) {
missileInvader.remove(missile);
cast.remove(missile);
return;
}
}
}
}
private boolean checkCollision(SIthing missile, SIthing ship) {
Rectangle2D rect1 = new Rectangle2D.Double(
missile.getX(),
missile.getY(),
missile.getWidth(),
missile.getHeight()
);
Rectangle2D rect2 = new Rectangle2D.Double(
ship.getX(),
ship.getY(),
ship.getWidth(),
ship.getHeight()
);
return rect1.intersects(rect2);
}
private void switchBack() {
int defaultY = 12;
for (SIinvader s : invaders) {
if (s.getY() > getHeight()) {
gameOver = true;
return;
}
s.moveDown(defaultY);
}
}
private void gameOver() {
pause(true);
SI.setGameOverLabelVisibile(true);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.GREEN);
Font font = new Font("Arial", 0, 20);
setFont(font);
String score = "Score: "+this.score;
Rectangle2D rect = font.getStringBounds(score, g2.getFontRenderContext());
int screenWidth = 0;
try { screenWidth = (int) panelDimension.getWidth(); }
catch (NullPointerException e) {}
g2.setColor(Color.GREEN);
g2.drawString(score, (int) (screenWidth - (10 + rect.getWidth())), 20);
for(SIthing a:cast) {
a.paint(g);
}
}
public SIpanel() {
super();
setBackground(Color.BLACK);
cast = new ArrayList<SIthing>();
missileBase = new ArrayList<SImissile>();
score = invaderPace = mysteryCount = pulseRate = 0;
sound = new Music("AmbientMusic.wav");
panel = this;
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = true; break;
case KeyEvent.VK_RIGHT : right = true; break;
case KeyEvent.VK_SPACE : space = true; break;
}
}
#Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT : left = false; break;
case KeyEvent.VK_RIGHT : right = false; break;
case KeyEvent.VK_SPACE : space = false; break;
}
}
});
setFocusable(true);
timer = new Timer(10, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pulse();
}
});
}
public void reset() {
SI.setGameOverLabelVisibile(false);
score = invaderPace = mysteryCount = 0;
pulseRate = 50;
cast = new ArrayList<SIthing>();
invaders = new ArrayList<SIinvader>();
dead = new ArrayList<SIinvader>();
missileBase = new ArrayList<SImissile>();
missileInvader = new ArrayList<SImissile>();
base = new SIbase(230, 370, 26, 20);
waveDirection = true;
gameOver = false;
sound.stop();
sound.loop();
panelDimension = SI.getFrameDimensions();
bottomRow = getBottomRow();
newWave();
timer.start();
runningTimer=true;
}
public SIpanel getPanel() {
return this.panel;
}
public void pause(boolean paused) {
if (paused) timer.stop();
else timer.start();
}
}
I believe that collision detection may be the reason for lagging and you should simply investigate it by trying to increase and decrease count of enemies or missiles drastically to see if that makes a difference.
Consider garbage collector your enemy. In your checkCollision method you are instantiating two (very simple) objects. It may not seem like a lot, but consider that your might be creating them for each collision check, and that at 60fps it adds up until it may reach critical mass when GC says "stop the world" and you see noticeable lag.
If that is the case, possible solution to that would be to not instantiate any objects in a method called so frequently. You may create Rectangle2D once, and then update its position, instead of creating a new one each time, so you will avoid unnecessary memory allocation.