Langtons Ant in JAVA - java

I'm a very new Programmer and am learning Java atm. I am writing a Langton's Ant, however I can't seem to get my ant to do what it's supposed to. The ant only seems to run up and down the grid and stays within column 10 and 11.
Here is the code:
package ameise;
public class Ant {
// Variables
// Position of the ant
int xPos;
int yPos;
// Which way is the ant facing
String direction;
Grid g;
boolean isFinished;
public Ant(int xPos, int yPos, String direction, Grid g) {
// Constructor
this.xPos = xPos;
this.yPos = yPos;
this.direction = direction;
this.g = g;
}
// Getter X Y Coordinates
public int getXPos() {
return xPos;
}
public int getYPos() {
return yPos;
}
// Setter X Y Coordinates
protected void setXPos(int xPos) {
this.xPos = xPos;
}
protected void setYPos(int yPos) {
this.yPos = yPos;
}
public String getDirection() {
return direction;
}
protected void setDirection(String direction) {
this.direction = direction;
}
public void run() {
while (xPos >= 0 && yPos >= 0 && xPos < g.getWidth() && yPos < g.getHeight()) {
System.out.println(xPos + "," + yPos + "," + "Facing " + direction + " Color " + g.isWhite(xPos, yPos));
if (xPos == 0) {
isFinished = true;
} else if (xPos == g.getWidth()) {
isFinished = true;
} else if (yPos == 0) {
isFinished = true;
} else if (yPos == g.getHeight()) {
isFinished = true;
}
// Determine Directions ...
if (direction.equals("NORTH")) {
if (g.isWhite(xPos, yPos)) {
g.setBlack(xPos, yPos);
setDirection("WEST");
} else {
g.setWhite(xPos, yPos);
setDirection("EAST");
}
yPos++;
} else if (direction.equals("WEST")) {
if (g.isWhite(xPos, yPos)) {
g.setBlack(xPos, yPos);
setDirection("SOUTH");
} else {
g.setWhite(xPos, yPos);
setDirection("NORTH");
}
xPos--;
} else if (direction.equals("SOUTH")) {
if (g.isWhite(xPos, yPos)) {
g.setBlack(xPos, yPos);
setDirection("EAST");
} else {
g.setWhite(xPos, yPos);
setDirection("WEST");
}
yPos--;
}
else if (direction.equals("EAST")) {
if (g.isWhite(xPos, yPos)) {
g.setBlack(xPos, yPos);
setDirection("NORTH");
} else {
g.setWhite(xPos, yPos);
setDirection("SOUTH");
}
xPos++;
}
}
}
}
*** CLASS GRID ***
package ameise;
public class Grid {
// Define the variables
boolean[][] grid;
int height;
int width;
// constructor with user parameters
public Grid(int height, int width) {
this.height = height;
this.width = width;
grid = new boolean[height][width];
for (int h = 0; h < height; h++) {
for (int w = 0; w < width; w++) {
grid[h][w] = true;
}
}
}
// Methods
// Getter and Setter for grid
public boolean[][] getGrid() {
return grid;
}
public void setGrid(boolean[][] grid) {
this.grid = grid;
}
public int getHeight() {
return height;
}
public int getWidth() {
return width;
}
public boolean isWhite(int h, int w) {
return grid[h][w];
}
protected void setWhite(int h, int w) {
if (h < height && w < width)
grid[h][w] = true;
}
protected void setBlack(int h, int w) {
if (h < height && w < width)
grid[h][w] = false;
}
public void printGrid() {
for (int h = 0; h < 19; h++) {
for (int w = 0; w < 19; w++) {
if (isWhite(h, w)) {
System.out.printf("S", grid[h][w]);
} else
System.out.printf("X", grid[h][w]);
}
System.out.println();
}
}
}
*** MAIN CLASS***
public class Main {
/**
* #param args
*/
public static void main(String[] args) {
Grid grid = new Grid(20, 20);
Ant ant = new Ant(10, 10, "NORTH", grid);
ant.run();
grid.printGrid();
}
}
Somehow the ant only seems to be running. The output looks like
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS
SSSSSSSSSSXXSSSSSSS
SSSSSSSSSSSSSSSSSSS

Langton's Ant moves into a cell and based on it's color decides which way it will turn to leave the current cell. Your code decides which way to turn but leaves in the direction it was already facing:
if (direction.equals("NORTH")) {
// This section decides which way ant will go based on the current cell
if (g.isWhite(xPos, yPos)) {
g.setBlack(xPos, yPos);
setDirection("WEST");
} else {
g.setWhite(xPos, yPos);
setDirection("EAST");
}
// This section move north, not in the direction the ant turns.
yPos++;
} //...
I think the best way to fix it is replace each case with something like:
if (direction.equals("NORTH")) {
if (g.isWhite(xPos, yPos)) {
g.setBlack(xPos, yPos);
setDirection("WEST");
xPos--; //move West
} else {
g.setWhite(xPos, yPos);
setDirection("EAST");
xPos++; //move East
}
} //...

Related

Error in setting my character in the right color pixel in java

I am having some issues trying to set my character to spawn in the right color spot in my map sheet in java.
In the vídeos that I am watching to learn this I have every single line code identical to the vídeo but yet my character instead of spawning in the right spot is spawning in the up middle corner of the screen.
I'm using those code lines to make him and all Tiles and Entities spawn in the right spot :
public class World {
private Tile[] tiles;
public static int WIDTH,HEIGHT;
public World(String path) {
try {
BufferedImage map = ImageIO.read(getClass().getResource(path));
int[] pixels = new int[map.getWidth() * map.getHeight()];
WIDTH = map.getWidth();
HEIGHT = map.getHeight();
tiles = new Tile[map.getWidth() * map.getHeight()];
map.getRGB(0, 0, map.getWidth(), map.getHeight(), pixels, 0, map.getWidth());
for(int xx = 0; xx < map.getWidth(); xx++) {
for(int yy = 0; yy < map.getHeight(); yy++) {
int pixelAtual = pixels[xx + (yy*map.getWidth())];
tiles[xx + (yy * WIDTH)] = new FloorTile(xx*16,yy*16, Tile.TILE_FLOOR);
if(pixelAtual == 0xFF000000) {
//FLOOR
tiles[xx + (yy * WIDTH)] = new FloorTile(xx*16,yy*16, Tile.TILE_FLOOR);
}else if(pixelAtual == 0xFFFFFFFF){
//PAREDE
tiles[xx + (yy * WIDTH)] = new FloorTile(xx*16,yy*16, Tile.TILE_WALL);
}else if(pixelAtual == 0xFF0026FF) {
//Player
Game.player.setX(xx*16);
Game.player.setY(yy*16);
}else if(pixelAtual == 0xFFFF0000){
//Enemy
}else if(pixelAtual == 0xFFFF00DC) {
//WEAPON
}else if(pixelAtual == 0xFFFF7F7F) {
//LIFEPACK
}else if(pixelAtual == 0xFFFFD800) {
//BULLET
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
public void render(Graphics g) {
for(int xx = 0; xx < WIDTH; xx++) {
for(int yy = 0; yy < HEIGHT; yy++) {
Tile tile = tiles[xx + (yy*WIDTH)];
tile.render(g);
}
}
}
}
But when I use these two code lines that are from my Entity Class that are suposed to make my character spawn in the right place it doesn't work at all!
Game.player.setX(xx16);
Game.player.setY(yy16);
Here's my Entity Class for you to see if i did something wrong, and again, i did everything exactely like int the vídeo an in the vídeo it worked.
public class Entity {
public static BufferedImage LIFEPACK_EN = Game.spritesheet.getSprite(78, 0, 16, 16);
public static BufferedImage WEAPON_EN = Game.spritesheet.getSprite(96, 0, 16, 16);
public static BufferedImage BULLET_EN = Game.spritesheet.getSprite(78, 16, 16, 16);
public static BufferedImage ENEMY_EN = Game.spritesheet.getSprite(96, 16, 16, 16);
protected double x;
protected double y;
protected int width;
protected int height;
private BufferedImage sprite;
public Entity(int x, int y, int width, int height, BufferedImage sprite) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.sprite = sprite;
}
public void setX(int newX) {
this.x = newX;
}
public void setY(int newY) {
this.x = newY;
}
public int getX() {
return (int)this.x;
}
public int getY() {
return (int)this.y;
}
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public void update() {
}
public void render(Graphics g) {
g.drawImage(sprite, this.getX(), this.getY(), null);
}
}
I saw where I was wrong.
public void setY(int newY) {
this.x = newY;
In this line code here, it's suposed to be this.y and I thought that I did that, but I couldn't see.

Can't seem to access the image file in my PlayerClass even though it is properly loaded

I'm creating a 2D java game and ran into a nullpointer exception. Whenever I call my render in the playstate class, it throws the exception. I had previously rendered the Font file and got it to work when commenting out the player object references. The player "linkformatted.png" file is able to load after trying and catching, but the nullpointer exception stays. Changing the values didn't work.
public class PlayState extends GameState {
private Font font;
private Player player;
public PlayState(GameStateManager gsm) {
super(gsm);
font = new Font("font/ZeldaFont.png", 16, 16);
player = new Player(new Sprite("entity/linkformatted.png"), new Vector2f(100, 100), 32);
}
public void update() {
player.update();
}
public void input(MouseHandler mouse, KeyHandler key) {
player.input(mouse, key);
}
public void render(Graphics2D g) {
Sprite.drawArray(g, font, "YOU", new Vector2f(100, 100), 32, 32, 16, 0);
player.render(g);
}
}
public class Sprite {
private BufferedImage SPRITESHEET = null;
private BufferedImage[][] spriteArray;
private final int TILE_SIZE = 32;
public int w;
public int h;
private int wSprite;
private int hSprite;
public Sprite(String file) {
w = TILE_SIZE;
h = TILE_SIZE;
System.out.println("Loading: " + file + "...");
SPRITESHEET = loadSprite(file);
wSprite = SPRITESHEET.getWidth() / w;
hSprite = SPRITESHEET.getHeight() / h;
loadSpriteArray();
}
public Sprite(String file, int w, int h) {
this.w = w;
this.h = h;
System.out.println("Loading: " + file + "...");
SPRITESHEET = loadSprite(file);
wSprite = SPRITESHEET.getWidth() / w;
hSprite = SPRITESHEET.getHeight() / h;
loadSpriteArray();
}
public void setSize(int width, int height) {
setWidth(width);
setHeight(height);
}
public void setWidth(int i) {
w = i;
wSprite = SPRITESHEET.getWidth() / w;
}
public void setHeight(int i) {
h = i;
hSprite = SPRITESHEET.getHeight() / h;
}
public int getWidth() {
return w;
}
public int getHeight() {
return h;
}
private BufferedImage loadSprite(String file) {
BufferedImage sprite = null;
try {
sprite = ImageIO.read(getClass().getClassLoader().getResourceAsStream(file));
} catch(Exception e) {
System.out.println("Error: could not load file: " + file);
}
return sprite;
}
public void loadSpriteArray() {
spriteArray = new BufferedImage[wSprite][hSprite];
for(int x = 0; x < wSprite; x++) {
for(int y = 0; y < hSprite; y++) {
spriteArray[x][y] = getSprite(x, y);
}
}
}
public BufferedImage getSpriteSheet() {
return SPRITESHEET;
}
public BufferedImage getSprite(int x, int y) {
return SPRITESHEET.getSubimage(x * w, y * h, w, h);
}
public BufferedImage[] getSpriteArray(int i) {
return spriteArray[i];
}
public BufferedImage[][] getSpriteArray2(int i) {
return spriteArray;
}
public static void drawArray(Graphics2D g, ArrayList<BufferedImage> img, Vector2f pos, int width, int height, int xOffset, int yOffset) {
float x = pos.x;
float y = pos.y;
for(int i = 0; i < img.size(); i++) {
if(img.get(i) != null) {
g.drawImage(img.get(i), (int) x, (int) y, width, height, null);
}
x += xOffset;
y += yOffset;
}
}
public static void drawArray(Graphics2D g, Font f, String word, Vector2f pos, int width, int height, int xOffset, int yOffset) {
float x = pos.x;
float y = pos.y;
for(int i = 0; i < word.length(); i++ ) {
if(word.charAt(i) != 32); // the space
g.drawImage(f.getFont(word.charAt(i)), (int) x, (int) y, width, height, null);
x += xOffset;
y += yOffset;
}
}
}
public class Animation {
private BufferedImage[] frames;
private int currentFrame;
private int numFrames;
private int count;
private int delay;
private int timesPlayed;
public Animation(BufferedImage[] frames) {
timesPlayed = 0;
setFrames(frames);
}
public Animation() {
timesPlayed = 0;
}
public void setFrames(BufferedImage[] frames) {
frames = frames;
currentFrame = 0;
timesPlayed = 0;
delay = 2;
numFrames = frames.length;
}
public void setDelay(int i) { delay = i;}
public void setFrame(int i) { currentFrame = i;}
public void setNumFrames(int i) { numFrames = i;}
public void update() {
if(delay == -1) return;
count++;
if(count == delay) {
currentFrame++;
count = 0;
}
if(currentFrame == numFrames) {
currentFrame = 0;
timesPlayed++;
}
}
public int getDelay() {
return delay;
}
public int getFrame() {
return currentFrame;
}
public int getCount() {
return count;
}
public BufferedImage getImage() {
return frames[currentFrame];
}
public boolean hasPlayedOnce() {
return timesPlayed > 0;
}
public boolean hasPlayed(int i) {
return timesPlayed == i;
}
}
public class Player extends Entity {
public Player(Sprite sprite, Vector2f origin, int size) {
super(sprite, origin, size);
}
public void move() {
if(up) {
dy -= acc;
if(dy < -maxSpeed) {
dy = -maxSpeed;
}
} else {
if(dy < 0) {
dy += deacc;
if(dy > 0) {
dy = 0;
}
}
}
if(down) {
dy += acc;
if(dy < maxSpeed) {
dy = maxSpeed;
}
} else {
if(dy > 0) {
dy -= deacc;
if(dy < 0) {
dy = 0;
}
}
}
if(left) {
dx -= acc;
if(dx < -maxSpeed) {
dy = -maxSpeed;
}
} else {
if(dx < 0) {
dx += deacc;
if(dx > 0) {
dx = 0;
}
}
}
if(right) {
dx += acc;
if(dx > maxSpeed) {
dy = maxSpeed;
}
} else {
if(dx > 0) {
dx -= deacc;
if(dx < 0) {
dx = 0;
}
}
}
}
public void update() {
super.update();
move();
pos.x = dx;
pos.y = dy;
}
#Override
public void render(Graphics2D g) {
g.drawImage(ani.getImage(), (int) (pos.x), (int) (pos.y), size, size, null);
}
public void input(MouseHandler mouse, KeyHandler key) {
if(key.up.down) {
up = true;
} else {
up = false;
}
if(key.down.down) {
down = true;
} else {
down = false;
}
if(key.left.down) {
left = true;
} else {
left = false;
}
if(key.right.down) {
right = true;
} else {
right = false;
}
if(key.attack.down) {
attack = true;
} else {
attack = false;
}
}
}
Here is what is printed:
Loading: entity/linkformatted.png...
Exception in thread "GameThread" java.lang.NullPointerException
at com.zwellis.game.graphics.Animation.getImage(Animation.java:62)
at com.zwellis.game.entity.Player.render(Player.java:82)
at com.zwellis.game.states.PlayState.render(PlayState.java:34)
at com.zwellis.game.states.GameStateManager.render(GameStateManager.java:71)
at com.zwellis.game.GamePanel.render(GamePanel.java:133)
at com.zwellis.game.GamePanel.run(GamePanel.java:90)
at java.base/java.lang.Thread.run(Thread.java:834)
Here is what happens when I made another file to display the image:
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.*;
public class ImageInFrame {
public static void main(String[] args) throws IOException {
String path = "entity/linkformatted.png";
File file = new File(path);
BufferedImage image = ImageIO.read(file);
JLabel label = new JLabel(new ImageIcon(image));
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().add(label);
f.pack();
f.setLocation(200,200);
f.setVisible(true);
}
}
Here is what happens:
Exception in thread "main" javax.imageio.IIOException: Can't read input file!
at java.desktop/javax.imageio.ImageIO.read(ImageIO.java:1308)
at ImageInFrame.main(ImageInFrame.java:11)
Here is also the github link
https://github.com/xfyktcl/ZwellisKnight.git

How do I get my program to restart properly? (Brick Breaker)

When gameover is true and I call the startGame method from the DOWN button KeyListener, it breaks my game and doesn't allow me to click the exit button on the JFrame and the paddle doesn't work anymore. Please help.
import javax.swing.*;
import java.awt.event.*;
import java.awt.image.*;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.Image;
public class AustinsBrickBreaker {
JFrame window;
DrawPanel panel;
public AustinsBrickBreaker() {
window = new JFrame("Brick Breaker");
panel = new DrawPanel();
window.setSize(800, 592);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.getContentPane().add(panel);
window.setLocationRelativeTo(null);
window.setVisible(true);
window.setResizable(false);
}
public void go() {
panel.startGame();
}
public static void main(String[] args) {
AustinsBrickBreaker game = new AustinsBrickBreaker();
game.go();
}
}
#SuppressWarnings("serial")
class DrawPanel extends JPanel implements KeyListener {
final int WIDTH = 800, HEIGHT = 592;
BufferedImage buffer;
public static Brick[][] bricks = new Brick[3][5];
Paddle paddle;
Ball ball;
int score = 0;
int lives = 3;
boolean gameover = false;
Image brickImage = Toolkit.getDefaultToolkit().getImage("brick.png");
Image brickImage2 = Toolkit.getDefaultToolkit().getImage("brick2.png");
Image brickImage3 = Toolkit.getDefaultToolkit().getImage("brick3.png");
Image brickImage4 = Toolkit.getDefaultToolkit().getImage("brick4.png");
Image brickImage5 = Toolkit.getDefaultToolkit().getImage("brick5.png");
Image paddleImage = Toolkit.getDefaultToolkit().getImage("paddle.png");
Image background = Toolkit.getDefaultToolkit().getImage("background.jpg");
Image ballImage = Toolkit.getDefaultToolkit().getImage("ball.png");
Image heartImage = Toolkit.getDefaultToolkit().getImage("heart.png");
public DrawPanel() {
setIgnoreRepaint(true);
addKeyListener(this);
setFocusable(true);
}
public void keyTyped(KeyEvent e) {}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) paddle.left = true;
if (key == KeyEvent.VK_RIGHT) paddle.right = true;
if (key == KeyEvent.VK_UP && gameover) {
gameover = false;
score = 0;
lives = 3;
startGame();
}
if (key == KeyEvent.VK_DOWN && gameover) System.exit(0);
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) paddle.left = false;
if (key == KeyEvent.VK_RIGHT) paddle.right = false;
}
public int count() {
int count = 0;
for (int r = 0; r < DrawPanel.bricks.length; r++)
for (int c = 0; c < DrawPanel.bricks[r].length; c++)
if (!bricks[r][c].visible) count++;
else
break;
int returner = 0;
if (count == 15) returner = 1;
return returner;
}
public void initialize() {
buffer = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
for (int r = 0; r < DrawPanel.bricks.length; r++)
for (int c = 0; c < DrawPanel.bricks[r].length; c++)
DrawPanel.bricks[r][c] = new Brick(c * 150 + 50, r * 60 + 30, 100, 50);
ball = new Ball(390, 200, 20, 20, 10);
paddle = new Paddle(350, 510, 100, 20, 8);
}
public void updateMovement() {
paddle.move();
ball.move();
}
public void checkCollisions() {
if (paddle.x <= 20) paddle.x = 20;
if (paddle.x >= 679) paddle.x = 679;
if (ball.x < 21) {
ball.left = false;
ball.right = true;
}
if (ball.x > 761) {
ball.left = true;
ball.right = false;
}
if (ball.y < 21) {
ball.up = false;
ball.down = true;
}
if (paddle.getBounds().intersects(ball.getBounds())) ball.swap();
for (int r = 0; r < DrawPanel.bricks.length; r++)
for (int c = 0; c < DrawPanel.bricks[r].length; c++) {
if (ball.getBounds().intersects(DrawPanel.bricks[r][c].getBounds()) && !DrawPanel.bricks[r][c].collision) {
ball.swap();
bricks[r][c].collide();
score += 10;
}
}
}
public void drawBuffer() {
Graphics2D b = buffer.createGraphics();
b.drawImage(background, 0, 0, null);
if (!gameover) {
for (int l = 0; l < lives; l++)
b.drawImage(heartImage, 20 * l + 620, 535, null);
b.drawString("Score: " + score, 700, 550);
b.drawImage(paddleImage, paddle.getX(), paddle.getY(), null);
b.drawImage(ballImage, ball.getX(), ball.getY(), null);
for (int r = 0; r < DrawPanel.bricks.length; r++)
for (int c = 0; c < DrawPanel.bricks[r].length; c++) {
if (bricks[r][c].visible == true)
if (bricks[r][c].colour == 1)
b.drawImage(brickImage, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
else if (bricks[r][c].colour == 2)
b.drawImage(brickImage2, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
else if (bricks[r][c].colour == 3)
b.drawImage(brickImage3, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
else if (bricks[r][c].colour == 4)
b.drawImage(brickImage4, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
else if (bricks[r][c].colour == 5)
b.drawImage(brickImage5, DrawPanel.bricks[r][c].getX(), DrawPanel.bricks[r][c].getY(), null);
}
b.dispose();
} else {
b.drawString("G A M E O V E R !", 340, 300);
b.drawString("G A M E O V E R !", 341, 300);
b.drawString("G A M E O V E R !", 342, 300);
b.drawString("Press ↑ To Play Again!", 332, 320);
b.drawString("Press ↓ To Exit :(", 342, 340);
}
}
public void drawScreen() {
Graphics2D g = (Graphics2D) this.getGraphics();
g.drawImage(buffer, 0, 0, this);
Toolkit.getDefaultToolkit().sync();
g.dispose();
}
public void startGame() {
initialize();
while (!gameover) {
try {
updateMovement();
checkCollisions();
drawBuffer();
drawScreen();
Thread.sleep(15);
if (ball.y > 562 && lives != -1) {
Thread.sleep(500);
lives -= 1;
ball.x = 390;
ball.y = 200;
ball.left = false;
ball.right = false;
paddle.x = 350;
}
if (lives == -1) {
Thread.sleep(500);
gameover = true;
drawBuffer();
drawScreen();
}
//Replace Bricks
if (count() == 1) {
Thread.sleep(500);
startGame();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
/*--|--|--|--| GAME CLASSES |--|--|--|--*/
class Brick {
int x, y, width, height, colour;
boolean collision, visible;
public Brick(int x, int y, int w, int h) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.collision = false;
this.visible = true;
this.colour = (int) Math.ceil(Math.random() * 5);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Rectangle getBounds() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
public void collide() {
if (collision == false) {
visible = false;
collision = true;
}
}
}
class Paddle {
int x, y, width, height, speed;
boolean left, right;
public Paddle(int x, int y, int w, int h, int s) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.speed = s;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Rectangle getBounds() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
public void move() {
if (left) x -= speed;
if (right) x += speed;
}
}
class Ball {
int x, y, width, height, speed;
boolean up, down, left, right;
public Ball(int x, int y, int w, int h, int s) {
this.x = x;
this.y = y;
this.width = w;
this.height = h;
this.speed = s;
this.up = false;
this.down = true;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public Rectangle getBounds() {
return new Rectangle(getX(), getY(), getWidth(), getHeight());
}
public void move() {
if (up) y -= speed;
if (down) y += speed;
if (left) x -= (float) Math.ceil(Math.random() * 5);
if (right) x += (float) Math.ceil(Math.random() * 5);
}
public void swap() {
if (up) {
down = true;
up = false;
} else if (down) {
up = true;
down = false;
}
double r = Math.random();
if (r <= 0.5) {
left = false;
right = true;
} else if (r > 0.5) {
left = true;
right = false;
} else left = true;
}
}
Your code completely ignores Swing threading rules, and this is somehow allowed when first run, since when first run, the startGame() method is called in the main thread off of the Swing event thread. But when it is called a second time, it is then called on the event thread, and this time, all those sleep calls put the Swing event thread and your application to sleep. The solution: learn about Swing threading rules, and have your application obey these rules, including not calling Thread.sleep, or having forever loops called on the event thread.
see: Lesson: Concurrency in Swing.
This is not an answer, but a very long comment
First, getGraphics is NOT how custom painting works in Swing and you should never use it.
Start by taking a look at Painting in AWT and Swing and Performing Custom Painting for more details about how painting works in Swing.
Swing uses a passive rendering approaching, meaning that it's painting process can take place at any time, for any reason most without your interaction or knowledge, under your current approach, you could end up with intermediate flickering which be near impossible to diagnose or repeat.
If you want control over the painting (active painting), have a look at BufferStrategy and BufferStrategy and BufferCapabilities
Second, don't use KeyListener, there are a very limited number of circumstances I might consider using KeyListener, but this is not one of them and when you find yourself wanting to respond to key events, you should start with the key bindings API
Third, don't use Toolkit.getDefaultToolkit().getImage, but instead use ImageIO, it supports more images, it loads the image first before returning (rather than using a background thread) and throws an IOException when the image can't be loaded. See Reading/Loading an Image for more details
Fourth, you are violating the single thread rules of Swing. Basically, because the way the system works, main is called within what is called the "main" thread, but Swing runs in it's own thread (AKA The Event Dispatching Thread).
So when you first start, go is running in the "main" thread, but when you call start from your KeyListener, you're running within the EDT, meaning that you "game-loop" will block the EDT and nothing will ever paint again and the user won't be able to interact with your program.
See Concurrency in Swing for more details and How to Use Swing Timers for a possible solution

My x and y variables only sometimes change

I am testing out a Player object in a game I am trying to build, and I have begun testing my input using a white rectangle on the screen through OpenGL in LWJGL.
The problem is that when I compile the code and try moving the rectangle using the arrow keys, the rectangle only responds to RIGHT and DOWN. When testing it out in the loop, it appears the dx and dy are changing in the move() method, but the change does not persist into the updateXY() method.
-SNIP- (jump problem has been fixed)
I am completely stumped as to why this could be and I would love to get some help
Thanks in advance
EDIT: Added the AbstractMoveableEntity class
EDIT: Updated the code to reflect the current problem
public class Player extends AbstractMoveableEntity implements MoveableEntity {
MouseHandler m;
private double tx, ty;
private double SPEED;
private enum DIR{
UP, DOWN, LEFT, RIGHT;
}
public Player(double x, double y, MouseHandler m) {
super(x, y, 50, 50);
this.m = m;
this.tx = x;
this.ty = y;
this.ax = 0;
this.ay = 0;
this.SPEED = 5;
}
public void draw() {
glRectd(x,y,x+width,y+height);
}
public void update(int delta) {
updateXY();
draw();
}
public void updateXY(){
input();
//Updating target, velocity and position values
this.tx += this.dx;
this.ty += this.dy;
this.dx += this.ax;
this.dy += this.ay;
this.x += this.dx;
this.y += this.dy;
//Acceleration handling
if(tx > x){
this.ax += 1;
} else if(tx < x) {
this.ax -= 1;
} else {
this.ax = 0;
}
if(ty > y){
this.ay += 1;
} else if(ty < y) {
this.ay -= 1;
} else {
this.ay = 0;
}
}
public void input(){
//Event-Driven input
while(Keyboard.next()){
if(Keyboard.isKeyDown(Keyboard.KEY_SPACE)){
if(ay == 0){
jump();
} else {
x = tx;
y = ty;
ay = 0;
}
}
}
//Polled input
if(Keyboard.isKeyDown(Keyboard.KEY_UP)){
move(DIR.UP);
} else {
stop(DIR.UP);
}
if(Keyboard.isKeyDown(Keyboard.KEY_DOWN)){
move(DIR.DOWN);
} else {
stop(DIR.DOWN);
}
if(Keyboard.isKeyDown(Keyboard.KEY_LEFT)){
move(DIR.LEFT);
} else {
stop(DIR.LEFT);
}
if(Keyboard.isKeyDown(Keyboard.KEY_RIGHT)){
move(DIR.RIGHT);
} else {
stop(DIR.RIGHT);
}
}
public void jump(){
setAY(-10);
System.out.println("JUMP " + ay);
}
public void move(DIR d){
if(d == DIR.UP){
this.dy = -SPEED;
} else if(d == DIR.DOWN){
this.dy = SPEED;
} else if(d == DIR.LEFT){
this.dx = -SPEED;
} else{
this.dx = SPEED;
}
}
public void stop(DIR d){
if(d == DIR.UP || d == DIR.DOWN){
this.dy = 0;
} else {
this.dx = 0;
}
}
}
Public abstract class AbstractMoveableEntity extends AbstractEntity implements MoveableEntity {
protected double dx, dy, ax, ay;
public AbstractMoveableEntity(double x, double y, double width, double height) {
super(x, y, width, height);
this.dx = 0;
this.dy = 0;
this.ax = 0;
this.ay = 0;
}
public double getDX() {
return dx;
}
public double getDY() {
return dy;
}
public void setDX(double dx) {
this.dx = dx;
}
public void setDY(double dy) {
this.dy = dy;
}
public void setAX(double ax){
this.ax = ax;
}
public void setAY(double ay) {
this.ay = ay;
}
}
The problem is the part in the input() function marked //Polled input.
When the user presses the KEY_UP key, the first if-condition calls move(DIR.UP). At this point, dy is set to -SPEED. Then the next if-condition checks whether the user is pressing the KEY_DOWN key, sees that he isn't, and calls stop(DIR.DOWN). This sets dy to 0, effectively overwriting the previous call to move(DIR.UP).
The situation with LEFT/RIGHT is identical.

Why does my player continue to move (very slowly) after releasing the arrow keys?

I'm working on my first 2D Java game using Swing, and I've run into an odd bug.
Here's the relevant code, first of all:
GamePanel.java
public class GamePanel extends JPanel implements KeyListener {
public GamePanel() {
setPreferredSize(new Dimension(STAGE_WIDTH, STAGE_HEIGHT));
Thread runner = new Thread(new Runnable() {
#Override
public void run() {
begin();
long lastUpdate = System.currentTimeMillis();
while (true) {
long elapsed = System.currentTimeMillis() - lastUpdate;
repaint();
if (elapsed < 16) {
try {
Thread.sleep(20 - elapsed);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
update((System.currentTimeMillis() - lastUpdate) / 1000.0);
lastUpdate = System.currentTimeMillis();
}
}
});
runner.start();
}
//variables
int bulletVelocity = 10;
final int STAGE_HEIGHT = 600;
final int STAGE_WIDTH = 800;
int playerWidth = 50;
int playerHeight = 50;
//lists
List<Bullet> bulletList = new ArrayList<>();
List<Enemy> enemyList = new ArrayList<>();
//objects
Player player = new Player((STAGE_WIDTH - playerWidth) / 2, (STAGE_HEIGHT - playerHeight) / 2, 0, 0, playerWidth, playerHeight);
public void begin() {
}
public void update(double delta) {
player.update(delta);
//System.out.println(delta);
for (Bullet bullet : bulletList) {
bullet.update();
}
for (Enemy enemy : enemyList) {
enemy.update(player.getXPos(), player.getYPos());
}
}
#Override
public void paint(Graphics g) {
g.setColor(Color.BLACK);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.RED);
g.fillRect((int) player.getXPos(), (int) player.getYPos(), player.getWidth(), player.getHeight());
g.setColor(Color.BLUE);
for (Bullet bullet : bulletList) {
g.fillRect((int) bullet.getXPos(), (int) bullet.getYPos(), 10, 10);
}
g.setColor(Color.GREEN);
for (Enemy enemy : enemyList) {
g.fillOval((int) enemy.getXPos(), (int) enemy.getYPos(), enemy.getWidth(), enemy.getHeight());
}
}
#Override
public void keyTyped(KeyEvent e) {
}
private Set<Integer> keysDown = new HashSet<Integer>();
#Override
public void keyPressed(KeyEvent e) {
if (keysDown.contains(e.getKeyCode())) {
return;
}
keysDown.add(e.getKeyCode());
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
player.addAccelX(-1);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
player.addAccelX(1);
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
player.addAccelY(-1);
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
player.addAccelY(1);
} else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
Bullet bullet = new Bullet(player.getXPos() + (player.getWidth() / 2), player.getYPos(), bulletVelocity - (player.getYVel() / 4));
bulletList.add(bullet);
} else if (e.getKeyCode() == KeyEvent.VK_E) {
Enemy enemy = new Enemy(100, 100, Math.random() * 3 + .5, 10, 10);
enemyList.add(enemy);
} else if (e.getKeyCode() == KeyEvent.VK_A) {
System.out.println(toDegrees(atan2(player.getYPos() - 0, player.getXPos() - 0)));
}
}
#Override
public void keyReleased(KeyEvent e) {
keysDown.remove(e.getKeyCode());
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
player.addAccelX(1);
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
player.addAccelX(-1);
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
player.addAccelY(1);
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
player.addAccelY(-1);
}
}
}
Player.java
public class Player {
private final double MAX_VELOCITY = 500;
private final double ACCELERATION = 3000.0;
//friction is % ? Add that later
private final double FRICTION = 400.0;
private double mass = 10.0;
private double xPos = 400;
private double yPos = 200;
private double xVel = 0.0;
private double yVel = 0.0;
private int width = 100;
private int height = 100;
private int xDir = 0;
private int yDir = 0;
private boolean moving = false;
private double accelX = 0.0;
private double accelY = 0.0;
public Player() {
}
public Player(double xPos, double yPos, double xVel, double yVel, int width, int height) {
this.xPos = xPos;
this.yPos = yPos;
this.xVel = xVel;
this.yVel = yVel;
this.width = width;
this.height = height;
}
public void update(double delta) {
this.xVel += accelX * delta;
this.yVel += accelY * delta;
if(abs(xVel) > MAX_VELOCITY){xVel = MAX_VELOCITY * xDir;}
if(abs(yVel) > MAX_VELOCITY){yVel = MAX_VELOCITY * yDir;}
if(xVel > 0) xVel += -FRICTION / mass;
if(xVel < 0) xVel += FRICTION / mass;
//debugging
//System.out.println(yVel);
if(yVel > 0) yVel += -FRICTION / mass;
if(yVel < 0) yVel += FRICTION / mass;
//System.out.println(yVel);
//if(!moving){xVel = 0; yVel = 0;}
this.xPos += this.xVel * delta;
this.yPos += this.yVel * delta;
}
public void setMoving(boolean moving){
this.moving = moving;
}
public void move(double delta) {
/*
* Acceleration = Force / Mass
* Velocity += Acceleration * ElapsedTime (delta)
* Position += Velocity * ElapsedTime (delta)
*/
}
public double getAccel(){
return ACCELERATION;
}
public void addAccelX(int dir) {
this.accelX += ACCELERATION * dir;
//this.xDir = dir;
}
public void addAccelY(int dir) {
this.accelY += ACCELERATION * dir;
//this.yDir = dir;
}
public double getXPos() {
return this.xPos;
}
public double getYPos() {
return this.yPos;
}
public double getXVel() {
return this.xVel;
}
public double getYVel() {
return this.yVel;
}
public int getHeight() {
return this.height;
}
public int getWidth() {
return this.width;
}
public void addXPos(int delta) {
this.xPos += delta;
}
public void addYPos(int delta) {
this.yPos += delta;
}
public void addXVel(int delta) {
this.xVel += delta;
}
public void addYVel(int delta) {
this.yVel += delta;
}
}
(Please excuse the sloppy code.)
The little red square player moves fine, but when I release the arrow keys, the player moves (either down or to the right) with a velocity of 20 (arbitrary units at this point), which comes out to a few pixels/sec.
I think that it has something to do with the friction, but I'm not sure.
You never reset accelX and accelY and so the acceleration is continuously applied across frames. Your player should actually be accelerating, but I think that friction may be interacting in some way to create slow movement.

Categories

Resources