skip to Main Content

I am currently creating a fighting game from scratch using native JavaScript, HTML, and CSS. When I run my button clicks and have them hit each other, the health boxes do not shrink or move.

Question: How can I get my health bars to work in native JS?

const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext("2d");

canvas.width = 1024;
canvas.height = 576;

function logMessage(msg) {
    document.querySelector('#myMessage').textContent += msg + '. ';
}

//This creates a background
ctx.fillRect(0, 0, canvas.width, canvas.height);

//Changing this value changes how fast the sprites fall
const gravity = 0.7;

class Sprite {
    //The curly braces makes it easier to pass values back and forth
    constructor({position, velocity, color, offset}) {
        this.position = position;
        this.velocity = velocity;
        this.height = 150;
        this.width = 50;
        this.lastKey;
        this.attackBox = {
            position: {
                x: this.position.x,
                y: this.position.y
            },
            offset,
            width: 100,
            height: 50,
            color: 'green'
        }
        this.color = color;
        this.isAttacking;
        this.health = 100;
    }

    draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.position.x, this.position.y, this.width, this.height);

        //Attack box: only appears when attacking
        if (this.isAttacking) {
            ctx.fillStyle = this.attackBox.color;
            ctx.fillRect(
                this.attackBox.position.x,
                this.attackBox.position.y,
                this.attackBox.width,
                this.attackBox.height
            )
        }
    }

    update() {
        this.draw();
        this.attackBox.position.x = this.position.x - this.attackBox.offset.x;
        this.attackBox.position.y = this.position.y;
        //This keeps the Sprites from going off the edge of the canvas
        this.position.x = Math.max(0, Math.min(canvas.width - this.width, this.position.x + this.velocity.x));
        //This stops the sprite from going above the canvas
        this.position.y = Math.max(0, Math.min(canvas.height, this.position.y + this.velocity.y));

        //Stops the velocity in the y direction if the sprite hits the bottom
        if (this.position.y + this.height + this.velocity.y >= canvas.height) {
            this.velocity.y = 0;
        } else {
            this.velocity.y += gravity;
        }
    }

    attack() {
        this.isAttacking = true;
        
        setTimeout(() => {
            this.isAttacking = false;
        }, 100)
    }
}

const Player = new Sprite({
    position: {
        x: 0,
        y: 0
    },
    velocity: {
        x: 0,
        y: 0
    },
    offset: {
        x: 0,
        y: 0
    },
    color: 'blue'
})

const Enemy = new Sprite({
    position: {
        x: 400,
        y: 100
    },
    velocity: {
        x: 0,
        y: 0
    },
    offset: {
        x: 50,
        y: 0
    },
    color: 'red'
})

const keys = {
    w: {
        pressed: false
    },
    a: {
        pressed: false
    },
    d: {
        pressed: false
    },
    ArrowUp: {
        pressed: false
    },
    ArrowLeft: {
        pressed: false
    },
    ArrowRight: {
        pressed: false
    }
}

function rectangularCollision({rectangle1, rectangle2}) {
    return (
        rectangle1.attackBox.position.x + rectangle1.attackBox.width >= rectangle2.position.x &&
        rectangle1.attackBox.position.x <= rectangle2.position.x + rectangle2.width &&
        rectangle1.attackBox.position.y + rectangle1.attackBox.height >= rectangle2.position.y &&
        rectangle1.attackBox.position.y <= rectangle2.position.y + rectangle2.height &&
        rectangle1.isAttacking
    )
}

function animate() {
    window.requestAnimationFrame(animate);
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    Player.update();
    Enemy.update();

    //Player movement
    Player.velocity.x = 0;

    if (keys.a.pressed == true && Player.lastKey == "a") {
        Player.velocity.x = -5;
    } else if (keys.d.pressed == true && Player.lastKey == "d") {
        Player.velocity.x = 5;
    }

    //Enemy movement
    Enemy.velocity.x = 0;

    if (keys.ArrowLeft.pressed == true && Enemy.lastKey == "ArrowLeft") {
        Enemy.velocity.x = -5;
    } else if (keys.ArrowRight.pressed == true && Enemy.lastKey == "ArrowRight") {
        Enemy.velocity.x = 5;
    }

    //Detect for the player hitting the enemy
    if (rectangularCollision({rectangle1: Player, rectangle2: Enemy})) {
        Player.isAttacking = false;
        Enemy.health -= 20;
        document.querySelector('#enemy-health').style.width = Enemy.health;
    } 
    
    //Detect for thr enemy hitting the player
    if (rectangularCollision({rectangle1: Enemy, rectangle2: Player})) {
        Enemy.isAttacking = false;
        Player.health -= 20;
        document.querySelector('#player-health').style.width = Player.health;
    }    
}

animate();

//Event listeners that move the player when certain keys are pressed
window.addEventListener('keydown', (event) => {
    switch (event.key) {
        //Player movement
        case 'w':
            Player.velocity.y = -20;
        break;

        case 'a':
            keys.a.pressed = true;
            Player.lastKey = "a";
        break

        case 'd':
            keys.d.pressed = true;
            Player.lastKey = "d";
        break;

        case ' ':
            Player.attack();
        break;    
    }

    //Enemy movement
    switch (event.key) {
        case 'ArrowUp':
            Enemy.velocity.y = -20;
        break;

        case 'ArrowRight':
            keys.ArrowRight.pressed = true;
            Enemy.lastKey = 'ArrowRight'
        break

        case 'ArrowLeft':
            keys.ArrowLeft.pressed = true;
            Enemy.lastKey = 'ArrowLeft'
        break;

        case 'Enter':
            Enemy.attack();
        break;    
    }    
})

window.addEventListener('keyup', (event) => {
    //Player keys
    switch (event.key) {
        case 'w':
            keys.w.pressed = false;
        break;    

        case 'a':
            keys.a.pressed = false;
        break

        case 'd':
            keys.d.pressed = false;
        break;
    }

    //Enemy keys
    switch (event.key) {
        case 'ArrowUp':
            keys.ArrowUp.pressed = false;
        break;    

        case 'ArrowLeft':
            keys.ArrowLeft.pressed = false;
        break

        case 'ArrowRight':
            keys.ArrowRight.pressed = false;
        break;
    }
})
* {
    box-sizing: border-box;
}

#mother-div {
    position: relative;
    display: inline-block;
}

#small-container {
    position: absolute;
    display: flex;
    width: 100%;
    align-items: center;
    padding: 20px;
}

.healthDiv {
    position: relative;
    height: 30px;
    width: 100%;
}

#player-health, #enemy-health {
    position: absolute;
    background-color: blue;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
}

#timer {
    background-color: red;
    width: 100px;
    height: 100px;
    flex-shrink: 0;
}

#myConsole {
    background-color: black;
    color: white;
    min-height: 100px;
}
<!DOCTYPE html>
<html lang="en">

<html>
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="X-UA-Compatible" content="IE-edge">
        <meta name="viewport", content="width=device-width, initial-scale=1.0">
        <meta name="author" content="Christian Davis">
        <link rel="stylesheet" href="styles.css">

        <title>Fighting Game</title>
    </head>

    <body>
        <!--Red container div-->
        <div id="mother-div">
            <!--Smaller red container div-->
            <div id="small-container">
                <!--Player Health-->
                <div class="healthDiv">
                    <div id="player-health">

                    </div>
                </div>

                <!--Timer-->
                <div id="timer">

                </div>

                <!--Enemy Health-->
                <div class="healthDiv">
                    <div id="enemy-health">

                    </div>
                </div>
            </div>

            <canvas id="canvas"></canvas>
        </div>

        <p id="myConsole">&gt;&nbsp;<span id="myMessage"></span></p>

        <script src="app.js"></script>
    </body>
</html>

What I need to happen is the bars on either side of the box in the center need to shrink their width inward (they need to get thinner and closer to the center box).

2

Answers


  1. Chosen as BEST ANSWER

    After editing my code a little bit, it works perfectly. All I did was change some divs and I also had to separate the enemy health and player health inside of the CSS. The solution proposed by @Harry Hsu gave me a start but did not help entirely.

    Finished code:

    const canvas = document.querySelector('#canvas');
    const ctx = canvas.getContext("2d");
    
    canvas.width = 1024;
    canvas.height = 576;
    
    function logMessage(msg) {
        document.querySelector('#myMessage').textContent += msg + '. ';
    }
    
    //This creates a background
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    
    //Changing this value changes how fast the sprites fall
    const gravity = 0.7;
    
    class Sprite {
        constructor({position, velocity, color, offset}) {
            this.position = position;
            this.velocity = velocity;
            this.height = 150;
            this.width = 50;
            this.lastKey;
            this.attackBox = {
                position: {
                    x: this.position.x,
                    y: this.position.y
                },
                offset,
                width: 100,
                height: 50,
                color: 'green'
            }
            this.color = color;
            this.isAttacking;
            this.health = 100;
        }
    
        draw() {
            ctx.fillStyle = this.color;
            ctx.fillRect(this.position.x, this.position.y, this.width, this.height);
    
            if (this.isAttacking) {
                ctx.fillStyle = this.attackBox.color;
                ctx.fillRect(
                    this.attackBox.position.x,
                    this.attackBox.position.y,
                    this.attackBox.width,
                    this.attackBox.height
                )
            }
        }
    
        update() {
            this.draw();
            this.attackBox.position.x = this.position.x - this.attackBox.offset.x;
            this.attackBox.position.y = this.position.y;
            //This keeps the Sprites from going off the edge of the canvas
            this.position.x = Math.max(0, Math.min(canvas.width - this.width, this.position.x + this.velocity.x));
            //This stops the sprite from going above the canvas
            this.position.y = Math.max(0, Math.min(canvas.height, this.position.y + this.velocity.y));
    
            //Stops the velocity in the y direction if the sprite hits the bottom
            if (this.position.y + this.height + this.velocity.y >= canvas.height) {
                this.velocity.y = 0;
            } else {
                this.velocity.y += gravity;
            }
        }
    
        attack() {
            this.isAttacking = true;
            
            setTimeout(() => {
                this.isAttacking = false;
            }, 100)
        }
    }
    
    const Player = new Sprite({
        position: {
            x: 0,
            y: 0
        },
        velocity: {
            x: 0,
            y: 0
        },
        offset: {
            x: 0,
            y: 0
        },
        color: 'blue'
    })
    
    const Enemy = new Sprite({
        position: {
            x: 400,
            y: 100
        },
        velocity: {
            x: 0,
            y: 0
        },
        offset: {
            x: 50,
            y: 0
        },
        color: 'red'
    })
    
    const keys = {
        w: {
            pressed: false
        },
        a: {
            pressed: false
        },
        d: {
            pressed: false
        },
        ArrowUp: {
            pressed: false
        },
        ArrowLeft: {
            pressed: false
        },
        ArrowRight: {
            pressed: false
        }
    }
    
    function rectangularCollision({rectangle1, rectangle2}) {
        return (
            rectangle1.attackBox.position.x + rectangle1.attackBox.width >= rectangle2.position.x &&
            rectangle1.attackBox.position.x <= rectangle2.position.x + rectangle2.width &&
            rectangle1.attackBox.position.y + rectangle1.attackBox.height >= rectangle2.position.y &&
            rectangle1.attackBox.position.y <= rectangle2.position.y + rectangle2.height &&
            rectangle1.isAttacking
        )
    }
    
    function animate() {
        window.requestAnimationFrame(animate);
        ctx.fillStyle = 'black';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        Player.update();
        Enemy.update();
    
        //Player movement
        Player.velocity.x = 0;
    
        if (keys.a.pressed == true && Player.lastKey == "a") {
            Player.velocity.x = -5;
        } else if (keys.d.pressed == true && Player.lastKey == "d") {
            Player.velocity.x = 5;
        }
    
        //Enemy movement
        Enemy.velocity.x = 0;
    
        if (keys.ArrowLeft.pressed == true && Enemy.lastKey == "ArrowLeft") {
            Enemy.velocity.x = -5;
        } else if (keys.ArrowRight.pressed == true && Enemy.lastKey == "ArrowRight") {
            Enemy.velocity.x = 5;
        }
    
        //Detect for the player hitting the enemy
        if (rectangularCollision({rectangle1: Player, rectangle2: Enemy})) {
            Player.isAttacking = false;
            Enemy.health -= 20;
            document.querySelector('#enemy-health').style.width = Enemy.health + '%';
        } 
        
        //Detect for thr enemy hitting the player
        if (rectangularCollision({rectangle1: Enemy, rectangle2: Player})) {
            Enemy.isAttacking = false;
            Player.health -= 20;
            document.querySelector('#player-health').style.width = Player.health + '%';
        }    
    }
    
    animate();
    
    window.addEventListener('keydown', (event) => {
        switch (event.key) {
            //Player movement
            case 'w':
                Player.velocity.y = -20;
            break;
    
            case 'a':
                keys.a.pressed = true;
                Player.lastKey = "a";
            break
    
            case 'd':
                keys.d.pressed = true;
                Player.lastKey = "d";
            break;
    
            case ' ':
                Player.attack();
            break;    
        }
    
        //Enemy movement
        switch (event.key) {
            case 'ArrowUp':
                Enemy.velocity.y = -20;
            break;
    
            case 'ArrowRight':
                keys.ArrowRight.pressed = true;
                Enemy.lastKey = 'ArrowRight'
            break
    
            case 'ArrowLeft':
                keys.ArrowLeft.pressed = true;
                Enemy.lastKey = 'ArrowLeft'
            break;
    
            case 'Enter':
                Enemy.attack();
            break;    
        }    
    })
    
    window.addEventListener('keyup', (event) => {
        //Player keys
        switch (event.key) {
            case 'w':
                keys.w.pressed = false;
            break;    
    
            case 'a':
                keys.a.pressed = false;
            break
    
            case 'd':
                keys.d.pressed = false;
            break;
        }
    
        //Enemy keys
        switch (event.key) {
            case 'ArrowUp':
                keys.ArrowUp.pressed = false;
            break;    
    
            case 'ArrowLeft':
                keys.ArrowLeft.pressed = false;
            break
    
            case 'ArrowRight':
                keys.ArrowRight.pressed = false;
            break;
        }
    })
    * {
        box-sizing: border-box;
    }
    
    #mother-div {
        position: relative;
        display: inline-block;
    }
    
    #small-container {
        position: absolute;
        display: flex;
        width: 100%;
        align-items: center;
        padding: 20px;
    }
    
    .healthDiv {
        position: relative;
        height: 30px;
        width: 100%;
    }
    
    .backgroundHealth {
        background-color: red;
        height: 30px;
        width: 100%
    }
    
    #player-health {
        position: absolute;
        background-color: lime;
        top: 0;
        right: 0;
        bottom: 0;
        width: 100%
    }
    
    #enemy-health {
        position: absolute;
        background-color: yellow;
        top: 0;
        right: 0;
        bottom: 0;
        left: 0
    }
    
    #playerHealthDiv {
        display: flex;
        justify-content: flex-end;
    }
    
    #timer {
        background-color: red;
        width: 100px;
        height: 100px;
        flex-shrink: 0;
        border: solid white 2px;
    }
    
    #myConsole {
        background-color: black;
        color: white;
        min-height: 100px;
    }
    <!DOCTYPE html>
    <html lang="en">
    
    <html>
        <head>
            <meta charset="UTF-8">
            <meta http-equiv="X-UA-Compatible" content="IE-edge">
            <meta name="viewport", content="width=device-width, initial-scale=1.0">
            <meta name="author" content="Christian Davis">
            <link rel="stylesheet" href="styles.css">
    
            <title>Fighting Game</title>
        </head>
    
        <body>
            <!--Red container div-->
            <div id="mother-div">
                <!--Smaller red container div-->
                <div id="small-container">
                    <!--Player Health-->
                    <div class="healthDiv" id="playerHealthDiv">
                        <div class="backgroundHealth"></div>
                        <div id="player-health"></div>
                    </div>
    
                    <!--Timer-->
                    <div id="timer">
    
                    </div>
    
                    <!--Enemy Health-->
                    <div class="healthDiv">
                        <div class="backgroundHealth"></div>
                        <div id="enemy-health"></div>
                    </div>
                </div>
    
                <canvas id="canvas"></canvas>
            </div>
    
            <p id="myConsole">&gt;&nbsp;<span id="myMessage"></span></p>
    
            <script src="app.js"></script>
        </body>
    </html>


  2. When setting width/height value, you need unit suffix like "px" if value is not 0

    const width = Player.health === 0 ? 0 : Player.health + "px";
    document.querySelector('#player-health').style.width = width ;
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search