简体   繁体   English

在Java中移动两个对象在同一个class上一个JFrame

[英]Moving two objects in the same class on a JFrame in Java

I have a project I am working on in that I have to create two objects, I would like the big rectangle(BLUE) to move around the frame every time I press the arrow keys on my keyboard while the small rectangle(RED) is moving away, once the big square touches/tags the small rectangle, screen refreshes and I can move the big rectangle again to chase down the small rectangle.我有一个正在处理的项目,因为我必须创建两个对象,每次我在小矩形(红色)移动时按下键盘上的箭头键时,我希望大矩形(蓝色)在框架周围移动离开,一旦大方块接触/标记小矩形,屏幕就会刷新,我可以再次移动大矩形来追逐小矩形。 Below is my main class, and IT class where I have implemented my two shapes.下面是我的主要 class 和 IT class,我在其中实现了两种形状。

The goal is to have the two rectangles, small rectangle runs away in the frame every time the big rectangle comes close until it's tagged.目标是让两个矩形,每次大矩形靠近时小矩形都会在框架中跑开,直到它被标记。 Would also have to add some kind of score panel on the frame to show updated scores and a timer to count down when the player starts playing.还必须在框架上添加某种分数面板以显示更新的分数和一个计时器以在玩家开始播放时倒计时。

I need help having the two rectangles move differently and not on top of each other.我需要帮助让两个矩形以不同方式移动而不是彼此重叠。 I would like the second rectangle to move away every time the first rectangle comes close to it moving around the Frame每当第一个矩形靠近它时,我希望第二个矩形在框架周围移动时移开

` `

My class IT

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

public class IT extends JPanel implements ActionListener, KeyListener {
    
    Timer shapeTimer = new Timer(5, this);

    public double xPos = 0, yPos = 0, movementX = 0, movementY = 0;

    public int rectSize = 50;
    public int rectSize2 = 35;

    public int windowWidth;
    int windowHeight;

    public int xBound;
    public int yBound;

    public IT(int w, int h){
        shapeTimer.start();

        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);

        windowWidth = w;
        windowHeight = h;

        xBound = (windowWidth - rectSize);
        yBound = (windowHeight - rectSize);
    }
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D) g;

        Rectangle2D movableRect = new Rectangle2D.Double(xPos, yPos, rectSize, rectSize);
        
        g2.setColor(Color.BLUE);
        g2.draw(movableRect);
        
        g2.fill(movableRect);
        
        Rectangle2D movableRect2 = new Rectangle2D.Double(xPos, yPos, rectSize2, rectSize2);
        g2.setColor(Color.RED);
        g2.draw(movableRect2);
        
        g2.fill(movableRect2);
     
    }

    public void actionPerformed(ActionEvent e){
        repaint();

        xPos += movementX;
        yPos += movementY;
    }

    public void moveUp(){
        if (yPos == 0){
            movementY = 0;
            movementX = 0;
        }
        movementY = -0.5;
        movementX = 0;
    }

    public void moveDown(){
        if (yPos == yBound){
            movementY = 0;
            movementX = 0;              
        }
        movementY = 0.5;
        movementX = 0;
    }
    public void moveLeft()
    {        
        if (xPos == 0){
            movementY = 0;
            movementX = 0;              
        }         
        movementX = -0.5;
        movementY = 0;
    }

    public void moveRight(){
        if (xPos == xBound)
        {
            movementY = 0;
            movementX = 0;
        }
            
        movementX = 0.5;
        movementY = 0;
    }

    public void enlargeSquare(){
        rectSize++;
        
        rectSize2++;
    }

    public void shrinkSquare(){
        rectSize--;
        
        rectSize2--;
    }

    public void keyPressed(KeyEvent e){
        int keyCode = e.getKeyCode();

        if (keyCode == KeyEvent.VK_UP){
            moveUp();
        }

        if (keyCode == KeyEvent.VK_DOWN){
            moveDown();
        }

        if (keyCode == KeyEvent.VK_RIGHT){
            moveRight();
        }

        if (keyCode == KeyEvent.VK_LEFT){
            moveLeft();
        }

        if (keyCode == KeyEvent.VK_OPEN_BRACKET)
        {
            shrinkSquare();
        }

        if (keyCode == KeyEvent.VK_CLOSE_BRACKET)
        {
            enlargeSquare();
        }
    }


    public void keyTyped(KeyEvent e){

    }

    public void keyReleased(KeyEvent e){
       int keyCode = e.getKeyCode();

        if (keyCode == KeyEvent.VK_UP){
            movementX = 0;
            movementY = 0;
        }

        if (keyCode == KeyEvent.VK_DOWN){
            movementX = 0;
            movementY = 0;
        }

        if (keyCode == KeyEvent.VK_RIGHT){
            movementX = 0;
            movementY = 0;
        }

        if (keyCode == KeyEvent.VK_UP){
            movementX = 0;
            movementY = 0;
        }               
    }

}

` MainTester class ` MainTester class

` `

import javax.swing.*;

import javax.swing.JFrame;

public class MainTester {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int frameWidth = 850;
        int frameHeight = 650;

        JFrame frmMain = new JFrame();
        frmMain.setSize(frameWidth, frameHeight);

        IT it = new IT(frameWidth, frameHeight);      
        frmMain.add(it);

        frmMain.setVisible(true);
        frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frmMain.setTitle("Tag Game");

    }

}

` `

Use key bindings , seriously, this is going to solve a swagger of issues related to KeyListener .使用键绑定,说真的,这将解决 swagger 与KeyListener相关的问题。

Decouple and seperate your logic.解耦和分离你的逻辑。 Each "entity" should be a self contained unit of work.每个“实体”应该是一个独立的工作单元。 In your case, they should contain information about their color, location and size at a minimum.在您的情况下,它们至少应包含有关颜色、位置和大小的信息。

For simplicity, I started out with something which could just be painted...为简单起见,我从一些可以涂漆的东西开始......

public interface Entity {
    public void paint(Graphics2D g2d);
}

Now, you could have a lot of different interface s which reflect this which can be painted, moved, controlled, represents effects or what ever you need - then your classes should implement the interface s they need.现在,你可以有很多不同的interface来反映它,它可以被绘制、移动、控制、代表效果或任何你需要的东西——然后你的类应该实现他们需要的interface Then, your engine just deals with the "concepts" it wants to - need all "paintable" entities, need all "movable" entities, etc, when it needs to.然后,您的引擎只处理它想要的“概念”——在需要时需要所有“可绘制”实体,需要所有“可移动”实体等。

Next I created a concept of a "player".接下来我创建了一个“玩家”的概念。 A player is a "paintable" entity, but which can be controlled by the player in some way, so it takes the current state of the "input"s and updates itself based on those states (more about that to come)玩家是一个“可绘制”实体,但可以通过某种方式由玩家控制,因此它采用当前 state 的“输入”并根据这些状态更新自身(更多信息即将到来)

public static class PlayerEntity implements Entity {
    
   protected static final int DELTA = 2;
    
    private Rectangle bounds = new Rectangle(0, 0, 35, 35);
    private Color fillColor;

    public PlayerEntity(Color fillColor, Point location) {
        this.fillColor = fillColor;
        this.bounds.setLocation(location);
    }

    public Color getFillColor() {
        return fillColor;
    }

    public Rectangle getBounds() {
        return bounds;
    }
    
    public Point getCenter() {
        return new Point((int)getBounds().getCenterX(), (int)getBounds().getCenterY());
    }
    
    public void update(Set<PlayerAction> actions, Dimension size) {
        Rectangle currentBounds = getBounds();
        int x = currentBounds.x;
        int y = currentBounds.y;
        
        if (actions.contains(PlayerAction.UP)) {
            y -= DELTA;
        }
        if (actions.contains(PlayerAction.DOWN)) {
            y += DELTA;
        }
        if (actions.contains(PlayerAction.LEFT)) {
            x -= DELTA;
        }
        if (actions.contains(PlayerAction.RIGHT)) {
            x += DELTA;
        }
        
        if (y < 0) {
            y = 0;
        }
        if (y + currentBounds.height > size.height) {
            y = size.height - currentBounds.height;
        }
        if (x < 0) {
            x = 0;
        }
        if (x + currentBounds.width > size.width) {
            x = size.width - currentBounds.width;
        }
        
        getBounds().setLocation(x, y);
    }

    @Override
    public void paint(Graphics2D g2d) {
        g2d.setColor(getFillColor());
        g2d.fill(getBounds());
    }
    
}

For reference, PlayerAction represents all the valid actions which can be performed by the player, for simplicity sake, I've just stuck to movement:作为参考, PlayerAction表示玩家可以执行的所有有效动作,为了简单起见,我只坚持移动:

public enum PlayerAction {
    UP, DOWN, LEFT, RIGHT;
}

Next I created a "monster" entity, in this case, the "monster" will always try and follow the player, this implementation is loosely based on Java: Move image towards mouse position接下来我创建了一个“怪物”实体,在这种情况下,“怪物”将始终尝试并跟随玩家,此实现大致基于Java:将图像移向鼠标 position

public static class MonsterEntity implements Entity {
    protected static final int DELTA = 1;

    private Rectangle bounds = new Rectangle(0, 0, 15, 15);
    private Color fillColor;

    public MonsterEntity(Color fillColor, Point location) {
        this.fillColor = fillColor;
        this.bounds.setLocation(location);
    }

    public Color getFillColor() {
        return fillColor;
    }

    public Rectangle getBounds() {
        return bounds;
    }
            
    public Point getCenter() {
        return new Point((int)getBounds().getCenterX(), (int)getBounds().getCenterY());
    }

    public void moveTowards(Point target) {
        Rectangle bounds = getBounds();
        Point center = getCenter();
        int xDelta = target.x < center.x ? -DELTA : DELTA;
        int yDelta = target.y < center.y ? -DELTA : DELTA;
        
        getBounds().setLocation(bounds.x + xDelta, bounds.y + yDelta);
    }

    @Override
    public void paint(Graphics2D g2d) {
        g2d.setColor(getFillColor());
        g2d.fill(getBounds());
    }
}

The monster is always trying to move it's center to the target location (which will eventually be the center of the player)怪物总是试图将它的中心移动到目标位置(最终将成为玩家的中心)

Now, this is where things become complicated.现在,这就是事情变得复杂的地方。

We need:我们需要:

  • A renderable surface onto which we can paint the player and monster(s)我们可以在其上绘制玩家和怪物的可渲染表面
  • Input bindings输入绑定
  • A "game loop" to update the state of the entities and schedule repaints更新实体的 state 和安排重绘的“游戏循环”

For simplicity, I started with a JPanel , made use of Swing Timer and the key bindings API.为简单起见,我从JPanel开始,使用 Swing Timer和键绑定 API。

public class MainPane extends JPanel {
    
    // This represents the "input bindings", these represent
    // abstract actions which can be applied to the player
    // or game state.
    private enum InputKey {
        PRESSED_UP, PRESSED_DOWN, PRESSED_LEFT, PRESSED_RIGHT,
        RELEASED_UP, RELEASED_DOWN, RELEASED_LEFT, RELEASED_RIGHT;
        
        public KeyStroke getKeyStroke() {
            switch (this) {
                case PRESSED_UP: return KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
                case PRESSED_DOWN: return KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false);
                case PRESSED_LEFT: return KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);
                case PRESSED_RIGHT: return KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
                case RELEASED_UP: return KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true);
                case RELEASED_DOWN: return KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true);
                case RELEASED_LEFT: return KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true);
                case RELEASED_RIGHT: return KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true);
            }
            return null;
        }
    }
    
    private PlayerEntity playerEntity;
    private MonsterEntity monsterEntity;
    private Timer timer;
    
    private Set<PlayerAction> actions = new HashSet<PlayerAction>();
    
    public MainPane() {
        InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = getActionMap();
        
        inputMap.put(InputKey.PRESSED_UP.getKeyStroke(), InputKey.PRESSED_UP);
        inputMap.put(InputKey.PRESSED_DOWN.getKeyStroke(), InputKey.PRESSED_DOWN);
        inputMap.put(InputKey.PRESSED_LEFT.getKeyStroke(), InputKey.PRESSED_LEFT);
        inputMap.put(InputKey.PRESSED_RIGHT.getKeyStroke(), InputKey.PRESSED_RIGHT);
        inputMap.put(InputKey.RELEASED_UP.getKeyStroke(), InputKey.RELEASED_UP);
        inputMap.put(InputKey.RELEASED_DOWN.getKeyStroke(), InputKey.RELEASED_DOWN);
        inputMap.put(InputKey.RELEASED_LEFT.getKeyStroke(), InputKey.RELEASED_LEFT);
        inputMap.put(InputKey.RELEASED_RIGHT.getKeyStroke(), InputKey.RELEASED_RIGHT);
        
        actionMap.put(InputKey.PRESSED_UP, new MoveAction(actions, PlayerAction.UP, true));
        actionMap.put(InputKey.PRESSED_DOWN, new MoveAction(actions, PlayerAction.DOWN, true));
        actionMap.put(InputKey.PRESSED_LEFT, new MoveAction(actions, PlayerAction.LEFT, true));
        actionMap.put(InputKey.PRESSED_RIGHT, new MoveAction(actions, PlayerAction.RIGHT, true));
        actionMap.put(InputKey.RELEASED_UP, new MoveAction(actions, PlayerAction.UP, false));
        actionMap.put(InputKey.RELEASED_DOWN, new MoveAction(actions, PlayerAction.DOWN, false));
        actionMap.put(InputKey.RELEASED_LEFT, new MoveAction(actions, PlayerAction.LEFT, false));
        actionMap.put(InputKey.RELEASED_RIGHT, new MoveAction(actions, PlayerAction.RIGHT, false));
        
        Dimension size = getPreferredSize();
        Point center = new Point((size.width - 35) / 2, (size.height - 35) / 2);
        
        playerEntity = new PlayerEntity(Color.BLUE, center);
        monsterEntity = new MonsterEntity(Color.RED, new Point(size.width - 15, size.height - 15));
    }

    @Override
    public void addNotify() {
        super.addNotify();
        if (timer != null) {
            timer.stop();
        }
        timer = new Timer(5, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                performTick();
            }
        });
        timer.start();
    }

    @Override
    public void removeNotify() {
        super.removeNotify();
        if (timer != null) {
            timer.stop();
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(400, 400);
    }
    
    protected void performTick() {
        playerEntity.update(actions, getSize());
        monsterEntity.moveTowards(playerEntity.getCenter());
        repaint();
    }
    
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        playerEntity.paint(g2d);
        monsterEntity.paint(g2d);
        g2d.dispose();
    }        
}

Movement (or input) is controlled through the key bindings API, this triggers a MoveAction which updates a centralised state repository (which is then passed to the PlayerEntity so it apply the state accordingly).移动(或输入)是通过键绑定 API 控制的,这会触发一个MoveAction ,它会更新集中式 state 存储库(然后传递给PlayerEntity ,以便它相应地应用 state)。

For simplicity, I've only used a single Action , but you could make a couple, one representing "press/activate" or "release/deactivate"为简单起见,我只使用了一个Action ,但你可以做一对,一个代表“按下/激活”或“释放/停用”

public class MoveAction extends AbstractAction {
    
    private Set<PlayerAction> actions;
    private PlayerAction action;
    private boolean activate;

    public MoveAction(Set<PlayerAction> directions, PlayerAction direction, boolean activate) {
        this.actions = directions;
        this.action = direction;
        this.activate = activate;
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        if (activate) {
            actions.add(action);
        } else {
            actions.remove(action);
        }
    }
    
}

See How to Use Actions for more details about actions.有关操作的更多详细信息,请参阅如何使用操作

But why follow this workflow?!但为什么要遵循这个工作流程?!

  1. It decouples and decentralises a lot of the workflows.它解耦和分散了许多工作流程。 In fact, if you really wanted to, you could also seperate out the Timer and "paint" workflows to seperate classes, further decoupling the classes.事实上,如果你真的想要,你也可以将Timer和“paint”工作流分离出来以分离类,进一步解耦类。
  2. Key bindings solve all the issues related to KeyListener weirdness.键绑定解决了与KeyListener怪异相关的所有问题。 It also decouples the input - want to add touch controls/buttons, no worries, it's done via Action s.它还分离了输入 - 想要添加触摸控件/按钮,不用担心,它是通过Action s 完成的。 Want to add joystick/controllers, no worries, it's done via Action s.想要添加操纵杆/控制器,不用担心,这是通过Action s 完成的。

Want more monsters?想要更多的怪物?

Change:改变:

private MonsterEntity monsterEntity;

to:到:

private List<MonsterEntity> monsterEntitys = new ArrayList<>(32);

Change:改变:

monsterEntity = new MonsterEntity(Color.RED, new Point(size.width - 15, size.height - 15));

to:到:

monsterEntitys.add(new MonsterEntity(Color.RED, new Point(size.width - 15, size.height - 15)));
monsterEntitys.add(new MonsterEntity(Color.RED, new Point(0, 0)));
monsterEntitys.add(new MonsterEntity(Color.RED, new Point(size.width - 15, 0)));
monsterEntitys.add(new MonsterEntity(Color.RED, new Point(0, size.height - 15)));

Change:改变:

monsterEntity.paint(g2d);

to:到:

for (MonsterEntity entity : monsterEntitys) {
    entity.paint(g2d);
}

And now you have more monsters!现在你有更多的怪物! Have fun with that!玩得开心!

Runnable example...可运行的例子...

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.HashSet;
import java.util.Set;
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.Timer;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new MainPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public enum PlayerAction {
        UP, DOWN, LEFT, RIGHT;
    }

    public class MainPane extends JPanel {

        private enum InputKey {
            PRESSED_UP, PRESSED_DOWN, PRESSED_LEFT, PRESSED_RIGHT,
            RELEASED_UP, RELEASED_DOWN, RELEASED_LEFT, RELEASED_RIGHT;

            public KeyStroke getKeyStroke() {
                switch (this) {
                    case PRESSED_UP: return KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false);
                    case PRESSED_DOWN: return KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false);
                    case PRESSED_LEFT: return KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false);
                    case PRESSED_RIGHT: return KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false);
                    case RELEASED_UP: return KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true);
                    case RELEASED_DOWN: return KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true);
                    case RELEASED_LEFT: return KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, true);
                    case RELEASED_RIGHT: return KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, true);
                }
                return null;
            }
        }

        private PlayerEntity playerEntity;
        private MonsterEntity monsterEntity;
        private Timer timer;

        private Set<PlayerAction> actions = new HashSet<PlayerAction>();

        public MainPane() {
            InputMap inputMap = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap actionMap = getActionMap();

            inputMap.put(InputKey.PRESSED_UP.getKeyStroke(), InputKey.PRESSED_UP);
            inputMap.put(InputKey.PRESSED_DOWN.getKeyStroke(), InputKey.PRESSED_DOWN);
            inputMap.put(InputKey.PRESSED_LEFT.getKeyStroke(), InputKey.PRESSED_LEFT);
            inputMap.put(InputKey.PRESSED_RIGHT.getKeyStroke(), InputKey.PRESSED_RIGHT);
            inputMap.put(InputKey.RELEASED_UP.getKeyStroke(), InputKey.RELEASED_UP);
            inputMap.put(InputKey.RELEASED_DOWN.getKeyStroke(), InputKey.RELEASED_DOWN);
            inputMap.put(InputKey.RELEASED_LEFT.getKeyStroke(), InputKey.RELEASED_LEFT);
            inputMap.put(InputKey.RELEASED_RIGHT.getKeyStroke(), InputKey.RELEASED_RIGHT);

            actionMap.put(InputKey.PRESSED_UP, new MoveAction(actions, PlayerAction.UP, true));
            actionMap.put(InputKey.PRESSED_DOWN, new MoveAction(actions, PlayerAction.DOWN, true));
            actionMap.put(InputKey.PRESSED_LEFT, new MoveAction(actions, PlayerAction.LEFT, true));
            actionMap.put(InputKey.PRESSED_RIGHT, new MoveAction(actions, PlayerAction.RIGHT, true));
            actionMap.put(InputKey.RELEASED_UP, new MoveAction(actions, PlayerAction.UP, false));
            actionMap.put(InputKey.RELEASED_DOWN, new MoveAction(actions, PlayerAction.DOWN, false));
            actionMap.put(InputKey.RELEASED_LEFT, new MoveAction(actions, PlayerAction.LEFT, false));
            actionMap.put(InputKey.RELEASED_RIGHT, new MoveAction(actions, PlayerAction.RIGHT, false));

            Dimension size = getPreferredSize();
            Point center = new Point((size.width - 35) / 2, (size.height - 35) / 2);

            playerEntity = new PlayerEntity(Color.BLUE, center);
            monsterEntity = new MonsterEntity(Color.RED, new Point(size.width - 15, size.height - 15));
        }

        @Override
        public void addNotify() {
            super.addNotify();
            if (timer != null) {
                timer.stop();
            }
            timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    performTick();
                }
            });
            timer.start();
        }

        @Override
        public void removeNotify() {
            super.removeNotify();
            if (timer != null) {
                timer.stop();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        protected void performTick() {
            playerEntity.update(actions, getSize());
            monsterEntity.moveTowards(playerEntity.getCenter());
            repaint();
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            playerEntity.paint(g2d);
            monsterEntity.paint(g2d);
            g2d.dispose();
        }        
    }

    public class MoveAction extends AbstractAction {

        private Set<PlayerAction> actions;
        private PlayerAction action;
        private boolean activate;

        public MoveAction(Set<PlayerAction> directions, PlayerAction direction, boolean activate) {
            this.actions = directions;
            this.action = direction;
            this.activate = activate;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (activate) {
                actions.add(action);
            } else {
                actions.remove(action);
            }
        }

    }

    public interface Entity {
        public void paint(Graphics2D g2d);
    }

    public static class MonsterEntity implements Entity {
        protected static final int DELTA = 1;

        private Rectangle bounds = new Rectangle(0, 0, 15, 15);
        private Color fillColor;

        public MonsterEntity(Color fillColor, Point location) {
            this.fillColor = fillColor;
            this.bounds.setLocation(location);
        }

        public Color getFillColor() {
            return fillColor;
        }

        public Rectangle getBounds() {
            return bounds;
        }

        public Point getCenter() {
            return new Point((int)getBounds().getCenterX(), (int)getBounds().getCenterY());
        }

        public void moveTowards(Point target) {
            Rectangle bounds = getBounds();
            Point center = getCenter();
            int xDelta = target.x < center.x ? -DELTA : DELTA;
            int yDelta = target.y < center.y ? -DELTA : DELTA;

            getBounds().setLocation(bounds.x + xDelta, bounds.y + yDelta);
        }

        @Override
        public void paint(Graphics2D g2d) {
            g2d.setColor(getFillColor());
            g2d.fill(getBounds());
        }
    }

    public static class PlayerEntity implements Entity {

       protected static final int DELTA = 2;

        private Rectangle bounds = new Rectangle(0, 0, 35, 35);
        private Color fillColor;

        public PlayerEntity(Color fillColor, Point location) {
            this.fillColor = fillColor;
            this.bounds.setLocation(location);
        }

        public Color getFillColor() {
            return fillColor;
        }

        public Rectangle getBounds() {
            return bounds;
        }

        public Point getCenter() {
            return new Point((int)getBounds().getCenterX(), (int)getBounds().getCenterY());
        }

        public void update(Set<PlayerAction> actions, Dimension size) {
            Rectangle currentBounds = getBounds();
            int x = currentBounds.x;
            int y = currentBounds.y;

            if (actions.contains(PlayerAction.UP)) {
                y -= DELTA;
            }
            if (actions.contains(PlayerAction.DOWN)) {
                y += DELTA;
            }
            if (actions.contains(PlayerAction.LEFT)) {
                x -= DELTA;
            }
            if (actions.contains(PlayerAction.RIGHT)) {
                x += DELTA;
            }

            if (y < 0) {
                y = 0;
            }
            if (y + currentBounds.height > size.height) {
                y = size.height - currentBounds.height;
            }
            if (x < 0) {
                x = 0;
            }
            if (x + currentBounds.width > size.width) {
                x = size.width - currentBounds.width;
            }

            getBounds().setLocation(x, y);
        }

        @Override
        public void paint(Graphics2D g2d) {
            g2d.setColor(getFillColor());
            g2d.fill(getBounds());
        }

    }
}

Other considerations...其他考虑...

Right now the speed/delta is actually really high.现在速度/增量实际上非常高。 I would consider making use of the Shape API, using things like Point2D and Rectangle2D which provide double based properties instead of int , which would give away to reduce the delta values and slow down the entities.我会考虑使用Shape API,使用Point2DRectangle2D之类的东西,它们提供基于double的属性而不是int ,这会减少增量值并减慢实体的速度。

See Working with Geometry for some more details有关更多详细信息,请参阅 使用几何

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM