如何为这个元素赋予惯性/动量?

3

我正在开发一个基于Asteroids的小游戏,只使用DOM而非Canvas。目前,当按下箭头键时,“飞船”移动得相当平滑,但是我该如何给予飞船动量呢?当用户松开键时,我不希望飞船停止。我试图模拟一点太空物理学。如何让这艘飞船在保持原来方向运动的同时允许自由旋转,而不会朝着它当前指向的方向移动(除非按下上箭头)?有什么想法吗?

var Keys = {
  up: false,
  down: false,
  left: false,
  right: false
}

window.onkeydown = function( e ) {
  var kc = e.keyCode;
  e.preventDefault();

  if ( kc === 37 ) Keys.left = true;
  else if ( kc === 38 ) Keys.up = true;
  else if ( kc === 39 ) Keys.right = true;
  else if ( kc === 40 ) Keys.down = true;
};

window.onkeyup = function( e ) {
  var kc = e.keyCode;
  e.preventDefault();

  if ( kc === 37 ) Keys.left = false;
  else if ( kc === 38 ) Keys.up = false;
  else if ( kc === 39 ) Keys.right = false;
  else if ( kc === 40 ) Keys.down = false;
};
@import url( "https://fonts.googleapis.com/css?family=Nunito" );

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  font-family: "Nunito", sans-serif;
  font-size: 4rem;
}

b {
  display: block;
  transform: rotate( 180deg );
}
<div>
  <b>v</b>
</div>

<script>
  function update() {
    if ( Keys.up ) {
      document.querySelector( 'div' ).style.transform += 'translateY( -1px )';
    }
    else if ( Keys.down ) {
      document.querySelector( 'div' ).style.transform += 'translateY( 1px )';
    }

    if ( Keys.left ) {
      document.querySelector( 'div' ).style.transform += 'rotate( -1deg )';
    }
    else if ( Keys.right ) { 
      document.querySelector( 'div' ).style.transform += 'rotate( 1deg )';
    }

    requestAnimationFrame( update );
  }
  
  requestAnimationFrame( update );
</script>

使用箭头键控制代码片段。

我给你提供了一个以惯性为例的示例...你需要定义一个速度,这个速度会慢慢减小以模拟阻力,并使用这个速度来增加位置。 - vals
@vals 问题是船只总是朝向前进的方向移动。我仍在尝试找出一个解决办法,可以使船只在释放按键时继续保持原来的前进方向。当推进停止时,船只旋转时不应该跟着转动。 - Lynel Hudson
1个回答

3
注意:你正在使用的控制方法将大量的“translate”指令添加到你的船元素样式中。运行你的片段,打开浏览器检查器并检查游戏。每一帧,你都会追加新的增量变换。这不是可持续的方法!每个单独的变换代表一个单独的计算,每帧重新计算和应用,更不用说标记正在不断扩展。
矩阵操作顺序很重要,因此旋转后跟随平移将沿着旋转方向移动,而平移后跟随旋转将产生不同的结果(虽然也不是你想要的)。
理想情况下,你应该完全改变你的移动代码。如果你想坚持使用CSS进行渲染,而不是在每一帧上附加新的转换,你将希望在每一帧上更新转换属性。你可能需要获得一个矩阵数学库(例如http://glmatrix.net/),然后在JavaScript变量中应用和存储你的变换,并只将最终计算的变换推送到CSS进行渲染(更新而不是附加)。
此时,您可以开始解决问题:需要将旋转与平移方向分离。最终目标是能够表示一艘船绕其自身原点旋转,并以正确的世界位置进行平移,在一个聚合矩阵中总结应用于船上的所有变换及其应用顺序。有几种方法可以做到这一点。其中一种非常简单和常见的方法是通过转换暂时将您的船放置在其原点(您想要围绕其旋转的点)处,应用旋转变换,然后将最终平移应用到您想要的船的位置。如果您使用我建议的矩阵库,则会对表示船的变换的矩阵执行此操作。
我建议您阅读有关矩阵及其堆叠方式的内容,有大量的游戏开发教程讨论了这个问题 - 更具体地讲,如何推送=应用和弹出=撤消变换矩阵(提示:我上面提到的0,0旋转涉及暂时推送新的变换,将聚合变换位置带到0,0,计算处于该变换状态下的船的所需旋转,然后弹出最后一个变换矩阵=撤消到0,0的平移,这只是您暂时需要的)。
祝您好运!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接