java - 2D游戏相机逻辑

标签 java swing camera jpanel paintcomponent

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

掌握 normalocity's post 的诀窍,我尝试通过制作一个相机测试项目从简单开始,在该项目中我通过将 Sprite 绘制到 JPanel 来模拟相机,然后移动“相机”对象(即 JPanel)并设置 Sprite 的 x,y 相对对此。

正如我所说,Camera 是 JPanel...我添加了一个“world”,这是一个 x,y 为 0,0 的类,并且 w=1000,h=1000。我已经包含了 Sprite 相对于世界的位置以及相机。当我向上移动相机时, Sprite 向下移动,玩家如预期的那样留在中间..

enter image description here

但如果我继续按下, Sprite 似乎会不断地覆盖自己。

enter image description here

我的问题是:

  • 根据以下代码,我在实现相机方面是否走在正确的轨道上?
  • 为什么 Sprite 开始在那里画自己?它应该从 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;
    }   
}

Sprite 类:

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);      
    }


}

最佳答案

1) 您没有通过在 paintComponent(..) 中调用 super.paintComponent(g) 来尊重 paint 链:

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

    //do drawing here
}

根据 Java docs :

protected void paintComponent(Graphics g)

Further, if you do not invoker super's implementation you must honor the opaque property, that is if this component is opaque, you must completely fill in the background in a non-opaque color. If you do not honor the opaque property you will likely see visual artifacts.

2) 同时注意 @Override annotation我补充说,事实上我将 public 修饰符更改为 protected 因为这就是实现类中定义的访问级别,除非出于特定原因,否则我们应该保留它。

3) Swing 还使用 Keybindings 读取 How to Use Key Bindings

4) 也可以阅读 Concurrency in Swing具体在 The Event Dispatch Thread它指示所有 swing 组件都通过 SwingUtilities.invokeXXX(..) block 在 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
    }
}

关于java - 2D游戏相机逻辑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17954220/

相关文章:

java - 使用 OSGi 将 JMenuItems 附加到 GUI

使用 GridBagLayout 调整 Java Swing 组件的大小

c# - 在 Xamarin.Forms 中访问相机

java - 使用 java 的 FTPS 连接构建器在连接打开后使用与标准 ftp/sftp 相同的功能

java - 使用 Arrays.sort 对数组元素进行排序

java - JTable:WAITING根据用户输入选择行

ios - 从相机获取 yuv 平面格式图像 - iOS

android - 在 Android webview 中访问相机功能?

java - 使用 '%' 将 String 转换为 double

java - 使用java程序将数据复制到ftp时的文件大小差异