2
0
Эх сурвалжийг харах

add note color and more coroutine info

Gregg Tavares 6 жил өмнө
parent
commit
a7dd46198d

+ 42 - 4
threejs/lessons/threejs-game.md

@@ -1871,10 +1871,31 @@ function* countOTo9() {
 }
 }
 ```
 ```
 
 
-If we passed this function to the `CoroutineRunner` above it would print
+If we added this function to the `CoroutineRunner` above it would print
 out each number, 0 to 9, once per frame or rather once per time we called `runner.update`.
 out each number, 0 to 9, once per frame or rather once per time we called `runner.update`.
 
 
-In the player let's use a coroutine to emit a note every half second to 1 second
+```js
+const runner = new CoroutineRunner();
+runner.add(count0To9);
+while(runner.isBusy()) {
+  runner.update();
+}
+```
+
+Coroutines are removed automatically when they are finished. 
+To remove a coroutine early, before it reaches the end you need to keep
+a reference to its generator like this
+
+```js
+const gen = count0To9();
+runner.add(gen);
+
+// sometime later
+
+runner.remove(gen);
+```
+
+In any case, in the player let's use a coroutine to emit a note every half second to 1 second
 
 
 ```js
 ```js
 class Player extends Component {
 class Player extends Component {
@@ -1928,12 +1949,16 @@ function makeTextTexture(str) {
   ctx.font = '60px sans-serif';
   ctx.font = '60px sans-serif';
   ctx.textAlign = 'center';
   ctx.textAlign = 'center';
   ctx.textBaseline = 'middle';
   ctx.textBaseline = 'middle';
+  ctx.fillStyle = '#FFF';
   ctx.fillText(str, ctx.canvas.width / 2, ctx.canvas.height / 2);
   ctx.fillText(str, ctx.canvas.width / 2, ctx.canvas.height / 2);
   return new THREE.CanvasTexture(ctx.canvas);
   return new THREE.CanvasTexture(ctx.canvas);
 }
 }
 const noteTexture = makeTextTexture('♪');
 const noteTexture = makeTextTexture('♪');
 ```
 ```
 
 
+The texture we create above is white each means when we use it
+we can set the material's color and get a note of any color.
+
 Now that we have a noteTexture here's the `Note` component.
 Now that we have a noteTexture here's the `Note` component.
 It uses `SpriteMaterial` and a `Sprite` like we covered in
 It uses `SpriteMaterial` and a `Sprite` like we covered in
 [the article on billboards](threejs-billboards.html) 
 [the article on billboards](threejs-billboards.html) 
@@ -1944,6 +1969,7 @@ class Note extends Component {
     super(gameObject);
     super(gameObject);
     const {transform} = gameObject;
     const {transform} = gameObject;
     const noteMaterial = new THREE.SpriteMaterial({
     const noteMaterial = new THREE.SpriteMaterial({
+      color: new THREE.Color().setHSL(rand(1), 1, 0.5),
       map: noteTexture,
       map: noteTexture,
       side: THREE.DoubleSide,
       side: THREE.DoubleSide,
       transparent: true,
       transparent: true,
@@ -1981,8 +2007,8 @@ from the scene and the note itself from active gameobjects.
 {{{example url="../threejs-game-conga-line-w-notes.html"}}}
 {{{example url="../threejs-game-conga-line-w-notes.html"}}}
 
 
 You might be asking, why not use `setTimeout`? The problem with `setTimeout`
 You might be asking, why not use `setTimeout`? The problem with `setTimeout`
-is it's not related to the game clock. For example above we make the maximum
-amount of time allowed to elapse between frames is 1/20th of a second.
+is it's not related to the game clock. For example above we made the maximum
+amount of time allowed to elapse between frames to be 1/20th of a second.
 Our coroutine system will respect that limit but `setTimeout` would not.
 Our coroutine system will respect that limit but `setTimeout` would not.
 
 
 Of course we could have made a simple timer ourselves
 Of course we could have made a simple timer ourselves
@@ -1992,6 +2018,7 @@ class Player ... {
   update() {
   update() {
     this.noteTimer -= globals.deltaTime;
     this.noteTimer -= globals.deltaTime;
     if (this.noteTimer <= 0) {
     if (this.noteTimer <= 0) {
+      // reset timer
       this.noteTimer = rand(0.5, 1);
       this.noteTimer = rand(0.5, 1);
       // create a gameobject with a note component
       // create a gameobject with a note component
     }
     }
@@ -2037,6 +2064,17 @@ function* animalCoroutine() {
 This would have worked but of course as soon as our states were not so linear
 This would have worked but of course as soon as our states were not so linear
 we'd have had to switch to a `FiniteStateMachine`.
 we'd have had to switch to a `FiniteStateMachine`.
 
 
+It also wasn't clear to me if coroutines should run independently of their
+components. We could have made a global `CoroutineRunner` and put all
+coroutines on it. That would make cleaning them up harder. As it is now
+if the gameobject is removed all of it's components are removed and
+therefore the coroutine runners created are no longer called and it will
+all get garbage collected. If we had global runner then it would be
+the responsibility of each component to remove any coroutines it added
+or else some other mechanism of registering coroutines with a particular
+component or gameobject would be needed so that removing one removes the
+others.
+
 There are lots more issues a
 There are lots more issues a
 normal game engine would deal with. As it is there is no order to how
 normal game engine would deal with. As it is there is no order to how
 gameobjects or their components are run. They are just run in the order added.
 gameobjects or their components are run. They are just run in the order added.

+ 9 - 6
threejs/threejs-game-conga-line-w-notes.html

@@ -194,11 +194,11 @@ function main() {
   const models = {
   const models = {
     pig:    { url: 'resources/models/animals/Pig.gltf' },
     pig:    { url: 'resources/models/animals/Pig.gltf' },
     cow:    { url: 'resources/models/animals/Cow.gltf' },
     cow:    { url: 'resources/models/animals/Cow.gltf' },
-    llama:  { url: 'resources/models/animals/Llama.gltf' },
-    pug:    { url: 'resources/models/animals/Pug.gltf' },
-    sheep:  { url: 'resources/models/animals/Sheep.gltf' },
-    zebra:  { url: 'resources/models/animals/Zebra.gltf' },
-    horse:  { url: 'resources/models/animals/Horse.gltf' },
+    llama:  { url: 'resources/models/animals/llama.gltf' },
+    pug:    { url: 'resources/models/animals/pug.gltf' },
+    sheep:  { url: 'resources/models/animals/sheep.gltf' },
+    zebra:  { url: 'resources/models/animals/zebra.gltf' },
+    horse:  { url: 'resources/models/animals/horse.gltf' },
     knight: { url: 'resources/models/knight/KnightCharacter.gltf' },
     knight: { url: 'resources/models/knight/KnightCharacter.gltf' },
   };
   };
   {
   {
@@ -676,16 +676,19 @@ function main() {
     ctx.font = '60px sans-serif';
     ctx.font = '60px sans-serif';
     ctx.textAlign = 'center';
     ctx.textAlign = 'center';
     ctx.textBaseline = 'middle';
     ctx.textBaseline = 'middle';
+    ctx.fillStyle = '#FFF';
     ctx.fillText(str, ctx.canvas.width / 2, ctx.canvas.height / 2);
     ctx.fillText(str, ctx.canvas.width / 2, ctx.canvas.height / 2);
     return new THREE.CanvasTexture(ctx.canvas);
     return new THREE.CanvasTexture(ctx.canvas);
   }
   }
+  const noteTexture = makeTextTexture('♪');
 
 
   class Note extends Component {
   class Note extends Component {
     constructor(gameObject) {
     constructor(gameObject) {
       super(gameObject);
       super(gameObject);
       const {transform} = gameObject;
       const {transform} = gameObject;
       const noteMaterial = new THREE.SpriteMaterial({
       const noteMaterial = new THREE.SpriteMaterial({
-        map: makeTextTexture('♪'),
+        color: new THREE.Color().setHSL(rand(1), 1, 0.5),
+        map: noteTexture,
         side: THREE.DoubleSide,
         side: THREE.DoubleSide,
         transparent: true,
         transparent: true,
       });
       });