Search code examples
javascriptgame-developmentphaser-frameworkphaserjs

Making a Tile Follow Another Tile in Phaser 3


This is more of a logic question than a Phaser 3 question. I am trying to make the game 'snake'. I can move 1 body up, down, left, and right easily, however, I do have issues when there is more than 1 body of 'snake'. In snake, when the front of a snake switches directions, the others follow suit in such a way so that they stay behind the snake. I cannot seem to figure out how to do this- changing the direction respectively for all of the 'other' bodies behind the 'snake'. In short, this is basically one sprite following another sprite. I would appreciate some help on this. Here is my code so far:

create() {
    this.snake = this.physics.add.group()
    this.front = this.snake.create(25,25,"tile").setScale(0.12)
}

This is where I create my snake, as well as the 'front' of the snake.

 update() {
    this.cursors = this.input.keyboard.createCursorKeys()
    if (this.cursors.right.isDown) {
        this.x_vel = this.vel
        this.y_vel = 0
        this.DIRECTION = "right"
    } if (this.cursors.left.isDown) {
        this.x_vel = -this.vel
        this.y_vel = 0
        this.DIRECTION = "left"
    } if (this.cursors.up.isDown) {
        this.x_vel = 0
        this.y_vel = -this.vel
        this.DIRECTION = "up"
    } if (this.cursors.down.isDown) {
        this.x_vel = 0
        this.y_vel = this.vel
        this.DIRECTION = "down"
    }
    this.front.x += this.x_vel
    this.front.y += this.y_vel

}

This is how I will move my snake. I am only moving the 'front' of the snake because I want all of the other snake 'bodies' to follow the 'front' of the snake.

I have tried looking at other snake projects, especially those on phaser discussions and on medium, but they don't go over the details that much and I have trouble following their code.

In short, I would appreciate any hints or pointers you'd give me. Thanks in advance.


Solution

  • There are many different way's to do this, one easy solution is the way show on an official phaser game example (It uses the old Phaser "class" creation, but the idea is still the same)

    Basically just use the built-in function Phaser.Actions.ShiftPosition here is the link to the documentation. This function shifts the position of all items in array, to the last position of the previous item. So basically this function hast all the logic, and move the snake.

    You just need to create a Group (or you can use an array) with the body parts and pass it to the function, and the function will take care of moving each child.

    Phaser.Actions.ShiftPosition(myObjects, 400, 300);
    

    Phaser.Actions.ShiftPosition(...) is the function to call
    myObjects is the list of snake parts you want to move
    400,300 should be the new position for the first item in the Array

    Tipp: In your posted code, I would move this line this.cursors = this.input.keyboard.createCursorKeys() into the create function, since you just have to set this.cursor once.

    Here is a Short Demo:
    (ShowCasing the shifting array)

    const COLORS = [ 0x9bbc0f, 0x8bac0f, 0x306230, 0x0f380f ];
    
    class DemoScene extends Phaser.Scene {
        
        preload(){
           //create texture for the demo
           let graphics  = this.make.graphics();
           graphics.fillStyle( 0xff0000 );
           graphics.fillRect(0, 0, 8, 8);
           graphics.generateTexture(`texture`, 8, 8);
        }
    
        create () {
            this.add.text(10,10,'Demo');
            
            this.snake = this.add.group();
            
            // create head
            this.snake.create(100, 100, 'texture');
           
            // body part1
            this.snake.create(90, 100, 'texture');    
            // body part2
            this.snake.create(80, 100, 'texture');    
                    
            // move timer
            this.lastStep  = 0
            
        }
        
        update (delta) {
            //movement should be improved, this is just for the demo
            
            if(this.lastStep + 10 < delta ){
            
                let bodyParts = this.snake.getChildren();
                let {x, y} = bodyParts[bodyParts.length - 1];
                
                // here the magic happens
                Phaser.Actions.ShiftPosition( bodyParts, bodyParts[0].x + 1, bodyParts[0].y)   
                
                this.lastStep = delta
                
            }
        }
    
    }
    
    var config = {
        width: 540,
        height: 180,
        scene: DemoScene,
    }; 
    
    new Phaser.Game(config);
    
    console.clear();
    document.body.style = 'margin:0;';
    <script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>