Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
101 views
in Technique[技术] by (71.8m points)

html - run multiple instances of a class simultaneously javascript

You probably only need to look at obstacle.js

I have a class which draws a square on a canvas and adds collision detection to it.

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

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>
question from:https://stackoverflow.com/questions/65870725/run-multiple-instances-of-a-class-simultaneously-javascript

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Create your TickManager (this one, based on 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):

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.listener.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!). Add the Keys, Allow, Character and DOM element to it.
  • Pass the tick manager as an argument to players and obstacles creators, so you stop using the same context and can start importing modules to split and organize your code.
  • 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.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

1.4m articles

1.4m replys

5 comments

56.9k users

...