我正在尝试在Java Applet中开发2D RPG游戏。现在我有一个简单的椭圆形,玩家可以使用左,右,上和下移动,并且与小程序边界的碰撞会阻止它们。问题是,我想创造一个玩家可以移动的巨大世界(2000px乘2000x)的区域。但是,我希望他们一次只能看到600px到400x的屏幕。如果他们继续向前移动,我希望屏幕跟随他们,同样是向上,向下和向左。谁能告诉我怎么做?到目前为止,这是我的代码:
import java.awt.*;
import java.awt.event.KeyEvent;
import java.applet.Applet;
import java.awt.event.KeyListener;
import javax.swing.*;
public class Main extends Applet implements Runnable, KeyListener
{
private Image dbImage;
private Graphics dbg;
Thread t1;
int x = 0;
int y = 0;
int prevX = x;
int prevY = y;
int radius = 40;
boolean keyReleased = false;
public void init()
{
setSize(600, 400);
}
public void start()
{
addKeyListener(this);
t1 = new Thread(this);
t1.start();
}
public void destroy()
{
}
public void stop()
{
}
public void paint(Graphics g)
{
//player
g.setColor(Color.RED);
g.fillOval(x, y, radius, radius);
}
public void update(Graphics g)
{
dbImage = createImage (this.getSize().width, this.getSize().height);
dbg = dbImage.getGraphics();
// initialize buffer
if (dbImage == null)
{
}
// clear screen in background
dbg.setColor(getBackground());
dbg.fillRect(0, 0, this.getSize().width, this.getSize().height);
// draw elements in background
dbg.setColor(getForeground());
paint(dbg);
// draw image on the screen
g.drawImage(dbImage, 0, 0, this);
}
@Override
public void run()
{
while (true)
{
//x++;
repaint();
try
{
t1.sleep(17);
}
catch (Exception e)
{
}
}
}
public boolean CheckCollision(String dir)
{
if (x <= 0 && dir.equals("L"))
{
x = prevX;
return true;
}
else if (y <= 0 && dir.equals("U"))
{
y = prevY;
return true;
}
else if (x >= (getWidth() - radius) && dir.equals("R"))
{
System.out.println(getWidth());
x = prevX;
return true;
}
else if (y >= (getHeight() - radius) && dir.equals("D"))
{
y = prevY;
return true;
}
return false;
}
@Override
public void keyPressed(KeyEvent e)
{
switch (e.getKeyCode())
{
case KeyEvent.VK_RIGHT:
if (!CheckCollision("R"))
{
x += 4;
prevX = x;
}
break;
case KeyEvent.VK_LEFT:
if (!CheckCollision("L"))
{
x -= 4;
prevX = x;
}
break;
case KeyEvent.VK_UP:
if (!CheckCollision("U"))
{
y -= 4;
prevY = y;
}
break;
case KeyEvent.VK_DOWN:
if (!CheckCollision("D"))
{
y += 4;
prevY = y;
}
break;
}
}
@Override
public void keyReleased(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0)
{
// TODO Auto-generated method stub
}
}
答案 0 :(得分:7)
这是滚动可视区域的基本示例,其中虚拟世界比视图区域大。
这基本上维护了许多参数。它保持了世界上视图的顶部/左侧和玩家在世界中的位置。
这些值将转换回真实世界坐标(其中0x0是可视区域的左上角)。
这些示例还使用BufferedImage#getSubImage
来简化渲染。您也可以计算地图到视图的偏移位置,但这可以归结为需要......
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class MiddleEarth {
public static void main(String[] args) {
new MiddleEarth();
}
public MiddleEarth() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new WorldPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class WorldPane extends JPanel {
private BufferedImage map;
private BufferedImage party;
private Point viewPort;
private Point partyPoint;
private BufferedImage view;
public WorldPane() {
try {
map = ImageIO.read(getClass().getResource("/MiddleEarth.jpg"));
party = ImageIO.read(getClass().getResource("/8BitFrodo.png"));
viewPort = new Point(0, (map.getHeight() / 2) - 100);
partyPoint = new Point(party.getWidth() / 2, (map.getHeight() / 2)); // Virtual Point...
} catch (IOException exp) {
exp.printStackTrace();
}
InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
ActionMap am = getActionMap();
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "goRight");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "goLeft");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "goUp");
im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "goDown");
am.put("goRight", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
moveParty(10, 0);
}
});
am.put("goLeft", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
moveParty(-10, 0);
}
});
am.put("goUp", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
moveParty(0, -10);
}
});
am.put("goDown", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
moveParty(0, 10);
}
});
}
protected void moveParty(int xDelta, int yDelta) {
partyPoint.x += xDelta;
partyPoint.y += yDelta;
Point view = fromWorld(partyPoint);
if (view.x > getWidth() - (party.getWidth() / 2)) {
viewPort.x += xDelta;
if (viewPort.x + getWidth() > map.getWidth()) {
viewPort.x = map.getWidth() - getWidth();
partyPoint.x = map.getWidth() - (party.getWidth() / 2) - 1;
}
invalidate();
} else if (view.x < party.getWidth() / 2) {
viewPort.x += xDelta;
if (viewPort.x < 0) {
viewPort.x = 0;
partyPoint.x = (party.getWidth() / 2);
}
invalidate();
}
System.out.println(view + "; " + getHeight());
if (view.y > getHeight() - (party.getHeight() / 2)) {
viewPort.y += yDelta;
if (viewPort.y + getHeight() > map.getHeight()) {
viewPort.y = map.getHeight() - getHeight();
partyPoint.y = map.getHeight() - (party.getHeight() / 2) - 1;
}
invalidate();
} else if (view.y < party.getHeight() / 2) {
viewPort.y += yDelta;
if (viewPort.y < 0) {
viewPort.y = 0;
partyPoint.y = (party.getHeight() / 2);
}
invalidate();
}
repaint();
}
@Override
public void invalidate() {
view = null;
super.invalidate();
}
public BufferedImage getView() {
if (view == null && getWidth() > 0 && getHeight() > 0) {
view = map.getSubimage(viewPort.x, viewPort.y, getWidth(), getHeight());
}
return view;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
if (map != null) {
g2d.drawImage(getView(), 0, 0, this);
Point real = fromWorld(partyPoint);
int x = real.x - (party.getWidth() / 2);
int y = real.y - (party.getHeight()/ 2);
g2d.drawImage(party, x, y, this);
}
g2d.dispose();
}
protected Point fromWorld(Point wp) {
Point p = new Point();
p.x = wp.x - viewPort.x;
p.y = wp.y - viewPort.y;
return p;
}
}
}
答案 1 :(得分:1)
这就是我在引擎中的表现。
我会保留两个变量OffSetX
和OffSetY
并计算每一步以使玩家居中这样。
OffSetX = 0;
OffSetY = 0;
if (MAP_WIDTH > WINDOW_WIDTH) {
OffSetX = Math.round(WINDOW_WIDTH / 2 - obj.getX() - TILE_SIZE);
OffSetX = Math.min(OffSetX, 0);
OffSetX = Math.max(OffSetX, WINDOW_WIDTH - MAP_WIDTH);
}
if (MAP_HEIGHT > WINDOW_HEIGHT) {
OffSetY = Math.round(WINDOW_HEIGHT / 2 - obj.getY() - TILE_SIZE);
OffSetY = Math.min(OffSetY, 0);
OffSetY = Math.max(OffSetY, WINDOW_HEIGHT - MAP_HEIGHT);
}
然后在(OffSetX, OffSetY)
位置绘制地图,即将这些地图添加到要绘制的对象的原始位置。
您可能希望跳过不可见的渲染对象。