I am writing a space invaders clone for a school project, I am in the process of writing the aliens and their algorithm for movement with the use of an array.
My issue is a bunch of errors occur when I run the code but I can`t find why?
any help would be appreciated and bare in mind I am very inexperienced with game development and java
bellow is my GamePanel class, and then my Alien class
package Main;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JPanel;
import entity.Alien;
import entity.Controller;
import entity.Player;
import entity.playerBullet;
public class GamePanel extends JPanel implements Runnable{
public final int screenHeight = 600;
public final int screenWidth = 800;
public final int playerSize = 48;
int fps = 60;
KeyHandler keyH = new KeyHandler();
Thread gameThread;
public Player player = new Player(this,keyH);
public CollisionChecker cChecker = new CollisionChecker(this);
private Controller c = new Controller(null);
Alien alien;
//player default position
int playerX = 100;
int playerY = 100;
int playerSpeed = 4;
public GamePanel() {
this.setPreferredSize(new Dimension (screenWidth, screenHeight));
this.setBackground(Color.black);
this.setDoubleBuffered(true);
this.addKeyListener(keyH);
this.setFocusable(true);
}
public void startGameThread() {
gameThread = new Thread (this);
gameThread.start();
alien.initAlien();
}
public void run() {
double drawInterval = 1000000000/fps; // 0.01666 seconds = 60 times per seconds
double nextDrawTime = System.nanoTime() + drawInterval;
while(gameThread != null) {
System.out.println("this game is runing");
// update information such as character positions
// draw the screen with the updated information
update();
repaint();
try {
double remainingTime = nextDrawTime - System.nanoTime();
remainingTime = remainingTime/1000000;
if(remainingTime<0) {
remainingTime = 0;
}
Thread.sleep ((long) remainingTime);
nextDrawTime += drawInterval;
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private void update() {
player.update();
c.tick();
alien.moveAliens();
}
public void paintComponent(Graphics g) {
// to draw something
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
player.draw(g2);
c.render(g );
g2.dispose();
alien.render(g );
}
}
Alien class
package entity;
import java.awt.Color;
import java.awt.Graphics;
public class Alien {
boolean isVisible;
boolean moveLeft;
boolean moveRight;
Alien[] a = new Alien[10];
private int x;
private int y;
int ax = 10;
int ay = 10;
public Alien(int x, int y) {
}
public void initAlien() {
for(int i=0;i<a.length; i++) {
a[i] = new Alien(ax,ay);
ax += 40;
if(i==4) {
ax=10;
ay+=40;
}
}
}
public void moveAliens() {
for(int i=0;i<a.length; i++) {
if (a[i].moveLeft ==true) {
a[i].x -=2;
}
if (a[i].moveRight ==true) {
a[i].x+=2;
}
for(int i1 = 0; i<a.length; ) {
if(a[i].x>600) {
for(int j =0;j<a.length; j++) {
a[j].moveLeft = true;
a[j].moveRight = false;
a[j].y += 5;
}
}
if(a[i].x<0) {
for(int j = 0; j< a.length; j++) {
a[j].moveLeft = false;
a[j].moveRight = true;
a[j].y += 5;
}
}
}
}
}
Related
To be frank i have not the slightest clue how to fix this whats so ever. It works until you get to the part that only 1 brick shows and its kinda frustrating... If anyone could help me i would appreciate it. I did look up how to fix this but i didn't even find anyone that had this problem. Google searching isn't really that good. Oh and i used Eclipse for this program.
Board Class
package Final;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Timer;
import java.util.TimerTask;
import javax.swing.JPanel;
public class Board extends JPanel implements Commons {
private Timer timer;
private String message = "Your Fired";
private Ball ball;
private Paddle paddle;
private Brick bricks[];
private boolean ingame = true;
public Board() {
initBoard();
}
private void initBoard() {
addKeyListener(new TAdapter());
setFocusable(true);
bricks = new Brick[N_OF_BRICKS];
setDoubleBuffered(true);
timer = new Timer();
timer.scheduleAtFixedRate(new ScheduleTask(), DELAY, PERIOD);
}
#Override
public void addNotify() {
super.addNotify();
gameInit();
}
private void gameInit() {
ball = new Ball();
paddle = new Paddle();
int k = 0;
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 6; j++) {
bricks[k] = new Brick(j * 40 + 30, i * 10 + 50);
k++;
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
if (ingame) {
drawObjects(g2d);
} else {
gameFinished(g2d);
}
Toolkit.getDefaultToolkit().sync();
}
private void drawObjects(Graphics2D g2d) {
g2d.drawImage(ball.getImage(), ball.getX(), ball.getY(),
ball.getWidth(), ball.getHeight(), this);
g2d.drawImage(paddle.getImage(), paddle.getX(), paddle.getY(),
paddle.getWidth(), paddle.getHeight(), this);
for (int i = 0; i < N_OF_BRICKS; i++) {
if (!bricks[i].isDestroyed()) {
g2d.drawImage(bricks[i].getImage(), bricks[i].getX(),
bricks[i].getY(), bricks[i].getWidth(),
bricks[i].getHeight(), this);
}
}
}
private void gameFinished(Graphics2D g2d) {
Font font = new Font("Verdana", Font.BOLD, 18);
FontMetrics metr = this.getFontMetrics(font);
g2d.setColor(Color.BLACK);
g2d.setFont(font);
g2d.drawString(message,
(Commons.WIDTH - metr.stringWidth(message)) / 2,
Commons.WIDTH / 2);
}
private class TAdapter extends KeyAdapter {
#Override
public void keyReleased(KeyEvent e) {
paddle.keyReleased(e);
}
#Override
public void keyPressed(KeyEvent e) {
paddle.keyPressed(e);
}
}
private class ScheduleTask extends TimerTask {
#Override
public void run() {
ball.move();
paddle.move();
checkCollision();
repaint();
}
}
private void stopGame() {
ingame = false;
timer.cancel();
}
private void checkCollision() {
if (ball.getRect().getMaxY() > Commons.BOTTOM_EDGE) {
stopGame();
}
for (int i = 0, j = 0; i < N_OF_BRICKS; i++) {
if (bricks[i].isDestroyed()) {
j++;
}
if (j == N_OF_BRICKS) {
message = "Pay Day";
stopGame();
}
}
if ((ball.getRect()).intersects(paddle.getRect())) {
int paddleLPos = (int) paddle.getRect().getMinX();
int ballLPos = (int) ball.getRect().getMinX();
int first = paddleLPos + 8;
int second = paddleLPos + 16;
int third = paddleLPos + 24;
int fourth = paddleLPos + 32;
if (ballLPos < first) {
ball.setXDir(-1);
ball.setYDir(-1);
}
if (ballLPos >= first && ballLPos < second) {
ball.setXDir(-1);
ball.setYDir(-1 * ball.getYDir());
}
if (ballLPos >= second && ballLPos < third) {
ball.setXDir(0);
ball.setYDir(-1);
}
if (ballLPos >= third && ballLPos < fourth) {
ball.setXDir(1);
ball.setYDir(-1 * ball.getYDir());
}
if (ballLPos > fourth) {
ball.setXDir(1);
ball.setYDir(-1);
}
}
for (int i = 0; i < N_OF_BRICKS; i++) {
if ((ball.getRect()).intersects(bricks[i].getRect())) {
int ballLeft = (int) ball.getRect().getMinX();
int ballHeight = (int) ball.getRect().getHeight();
int ballWidth = (int) ball.getRect().getWidth();
int ballTop = (int) ball.getRect().getMinY();
Point pointRight = new Point(ballLeft + ballWidth + 1, ballTop);
Point pointLeft = new Point(ballLeft - 1, ballTop);
Point pointTop = new Point(ballLeft, ballTop - 1);
Point pointBottom = new Point(ballLeft, ballTop + ballHeight + 1);
if (!bricks[i].isDestroyed()) {
if (bricks[i].getRect().contains(pointRight)) {
ball.setXDir(-1);
} else if (bricks[i].getRect().contains(pointLeft)) {
ball.setXDir(1);
}
if (bricks[i].getRect().contains(pointTop)) {
ball.setYDir(1);
} else if (bricks[i].getRect().contains(pointBottom)) {
ball.setYDir(-1);
}
bricks[i].setDestroyed(true);
}
}
}
}
}
Brick Class
package Final;
import javax.swing.ImageIcon;
public class Brick extends Sprite {
private boolean destroyed;
public Brick(int x, int y) {
ImageIcon ii = new ImageIcon("images/bricks.png");
image = ii.getImage();
i_width = image.getWidth(null);
i_heigth = image.getHeight(null);
destroyed = false;
}
public boolean isDestroyed() {
return destroyed;
}
public void setDestroyed(boolean val) {
destroyed = val;
}
}
Commons Class
package Final;
public interface Commons {
public static final int WIDTH = 300;
public static final int HEIGTH = 400;
public static final int BOTTOM_EDGE = 390;
public static final int N_OF_BRICKS = 30;
public static final int INIT_PADDLE_X = 200;
public static final int INIT_PADDLE_Y = 360;
public static final int INIT_BALL_X = 230;
public static final int INIT_BALL_Y = 355;
public static final int DELAY = 1000;
public static final int PERIOD = 10;
}
Sprite Class
package Final;
import java.awt.Image;
import java.awt.Rectangle;
public class Sprite {
protected int x;
protected int y;
protected int i_width;
protected int i_heigth;
protected Image image;
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
public int getWidth() {
return i_width;
}
public int getHeight() {
return i_heigth;
}
Image getImage() {
return image;
}
Rectangle getRect() {
return new Rectangle(x, y,
image.getWidth(null), image.getHeight(null));
}
}
Breakout Class
package Final;
import java.awt.EventQueue;
import javax.swing.JFrame;
public class Breakout extends JFrame {
public Breakout() {
initUI();
}
private void initUI() {
add(new Board());
setTitle("Lord Carl's Demolition Job");
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(Commons.WIDTH, Commons.HEIGTH);
setLocationRelativeTo(null);
setResizable(false);
setVisible(true);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
Breakout game = new Breakout();
game.setVisible(true);
}
});
}
}
The problem is in checkCollision(). Inside the loop, j will never equal N_OF_BRICKS because of the loop condition. You could change to:
private void checkCollision() {
if (ball.getRect().getMaxY() > Commons.BOTTOM_EDGE) {
stopGame();
}
int j = 0;
for (int i = 0; i < N_OF_BRICKS; i++) {
if (bricks[i].isDestroyed()) {
j++;
}
}
if (j == N_OF_BRICKS) {
message = "Pay Day";
stopGame();
}
}
Also, in the Brick class you neglect to store the x,y coords:
public class Brick extends Sprite {
....
public Brick(int x, int y) {
ImageIcon ii = new ImageIcon("images/bricks.png");
image = ii.getImage();
i_width = image.getWidth(null);
i_heigth = image.getHeight(null);
destroyed = false;
// Save these
this.x = x;
this.y = y
}
....
}
Or, add a constructor to the Sprite class and call that from the Brick constructor:
public class Sprite {
....
public Sprite(int x, int y) {
this.x = x;
this.y = y;
}
....
}
public class Brick extends Sprite {
....
public Brick(int x, int y) {
// Call the sprite constructor
super(x, y);
ImageIcon ii = new ImageIcon("images/bricks.png");
image = ii.getImage();
i_width = image.getWidth(null);
i_heigth = image.getHeight(null);
destroyed = false;
}
....
}
I am currently making a Space Shooter in Java. I am able to make bullets shoot and enemies come from the top, but I am not sure how to check if they intersect. I understand that the Rectangle class has a intersects method, but I am not sure how I would place the rectangles around the bullets and the enemies, since I don't know beforehand how many may be on the screen. How can I do this? Here is my code:
Game.java
package main;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable, KeyListener {
//declare values
private static final long serialVersionUID = 1L;
public static final int WIDTH = 800;
public static final int HEIGHT = 600;
public static final String TITLE = "Space Shooter";
private boolean running = false;
private Thread thread;
private Player player;
private BufferedImage playerImage;
private BufferedImage bulletImage;
private BufferedImage enemyImage;
int playerx;
int playery;
int round = 1;
public Game() {
//
player = new Player((WIDTH/2)-32, HEIGHT-200);
//allocates all file resources
try {
playerImage = ImageIO.read(this.getClass().getResourceAsStream("/resources/player.png"));
bulletImage = ImageIO.read(this.getClass().getResourceAsStream("/resources/bullet.png"));
enemyImage = ImageIO.read(this.getClass().getResourceAsStream("/resources/enemy.png"));
} catch (IOException e) {
e.printStackTrace();
}
addKeyListener(this);
setFocusable(true);
requestFocusInWindow();
}
//starts thread
private synchronized void start() {
if (running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
//stops thread
private synchronized void stop() {
if (!running)
return;
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.exit(1);
}
#Override
//game loop
public void run() {
long lastTime = System.nanoTime();
final double amountOfTicks = 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
int updates = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while (running) {
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if (delta > 1) {
tick();
updates++;
delta--;
}
Shoot.updateBullets();
Enemy.updateEnemies();
render();
frames++;
if (System.currentTimeMillis() - timer > 1000) {
timer += 1000;
System.out.println(updates + " TICKS, " + frames + " FPS");
updates = 0;
frames = 0;
}
}
stop();
}
//updates sprite locations
public void tick() {
playerx = player.getX();
playery = player.getY();
}
//renders sprites
public void render() {
//setting up triple-buffering
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
//////////////////////////////////
g.setColor(Color.BLACK); g.fillRect(0,0,getWidth(), getHeight());
g.drawImage(playerImage, playerx, playery, this);
if (Shoot.allBullets.size() != 0) {
for (int i = 0; i < Shoot.allBullets.size(); i++) {
int bulletx = (int) Shoot.allBullets.get(i).x;
int bullety = (int) Shoot.allBullets.get(i).y;
g.drawImage(bulletImage, bulletx + 21, bullety, this);
}
}
if (Enemy.allEnemies.size() != 0) {
for (int i = 0; i < Enemy.allEnemies.size(); i++) {
int enemyx = (int) Enemy.allEnemies.get(i).x;
int enemyy = (int) Enemy.allEnemies.get(i).y;
g.drawImage(enemyImage, enemyx, enemyy, this);
}
} else {
Enemy.createEnemies(round);
round++;
}
//////////////////////////////////
g.dispose();
bs.show();
}
#Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_SPACE) {
Shoot.addBullet(player.getX(), player.getY());
}
}
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_UP) {
player.setY(playery -= 20);
} else if (key == KeyEvent.VK_DOWN) {
player.setY(playery += 20);
} else if (key == KeyEvent.VK_RIGHT) {
player.setX(playerx += 40);
} else if (key == KeyEvent.VK_LEFT) {
player.setX(playerx -= 40);
}
}
public void keyTyped(KeyEvent e) {}
public static void main(String[] args) {
Game game = new Game();
JFrame frame = new JFrame(TITLE);
frame.setSize(WIDTH, HEIGHT);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(game);
frame.getContentPane().setBackground(Color.BLACK);
frame.setVisible(true);
game.start();
}
}
Shoot.java
package main;
import java.util.ArrayList;
public class Shoot {
static ArrayList<Point> allBullets = new ArrayList<Point>();
public static void addBullet(int x, int y) {
allBullets.add(new Point(x, y));
}
public static ArrayList<Point> getAllBulletPosistions() {
return allBullets;
}
public static void updateBullets() {
if (allBullets.size() != 0) {
for (int i = 0; i < allBullets.size(); i++) {
allBullets.get(i).y -= 1;
}
}
}
}
Enemy.java
package main;
import java.util.ArrayList;
public class Enemy {
static ArrayList<Point> allEnemies = new ArrayList<Point>();
public static ArrayList<Point> createEnemies(int round) {
for (int i = 0; i < round; i++) {
Point newEnemyLocation = new Point((int) (Math.random()*Game.WIDTH - 64), 0);
if (newEnemyLocation.x < 64) {
newEnemyLocation.x += 70;
}
allEnemies.add(newEnemyLocation);
}
return allEnemies;
}
int validate(int xpos) {
if (xpos > Game.WIDTH - 64) {
xpos -= 64;
}
if (xpos < 64) {
xpos += 64;
}
return xpos;
}
public static ArrayList<Point> updateEnemies() {
if (allEnemies.size() != 0) {
for (int i = 0; i < allEnemies.size(); i++) {
Point enemyLocation = allEnemies.get(i);
if (enemyLocation.y <= Game.HEIGHT) {
allEnemies.get(i).y += 0.1;
} else {
allEnemies.remove(i);
}
}
}
return allEnemies;
}
}
for(int i = 0; i < Shoot.allBullets.size(); i++){
for(int j = 0; j < Enemy.allEnemys.size(); j++){
if(new Rectangle(Shoot.allBullets.get(i).x,Shoot.allBullets.get(i).y, width, height).intersects(new Rectangle(Enemy.allEnemys.get(j).x, Enemy.allEnemys.get(j).y, width, height)){
//on intersect
}
}
}
This would work but you shouldn't create new rectangles like this instead you should create a bullet class and a Enemy class that both contains the position and Rectangle anyways good luck!
This is my Game Class:
package Game;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Game extends JPanel implements Runnable {
Thread thread;
private boolean running = true;
private double FPS = 1.0/60.0;
private Level level;
public Game(){
level = new LevelOne();
level.setBackground(Color.BLACK);
add(level);
}
public synchronized void start() {
thread = new Thread(this, "Game");
thread.start();
}
public synchronized void stop() {
running = false;
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
#Override
public void run() {
double firstTime = 0;
double lastTime = System.nanoTime() / 1000000000.0;
double passedTime = 0;
double updateTime = 0;
double timer = System.nanoTime() / 1000000000.0;
int rendered = 0;
int updates = 0;
while (running) {
firstTime = System.nanoTime() / 1000000000.0;
passedTime = firstTime - lastTime;
lastTime = firstTime;
updateTime += passedTime;
while(updateTime > FPS){
updates++;
update();
updateTime -= FPS;
}
render();
rendered++;
if((System.nanoTime() / 1000000000) - timer > 1){
timer += 1;
System.out.println("FPS:"+rendered+" Updates:"+updates);
updates = 0;
rendered = 0;
}
}
}
private void update() {
}
private void render() {
this.repaint();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
level.repaint();
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setLocationRelativeTo(null);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setTitle("Game");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Game game = new Game();
frame.add(game);
game.start();
}
}
My LevelOne class:
package Game;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class LevelOne extends Level {
private BufferedImage spriteSheet;
private BufferedImage[] player = new BufferedImage[4]; //0 = down, 1 = right, 2 = up, 3 = left
private int dir = 0;
private String UP = "W";
private String DOWN = "S";
private String LEFT = "A";
private String RIGHT = "D";
private int speedX = 0;
private int speedY = 0;
public LevelOne(){
try {
spriteSheet = ImageIO.read(new File("images/sprites.png"));
} catch (IOException e) {
e.printStackTrace();
}
for (int i = 0; i < 4; i++) {
player[i] = spriteSheet.getSubimage((i * 18), 0, 18, 28);
}
this.addKeyListener(new KeyListener() {
#Override
public void keyPressed(KeyEvent e) {
String key = e.getKeyText(e.getKeyCode());
if (key.equals(UP)) {
dir = 2;
speedY = -5;
} else if (key.equals(LEFT)) {
dir = 3;
speedX = -5;
} else if (key.equals(RIGHT)) {
dir = 1;
speedX = 5;
} else if (key.equals(DOWN)) {
dir = 0;
speedY = 5;
}
}
#Override
public void keyReleased(KeyEvent e) {
String key = e.getKeyText(e.getKeyCode());
if (key.equals(UP)) {
speedY = 0;
} else if (key.equals(LEFT)) {
speedX = 0;
} else if (key.equals(RIGHT)) {
speedX = 0;
} else if (key.equals(DOWN)) {
speedY = 0;
}
}
#Override
public void keyTyped(KeyEvent e) {
}
});
}
public void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(player[dir], 0, 0, 18, 28, null);
}
}
LevelOne extends Level, which is currently empty(And extends JPanel), I'm not sure if I need to add anything to Level. I just dont get what I need to do to make the player image show up...
And sorry if my code is sloppy, I'm trying to get into higher level Java, and im not sure if I am just approaching it wrong.
Thanks.
Six things...
Don't call level.repaint from within the paintComponent method of Game, this could cause an infinite loop of repaint requests which is going to screw with your frame rate. Consider calling it within your render method
paintComponent should never public, there's no reason for anybody to ever call it directly.
Use key bindings over KeyListener, they will solve focus related issues. How to Use Key Bindings
Move frame.setVisible AFTER frame.add(game);, in fact, it really should the last thing you do
Make sure your images are loading properly
Set the layout manager for Game to BorderLayout
I'm creating a game like zType
and I have a problem in validating the input. As you can see in the picture below it select two words. How can I fix this problem, please help.
This is My Game class
import java.awt.Canvas;
import java.awt.event.KeyListener;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.LinkedList;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
public class Game extends Canvas implements Runnable, KeyListener
{
public static final int WIDTH = 640;
public static final int HEIGHT = 680;
public final String TITLE = "Game";
private boolean running = false;
private Thread thread;
private BufferedImage spriteSheet = null;
private BufferedImage background = null;
public int level = 1;
public int fps = 0;
public int score = 0;
private int enemy_count = 15;
private int enemy_killed = 0;
private int enemy_notkilled = 0;
private boolean target = false;
public String t = "";
private Controller c;
private Textures tex;
private LinkedList<Enemy> e = new LinkedList<Enemy>();
private Enemy enemy;
public void init()
{
requestFocus();
try
{
spriteSheet = ImageIO.read(getClass().getResource("/sprite_sheet.png"));
background = ImageIO.read(getClass().getResource("/background.png"));
}
catch(IOException e)
{
e.printStackTrace();
}
tex = new Textures(this);
c = new Controller(tex, this);
addKeyListener(this);
c.createEnemy(enemy_count);
e = c.getEnemy();
}
private synchronized void start()
{
if(running)
return;
running = true;
thread = new Thread(this);
thread.start();
}
private synchronized void stop()
{
if(!running)
return;
running = false;
try
{
thread.join();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
System.exit(1);
}
public void run()
{
init();
long lastTime = System.nanoTime();
final double amountOfTicks= 60.0;
double ns = 1000000000 / amountOfTicks;
double delta = 0;
int frames = 0;
long timer = System.currentTimeMillis();
while(running)
{
long now = System.nanoTime();
delta += (now - lastTime) / ns;
lastTime = now;
if(delta >= 1)
{
update();
delta--;
}
render();
frames++;
if(System.currentTimeMillis() - timer > 1000)
{
timer += 1000;
fps = frames;
frames = 0;
}
}
stop();
}
private void update()
{
c.update();
if(enemy_killed + enemy_notkilled >= enemy_count)
{
e.clear();
t = "";
level++;
enemy_killed = 0;
enemy_notkilled = 0;
c.createEnemy(enemy_count);
}
}
private void render()
{
BufferStrategy bs = this.getBufferStrategy();
if(bs == null)
{
createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.drawImage(background, 0, 0, null);
c.render(g);
g.dispose();
bs.show();
}
public void keyPressed(KeyEvent ek)
{
int key = ek.getKeyCode();
char character = Character.toLowerCase(ek.getKeyChar());
boolean result = isValid(key);
if(result && !target)
{
for(int i = 0; i < e.size(); i++)
if(e.get(i).getFirstLetter() == character && e.get(i).getOnScreen())
{
enemy = e.get(i);
t = enemy.getText();
if(enemy.getCurrentIndex() == 0)
enemy.addCurrentIndex();
target = true;
System.out.println("---"+enemy.text);
break;
}
}
else if(result && t.charAt(enemy.getCurrentIndex()) == character)
enemy.addCurrentIndex();
}
public void keyReleased(KeyEvent ek){ }
public void keyTyped(KeyEvent ek){ }
public static void main(String[] args)
{
Game game = new Game();
game.setPreferredSize(new Dimension(WIDTH, HEIGHT));
game.setMaximumSize(new Dimension(WIDTH, HEIGHT));
game.setMinimumSize(new Dimension(WIDTH, HEIGHT));
JFrame frame = new JFrame(game.TITLE);
frame.add(game);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
game.start();
}
public boolean isValid(int key)
{
return key >= 65 && key <= 90 ? true : false;
}
public BufferedImage getSpriteSheet()
{
return spriteSheet;
}
public int getEnemy_count()
{
return enemy_count;
}
public void setEnemy_count(int enemy_count)
{
this.enemy_count = enemy_count;
}
public int getEnemy_killed()
{
return enemy_killed;
}
public void setEnemy_killed(int enemy_killed)
{
this.enemy_killed = enemy_killed;
}
public int getEnemy_notkilled()
{
return enemy_notkilled;
}
public void setEnemy_notkilled(int enemy_notkilled)
{
this.enemy_notkilled = enemy_notkilled;
}
public void addScore(int k)
{
score += k;
}
public void falseTarget()
{
target = false;
}
public String getT()
{
return t;
}
public void setT(String k)
{
t = k;
}
}
This is my Enemy Class
import java.awt.*;
import java.awt.font.TextAttribute;
import java.text.AttributedString;
public class Enemy
{
private double x ,y;
public String text;
private char firstLetter;
private AttributedString as;
private Controller c;
private Textures tex;
private Game game;
private int currentIndex = 0;
private int textLength = 0;
private double speed = 0.0;
private int stringWidth = 0;
private boolean onScreen = false;
public Enemy(double x, double y, double speed, Textures tex, Controller c, Game game, String text, int stringWidth)
{
this.x = x;
this.y = y;
this.tex = tex;
this.text = text;
this.game = game;
this.c = c;
this.speed = speed;
firstLetter = this.text.charAt(0);
textLength = this.text.length();
this.stringWidth = stringWidth;
}
public void update()
{
y += speed;
if(y >= 0)
onScreen = true;
if(currentIndex >= textLength)
{
game.addScore(5);
game.setT("");
c.removeEnemy(this);
game.setEnemy_killed(game.getEnemy_killed() + 1);
game.falseTarget();
}
if(y >= Game.HEIGHT - 50)
{
//game.decreaseHealth();
game.setT("");
c.removeEnemy(this);
game.setEnemy_notkilled(game.getEnemy_notkilled() + 1);
game.falseTarget();
game.t ="";
}
}
public void render(Graphics g)
{
g.drawImage(tex.enemy, (int)x, (int)y, null);
as = new AttributedString(text);
if(currentIndex >= 1)
as.addAttribute(TextAttribute.FOREGROUND, Color.WHITE, 0, currentIndex);
as.addAttribute(TextAttribute.FONT, new Font("Consolas", Font.BOLD, 12), 0, text.length());
g.drawString(as.getIterator(), (int)x + getAdd(stringWidth), (int)y + 13);
}
public double getX()
{
return x;
}
public double getY()
{
return y;
}
public String getText()
{
return text;
}
public char getFirstLetter()
{
return firstLetter;
}
public void addCurrentIndex()
{
currentIndex++;
}
public int getCurrentIndex()
{
return currentIndex;
}
public int getTextLength()
{
return textLength;
}
public int getAdd(int width)
{
return (96 / 2) - (width / 2);
}
public boolean getOnScreen()
{
return onScreen;
}
}
The problem is that you're calling falseTarget() whenever an enemy moves out of the screen. In your example, you assigned target = true when you pressed the 'o' (for the enemy named "owe"), but then a different enemy (maybe "jet", maybe an enemy that is no longer visible) finished "dropping" out of the screen (y >= Game.HEIGHT - 50), so you called falseTarget() - and thus, when you pressed 'i' you started a new enemy ("ice").
What you want to do is call falseTarget() in this case only if the enemy that dropped out of the screen is the one that's currently being targeted:
if(y >= Game.HEIGHT - 50)
{
//game.decreaseHealth();
//game.setT(""); // <-- Commented this line out
c.removeEnemy(this);
game.setEnemy_notkilled(game.getEnemy_notkilled() + 1);
if(game.getT().equals(text)) // <-- Added this if before calling falseTarget()
{ // and clearing the game's current enemy text
game.falseTarget();
game.t ="";
}
}
I am writing the Snake game. I am stuck with the animations, because I want to get smooth animation. I don't how to double buffer images so that to get double-buffering. What has to be done so that this becomes double-buffered?
I use main frame that extends JFrame, and here I add two JPanels - one for status bar and one for animation.
Here are the classes used for snake animation:
Player.class
package snake;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import javax.swing.ImageIcon;
public class Player
{
private int headSizeX;
private int headSizeY;
private int tailSizeX;
private int tailSizeY;
private int x;
private int y;
private int speed = 5;
private int snakeSize = 40;
private Image[] snake = new Image[5];
private ArrayList<Integer> X,Y;
private static int imageNr = 0;
private int c = 0;
private int tmp;
private boolean death = false;
static int player;
private static boolean inverse = false;
private boolean left = false;
private boolean right = false;
private boolean up = true;
private boolean down = false;
public Player()
{
initPlayer();
headSizeX = snake[0].getWidth(null);
headSizeY = snake[0].getHeight(null)-2;
tailSizeX = snake[4].getWidth(null);
tailSizeY = snake[4].getHeight(null);
System.out.println("tail: "+tailSizeX+" "+tailSizeY);
x = MainGamePanel.getSizeX()/2;
y= MainGamePanel.getSizeY()-130;
}
public void initPlayer()
{
int imgNr = 5;
X = new ArrayList<Integer>();
Y = new ArrayList<Integer>();
String name = "green";
switch (player)
{
case 1:
name = "green"; break;
case 2:
name = "red"; break;
case 3:
name = "blue"; break;
}
for (int nr = 1; nr <= imgNr; nr++)
{
snake[nr-1] = new ImageIcon("img/" +name+"/snake" +nr+".png").getImage();
}
X.add(MainGamePanel.getSizeX()/2);
Y.add( MainGamePanel.getSizeY()-200);
X.add( MainGamePanel.getSizeX()/2);
Y.add( MainGamePanel.getSizeX()/2+33);
for (int i = 2; i < snakeSize; i++) {
X.add( MainGamePanel.getSizeX()/2);
Y.add( MainGamePanel.getSizeX()/2 + i*20+13);
}
}
public void paint(Graphics g)
{
//g.drawImage(snake[imageNr], x,y,headSizeX,headSizeY,null);
for (int i = 0; i < snakeSize; i++) {
if (i == 0)
g.drawImage(snake[imageNr], X.get(i), Y.get(i), null);
else
g.drawImage(snake[4], X.get(i), Y.get(i), null);
}
/*g.drawImage(snake[4],x, y+headSizeY, tailSizeX, tailSizeY, null);
for (int i = 1;i<snakeSize;i++)
g.drawImage(snake[4],x, y+i*tailSizeY+headSizeY, tailSizeX, tailSizeY, null);*/
}
public void update()
{
y = MainGamePanel.getSizeY()-headSizeY - 35;
for (int i = snakeSize-1; i > 0; i--) {
X.set(i, X.get(i-1));
Y.set(i, Y.get(i-1));
}
if (left) {
tmp = X.get(0);
X.set(0, tmp-20);
imageNr = 3;
}
if (right) {
tmp = X.get(0);
X.set(0, tmp+20);
imageNr = 1;
}
if (up) {
tmp = Y.get(0);
Y.set(0, tmp-20);
imageNr = 0;
}
if (down) {
tmp = Y.get(0);
Y.set(0, tmp+20);
imageNr = 2;
}
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
if ((key == KeyEvent.VK_LEFT) && (!right)) {
left = true;
up = false;
down = false;
System.out.println("LEWO");
}
if ((key == KeyEvent.VK_RIGHT) && (!left)) {
right = true;
up = false;
down = false;
System.out.println("PRAWO");
}
if ((key == KeyEvent.VK_UP) && (!down)) {
up = true;
right = false;
left = false;
System.out.println("GÓRA");
}
if ((key == KeyEvent.VK_DOWN) && (!up)) {
down = true;
right = false;
left = false;
System.out.println("DÓŁ");
}
}
public void collision()
{
death = true;
}
public void reset()
{
imageNr = 0;
death = false;
}
public void setInverse(boolean set)
{
inverse = set;
}
public void increaseSpeed(int inc)
{
speed += inc;
}
public void decreaseSpeed(int dec)
{
speed -=dec;
}
public int getSnakeSize()
{
return snakeSize;
}
public void increaseSnakeSize()
{
snakeSize += 1;
}
public void decreaseSnakeSize(int dec)
{
snakeSize -= dec;
}
}
MainGamePanel.class
package snake;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
#SuppressWarnings("serial")
public class MainGamePanel extends JPanel implements KeyListener{
private Image bounds;
private Player player;
public static int sizex;
private Image tail;
private Image background;
private int lives;
private int speed;
private int levels;
private int counter = 0;
private int appleCounter = 0;
private static int level = 1;
public static int sizeX = 784;
public static int sizeY = 617;
public static int applesNumber;
private boolean gameover = false;
private boolean gameend = false;
private boolean death = false;
private boolean levelCompleted = false;
private Graphics buffer;
private BufferedImage img;
public MainGamePanel(int[] settings)
{
lives = settings[0];
speed = settings[1];
levels = settings[2];
bounds = new ImageIcon("img/bounds.jpg").getImage();
setFocusable(true);
addKeyListener(this);
//new Apple();
}
public void init()
{
player = new Player();
img = new BufferedImage(sizeX, sizeY, 2);
Levels.getLevel(1);
this.applesNumber = Levels.getApplesNumber();
this.background = new ImageIcon("img/bg/" + Levels.getBackground()).getImage();
}
public void addNotify()
{
super.addNotify();
init();
}
public void paintComponent(Graphics g){
super.paintComponent(g);
buffer = img.getGraphics();
buffer.drawImage(background, 0,0, sizeX, sizeY, null);
player.paint(buffer);
for (int i = 0; i <= getWidth(); i += 12) {
buffer.drawImage(bounds, i, 0, this);
buffer.drawImage(bounds, i, getHeight()-12, this);
}
for (int i = 12; i < getHeight(); i += 12) {
buffer.drawImage(bounds, 0, i, this);
buffer.drawImage(bounds, getWidth()-12, i, this);
}
g.drawImage(this.img, 0, 0, getWidth(), getHeight(), null);
buffer.clearRect(12, 12, sizeX, sizeY);
}
public void play()
{
if (level == this.levels) gameend = true;
this.player.reset();
this.counter = 0;
this.appleCounter = 0;
long StartTime = System.currentTimeMillis();
player.update();
repaint();
/*do
{
Thread.yield();
}
while (System.currentTimeMillis() - StartTime < this.speed);*/
}
public void gameLoop()
{
while(true)
{
play();
try
{
Thread.sleep(150);
}
catch (InterruptedException ex)
{
}
if (death)
{
lives -= 1;
death = false; continue;
}
levelCompleted = false;
level+=1;
Levels.getLevel(level);
applesNumber = Levels.getApplesNumber();
}
}
public static int getApp()
{
return applesNumber;
}
public static int getSizeX()
{
return sizeX;
}
public static int getSizeY()
{
return sizeY;
}
public void setGameOver()
{
gameover = true;
}
#Override
public void keyPressed(KeyEvent e)
{
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) System.exit(0);
player.keyPressed(e);
}
#Override
public void keyReleased(KeyEvent e) {}
#Override
public void keyTyped(KeyEvent e) {}
}
and Game.class for JFrame
package snake;
import java.awt.Dimension;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import java.awt.BorderLayout;
#SuppressWarnings("serial")
public class Game extends JFrame {
//public SnakeTheGame start;
private ImageIcon icon;
StatBar statbar;
private MainGamePanel start;
public static final int WIDTH = 800;
public static final int HEIGHT = 700;
public static final int MIN_WIDTH = 450;
public static final int MIN_HEIGHT = 450;
public Game()
{
start = new MainGamePanel(new int[] { Settings.getLives(), Settings.getSpeed(), Settings.getLevels() });
statbar = new StatBar();
icon = new ImageIcon("img//icon.png");
setBounds(200, 200, WIDTH, HEIGHT);
setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
setTitle("Snake The Game");
setIconImage(this.icon.getImage());
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
getContentPane().add(statbar, BorderLayout.SOUTH);
getContentPane().add(start, BorderLayout.CENTER);
// this.createBufferStrategy(2);
this.start.setVisible(true);
start.requestFocus();
}
public void start()
{
start.gameLoop();
}
}
JPanel is double-buffered by default. What you need to do is remove the loop in favour of a timer which does 60 FPS, calling play() and invoking one of the repaint methods.
Sample code
(Import from java.util. I did not use your names.)
private class AnimationTask extends TimerTask {
#Override
public void run() {
play();
animationPanel.repaint();
}
}
private Timer timer;
/**
* Creates new form AnimationDemoFrame
*/
public AnimationDemoFrame() {
timer = new Timer();
initComponents();
timer.schedule(new AnimationTask(), 150);
}
private void play() {
;
}