Detect Collision in Simple Space Invaders - java

Im using java to create a space invaders game but i seem to be having trouble detecting collisions, here is my game panel, we were given some sample code which i have added to. I have created different classes for each enemy which are extended from the enemy class.
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Random;
import javax.swing.JPanel;
import javax.swing.Timer;
#SuppressWarnings("serial")
public class GamePanel extends JPanel implements ActionListener, KeyListener
{
private Player player;
private Enemy enemy;
private Enemy mothership;
private Enemy destroyer;
private Enemy meteor;
private int enemyNumber = 0;
private int totalscore = 0;
private boolean destroyerspawn = false;
private boolean meteorspawn = false;
private boolean mothershipstop = false;
private boolean meteorstop = false;
private boolean destroyerstop = false;
private Random random = new Random();
private ArrayList<Enemy> enemyList;
Timer redrawTimer;
public GamePanel()
{
// As above commented out until enemy classes have been made
enemyList = new ArrayList<Enemy>();
// This starts the time that controls how often the screen is redrawn
redrawTimer = new Timer(10, this);
}
// Method to start the game
public void startGame(int width, int height)
{
// Create player
player = new Player(width, height);
// Create mothership
mothership = new Mothership(width, height, 0, 0);
// Create destroyer
destroyer = new Destroyers(width, height, 0, 0);
// Create meteor
meteor = new Meteor(width, height, 0, 0);
// Loop to create multiple enemies
// Goes through y axis changing the enemy type at each increment
for (int y = 0; y < 3; y++)
{
// Goes through x axis making 6 of each enemy type
for (int x = 0; x < 6; x++)
{
if(y == 0 || y == 3)
{
enemy = new Martians(width, height, (x * 70), (y * 70));
enemyList.add(enemy);
enemyNumber++;
}
else if(y == 1 || y == 4)
{
enemy = new Mercurians(width, height, (x * 70), (y * 70));
enemyList.add(enemy);
enemyNumber++;
}
else if(y == 2 || y == 5)
{
enemy = new Venusians(width, height, (x * 70), (y * 70));
enemyList.add(enemy);
enemyNumber++;
}
}
}
// Starts draw timer
redrawTimer.start();
}
// Method to pause the game
public void pauseGame()
{
redrawTimer.restart();
}
// Handles the timer event, so this method repeats based on the interval set in your timer
#Override
public void actionPerformed(ActionEvent e)
{
this.revalidate();
// Causes the screen to be redrawn
this.repaint();
}
// Our paint component method that draws every thing we need to the screen
public void paintComponent(Graphics g)
{
// This line ensures that every that would usually be drawn by a panel is
super.paintComponent(g);
// Clear the screen
g.setColor(Color.black);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
if(player!= null && player.isActive())
{
// Draw the player
player.draw(g);
}
// If statement that stops this code running once it's deactivated once
if (mothershipstop == false)
{
// If there are no enemies left
if (enemyNumber == 0)
{
if(mothership!= null && mothership.isActive())
{
// Draw and move the mothership
mothership.draw(g);
mothership.Move();
}
// Detects whether there's been a collision
for (int b = 0; b < player.getBulletCount(); b++)
{
// Collision detection for bullet
player.getBullet(b).detectCollision(mothership);
}
if (player.isActive() == true && mothership.isActive())
{
// Collision detection for player
player.detectCollision(mothership);
}
}
}
// If statement that stops this code running once it's deactivated once
if (destroyerstop == false)
{
// Each tick will have a 1 in 1000 chance of spawning a destroyer
if (random.nextInt(1000) == 1)
{
destroyerspawn = true;
}
// If the random integer got activated, destroyer spawns
if (destroyerspawn == true && destroyer!= null && destroyer.isActive())
{
// Draw and move the destroyer
destroyer.draw(g);
destroyer.Move();
// Detects whether there's been a collision
for (int b = 0; b < player.getBulletCount(); b++)
{
// Collision detection for bullet
player.getBullet(b).detectCollision(destroyer);
}
}
else if (destroyer.isActive() == false)
{
destroyerstop = true;
totalscore = totalscore + destroyer.GetScore();
}
}
// If statement that stops this code running once it's deactivated once
if (meteorstop == false)
{
// Each tick will have a 1 in 700 chance of spawning an asteroid
if (random.nextInt(700) == 1)
{
meteorspawn = true;
}
// If the random integer got activated, asteroid spawns
if (meteorspawn == true && meteor!= null && meteor.isActive())
{
// Draw and move the asteroid
meteor.draw(g);
meteor.Move();
// Detects whether there's been a collision
for (int b = 0; b < player.getBulletCount(); b++)
{
// Collision detection for bullet
player.getBullet(b).detectCollision(meteor);
}
if (player.isActive() == true && meteor.isActive())
{
// Collision detection for player
player.detectCollision(meteor);
}
}
else if (meteor.isActive() == false)
{
meteorstop = true;
totalscore = totalscore + meteor.GetScore();
}
}
// Code to draw the enemy
Iterator<Enemy> iterator = enemyList.iterator();
// Loops to check each enemy
while (iterator.hasNext())
{
// Checks the next enemy
enemy = iterator.next();
// If there's an enemy or active enemy
if(enemy != null && enemy.isActive())
{
// Draw and move the enemy
enemy.draw(g);
enemy.Move();
} // If non-existent enemy or is inactive
else
{
// Get score
totalscore = totalscore + enemy.GetScore();
// Remove the enemy
iterator.remove();
}
// If an enemy has been removed
if (enemy.lives == 0)
{
// Decrement number of enemies
enemyNumber--;
}
// Detects whether there's been a collision
for (int b = 0; b < player.getBulletCount(); b++)
{
// Collision detection for bullet
player.getBullet(b).detectCollision(enemy);
}
if (player.isActive() == true && enemy.isActive())
{
// Collision detection for player
}
}
// Checks if game ends
endGame();
}
public void endGame()
{
if (player.isActive() == false)
{
// You lose
System.out.println("Game over! You lose.");
System.out.println("Your score is: " + totalscore);
// Close game
System.exit(ABORT);
}else if (mothership.isActive() == false)
{
// You win
totalscore = totalscore + mothership.GetScore();
System.out.println("Congratulations! You win.");
System.out.println("Your score is: " + totalscore);
// Close game
System.exit(ABORT);
}
}
// Code here controls the key events
#Override
public void keyPressed(KeyEvent event)
{
switch(event.getKeyCode())
{
case KeyEvent.VK_RIGHT: player.move(1); break;
case KeyEvent.VK_LEFT: player.move(-1); break;
case KeyEvent.VK_SPACE: player.fire(); break;
}
}
#Override
public void keyReleased(KeyEvent event)
{
}
#Override
public void keyTyped(KeyEvent event)
{
}
}
n my bullet class there is a detect collision method that we have to fill in, i however have no clue how to do this. here is the code for the bullet class.
import java.awt.Graphics;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
public class Bullet {
private Point position;
private int height, width;
private BufferedImage img;
private int speed = 20;
private boolean active;
public Bullet(Point playerPosition){
//same as the player class this simply loads the image for the bullet.
try {
img = ImageIO.read(getClass().getResource("/playerbullet.jpg"));
//System.out.println("***************OK*******************");
} catch (IOException e) {
//System.out.println("***************CAN'T READ FILE*******************");
e.printStackTrace();
}
height = img.getHeight();
width = img.getWidth();
//sets the bullet position we have to do a little offset wit the bullet image so our bullet appears in the (horizontal) centre of our player
position = new Point(playerPosition.x - (width/2), playerPosition.y);
active = true;
}
//draws the bullet
public void draw(Graphics g) {
g.drawImage(img, position.x, position.y, width, height, null);
}
//moves the bullet unless it has gone off the top of the screen in which case the bullet is destroyed
public void move(){
if(position.y < 0){
destroy();
}
else{
position.y-=speed;
}
}
//sets the bullet as inactive
public void destroy(){
active = false;
}
//returns whether the bullet is active or not
public boolean isActive(){
return active;
}
//returns the bullets current position
public Point getPosition() {
// TODO Auto-generated method stub
return position;
}
// this method will flag as an error until you create your enemy classes
public void detectCollision(Enemy e)
{
}
}

You can try Rectangle class in Java
There is a method called "createIntersection" which returns the Rectangle where 2 rectangles overlap. If that area is zero, there's no collision.
Inside your Bullet class, you stored the position, width and height. But in fact this tells that you are actually storing the "Rectangle". So, try to refactor your implementation and use Rectangle instead.
In the detectCollision() method, the parameter should be the Rectangle of the checking target (i.e. player). Then you can use the createIntersection() to check the overlapping area

Related

A* pathfinding game system exit issue

I am making a game where a badGuy AI is trying to chase me while I use arrow keys to move away. In my main I have a try catch block for if the player attempts to exit the screen border. For some reason however when I click on start I get the exception which I have a system print out saying "GAME OVER, you exited the map". Without my reCalcPath method in the badguy class this does not happen so it must be an issue within this method.
For this method I have a map array. This array is a 40x40 boolean array of 20x20 pixels/cells/squares which states true if I have clicked on that cell position if previously false, painting a white square and visa versa. Now I thought, check the cell position of the badGuy, then check all of his neighbouring cells, if the state of that cell is false i.e. no cell is painted (which means there is no wall blocking him in this sense), then check for the distance between him and my player. I use a Euclidean distance approach by treating xPlayer-xbadGuy, yPLayer-xBadGuy as the opposite and adjacent sides of a triangle. Using pythagoras I get the hypotenuse. Do this for each neighbouring cell, the one with the smallest hypotenuse means shortest distance. Now this is not working at all as when its called the game crashes. Ignore the move method as that is irrelevant if recalcpath won't work
Main
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.image.*;
import java.io.*;
public class AStarMaze extends JFrame implements Runnable, MouseListener, MouseMotionListener, KeyListener {
// member data
private boolean isInitialised = false;
private BufferStrategy strategy;
private Graphics offscreenBuffer;
public boolean map[][] = new boolean[40][40];
private boolean isGameRunning = false;
private BadGuy badguy;
private Player player;
private int startI, startJ;
private int endI, endJ;
private String pFilePath, bgFilePath;
// constructor
public AStarMaze () {
//Display the window, centred on the screen
Dimension screensize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
int x = screensize.width/2 - 400;
int y = screensize.height/2 - 400;
setBounds(x, y, 800, 800);
setVisible(true);
this.setTitle("A* Pathfinding Demo");
bgFilePath = "C:\\Users\\brads\\IdeaProjects\\PathfindingAssignment\\src\\badguy.png";
pFilePath = "C:\\Users\\brads\\IdeaProjects\\PathfindingAssignment\\src\\player.png";
// load raster graphics and instantiate game objects
ImageIcon icon = new ImageIcon(bgFilePath);
Image img = icon.getImage();
badguy = new BadGuy(img);
icon = new ImageIcon(pFilePath);
img = icon.getImage();
player = new Player(img);
// create and start our animation thread
Thread t = new Thread(this);
t.start();
// initialise double-buffering
createBufferStrategy(2);
strategy = getBufferStrategy();
offscreenBuffer = strategy.getDrawGraphics();
// register the Jframe itself to receive mouse and keyboard events
addMouseListener(this);
addMouseMotionListener(this);
addKeyListener(this);
// initialise the map state
for (x=0;x<40;x++) {
for (y=0;y<40;y++) {
map[x][y]=false;
}
}
isInitialised = true;
}
public boolean[][] getMap(){
return map;
}
// thread's entry point
public void run() {
long loops=0;
while ( 1==1 ) {
// 1: sleep for 1/5 sec
try {
Thread.sleep(100);
} catch (InterruptedException e) { }
try {
// 2: animate game objects
if (isGameRunning) {
loops++;
player.move(map); // player moves every frame
if (loops % 3 == 0) // badguy moves once every 3 frames
badguy.reCalcPath(map,player.x,player.y);
// badguy.move(map, player.x, player.y);
}
// 3: force an application repaint
this.repaint();
}
catch(IndexOutOfBoundsException e){
System.out.println("GAME OVER, you exited the map");
System.exit(-1);
}
}
}
private void loadMaze() {
String filename = "C:\\Users\\brads\\IdeaProjects\\PathfindingAssignment\\maze.txt";
String textinput = null;
try {
BufferedReader reader = new BufferedReader(new FileReader(filename));
textinput = reader.readLine();
reader.close();
}
catch (IOException e) { }
if (textinput!=null) {
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
map[x][y] = (textinput.charAt(x*40+y)=='1');
}
}
}
}
private void saveMaze() {
// pack maze into a string
String outputtext="";
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
if (map[x][y])
outputtext+="1";
else
outputtext+="0";
}
}
try {
String filename = "C:\\Users\\brads\\IdeaProjects\\PathfindingAssignment\\maze.txt";
BufferedWriter writer = new BufferedWriter(new FileWriter(filename));
writer.write(outputtext);
writer.close();
}
catch (IOException e) { }
}
// mouse events which must be implemented for MouseListener
public void mousePressed(MouseEvent e) {
if (!isGameRunning) {
// was the click on the 'start button'?
int x = e.getX();
int y = e.getY();
if (x>=15 && x<=85 && y>=40 && y<=70) {
isGameRunning=true;
return;
}
// or the 'load' button?
if (x>=315 && x<=385 && y>=40 && y<=70) {
loadMaze();
return;
}
// or the 'save' button?
if (x>=415 && x<=485 && y>=40 && y<=70) {
saveMaze();
return;
}
}
// determine which cell of the gameState array was clicked on
int x = e.getX()/20;
int y = e.getY()/20;
// toggle the state of the cell
map[x][y] = !map[x][y];
// throw an extra repaint, to get immediate visual feedback
this.repaint();
// store mouse position so that each tiny drag doesn't toggle the cell
// (see mouseDragged method below)
prevx=x;
prevy=y;
}
public void mouseReleased(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
public void mouseClicked(MouseEvent e) {}
//
// mouse events which must be implemented for MouseMotionListener
public void mouseMoved(MouseEvent e) {}
// mouse position on previous mouseDragged event
// must be member variables for lifetime reasons
int prevx=-1, prevy=-1;
public void mouseDragged(MouseEvent e) {
// determine which cell of the gameState array was clicked on
// and make sure it has changed since the last mouseDragged event
int x = e.getX()/20;
int y = e.getY()/20;
if (x!=prevx || y!=prevy) {
// toggle the state of the cell
map[x][y] = !map[x][y];
// throw an extra repaint, to get immediate visual feedback
this.repaint();
// store mouse position so that each tiny drag doesn't toggle the cell
prevx=x;
prevy=y;
}
}
//
// Keyboard events
public void keyPressed(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_LEFT)
player.setXSpeed(-1);
else if (e.getKeyCode()==KeyEvent.VK_RIGHT)
player.setXSpeed(1);
else if (e.getKeyCode()==KeyEvent.VK_UP)
player.setYSpeed(-1);
else if (e.getKeyCode()==KeyEvent.VK_DOWN)
player.setYSpeed(1);
}
public void keyReleased(KeyEvent e) {
if (e.getKeyCode()==KeyEvent.VK_LEFT || e.getKeyCode()==KeyEvent.VK_RIGHT)
player.setXSpeed(0);
else if (e.getKeyCode()==KeyEvent.VK_UP || e.getKeyCode()==KeyEvent.VK_DOWN)
player.setYSpeed(0);
}
public void keyTyped(KeyEvent e) { }
//
// application's paint method
public void paint(Graphics g) {
if (!isInitialised)
return;
g = offscreenBuffer; // draw to offscreen buffer
// clear the canvas with a big black rectangle
g.setColor(Color.BLACK);
g.fillRect(0, 0, 800, 800);
// redraw the map
g.setColor(Color.WHITE);
for (int x=0;x<40;x++) {
for (int y=0;y<40;y++) {
if (map[x][y]) {
g.fillRect(x*20, y*20, 20, 20);
}
}
}
// redraw the player and badguy
// paint the game objects
player.paint(g);
badguy.paint(g);
if (!isGameRunning) {
// game is not running..
// draw a 'start button' as a rectangle with text on top
// also draw 'load' and 'save' buttons
g.setColor(Color.GREEN);
g.fillRect(15, 40, 70, 30);
g.fillRect(315, 40, 70, 30);
g.fillRect(415, 40, 70, 30);
g.setFont(new Font("Times", Font.PLAIN, 24));
g.setColor(Color.BLACK);
g.drawString("Start", 22, 62);
g.drawString("Load", 322, 62);
g.drawString("Save", 422, 62);
}
// flip the buffers
strategy.show();
}
// application entry point
public static void main(String[] args) {
AStarMaze w = new AStarMaze();
}
}
Player Class
import java.awt.Graphics;
import java.awt.Image;
public class Player {
Image myImage;
int x=0,y=0;
int xSpeed=0, ySpeed=0;
public Player( Image i ) {
myImage=i;
x=10;
y=35;
}
public void setXSpeed( int x ) {
xSpeed=x;
}
public void setYSpeed( int y ) {
ySpeed=y;
}
public void move(boolean map[][]) {
int newx=x+xSpeed;
int newy=y+ySpeed;
if (!map[newx][newy]) {
x=newx;
y=newy;
}
}
public void paint(Graphics g) {
g.drawImage(myImage, x*20, y*20, null);
}
}
Bad Guy
import java.awt.Graphics;
import java.awt.Image;
public class BadGuy {
Image myImage;
int x=0,y=0;
int distanceX = 0, distanceY = 0;
boolean hasPath=false;
public BadGuy( Image i ) {
myImage=i;
x = 30;
y = 10;
}
public void reCalcPath(boolean map[][],int targx, int targy) {
// TO DO: calculate A* path to targx,targy, taking account of walls defined in map[][]
int totalDistance = 0;
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
if (!map[(x / 20) + i][(y / 20) + j]) {
if ((((targx - x) ^ 2) + ((targy - y) ^ 2)) <= totalDistance) {
totalDistance = (((targx - x) ^ 2) + ((targy - y) ^ 2));
x = ((x / 20) + i);
y = ((y / 20) + j);
return;
}
}
}
}
System.out.println("Not working");
}
// public void move(boolean map[][],int targx, int targy) {
// if (hasPath) {
// // TO DO: follow A* path, if we have one defined
// }
// else if(map[x / 20][y / 20]) {
// hasPath = false;
// }
// }
public void paint(Graphics g) {
g.drawImage(myImage, x*20, y*20, null);
}
}
Your catch block is triggered by an IndexOutOfBoundsException. One easy way to find more information about your error is to log or output the stack trace. You can do that in your code by adding e.printStackTrace() to your catch block:
catch(IndexOutOfBoundsException e){
System.out.println("GAME OVER, you exited the map");
e.printStackTrace()
System.exit(-1);
}
This should show you the line number that's causing your problem.
Looking at the code in your reCalcPath method, my educated guess is the line causing the problem is this: if (!map[(x / 20) + i][(y / 20) + j]) {. If either (x / 20) + i or (y / 20) + j are less than 0 or greater than your map dimensions, it will throw the IndexOutOfBoundsException that you are seeing. In the case where you start and x=30, y=10, i=-1, and j=-1, that evaluates to map[0][-1].
This is what's known as an edge case. You need to check for the case where your x and y are on the edges of the grid. In that situation the neighboring grid cells are outside of the map and will throw an exception.

How can I change the vector of a ball in breakout game made using Java?

I'm using Java to make a breakout game. The independent parts are functioning: the paddle, the ball, the bricks.
However, the ball hits a wall and then instead of changing it's vector, the ball just travels up the x-axis in a straight line at the edge of the JFrame window until it hits the top of the window and bounces back down from this corner.
The ball then gets stuck in an infinite back and forth line from the top left corner until it touches the paddle (back and forth) and will never break any of the other bricks.
How can I change my code to fix this problem?
import java.awt.Graphics;
public class Ball extends Sprite {
private int xVelocity = 1, yVelocity = -1;
// Constructor
public Ball() {
setWidth(Settings.BALL_WIDTH);
setHeight(Settings.BALL_HEIGHT);
resetPosition();
public void resetPosition() {
setX(Settings.INITIAL_BALL_X);
setY(Settings.INITIAL_BALL_Y);
}
public void update() {
x += yVelocity;
y += yVelocity;
// Bounce off left side of screen
if(x <= 0) {
x = 0;
setXVelocity(-1);
}
// Bounce off right side of screen
if(x >= Settings.WINDOW_WIDTH - Settings.BALL_WIDTH) {
x =Settings.WINDOW_WIDTH;
setXVelocity(-1);
}
// Bounce off top of screen
if(y <= 0) {
y = 0;
setYVelocity(1);
}
}
public void setXVelocity(int x) {
xVelocity = x;
}
public void setYVelocity(int y) {
yVelocity = y;
}
public int getXVelocity() {
return xVelocity;
}
public int getYVelocity() {
return yVelocity;
}
public void paint(Graphics g) {
g.fillOval(x, y, Settings.BALL_WIDTH, Settings.BALL_HEIGHT);
}
}
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Paint;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;
import javax.swing.Timer;
public class BreakoutPanel extends JPanel implements ActionListener, KeyListener {
static final long serialVersionUID = 2L;
private boolean gameRunning = true;
private int livesLeft = 3;
private String screenMessage = "";
private Ball ball;
private Paddle paddle;
private Brick bricks[];
public BreakoutPanel(Breakout game) {
addKeyListener(this);
setFocusable(true);
Timer timer = new Timer(5, this);
timer.start();
ball = new Ball();
paddle = new Paddle();
bricks = new Brick[Settings.TOTAL_BRICKS];
createBricks();
}
private void createBricks() {
int counter = 0;
int x_space = 0;
int y_space = 0;
for(int x = 0; x < 4; x++) {
for(int y = 0; y < 5; y++) {
bricks[counter] = new Brick((x * Settings.BRICK_WIDTH) + Settings.BRICK_HORI_PADDING + x_space, (y * Settings.BRICK_HEIGHT) + Settings.BRICK_VERT_PADDING + y_space);
counter++;
y_space++;
}
x_space++;
y_space = 0;
}
}
private void paintBricks(Graphics g) {
for(int x = 0; x < Settings.TOTAL_BRICKS; x++) {
for(int y = 0; y < Settings.TOTAL_BRICKS; y++) {
bricks[y].paint(g);
}
}
}
private void update() {
if(gameRunning) {
// TODO: Update the ball and paddle
ball.update();
paddle.update();
collisions();
repaint();
}
}
private void gameOver() {
stopGame();
screenMessage = "Game Over!";
}
private void gameWon() {
stopGame();
screenMessage = "Congratulations! You have won!";
}
private void stopGame() {
gameRunning = false;
}
private void collisions() {
// Check for loss
if(ball.y > 450) {
// Game over
livesLeft--;
if(livesLeft <= 0) {
gameOver();
return;
} else {
ball.resetPosition();
ball.setYVelocity(-1);
}
}
// Check for win
boolean bricksLeft = false;
for(int i = 0; i < bricks.length; i++) {
// Check if there are any bricks left
if(!bricks[i].isBroken()) {
// Brick was found, close loop
bricksLeft = true;
break;
}
}
if(!bricksLeft) {
gameWon();
return;
}
// Check collisions
if(ball.getRectangle().intersects(paddle.getRectangle())) {
// Simplified touching of paddle
ball.setYVelocity(-1);
}
for(int i = 0; i < bricks.length; i++) {
if (ball.getRectangle().intersects(bricks[i].getRectangle())) {
int ballLeft = (int) ball.getRectangle().getMinX();
int ballHeight = (int) ball.getRectangle().getHeight();
int ballWidth = (int) ball.getRectangle().getWidth();
int ballTop = (int) ball.getRectangle().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].isBroken()) {
if (bricks[i].getRectangle().contains(pointRight)) {
ball.setXVelocity(-1);
} else if (bricks[i].getRectangle().contains(pointLeft)) {
ball.setXVelocity(1);
}
if (bricks[i].getRectangle().contains(pointTop)) {
ball.setYVelocity(1);
} else if (bricks[i].getRectangle().contains(pointBottom)) {
ball.setYVelocity(-1);
}
bricks[i].setBroken(true);
}
}
}
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
ball.paint(g);
paddle.paint(g);
paintBricks(g);
// Draw lives left
// TODO: Draw lives left in the top left hand corner**
if(livesLeft != 0) {
String displayLives = Integer.toString(livesLeft);
g.setFont(new Font("Arial", Font.BOLD, 18));
g.drawString(displayLives, Settings.LIVES_POSITION_X, Settings.LIVES_POSITION_Y);
}
// Draw screen message*
if(screenMessage != null) {
g.setFont(new Font("Arial", Font.BOLD, 18));
int messageWidth = g.getFontMetrics().stringWidth(screenMessage);
g.drawString(screenMessage, (Settings.WINDOW_WIDTH / 2) - (messageWidth / 2),
Settings.MESSAGE_POSITION);
}
}
#Override
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
if (key == KeyEvent.VK_LEFT) {
paddle.setXVelocity(-1);
}
if (key == KeyEvent.VK_RIGHT) {
paddle.setXVelocity(1);
}
}
#Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == KeyEvent.VK_LEFT || e.getKeyCode() == KeyEvent.VK_RIGHT) {
paddle.setXVelocity(0);
}
}
#Override
public void keyTyped(KeyEvent arg0) {
}
#Override
public void actionPerformed(ActionEvent arg0) {
update();
}
}
I made a similar game in python years ago. What I did to solve this problem was allow the player to control the direction of the ball by hitting it with different parts of the paddle.
If the player hit the ball with the absolute center of the paddle, then I would just reverse the vector as if it had hit off a wall. But if the absolute edge of the paddle hit the ball, then I would increase the x velocity in the same direction of the edge that it hit. You can make the effect continuous, so if the the ball hits the paddle halfway between the edge and the center, it increases the x velocity half as much as it would have if it had hit the absolute edge.
This way the vector will continuously change and the ball will bounce off of things in a more interesting way, as well as give the player more control so they don't have to just wait until the ball eventually hits every brick in a predefined pattern.
You can use a coefficient, or more complex function if you don't want the effect of where the ball hits the paddle to effect the x velocity in such a linear manner.
You can use a similar strategy for handling collisions with the bricks. For instance, if the ball hits the corner of a brick, you probably don't want it to react as if it had hit the bottom, or the side, but have a reaction that is somewhere in between.

Call "addkeylistener" on JPanel object or JFrame object

all.
I recently got confused about how the event handling stuff works. Can someone good about it give me some hints, thank!
Here is what I understand, in order to do event handling, there are 3 steps:
(1) implement the listener (Action, Key, ...)
(2) provide an event handler (actionperformed ...)
(3) register the listener with the source (This is actually the step that I got confused)
I had see people doing addKeyListener on the JPanel object, and someone doing on JFrame object. Personally, I try both, and sometimes event can be handle, and sometimes can not be, depend on which either JPanel obj. or JFrame obj that I choose to addkeylistener.
So, in what kind of situation we can determine either JPanel or JPanel should be used, and any other object will have the similar issue?
Thank you!
Below is my practice code of trying to make a snake game. It is not done yet, but it has the issue that I described, which calling addKeyListener will work on JFrame, but fail on JPanel.
Snake.java
package com.snake;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.Random;
public class Snake implements ActionListener, KeyListener {
public static Snake snake;
public Dimension dimension;
public JFrame jFrame;
public RenderPanel renderPanel;
public ArrayList<Point> snakeParts = new ArrayList<>();
public static final int UP = 0, DOWN = 1, LEFT = 2, RIGHT = 3, SCALE = 10;
public int ticks = 0, direction = DOWN, score, tailLength;
public Point head, cherry;
public Random random;
public boolean hitEdge, putNewCherry;
public Timer timer;
public Snake() {
dimension = Toolkit.getDefaultToolkit().getScreenSize();
jFrame = new JFrame("Snake");
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setSize(500, 500);
jFrame.setLocation((dimension.width - jFrame.getWidth()) / 2, (dimension.height - jFrame.getHeight()) / 2);
jFrame.add(renderPanel = new RenderPanel());
jFrame.addKeyListener(this); // Add Keylistener (1)
jFrame.setFocusable(true);
random = new Random();
cherry = new Point(random.nextInt(jFrame.getWidth()) + 0, random.nextInt(jFrame.getHeight() + 0));
head = new Point(0, 0); // head needs to be instantiated
hitEdge = false;
putNewCherry = true;
timer = new Timer(20, this);
timer.start();
}
// ---------------------------------------------------------------------------- Control the snake by pressing "I, J, K, L"
#Override
public void keyTyped(KeyEvent e) {
// System.out.println("keyPressed="+KeyEvent.getKeyText(e.getKeyCode()));
}
#Override
public void keyPressed(KeyEvent e) {
int i = e.getKeyCode();
if (i == KeyEvent.VK_I && direction != DOWN) {
direction = UP;
System.out.println("UP");
}
if (i == KeyEvent.VK_K && direction != UP) {
direction = DOWN;
System.out.println("DOWN");
}
if (i == KeyEvent.VK_J && direction != RIGHT) {
direction = LEFT;
System.out.println("LEFT");
}
if (i == KeyEvent.VK_L && direction != LEFT) {
direction = RIGHT;
System.out.println("RIGHT");
}
}
#Override
public void keyReleased(KeyEvent e) {
}
// ---------------------------------------------------------------------------- Make the snake moving
#Override
public void actionPerformed(ActionEvent e) {
renderPanel.repaint();
ticks++;
// ---------------------------------------------------------------------------- Determine the direction
if (ticks % 10 == 0 && head != null && hitEdge != true) {
// snakeParts.add(new Point(head.x, head.y));
if (direction == UP) {
if (head.y - 1 > 0) {
// head = new Point(head.x, head.y - 1); // Option (1)
snakeParts.add(new Point(head.x, head.y--)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
if (direction == DOWN) {
if (head.y + 1 < dimension.height / SCALE) {
// head = new Point(head.x, head.y + 1); // Option (1)
snakeParts.add(new Point(head.x, head.y++)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
if (direction == LEFT) {
if (head.x - 1 > 0) {
// head = new Point(head.x - 1, head.y); // Option (1)
snakeParts.add(new Point(head.x--, head.y)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
if (direction == RIGHT) {
if (head.x + 1 < dimension.width / SCALE) {
// head = new Point(head.x + 1, head.y); // Option (1)
snakeParts.add(new Point(head.x++, head.y)); // OPtion (2), can be replaced by (1)
} else {
hitEdge = true;
}
}
// snakeParts.add(new Point(head.x, head.y)); // Option (1)
// ---------------------------------------------------------------------------- Remove the tail part each time to maintain the whole body length as the same
snakeParts.remove(0);
// Each a cherry, gain longer length, get score
if (cherry != null && head.equals(cherry)) {
score += 100;
tailLength++;
// Reset the cherry's location == put a new cherry.
cherry.setLocation(random.nextInt(jFrame.getWidth()) + 0, random.nextInt(jFrame.getHeight() + 0));
}
// ----------------------------------------------------------------------------
}
}
}
RenderPanel.java
import javax.swing.*;
import java.awt.*;
public class RenderPanel extends JPanel {
// public static int cherryX, cherryY;
// // Instantiate the RenderPanel to register the Snake as KeyListerner
// public RenderPanel(){
// addKeyListener(Snake.snake); // Add Keylistener (1) ???
// setFocusable(true);
// System.out.println("Call RenderPanel");
// }
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Paint the background
g.setColor(color.BLACK);
g.fillRect(0, 0, 500, 500);
// Pain the snake body
Snake snake = Snake.snake;
g.setColor(color.WHITE); // Assign the new color to the snake's body
for (Point snakePart : snake.snakeParts) { // Loop to paint each part of the snake body
g.fillRect(snakePart.x * snake.SCALE, snakePart.y * snake.SCALE, snake.SCALE, snake.SCALE);
}
g.fillRect(snake.head.x * snake.SCALE, snake.head.y * snake.SCALE, snake.SCALE, snake.SCALE);
g.setColor(color.RED);
g.fillRect(snake.cherry.x, snake.cherry.y, snake.SCALE, snake.SCALE);
}
}
Main.java
public class Main {
public static void main(String[] args) {
Snake.snake = new Snake();
}
}

PacMan game movement

I am creating a pacman game in Java and I have 1 problem I can't get rid of.. The problem is as follows:
I have 4 buttons in the game screen for each way: up, down, left, right. The problem is that I can not use the buttons in the same time in x position as in the y position because I always get a value of 0 ( you understand this if you see my code below )
Below you can find my class for the pacman that i think is related to the problem ( see setBesturing(int besturing) method )
package h04PacMan;
/*
* PacMan laten bewegen
*/
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class PacMan extends JPanel implements ActionListener {
private int horizontalePlaats = 250; // x location
private int verticalePlaats = 150; // y location
private int richtingEnSnelheid = +10; // speed
private final int WACHTTIJD = 500; // DELAY
int diameter;
int waarde;
public PacMan() {
// create timer and start timer
javax.swing.Timer autoKlik = new javax.swing.Timer(WACHTTIJD, this);
autoKlik.start();
}
public int getHorPlaats() {
return horizontalePlaats;
}
// current y positie
public int getVerPlaats() {
return verticalePlaats;
}
// speed and way;
public int getRichtingEnSnelheid() {
return richtingEnSnelheid;
}
// new x position
public void setHorPlaats(int nieuweHorPlaats) {
if(nieuweHorPlaats > getWidth()) {
nieuweHorPlaats = 0;
}
else if(nieuweHorPlaats < 0) {
nieuweHorPlaats = getWidth();
}
horizontalePlaats = nieuweHorPlaats;
}
// new y position
public void setVerPlaats(int nieuweVerPlaats) {
if(nieuweVerPlaats > getHeight()) {
nieuweVerPlaats = 0;
}
else if(nieuweVerPlaats < 0) {
nieuweVerPlaats = getHeight();
}
verticalePlaats = nieuweVerPlaats;
}
public void setRichtingEnSnelheid(int nieuweRichtingEnSnelheid) {
richtingEnSnelheid = nieuweRichtingEnSnelheid;
}
//movement
public void setBesturing(int besturing) {
besturing = waarde;
if(waarde == 0) {
setVerPlaats( getVerPlaats() + richtingEnSnelheid);
}
else if(waarde == 1){
setHorPlaats( getHorPlaats() + richtingEnSnelheid);
}
}
#Override
public void actionPerformed(ActionEvent e) {
setBesturing(waarde);
System.out.println(waarde);
repaint();
}
DrawPacMan pacman = new DrawPacMan();
DrawPacMan ghost1 = new DrawPacMan();
DrawPacMan ghost2 = new DrawPacMan();
public void paintComponent(Graphics g) {
super.paintComponent(g);
// pacman movement
diameter = 75;
pacman.drawPacMan(g, getHorPlaats(), getVerPlaats(), diameter, Color.yellow);
// ghosts movement
int g1x;
for(g1x = 0; g1x < 10; g1x++) {
pacman.drawGhost(g, g1x, 40, diameter, Color.red);
}
pacman.drawGhost(g, 170, 70, diameter, Color.blue);
}
}
and this is the actionListener in my gamecontrol class
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == links) {
pacman.setRichtingEnSnelheid( -10 );
pacman.setBesturing(1);
System.out.println("links");
}
else if(e.getSource() == rechts) {
pacman.setRichtingEnSnelheid( +10 );
pacman.setBesturing(1);
System.out.println("rechts");
}
else if(e.getSource() == boven) {
pacman.setRichtingEnSnelheid( -10);
pacman.setBesturing(0);
System.out.println("boven");
}
else {
pacman.setRichtingEnSnelheid( +10);
pacman.setBesturing(0);
System.out.println("beneden");
}
}
Here is your problem:
//movement
public void setBesturing(int besturing) {
besturing = waarde; <-- THIS LINE
if(waarde == 0) {
setVerPlaats( getVerPlaats() + richtingEnSnelheid);
}
else if(waarde == 1){
setHorPlaats( getHorPlaats() + richtingEnSnelheid);
}
}
You are overwriting the value of besturing with the old value waarde. It should be the other way around.
//movement
public void setBesturing(int besturing) {
waarde = besturing; <-- THIS LINE
if(waarde == 0) {
setVerPlaats( getVerPlaats() + richtingEnSnelheid);
}
else if(waarde == 1){
setHorPlaats( getHorPlaats() + richtingEnSnelheid);
}
}
I think inside the method setBesturing(int besturing) should be:
waarde = besturing;
In your setBesturing method: -
besturing = waarde;
This line never changes the value of your waarde.. It is always zero.
You should do the assignment the other way : -
this.waarde = besturing;
You'll need to keep track of whether the button is pressed or not indepentently. Also, you're model doesn't support a diagonal movement at all (I'm not sure what your nederlands names exactly mean, i can interprete snelheid=Schnelligkeit=speed and some more).
You'll need to put diagonal movement into the model (e.g. give him an x and y velocity indepent from each other)

Adding menu to Java Game

I've been working my way through Developing Games in Java by David Brackeen and have come across a problem. I am modifying the game and pulling it apart to better understand how it works. I have no idea however how to add a menu like the one that was demonstrated in chapter Chapter 3. Any guidance is appreciated.
I have been looking in the ScreenManager and the GameManager for an idea on how to do this. I know how the game gets the screen size, I just need a push on how to get a menu to display.
Here is the code:
ScreenManager.java
package com.brackeen.javagamebook.graphics;
import java.awt.*;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
The ScreenManager class manages initializing and displaying
full screen graphics modes.
*/
public class ScreenManager {
private GraphicsDevice device;
/**
Creates a new ScreenManager object.
*/
public ScreenManager() {
GraphicsEnvironment environment =
GraphicsEnvironment.getLocalGraphicsEnvironment();
device = environment.getDefaultScreenDevice();
}
/**
Returns a list of compatible display modes for the
default device on the system.
*/
public DisplayMode[] getCompatibleDisplayModes() {
return device.getDisplayModes();
}
/**
Returns the first compatible mode in a list of modes.
Returns null if no modes are compatible.
*/
public DisplayMode findFirstCompatibleMode(
DisplayMode modes[])
{
DisplayMode goodModes[] = device.getDisplayModes();
for (int i = 0; i < modes.length; i++) {
for (int j = 0; j < goodModes.length; j++) {
if (displayModesMatch(modes[i], goodModes[j])) {
return modes[i];
}
}
}
return null;
}
/**
Returns the current display mode.
*/
public DisplayMode getCurrentDisplayMode() {
return device.getDisplayMode();
}
/**
Determines if two display modes "match". Two display
modes match if they have the same resolution, bit depth,
and refresh rate. The bit depth is ignored if one of the
modes has a bit depth of DisplayMode.BIT_DEPTH_MULTI.
Likewise, the refresh rate is ignored if one of the
modes has a refresh rate of
DisplayMode.REFRESH_RATE_UNKNOWN.
*/
public boolean displayModesMatch(DisplayMode mode1,
DisplayMode mode2)
{
if (mode1.getWidth() != mode2.getWidth() ||
mode1.getHeight() != mode2.getHeight())
{
return false;
}
if (mode1.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI &&
mode2.getBitDepth() != DisplayMode.BIT_DEPTH_MULTI &&
mode1.getBitDepth() != mode2.getBitDepth())
{
return false;
}
if (mode1.getRefreshRate() !=
DisplayMode.REFRESH_RATE_UNKNOWN &&
mode2.getRefreshRate() !=
DisplayMode.REFRESH_RATE_UNKNOWN &&
mode1.getRefreshRate() != mode2.getRefreshRate())
{
return false;
}
return true;
}
/**
Enters full screen mode and changes the display mode.
If the specified display mode is null or not compatible
with this device, or if the display mode cannot be
changed on this system, the current display mode is used.
<p>
The display uses a BufferStrategy with 2 buffers.
*/
public void setFullScreen(DisplayMode displayMode) {
final JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.setIgnoreRepaint(true);
frame.setResizable(false);
device.setFullScreenWindow(frame);
if (displayMode != null &&
device.isDisplayChangeSupported())
{
try {
device.setDisplayMode(displayMode);
}
catch (IllegalArgumentException ex) { }
// fix for mac os x
frame.setSize(displayMode.getWidth(),
displayMode.getHeight());
}
// avoid potential deadlock in 1.4.1_02
try {
EventQueue.invokeAndWait(new Runnable() {
public void run() {
frame.createBufferStrategy(2);
}
});
}
catch (InterruptedException ex) {
// ignore
}
catch (InvocationTargetException ex) {
// ignore
}
}
/**
Gets the graphics context for the display. The
ScreenManager uses double buffering, so applications must
call update() to show any graphics drawn.
<p>
The application must dispose of the graphics object.
*/
public Graphics2D getGraphics() {
Window window = device.getFullScreenWindow();
if (window != null) {
BufferStrategy strategy = window.getBufferStrategy();
return (Graphics2D)strategy.getDrawGraphics();
}
else {
return null;
}
}
/**
Updates the display.
*/
public void update() {
Window window = device.getFullScreenWindow();
if (window != null) {
BufferStrategy strategy = window.getBufferStrategy();
if (!strategy.contentsLost()) {
strategy.show();
}
}
// Sync the display on some systems.
// (on Linux, this fixes event queue problems)
Toolkit.getDefaultToolkit().sync();
}
/**
Returns the window currently used in full screen mode.
Returns null if the device is not in full screen mode.
*/
public JFrame getFullScreenWindow() {
return (JFrame)device.getFullScreenWindow();
}
/**
Returns the width of the window currently used in full
screen mode. Returns 0 if the device is not in full
screen mode.
*/
public int getWidth() {
Window window = device.getFullScreenWindow();
if (window != null) {
return window.getWidth();
}
else {
return 0;
}
}
/**
Returns the height of the window currently used in full
screen mode. Returns 0 if the device is not in full
screen mode.
*/
public int getHeight() {
Window window = device.getFullScreenWindow();
if (window != null) {
return window.getHeight();
}
else {
return 0;
}
}
/**
Restores the screen's display mode.
*/
public void restoreScreen() {
Window window = device.getFullScreenWindow();
if (window != null) {
window.dispose();
}
device.setFullScreenWindow(null);
}
/**
Creates an image compatible with the current display.
*/
public BufferedImage createCompatibleImage(int w, int h,
int transparancy)
{
Window window = device.getFullScreenWindow();
if (window != null) {
GraphicsConfiguration gc =
window.getGraphicsConfiguration();
return gc.createCompatibleImage(w, h, transparancy);
}
return null;
}
}
GameManager.java
package com.brackeen.javagamebook.tilegame;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.util.Iterator;
import javax.sound.midi.Sequence;
import javax.sound.midi.Sequencer;
import javax.sound.sampled.AudioFormat;
import com.brackeen.javagamebook.graphics.*;
import com.brackeen.javagamebook.sound.*;
import com.brackeen.javagamebook.input.*;
import com.brackeen.javagamebook.test.GameCore;
import com.brackeen.javagamebook.tilegame.sprites.*;
/**
GameManager manages all parts of the game.
*/
public class GameManager extends GameCore {
public static void main(String[] args) {
new GameManager().run();
}
// uncompressed, 44100Hz, 16-bit, mono, signed, little-endian
private static final AudioFormat PLAYBACK_FORMAT =
new AudioFormat(44100, 16, 1, true, false);
private static final int DRUM_TRACK = 1;
public static final float GRAVITY = 0.002f;
private Point pointCache = new Point();
private TileMap map;
private MidiPlayer midiPlayer;
private SoundManager soundManager;
private ResourceManager resourceManager;
private Sound prizeSound;
private Sound boopSound;
private Sound jacksound;
private InputManager inputManager;
private TileMapRenderer renderer;
public Boolean panimation = false;
public Boolean playing = false;
private int points;
private GameAction moveLeft;
private GameAction moveRight;
private GameAction jump;
private GameAction exit;
private GameAction pause;
public void init() {
super.init();
// set up input manager
initInput();
// start resource manager
resourceManager = new ResourceManager(
screen.getFullScreenWindow().getGraphicsConfiguration());
// load resources
renderer = new TileMapRenderer();
renderer.setBackground(
resourceManager.loadImage("background.png"));
// load first map
map = resourceManager.loadNextMap();
// load sounds
soundManager = new SoundManager(PLAYBACK_FORMAT);
prizeSound = soundManager.getSound("sounds/prizes.wav");
boopSound = soundManager.getSound("sounds/boop2.wav");
jacksound = soundManager.getSound("sounds/jack.wav");
// start music
midiPlayer = new MidiPlayer();
Sequence sequence =
midiPlayer.getSequence("sounds/music.midi");
midiPlayer.play(sequence, true);
toggleDrumPlayback();
}
/**
Closes any resurces used by the GameManager.
*/
public void stop() {
super.stop();
midiPlayer.close();
soundManager.close();
}
public void pause() {
if(!panimation){
panimation = true;
soundManager.setPaused(true);
midiPlayer.setPaused(true);
}
else{
panimation = false;
soundManager.setPaused(false);
midiPlayer.setPaused(false);
}
}
private void initInput() {
moveLeft = new GameAction("moveLeft");
moveRight = new GameAction("moveRight");
jump = new GameAction("jump",
GameAction.DETECT_INITAL_PRESS_ONLY);
exit = new GameAction("exit",
GameAction.DETECT_INITAL_PRESS_ONLY);
pause = new GameAction("pause",
GameAction.DETECT_INITAL_PRESS_ONLY);
inputManager = new InputManager(
screen.getFullScreenWindow());
inputManager.setCursor(InputManager.INVISIBLE_CURSOR);
inputManager.mapToKey(moveLeft, KeyEvent.VK_LEFT);
inputManager.mapToKey(moveRight, KeyEvent.VK_RIGHT);
inputManager.mapToKey(jump, KeyEvent.VK_SPACE);
inputManager.mapToKey(exit, KeyEvent.VK_ESCAPE);
inputManager.mapToKey(pause, KeyEvent.VK_F1);
}
private void checkInput(long elapsedTime) {
if (exit.isPressed()) {
stop();
String spoints = Integer.toString(points);
System.out.println("Points: " + spoints);
}
if (pause.isPressed()){
pause();
}
Player player = (Player)map.getPlayer();
if (player.isAlive()) {
float velocityX = 0;
if (moveLeft.isPressed()) {
velocityX-=player.getMaxSpeed();
}
if (moveRight.isPressed()) {
velocityX+=player.getMaxSpeed();
}
if (jump.isPressed()) {
player.jump(false);
}
player.setVelocityX(velocityX);
}
}
public void draw(Graphics2D g) {
renderer.draw(g, map,
screen.getWidth(), screen.getHeight());
}
/**
Gets the current map.
*/
public TileMap getMap() {
return map;
}
/**
Turns on/off drum playback in the midi music (track 1).
*/
public void toggleDrumPlayback() {
Sequencer sequencer = midiPlayer.getSequencer();
if (sequencer != null) {
sequencer.setTrackMute(DRUM_TRACK,
!sequencer.getTrackMute(DRUM_TRACK));
}
}
/**
Gets the tile that a Sprites collides with. Only the
Sprite's X or Y should be changed, not both. Returns null
if no collision is detected.
*/
public Point getTileCollision(Sprite sprite,
float newX, float newY)
{
float fromX = Math.min(sprite.getX(), newX);
float fromY = Math.min(sprite.getY(), newY);
float toX = Math.max(sprite.getX(), newX);
float toY = Math.max(sprite.getY(), newY);
// get the tile locations
int fromTileX = TileMapRenderer.pixelsToTiles(fromX);
int fromTileY = TileMapRenderer.pixelsToTiles(fromY);
int toTileX = TileMapRenderer.pixelsToTiles(
toX + sprite.getWidth() - 1);
int toTileY = TileMapRenderer.pixelsToTiles(
toY + sprite.getHeight() - 1);
// check each tile for a collision
for (int x=fromTileX; x<=toTileX; x++) {
for (int y=fromTileY; y<=toTileY; y++) {
if (x < 0 || x >= map.getWidth() ||
map.getTile(x, y) != null)
{
// collision found, return the tile
pointCache.setLocation(x, y);
return pointCache;
}
}
}
// no collision found
return null;
}
/**
Checks if two Sprites collide with one another. Returns
false if the two Sprites are the same. Returns false if
one of the Sprites is a Creature that is not alive.
*/
public boolean isCollision(Sprite s1, Sprite s2) {
// if the Sprites are the same, return false
if (s1 == s2) {
return false;
}
// if one of the Sprites is a dead Creature, return false
if (s1 instanceof Creature && !((Creature)s1).isAlive()) {
return false;
}
if (s2 instanceof Creature && !((Creature)s2).isAlive()) {
return false;
}
// get the pixel location of the Sprites
int s1x = Math.round(s1.getX());
int s1y = Math.round(s1.getY());
int s2x = Math.round(s2.getX());
int s2y = Math.round(s2.getY());
// check if the two sprites' boundaries intersect
return (s1x < s2x + s2.getWidth() &&
s2x < s1x + s1.getWidth() &&
s1y < s2y + s2.getHeight() &&
s2y < s1y + s1.getHeight());
}
/**
Gets the Sprite that collides with the specified Sprite,
or null if no Sprite collides with the specified Sprite.
*/
public Sprite getSpriteCollision(Sprite sprite) {
// run through the list of Sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite otherSprite = (Sprite)i.next();
if (isCollision(sprite, otherSprite)) {
// collision found, return the Sprite
return otherSprite;
}
}
// no collision found
return null;
}
/**
Updates Animation, position, and velocity of all Sprites
in the current map.
*/
public void update(long elapsedTime) {
Creature player = (Creature)map.getPlayer();
// player is dead! start map over
if (player.getState() == Creature.STATE_DEAD) {
map = resourceManager.reloadMap();
return;
}
// get keyboard/mouse input
checkInput(elapsedTime);
if (!panimation) { //If game is paused, it stops the updating of the animation.
// update player
updateCreature(player, elapsedTime);
player.update(elapsedTime);
// update other sprites
Iterator i = map.getSprites();
while (i.hasNext()) {
Sprite sprite = (Sprite)i.next();
if (sprite instanceof Creature) {
Creature creature = (Creature)sprite;
if (creature.getState() == Creature.STATE_DEAD) {
i.remove();
}
else {
updateCreature(creature, elapsedTime);
}
}
// normal update
sprite.update(elapsedTime);
}
}
}
/**
Updates the creature, applying gravity for creatures that
aren't flying, and checks collisions.
*/
private void updateCreature(Creature creature,
long elapsedTime)
{
// apply gravity
if (!creature.isFlying()) {
creature.setVelocityY(creature.getVelocityY() +
GRAVITY * elapsedTime);
}
// change x
float dx = creature.getVelocityX();
float oldX = creature.getX();
float newX = oldX + dx * elapsedTime;
Point tile =
getTileCollision(creature, newX, creature.getY());
if (tile == null) {
creature.setX(newX);
}
else {
// line up with the tile boundary
if (dx > 0) {
creature.setX(
TileMapRenderer.tilesToPixels(tile.x) -
creature.getWidth());
}
else if (dx < 0) {
creature.setX(
TileMapRenderer.tilesToPixels(tile.x + 1));
}
creature.collideHorizontal();
}
if (creature instanceof Player) {
checkPlayerCollision((Player)creature, false);
}
// change y
float dy = creature.getVelocityY();
float oldY = creature.getY();
float newY = oldY + dy * elapsedTime;
tile = getTileCollision(creature, creature.getX(), newY);
if (tile == null) {
creature.setY(newY);
}
else {
// line up with the tile boundary
if (dy > 0) {
creature.setY(
TileMapRenderer.tilesToPixels(tile.y) -
creature.getHeight());
}
else if (dy < 0) {
creature.setY(
TileMapRenderer.tilesToPixels(tile.y + 1));
}
creature.collideVertical();
}
if (creature instanceof Player) {
boolean canKill = (oldY < creature.getY());
checkPlayerCollision((Player)creature, canKill);
}
}
/**
Checks for Player collision with other Sprites. If
canKill is true, collisions with Creatures will kill
them.
*/
public void checkPlayerCollision(Player player,
boolean canKill)
{
if (!player.isAlive()) {
return;
}
// check for player collision with other sprites
Sprite collisionSprite = getSpriteCollision(player);
if (collisionSprite instanceof PowerUp) {
acquirePowerUp((PowerUp)collisionSprite);
}
else if (collisionSprite instanceof Creature) {
Creature badguy = (Creature)collisionSprite;
if (canKill) {
// kill the badguy and make player bounce
soundManager.play(boopSound);
badguy.setState(Creature.STATE_DYING);
player.setY(badguy.getY() - player.getHeight());
player.jump(true);
}
else {
// player dies!
player.setState(Creature.STATE_DYING);
points = 0;
}
}
}
/**
Gives the player the speicifed power up and removes it
from the map.
*/
public void acquirePowerUp(PowerUp powerUp) {
// remove it from the map
map.removeSprite(powerUp);
Player player = (Player)map.getPlayer();
if (powerUp instanceof PowerUp.Star) {
// do something here, like give the player points
soundManager.play(prizeSound);
points = points + 5;
}
else if (powerUp instanceof PowerUp.Music) {
// change the music
player.setMaxSpeed();
if (! playing){
soundManager.play(jacksound);
playing = true;
}
else
{
//Do nothing
}
toggleDrumPlayback();
}
else if (powerUp instanceof PowerUp.Goal) {
// advance to next map
soundManager.play(prizeSound,
new EchoFilter(2000, .7f), false);
map = resourceManager.loadNextMap();
}
}
}
The book has an example menu in the chapter.
MenuTest.java
package com.brackeen.javagamebook.tilegame;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import com.brackeen.javagamebook.graphics.*;
import com.brackeen.javagamebook.sound.*;
import com.brackeen.javagamebook.input.*;
import com.brackeen.javagamebook.test.GameCore;
import com.brackeen.javagamebook.tilegame.sprites.*;
/**
Extends the InputManagerTest demo and adds Swing buttons
for pause, config and quit.
*/
public class Menu extends InputManager
implements ActionListener
{
public static void main(String[] args) {
new Menu().run();
}
protected GameAction configAction;
private JButton playButton;
private JButton configButton;
private JButton quitButton;
private JButton pauseButton;
private JPanel playButtonSpace;
public void init() {
super.init();
// make sure Swing components don't paint themselves
NullRepaintManager.install();
// create an addtional GameAction for "config"
configAction = new GameAction("config");
// create buttons
quitButton = createButton("quit", "Quit");
playButton = createButton("play", "Continue");
pauseButton = createButton("pause", "Pause");
configButton = createButton("config", "Change Settings");
// create the space where the play/pause buttons go.
playButtonSpace = new JPanel();
playButtonSpace.setOpaque(false);
playButtonSpace.add(pauseButton);
JFrame frame = super.screen.getFullScreenWindow();
Container contentPane = frame.getContentPane();
// make sure the content pane is transparent
if (contentPane instanceof JComponent) {
((JComponent)contentPane).setOpaque(false);
}
// add components to the screen's content pane
contentPane.setLayout(new FlowLayout(FlowLayout.LEFT));
contentPane.add(playButtonSpace);
contentPane.add(configButton);
contentPane.add(quitButton);
// explicitly layout components (needed on some systems)
frame.validate();
}
/**
Extends InputManagerTest's functionality to draw all
Swing components.
*/
public void draw(Graphics2D g) {
super.draw(g);
JFrame frame = super.screen.getFullScreenWindow();
// the layered pane contains things like popups (tooltips,
// popup menus) and the content pane.
frame.getLayeredPane().paintComponents(g);
}
/**
Changes the pause/play button whenever the pause state
changes.
*/
public void setPaused(boolean p) {
super.setPaused(p);
playButtonSpace.removeAll();
if (isPaused()) {
playButtonSpace.add(playButton);
}
else {
playButtonSpace.add(pauseButton);
}
}
/**
Called by the AWT event dispatch thread when a button is
pressed.
*/
public void actionPerformed(ActionEvent e) {
Object src = e.getSource();
if (src == quitButton) {
// fire the "exit" gameAction
super.exit.tap();
}
else if (src == configButton) {
// doesn't do anything (for now)
configAction.tap();
}
else if (src == playButton || src == pauseButton) {
// fire the "pause" gameAction
super.pause.tap();
}
}
/**
Creates a Swing JButton. The image used for the button is
located at "../images/menu/" + name + ".png". The image is
modified to create a "default" look (translucent) and a
"pressed" look (moved down and to the right).
<p>The button doesn't use Swing's look-and-feel and
instead just uses the image.
*/
public JButton createButton(String name, String toolTip) {
// load the image
String imagePath = "../images/menu/" + name + ".png";
ImageIcon iconRollover = new ImageIcon(imagePath);
int w = iconRollover.getIconWidth();
int h = iconRollover.getIconHeight();
// get the cursor for this button
Cursor cursor =
Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
// make translucent default image
Image image = screen.createCompatibleImage(w, h,
Transparency.TRANSLUCENT);
Graphics2D g = (Graphics2D)image.getGraphics();
Composite alpha = AlphaComposite.getInstance(
AlphaComposite.SRC_OVER, .5f);
g.setComposite(alpha);
g.drawImage(iconRollover.getImage(), 0, 0, null);
g.dispose();
ImageIcon iconDefault = new ImageIcon(image);
// make a pressed iamge
image = screen.createCompatibleImage(w, h,
Transparency.TRANSLUCENT);
g = (Graphics2D)image.getGraphics();
g.drawImage(iconRollover.getImage(), 2, 2, null);
g.dispose();
ImageIcon iconPressed = new ImageIcon(image);
// create the button
JButton button = new JButton();
button.addActionListener(this);
button.setIgnoreRepaint(true);
button.setFocusable(false);
button.setToolTipText(toolTip);
button.setBorder(null);
button.setContentAreaFilled(false);
button.setCursor(cursor);
button.setIcon(iconDefault);
button.setRolloverIcon(iconRollover);
button.setPressedIcon(iconPressed);
return button;
}
}

Categories

Resources