A* pathfinding game system exit issue - java

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.

Related

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.

Space Invaders Type Game, Missiles won't Show Up

As the title says, my missiles aren't showing up. I'm not sure if it's an input error, or what. Here's what the assignment says:
BlockquotePart 5: Shooting
The patrol ship will shoot a missile when the up arrow key is pushed.
Make class variables patrolMissileX and patrolMissileY. Initialize
patrolMissileY to 0. Make a contant PATROL_MISSILE_LENGTH initialized
to 10. Write a method: public static void
movePatrolMissileAndDraw(Graphics g); that moves the missile and draws
it similar to moveEnemyShipAndDraw: Do not draw anything if
patrolMissileY is 0. Otherwise, the missile as a vertical line with
the stated length and x-position. patrolMissileY is the top of the
line. Draw the missile in white, move the missile up 5 pixels, and
draw it again in black. If the patrolMissileY is 0 or negative, do not
draw the missile in black, but set patrolMissileY to 0.
Call this method before the sleep in the loop. When the up arrow key
is pushed and patrolMissileY is 0, set patrolMissileX to be the center
of the patrol ship and set the top of the missile so that its bottom
is one pixel above the top of the patrol ship (PATROL_Y). You should
only be able to fire one missile at a time and the up arrow should not
do anything if a missile is still displayed.
Also, since I keep coming here for every part, any tips for the final part would be appreciated:
Part 6: Detecting a hit
Make a boolean class variable, hit, initialized to false; Write the
method: public static boolean detectHit(); that returns true if the
current missile has hit the enemy ship and false otherwise. There is a
hit if the top of the missile is inside the enemy ship. For this to
happen two thing must be true: the x value of the top of the missile
must be between the left and right sides of the enemy the y value of
the top of the missile must be between the top and bottom of the
enemy. At the end of the loop in startGame, set hit to true if
detectHit() returns true. Modify moveEnemyShipAndDraw so that if hit
is true, the enemy ship is drawn in black and does not move. In this
case, display the message: Enemy ship hit! in green on a line below
the patrol ship. If the enemy ship moves off the screen or time runs
out, Display the message: Enemy ship got away! in red on a line below
the patrol ship.
Here's the code:
import java.awt.*;
public class Project2 {
public static final int PATROL_Y = 250;
public static final int PATROL_SIZE = 20;
public static int patrolX = 270;
public static final int ENEMY_Y = 20;
public static final int ENEMY_SIZE = 30;
public static int enemyX = 0;
public static final int RIGHT_ARROW = 39;
public static final int LEFT_ARROW = 37;
public static final int UP_ARROW = 38;
public static int patrolMissileX = 0;
public static int patrolMissileY = 0;
public static final int PATROL_MISSILE_LENGTH = 10;
//exe starts here
public static void main(String[] args) {
DrawingPanel panel = new DrawingPanel(300, 300);
Graphics g = panel.getGraphics( );
g.drawString("Project 2 by Garrett Griffin", 10, 15);
startGame(panel, g);
}
//Creates a patrol ship at x = patrolX,y=PATROL_Y, with side PATROL_SIZE in the given color
public static void drawPatrol(Graphics g, Color c){
g.setColor(Color.GREEN);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
}
//moveEnemyShipAndDraw: draws the enemy ship first in white, then increment enemyX by 1, then draws the ship in red again.
public static void moveEnemyShipAndDraw(Graphics g) {
g.setColor(Color.WHITE);
g.fillRect(enemyX, ENEMY_Y, ENEMY_SIZE, ENEMY_SIZE);
enemyX+=1;
g.setColor(Color.RED);
g.fillRect(enemyX, ENEMY_Y, ENEMY_SIZE, ENEMY_SIZE);
if(enemyX>300) {
g.setColor(Color.RED);
g.drawString("The enemy ship got away!", 10, 290);
}
}
//Handles user input: RIGHT_ARROW and LEFT_ARROW moves patrolship by 3 pixels left or right
public static void handleKeys(DrawingPanel panel, Graphics g) {
//Set panel.getKeyCode(); to a variable. Any variable.
int i = panel.getKeyCode();
//keep from going out of bounds on the right side
if (RIGHT_ARROW==i && patrolX>=280) {
g.setColor(Color.WHITE);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
patrolX-=3;
g.setColor(Color.GREEN);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
} else if (LEFT_ARROW==i && patrolX<=0) {
g.setColor(Color.WHITE);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
patrolX+=3;
g.setColor(Color.GREEN);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
//if RA, move right 3 pixels
} else if (RIGHT_ARROW==i) {
g.setColor(Color.WHITE);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
patrolX+=3;
g.setColor(Color.GREEN);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
//if LA, move left 3 pixels
} else if(LEFT_ARROW==i) {
g.setColor(Color.WHITE);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
patrolX-=3;
g.setColor(Color.GREEN);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
//if zero, do nothing
} else if(i==0) {
g.setColor(Color.GREEN);
g.fillRect(patrolX, PATROL_Y, PATROL_SIZE, PATROL_SIZE);
}
}
//Gets uparrow input from user to create missile. Do not draw anything if patrolMissileY is 0.
public static void movePatrolMissileAndDraw(DrawingPanel panel, Graphics g) {
int i = panel.getKeyCode();
if(UP_ARROW==i && patrolMissileY>0){
patrolMissileX=patrolX;
patrolMissileY=PATROL_Y;
g.setColor(Color.WHITE);
g.drawLine(patrolMissileX, patrolMissileY, PATROL_MISSILE_LENGTH, PATROL_MISSILE_LENGTH);
patrolMissileY+=5;
g.setColor(Color.BLACK);
g.drawLine(patrolMissileX, patrolMissileY, PATROL_MISSILE_LENGTH, PATROL_MISSILE_LENGTH);
}
}
public static void startGame(DrawingPanel panel, Graphics g) {
int x = 0;
int y = 270;
int deltaX = 1;
int deltaY = -3;
drawPatrol(g, Color.green);
for (int time = 0; time <= 1000; time++) {
moveEnemyShipAndDraw(g);
handleKeys(panel, g);
movePatrolMissileAndDraw(panel, g);
panel.sleep(50);
}
}
}
DrawingPanel class I'm using:
/*
Stuart Reges and Marty Stepp
February 24, 2007
Changes by Tom Bylander in 2010 (no anti-alias, repaint on sleep)
Changes by Tom Bylander in 2012 (track mouse clicks and movement)
Changes by Tom Bylander in 2013 (fix bug in tracking mouse clicks)
Changes by S. Robbins in 2014 (getters for width and height)
Changes by S. Robbins in 2014 (addKeyListener added)
Changes by S. Robbins in 2014 (catch exception on default close so that it works in an applet)
Changes by S. Robbins in 2015 (buffer key events)
Changes by S. Robbins in 2015 (show mouse status by default is off)
The DrawingPanel class provides a simple interface for drawing persistent
images using a Graphics object. An internal BufferedImage object is used
to keep track of what has been drawn. A client of the class simply
constructs a DrawingPanel of a particular size and then draws on it with
the Graphics object, setting the background color if they so choose.
To ensure that the image is always displayed, a timer calls repaint at
regular intervals.
*/
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import javax.swing.*;
import javax.swing.event.*;
import java.util.ArrayList;
public class DrawingPanel implements ActionListener {
private static final String versionMessage =
"Drawing Panel version 1.1, January 25, 2015";
private static final int DELAY = 100; // delay between repaints in millis
private static final boolean PRETTY = false; // true to anti-alias
private static boolean showStatus = false;
private static final int MAX_KEY_BUF_SIZE = 10;
private int width, height; // dimensions of window frame
private JFrame frame; // overall window frame
private JPanel panel; // overall drawing surface
private BufferedImage image; // remembers drawing commands
private Graphics2D g2; // graphics context for painting
private JLabel statusBar; // status bar showing mouse position
private volatile MouseEvent click; // stores the last mouse click
private volatile boolean pressed; // true if the mouse is pressed
private volatile MouseEvent move; // stores the position of the mouse
private ArrayList<KeyInfo> keys;
// construct a drawing panel of given width and height enclosed in a window
public DrawingPanel(int width, int height) {
this.width = width;
this.height = height;
keys = new ArrayList<KeyInfo>();
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
statusBar = new JLabel(" ");
statusBar.setBorder(BorderFactory.createLineBorder(Color.BLACK));
statusBar.setText(versionMessage);
panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
panel.setBackground(Color.WHITE);
panel.setPreferredSize(new Dimension(width, height));
panel.add(new JLabel(new ImageIcon(image)));
click = null;
move = null;
pressed = false;
// listen to mouse movement
MouseInputAdapter listener = new MouseInputAdapter() {
public void mouseMoved(MouseEvent e) {
pressed = false;
move = e;
if (showStatus)
statusBar.setText("moved (" + e.getX() + ", " + e.getY() + ")");
}
public void mousePressed(MouseEvent e) {
pressed = true;
move = e;
if (showStatus)
statusBar.setText("pressed (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseDragged(MouseEvent e) {
pressed = true;
move = e;
if (showStatus)
statusBar.setText("dragged (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseReleased(MouseEvent e) {
click = e;
pressed = false;
if (showStatus)
statusBar.setText("released (" + e.getX() + ", " + e.getY() + ")");
}
public void mouseEntered(MouseEvent e) {
// System.out.println("mouse entered");
panel.requestFocus();
}
};
panel.addMouseListener(listener);
panel.addMouseMotionListener(listener);
new DrawingPanelKeyListener();
g2 = (Graphics2D)image.getGraphics();
g2.setColor(Color.BLACK);
if (PRETTY) {
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setStroke(new BasicStroke(1.1f));
}
frame = new JFrame("Drawing Panel");
frame.setResizable(false);
try {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // so that this works in an applet
} catch (Exception e) {}
frame.getContentPane().add(panel);
frame.getContentPane().add(statusBar, "South");
frame.pack();
frame.setVisible(true);
toFront();
frame.requestFocus();
// repaint timer so that the screen will update
new Timer(DELAY, this).start();
}
public void showMouseStatus(boolean f) {
showStatus = f;
}
public void addKeyListener(KeyListener listener) {
panel.addKeyListener(listener);
panel.requestFocus();
}
// used for an internal timer that keeps repainting
public void actionPerformed(ActionEvent e) {
panel.repaint();
}
// obtain the Graphics object to draw on the panel
public Graphics2D getGraphics() {
return g2;
}
// set the background color of the drawing panel
public void setBackground(Color c) {
panel.setBackground(c);
}
// show or hide the drawing panel on the screen
public void setVisible(boolean visible) {
frame.setVisible(visible);
}
// makes the program pause for the given amount of time,
// allowing for animation
public void sleep(int millis) {
panel.repaint();
try {
Thread.sleep(millis);
} catch (InterruptedException e) {}
}
// close the drawing panel
public void close() {
frame.dispose();
}
// makes drawing panel become the frontmost window on the screen
public void toFront() {
frame.toFront();
}
// return panel width
public int getWidth() {
return width;
}
// return panel height
public int getHeight() {
return height;
}
// return the X position of the mouse or -1
public int getMouseX() {
if (move == null) {
return -1;
} else {
return move.getX();
}
}
// return the Y position of the mouse or -1
public int getMouseY() {
if (move == null) {
return -1;
} else {
return move.getY();
}
}
// return the X position of the last click or -1
public int getClickX() {
if (click == null) {
return -1;
} else {
return click.getX();
}
}
// return the Y position of the last click or -1
public int getClickY() {
if (click == null) {
return -1;
} else {
return click.getY();
}
}
// return true if a mouse button is pressed
public boolean mousePressed() {
return pressed;
}
public synchronized int getKeyCode() {
if (keys.size() == 0)
return 0;
return keys.remove(0).keyCode;
}
public synchronized char getKeyChar() {
if (keys.size() == 0)
return 0;
return keys.remove(0).keyChar;
}
public synchronized int getKeysSize() {
return keys.size();
}
private synchronized void insertKeyData(char c, int code) {
keys.add(new KeyInfo(c,code));
if (keys.size() > MAX_KEY_BUF_SIZE) {
keys.remove(0);
// System.out.println("Dropped key");
}
}
private class KeyInfo {
public int keyCode;
public char keyChar;
public KeyInfo(char keyChar, int keyCode) {
this.keyCode = keyCode;
this.keyChar = keyChar;
}
}
private class DrawingPanelKeyListener implements KeyListener {
int repeatCount = 0;
public DrawingPanelKeyListener() {
panel.addKeyListener(this);
panel.requestFocus();
}
public void keyPressed(KeyEvent event) {
// System.out.println("key pressed");
repeatCount++;
if ((repeatCount == 1) || (getKeysSize() < 2))
insertKeyData(event.getKeyChar(),event.getKeyCode());
}
public void keyTyped(KeyEvent event) {
}
public void keyReleased(KeyEvent event) {
repeatCount = 0;
}
}
}
Thanks for all the help friends. Y'all are invaluable.
originally you set
public static int patrolMissileY = 0;
but in
public static void movePatrolMissileAndDraw(DrawingPanel panel, Graphics g)
you do
if(UP_ARROW==i && patrolMissileY>0){
it is never going to enter here.

Detect Collision in Simple Space Invaders

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

How to get the color of a pixel

In my code below....i wish to add a yellow bar at the bottom if upon firing a bullet, the bullet reaches the moving bar at the top(which is a trail of alternative yellow and cyan boxes) and touches it at a yellow box.For that what I am planning is to first detect the color of the pixel where the bullet touches the moving bar and then add yellow bar below if the pixel color was yellow............Here is my code:
//
import java.awt.*;
import java.applet.Applet;
import java.awt.event.*;
public class abyss extends Applet implements Runnable,KeyListener{
int lim=446,l,src,i=-40,n,c,ct=450,cl=225,y,f,bl,bw,fr,mud=0;
Thread v=null;
public void init() {
setBackground(Color.black);
addKeyListener(this);
}
public void start() {
v=new Thread(this);
v.start();
}
public void run() {
try {
int trainDelay = 0;
while (true) {
if(ct<=200)
{repaint();
}
if (y == 1) {
if (f<=41) {
bl = cl + 25;
bw = 10;
f = lim;
}
if (f > 41) {
repaint(bl, f, bw, bw + 1);
if (--f<=41) {
if(l%80==0)
{mud=1;
ct=ct-20;
System.out.println("decreased");
lim=lim-20;
repaint();}
else if(l%80!=0 && (ct+20<=420))
{ct=ct+20;
lim=lim+20;
}
y = 0;
bw = 0;
}
}
}
if (trainDelay <= 0) {
repaint();
i = i + 40;
c = 1;
n = i / 40;
trainDelay = 200;
}
Thread.sleep(5);
trainDelay--;
}
} catch (Exception e) {
}
}
public void paint(Graphics g) {
if(ct>=200){
if(mud==1)
{g.setColor(Color.orange);
g.fill3DRect(0,ct+20,500,450-ct,true);}
g.setColor(Color.darkGray);
g.fill3DRect(0,200,30,300,true);
g.fill3DRect(470,200,30,300,true);
g.fill3DRect(0,470,500,30,true);
g.setColor(Color.blue);
g.fill3DRect(cl,ct,50,20,true);
setBackground(Color.black);
for(int j=n-1;j>=0;j--)
{ l=j*40;
if((c%2)==0)
{g.setColor(Color.cyan);
g.fill3DRect(l,0,50,40,true);}
else
{g.setColor(Color.orange);
g.fill3DRect(l,0,50,40,true);}
c++;
}
}
{g.setColor(Color.yellow);
g.fillOval(bl,f,bw,bw);
if(ct<=200)
{setBackground(Color.red);
g.setColor(Color.yellow);
g.drawString("You win!!",215,210);
}
} }
public void keyPressed(KeyEvent e) {
if(e.getKeyCode()==KeyEvent.VK_LEFT && cl>=38){
cl=cl-10;}
if(e.getKeyCode()==KeyEvent.VK_RIGHT && cl<=412){
cl=cl+10;}
if(e.getKeyCode()==KeyEvent.VK_UP){
y=1;}
}
public void keyReleased(KeyEvent e) {}
public void keyTyped(KeyEvent e) {}
public void stop() {
try{wait();}
catch(Exception e) {}
}
public void destroy() {}
}
Please tell me how to detect the color.........can getColor() be used??
It looks like you are off to a good start.
I would recommend that you have your cyan and yellow boxes be objects with a color and location attributes.
Create a getColor method for your box objects, and create a getLocation method for your box objects and bullet object.
when bullet.getLocation = box.getLocation
then box.getColor
Take a look at this Java/Processing App that sets the color of a circle when clicked on. It uses principles similar to what I just described.
https://sourceforge.net/projects/all-spark-cube/
https://github.com/spudstud/All-Spark-Cube/blob/master/Sandbox/Panel_2d/LedObject.pde

method repaint() not repainting, ball gravity animation

The problem is that this ball after it is dragged and exited click, it is supposed to repaint according to the new y component given. This is calculated from the gravity final and added to the velocity which is added to the existing y component in a loop.
I have debugged many times and I just cant hit it on the head.
Its supposed to..
move to where you drag it >>> when you let go it is supposed to fall until it hits the ground.
Thank you ahead of time.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DragBallPanel extends JPanel implements MouseListener, MouseMotionListener
{
private static final int BALL_DIAMETER = 40;
private int screen_size_x = 300;
private int screen_size_y = 300;
private int ground_lvl = screen_size_y - 15;
private int _ballX = ground_lvl/2;
private int _ballY = ground_lvl - BALL_DIAMETER;
private final double GRAVITY = -9.8;
private double velocity;
private static final double TERM_VEL = -100;
private int _dragFromX = 0;
private int _dragFromY = 0;
private boolean _canDrag = false;
public DragBallPanel() throws InterruptedException
{
setPreferredSize(new Dimension(screen_size_x, screen_size_y));
setBackground(Color.darkGray);
setForeground(Color.darkGray);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g); // Required for background.
g.setColor (Color.green);
g.fillRect (0, 280, 400, 50 );
g.setColor (Color.black);
g.fillOval(_ballX, _ballY, BALL_DIAMETER, BALL_DIAMETER);
}
public void mousePressed(MouseEvent e)
{
int x = e.getX();
int y = e.getY();
if (x >= _ballX && x <= (_ballX + BALL_DIAMETER)
&& y >= _ballY && y <= (_ballY + BALL_DIAMETER))\
{
_canDrag = true;
_dragFromX = x - _ballX;
_dragFromY = y - _ballY;
} else
{
_canDrag = false;
}
}
//===== mouseDragged ======
/** Set x,y to mouse position and repaint. */
public void mouseDragged(MouseEvent e)
{
if (_canDrag)
{ // True only if button was pressed inside ball.
//--- Ball pos from mouse and original click displacement
_ballX = e.getX() - _dragFromX;
_ballY = e.getY() - _dragFromY;
//--- Don't move the ball off the screen sides
_ballX = Math.max(_ballX, 0);
_ballX = Math.min(_ballX, getWidth() - BALL_DIAMETER);
//--- Don't move the ball off top or bottom
_ballY = Math.max(_ballY, 0);
_ballY = Math.min(_ballY, getHeight() - BALL_DIAMETER);
this.repaint();
}
}
public void mouseExited(MouseEvent e)
{
while(_ballY < ground_lvl)
{
simulateGravity();
}
}
public void simulateGravity()
{
if(_canDrag)
{
try{
velocity = velocity + GRAVITY;
if (velocity < TERM_VEL)
{
velocity = TERM_VEL;
}
if (_ballY >= ground_lvl - BALL_DIAMETER)
{
velocity = velocity/4;
}
_ballY += velocity;
Thread.sleep(400);
this.repaint();//**problem occurs here**
}catch(InterruptedException ie)
{
}
}
}
public void mouseMoved (MouseEvent e){}
public void mouseEntered (MouseEvent e){}
public void mouseClicked (MouseEvent e){}
public void mouseReleased(MouseEvent e){}
}
main() class
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class DragDemo extends JApplet
{
public static void main(String[] args) throws InterruptedException
{
JFrame window = new JFrame();
window.setTitle("Drag Demo");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//window.add(new DragBallPanel());
window.setContentPane(new DragBallPanel());
window.setResizable(false);
window.pack();
window.show();
}
public DragDemo() throws InterruptedException
{
new DragBallPanel();
}
}
This SSCCE begins to show the problems in the code.
Compile the code.
Run it.
Drag the ball upwards.
Release the ball.
Remove the mouse from the drawing area, to see..
The ball fall upwards!
You seem to have gotten the Y values upside down. They start at top of screen, and go downwards. Also, the code was blocking the EDT in an infinite loop. To solve that, run the animation using a Swing Timer.
Please read the document on the SSCCE & ask if there is anything in it you do not understand. I am well placed to explain. :)
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DragBallPanel extends JPanel implements MouseListener, MouseMotionListener
{
private static final int BALL_DIAMETER = 40; // Diameter of ball
private int screen_size_x = 300;
private int screen_size_y = 300;
private int ground_lvl = screen_size_y - 15;
private int _ballX = ground_lvl/2;
private int _ballY = ground_lvl - BALL_DIAMETER;
private final double GRAVITY = -9.8;
private double velocity;
private static final double TERM_VEL = 100;
private int _dragFromX = 0; // pressed this far inside ball's
private int _dragFromY = 0; // bounding box.
/** true means mouse was pressed in ball and still in panel.*/
private boolean _canDrag = false;
public DragBallPanel()
{
setPreferredSize(new Dimension(screen_size_x, screen_size_y));
setBackground(Color.darkGray);
setForeground(Color.darkGray);
this.addMouseListener(this);
this.addMouseMotionListener(this);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g); // Required for background.
g.setColor (Color.green);
g.fillRect (0, 280, 400, 50 );
g.setColor (Color.black);
g.fillOval(_ballX, _ballY, BALL_DIAMETER, BALL_DIAMETER);
}
public void mousePressed(MouseEvent e)
{
int x = e.getX(); // Save the x coord of the click
int y = e.getY(); // Save the y coord of the click
if (x >= _ballX && x <= (_ballX + BALL_DIAMETER)
&& y >= _ballY && y <= (_ballY + BALL_DIAMETER)) {
_canDrag = true;
_dragFromX = x - _ballX; // how far from left
_dragFromY = y - _ballY; // how far from top
} else {
_canDrag = false;
}
}
//========= mouseDragged =================
/** Set x,y to mouse position and repaint. */
public void mouseDragged(MouseEvent e)
{
if (_canDrag) { // True only if button was pressed inside ball.
//--- Ball pos from mouse and original click displacement
_ballX = e.getX() - _dragFromX;
_ballY = e.getY() - _dragFromY;
//--- Don't move the ball off the screen sides
_ballX = Math.max(_ballX, 0);
_ballX = Math.min(_ballX, getWidth() - BALL_DIAMETER);
//--- Don't move the ball off top or bottom
_ballY = Math.max(_ballY, 0);
_ballY = Math.min(_ballY, getHeight() - BALL_DIAMETER);
this.repaint(); // Repaint because position changed.
}
}
//====================================================== method mouseExited
/** Turn off dragging if mouse exits panel. */
public void mouseExited(MouseEvent e)
{
System.out.println("Exited: " + e);
//_canDrag = false;
runGravity();
/* while(_ballY < ground_lvl)
{
simulateGravity();
}*/
}
Timer timer;
ActionListener animate;
public void runGravity() {
if (animate==null) {
animate = new ActionListener() {
public void actionPerformed(ActionEvent ae) {
System.out.println("Ground: " + (_ballY-ground_lvl));
if (_ballY > ground_lvl) {
timer.stop();
} else {
simulateGravity();
}
}
};
timer = new Timer(100,animate);
}
timer.start();
}
public void simulateGravity()
{
System.out.println("_canDrag: " + _canDrag);
if(_canDrag)
{
velocity = velocity + GRAVITY;
if (velocity > TERM_VEL)
{
velocity = TERM_VEL;
}
if (_ballY >= ground_lvl - BALL_DIAMETER)
{
//We have hit the "ground", so bounce back up. Reverse
//the speed and divide by 4 to make it slower on bouncing.
//Just change 4 to 2 or something to make it faster.
velocity = velocity/4;
}
_ballY += velocity;
//this.revalidate();
this.repaint();
}
}
public void mouseMoved (MouseEvent e){}
public void mouseEntered (MouseEvent e){}
public void mouseClicked (MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
DragBallPanel dbp = new DragBallPanel();
JOptionPane.showMessageDialog(null, dbp);
}
});
}
}
Try updateUI() instead of repaint().
If there is no effect remove the component and add it again.

Categories

Resources