简体   繁体   English

子弹跟随鼠标位置

[英]Bullets follows mouse position

Im making simple arena shooter in JS and HTML.我正在用 JS 和 HTML 制作简单的竞技场射击游戏。

right now I wanted to add shooting mechanic,I thought i would use code from my enemy class with bits of tweaking现在我想添加射击机制,我想我会使用敌人类的代码并进行一些调整

here:这里:

//differences between objects
let dirx = mouse.x - player.x,  
diry = mouse.y - player.y; 
//normalizing
let dist = Math.sqrt(dirx * dirx + diry * diry);

dirx = dirx / dist;
diry = diry / dist;

this.x += dirx * 5; 
this.y += diry * 5;

Since my player is moving the player.x& player.y coords in dirX & dirY will change, meaning bullet wont go to original coords.由于我的播放器正在移动 dirX 和 dirY 中的 player.x& player.y 坐标会发生变化,这意味着子弹不会转到原始坐标。

So I would be pleased for some help.所以我会很高兴得到一些帮助。

You could use vectors to determine the trajectory of the bullets.您可以使用矢量来确定子弹的轨迹。

In the example below, when I fire a bullet:在下面的示例中,当我发射子弹时:

  • Initialize the position at the source of the bullet初始化子弹来源处的位置
  • The speed is determined by:速度由以下因素决定:
    • Subtracting the mouse position from the source从源中减去鼠标位置
    • Normalizing the distance标准化距离
    • Applying a speed constant应用速度常数
class Bullet {
  constructor(source, target, created) {
    this.position = source.clone();
    this.speed = this.position.clone()
      .subtract(Victor.fromObject(target))
      .normalize()
      .multiply(new Victor(-2, -2));
    this.size = 3;
    this.timeLeft = created + 500;
  }
  update() {
    this.position = this.position.add(this.speed);
  }
  draw(ctx) {
    ctx.fillStyle = 'yellow';
    ctx.beginPath();
    ctx.arc(this.position.x, this.position.y, this.size / 2, 0, 2 * Math.PI);
    ctx.fill();
  }
}

Note: I also added a timeLeft variable to remove the bullet from the game after a set period of time eg 500ms.注意:我还添加了一个timeLeft变量以在设定的时间段(例如 500 毫秒)后从游戏中移除子弹。


Demo演示

Here is an example using the vector logic explained above.这是使用上述矢量逻辑的示例。

Controls控件

  • W (Up) - Move up W (Up) - 向上移动
  • A (Left) - Move left A (左) - 向左移动
  • S (Down) - Move down S (向下) - 向下移动
  • D (Right) - Move right D (右) - 向右移动
  • Mouse 1 - Hold to fire鼠标 1 - 按住开火

 const VK_W = 87; const VK_A = 65; const VK_S = 83; const VK_D = 68; const VK_UP = 38; const VK_DOWN = 40; const VK_LEFT = 37; const VK_RIGHT = 39; const canvas = document.querySelector('.game'), stateBtn = document.querySelector('.state-btn'); let game; const main = () => { stateBtn.addEventListener('click', changeState); const ctx = canvas.getContext('2d'); game = new Game(ctx, { width: 400, height: 300 }); game.run(); }; const changeState = (e) => { const btn = e.currentTarget, running = btn.dataset.running === 'true'; if (running) { game.pause(); } else { game.run(); } btn.textContent = running ? 'Pause' : 'Resume'; btn.dataset.running = !running; }; class Game { constructor(ctx, options) { const { width, height } = options; this.lastRender = 0; this.ctx = ctx; this.state = { keySet: new Set() }; this.bullets = []; Object.assign(ctx.canvas, { width, height }); const origin = new Victor(width / 2, height / 2); this.player = new Player({ name: 'Bob', position: origin }); ctx.canvas.addEventListener('mousemove', (e) => this.followMouse(e)); ctx.canvas.addEventListener('mousedown', (e) => this.mouseDown(e)); ctx.canvas.addEventListener('mouseup', (e) => this.mouseUp(e)); document.addEventListener('keydown', (e) => this.addKey(e), false); document.addEventListener('keyup', (e) => this.removeKey(e), false); } followMouse(e) { this.state.mousePos = getMousePos(e.currentTarget, e); } mouseDown(e) { this.state.mouseDown = true; } mouseUp(e) { this.state.mouseDown = false; } addKey(e) { const key = e.which || e.keyCode || 0; this.state.keySet.add(key); } removeKey(e) { const key = e.which || e.keyCode || 0; this.state.keySet.delete(key); } update(progress) { const ks = this.state.keySet; const x = (ks.has(VK_D) || ks.has(VK_RIGHT)) ? 1 : (ks.has(VK_A) || ks.has(VK_LEFT)) ? -1 : 0; const y = (ks.has(VK_S) || ks.has(VK_DOWN)) ? 1 : (ks.has(VK_W) || ks.has(VK_UP)) ? -1 : 0; this.player.position.add(new Victor(x, y)); this.bullets.forEach((bullet, index) => { if (this.lastRender > bullet.timeLeft) { this.bullets.splice(index, 1); } bullet.update(this.lastRender); }); if (this.state.mousePos && this.state.mouseDown) { this.bullets.push(new Bullet(this.player.position, this.state.mousePos, this.lastRender)); } } draw() { this.ctx.clearRect(0, 0, this.ctx.canvas.width, this.ctx.canvas.height); this.player.draw(this.ctx); this.bullets.forEach(bullet => bullet.draw(this.ctx)); } run(timestamp) { const progress = timestamp - this.lastRender; this.update(progress); this.draw(); this.lastRender = timestamp; this.req = window.requestAnimationFrame((t) => this.run(t)); } pause() { const { width, height } = this.ctx.canvas; this.ctx.fillStyle = 'rgba(0, 0, 0, 0.5)'; this.ctx.fillRect(0, 0, width, height); this.ctx.font = '32px Arial'; this.ctx.fillStyle = '#FFF'; this.ctx.textAlign = 'center'; this.ctx.textBaseline = 'middle'; this.ctx.fillText('Paused', width / 2, height / 2); cancelAnimationFrame(this.req); this.req = null; } isRunning() { return this.req !== null; } } class Player { constructor(options) { const opts = { ...Player.defaultOptions, ...options }; this.name = opts.name; this.position = opts.position; this.size = opts.size; } draw(ctx) { ctx.fillStyle = '#00FF00'; ctx.fillRect(this.position.x - this.size / 2, this.position.y - this.size / 2, this.size, this.size); } }; Player.defaultOptions = { size: 10, position: new Victor(0, 0) }; class Bullet { constructor(source, target, created) { this.position = source.clone(); this.speed = this.position.clone() .subtract(Victor.fromObject(target)) .normalize() .multiply(new Victor(-2, -2)); this.size = 3; this.timeLeft = created + 500; } update() { this.position = this.position.add(this.speed); } draw(ctx) { ctx.fillStyle = 'yellow'; ctx.beginPath(); ctx.arc(this.position.x, this.position.y, this.size / 2, 0, 2 * Math.PI); ctx.fill(); } } const getMousePos = (canvas, event) => (({ top, left }) => ({ x: event.clientX - left, y: event.clientY - top }))(canvas.getBoundingClientRect()); main();
 .game { background: #111; } .as-console-wrapper { max-height: 4em !important; }
 <script src="https://cdnjs.cloudflare.com/ajax/libs/victor/1.1.0/victor.min.js"></script> <canvas class="game"></canvas> <div class="controls"> <button class="state-btn" data-running="true">Pause</button> </div>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM