Java 蛇类游戏如何使尾巴跟随头部?

Java 蛇类游戏如何使尾巴跟随头部?,java,swing,Java,Swing,我在做一个蛇的游戏,我被困在尾巴跟着头的地方。我听说在头部和尾部使用添加和删除可以实现这一点,但我不知道从哪里开始 以下是我目前的代码: Screen.java public class Screen extends JPanel implements ActionListener, KeyListener { public static final JLabel statusbar = new JLabel("Default"); public static final int

我在做一个蛇的游戏,我被困在尾巴跟着头的地方。我听说在头部和尾部使用添加和删除可以实现这一点,但我不知道从哪里开始

以下是我目前的代码:

Screen.java

public class Screen extends JPanel implements ActionListener, KeyListener {
    public static final JLabel statusbar = new JLabel("Default");
    public static final int WIDTH = 800, HEIGHT = 800;
    Timer t = new Timer(100, this);
    int x = 400;
    int y = 400;
    int size = 5; //increase size if eat 
    private boolean right = false, left = false, up = false, down = false;

    int head = 0;

    private LinkedList<BodyPart> snake = new LinkedList<BodyPart>();
    private BodyPart b;

    public Screen(){

        initSnake();

        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    public void update(){

    }

    public void direction(){
        if(right) x+=10;
        if(left) x-=10;
        if(up) y-=10;
        if(down) y+=10;
    }

    public void trackOutBound(){
        if(x < 0 || x > 800 || y < 0 || y > 800) {
            x = 400;
            y = 400;
        }
    }

    public void initSnake(){
        if(snake.size() == 0){
            b = new BodyPart(x, y);
            for(int i = 0; i < size; i++) {
                snake.add(b);
            }
            System.out.println(snake);
        }
    }

    public static void main(String[] args) {

    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(new Color(10, 50, 0));
        g.fillRect(0, 0, WIDTH, HEIGHT);

        g.setColor(Color.BLACK);
        for(int i = 0; i < WIDTH / 10; i++) {
            g.drawLine(i * 10, 0, i * 10, HEIGHT);
        }

        for(int i = 0; i < HEIGHT / 10; i++) {
            g.drawLine(0, i * 10, WIDTH, i * 10);
        }

        int tempx = 0, tempy = 0;
        int temp = 0;
        for(int i = 0; i < size; i++){
            if(i == head) {
                snake.get(i).x = x;
                snake.get(i).y = y;
                snake.get(i).draw(g);
                g.setColor(Color.blue);
                g.fillRect(x, y, 10, 10);
                g.setColor(Color.white);
                g.drawRect(x, y, 10, 10);
            } else if(i > 0 && up) {
                snake.get(i).x = x;
                snake.get(i).y = y + temp;
                snake.get(i).draw(g);
            } else if(i > 0 && down) {
                snake.get(i).x = x;
                snake.get(i).y = y - temp;
                snake.get(i).draw(g);
            } else if(i > 0 && left) {
                snake.get(i).x = x + temp;
                snake.get(i).y = y;
                snake.get(i).draw(g);
            } else if(i > 0 && right) {
                snake.get(i).x = x - temp;
                snake.get(i).y = y;
                snake.get(i).draw(g);
            }
            temp += 10;
        }

        /*
        if(snake.size() == 5){
            snake.add(b);
            size += 1;
        }
                */

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        direction();
        trackOutBound();
        repaint();        
       // System.out.println(snake);
        statusbar.setText("(" + x + " , " + y + ")");
    }

    @Override
    public void keyTyped(KeyEvent e) {}

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == KeyEvent.VK_RIGHT && !left) { 
            up = false;
            down = false;
            right = true;
        }
        if(key == KeyEvent.VK_LEFT && !right) { 
                up = false;
                down = false;
                left = true;
        }
        if(key == KeyEvent.VK_UP && !down) {
                left = false;
                right = false;
                up = true;
        }
        if(key == KeyEvent.VK_DOWN && !up) {
                left = false;
                right = false;
                down = true;
        } 
    }

    @Override
    public void keyReleased(KeyEvent e) {}
}
public class BodyPart {

    int x;
    int y;

    public BodyPart(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void draw(Graphics g) {
        this.x = x;
        this.y = y;
    g.setColor(Color.red);
        g.fillRect(x, y, 10, 10);
        g.setColor(Color.white);
        g.drawRect(x, y, 10, 10);
    }
}
public class Frame extends JPanel {
    private static JLabel statusbar = new JLabel("Default");

    public void statusbar(){
        statusbar = Screen.statusbar;
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        Screen s = new Screen();
        f.add(s);

        f.add(statusbar, BorderLayout.SOUTH);
        f.setSize(800, 800);
        f.setVisible(true);
        f.setLocationRelativeTo(null);
        f.setResizable(false);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}
Frame.java

public class Screen extends JPanel implements ActionListener, KeyListener {
    public static final JLabel statusbar = new JLabel("Default");
    public static final int WIDTH = 800, HEIGHT = 800;
    Timer t = new Timer(100, this);
    int x = 400;
    int y = 400;
    int size = 5; //increase size if eat 
    private boolean right = false, left = false, up = false, down = false;

    int head = 0;

    private LinkedList<BodyPart> snake = new LinkedList<BodyPart>();
    private BodyPart b;

    public Screen(){

        initSnake();

        t.start();
        addKeyListener(this);
        setFocusable(true);
        setFocusTraversalKeysEnabled(false);
    }

    public void update(){

    }

    public void direction(){
        if(right) x+=10;
        if(left) x-=10;
        if(up) y-=10;
        if(down) y+=10;
    }

    public void trackOutBound(){
        if(x < 0 || x > 800 || y < 0 || y > 800) {
            x = 400;
            y = 400;
        }
    }

    public void initSnake(){
        if(snake.size() == 0){
            b = new BodyPart(x, y);
            for(int i = 0; i < size; i++) {
                snake.add(b);
            }
            System.out.println(snake);
        }
    }

    public static void main(String[] args) {

    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        g.setColor(new Color(10, 50, 0));
        g.fillRect(0, 0, WIDTH, HEIGHT);

        g.setColor(Color.BLACK);
        for(int i = 0; i < WIDTH / 10; i++) {
            g.drawLine(i * 10, 0, i * 10, HEIGHT);
        }

        for(int i = 0; i < HEIGHT / 10; i++) {
            g.drawLine(0, i * 10, WIDTH, i * 10);
        }

        int tempx = 0, tempy = 0;
        int temp = 0;
        for(int i = 0; i < size; i++){
            if(i == head) {
                snake.get(i).x = x;
                snake.get(i).y = y;
                snake.get(i).draw(g);
                g.setColor(Color.blue);
                g.fillRect(x, y, 10, 10);
                g.setColor(Color.white);
                g.drawRect(x, y, 10, 10);
            } else if(i > 0 && up) {
                snake.get(i).x = x;
                snake.get(i).y = y + temp;
                snake.get(i).draw(g);
            } else if(i > 0 && down) {
                snake.get(i).x = x;
                snake.get(i).y = y - temp;
                snake.get(i).draw(g);
            } else if(i > 0 && left) {
                snake.get(i).x = x + temp;
                snake.get(i).y = y;
                snake.get(i).draw(g);
            } else if(i > 0 && right) {
                snake.get(i).x = x - temp;
                snake.get(i).y = y;
                snake.get(i).draw(g);
            }
            temp += 10;
        }

        /*
        if(snake.size() == 5){
            snake.add(b);
            size += 1;
        }
                */

    }

    @Override
    public void actionPerformed(ActionEvent e) {
        direction();
        trackOutBound();
        repaint();        
       // System.out.println(snake);
        statusbar.setText("(" + x + " , " + y + ")");
    }

    @Override
    public void keyTyped(KeyEvent e) {}

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        if(key == KeyEvent.VK_RIGHT && !left) { 
            up = false;
            down = false;
            right = true;
        }
        if(key == KeyEvent.VK_LEFT && !right) { 
                up = false;
                down = false;
                left = true;
        }
        if(key == KeyEvent.VK_UP && !down) {
                left = false;
                right = false;
                up = true;
        }
        if(key == KeyEvent.VK_DOWN && !up) {
                left = false;
                right = false;
                down = true;
        } 
    }

    @Override
    public void keyReleased(KeyEvent e) {}
}
public class BodyPart {

    int x;
    int y;

    public BodyPart(int x, int y) {
        this.x = x;
        this.y = y;
    }
    public void draw(Graphics g) {
        this.x = x;
        this.y = y;
    g.setColor(Color.red);
        g.fillRect(x, y, 10, 10);
        g.setColor(Color.white);
        g.drawRect(x, y, 10, 10);
    }
}
public class Frame extends JPanel {
    private static JLabel statusbar = new JLabel("Default");

    public void statusbar(){
        statusbar = Screen.statusbar;
    }

    public static void main(String[] args) {
        JFrame f = new JFrame();
        Screen s = new Screen();
        f.add(s);

        f.add(statusbar, BorderLayout.SOUTH);
        f.setSize(800, 800);
        f.setVisible(true);
        f.setLocationRelativeTo(null);
        f.setResizable(false);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }
}
现在这个代码只能使尾巴翻转到水平或垂直方向,使用这个代码可以使尾巴跟随头部吗?或者我需要更改代码


感谢您

蛇形移动,您可以从尾部到头部,将每个
身体部位
位置移动到前面的
身体部位
位置。对于头部,前面没有零件,因此您必须编写决策代码,决定是简单地移动与前面零件相同的方向,还是基于输入的新方向。然后更新屏幕。

对于蛇形运动,您可以从尾部到头部,将每个
身体部位
位置移动到前面的
身体部位
位置。对于头部,前面没有零件,因此您必须编写决策代码,决定是简单地移动与前面零件相同的方向,还是基于输入的新方向。然后更新屏幕。

基本思想是,您需要某种包含蛇的所有点的
列表。从概念上讲,
列表
将包含虚拟坐标,即
1x1
将表示虚拟空间中的坐标,该坐标表示虚拟板上的一个位置(具有一定的宽度和高度)

然后可以将其转换到屏幕上,这样就可以使蛇的每个部分都比单个像素大。因此,如果每个部分都是
5x5
像素,那么
1x1
实际上就是屏幕上的
5x5

每次蛇移动时,您都会向头部添加一个新值,并从尾部删除最后一个值(假设它没有增长)。当需要绘制蛇时,只需在
列表上迭代,绘制蛇的每个点

下面是一个简单的示例,它使用一个
链接列表
,将一个新的
推到
列表
,创建一个新的头部,并删除每个循环中的最后一个元素(尾部)

这基本上可以归结为

snakeBody.removeLast();
snakeBody.push(new Point(xPos, yPos));
作为一个可运行的概念

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.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Snake {

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

    public Snake() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        public enum Direction {

            UP, DOWN, LEFT, RIGHT
        }

        private int xPos, yPos;

        private Direction direction = Direction.UP;

        private LinkedList<Point> snakeBody = new LinkedList<>();

        public TestPane() {
            xPos = 100;
            yPos = 100;

            for (int index = 0; index < 50; index++) {
                snakeBody.add(new Point(xPos, yPos));
            }

            bindKeyStrokeTo("up.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), new MoveAction(Direction.UP));
            bindKeyStrokeTo("down.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), new MoveAction(Direction.DOWN));

            bindKeyStrokeTo("left.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0, false), new MoveAction(Direction.LEFT));
            bindKeyStrokeTo("right.pressed", KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0, false), new MoveAction(Direction.RIGHT));

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    switch (direction) {
                        case UP:
                            yPos--;
                            break;
                        case DOWN:
                            yPos++;
                            break;
                        case LEFT:
                            xPos--;
                            break;
                        case RIGHT:
                            xPos++;
                            break;
                    }
                    if (yPos < 0) {
                        yPos--;
                    } else if (yPos > getHeight() - 1) {
                        yPos = getHeight() - 1;
                    }
                    if (xPos < 0) {
                        xPos--;
                    } else if (xPos > getWidth() - 1) {
                        xPos = getWidth() - 1;
                    }

                    snakeBody.removeLast();
                    snakeBody.push(new Point(xPos, yPos));
                    repaint();
                }
            });
            timer.start();
        }

        public void bindKeyStrokeTo(String name, KeyStroke keyStroke, Action action) {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(keyStroke, name);
            am.put(name, action);
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.RED);
            for (Point p : snakeBody) {
                g2d.drawLine(p.x, p.y, p.x, p.y);
            }
            g2d.dispose();
        }

        public class MoveAction extends AbstractAction {

            private Direction moveIn;

            public MoveAction(Direction direction) {
                this.moveIn = direction;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                direction = this.moveIn;
            }

        }

    }

}
导入java.awt.Color;
导入java.awt.Dimension;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.awt.Graphics2D;
导入java.awt.Point;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.KeyEvent;
导入java.util.LinkedList;
导入javax.swing.AbstractAction;
导入javax.swing.Action;
导入javax.swing.ActionMap;
导入javax.swing.InputMap;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.KeyStroke;
导入javax.swing.Timer;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公营蛇{
公共静态void main(字符串[]args){
新蛇();
}
公蛇({
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
例如printStackTrace();
}
JFrame=新JFrame(“测试”);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(newtestpane());
frame.pack();
frame.setLocationRelativeTo(空);
frame.setVisible(true);
}
});
}
公共静态类TestPane扩展了JPanel{
公共枚举方向{
上、下、左、右
}
私人int XPO、YPO;
专用方向=方向.UP;
私有LinkedList snakeBody=新LinkedList();
公共测试窗格(){
xPos=100;
yPos=100;
对于(int-index=0;index<50;index++){
添加(新点(xPos、YPO));
}
bindKeyStrokeTo(“向上.按下”,KeyStroke.getKeyStroke(KeyEvent.VK_up,0,false),new MoveAction(Direction.up));
bindKeyStrokeTo(“向下.按下”,KeyStroke.getKeyStroke(KeyEvent.VK_向下,0,false),new MoveAction(Direction.down));
bindKeyStrokeTo(“left.pressed”、KeyStroke.getKeyStroke(KeyEvent.VK_left,0,false)、new MoveAction(Direction.left));
bindKeyStrokeTo(“right.pressed”、KeyStroke.getKeyStroke(KeyEvent.VK_right,0,false)、new-MoveAction(Direction.right));
计时器计时器=新计时器(40,新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
开关(方向){
个案:
yPos--;
打破
按大小写:
yPos++;
打破
案例左:
xPos--;
打破
案例权利:
xPos++;
打破
}
if(yPos<0){
yPos--;
}else if(yPos>getHeight()-1){
yPos=getHeight()-1;
}
如果(xPos<0){
xPos--;
}else if(xPos>getWidth()-1){
xPos=getWidth()-1;
}
蛇体。removeLast();
蛇身推进(新点(xPos,YPO));
雷帕