Ethans Final Project
<< Cameron's Final Project | OldProjectsTrailIndex | Ian's Final Project >>
Great, I just took a look. You dont have to sacrifice the graphic, since you can generate a Rectangle2D object from the Buffered Image, like I did in Heart class of my DuckyLove applet. The heart changes the size of the graphic, so I use x,y,w,h, but you can just use image.getHeight() if you prefer
public Rectangle2D area(){ return new Rectangle2D.Double(x-w/2, y-h/2, w, h); }
Matt and Cameron are processing key presses differently for a more "responsive" feel. on the keypress, they add it to an ArrayList, so you press and hold a key to glide the paddle. you can also opt to use the mouse instead. I've posted an alternate Paddle and Breakout to demonstrate, but feel free to make it work the way you wish. The way the bricks will interact with the ball is similar to the paddle, so I made the Paddle a subclass of Brick. I'm sure you can find a way to adds the bricks, and finding a way of scoring, adding sound if you wish...
FrC's Brick.java
import java.awt.Graphics; import java.awt.geom.Rectangle2D; import java.awt.Color; public class Brick { protected int x,y,width,height; protected Color color; protected boolean visable; public Brick(int x, int y, int width, int height){ this.x=x; this.y=y; this.width=width; this.height=height; this.setColor(Color.RED); } public Rectangle2D area(){ return new Rectangle2D.Double(x,y,width,height); } public boolean touches(Ball ball){ return area().intersects(ball.area()); } /** * changes ball location and direction * depending on where on the brick is * in relation to the ball * @param ball */ public void hit(Ball ball){ Rectangle2D br=ball.area(); double rise=br.getCenterY()- area().getCenterY(); double run=br.getCenterX()- area().getCenterX(); double theta =Math.atan2(rise, run); ball.setRise((int)(5*Math.sin(theta))); ball.setRun((int)(5*Math.cos(theta))); } public void setVisable(boolean visable) {this.visable = visable;} public boolean isVisable() {return visable;} public void setColor(Color color) {this.color = color;} public int getX() {return x;} public int getY() {return y;} public int getWidth(){return width;} public int getHeight(){return height;} public void setX(int x){ this.x=x;} public void setY(int y){ this.y=y;} public void setWidth(int w){ width=w;} public void setHeight(int h){ height=h;} public void draw(Graphics g){ Color c=g.getColor(); g.setColor(color); g.fillRect(x, y, width, height); g.setColor(c); } }
FrC's Paddle.java
import java.awt.Color; public class Paddle extends Brick{ public static final int leftLimit=10; public static final int rtLimit=790; public static final int topLimit = 300; public static final int bottomLimit = 590; public Paddle(int x, int y, int width, int height){ super(x,y,width,height); this.setColor(Color.RED); } public void moveLeft(int amount) { x-=amount; if (x<leftLimit) x=leftLimit; } public void moveRight(int amount) { x+=amount; if(x>rtLimit-width) x=rtLimit-width; } public void moveUp(int amount) { y-=amount; if (y<topLimit) y=topLimit; } public void moveDown(int amount) { y+=amount; if (y>bottomLimit-height) y=bottomLimit-height; } }
FrC's Ball.java
import java.awt.Color; import java.awt.Graphics; import java.awt.geom.Rectangle2D; public class Ball { public static final int MAX_SPEED = 4; private int x; private int y; private int radius; private int rise; private int run; private int speed; private Color color; private boolean visable; public Ball(int radius){ x=randInt(350,450); y=300; this.radius=radius; rise=randInt(1,8); run=randInt(-8,8); setVisable(false); setColor(Color.BLUE); setSpeed(1); } public int randInt(int min, int max){ return min+(int)((max-min)*Math.random()); } public void move(){ x+=speed*run; y+=speed*rise; } /** * set ball's top left corner to (x,y) * @param x * @param y */ public void moveTo(int x, int y){ this.x=x+radius; this.y=y+radius; } public void bounceVertical(){ rise*=-1; } public void bounceHorizontal(){ run*=-1; } public void draw(Graphics g){ if (visable){ Color c=g.getColor(); g.setColor(Color.BLUE); g.fillOval(x-radius, y-radius, 2*radius, 2*radius); g.setColor(c); } } public void setVisable(boolean visable) { this.visable = visable; } public boolean isVisable() { return visable; } public Rectangle2D area(){ return new Rectangle2D.Double(x-radius, y-radius, 2*radius, 2*radius); } public void setRise(int rise){ this.rise=rise;} public void setRun(int run){ this.run=run;} public int getRise(){return rise;} public int getRun(){return run;} public void setX(int x){ this.x=x;} public void setY(int y){ this.y=y;} public int getX(){return x;}//center x public int getY(){return y;}//center y public int getRadius(){return radius;} public void setColor(Color c){ this.color=c;} public Color getColor(){return this.color;} public void setSpeed(int speed) {this.speed = speed;} public int getSpeed() {return speed;} public void increaseSpeed() { speed++; if (speed>MAX_SPEED) speed=MAX_SPEED; } public void decreaseSpeed() { speed--; if (speed<0) speed=0; } }
FrC's Brickout.java (using pressing and holding keys rather than the mouse, no bricks in place, yet)
import java.awt.event.*; import java.applet.Applet; import java.awt.*; import java.util.ArrayList; import javax.swing.*; public class Breakout extends Applet implements ActionListener, KeyListener { /** * */ private static final long serialVersionUID = 1L; /** * Need an array list of bricks once the paddle is worked out */ public static final int amount=6; Timer timer; Image virtualMem; Graphics gBuffer; Ball ball; Wall top,bottom,left,right; int appletWidth; int appletHeight; int frame; int lastFrame; int hits=0; Button myButton; Paddle paddle; ArrayList<Integer> keyPresses; // OUR CLASS IS A SUBCLASS OF APPLET /** * this init() method will be run at the beginning * and where we create the Listeners */ public void init() { paddle = new Paddle(375, 450,75,15); this.addKeyListener((KeyListener)this); keyPresses=new ArrayList<Integer>(); ball = new Ball(10); top = new Wall(0,0,800,10); bottom = new Wall(0,590,800,10); left = new Wall(0,10,10,590); right = new Wall(790,10,10,590); appletWidth = getWidth(); appletHeight = getHeight(); frame=0; timer=new Timer(1, this); lastFrame=appletWidth; virtualMem = createImage(appletWidth,appletHeight); gBuffer = virtualMem.getGraphics(); gBuffer.setColor(Color.white); gBuffer.fillRect(0,0,appletWidth,appletHeight); myButton= new Button("Do It Again"); //the class is its own button listener myButton.addActionListener (this); add(myButton); paddle = new Paddle( 375, 450,75,15); this.setFocusable(true); } public void paint(Graphics g) { //We draw using the object methods of // the graphics buffer, not what is // currently on the screen gBuffer.setColor(Color.white); gBuffer.fillRect(0,0,appletWidth,appletHeight);gBuffer.setColor(Color.black); gBuffer.setColor(Color.black); gBuffer.drawString("speed "+ball.getSpeed(), 20,20); gBuffer.drawString("hits "+hits, 20,50); ball.draw(gBuffer); top.draw(gBuffer); bottom.draw(gBuffer); left.draw(gBuffer); right.draw(gBuffer); paddle.draw(gBuffer); //Now we send the result to the screen g.drawImage(virtualMem,0,0,this); } public void update(Graphics g) { paint(g); //get rid of flicker with this method } /** * ActionListener is an interface and * requires the actionPerformed() method * to be defined..in this case we * look for a restart button being pressed */ public void actionPerformed(ActionEvent e){ Object source = e.getSource(); if (source == timer) { frame++; frame%=100; ball.move(); if (paddle.touches(ball)){ paddle.hit(ball); hits++; if (hits%3==0) ball.increaseSpeed(); } processKeyPresses(); if (top.touches(ball) || bottom.touches(ball)){ ball.bounceVertical(); } if (left.touches(ball) || right.touches(ball)){ ball.bounceHorizontal(); } } else {//restart button pressed frame=0; if (timer.isRunning()) { timer.stop(); myButton.setLabel("Start"); ball.setVisable(false); paddle.setVisable(false); } else { timer.start(); myButton.setLabel("Stop"); ball=new Ball(10); hits=0; ball.setVisable(true); paddle.setVisable(true); requestFocusInWindow(); } } repaint(); } public void keyPressed(KeyEvent e){ if(!keyPresses.contains(e.getKeyCode())) keyPresses.add(e.getKeyCode()); } public void keyReleased(KeyEvent e){ keyPresses.remove(new Integer(e.getKeyCode())); } public void keyTyped(KeyEvent e) {} public void processKeyPresses(){ if(keyPresses.contains(KeyEvent.VK_A)||keyPresses.contains(KeyEvent.VK_LEFT)) paddle.moveLeft(amount); //tells ship to move left when a or left is held if(keyPresses.contains(KeyEvent.VK_D)||keyPresses.contains(KeyEvent.VK_RIGHT)) paddle.moveRight(amount); //tells ship to move right when d or right is held if(keyPresses.contains(KeyEvent.VK_W)||keyPresses.contains(KeyEvent.VK_UP)) paddle.moveUp(amount); //tells ship to move up when w or up is held if(keyPresses.contains(KeyEvent.VK_S)||keyPresses.contains(KeyEvent.VK_DOWN)) paddle.moveDown(amount); //tells ship to move down when s or down is held } }
Breakout.java
import java.awt.event.*; import java.applet.Applet; import java.awt.*; import java.io.IOException; import javax.swing.*; public class Breakout extends Applet implements ActionListener, KeyListener { /** * Need an array list of bricks once the paddle is worked out */ public static final int amount=5; Timer timer; Image virtualMem; Graphics gBuffer; Ball ball; Wall top,bottom,left,right; int appletWidth; int appletHeight; int frame; int lastFrame; Button myButton; Paddle paddle; // OUR CLASS IS A SUBCLASS OF APPLET /** * this init() method will be run at the beginning * and where we create the Listeners */ public void init() { paddle = new Paddle(375, 450,75,15); this.addKeyListener((KeyListener)this); ball = new Ball(10); top = new Wall(0,0,800,10); bottom = new Wall(0,590,800,10); left = new Wall(0,10,10,590); right = new Wall(790,10,10,590); appletWidth = getWidth(); appletHeight = getHeight(); frame=0; timer=new Timer(1, this); lastFrame=appletWidth; virtualMem = createImage(appletWidth,appletHeight); gBuffer = virtualMem.getGraphics(); gBuffer.setColor(Color.white); gBuffer.fillRect(0,0,appletWidth,appletHeight); myButton= new Button("Do It Again"); //the class is its own button listener myButton.addActionListener (this); add(myButton); } public void paint(Graphics g) { //We draw using the object methods of // the graphics buffer, not what is // currently on the screen gBuffer.setColor(Color.white); gBuffer.fillRect(0,0,appletWidth,appletHeight);gBuffer.setColor(Color.black); gBuffer.setColor(Color.black); gBuffer.drawString("Frame "+frame, 20,20); ball.draw(gBuffer); top.draw(gBuffer); bottom.draw(gBuffer); left.draw(gBuffer); right.draw(gBuffer); paddle.draw(gBuffer); //Now we send the result to the screen g.drawImage(virtualMem,0,0,this); } public void update(Graphics g) { paint(g); //get rid of flicker with this method } /** * ActionListener is an interface and * requires the actionPerformed() method * to be defined..in this case we * look for a restart button being pressed */ public void actionPerformed(ActionEvent e){ Object source = e.getSource(); if (source == timer) { frame++; frame%=100; ball.move(); /** * For now, this is fine until i get the paddle working. * Once that happens, change the first if statement to * if (top.touches(ball)){ ball.bounceVertical();} */ /** * Additionally, this new if statement needs to be added as well as * adding a display message of "Game Over" * if (bottom.touches(ball)){ ball.setVisable(false); paddle.setVisable(false);} */ if (top.touches(ball) || bottom.touches(ball)){ ball.bounceVertical(); } if (left.touches(ball) || right.touches(ball)){ ball.bounceHorizontal(); } if (paddle.touches(ball)){ ball.bounceVertical(); } } else {//restart button pressed frame=0; if (timer.isRunning()) { timer.stop(); myButton.setLabel("Start"); ball.setVisable(false); paddle.setVisable(false); } else { timer.start(); myButton.setLabel("Stop"); ball=new Ball(10); paddle = new Paddle( 375, 450,75,15); ball.setVisable(true); paddle.setVisable(true); } } repaint(); } @Override public void keyPressed(KeyEvent e) { int keyCode=e.getKeyCode(); if(keyCode==38){ //up paddle.setY(paddle.getY()-amount); } else if (keyCode==40){ //down paddle.setY(paddle.getY()+amount); } else if (keyCode==37){ //left paddle.setX(paddle.getX()-amount); } else if (keyCode==39){ //right paddle.setX(paddle.getX()+amount); }else if (keyCode==65){ //forward } repaint(); } @Override public void keyReleased(KeyEvent e) {} @Override public void keyTyped(KeyEvent e) {} }
Paddle.java
import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import java.awt.geom.Rectangle2D; import java.awt.Color; import java.awt.Graphics; /** * Possibility of losing the graphic in favor of a Rectangle2D.Double in order to use the * intersects method, allowing for a similar touches(Ball ball) method to the * touches(Ball ball) method that the wall class has? */ public class Paddle { private int x,y,width,height; private Color color; boolean left; private Rectangle2D.Double rect; private boolean visable; // see http://download.oracle.com/javase/tutorial/2d/images/loadimage.html public Paddle(int x, int y, int width, int height){ rect=new Rectangle2D.Double(x, y, width, height); this.x=x; this.y=y; this.width=width; this.height=height; this.setColor(Color.RED); } public boolean touches(Ball ball){ return rect.intersects(ball.area()); } public void setVisable(boolean visable) { this.visable = visable; } public boolean isVisable() { return visable; } public void setColor(Color color) { this.color = color; } public int getX() {return x;} public int getY() {return y;} /** * if x changes, we might need to switch the direction our monster is facing * @param x */ public void setX(int x){ left=true; if (x>this.x){ left=false; } this.x=x; } public void setY(int y){ this.y=y;} // see http://download.oracle.com/javase/tutorial/2d/images/drawimage.html /** * this is a basic way of drawing the whole img, as it is */ public void draw(Graphics g){ Color c=g.getColor(); g.setColor(color); g.fillRect(x, y, width, height); g.setColor(c); } }
Wall.java
import java.awt.Color; import java.awt.Graphics; import java.awt.geom.Rectangle2D; public class Wall { private Rectangle2D.Double rect; private Color color; private int x,y,width,height; public Wall(int x, int y, int width, int height){ rect=new Rectangle2D.Double(x, y, width, height); this.x=x; this.y=y; this.width=width; this.height=height; setColor(Color.BLACK); } public boolean touches(Ball ball){ return rect.intersects(ball.area()); } public void draw(Graphics g){ Color c=g.getColor(); g.setColor(color); g.fillRect(x, y, width, height); g.setColor(c); } public void setColor(Color color) { this.color = color; } public Color getColor() { return color; } }
Ball.java
import java.awt.Color; import java.awt.Graphics; import java.awt.geom.Rectangle2D; public class Ball { private int x; private int y; private int radius; private int rise; private int run; private boolean visable; public Ball(int radius){ x=randInt(350,450); y=randInt(250,350); this.radius=radius; rise=randInt(1,8); run=randInt(-8,8); setVisable(false); } public int randInt(int min, int max){ return min+(int)((max-min)*Math.random()); } public void move(){ x+=run; y+=rise; } public void bounceVertical(){ rise*=-1; } public void bounceHorizontal(){ run*=-1; } public void draw(Graphics g){ if (visable){ Color c=g.getColor(); g.setColor(Color.BLUE); g.fillOval(x-radius, y-radius, 2*radius, 2*radius); g.setColor(c); } } public void setVisable(boolean visable) { this.visable = visable; } public boolean isVisable() { return visable; } public Rectangle2D area(){ return new Rectangle2D.Double(x-radius, y-radius, 2*radius, 2*radius); } }