我目前正在创建一款格斗游戏,我有两个精灵(玩家是蓝色的,敌人是红色的).我目前有一个可以工作的计时器.然而,时间到了之后,精灵仍然可以相互攻击,中间的文本会不断变化(如果运行代码片断会更有意义).

Question:如何才能使我的精灵在计时器结束后不能互相攻击?

100问:我如何在计时器用完后阻止我的精灵移动?我觉得如果第一个问题得到回答,我可以做这个问题

注意:我没有使用任何库或框架,我使用的是原生的JavaScript、CSS和HTML.

注意:使用"回车"或"空格键",当精灵中的一个降到没有生命值的时候.然后用另一个精灵,更多地击打原来的那个.最终,文本将从"玩家1/2获胜!"到"玩家2/1赢了!",尽管生命已经消失.

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

const winnerDisplay = document.querySelector('#winner-display');

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

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

ctx.fillRect(0, 0, canvas.width, canvas.height);

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

        //Attack box
        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.position.x = Math.max(0, Math.min(canvas.width - this.width, this.position.x + this.velocity.x));
        this.position.y = Math.max(0, Math.min(canvas.height, this.position.y + this.velocity.y));

        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
        }, 50)
    }
}

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: canvas.width,
        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 determineWinner({ Player, Enemy, timerId }) {
    clearTimeout(timerId);
    winnerDisplay.style.display = 'flex';

    if (Player.health == Enemy.health) {
        winnerDisplay.innerHTML = 'Tie!';
    }

    if (Player.health > Enemy.health) {
        winnerDisplay.innerHTML = 'Player 1 wins!';
    }

    if (Player.health < Enemy.health) {
        winnerDisplay.innerHTML = 'Player 2 wins!';
    }
}

//Timer and end game
//Feel free to change these starting values as you need
const startingMinutes = 1;
const startingSeconds = 30;
let time = startingMinutes * 60 + startingSeconds;
let timerId;

function decreaseTimer() {
    const timeLeft = document.querySelector('#time-left');

    if (time > 0) {
        timerId = setTimeout(decreaseTimer, 1000);

        const minutes = Math.floor(time / 60);
        let seconds = time % 60;

        seconds = seconds < 10 ? '0' + seconds : seconds;
        timeLeft.innerHTML = `0${minutes}:${seconds}`;
        time--;
    }

    if (time == 0) {
        timeLeft.innerHTML = `00:00`;
        determineWinner({ Player, Enemy, timerId });

        Player.position.x = 0;
        Enemy.position.x = canvas.width;
    }    
}

decreaseTimer();

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 the enemy hitting the player
    if (rectangularCollision({rectangle1: Enemy, rectangle2: Player})) {
        Enemy.isAttacking = false;
        Player.health -= 20;
        document.querySelector('#player-health').style.width = Player.health + '%';
    }  
    
    //End game based on health
    if (Enemy.health <= 0 || Player.health <= 0) {
        determineWinner({ Player, Enemy, timerId });
    }
}

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;
    display: flex;
    align-items: center;
    justify-content: center;
}

#winner-display {
    position: absolute;
    color: white;
    align-items: center;
    justify-content: center;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: none;
}

#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">
                    <span id="time-left">02:00</span>
                </div>

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

            <!--Winner display-->
            <div id="winner-display"></div>

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

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

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

推荐答案

跟踪整体游戏状态

使用变量跟踪游戏状态并帮助协调整个用户体验.

你如何跟踪状态(S)由你决定.它可以是单个布尔变量(TRUE/FALSE)或ENUM(例如‘LOADING’、‘INTRO’、‘PAUSED’、‘ACTIVE’、‘OVER’等).在任何情况下,你都会做一些东西来控制游戏的状态.

更深入地说,你可能还需要保存游戏回合的状态(例如当前回合或回合数等),当前角色是什么(在游戏角色可以交换的情况下),玩家是否启用了增强模式等.

无论如何,在游戏中,你在某些事件中设置或获得状态(S):

  1. 计时器启动
  2. 计时器结束
  3. 胜利者决出
  4. 按键
  5. 游戏暂停
  6. 等等..

为了说明这一点,我在这里创建了一个全局变量"gameIsActive":

var gameIsActive = true

然后,在某些事件中,我们设置状态,例如,当计时器结束时:

gameIsActive = false

然后,在某些事件中,我们获得状态并相应地执行逻辑,例如,只有当gameIsActivetrue时才会发生移动:

window.addEventListener('keyup', (event) => {
    if (gameIsActive) {
        // do stuff...

Here it is applied to your mini-game:

https://codepen.io/MarsAndBack/pen/OJqLRWK?editors=1111

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

// NEW
var gameIsActive = true;

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

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

ctx.fillRect(0, 0, canvas.width, canvas.height);

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

        //Attack box
        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.position.x = Math.max(0, Math.min(canvas.width - this.width, this.position.x + this.velocity.x));
        this.position.y = Math.max(0, Math.min(canvas.height, this.position.y + this.velocity.y));

        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
        }, 50)
    }
}

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: canvas.width,
        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 determineWinner({ Player, Enemy, timerId }) {
    clearTimeout(timerId);
    winnerDisplay.style.display = 'flex';

    if (Player.health == Enemy.health) {
        winnerDisplay.innerHTML = 'Tie!';
    }

    if (Player.health > Enemy.health) {
        winnerDisplay.innerHTML = 'Player 1 wins!';
    }

    if (Player.health < Enemy.health) {
        winnerDisplay.innerHTML = 'Player 2 wins!';
    }
}

//Timer and end game
//Feel free to change these starting values as you need
const startingMinutes = 1;
const startingSeconds = 30;
let time = startingMinutes * 60 + startingSeconds;
let timerId;

function decreaseTimer() {
    const timeLeft = document.querySelector('#time-left');

    if (time > 0) {
        timerId = setTimeout(decreaseTimer, 1000);

        const minutes = Math.floor(time / 60);
        let seconds = time % 60;

        seconds = seconds < 10 ? '0' + seconds : seconds;
        timeLeft.innerHTML = `0${minutes}:${seconds}`;
        time--;
    }

    if (time == 0) {
        timeLeft.innerHTML = `00:00`;

        // NEW
        gameIsActive = false;

        determineWinner({ Player, Enemy, timerId });

        Player.position.x = 0;
        Enemy.position.x = canvas.width;
    }    
}

decreaseTimer();

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 the enemy hitting the player
    if (rectangularCollision({rectangle1: Enemy, rectangle2: Player})) {
        Enemy.isAttacking = false;
        Player.health -= 20;
        document.querySelector('#player-health').style.width = Player.health + '%';
    }  
    
    //End game based on health
    if (Enemy.health <= 0 || Player.health <= 0) {

        // NEW
        gameIsActive = false;

        determineWinner({ Player, Enemy, timerId });
    }
}

animate();

window.addEventListener('keydown', (event) => {
  
  // NEW 
  if (gameIsActive) {
     
      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) => {
  
  // NEW 
  if (gameIsActive) {
    
    //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;
    display: flex;
    align-items: center;
    justify-content: center;
}

#winner-display {
    position: absolute;
    color: white;
    align-items: center;
    justify-content: center;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    display: none;
}

#myConsole {
    background-color: black;
    color: white;
    min-height: 100px;
}
<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">
                    <span id="time-left">02:00</span>
                </div>

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

            <!--Winner display-->
            <div id="winner-display"></div>

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

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

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

Javascript相关问答推荐

RxJS setTimeout操作符等效

如何最好地从TypScript中的enum获取值

从PWA中的内部存储读取文件

useNavigation更改URL,但不呈现或显示组件

判断表格单元格中是否存在文本框

我怎么才能得到Kotlin的密文?

JS:XML insertBefore插入元素

扩展类型的联合被解析为基类型

使用NextJS+MongoDB+Prisma ORM获取无效请求正文,无法发布错误

在SHINY R中的嵌套模块中,不能使用Java代码

如何使用基于promise (非事件emits 器)的方法来传输数据?

将范围 Select 器添加到HighChart面积图

Socket.IO在刷新页面时执行函数两次

是否可以在不更改组件标识的情况下换出Reaction组件定义(以维护状态/引用等)?如果是这样的话,是如何做到的呢?

Chart.js Hover线条在鼠标离开时不会消失

如何在Web项目中同步语音合成和文本 colored颜色 更改

无法向甜甜圈图表上的ChartJSImage添加可见标签

将Windows XP转换为原始数据以在html前端中显示

我想为我的Reaction项目在画布上加载图像/视频,图像正在工作,但视频没有

浮动标签效果移除时,所需的也被移除