飞码网-免费源码博客分享网站

点击这里给我发消息

快速技巧:如何用JavaScript制作游戏循环|-JavaScript教程

飞码网-免费源码博客分享网站 爱上飞码网—https://www.codefrees.com— 飞码网-matlab-python-C++ 爱上飞码网—https://www.codefrees.com— 飞码网-免费源码博客分享网站

“游戏圈”是给用来渲染动画和游戏随着时间的推移不断变化的状态的技术名称。它的核心是尽可能多次运行的功能,接受用户输入,更新经过的时间的状态,然后绘制框架。

在这篇简短的文章中,您将学习这种基本技术的工作原理,并且能够开始制作自己的基于浏览器的游戏和动画。

JavaScript中的游戏循环如下所示:

function update(progress) {
  // Update the state of the world for the elapsed time since last render
}

function draw() {
  // Draw the state of the world
}

function loop(timestamp) {
  var progress = timestamp - lastRender

  update(progress)
  draw()

  lastRender = timestamp
  window.requestAnimationFrame(loop)
}
var lastRender = 0
window.requestAnimationFrame(loop)

requestAnimationFrame方法请求浏览器在下一次重绘发生之前尽快调用指定的函数。这是专门用于渲染动画的API,但您也可以setTimeout在较短的超时时间内使用以获得类似的结果。requestAnimationFrame在回调开始触发时传递一个时间戳,它包含自加载窗口以来的毫秒数,并且等于performance.now()。

progress值或两次渲染之间的时间对于创建平滑动画至关重要。通过使用它来调整update函数中的x和y位置,我们确保动画以一致的速度移动。

更新职位

我们的第一个动画将超级简单。一个红色方块,向右移动,直到到达画布的边缘,然后循环回到起点。

我们需要存储正方形的位置并在update函数中增加x的位置当我们达到边界时,我们可以减去画布宽度来回绕。

var width = 800
var height = 200

var state = {
  x: width / 2,
  y: height / 2
}

function update(progress) {
  state.x += progress

  if (state.x > width) {
    state.x -= width
  }
}

绘制新框架

此示例使用<canvas>元素来渲染图形,但是游戏循环也可以与其他输出(例如HTML或SVG文档)一起使用。

draw函数仅呈现世界的当前状态。在每一帧上,我们将清除画布,然后绘制一个10px的红色正方形,其中心位于存储在state对象中的位置

var canvas = document.getElementById("canvas")
var width = canvas.width
var height = canvas.height
var ctx = canvas.getContext("2d")
ctx.fillStyle = "red"

function draw() {
  ctx.clearRect(0, 0, width, height)

  ctx.fillRect(state.x - 5, state.y - 5, 10, 10)
}

而且我们有运动!

请参阅CodePen上的JavaScript:SitePoint的基本运动(@SitePoint)中的笔游戏循环。

 

注意:在演示中,您可能会注意到CSS以及HTML元素上的viawidthheight属性都设置了画布的大小CSS样式设置将绘制到页面上的canvas元素的实际大小,HTML属性设置canvas API将使用的坐标系或“网格”的大小。有关更多信息,请参见此堆栈溢出问题。

 

 

响应用户输入

接下来,我们将获得键盘输入来控制对象的位置,state.pressedKeys并跟踪按下了哪些键。

var state = {
  x: (width / 2),
  y: (height / 2),
  pressedKeys: {
    left: false,
    right: false,
    up: false,
    down: false
  }
}

让我们听听所有的keydown和keyup事件,并进行相应的更新state.pressedKeys我将使用的键是D右,A左,W上和S下。您可以在此处找到关键代码列表。

var keyMap = {
  68: 'right',
  65: 'left',
  87: 'up',
  83: 'down'
}
function keydown(event) {
  var key = keyMap[event.keyCode]
  state.pressedKeys[key] = true
}
function keyup(event) {
  var key = keyMap[event.keyCode]
  state.pressedKeys[key] = false
}

window.addEventListener("keydown", keydown, false)
window.addEventListener("keyup", keyup, false)

然后,我们只需要根据所按下的键来更新x和y值,并确保我们将对象保持在边界之内。

function update(progress) {
  if (state.pressedKeys.left) {
    state.x -= progress
  }
  if (state.pressedKeys.right) {
    state.x += progress
  }
  if (state.pressedKeys.up) {
    state.y -= progress
  }
  if (state.pressedKeys.down) {
    state.y += progress
  }

  // Flip position at boundaries
  if (state.x > width) {
    state.x -= width
  }
  else if (state.x < 0) {
    state.x += width
  }
  if (state.y > height) {
    state.y -= height
  }
  else if (state.y < 0) {
    state.y += height
  }
}

并且我们有用户输入!

 

请参阅Javascript中的笔游戏循环:在CodePen上处理SitePoint(@SitePoint)的用户输入。

 

小行星

既然我们掌握了基础知识,我们可以做一些更有趣的事情。

像在经典游戏《小行星》中看到的那样,制造一艘船并没有那么复杂。

我们state需要存储一个附加的矢量(x,y对)以进行运动以及船舶方向的旋转。

var state = {
  position: {
    x: (width / 2),
    y: (height / 2)
  },
  movement: {
    x: 0,
    y: 0
  },
  rotation: 0,
  pressedKeys: {
    left: false,
    right: false,
    up: false,
    down: false
  }
}

我们的update职能需要更新三件事:

  • 根据向左/向右按键旋转
  • 移动基于上/下键和旋转
  • 位置基于所述运动矢量和画布的边界
function update(progress) {
  // Make a smaller time value that's easier to work with
  var p = progress / 16

  updateRotation(p)
  updateMovement(p)
  updatePosition(p)
}

function updateRotation(p) {
  if (state.pressedKeys.left) {
    state.rotation -= p * 5
  }
  else if (state.pressedKeys.right) {
    state.rotation += p * 5
  }
}

function updateMovement(p) {
  // Behold! Mathematics for mapping a rotation to it's x, y components
  var accelerationVector = {
    x: p * .3 * Math.cos((state.rotation-90) * (Math.PI/180)),
    y: p * .3 * Math.sin((state.rotation-90) * (Math.PI/180))
  }

  if (state.pressedKeys.up) {
    state.movement.x += accelerationVector.x
    state.movement.y += accelerationVector.y
  }
  else if (state.pressedKeys.down) {
    state.movement.x -= accelerationVector.x
    state.movement.y -= accelerationVector.y
  }

  // Limit movement speed
  if (state.movement.x > 40) {
    state.movement.x = 40
  }
  else if (state.movement.x < -40) {
    state.movement.x = -40
  }
  if (state.movement.y > 40) {
    state.movement.y = 40
  }
  else if (state.movement.y < -40) {
    state.movement.y = -40
  }
}

function updatePosition(p) {
  state.position.x += state.movement.x
  state.position.y += state.movement.y

  // Detect boundaries
  if (state.position.x > width) {
    state.position.x -= width
  }
  else if (state.position.x < 0) {
    state.position.x += width
  }
  if (state.position.y > height) {
    state.position.y -= height
  }
  else if (state.position.y < 0) {
    state.position.y += height
  }
}

draw功能在绘制箭头形状之前平移并旋转画布原点。

function draw() {
  ctx.clearRect(0, 0, width, height)

  ctx.save()
  ctx.translate(state.position.x, state.position.y)
  ctx.rotate((Math.PI/180) * state.rotation)

  ctx.strokeStyle = 'white'
  ctx.lineWidth = 2
  ctx.beginPath ()
  ctx.moveTo(0, 0)
  ctx.lineTo(10, 10)
  ctx.lineTo(0, -20)
  ctx.lineTo(-10, 10)
  ctx.lineTo(0, 0)
  ctx.closePath()
  ctx.stroke()
  ctx.restore()
}

这就是我们像Asteroids中一样重新创建飞船所需的全部代码。该演示的按键与上一个相同(D右,A左,W上和S下)。

 

飞码网-免费源码博客分享网站 爱上飞码网—https://www.codefrees.com— 飞码网-matlab-python-C++ 爱上飞码网—https://www.codefrees.com— 飞码网-免费源码博客分享网站
赞 ()

相关推荐

内容页底部广告位3
留言与评论(共有 0 条评论)
   
验证码: