1

我目前正在开发Java rpg 游戏。我处于早期阶段,试图弄清楚游戏引擎,特别是平铺机制。游戏确实是由平铺组成的,玩家是静止的,而背景是移动的。我遇到了一个关于用于碰撞检测的二维数组的大问题。这是代码(请原谅长度):

package java4k;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFrame;

/**
 *
 * @author Christophe
 */
public class Main extends JFrame implements Runnable{

    public Image dbImage;
    public Graphics dbGraphics;

    //Move Variables
    int x = 320,y = 240, xDirection, yDirection;

    //Sprites
    BufferedImage spriteSheet;

    //Lists for sprite sheet: 1 = STILL; 2 = MOVING_1; 3 = MOVING_2
    BufferedImage[] ARCHER_NORTH = new BufferedImage[4];
    BufferedImage[] ARCHER_SOUTH = new BufferedImage[4];
    BufferedImage[] ARCHER_EAST = new BufferedImage[4];
    BufferedImage[] ARCHER_WEST = new BufferedImage[4];

    Image[] TILE = new Image[4];

    //Animation Variables
    int currentFrame = 0, framePeriod = 150;
    long frameTicker = 0l;
    Boolean still = true;
    Boolean MOVING_NORTH = false, MOVING_SOUTH = false, MOVING_EAST = false, MOVING_WEST = false;

    BufferedImage player = ARCHER_SOUTH[0];

    //World Tile Variables
    //20 X 15 = 300 tiles 
    Rectangle[][] blocks = new Rectangle[20][15];
    Image[][] blockImg = new Image[20][15];
    int tileX = 0, tileY = 0;
    Random r = new Random();

    Rectangle playerRect = new Rectangle(x+4,y+20,32,20);
    Rectangle checkRect;

    //Map Navigation
    static final byte PAN_UP = 0, PAN_DOWN  = 1, PAN_LEFT = 2, PAN_RIGHT = 3;



    public Main(){

        this.setTitle("JAVA4K");
        this.setSize(640,505);
        this.setResizable(false);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);

        addKeyListener(new AL());

        TILE[0] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_GRASS_1.png").getImage();
        TILE[1] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_GRASS_2.png").getImage();
        TILE[2] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_GRASS_3.png").getImage();
        TILE[3] = new ImageIcon("C:/Users/Christophe/Documents/NetBeansProjects/Java4k/src/java4k/TILE_WATER_1.png").getImage();

        loadTiles();

        init();
    }

    //First called to store image tiles in blockImg[][] and tile rectangles in blocks[][]
    private void loadTiles(){
        tileX = tileY = 0;
        for(int i = 0; i < 20; i++){
            for(int j = 0; j < 15; j++){

                if(tileX>=640){
                    tileX = 0;
                    tileY += 32;
                }
                blockImg[i][j] = TILE[r.nextInt(4)];
                blocks[i][j] = new Rectangle(tileX, tileY, 32, 32);
                tileX += 32;
            }
        }
        System.out.println(blocks[2][0]);
    }

    //collision detection
    public boolean collide(Rectangle in)
    {
        for (int y = (int)((in.y) / 32)-1; y <= (int)((in.y+in.height) / 32)+1; y++){
            for (int x = (int)((in.x) / 32)-1; x <= (int)((in.x+in.width) / 32)+1; x++){
                if (x >= 0 && y >= 0 && x < 32 && y < 32){
                    if (blockImg[x][y] != null)
                    {
                        checkRect.setBounds(x*32,y*32, 32, 32);
                        if (in.intersects(checkRect))
                        {
                            return true;
                        }
                    }
                }
            }
        }

      return false;
    }

    //Key Listener
    public class AL extends KeyAdapter{
        public void keyPressed(KeyEvent e){

            int keyInput = e.getKeyCode();
            still = false;
            if(keyInput == e.VK_LEFT){

                navigateMap(PAN_RIGHT);
                MOVING_WEST = true;

            }if(keyInput == e.VK_RIGHT){

                navigateMap(PAN_LEFT);
                MOVING_EAST = true;

            }if(keyInput == e.VK_UP){

                navigateMap(PAN_DOWN);
                MOVING_NORTH = true;

            }if(keyInput == e.VK_DOWN){

                navigateMap(PAN_UP);
                MOVING_SOUTH = true;
            }
        }
        public void keyReleased(KeyEvent e){

            int keyInput = e.getKeyCode();
            setXDirection(0);
            setYDirection(0);
            still = true;
            MOVING_SOUTH  = false;
            MOVING_NORTH = MOVING_SOUTH = MOVING_EAST = MOVING_WEST = false;
            if(keyInput == e.VK_LEFT){

                player = ARCHER_WEST[0];

            }if(keyInput == e.VK_RIGHT){

                player = ARCHER_EAST[0];

            }if(keyInput == e.VK_UP){

                player = ARCHER_NORTH[0];

            }if(keyInput == e.VK_DOWN){

                player = ARCHER_SOUTH[0];
            }
        }
    }


    public void moveMap(){

        for(Rectangle[] r : blocks){
            for(Rectangle r2 : r){
                r2.x += xDirection;
                r2.y += yDirection;
            }
        }    
    }


    public void navigateMap(byte pan){
        switch(pan){
            default:
                System.out.println("Unrecognized pan!");
                break;
            case PAN_UP:
                setYDirection(-1);
                break;
            case PAN_DOWN:
                setYDirection(+1);
                break;
            case PAN_LEFT:
                setXDirection(-1);
                break;
            case PAN_RIGHT:
                setXDirection(+1);
                break;
        }
    }


    //Animation Update
    public void update(long gameTime) {

        if (gameTime > frameTicker + framePeriod) {
            frameTicker = gameTime;
            currentFrame++;
            if (currentFrame >= 4) {
                currentFrame = 0;
            }
        }
        if(MOVING_NORTH) player = ARCHER_NORTH[currentFrame];
        if(MOVING_SOUTH) player = ARCHER_SOUTH[currentFrame];
        if(MOVING_EAST) player = ARCHER_EAST[currentFrame];
        if(MOVING_WEST) player = ARCHER_WEST[currentFrame];
    }

    public void setXDirection(int xdir){

        xDirection = xdir;
    }

    public void setYDirection(int ydir){

        yDirection = ydir;
    }


    //Method to get sprites
    public BufferedImage grabSprite(int x, int y, int width, int height){
        BufferedImage sprite = spriteSheet.getSubimage(x, y, width, height);
        return sprite;
    }

    private void init(){    
        spriteSheet = null;
        try {
            spriteSheet = loadImage("ARCHER_SPRITESHEET.png");
        } catch (IOException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        }
        for(int i = 0; i <= 3; i++){
            ARCHER_NORTH[i] = grabSprite(i*16, 16, 16,16);
            ARCHER_SOUTH[i] = grabSprite(i*16, 0, 16, 16);
            ARCHER_EAST[i] = grabSprite(i*16, 32, 16, 16);
            ARCHER_WEST[i] = grabSprite(i*16, 48, 16, 16);
        }
    }

    public BufferedImage loadImage(String pathRelativeToThis) throws IOException{

        URL url = this.getClass().getResource(pathRelativeToThis);
        BufferedImage img = ImageIO.read(url);
        return img;
    }


    public void paint(Graphics g){

        dbImage = createImage(getWidth(), getHeight());
        dbGraphics = dbImage.getGraphics();
        paintComponent(dbGraphics);
        g.drawImage(dbImage, 0, 25, this);

    }

    public void paintComponent(Graphics g){
        requestFocus();

        //Draws tiles and rectangular boundaries for debugging
        for(int a = 0; a < 20; a++){
            for(int b = 0; b < 15; b++){
                if(blockImg[a][b] != null && blocks[a][b] != null){
                    g.drawImage(blockImg[a][b], blocks[a][b].x, blocks[a][b].y, 32, 32, null);
                    g.drawRect(blocks[a][b].x, blocks[a][b].y, 32, 32);
                } 
            }
        }   

        //Draw player and rectangular boundary for collision detection
        g.drawRect(playerRect.x, playerRect.y, playerRect.width, playerRect.height);
        g.drawImage(player, x, y, 40, 40, null);
        repaint();
    }

    public void run(){
        try{
            while(true){
                moveMap();
                if(!still) update(System.currentTimeMillis());
                Thread.sleep(13);
            }
        }catch(Exception e){
            System.out.println("RUNTIME ERROR: " + e);
        }    
    }



    public static void main(String[] args) {
        Main main = new Main();

        //Threads
        Thread thread1 = new Thread(main);
        thread1.start();
    }
}

我的错误如下:如果我要从 blocks[][] (一个存储用于碰撞检测的矩形的二维数组)中调用一个对象,它会给我带来完全不同的东西。例如,我取blocks[0][0](注意每个图块是一个 32 像素的正方形)。这个矩形的坐标是0,0。但是,如果我要绘制块 [1][0],这在逻辑上会给我(32;0),它会返回(480;0)。我几乎把头发拉出来试图找到造成这种情况的原因,我猜这是由于blocks[].x在某个地方被改变了,但我找不到在哪里。我试过打印出每个值blocks[][]在 draw 方法中查看问题在哪里,出于某种原因,在 loadTiles() 中一切都很好,突然间一切都搞砸了。提前感谢您的帮助,我希望我提供了足够的信息:)!

4

1 回答 1

0

loadTiles 似乎有错误。

您正在遍历每个 x,并且对于每个 x:
您正在遍历每个 y,并且对于每个 y:
将 blocks[x][y] 设置为 tileX, tileY
tileX += 32;

由于您在第二个循环中循环 y ,那不应该是
tileY += 32;

或者:

//First called to store image tiles in blockImg[][] and tile rectangles in blocks[][]
private void loadTiles(){
    tileX = tileY = 0;
    for(int i = 0; i < 20; i++){
        tileX = 32 * i;
        for(int j = 0; j < 15; j++){

            tyleY = 32 * j;

            blockImg[i][j] = TILE[r.nextInt(4)];
            blocks[i][j] = new Rectangle(tileX, tileY, 32, 32);
        }
    }
    System.out.println(blocks[2][0]);
}
于 2013-07-24T14:23:25.453 回答