20251109-2

我才发现我这碰撞检测写的简直是一坨屎,稍微优化了一下,虽然依旧一坨屎。
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  body {
    margin: 0;
    overflow: hidden;
  }
</style>

<body>
  <canvas id="Canvas" style="border:1px solid #000000;"></canvas>
</body>
<script>
  //初始化画布
  const canvas = document.getElementById('Canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  canvas.style.backgroundColor = '#000000';
  const ctx = canvas.getContext('2d');
  //定义游戏对象数组
  const grounds = [];
  const monsters = [];
  //定义玩家类
  class Player {
    //基础属性
    maxHp = 10;
    hp = 10;
    x = Math.round(canvas.width / 2);
    y = Math.round(canvas.height / 2);
    width = 30;
    height = 30;
    color = '#FF0000';
    invincibleColor = 'white';
    speedX = 0;
    speedY = 0;
    a = 0.05;
    g = 0.1;
    maxSpeedX = 3;
    maxSpeedY = 3;

    lastAttackedTime = Date.now();

    status = {
      up: false,
      down: false,
      left: false,
      right: false,

      landing: false,
      toward: 'right',
      attacking: false,
      invincible: false,
    }

    damage = {
      at: 1,
      width: 80,
      height: 40,
    }

    //方法

    //跳跃方法
    jump() {
      this.speedY = -5;
      this.status.landing = false;
    }
    //玩家运动
    move() {
      this.x += this.speedX;
      this.y += this.speedY;
    }
    //碰撞监测
    checkCrash() {
      //陆地检测
      grounds.forEach(Ground => {
        //下落碰撞检测
        if (Ground.y - (this.y + this.height) <= 0 &&
          Ground.y - (this.y + this.height) >= -this.speedY &&
          this.x + this.width > Ground.x &&
          this.x < Ground.x + Ground.width
        ) {
          this.y = Ground.y - this.height;
          this.status.landing = true;
        }
        //左侧
        if (
          this.x < Ground.x + Ground.width &&
          this.x > Ground.x + Ground.width + this.speedX &&
          this.y + this.height > Ground.y &&
          this.y < Ground.y + Ground.height
        ) {
          this.x = Ground.x + Ground.width;
          this.speedX = 0;
          this.status.left = false;
        }
        //右侧
        if (
          this.x + this.width > Ground.x &&
          this.x + this.width < Ground.x + this.speedX &&
          this.y + this.height > Ground.y &&
          this.y < Ground.y + Ground.height
        ) {
          this.x = Ground.x - this.width;
          this.speedX = 0;
          this.status.right = false;
        }
      });
      //边界检测
      if (this.x < 0) {
        this.x = 0;
        this.speedX = 0;
      }
      if (this.x + this.width > canvas.width) {
        this.x = canvas.width - this.width;
        this.speedX = 0;
      }
      if (this.y < 0) {
        this.y = 0;
        this.speedY = 0;
      }
      if (this.y + this.height > canvas.height) {
        this.y = canvas.height - this.height;
        this.status.landing = true;
      }
    }
    //重力作用
    applyGravity() {
      if (this.status.landing == false) {
        this.speedY += this.g;
        if (this.speedY > this.maxSpeedY)
          this.speedY = this.maxSpeedY;
      } else {
        this.speedY = 0;
      }
    }
    //水平无操作时水平减速
    velocityDecay() {
      if ((this.status.left == false && this.status.right == false) || (this.status.left == true && this.status.right == true)) {
        if (this.speedX > 0) {
          this.speedX -= this.a;
          if (this.speedX < 0) this.speedX = 0;
        } else if (this.speedX < 0) {
          this.speedX += this.a;
          if (this.speedX > 0) this.speedX = 0;
        }
      }
    }
    //水平加速度操作速度
    controlSpeed() {
      if (this.status.left) {
        this.speedX -= this.a;
        if (this.speedX < -this.maxSpeedX) this.speedX = -this.maxSpeedX;
      }
      if (this.status.right) {
        this.speedX += this.a;
        if (this.speedX > this.maxSpeedX) this.speedX = this.maxSpeedX;
      }
    }
    //绘制玩家
    draw() {
      if (this.status.invincible)
        ctx.fillStyle = this.invincibleColor;
      else
        ctx.fillStyle = this.color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    //展示血量数字
    showHp() {
      ctx.fillStyle = 'white';
      ctx.font = '12px Arial';
      ctx.fillText(this.hp, this.x + this.width / 2 - 6, this.y - 2);
    }
    //攻击方法
    attack(m) {
      m.hp -= this.damage.at;
      console.log("攻击命中!怪物剩余血量:" + m.hp);
      if (m.hp <= 0) {
        const index = monsters.indexOf(m);
        if (index > -1) {
          monsters.splice(index, 1);
          console.log("怪物已被击败!");
        }
      }
    }
    //绘制攻击范围与攻击判定
    drawAttackRange() {
      //绘制范围
      if (this.status.attacking) {
        ctx.fillStyle = '#FFFF00';
        if (this.status.toward == 'right') {
          ctx.fillRect(this.x + this.width, this.y + (this.height - this.damage.height) / 2, this.damage.width, this.damage.height);
        } else if (this.status.toward == 'left') {
          ctx.fillRect(this.x - this.damage.width, this.y + (this.height - this.damage.height) / 2, this.damage.width, this.damage.height);
        }
        //攻击判定
        monsters.forEach(m => {
          if (this.status.toward == 'right' &&
            m.x < this.x + this.width + this.damage.width &&
            m.x + m.width > this.x + this.width &&
            m.y < this.y + (this.height + this.damage.height) / 2 &&
            m.y + m.height > this.y + (this.height - this.damage.height) / 2
          ) {
            this.attack(m);
          }
          else if (
            this.status.toward == 'left' &&
            m.x + m.width > this.x - this.damage.width &&
            m.x < this.x &&
            m.y < this.y + (this.height + this.damage.height) / 2 &&
            m.y + m.height > this.y + (this.height - this.damage.height) / 2
          ) {
            this.attack(m);
          }
        })
        this.status.attacking = false;
      }
    }
    //受击方法
    attacked() {
      monsters.forEach(m => {
        if (
          m.x < this.x + this.width &&
          m.x + m.width > this.x &&
          m.y < this.y + this.height &&
          m.y + m.height > this.y
        ) {
          this.reduceHp(m.at);
        }
      });
    }
    //常规血量减少
    reduceHp(at) {
      const currentTime = Date.now();
      if (currentTime - this.lastAttackedTime > 1000) {
        this.hp -= at;
        this.status.invincible = true;
        this.lastAttackedTime = currentTime;
        //异步延迟
        setTimeout(() => {
          this.status.invincible = false;
        }, 1000);
      }
    }
  }
  //定义地面类
  class Ground {
    x = 0;
    y = 0;
    width = 0;
    height = 0;
    color = '#654321';

    constructor(x, y, width, height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
    }
  }
  //定义怪物类
  class Monster {
    hp = 5;
    at = 1;
    x = 0;
    y = 0;
    width = 30;
    height = 30;
    invincibleColor = 'white';
    speedX = 0;
    speedY = 0;
    a = 0.03;
    g = 0.1;
    maxSpeedX = 2;
    maxSpeedY = 3;
    color = '#00FF00';

    status = {
      up: false,
      down: false,
      left: false,
      right: false,

      landing: false,
      toward: 'right',
      attacking: false,
      invincible: false,
    }

    constructor(x, y, width, height) {
      this.x = x;
      this.y = y;
      this.width = width;
      this.height = height;
    }
    //绘制怪物
    draw() {
      ctx.fillStyle = this.color;
      ctx.fillRect(this.x, this.y, this.width, this.height);
    }
    //展示血量数字
    showHp() {
      ctx.fillStyle = 'white';
      ctx.font = '12px Arial';
      ctx.fillText(this.hp, this.x + this.width / 2 - 6, this.y - 2);
    }
    //怪物运动
    move() {
      this.x += this.speedX;
      this.y += this.speedY;
    }
    //水平加速度操作速度
    controlSpeed() {
      if (this.status.left) {
        this.speedX -= this.a;
        if (this.speedX < -this.maxSpeedX) this.speedX = -this.maxSpeedX;
      }
      if (this.status.right) {
        this.speedX += this.a;
        if (this.speedX > this.maxSpeedX) this.speedX = this.maxSpeedX;
      }
    }
    //判断玩家位置并移动
    pursuePlayer(p) {
      if (p.x < this.x) {
        this.status.left = true;
        this.status.right = false;
      } else if (p.x > this.x) {
        this.status.right = true;
        this.status.left = false;
      } else {
        this.status.left = false;
        this.status.right = false;
      }
    }
    //重力作用
    applyGravity() {
      if (this.status.landing == false) {
        this.speedY += this.g;
        if (this.speedY > this.maxSpeedY)
          this.speedY = this.maxSpeedY;
      } else {
        this.speedY = 0;
      }
    }
    //碰撞监测
    checkCrash() {
      grounds.forEach(Ground => {
        //下落碰撞检测
        if (Ground.y - (this.y + this.height) <= 0 &&
          Ground.y - (this.y + this.height) >= -this.speedY &&
          this.x + this.width > Ground.x &&
          this.x < Ground.x + Ground.width) {
          this.y = Ground.y - this.height;
          this.status.landing = true;
        }
        //左侧
        if (
          this.x < Ground.x + Ground.width &&
          this.x > Ground.x + Ground.width + this.speedX &&
          this.y + this.height > Ground.y &&
          this.y < Ground.y + Ground.height
        ) {
          this.x = Ground.x + Ground.width;
          this.speedX = 0;
        }
        //右侧
        if (
          this.x + this.width > Ground.x &&
          this.x + this.width < Ground.x + this.speedX &&
          this.y + this.height > Ground.y &&
          this.y < Ground.y + Ground.height
        ) {
          this.x = Ground.x - this.width;
          this.speedX = 0;
        }
      });
      //边界检测
      if (this.x < 0) {
        this.x = 0;
        this.speedX = 0;
      }
      if (this.x + this.width > canvas.width) {
        this.x = canvas.width - this.width;
        this.speedX = 0;
      }
      if (this.y < 0) {
        this.y = 0;
        this.speedY = 0;
      }
      if (this.y + this.height > canvas.height) {
        this.y = canvas.height - this.height;
        this.status.landing = true;
      }
    }
  }

  //创建初始测试 玩家对象 地面对象 怪物对象
  const p = new Player();
  const ground1 = new Ground(0, Math.round(canvas.height - 100), Math.round(canvas.width), 100);
  grounds.push(ground1);
  const monster1 = new Monster(200, ground1.y - 30, 30, 30);
  monsters.push(monster1);

  //键盘事件监听

  //1.按下按键
  document.addEventListener('keydown', function (event) {
    switch (event.key) {
      case 'ArrowUp':
        if (p.status.landing == true)
          p.jump();
        break;
      case 'ArrowDown':
        p.status.down = true;
        break;
      case 'ArrowLeft':
        p.status.left = true;
        p.status.toward = 'left';
        break;
      case 'ArrowRight':
        p.status.right = true;
        p.status.toward = 'right';
        break;
      case 'z':
        p.status.attacking = true;
        break;
      case 'Z':
        p.status.attacking = true;
        break;
    }
  });
  //2.松开按键
  document.addEventListener('keyup', function (event) {
    switch (event.key) {
      case 'ArrowUp':
        break;
      case 'ArrowDown':
        p.status.down = false;
        break;
      case 'ArrowLeft':
        p.status.left = false;
        break;
      case 'ArrowRight':
        p.status.right = false;
        break;
    }
  });
  //3.c键查看玩家状态
  document.addEventListener('keydown', function (event) {
    if (event.key === 'c' || event.key === 'C') {
      console.log("玩家状态:", p);
    }

  });
  //动画循环
  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    //绘制陆地
    grounds.forEach(Ground => {
      ctx.fillStyle = Ground.color;
      ctx.fillRect(Ground.x, Ground.y, Ground.width, Ground.height);
    });

    //玩家
    {
      //玩家运动
      p.move();
      //碰撞监测
      p.checkCrash();
      //重力作用
      p.applyGravity();
      //水平无操作时水平减速
      p.velocityDecay();
      //水平加速度操作速度
      p.controlSpeed();
      //受到伤害方法
      p.attacked()
      //绘制玩家
      p.draw();
      //展示血量
      p.showHp();
      //绘制攻击范围
      p.drawAttackRange();
    }

    //怪物
    {
      monsters.forEach(m => {
        //下落碰撞检测
        m.checkCrash();
        //重力作用
        m.applyGravity();
        //绘制怪物
        m.draw();
        //展示血量
        m.showHp();
        //怪物运动
        m.pursuePlayer(p)
        //水平加速度操作速度
        m.controlSpeed();
        //怪物移动
        m.move();
      });

    }
    requestAnimationFrame(animate);
  }
  //启动!!
  animate();
</script>

</html>

 

posted @ 2025-11-09 10:42  Lee_sz  阅读(6)  评论(0)    收藏  举报