3

Have a very small snippet of an asteroids-like game I'm working on using only the DOM without Canvas. I have the "ship" moving pretty smoothly when arrow keys are pressed but how would I go about giving the ship momentum? When the user releases a key I don't want the ship to stop. I'm trying to simulate the physics of space a little bit. How could I get this ship to keep moving in the direction it was going while allowing it to rotate freely without traveling in the direction it's currently pointing ( unless up arrow is being pressed )? Ideas?

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>

Use the arrow keys to control snippet.

Lynel Hudson
  • 2,335
  • 1
  • 18
  • 34
  • I gave you an example using inertia ... you need to define a speed, the speed slowly decreases to simulate drag, and you use the speed to increase the position. – vals May 02 '17 at 16:10
  • @vals The problem is the ship always moves in the direction it's facing. Still trying to figure out a solution that will keep moving the ship in the direction it was going when the key was released. When the ship is turned while thrust is released it shouldn't follow the turn. – Lynel Hudson May 02 '17 at 16:16

1 Answers1

3

Note: The control method you're using is adding tons of translate directives into your ship element's style. Run your snippet, open up the browser inspector, and examine the game. Every frame, you are appending new incremental transforms. This is not a sustainable approach! Each individual transformation represents a separate computation that is re-computed and applied each frame, not to mention that the markup is expanding like crazy.

Matrix operation order matters, and so rotate followed by translate will move in the rotated direction, whereas translate followed by rotate will produce a different result (also not what you want though).

Ideally you'd change your movement code entirely. If you want to stick with CSS for rendering, instead of appending new transforms on each frame, you'll want to instead update the transform property on each frame. You'll probably want to get a matrix math library (e.g. http://glmatrix.net/) and then apply and store your transforms in JavaScript variables and only push the final computed transforms to CSS for rendering (update, not append).

At this point you can begin to solve the issue: you need to decouple rotation from the translate direction. The end goal is to be able to represent a ship rotated on its own point of origin, and translated to the right world position, in 1 aggregated matrix which summarizes all the transforms applied on the ship, and in what order they were applied. There are several ways to do this. One very simple and common way to do this is to temporarily place your ship (via transform) so that its point of origin (around which you want to rotate) is at 0, 0, apply the rotation transformation, and then apply the final translation to where you want the ship to actually be. If you use a matrix library as I suggested, then you'd perform this on the matrix that represents your ship's transform.

I suggest you read about matrices and how they stack, there's tons of game development tutorials that talk about this - and more specifically about how transformation matrices can be pushed = applied and popped = undone (hint: the 0,0 rotation thing I mentioned above involves pushing a new transform temporarily which brings the aggregate transformation position to 0,0, computing the ship's desired rotation while under this this transform state, and then popping the last transformation matrix = undo the translation to 0, 0 which you only needed temporarily).

Best of luck!

smerg
  • 1,506
  • 3
  • 10
  • 14