2D游戏相机逻辑

时间:2013-07-30 18:05:21

标签: java swing camera jpanel

我正在尝试为我正在制作的2D游戏实现一个摄像头......目标是让摄像头将玩家保持在中心,将精灵保持在相对于摄像头的位置。

为了解决normalocity's post的问题,我尝试通过制作一个Camera Test项目开始简单,我通过将一个精灵绘制到一个JPanel来模拟一个相机,并移动一个“相机”对象(是JPanel)并设置精灵的x,y相对于它。

正如我所说,相机是JPanel ......我添加了一个“世界”,这是一个x,y of 0,0w=1000, h=1000的类。我已经包含了精灵相对于世界的位置以及相机。当我向上移动相机时,精灵向下移动,玩家按预期保持在中间位置。

enter image description here

但如果我继续按下,那么精灵似乎不停地掠过自己。

enter image description here

我的问题是:

  • 根据以下代码,我是否正在实施相机?
  • 为什么精灵开始在那里画画?它应该从viewPort / JPanel
  • 中消失

谢谢!

现在添加了PaintComponent(g),我的JPanel bg灰色现在滑落了。这应该发生吗?

enter image description here


编辑:我的计划的SSCCE:

主要类别:

import java.awt.Dimension;
import java.awt.Toolkit;
import javax.swing.JFrame;

@SuppressWarnings("serial")
public class MainSSCCE extends JFrame {
static MainSSCCE runMe;

public MainSSCCE() {
    JFrame f = new JFrame("Camera Test");
    CameraSSCCE cam = new CameraSSCCE(0, 0, 500, 500);
    f.add(cam);
    f.setSize(cam.getWidth(), cam.getHeight());    
    f.setVisible(true);
    f.setResizable(false);
    f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE ); 
    Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
    f.setLocation( (screensize.width - f.getWidth())/2,
         (screensize.height - f.getHeight())/2-100 );
}

public static void main(String[] args) {
    runMe = new MainSSCCE();
}
}

相机类:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JPanel;

//Camera is the JPanel that will draw all objects... each object location will be in relation to the World
public class CameraSSCCE extends JPanel implements KeyListener {
    //add world to camera...
    private static final long serialVersionUID = 1L;
    private int camX, camY, camH, camW;
    private SpriteSSCCE sprite;
    private PlayerSSCCE player;
    private WorldSSCCE world;

    public CameraSSCCE(int x, int y, int w, int h) {
        camX = x;
        camY = y;
        camW = w;       
        camH = h;   
        sprite = new SpriteSSCCE(this, 300, 300, 20, 20);
        player = new PlayerSSCCE(this, camW/2, camH/2, 25, 40);
        world = new WorldSSCCE(this, 0, 0, 1000, 1000);

        addKeyListener(this);
        setFocusable(true);
    }

    public int getWidth() {
        return camW;
    }

    public int getHeight() {
        return camH;
    }    

    @Override   
    protected void paintComponent(Graphics g) { 
        super.paintComponent(g);

        //cam is 500 x 500
        g.setColor(Color.gray);
        g.fillRect(camX, camY, camW, camH);     

        //draw sprite at JPanel location if in camera sight
        if (((sprite.getX()-camX) >= camX) && ((sprite.getX()-camX) <= (camX+camW)) && ((sprite.getY()-camY) >= camY) && ((sprite.getY()-camY) <= (camY+camH))) {
            g.setColor(Color.green);
            g.fillRect(sprite.getX()-camX, sprite.getY()-camY, 20, 20); 

            //Cam Sprite Location
            g.setColor(Color.white);
            g.drawString("Camera Sprite Location: (" + (sprite.getX()-camX) + ", " + (sprite.getY()-camY) + ")", sprite.getX()-camX, sprite.getY()-camY);                   
        }

        //Player location (center of Camera... Camera follows player)
        g.setColor(Color.cyan);
        g.fillRect(player.getX()-player.getWidth(), player.getY()-player.getWidth(), player.getWidth(), player.getHeight());

        g.setColor(Color.white);
        //World Sprite Location
        g.drawString("World Sprite Location: (" + sprite.getX() + ", " + sprite.getY() + ")", sprite.getX(), sprite.getY());

        //Cam Player Location
        g.drawString("Cam Player Location: (" + (camW/2-player.getWidth()) + ", " + (camH/2-player.getHeight()) + ")", camW/2-player.getWidth(), camH/2-player.getHeight());
    }

    public void keyPressed(KeyEvent e) {
        //move camera right in relation to World
        if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
            camX+=5;
        }
        //move camera left in relation to World
        if (e.getKeyCode() == KeyEvent.VK_LEFT) {
            camX-=5;
        }
        //move camera up in relation to World
        if (e.getKeyCode() == KeyEvent.VK_UP) {
            camY-=5;
        }
        //move camera down in relation to World
        if (e.getKeyCode() == KeyEvent.VK_DOWN) {
            camY+=5;
        }
        repaint();
    }   

    public void keyReleased(KeyEvent e) {}
    public void keyTyped(KeyEvent e) {}

}

世界级:

public class WorldSSCCE {
    private int x, y, w, h;
    private CameraSSCCE camera;

    public WorldSSCCE(CameraSSCCE cam, int x, int y, int w, int h) {
        camera = cam;               
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;  
    }

    public int getWidth() {
        return this.w;
    }

    public int getHeight() {
        return this.h;
    }
}

玩家等级:

import java.awt.Dimension;

public class PlayerSSCCE {
    private int x, y, w, h;
    private CameraSSCCE cam;

    public PlayerSSCCE(CameraSSCCE cm, int x, int y, int w, int h) {
        cam = cm;               
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
    }

    public int getX() {
        return this.x;
    }

    public int getY() {
        return this.y;  
    }

    public int getWidth() {
        return this.w;
    }

    public int getHeight() {
        return this.h;
    }

    public void setX(int val) {
        this.x += val;
    }

    public void setY(int val) {
        this.y += val;
    }   
}

精灵类:

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

public class SpriteSSCCE {
    private int xLoc, yLoc, width, height;
    private CameraSSCCE world;

    public SpriteSSCCE(CameraSSCCE wld, int x, int y, int w, int h) {
        xLoc = x;
        yLoc = y;
        width = w;
        height = h;
        world = wld;    
    }

    public int getX() {
        return xLoc;
    }

    public int getY() {
        return yLoc;    
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }


    public void paintComponent(Graphics g) {
        g.setColor(Color.green);
        g.fillRect(xLoc, yLoc, width, height);      
    }


}

2 个答案:

答案 0 :(得分:3)

1)通过调用super.paintComponent(g)中的paintComponent(..),您没有兑现彩绘链

@Override
protected void paintComponent(Graphics g) {    
    super.paintComponent(g);

    //do drawing here
}

根据Java docs

  

protected void paintComponent(Graphics g)

     

此外,如果你没有邀请超级实施,你必须尊重   opaque属性,即如果此组件是不透明的,则必须   以非不透明的颜色完全填充背景。如果你不   尊重不透明属性,你可能会看到视觉文物。

2)另请注意我添加的@Override annotation以及我将public修饰符更改为protected的事实,因为我们应该保留的实现类中定义了访问级别的内容除非出于特定原因。

3)另外Swing使用Keybinding s读取How to Use Key Bindings

4)同时在Concurrency in Swing上专门阅读The Event Dispatch Thread,其中规定通过SwingUtillities.invokeXXX(..)块在EDT上创建所有摇摆组件:

SwingUtilities.invokeLater(new Runnable() {
   @Override
    public void run() {
         //create and manipulate swing components here
    }
});

5)你扩展JFrame类并创建一个实例,这不是你想要的,而是从类声明中删除 extends JFrame

public class MainSSCCE extends JFrame { //<-- Remove extends JFrame

    public MainSSCCE() {
       JFrame f = new JFrame("Camera Test");//<-- instance is created here
    }
}

答案 1 :(得分:2)

你的世界是一个比屏幕大的虚拟区域(或者你的jpanel重要的东西)。所有物体的位置都与世界相关。我们称之为绝对坐标。

您的相机是世界上的一个小矩形部分(您的面板)。通过移动它你会看到不同的世界部分。如果您可以像链接到的帖子那样移动相机,那么在某些时候您将无法同时看到播放器和其他精灵。

由于你的目标是让玩家在屏幕上居中,这对我们的世界意味着什么?这意味着玩家和相机一起移动与世界相关。

鉴于上述情况,在第一张截图中绘制相机精灵没有意义。相机精灵应该是不可见的,或者它应该与玩家精灵一起绘制在相同的位置。在不改变播放器的情况下更改相机的绝对坐标也没有意义。这两个人在一起移动。 (在keyPressed()方法中考虑到这一点)

现在绘画时,您正在从相机的角度绘制(或者换句话说,在相机的坐标系中)。从这个角度来看,相机总是会看到(0, 0, cameraWidth, cameraHeight)的矩形。这是清除灰色区域时应该使用的。这将解决您的移动背景问题。由于相机和播放器始终具有相同的绝对坐标,因此播放器将始终位于相同的位置(这就是我们想要的)。其余的精灵将相对于相机看到。

对于它们中的每一个,当你执行(sprite.x - cam.x)和(sprite.y - cam.y)时,你可以在相机的坐标系中进行平移。由于它们已翻译,您只需要检查它们是否在相机的矩形(0, 0, cameraWidth, cameraHeight)内。如果他们是你继续画它们。如果不理睬它们。

我希望有帮助

注意:cameraWidth, cameraHeight是您的jpanel维度