Home > other >  How to add dash function with vectors
How to add dash function with vectors

Time:02-02

In my 2D (top-down) game, I am attempting to add a dash function.

Using an if (keyWentDown("e")) {} condition inside a function named dash. I have a thing set up to face the player's direction, being: plrvector.rotation = 90, and I want my character to move about 50px smoothly when E is pressed.

Problem is, I have no clue how to use vectors. Any tips or directions? I have attempted to use various techniques; however, I could not find any tutorials or anything that could help me.

CodePudding user response:

I am not sure you want to move the player exactly 50px. You would just temporarily increase the velocity by a factor. In the example below, if the E key is pressed, a "turbo" mode is activate increasing the speed by a factor of 3.

You would have to do something along the lines of:

function update(progress) {
  const { player } = state;
  const turbo = state.pressedKeys.turbo ? 3 : 1; // x3 speed (E)

  if (state.pressedKeys.left) {
    if (player.speed.x > 0) player.speed.x *= -1;
    player.position.x  = progress * player.speed.x * turbo;
  }
}

Note: This can be modified to only allow turbo for a short duration. For instance, the player may have a turbo meter that they need to fill in order to use this mode.

The following example is adapted from: "Quick Tip: How to Make a Game Loop in JavaScript". I did not utilize vectors pre se, but I store the position and velocity (speed) in a vector-like object. If you want to convert this to vectors, you can check out victor.js. It can easily add/multiply/normalize vectors for you.

// Canvas context reference
const ctx = document.querySelector('#game').getContext('2d');
const hud = document.querySelector('#hud');

// Set the canvas size
Object.assign(ctx.canvas, { width: 600, height: 160 });

// Game state
const state = {
  player: {
    dimensions: { depth: 10, height: 10, width: 10 },
    position: { x: Math.floor(ctx.canvas.width / 2), y: Math.floor(ctx.canvas.height / 2) },
    speed: { x: 0.25, y: 0.25 }
  },
  pressedKeys: {
    left: false,
    right: false,
    turbo: false,
    up: false,
    down: false
  }
};

// Track keys
const keyMap = new Map(Object.entries({
  ArrowDown: 'down',
  ArrowLeft: 'left',
  ArrowRight: 'right',
  ArrowUp: 'up',
  a: 'left',
  d: 'right',
  e: 'turbo',
  s: 'down',
  w: 'up',
}));

// Game Loop ~ Update
function update(progress) {
  const { player } = state;
  
  hud.innerText = Object.entries(state.pressedKeys)
    .filter(([k, v]) => v)
    .map(([k]) => `<${k}>`)
    .sort()
    .join(' ');
    
  const turbo = state.pressedKeys.turbo ? 3 : 1; // x3 speed (E)

  // Check pressed keys to update position
  if (state.pressedKeys.left) {
    if (player.speed.x > 0) player.speed.x *= -1;
    player.position.x  = progress * player.speed.x * turbo;
  }
  if (state.pressedKeys.right) {
    if (player.speed.x < 0) player.speed.x *= -1;
    player.position.x  = progress * player.speed.x * turbo;
  }
  if (state.pressedKeys.up) {
    if (player.speed.y > 0) player.speed.y *= -1;
    player.position.y  = progress * player.speed.y * turbo;
  }
  if (state.pressedKeys.down) {
    if (player.speed.y < 0) player.speed.y *= -1;
    player.position.y  = progress * player.speed.y * turbo;
  }

  // Check bounds
  const threshold = player.dimensions.width;
  if (player.position.x > ctx.canvas.width - threshold) {
    player.position.x = ctx.canvas.width - threshold;
  } else if (player.position.x < threshold) {
    player.position.x = threshold;
  }
  if (player.position.y > ctx.canvas.height - threshold) {
    player.position.y = ctx.canvas.height - threshold;
  } else if (player.position.y < threshold) {
    player.position.y = threshold;
  }
}

// Game Loop ~ Draw
function draw() {
  const { player, pressedKeys } = state;

  ctx.fillStyle = 'black';
  ctx.beginPath();
  ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  ctx.closePath();
  
  ctx.fillStyle = 'red';
  ctx.beginPath();
  ctx.arc(player.position.x, player.position.y, player.dimensions.width, 0, 2 * Math.PI);
  ctx.fill();
  ctx.closePath();
}

// Game Loop ~ Main
function loop(timestamp) {
  const progress = timestamp - lastRender;
  update(progress);
  draw();
  lastRender = timestamp;
  window.requestAnimationFrame(loop);
}

// Begin game
let lastRender = 0;
window.requestAnimationFrame(loop);

// Register keyboard events
window.addEventListener('keydown', onKeyDown, false);
window.addEventListener('keyup', onKeyUp, false);

// Event handlers
function onKeyDown({ key }) {
  toggleKey(key, true);
}
function onKeyUp({ key }) {
  toggleKey(key, false);
}

// Convenience
function toggleKey(key, value) {
  const index = keyMap.get(key);
  if (index) {
    const currentValue = state.pressedKeys[index];
    state.pressedKeys[index] = value ?? !currentValue;
  }
}
*, *::before,*::after { box-sizing: border-box; }
html, body { width: 100%; height: 100%; margin: 0; padding: 0; }
body {
  display: flex; flex-direction: column;
  align-items: center; justify-content: flex-start; gap: 0.25em;
  padding: 0.25em;
}
#hud { white-space: pre; text-transform: uppercase; }
<!-- See: https://www.sitepoint.com/quick-tip-game-loop-in-javascript/ -->
<canvas id="game"></canvas>
<div id="hud"></div>


Vector math

Here is an example of adding/multiplying vectors:

  1. Add t and u to get { x: 4, y: 7 }
  2. Multiply the result above by t to get { x: 4, y: 14 }

const vectorAdd = (a, b) => ({ x: a.x   b.x, y: a.y   b.y });
const vectorMultiply = (a, b) => ({ x: a.x * b.x, y: a.y * b.y });

let t = { x: 1, y: 2 }, u = { x: 3, y: 5 }, v = vectorMultiply(vectorAdd(t, u), t);
console.log(v); // { x: 4, y: 14 }

If you want to chain these calls, you can try creating a wrapper:

const vectorAdd = (a, b) => ({ x: a.x   b.x, y: a.y   b.y });
const vectorMultiply = (a, b) => ({ x: a.x * b.x, y: a.y * b.y });

const vector = function({ x, y }) {
  [this.x, this.y] = [x, y];
  this.add = (other) => {
    const { x, y } = vectorAdd(this, other);
    [this.x, this.y] = [x, y];
    return this;
  };
  this.multiply = (other) => {
    const { x, y } = vectorMultiply(this, other);
    [this.x, this.y] = [x, y];
    return this;
  };
  this.value = () => ({ x: this.x, y: this.y });
  return this;
}

let t = { x: 1, y: 2 }, u = { x: 3, y: 5 }, v = vector(t).add(u).multiply(t).value();
console.log(v); // { x: 4, y: 14 }

  • Related