Actionscript 3.0鼠标追踪蛇游戏逻辑

Actionscript 3.0 Mouse trail snake game logic

我正在用 actionscript 3.0 (adobe flash) 开发一款类似于此 https://www.tvokids.com/preschool/games/caterpillar-count 的游戏。我有将蛇头拖向鼠标方向的代码。但是,我不知道如何添加蛇的 body 并使其跟随头部的路径。以下是我在鼠标方向拖动动画片段的代码:

        var _isActive = true;
        var _moveSpeedMax:Number = 1000;
        var _rotateSpeedMax:Number = 15;
        var _decay:Number = .98;
        var _destinationX:int = 150;
        var _destinationY:int = 150;
        var _dx:Number = 0;
        var _dy:Number = 0;
        var _vx:Number = 0;
        var _vy:Number = 0;
        var _trueRotation:Number = 0;
        var _player;
        var i;

        createPlayer();
        stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);

        function createPlayer():void{
            _player = new head();
            _player.x = stage.stageWidth / 2;
            _player.y = stage.stageHeight / 2;
            stage.addChild(_player);
        }

        function onDown(e:MouseEvent):void{
            _isActive = true;
            stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
            stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
        }

        function onMove(e:MouseEvent):void{
            updatePosition(_player);
            updateRotation(_player);
        }

        function onUp(e:MouseEvent):void{
            _isActive = false;
            stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
            stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
        }

        function updatePosition(mc):void
        {
            // check if mouse is down
            if (_isActive)
            {
                // update destination
                _destinationX = stage.mouseX;
                _destinationY = stage.mouseY;

                // update velocity
                _vx += (_destinationX - mc.x) / _moveSpeedMax;
                _vy += (_destinationY - mc.y) / _moveSpeedMax;
            }
            else
            {
                // when mouse is not down, update velocity half of normal speed
                _vx += (_destinationX - mc.x) / _moveSpeedMax * .25;
                _vy += (_destinationY - mc.y) / _moveSpeedMax * .25;
            }

            // apply decay (drag)
            _vx *= _decay;
            _vy *= _decay;

            // if close to target, slow down turn speed
            if (getDistance(_dx, _dy) < 50)
            {
                _trueRotation *= .5;
            }           

            // update position
            mc.x += _vx;
            mc.y += _vy;
        }

        function updateRotation(mc):void
        {
            // calculate rotation
            _dx = mc.x - _destinationX;
            _dy = mc.y - _destinationY;

            // which way to rotate
            var rotateTo:Number = getDegrees(getRadians(_dx, _dy)); 

            // keep rotation positive, between 0 and 360 degrees
            if (rotateTo > mc.rotation + 180) rotateTo -= 360;
            if (rotateTo < mc.rotation - 180) rotateTo += 360;

            // ease rotation
            _trueRotation = (rotateTo - mc.rotation) / _rotateSpeedMax;

            // update rotation
            mc.rotation += _trueRotation;           
        }

        function getDistance(delta_x:Number, delta_y:Number):Number
        {
            return Math.sqrt((delta_x*delta_x)+(delta_y*delta_y));
        }

        function getRadians(delta_x:Number, delta_y:Number):Number
        {
            var r:Number = Math.atan2(delta_y, delta_x);

            if (delta_y < 0)
            {
                r += (2 * Math.PI);
            }
            return r;
        }

        function getDegrees(radians:Number):Number
        {
            return Math.floor(radians/(Math.PI/180));
        }

下面的脚本不会奇迹般地单独运行,但它具有您需要的所有逻辑,并得到了很好的解释。它使任何长度的链条都按照一定的规则跟随其头部。很多年前我在这里使用了相同的原则:http://delimiter.ru/games/25-lines/alone.html

// This one will represent the Mouse position.
var Rat:Sprite = new Sprite;

// The ordered list of chain elements.
// It all starts with the Mouse.
var Snake:Array = [Rat];

// Call this one each time you want to
// extend the snake with the piece of tail.
function addTail(aPiece:DisplayObject):void
{
    // Get the last snake element.
    var lastPiece:DisplayObject = Snake[Snake.length - 1];

    // Sync the tail coordinates.
    aPiece.x = lastPiece.x;
    aPiece.y = lastPiece.y;

    // Add the new piece to the snake.
    Snake.push(aPiece);
}

// Add the pre-defined head as the first element.
addTail(SnakeHead);

// Now start following the Mouse.
addEventListener(Event.ENTER_FRAME, onFrame);

// Fires every frame and adjusts the whole snake, if needed.
function onFrame(e:Event):void
{
    // Sync the attractor point with the Mouse.
    Rat.x = mouseX;
    Rat.y = mouseY;

    // Now lets make each piece follow the previous piece,
    // one by one, starting from the head, down to the tail.
    for (var i:int = 1; i < Snake.length; i++)
    {
        followOne(Snake[i - 1], Snake[i]);
    }
}

function followOne(A:DisplayObject, B:DisplayObject):void
{
    // Think of these values as of vector
    // pointing from B position to A position.
    var dx:Number = A.x - B.x;
    var dy:Number = A.y - B.y;

    // Figure out the distance between the given pieces.
    var aDist:Number = Math.sqrt(dx * dx + dy * dy);

    // Do nothing if pieces are closer than 20 px apart.
    // You can change this value to make snake shorter or longer.
    if (aDist < 20)
    {
        return;
    }

    // This literally means "eat one tenth of the distance
    // between me and the previous piece". If you want pieces
    // to follow each other with more vigor, reduce this value,
    // if you want the whole snake to slither smoothly, increase it.
    B.x += dx / 10;
    B.y += dy / 10;

    // Rotate the B piece so it would look right into A's direction.
    // Well, unless your pieces are round and look all the same.
    B.rotation = Math.atan2(dy, dx) * 180 / Math.PI;
}