/** * @(#)pongX.java * * * @author: Michael Cecconet * @version 2.00 2007/5/16 * @ A lot of unecessary data strucutre coding as I planned to upgrade Pong into a themed version with * @ maps that dynamically change to add a new element to pong. Say, gravitaitional fields on the map anyone? * @ Stopped working on advanced collision detection as there was too many errors. It doesn't help either when * @ java graphics does not use the Cartesian Plane, or displays vectors that are always inconsistent to their angle. * @ Advanced linear collision was a let down. *///Collision Detection needs a lot of work :(import java.applet.*;import java.awt.*;import java.awt.event.*;import java.util.Random;//import java.Math.*;public class pongX extends Applet implements Runnable, KeyListener{ //Global Declarations private Image dbImage; private Graphics dbg; private int score1, score2, WIDTH, HEIGHT; private ball[] ballArray = new ball [1];// Handle multiple ball objects, even if only 1 is used. private paddle[] player = new paddle [2];// Create two paddles for two players. private line[] walls = new line[2];//Create the top and bottom wall. public String message =""; public String collision =""; //Utility Methods //Distance method for later usage public int distance(int pointX1, int pointY1, int pointX2,int pointY2){ int x, y; x = pointX2 - pointX1; y = pointY2 - pointY1; double temp = Math.sqrt( x*x + y*y ); return (int)temp; } //Define winning conditions. public boolean victory(int pointCap){ if (score1 >= pointCap){ message = "Player 1 has won the game."; return true; }else if (score2 >= pointCap){ message = "Player 2 has won the game."; return true; }else{ return false; } } //Linear Collision Detection public void advancedCollision(){ for (int i = 0; i < ballArray.length; i++){ for (int j = 0; j < walls.length; j++){//Collision detection for walls if (ballArray[i].collide( walls[j].x1, walls[j].y1, walls[j].x2,walls[j].y2, walls[j].angle, -(j+1), false) == true){ break; } } for (int j = 0; j < player.length; j++){//Collision detection for paddles if (ballArray[i].collide( player[j].x, player[j].y - player[j].size, player[j].x, player[j].y + player[j].size, 270, j+1, true) == true){ break; } } ballArray[i].move(); ballArray[i].score(); } } //Area Collision Detection public void simpleCollision(){ for (int i = 0; i < ballArray.length; i++){ //Walls are only used for advanced collision detection ballArray[i].bounce(0, WIDTH, 0, -1, false);//The school of anything goes, when im at the end of my patience. ballArray[i].bounce(0, WIDTH, HEIGHT, -2, true); for (int j = 0; j < player.length; j++){//Collision detection for paddles ballArray[i].check( player[j].x-5, player[j].y - player[j].size, player[j].x, player[j].y + player[j].size, j+1); } ballArray[i].translate(); ballArray[i].score(); } } //Ball Subclass public class ball { private int x,y,size,lastWallHit; private double angle, speed; private double deltaX, deltaY; private double vx, vy; //Ball Reset Method (true will reset the ball position to the center.) public void reset(boolean setCenter){ Random generator = new Random(); do{//Reset for Advanced angle = generator.nextInt(359); speed = generator.nextInt(10); } while(speed == 0 && angle % 90 != 0); angle += 1; do{//Reset for Basic vx = (generator.nextInt(100)- 50)/10; vy = (generator.nextInt(100)- 50)/10; } while(vx == 0 && vy == 0); if (setCenter == true){ x = WIDTH/2; y = HEIGHT/2; } collision = ""; lastWallHit = 0; } //Ball Constructor Method public ball(int setX, int setY, int setSize){ x = setX; y = setY; size = setSize; reset(false); } //Basic Wall Handling public void bounce( int x1, int x2, int yIn, int wallName, boolean annoyed){ Random generator = new Random(); int variance = 0; if (wallName != lastWallHit){ for (int i = 0; i < x2-x1 ; i++ ){// Strange error, top and bottom bounces need to be seperated to work properly if (distance(x,y,i,yIn) <= size + vy && annoyed == true){ collision = "HIT THE WALL! "+ wallName; variance = (generator.nextInt(20)-10)/10; vx = (vx + variance); variance = (generator.nextInt(20)-10)/10; vy = (vy + variance)* -1; lastWallHit = wallName; }else if (distance(x,y,i,yIn) <= size - vy && annoyed == false ){ collision = "HIT THE WALL! "+ wallName; variance = (generator.nextInt(20)-10)/10; vx = (vx + variance); variance = (generator.nextInt(20)-10)/10; vy = (vy + variance)* -1; lastWallHit = wallName; } } } } //Basic Collision Handling public void check(int getX1, int getY1, int getX2, int getY2, int wallName){ int variance = 0; Random generator = new Random(); if (wallName != lastWallHit){ if (x >= getX1 && x <= getX2){ if (y >= getY1 && y <= getY2){ lastWallHit = wallName; variance = (generator.nextInt(20)-10)/10; vx = (vx + variance)*-1; variance = (generator.nextInt(20)-10)/10; vy = (vy + variance); variance = generator.nextInt(10); variance = (variance % 2 == 0) ? 1:-1; vy = vy * variance; collision = "HIT! "+wallName; } } } } //Basic Movement Method public void translate(){ Random generator = new Random(); if (vx==0 || vy == 0){ vx = (generator.nextInt(100)- 50)/10; vy = (generator.nextInt(100)- 50)/10; } x += vx; y += vy; } //Advanced Collision Handling public boolean collide(int getX1, int getY1, int getX2, int getY2, int getAngle, int wallName, boolean modifySpeed){ int tempX, tempY, variance; int d = distance( getX1, getY1, getX2, getY2); Random generator = new Random(); if (wallName == lastWallHit){//Do not count multiple hits from the same wall. return false; } for(int i = 1; i < d; i++){ //Where geometry class comes in handy // Division-point theorum based linear point generator! // Points are calculated per percentage over the total distance. //tempX = ((i-d)/d)*getX1 + (i/d)*getX2; //tempY = ((i-d)/d)*getY1 + (i/d)*getY2; // Paramteric equations based linear point generator! // Points are calculated using an origin+direction*time tempX = getX1 + i* ((getX2-getX1)/d); tempY = getY1 + i* ((getY2-getY1)/d); collision = ""+distance( x, y, tempX, tempY)+" x : "+tempX+" y : "+tempY; if (distance( x, y, tempX, tempY) <= size*2){ //Collision! (only one change in direction and speed per line.) variance = generator.nextInt(20)-10; angle = 180 - 2*getAngle + angle + variance; collision = "!!!!!!!!!!!"+distance( x, y, tempX, tempY)+" x : "+tempX+" y : "+tempY;//"YES A HIT!"; lastWallHit = wallName;// Ignore multiple Collision Detects from a single wall. if (modifySpeed == true){ //The further from the center of the the two points, the more speed will be picked up. tempX = (getX1 + getX2)/2; tempY = (getY1 + getY2)/2; speed += distance(tempX,tempY,x,y)/speed; } return true; } } //collision = "No hits. :("; return false; } //Advanced Move Method public void move(){ if (speed > 10){//Deaccelerate if at max speed, or over. speed -= .1; }else if (speed == 0){// Make sure the ball is never at a complete rest. speed = 5; } deltaX = speed * Math.sin(angle); deltaY = speed * Math.cos(angle); x += (int)Math.round(deltaX); y += (int)Math.round(deltaY); message = angle+ " :angle " + speed + " :speed " + deltaX + " x : y " + deltaY; } //Score Method public void score(){ score2 += (x < 0) ? 1:0; score1 += (x > WIDTH) ? 1:0; if (x < 0 || x > WIDTH || y < - 20 || y > HEIGHT+20){ message = "Ball has been reset."; reset(true); repaint(); } } } //Paddle Subclass public class paddle { private int x,y, size, upKey, downKey, speed; //Paddle Constructor Method public paddle(int setX, int setY, int setSize, int setUpKey, int setDownKey){ x = setX; y = setY; size = setSize; upKey = setUpKey; downKey = setDownKey; } //Paddle Move Method public void move(){ if (speed > 0 && y < HEIGHT-size){//Move if going down and not over the screen limits. y += speed; }else if (speed < 0 && y > size){//Move if going up and not over the screen limits. y += speed; } } //Paddle Adjust Speed Method public void setSpeed(int getSpeed){ speed = getSpeed; } } //Line Subclass ( *ADVANCED COLLISION DETECTION ONLY - In order to later on implement mazes and obstacles on the playing field) public class line{ private int x1,y1,x2,y2, angle; public line(int setX1, int setY1, int setX2, int setY2){ x1 = setX1; y1 = setY1; x2 = setX2; y2 = setY2; if (x2 - x1 == 0){// Don't want to be dividing by 0 if the line happens to be straight if (y2 > y1){ angle = 270; }else{ angle = 90; } }else if(y2 - y1 == 0){ if (x2 > x1){ angle = 360; }else{ angle = 180; } }else{ angle = (int)Math.toDegrees(Math.atan((x2 - x1)/(y2 - y1)));//Calculate the angle of the line. } } } //Graphics Handling public void paint(Graphics g){ g.setColor(Color.black); g.fillRect( 0, 0, WIDTH, HEIGHT);//Background g.setColor(Color.white) ; for(int i = 0; i < ballArray.length; i++){//Draw all balls. g.fillOval( ballArray[i].x - ballArray[i].size/2, ballArray[i].y - ballArray[i].size/2, ballArray[i].size, ballArray[i].size); } for(int i = 0; i < player.length; i++){// Draw all paddles. g.fillRect( player[i].x - 5, player[i].y - player[i].size, 5, player[i].size * 2); } for(int i = 0; i < walls.length; i++){// Draw all paddles. g.drawLine( walls[i].x1, walls[i].y1, walls[i].x2, walls[i].y2); } g.drawString(""+score1,WIDTH/4,HEIGHT/11); g.drawString(""+score2,WIDTH*3/4,HEIGHT/11); g.setColor(Color.red); g.drawString(message,10,HEIGHT-10); g.drawString(collision,10,10); } //Double Buffering, as provided by the JavaBoutique Tutorial. public void update (Graphics g){ // initialize buffer if (dbImage == null){ dbImage = createImage (WIDTH, HEIGHT); dbg = dbImage.getGraphics (); } // clear screen in background dbg.setColor (getBackground ()); dbg.fillRect (0, 0, WIDTH, HEIGHT); // draw elements in background dbg.setColor (getForeground()); paint (dbg); // draw image on the screen g.drawImage (dbImage, 0, 0, this); } //Keyboard Handling public void keyPressed(KeyEvent e){ int key = e.getKeyCode(); for (int i = 0; i < player.length; i++){ if (key == player[i].upKey){ player[i].setSpeed(-10); }else if(key == player[i].downKey){ player[i].setSpeed(10); } } } public void keyReleased(KeyEvent e){ int key =e.getKeyCode(); for (int i = 0; i < player.length; i++){ if (key == player[i].upKey || key == player[i].downKey){ player[i].setSpeed(0); } } } public void keyTyped(KeyEvent e){ //Unused } //Thread Handling public void init(){ WIDTH = getSize().width; HEIGHT = getSize().height; score1=0; score2=0; ballArray[0] = new ball(WIDTH/2,HEIGHT/2,5); player[0] = new paddle(20, HEIGHT/2, 20, 87, 83); player[1] = new paddle(WIDTH - 20, HEIGHT/2, 20, 38, 40); walls[0] = new line( 0, 0, WIDTH, 0);//Top walls[1] = new line( 0, HEIGHT, WIDTH, HEIGHT);//Bottom //walls[2] = new line( 50,50,200,200);//Test message = "New Game"; } public void start(){ Thread game = new Thread (this); game.start(); } public void stop(){ //Unused } public void destroy(){ //Unused } public void run(){ Thread.currentThread().setPriority(Thread.MIN_PRIORITY); addKeyListener(this); while(true){ //Main Body Loop repaint(); for( int i = 0;i < player.length; i++){//Actions for all paddles player[i].move(); } //advancedCollision(); simpleCollision(); if (victory(10)==true){ victory(10); repaint(); break; } //collision = " the a "+walls[0].angle+" "+walls[1].angle; try { Thread.sleep(20); }catch(InterruptedException ex){ } // set ThreadPriority to maximum value Thread.currentThread().setPriority(Thread.MAX_PRIORITY); } }}