简体   繁体   English

同时运行 class 的多个实例 javascript

[英]run multiple instances of a class simultaneously javascript

You probably only need to look at obstacle.js您可能只需要查看障碍.js

I have a class which draws a square on a canvas and adds collision detection to it.我有一个 class 在 canvas 上绘制一个正方形并为其添加碰撞检测。

When I create one instance it works perfectly,当我创建一个实例时,它可以完美运行,

new Obstacle(100, 100, 100, 100).init()

but if I create 2 it only works on the second one I create但如果我创建 2 它只适用于我创建的第二个

new Obstacle(100, 100, 100, 100).init()
new Obstacle(400, 100, 100, 100).init()

does anyone know a way to make this code work on both instances?有谁知道让这段代码在两个实例上都工作的方法?

 // utility.js //define variables let Keys = { W: false, A: false, S: false, D: false } let Allow = { W: true, A: true, S: true, D: true } let Character = { X: 0, Y: 0, H: parseInt(window.getComputedStyle(character).getPropertyValue("height")), W: parseInt(window.getComputedStyle(character).getPropertyValue("width")), } //function to update the position of `character` every milisecond setInterval(function() { document.getElementById("character").style.left = Character.X + "px" document.getElementById("character").style.top = Character.Y + "px" }, 1) //waits for event `keyDOWN` to happen, if it happens it sets `Keys.` + the key to TRUE so it START animating document.addEventListener("keydown", (event) => { if (event.key === "w") Keys.W = true if (event.key === "a") Keys.A = true if (event.key === "s") Keys.S = true if (event.key === "d") Keys.D = true }) //waits for event `keyUP` to happen, if it happens it sets `Keys.` + the key to FALSE so it STOPS animating document.addEventListener("keyup", (event) => { if (event.key === "w") Keys.W = false if (event.key === "a") Keys.A = false if (event.key === "s") Keys.S = false if (event.key === "d") Keys.D = false }) //function that makes `character` move by adding to its X and Y value setInterval(function() { if (Keys.W && Allow.W) { if (Character.Y > 0) { Character.Y -= 1 } } if (Keys.A && Allow.A) { if (Character.X > 0) { Character.X -= 1 } } if (Keys.S && Allow.S) { if (Character.Y < 500 - Character.H) { Character.Y += 1 } } if (Keys.D && Allow.D) { if (Character.X < 800 - Character.W) { Character.X += 1 } } }, 1) // obstacle.js //define variables let canvas = document.getElementById("ObstacleHolder") let ctx = canvas.getContext("2d") //resize the canvas canvas.width = 800 canvas.height = 500 class Obstacle { constructor(x, y, height, width, src = null) { this.H = height this.W = width this.X = x this.Y = y this.src = src } //function to draw the obstacle on the canvas & apply colision detection init() { //array for the coordinates let ObstaclePositions = [this.X - Character.W, this.Y - Character.H, (this.X + this.W), (this.Y + this.H)] //draw the obstacle on the canvas ctx.beginPath() ctx.rect(this.X, this.Y, this.W, this.H) ctx.fillStyle = "Red" ctx.fill() //colision detection setInterval(function() { //colision detection X if (Character.Y > ObstaclePositions[1] && Character.Y < ObstaclePositions[3] && Character.X > ObstaclePositions[0] - 1 && Character.X < ObstaclePositions[2] - 1) { Allow.D = false Allow.A = true Allow.S = true Allow.W = true } else { Allow.D = true } if (Character.Y > ObstaclePositions[1] && Character.Y < ObstaclePositions[3] && Character.X > ObstaclePositions[0] + 1 && Character.X < ObstaclePositions[2] + 1) { Allow.A = false Allow.D = true Allow.S = true Allow.W = true } else { Allow.A = true } //colision detection Y if (Character.Y > ObstaclePositions[1] - 1 && Character.Y < ObstaclePositions[3] - 1 && Character.X > ObstaclePositions[0] && Character.X < ObstaclePositions[2]) { Allow.S = false Allow.D = true Allow.A = true Allow.W = true } else { Allow.S = true } if (Character.Y > ObstaclePositions[1] + 1 && Character.Y < ObstaclePositions[3] + 1 && Character.X > ObstaclePositions[0] && Character.X < ObstaclePositions[2]) { Allow.W = false Allow.A = true Allow.D = true Allow.S = true } else { Allow.W = true } }, 1) } } new Obstacle(100, 100, 100, 100).init() new Obstacle(400, 100, 100, 100).init()
 * { padding: 0; margin: 0; font-family: "Dosis", "Source Sans Pro", "Helvetica Neue", Arial, sans-serif; -webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; } #canvas { height: 500px; width: 800px; border: 1px solid black; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } #character { height: 50px; width: 50px; background-color: rgb(0, 204, 255); position: absolute; top: 0px; left: 0px; } #ObstacleHolder { background-color: rgba(100, 100, 158, 0.288); position: absolute; }
 <,DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width. initial-scale=1.0"> <title>Prototype</title> </head> <body> <div id="canvas"> <canvas id="ObstacleHolder"></canvas> <div id="character"></div> </div> </body> </html> <.-- import css file --> <link rel="stylesheet" href="style.css"> <!-- import javascript files --> <script src="utility.js"></script> <script src="obstacle.js"></script>

Create your TickManager (this one, based on EventEmitter ):创建你的TickManager (这个,基于EventEmitter ):

class TickManager extends EventEmitter {
  timer = false;
  running = false;

  constructor(...props) {
    super(...props);
    this.onStop = this.stop.bind(this);
    this.on('stop', this.onStop);
  }

  destroy(...props) {
    this.off('stop', this.onStop);
    super.destroy(...props);
  }

  start() {
    if(!this.running) {
      this.running = true;
      this.tick();
    }
  }

  stop() {
    cancelAnimationFrame(this.timer);
    this.running = false;
  }

  tick() {
    this.timer = false;
    this.emit( 'beforetick' );
    this.emit( 'tick' );
    this.emit( 'aftertick' );
    if(this.running) {
      this.timer = requestAnimationFrame(this.tick.bind(this));
    }
  }
}

const tickManager = new TickManager();

Use it in your player:在您的播放器中使用它:

tickManager.on('beforetick', function() {
  Allow = {
    W: true,
    A: true,
    S: true,
    D: true
  };

  // Allow obstacles to disallow directions
  tickManager.emit('afterplayertick');
});

// Update the position of `character` after all calculations have been done
tickManager.on('aftertick', function() {
  document.getElementById("character").style.left = Character.X + "px"
  document.getElementById("character").style.top = Character.Y + "px"
});

// Makes `character` move by adding to its X and Y value, if allowed by obstacles
tickManager.on('tick', function() {
  if (Keys.W && Allow.W) {
    if (Character.Y > 0) {
      Character.Y -= 1
    }
  }
  if (Keys.A && Allow.A) {
    if (Character.X > 0) {
      Character.X -= 1
    }
  }
  if (Keys.S && Allow.S) {
    if (Character.Y < 500 - Character.H) {
      Character.Y += 1
    }
  }
  if (Keys.D && Allow.D) {
    if (Character.X < 800 - Character.W) {
      Character.X += 1
    }
  }
});

Use it in your obstacles:在你的障碍中使用它:

class Obstacle {
  // ...
  init() {
    // ...
    // Colision detection
    tickManager.on('afterplayertick', function() {
      //colision detection X
      if (Character.Y > ObstaclePositions[1] &&
          Character.Y < ObstaclePositions[3] &&
          Character.X > ObstaclePositions[0] - 1 &&
          Character.X < ObstaclePositions[2] - 1) {
        Allow.D = false
      }
      if (Character.Y > ObstaclePositions[1] &&
          Character.Y < ObstaclePositions[3] &&
          Character.X > ObstaclePositions[0] + 1 &&
          Character.X < ObstaclePositions[2] + 1) {
        Allow.A = false
      }
      if (Character.Y > ObstaclePositions[1] - 1 &&
          Character.Y < ObstaclePositions[3] - 1 &&
          Character.X > ObstaclePositions[0] &&
          Character.X < ObstaclePositions[2]) {
        Allow.S = false
      }
      if (Character.Y > ObstaclePositions[1] + 1 &&
          Character.Y < ObstaclePositions[3] + 1 &&
          Character.X > ObstaclePositions[0] &&
          Character.X < ObstaclePositions[2]) {
        Allow.W = false
      }
    });
  }
}

And, finally, start the tick manager:最后,启动分时管理器:

tickManager.start();

EventEmitter事件发射器

You can use EventEmitter from NPM Event package or do it yourself (copied from this article ):您可以使用来自EventEmitter事件 package的 EventEmitter 或自己做(从本文复制):

class EventEmitter {
  listeners = [];
  emit(eventName, data) {
    this.listeners
      .filter(({ name }) => name === eventName)
      .forEach(
        ({ callback }) => setTimeout(
          callback.apply(this, [this, ...data]), 0
        );
      )
  }
  on(name, callback) {
    if (
      typeof callback === 'function'
      && typeof name === 'string'
    ) {
      this.listeners.push({ name, callback });
    }
  }
  off(eventName, callback) {
    this.listeners = this.listeners.filter(
      listener => !(listener.name === eventName &&
        listener.callback === callback)
    );
  }
  destroy() {
    this.listeners.length = 0;
  }
}

There are lots of other impovements you can do to this code:你可以对这段代码做很多其他的改进:

  • Create a Player class (so you can have more than one.).创建一个Player class(这样您就可以拥有多个播放器。)。 Add the Keys , Allow , Character and DOM element to it.向其中添加KeysAllowCharacter和 DOM 元素。
  • Pass the tick manager as an argument to players and obstacles creators, so you stop using the same context and can start import ing modules to split and organize your code.将刻度管理器作为参数传递给玩家和障碍物创建者,这样您就可以停止使用相同的上下文并可以开始import模块来拆分和组织您的代码。
  • In this example, the player emits an event.在这个例子中,玩家发出一个事件。 Pass the player as an argument to its listeners, so the obstacles listeners can control the collision against each player.将玩家作为参数传递给其侦听器,因此障碍侦听器可以控制与每个玩家的碰撞。

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

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