CyberLord09 / CSSE1_Final

MIT License
0 stars 0 forks source link

Base Enemy Explanation #6

Open TianbinLiu opened 2 months ago

TianbinLiu commented 2 months ago

The enemy doesn't have animation, it is just a single image without using SpriteSheet. Image Image

So if we want to create an enemy with animation using the sprite sheet, we can't just use Goomba class we currently have or change the Goomba.js to fit the new enemy(because it will be easy to break the game or the Goomba). Instead, the best way is to have a new "enemy" file therefore it will be safer and won't affect other objects.

setAnimation() function

    setAnimation(key) {
        // animation comes from playerData
        var animation = this.playerData[key]

        // set frame and idle frame
        this.setFrameY(animation.row);
        this.setMinFrame(animation.min ? animation.min : 0);
        this.setMaxFrame(animation.frames);
        if (this.isIdle && animation.idleFrame) {
            this.setFrameX(animation.idleFrame.column)
            this.setMinFrame(animation.idleFrame.frames);
        }
    }

The major difference between Goomba.js and the Enemy.js we need to create is the "setAnimation()". You can also find setAnimation() function exists in Player.js. The function first creates a variable called "animation" which will store the properties you assign in GameSetup.js:

        boss: {
          src: "/images/platformer/sprites/boss.png",
          width: 64,
          height: 64,
          scaleSize: 320,
          speedRatio: 0.7,
          wa: { row: 9, min: 0, frames: 8 },
          wd: { row: 11, min: 0, frames: 8 },
          a: { row: 9, frames: 8, idleFrame: { column: 7, frames: 0 } },
          d: { row: 11, frames: 8, idleFrame: { column: 7, frames: 0 } }
        },

For example, if you assign the input "key" as "wa" like setAnimation("wa") then, the "animation" variable will store "wa: { row: 9, min: 0, frames: 8 }". So if you call "animation.row" it will return an integer "9".

then it will use the function from "Character.js": setFrameY(), setMinFrame(), setMaxFrame() to change the enemy's frames and therefore make the enemy play animation.

Or maybe you can use the newest function "setSpriteAnimation()" updated by Mr.M(You can find this in Character.js and PlayerBase.js):

    setSpriteAnimation(animation) {
        this.setFrameY(animation.row);
        this.setMinFrame(animation.min ? animation.min : 0);
        this.setMaxFrame(animation.frames);
    }

Direction:

If you compare the constructor of the Player class and the Goomba class, you will find out that the Player class has the property that stores the direction:

this.directionKey = "d"; // initially facing right

So by assigning the "this.directionKey" to the function setAnimation(), we can not only control the direction of the enemy, but also let the enemy to play with the specific animation that fits with its direction.

update() {
        super.update();
        this.setAnimation(this.directionKey);

///code hidden

}

The complete look of Enemy.js (the code does not use the newest updated version of code by Mr.M, like the PlayerBase.js, and may not organized well, but it works well and it's the same principle)

import Character from './Character.js';
import GameEnv from './GameEnv.js';
import GameControl from './GameControl.js';

export class Enemy extends Character {
    // constructors sets up Character object 
    constructor(canvas, image, data, xPercentage, yPercentage, name, minPosition) {
        super(canvas, image, data, 0.0, 0.2);

        this.playerData = data;
        //Unused but must be Defined
        this.name = name;
        this.y = yPercentage;

        this.isIdle = false;
        //Initial Position of Goomba
        this.x = xPercentage * GameEnv.innerWidth;

        //Access in which a Goomba can travel    
        this.minPosition = minPosition * GameEnv.innerWidth;
        this.maxPosition = this.x + xPercentage * GameEnv.innerWidth;

        this.immune = 0;

        this.storeSpeed = this.speed;

        this.direction = "d"; // initially facing right

        //Define Speed of Enemy
        if (["easy", "normal"].includes(GameEnv.difficulty)) {
            this.storeSpeed = this.speed * Math.floor(Math.random() * 1.5 + 2);
        } else if (GameEnv.difficulty === "hard") {
            this.storeSpeed = this.speed * Math.floor(Math.random() * 3 + 3);
        } else {
            this.storeSpeed = this.speed * 5
        }
    }

    setAnimation(key) {
        // animation comes from playerData
        var animation = this.playerData[key]

        // set frame and idle frame
        this.setFrameY(animation.row);
        this.setMinFrame(animation.min ? animation.min : 0);
        this.setMaxFrame(animation.frames);
        if (this.isIdle && animation.idleFrame) {
            this.setFrameX(animation.idleFrame.column)
            this.setMinFrame(animation.idleFrame.frames);
        }
    }

    update() {
        super.update();

        this.setAnimation(this.direction);

        // Check for boundaries
        if (this.x <= this.minPosition || (this.x + this.canvasWidth >= this.maxPosition)) {
            if (this.direction === "a") {
                this.direction = "d";
            }
            else if (this.direction === "d") {
                this.direction = "a";
            }
        };

        if (this.direction === "d") {
            this.speed = Math.abs(this.storeSpeed)
        }
        else if (this.direction === "a") {
            this.speed = -Math.abs(this.storeSpeed);
        }
        else if (this.direction === "idle") {
            this.speed = 0
        }

        // Move the enemy\
        this.x += this.speed;

        this.playerBottomCollision = false;
    }

    // Player action on collisions
    collisionAction() {
        if (this.collisionData.touchPoints.other.id === "tube") {
            if (this.direction === "a" && this.collisionData.touchPoints.other.right) {
                this.direction = "d";
            }
            else if (this.direction === "d" && this.collisionData.touchPoints.other.left) {
                this.direction = "a";
            }

        }

        if (this.collisionData.touchPoints.other.id === "player") {
            // Collision: Top of Goomba with Bottom of Player
            //console.log(this.collisionData.touchPoints.other.bottom + 'bottom')
            //console.log(this.collisionData.touchPoints.other.top + "top")
            //console.log(this.collisionData.touchPoints.other.right + "right")
            //console.log(this.collisionData.touchPoints.other.left + "left")
            if (this.collisionData.touchPoints.other.bottom && this.immune == 0) {
                GameEnv.invincible = true;
                GameEnv.goombaBounce = true;
                this.canvas.style.transition = "transform 1.5s, opacity 1s";
                this.canvas.style.transition = "transform 2s, opacity 1s";
                this.canvas.style.transformOrigin = "bottom"; // Set the transform origin to the bottom
                this.canvas.style.transform = "scaleY(0)"; // Make the Goomba flat
                this.speed = 0;
                GameEnv.playSound("goombaDeath");

                setTimeout((function () {
                    GameEnv.invincible = false;
                    this.destroy();
                }).bind(this), 1500);

            }
        }

        if (this.collisionData.touchPoints.other.id === "jumpPlatform") {
            if (this.direction === "a" && this.collisionData.touchPoints.other.right) {
                this.direction = "d";
            }
            else if (this.direction === "d" && this.collisionData.touchPoints.other.left) {
                this.direction = "a";
            }
        }
    }
}

export default Enemy;