我目前正在用原生的JavaScript、HTML和一些CSS创建一个游戏.我有两个名为Sprite的街区,每当它们朝画布的左边或右边走时,它们都不会停下来.Question:我如何使用原生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);

//Cahnging 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}) {
        this.position = position;
        this.velocity = velocity;
        this.height = 150;
        this.lastKey;
    }

    draw() {
        ctx.fillStyle = 'red';
        //Because this is inside of the class "Sprite",
        //We can use "this." to give us the position/velocity/whatever that is being used in this instance
        ctx.fillRect(this.position.x, this.position.y, 50, this.height);
    }

    update() {
        this.draw();
        this.position.x += this.velocity.x;
        this.position.y += this.velocity.y;

        //Stops the sprite from moving off the edge of the canvas
        if (this.position.x <= 0 || this.position.x + 50 >= canvas.width) {
            logMessage("Hi")
            this.velocity.x == 0;
        }

        //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;
        }
    }
}

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

const Enemy = new Sprite({
    position: {
        x: 400,
        y: 100
    },
    velocity: {
        x: 0,
        y: 0
    }
})

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

function animate() {
    //This makes the animate method run over and over
    window.requestAnimationFrame(animate);
    //The two below fill in the background so that when the sprites move, the background stays the same
    ctx.fillStyle = 'black';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
    Player.update();
    Enemy.update();

    //Player movement
    Player.velocity.x = 0; //This stops the sprite from continuously moving

    if (keys.a.pressed == true && Player.lastKey == "a") {
        Player.velocity.x = -5; //Changing this value will change how fast the sprite moves left
    } 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;
    }
}

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;
            //This keeps track of our last pressed key so our sprite does what was pressed most recently
            Player.lastKey = "a";
        break

        case 'd':
            keys.d.pressed = true;
            Player.lastKey = "d";
        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;
    }    
})

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;
    }
})
#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>
        <canvas id="canvas"></canvas>
        
        <p id="myConsole">&gt;&nbsp;<span id="myMessage"></span></p>

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

推荐答案

问题在于您确定画布范围的逻辑是有缺陷的.

您可以通过使用Math.min()Math.max()锁定position.x的界限来简化逻辑.我建议在你的精灵中增加一个width属性,以避免使用魔法数字.

this.position.x = Math.max(0, Math.min(canvas.width - 50, this.position.x + this.velocity.x));

下面是一个工作示例,请注意,我注释掉了另一个精灵以使效果更清晰.

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

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

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

//Cahnging 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
  }) {
    this.position = position;
    this.velocity = velocity;
    this.height = 150;
    this.lastKey;
  }

  draw() {
    ctx.fillStyle = 'red';
    ctx.fillRect(this.position.x, this.position.y, 50, this.height);
  }

  update() {
    this.draw();
    this.position.x = Math.max(0, Math.min(canvas.width - 50, this.position.x + this.velocity.x));
    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;
    }
  }
}

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

const Enemy = new Sprite({
  position: {
    x: 400,
    y: 100
  },
  velocity: {
    x: 0,
    y: 0
  }
})

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

function animate() {
  //This makes the animate method run over and over
  window.requestAnimationFrame(animate);
  //The two below fill in the background so that when the sprites move, the background stays the same
  ctx.fillStyle = 'black';
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  //Player.update();
  Enemy.update();

  //Player movement
  Player.velocity.x = 0; //This stops the sprite from continuously moving

  if (keys.a.pressed == true && Player.lastKey == "a") {
    Player.velocity.x = -5; //Changing this value will change how fast the sprite moves left
  } 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;
  }
}

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;
      //This keeps track of our last pressed key so our sprite does what was pressed most recently
      Player.lastKey = "a";
      break

    case 'd':
      keys.d.pressed = true;
      Player.lastKey = "d";
      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;
  }
})

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;
  }
})
#myConsole {
  background-color: black;
  color: white;
  min-height: 100px;
}
<canvas id="canvas"></canvas>

Javascript相关问答推荐

如何在使用fast-xml-parser构建ML时包括属性值?

通过使用100%间隔时间来代表我们还剩多少时间来倒计时

提交表格后保留Web表格中的收件箱值?

我开始使用/url?q=使用Cheerio

Cookie中未保存会话数据

在JavaScript中声明自定义内置元素不起作用

点击按钮一次有文本出现和褪色,而不是点击两次?(html,CSS,JavaScript)

用JavaScript复制C#CRC 32生成器

自定义高图中的x轴标签序列

Regex结果包含额外的match/group,只带一个返回

在运行时使用Next JS App Router在服务器组件中运行自定义函数

以Angular 实现ng-Circle-Progress时出错:模块没有导出的成员

DOM不自动更新,尽管运行倒计时TS,JS

使用插件构建包含chart.js提供程序的Angular 库?

WebSocketException:远程方在未完成关闭握手的情况下关闭了WebSocket连接.&#三十九岁;

JQuery使用选项填充HTMLSELECT并设置默认结果,默认结果显示为空

无法在Adyen自定义卡安全字段创建中使用自定义占位符

如何在不将整个文件加载到内存的情况下,在Node.js中实现Unix粘贴命令?

如何将值从后端传递到前端

在AgGrid中显示分组行的单元格值