SnakeGame how to make the tail follow the head?

后端 未结 2 507
借酒劲吻你
借酒劲吻你 2020-12-12 05:41

I am making a snake game, and I am stuck at where making the tails follow the head. And I heard using an add and remove on the head and tails could make that happen, but I h

相关标签:
2条回答
  • 2020-12-12 06:23

    For snake style movement, you can, from the tail to the head, move each BodyPart position to the position of the BodyPart ahead of it. For the head there is no part ahead so you have to write decision code whether to simply move the same direction as the part before it or a new direction based on input. Then update the screen.

    0 讨论(0)
  • 2020-12-12 06:25

    The basic idea is, you need some kind of List which contains ALL the points of the snake. Conceptually, the List would contain virtual coordinates, that is 1x1 would represent a coordinate in virtual space, which presented a place on a virtual board (which would have some wide and height).

    You could then translate that to the screen, so this would allow each part of the snake to be larger then a single pixel. So, if each part was 5x5 pixels, then 1x1 would actually be 5x5 in the screen.

    Each time the snake moves, you add a new value to the head and remove the last value from tail (assuming it's not growing). When you needed to paint the snake, you would simply iterate over the List, painting each point of the snake.

    The following is a simple example, which uses a LinkedList, which pushes a new Point onto the List, making a new head, and removing the last element (the tail) on each cycle.

    Which basically boils down to...

    snakeBody.removeLast();
    snakeBody.push(new Point(xPos, yPos));
    

    As a runnable concept

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

    Now, this has no collision detection or other functionality, but you can move the snake around and it will follow itself

    0 讨论(0)
提交回复
热议问题