优化突破(游戏)块命中检查

时间:2014-03-12 00:46:53

标签: java breakout

我做了Breakout并且它工作正常,但是因为大量的点击检查而有点滞后。有谁知道如何重做我的命中检查以提高速度/效率? (仅供参考didCollide [Direction]方法检查它是否在那一侧 - didCollideTop()检查它是否位于该块的顶部)

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Canvas;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import static java.lang.Character.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;

public class Breakout extends Canvas implements KeyListener, Runnable, Frame
{
private Ball ball;
private Paddle paddle;
private boolean[] keys;
private BufferedImage back;
private ArrayList<Wall> walls = new ArrayList<Wall>();
private ArrayList<Square> squares = new ArrayList<Square>();
private final int SIDEBORDER = 20;
private final int BOTTOMBORDER = 60;
private final int BALL_SPEED = 20;
private final int WALL_SIZE = 20;

public Breakout()
{
    ball = new Ball((int) (Frame.WIDTH / 2.1), (int) (Frame.HEIGHT / 1.15), 20, 20, Color.green, BALL_SPEED, -BALL_SPEED);      //instantiate a Ball
    paddle = new Paddle((int) (Frame.WIDTH / 2.2), Frame.HEIGHT - 80, 100, 25, Color.blue, 20);     //instantiate a Paddle

    //makes the left walls
    for (int i = 20; i < Frame.HEIGHT - BOTTOMBORDER; i += 20)
        walls.add(new Wall(0, i, WALL_SIZE, WALL_SIZE));

    //makes the top walls
    for (int i = 0; i < Frame.WIDTH - SIDEBORDER; i += 20)
        walls.add(new Wall(i, 0, WALL_SIZE, WALL_SIZE));

    //makes the right walls
    for (int i = 20; i < Frame.HEIGHT - BOTTOMBORDER; i += 20)
        walls.add(new Wall(Frame.WIDTH - 40, i, WALL_SIZE, WALL_SIZE));

    //makes the squares (the ones you hit)
    for (int i = 80; i < Frame.HEIGHT / 2; i += 40)
        for (int j = 80; j < Frame.WIDTH / 1.1; j += 70)
            squares.add(new Square(j, i, 60, 30));

    keys = new boolean[2];

        setBackground(Color.WHITE);
    setVisible(true);

    addKeyListener(this);   
    new Thread(this).start();
}

public void update(Graphics window)
{paint(window);}

public void paint(Graphics window)
{
    Graphics2D twoDGraph = (Graphics2D) window;

    back = null;

    //take a snap shop of the current screen and save it as an image
    if (back == null)
       back = (BufferedImage)(createImage(getWidth(), getHeight()));

    //create a graphics reference to the back ground image
    //draw all changes on the background image
    Graphics graphToBack = back.createGraphics();

    ball.moveAndDraw(graphToBack);
    paddle.draw(graphToBack);

    for (int i = 0; i < walls.size(); i++) //draw walls
        walls.get(i).draw(graphToBack);

    for (int i = 0; i < squares.size(); i++) //draw squares
        squares.get(i).draw(graphToBack);

    //see if the paddle can move
    if (keys[0] == true && paddle.getX() > WALL_SIZE + 15)
        paddle.moveLeftAndDraw(window);     //move paddle left and draw it

    if (keys[1] == true && paddle.getX() + paddle.getWidth() < walls.get(walls.size() - 1).getX() - 15)
        paddle.moveRightAndDraw(window);    //move paddle right and draw it

    //see if the ball hits the top walls
    if (ball.getY() + ball.getYSpeed() <= WALL_SIZE)
        ball.setYSpeed(-ball.getYSpeed());

    //see if the ball hits the left walls
    if (ball.getX() + ball.getXSpeed() <= WALL_SIZE)
        ball.setXSpeed(-ball.getXSpeed());  

    //see if the ball hits the right walls
    if (ball.getX() + ball.getWidth() + ball.getXSpeed() >= walls.get(walls.size() - 1).getX())
        ball.setXSpeed(-ball.getXSpeed());

    //see if the ball hits the paddle
    if (ball.didCollideTop(paddle))         //top of paddle
        ball.setYSpeed(-ball.getYSpeed());

    else if (ball.didCollideLeft(paddle) || ball.didCollideRight(paddle))   //sides of paddle
        ball.setXSpeed(-ball.getXSpeed());

    //checks if the ball hits a square
    for (int i = squares.size() - 1; i >= 0; i--)
    {
        if (ball.didCollideLeft(squares.get(i)) || ball.didCollideRight(squares.get(i)))
        {
            squares.remove(i);
            ball.setXSpeed(-ball.getXSpeed());
        }

        else if (ball.didCollideTop(squares.get(i)) || ball.didCollideBottom(squares.get(i)))
        {
            squares.remove(i);
            ball.setYSpeed(-ball.getYSpeed());
        }
    }

    if (ball.getY() + ball.getHeight() > Frame.HEIGHT)  //resets ball if it goes off screen
        resetBall();

    if (squares.size() == 0)
    {
        ball.setColor(Color.white);
        graphToBack.setColor(randomColor());
        graphToBack.setFont(window.getFont().deriveFont(200f));
        graphToBack.drawString("You Win!", (int) (Frame.WIDTH / 6.5), (int) (Frame.HEIGHT / 2.5));
    }

    twoDGraph.drawImage(back, null, 0, 0);
}

/**
 * Randomly generates true or false
 * Used to randomize ball direction on reset
 * @return true or false
 */
public boolean genRandom()
{
   if ((int) (Math.random() * 2) == 0)
       return true;
   else
       return false;
}

/**
 * Generates a random color
 * @return a random color
 */
public Color randomColor()
{
    int r = (int) (1 + Math.random() * 255);
    int g = (int) (1 + Math.random() * 255);
    int b = (int) (1 + Math.random() * 255);
    return new Color(r, g, b);
}

/**
 * Resets the ball in middle
 * Resets the ball's speed
 * Chooses a random direction
 */
public void resetBall()
{
   ball.setPos((int) (Frame.WIDTH / 2.1), (int) (Frame.HEIGHT / 1.15)); //reset position
   ball.setXSpeed(BALL_SPEED);                      //reset speeds
   ball.setYSpeed(-BALL_SPEED);

   if (genRandom())                                 //random X direction
       ball.setXSpeed(-BALL_SPEED);
}


public void keyPressed(KeyEvent e)
{
  switch(toUpperCase(e.getKeyChar()))
  {
     case 'D' : keys[0] = true; break;  //left
     case 'J' : keys[1] = true; break;  //right
  }
}

public void keyReleased(KeyEvent e)
{
switch(toUpperCase(e.getKeyChar()))
{
    case 'D' : keys[0] = false; break;
    case 'J' : keys[1] = false; break;
}
}

public void run()
{
try
{
    while(true)
    {
       Thread.currentThread().sleep(8);
               repaint();
            }
    }
catch(Exception e){}
}

public void keyTyped(KeyEvent e) {}
}

1 个答案:

答案 0 :(得分:2)

您的块排列在网格中。如果将块存储在2D数组中(由网格行和列编号索引),则可以直接计算球的网格坐标(划分球X /块宽度和球Y /块高度)然后检查是否存在该网格单元格中的一个块(或相邻的单元格,注意到球可能位于最多4个单元格的边界上 [假设其直径小于单元格的较小维度 - 但是您可以轻松适应情况并非如此] )。这将是O(1);你会直接确定球可能重叠的可能块。

然后你只需要对最多4个块(球的网格单元中的那些块)而不是每个块进行实际的碰撞检测 - 并且在任何时候你都不必迭代所有块。 / p>

你的墙细胞也可以在这个网格中工作。