如何让我的角色在重力下跳跃?

时间:2018-01-06 18:22:30

标签: javascript css html5-canvas

我是编码的新手,我正在制作游戏,但我不知道如何模拟重力让我的角色跳跃。我尝试了许多不同的事情,结果却带来了灾难性的后果。这是我的代码:



#canvas {
  border: 1px solid #d3d3d3;
  background-color: #f1f1f1;
}

<body>

  <canvas id='canvas' width='512px' height='300px'></canvas>

  <script>
    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    let charX = 20;
    let charY = 130;
    let charSide = 20;
    let velocity = 0;
    let resistance = 0;
    let rightPressed = false;
    let leftPressed = false;
    let upPressed = false;
    let aPressed = false;
    let dPressed = false;

    function drawRect(x, y, width, height, color) {
      ctx.beginPath();
      ctx.rect(x, y, width, height);
      ctx.fillStyle = color;
      ctx.fill();
      ctx.closePath();
    }

    function drawGround(x, y, count) {
      if (count === undefined) {
        count = 1;
      }
      drawRect(x, y, 32 * count, canvas.height - y, '#684027');
      drawRect(x, y, 32 * count, 10, 'green');
    }

    function draw() {
      //Updates Game
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      //Draws Character
      drawRect(charX, charY, charSide, charSide, 'lime');
      //Draws Ground
      drawGround(0, 150, 16);
      //Moves Character
      if (charY = 130) {
        speed = 0;
        accelerate = 0;
      }
      if (rightPressed && charX < canvas.width - charSide) {
        charX += 2;
      } else if (leftPressed && charX > 0) {
        charX -= 2;
      } else if (upPressed && charY > 0 && charY < 131) {
        velocity = 0;
        velocity += 50;
        resistance++;
        velocity -= resistance;
        charY -= velocity;
      } else if (upPressed === false && charY > 129) {
        resistance = 0;
        velocity = 0;
      }
    }
    //Character Movement Logic
    document.addEventListener("keydown", keyDownHandler, false);
    document.addEventListener("keyup", keyUpHandler, false);

    function keyDownHandler(e) {
      if (e.keyCode == 39) {
        rightPressed = true;
      } else if (e.keyCode == 37) {
        leftPressed = true;
      } else if (e.keyCode == 38) {
        upPressed = true;
      } else if (e.keyCode == 65) {
        aPressed = true;
      } else if (e.keyCode == 68) {
        dPressed = true;
      }
    }

    function keyUpHandler(e) {
      if (e.keyCode == 39) {
        rightPressed = false;
      } else if (e.keyCode == 37) {
        leftPressed = false;
      } else if (e.keyCode == 38) {
        upPressed = false;
      } else if (e.keyCode == 65) {
        aPressed = false;
      } else if (e.keyCode == 68) {
        dPressed = false;
      }
    }
    //Animates Game
    setInterval(draw, 10);
  </script>

</body>
&#13;
&#13;
&#13;

我试图制作不同的变量,比如速度和阻力,并在跳跃时将它们应用到我的角色的y位置,但它不起作用。

2 个答案:

答案 0 :(得分:4)

简单的游戏物理

首先动画使用requestAnimationFrame为动画计时。以下示例显示了如何。

重力

假设帧速率恒定,可以应用最简单的引力。对象具有y位置和y速度(Δy)。重力是一个恒定的力,每帧增加Δy

obj = {
   y : 0,  // position
   dy : 0, // speed
   size : 20, // height
   onGround : false,  // true if on the ground
   drag : 0.99, // the drag is 0.01 
}
const grav = 0.1;

每个框架(动画刻度线)应用重力并更新位置

obj.dy += grav;
obj.y += obj.dy;

如果物体撞击地面,则将delta y归零

if(obj.y + obj.size >= 150){ // has hit ground
   obj.y = 150 - obj.size;  // place on ground
   obj.dy = 0;              // stop delta y
   obj.onGround = true;
}else{
   obj.onGround = false;
}

然后绘制角色

跳转

要使角色跳转,只需将delta y设置为负值。仅在角色在地面时设置。上面的代码会让角色及时回归。

if(keyboard.up && obj.onGround){
   obj.dy = -5;
}

添加一些与速度成比例的阻力或阻力。你去的速度越快,你就会创建一个阻力系数。在添加重力后,将每个帧的delta y乘以此值。

obj.dy *= obj.drag;  // reduce speed due to drag

下面的示例显示了一个可以从地面跳起并左右移动的玩家。跳跃有一点阻力,当玩家在地面时,左右移动会有很大阻力。

演示

const ctx = canvas.getContext('2d');

// Simple keyboard handler
const keyboard = (() => {
  document.addEventListener("keydown", keyHandler);
  document.addEventListener("keyup", keyHandler);
  const keyboard = {
    right: false,
    left: false,
    up: false,
    any : false,
  };
  function keyHandler(e) {
    const state = e.type === "keydown"
    if (e.keyCode == 39) {
      keyboard.right = state;
    } else if (e.keyCode == 37) {
      keyboard.left = state;
    } else if (e.keyCode == 38) {
      keyboard.up = state;
      e.preventDefault();
    }
    if(state) { keyboard.any = true } // must reset when used
  }
  return keyboard;
})();

// define the player.
// update() updates position and response to keyboard
// draw() draws the player
// start() sets start position and state
const player = {
  x: 0,
  y: 0,
  dx: 0, // delta x and y
  dy: 0,
  size: 20,
  color: 'lime',
  onGround: false,
  jumpPower: -5,  // power of jump smaller jumps higher eg -10 smaller than -5
  moveSpeed: 2,
  update() {
    // react to keyboard state
    if (keyboard.up && this.onGround) { this.dy = this.jumpPower }
    if (keyboard.left) { this.dx = -this.moveSpeed }
    if (keyboard.right) { this.dx = this.moveSpeed }
 
    // apply gravity drag and move player
    this.dy += world.gravity;
    this.dy *= world.drag;
    this.dx *= this.onGround ? world.groundDrag : world.drag;
    this.x += this.dx;
    this.y += this.dy;

    // test ground contact and left and right limits
    if (this.y + this.size >= world.ground) {
      this.y = world.ground - this.size;
      this.dy = 0;
      this.onGround = true;
    } else {
      this.onGround = false;
    }
    if (this.x > ctx.canvas.width) {
      this.x -= ctx.canvas.width;
    } else if (this.x + this.size < 0) {
      this.x += ctx.canvas.width;
    }
  },
  draw() {
    drawRect(this.x, this.y, this.size, this.size, this.color);
  },
  start() {
    this.x = ctx.canvas.width / 2 - this.size / 2;
    this.y = world.ground - this.size;
    this.onGround = true;
    this.dx = 0;
    this.dy = 0;
  }
}
// define world
const world = {
  gravity: 0.2, // strength per frame of gravity
  drag: 0.999, // play with this value to change drag
  groundDrag: 0.9, // play with this value to change ground movement
  ground: 150,
}
// set start
player.start();
// call first frame. This will run after all the rest of the code has run
requestAnimationFrame(mainLoop); // start when ready

// From OP
function drawRect(x, y, width, height, color) {
  ctx.beginPath();
  ctx.rect(x, y, width, height);
  ctx.fillStyle = color;
  ctx.fill();
  ctx.closePath();
}

function drawGround(x, y, count = 1) {
  drawRect(x, y, 32 * count, canvas.height - y, '#684027');
  drawRect(x, y, 32 * count, 10, 'green');
}
// show instruct
var showI = true;
// main animation loop
function mainLoop(time) { // time passed by requestAnimationFrame        
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawGround(0, world.ground, 16);
  player.update();
  player.draw();
  if(showI){
     if(keyboard.any){
         keyboard.any = false;
         showI = false;
     }
     ctx.textAlign = "center";
     ctx.font = "24px arial";
     ctx.fillStyle = "#000";
     ctx.fillText("Up arrow to jump. Left right to move",ctx.canvas.width / 2, 80);
  }
  requestAnimationFrame(mainLoop);
}

// make sure window has focus for keyboard input.
window.focus();
#canvas {
  border: 1px solid #d3d3d3;
  background-color: #f1f1f1;
}
<canvas id='canvas' width='512px' height='300px'></canvas>

答案 1 :(得分:2)

一些建议:

  • 你的基本问题是速度和阻力的大小。通过调整你改变这些数量,你会越来越近。
  • 根据时间运行动画;不要在每次抽奖时更新头寸。这将使其对渲染率不变。
  • 封装您的对象以模拟其属性,包括重力对其的影响。这会让你在开发代码时不那么疯狂。
  • 有关于如何做到这一点的一些很棒的教程。搜索一下,你会发现一些有用的技术。