矩形相交与绘制到屏幕的内容不匹配

时间:2015-02-19 16:30:15

标签: java awt collision-detection

我正在使用Java AWT类来制作由两侧矩形组成的墙。 wall类扩展了矩形,并使用相同的变量绘制到屏幕上。

Walls Class:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;


public class Walls extends Rectangle {

public Walls(int startX, int startY, int width, int height ){
    //super(startX, startY, width, height);
//  
    //Checking with this way for the collision detection
    this.x = startX;
    this.y = startY;
    this.width = width;
    this.height = height;


    //this.wallStartX = startX;
    //this.wallStartY = startY;
    //this.wallWidth  = width;
    //this.wallHeight = height;
}

public void draw(Graphics g){

    g.setColor(Color.GRAY);
    //g.fillRect( this.wallStartX, this.wallStartY, this.wallWidth, this.wallHeight);
    //Trying with the rectangle methods
    g.fillRect( this.x, this.y, this.width, this.height);
}

我使用rectangle.intersects方法检查碰撞预测。它适用于左墙,但它似乎始终与右墙碰撞,即使玩家方块没有碰到。我在左右墙上使用了相同的代码,并且我确保墙的参数对于上面类中的矩形是相同的。

基于来自Java中杀手代码编程的蠕虫游戏

RacerPanel:

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.text.DecimalFormat;
import java.util.Random;
import java.awt.event.KeyEvent; //Should be for Key Usage
import java.awt.event.KeyListener;


public class RacingPanel extends GamePanel implements KeyListener {
///KeyListener from https://www.youtube.com/watch?v=5UaEUrbpDPE

//Q: Serial ID? http://stackoverflow.com/questions/285793/what-is-a-        serialversionuid-and-why-should-i-use-it
private static final long serialVersionUID = 1825086766957972644L;

private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp

private Main_Racer mrTop;
private Racer bob;
private Walls josephine;
private Walls jeremy;
private static Random randomGenerator = new Random();
boolean wallBuilder;
int leftCreateorDestroy = 100;
int rightCreateorDestroy = 100;
//private ArrayList()[] Walls kinderland;


//Q
private Font font;
private FontMetrics metrics;

//Q: definitely find out what this method is doing
public RacingPanel( Main_Racer rc, long period) {
    super(period);
    mrTop = rc;

    this.addKeyListener(this);
}


//In case we want to integrate mice
//Q: Why void? Why protected?
protected void mousePress( int x, int y){

}



//Q: in the worm game, it calls 
//fred.move(), presumably to move the worm

//wcTop.setTimeSpent(timeSpentInGame);
//Probably a counter
protected void simpleUpdate(){

}

//Q: Assuming that this should be things the
//game starts off with, like the block,
//the course. Also, font
protected void simpleInitialize(){

    //T: Maybe I need to initialize the racer
    bob = new Racer(PWIDTH, PHEIGHT);
    josephine = new Walls(0, 35, 100, 1);
    jeremy = new Walls(PWIDTH-100, 35, 100,1);
    //That did it!
    // so the arguments to the racer update change
    //where the square was rendered

    //TJ: I need to loop in such a way that will draw random variables

    // set up message font
            font = new Font("SansSerif", Font.BOLD, 24);
            metrics = this.getFontMetrics(font);

}

protected void simpleRender(Graphics dbg) {

    if(!gameOver){
    //These two seem pretty straight forward
    dbg.setColor(Color.blue);
    dbg.setFont(font);

    // report frame count & average FPS and UPS at top left
    // dbg.drawString("Frame Count " + frameCount, 10, 25);
    dbg.drawString("Average FPS/UPS: " + df.format(averageFPS) + ", "
            + df.format(averageUPS), 20, 25); // was (10,55)

    dbg.setColor(Color.black);

    // draw game elements: the obstacles and the worm

    //This'll probably be the block and the 
    //course instead

    //obs.draw(dbg);
    //fred.draw(dbg);

    bob.draw(dbg);
    //jeremy.draw(dbg);

    //See if we can draw this thing over and over
    for(int i = 35; i < PHEIGHT; i++){

        wallBuilder = randomGenerator.nextBoolean();

        if(wallBuilder == false){
            if ( leftCreateorDestroy < PWIDTH/2 - 50)
            leftCreateorDestroy++;
        }
        else{
            if(leftCreateorDestroy > 0){
                leftCreateorDestroy--;
            }

        }

        josephine = new Walls(0, i, leftCreateorDestroy, 1);
        josephine.draw(dbg);


        wallBuilder = randomGenerator.nextBoolean();

        //This wall keeps colliding with the other wall
        //Also, it isn't set to the other side of the screen due to conventions
        if(wallBuilder == false){
            //if ( (PWIDTH - rightCreateorDestroy) > (PWIDTH/2-150))
            if ( rightCreateorDestroy > 0)
            rightCreateorDestroy--;
        }
        else{
            if((PWIDTH/2 + 50) < PWIDTH - rightCreateorDestroy){
                rightCreateorDestroy++;
            }

        }

        //PWIDTH - rightCreateorDestroy is the length of the 
        jeremy = new Walls((PWIDTH - rightCreateorDestroy), i, rightCreateorDestroy, 1);
        //jeremy = new Walls((PWIDTH - rightCreateorDestroy), i, 100, 1);
        //Let's see if it will draw negative; will not;
        jeremy.draw(dbg);

        //Now to put up collision detection
        if(bob.intersects(josephine) ){
            System.out.println("Ouch!");
            gameOver = true;
        }

            //System.out.println(bob.);
        else if( bob.intersects(jeremy) ){
            Rectangle Sektor = bob.intersection(jeremy);
            System.out.println(Sektor);
            System.out.println(jeremy);

        }
            //System.out.println("Yow!");


        //Problems seem to be with the right side; let's take out the right and check.

        //For some reason, intersecting all of the time.
    }
    }

        //1msecond is too long. Starts clipping;
/*      try{
            Thread.sleep(1000);
        }catch ( InterruptedException exc ){
            System.out.println("No work");

            } */

        } 

    //So this does draw over and over again
    //FPS/UPS Still good





//Pretty straight forward as well. Just need
//to see when it is called
protected void gameOverMessage(Graphics g)
// center the game-over message in the panel
{
    //Keeps updating after death...
    String msg = "Game Over. Your Score: " + timeSpentInGame;
    int x = (PWIDTH - metrics.stringWidth(msg)) / 2;
    int y = (PHEIGHT - metrics.getHeight()) / 2;
    g.setColor(Color.red);
    g.setFont(font);
    g.drawString(msg, x, y);
} // end of gameOverMessage()



@Override
public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_RIGHT){
        //System.out.println("Right");
        //Should set x position to current position plus 1
        bob.setRacerPositionX(bob.getRacerPositionX() + 1);
    }
    if (e.getKeyCode() == KeyEvent.VK_LEFT){
    //  System.out.println("Left");
        bob.setRacerPositionX(bob.getRacerPositionX() - 1);
    }
    if (e.getKeyCode() == KeyEvent.VK_UP){
        //System.out.println("Up");
        bob.setRacerPositionY(bob.getRacerPositionY() - 1);
    }
    if (e.getKeyCode() == KeyEvent.VK_DOWN){
        //System.out.println("Down");
        bob.setRacerPositionY(bob.getRacerPositionY() + 1);
    }
}

游戏小组类:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.text.DecimalFormat;

import javax.swing.JPanel;

public abstract class GamePanel extends JPanel implements Runnable {
private static final long serialVersionUID = 1863596360846514344L;
private static long MAX_STATS_INTERVAL = 1000000000L;
// private static long MAX_STATS_INTERVAL = 1000L;
// record stats every 1 second (roughly)

private static int NUM_FPS = 10;
// number of FPS values stored to get an average

protected static final int PWIDTH = 500; // size of panel
protected static final int PHEIGHT = 400;

protected static final int NO_DELAYS_PER_YIELD = 16;
/*
 * Number of frames with a delay of 0 ms before the animation thread yields
 * to other running threads.
 */

protected static int MAX_FRAME_SKIPS = 5; // was 2;
// no. of frames that can be skipped in any one animation loop
// i.e the games state is updated but not rendered

private Thread animator; // the thread that performs the animation
protected boolean running = false; // used to stop the animation thread
protected boolean isPaused = false;

protected long period; // period between drawing in _nanosecs_

// used for gathering statistics
private long statsInterval = 0L; // in ns
private long prevStatsTime;
private long totalElapsedTime = 0L;
private long gameStartTime;
protected int timeSpentInGame = 0; // in seconds

private long frameCount = 0;
private double fpsStore[];
private long statsCount = 0;
protected double averageFPS = 0.0;

private long framesSkipped = 0L;
private long totalFramesSkipped = 0L;
private double upsStore[];
protected double averageUPS = 0.0;
private DecimalFormat df = new DecimalFormat("0.##"); // 2 dp

// used at game termination
protected boolean gameOver = false;

// off screen rendering
private Graphics dbg;
private Image dbImage = null;

public GamePanel(long period) {
    this.period = period;

    setBackground(Color.white);
    setPreferredSize(new Dimension(PWIDTH, PHEIGHT));

    setFocusable(true);
    requestFocus(); // the JPanel now has focus, so receives key events
    readyForTermination();

    simpleInitialize();

    addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent e) {
            mousePress(e.getX(), e.getY());
        }
    });

    // initialise timing elements
    fpsStore = new double[NUM_FPS];
    upsStore = new double[NUM_FPS];
    for (int i = 0; i < NUM_FPS; i++) {
        fpsStore[i] = 0.0;
        upsStore[i] = 0.0;
    }

} // end of GamePanel()

/**
 * Sets up a listener to kill the game loop if the user attempts to quit
 */
private void readyForTermination() {
    addKeyListener(new KeyAdapter() {
        // listen for esc, q, end, ctrl-c on the canvas to
        // allow a convenient exit from the full screen configuration
        public void keyPressed(KeyEvent e) {
            int keyCode = e.getKeyCode();
            if ((keyCode == KeyEvent.VK_ESCAPE)
                    || (keyCode == KeyEvent.VK_Q)
                    || (keyCode == KeyEvent.VK_END)
                    || ((keyCode == KeyEvent.VK_C) && e.isControlDown())) {
                running = false;
            }
        }
    });
} // end of readyForTermination()

/**
 * Triggers the animation loop to start
 */
public void addNotify()
// wait for the JPanel to be added to the JFrame before starting
{
    super.addNotify(); // creates the peer
    startGame(); // start the thread
}

/**
 * Starts the animation loop
 */
private void startGame()
// initialise and start the thread
{
    if (animator == null || !running) {
        animator = new Thread(this);
        animator.start();
    }
} // end of startGame()

// ------------- game life cycle methods ------------
// called by the JFrame's window listener methods

public void resumeGame()
// called when the JFrame is activated / deiconified
{
    isPaused = false;
}

public void pauseGame()
// called when the JFrame is deactivated / iconified
{
    isPaused = true;
}

public void stopGame()
// called when the JFrame is closing
{
    running = false;
}

// ----------------------------------------------

public void run()
/* The frames of the animation are drawn inside the while loop. */
{
    long beforeTime, afterTime, timeDiff, sleepTime;
    long overSleepTime = 0L;
    int noDelays = 0;
    long excess = 0L;

    gameStartTime = System.nanoTime();
    prevStatsTime = gameStartTime;
    beforeTime = gameStartTime;

    running = true;

    while (running) {
        gameUpdate();
        //T Entering Game Render
        System.out.println("Entering Game Render");
        gameRender();
        paintScreen();

        afterTime = System.nanoTime();
        timeDiff = afterTime - beforeTime;
        sleepTime = (period - timeDiff) - overSleepTime;

        if (sleepTime > 0) { // some time left in this cycle
            try {
                Thread.sleep(sleepTime / 1000000L); // nano -> ms
            } catch (InterruptedException ex) {
            }
            overSleepTime = (System.nanoTime() - afterTime) - sleepTime;
        } else { // sleepTime <= 0; the frame took longer than the period
            excess -= sleepTime; // store excess time value
            overSleepTime = 0L;

            if (++noDelays >= NO_DELAYS_PER_YIELD) {
                Thread.yield(); // give another thread a chance to run
                noDelays = 0;
            }
        }

        beforeTime = System.nanoTime();

        /*
         * If frame animation is taking too long, update the game state
         * without rendering it, to get the updates/sec nearer to the
         * required FPS.
         */
        int skips = 0;
        while ((excess > period) && (skips < MAX_FRAME_SKIPS)) {
            excess -= period;
            gameUpdate(); // update state but don't render
            skips++;
        }
        framesSkipped += skips;
        storeStats();
    }
    printStats();
    System.exit(0); // so window disappears
} // end of run()

/**
 * Renders to the backbuffer
 */
private void gameRender() {
    if (dbImage == null) {
        dbImage = createImage(PWIDTH, PHEIGHT);
        if (dbImage == null) {
            System.out.println("dbImage is null");
            return;
        } else
            dbg = dbImage.getGraphics();
        //T 
        System.out.println("dbg set");
    }

    // clear the background
    dbg.setColor(Color.white);
    dbg.fillRect(0, 0, PWIDTH, PHEIGHT);

    //T
    simpleRender(dbg);

    if (gameOver)
        gameOverMessage(dbg);
} // end of gameRender()

/**
 * Paints the back buffer
 */
private void paintScreen()
// use active rendering to put the buffered image on-screen
{
    Graphics g;
    try {
        g = this.getGraphics();
        if ((g != null) && (dbImage != null))
            g.drawImage(dbImage, 0, 0, null);
        g.dispose();
    } catch (Exception e) {
        System.out.println("Graphics context error: " + e);
    }
} // end of paintScreen()

/**
 * Should be update the game state
 */
private void gameUpdate() {
    if (!isPaused && !gameOver)
        simpleUpdate();

} // end of gameUpdate()

private void storeStats() {
    frameCount++;
    statsInterval += period;

    if (statsInterval >= MAX_STATS_INTERVAL) { // record stats every
        // MAX_STATS_INTERVAL
        long timeNow = System.nanoTime();
        timeSpentInGame = (int) ((timeNow - gameStartTime) / 1000000000L); 

        long realElapsedTime = timeNow - prevStatsTime; // time since last

        // stats collection
        totalElapsedTime += realElapsedTime;

        totalFramesSkipped += framesSkipped;

        double actualFPS = 0; // calculate the latest FPS and UPS
        double actualUPS = 0;
        if (totalElapsedTime > 0) {
            actualFPS = (((double) frameCount / totalElapsedTime) * 1000000000L);
            actualUPS = (((double) (frameCount + totalFramesSkipped) / totalElapsedTime) * 1000000000L);
        }

        // store the latest FPS and UPS
        fpsStore[(int) statsCount % NUM_FPS] = actualFPS;
        upsStore[(int) statsCount % NUM_FPS] = actualUPS;
        statsCount = statsCount + 1;

        double totalFPS = 0.0; // total the stored FPSs and UPSs
        double totalUPS = 0.0;
        for (int i = 0; i < NUM_FPS; i++) {
            totalFPS += fpsStore[i];
            totalUPS += upsStore[i];
        }

        if (statsCount < NUM_FPS) { // obtain the average FPS and UPS
            averageFPS = totalFPS / statsCount;
            averageUPS = totalUPS / statsCount;
        } else {
            averageFPS = totalFPS / NUM_FPS;
            averageUPS = totalUPS / NUM_FPS;
        }
        framesSkipped = 0;
        prevStatsTime = timeNow;
        statsInterval = 0L; // reset
    }
} // end of storeStats()

private void printStats() {
    System.out.println("Frame Count/Loss: " + frameCount + " / "
            + totalFramesSkipped);
    System.out.println("Average FPS: " + df.format(averageFPS));
    System.out.println("Average UPS: " + df.format(averageUPS));
    System.out.println("Time Spent: " + timeSpentInGame + " secs");
} // end of printStats()

/**
 * Should implement game specific rendering
 * 
 * @param g
 */
protected abstract void simpleRender(Graphics g);

/**
 * Should display a game specific game over message
 * 
 * @param g
 */
protected abstract void gameOverMessage(Graphics g);


protected abstract void simpleUpdate();

/**
 * This just gets called when a click occurs, no default behavior
 */
protected abstract void mousePress(int x, int y);

/**
 * Should be overridden to initialize the game specific components
 */
protected abstract void simpleInitialize();

} // GamePanel类的结束

赛车类:

import java.awt.*;
import java.awt.geom.*;

public class Racer extends Rectangle {

//Only method that will likely be common between
//the two areas. This presumably draws  to screen

//Size of Car
private static final int carSize = 20;



//Changing racer position from array to x and y coordinates

private int pWidth, pHeight;   // panel dimensions
private long startTime;        // in ms

public Racer (int pW, int pH){

    this.width = pW; 
    this.height = pH;

    //Meant to start racer in the center of the screen
    //But it does not
    this.x = pW/2;
    this.y = pW/2;



}

public void draw(Graphics g){
    g.setColor(Color.blue);
    g.fillRect( x, y, carSize, carSize);        
}

public int getRacerPositionX() {
    return x;
}

public void setRacerPositionX(int x) {
    this.x = x;
}

public int getRacerPositionY() {
    return y;
}

public void setRacerPositionY(int y) {
    this.y = y;
}

}

主赛车手:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Main_Racer  extends JFrame implements WindowListener

{

private static int DEFAULT_FPS = 80;


private RacingPanel rp;

//Let's leave now and make the panel



//Q: Just a value; why JTextField instead of int?
private JTextField jtfBox;

//Q: Just a value; why JTextField instead of int?
private JTextField jtfTime;

//Main_Racer Constructor
public Main_Racer(long period)
{
    //Q: Gotta find this constructor
    super("The Main Racder");
    //Q:What does the argument do?
    makeGUI(period);

    addWindowListener( this);
    pack();
    setResizable(false);
    setVisible(true);
}


    //Q: Warrants an in depth look
    private void makeGUI(long period)
    {
    Container c = getContentPane();    // default BorderLayout used

    rp = new RacingPanel(this, period);
    c.add(rp, "Center");

    JPanel ctrls = new JPanel();   // a row of textfields
    ctrls.setLayout( new BoxLayout(ctrls, BoxLayout.X_AXIS));

    //Keeps track of time. Might still be useful
    jtfTime = new JTextField("Time Spent: 0 secs");
    jtfTime.setEditable(false);
    ctrls.add(jtfTime);

    c.add(ctrls, "South");
    }  // end of makeGUI()

    //Pretty straing forward
    public void setTimeSpent(long t)
      {  jtfTime.setText("Time Spent: " + t + " secs"); }

// QQQ -----------------Going to copy the window listening methods, as probably n
//need em all

      public void windowActivated(WindowEvent e) 
      {  rp.resumeGame();  }

      public void windowDeactivated(WindowEvent e) 
      {  rp.pauseGame();  }


      public void windowDeiconified(WindowEvent e) 
      {  rp.resumeGame();  }

      public void windowIconified(WindowEvent e) 
      {  rp.pauseGame(); }


      public void windowClosing(WindowEvent e)
      {  rp.stopGame();  }


      public void windowClosed(WindowEvent e) {}
      public void windowOpened(WindowEvent e) {}

//=================================================================================

      public static void main(String args[])
      { 
        int fps = DEFAULT_FPS;
        if (args.length != 0)
          fps = Integer.parseInt(args[0]);

        long period = (long) 1000.0/fps;
        System.out.println("fps: " + fps + "; period: " + period + " ms");

        new Main_Racer(period*1000000L);    // ms --> nanosecs 
      }

    } // end of WormChase class

碰撞检测只能在一侧工作的原因是什么?

0 个答案:

没有答案