当前位置: 首页 > 面试题库 >

SnakeGame如何使尾巴跟随头部?

彭展
2023-03-14
问题内容

我正在做蛇游戏,并且被困在使尾巴跟着头部的位置。我听说在头和尾上使用添加和删除操作可能会发生这种情况,但是我不知道从哪里开始。

到目前为止,这是我的代码:

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

BodyPart.java

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

现在这段代码只会使尾巴翻转到水平或垂直方向,是否可以通过使用此代码使尾巴跟随头部?还是我需要更改代码?

谢谢


问题答案:

基本思想是,您需要某种List包含蛇的所有点的东西。从概念上讲,List它将包含虚拟坐标,即1x1表示虚拟空间中的坐标,该坐标表示虚拟板上的位置(宽度和高度会有所增加)。

然后,您可以将其翻译到屏幕上,这样将允许蛇的每个部分都大于单个像素。因此,如果每个部分都是5x5像素,则1x1实际上将5x5在屏幕中。

每次蛇移动时,都向头部添加一个新值,并从尾部删除最后一个值(假设它没有增长)。当您需要画蛇时,您只需遍历List,就可以画蛇的每个点。

以下是一个简单的示例,该示例使用一个LinkedList,将一个新的元素推Point到上List,制作一个新的头部,并在每个循环中都删除最后一个元素(尾部)。

基本上可以归结为…

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

        }

    }

}

现在,它没有碰撞检测或其他功能,但是您可以移动蛇,蛇会自动跟随



 类似资料:
  • 我在我的squarespace站点上使用了一些HTML&CSS来创建一个自定义的跟随光标。我只想有一个浮动的圆圈,没有实际的光标显示。我已经得到了它的工作,但当我的网站滚动跟随光标没有移动的页面滚动,只是卡在顶部。 这只会导致follow光标完全停止随鼠标移动而移动,在页面中心变成静态的。 将HTML&CSS注入到squarespace站点以创建自定义跟随光标: null null

  • 本文向大家介绍unity实现摄像头跟随,包括了unity实现摄像头跟随的使用技巧和注意事项,需要的朋友参考一下 代码很简单,这里就不多废话了,直接奉上代码 以上所述就是本文的全部内容了,希望大家能够喜欢,能够对大家学习unity有所帮助。

  • 如果你想创建一个像这样的单链表: 这个列表有方法“追加”、“删除”、“printList”和“findElement”。有必要有尾巴吗?因为使用“最后”你可以地址最后一个节点。 那么,什么时候有必要拥有所有三个节点“头”、“尾”和“最后”?例如,当您想将排序的节点插入列表时?

  • 工具与材料: 光环板,鳄鱼夹或导线,电池盒,剪刀,打孔工具,刻度尺,卡纸,双面胶,杜邦线,9g小舵机(3.3V)等。 制作小猫 在卡纸上画出小猫的身体和尾巴,将它们从卡纸上剪下,眼睛打孔。 注意:小猫眼睛的间距要和光环板最远的两颗LED灯距离相等。 将舵机与光环板连接,四个引脚都可以控制舵机。 舵机的红线是代表电源正极,与鳄鱼夹红线相连接,红线鳄鱼夹与光环板3.3V引脚相连接; 舵机的黑线代表电源

  • 问题内容: 在* NIX中实现tail的有效方法是什么?我提出(编写)了两个简单的解决方案,都使用一种圆形缓冲区将线加载到圆形结构中(数组|双向链接的圆形列表- 很有趣)。我已经看到了busybox中较旧的实现的一部分,并且据我了解,他们使用fseek查找EOF,然后“向后”阅读内容。有没有更干净,更快的东西?我在面试时被问到了,问问者看起来并不满意。先感谢您。 问题答案: 我认为没有其他解决方案

  • 问题内容: 说我有一堂课 然后可以按如下方式解析有效的json: 如果字符串包含的数据多于解析对象所需的数据,是否有办法使解析器失败? 例如,我希望以下操作失败(成功) 我使用带有JsonParser.Feature.AUTO_CLOSE_SOURCE = false的InputStream尝试了此操作,并检查该流是否已被完全消耗,但这不起作用: 那是, 仍然成功,可能是因为解析器从流中消耗了超出