Gregg Tavares 5 years ago
parent
commit
cab6031085
1 changed files with 31 additions and 24 deletions
  1. 31 24
      threejs/lessons/threejs-game.md

+ 31 - 24
threejs/lessons/threejs-game.md

@@ -8,12 +8,18 @@ will hopefully give you some ideas on how to start.
 
 At least at the time I'm writing this article it's probably going to be the
 longest article on this site. It's possible the code here is massively over
-engineered but as I wrote each new feature I'd run into needed a solution I'm
-used to from other games I've written. In other words each new solution seemed
-important so I'll try to show why. Of course the smaller your game the less you
-might need some of the solutions shown here but this is a pretty small game and
-yet with the complexities of 3D characters many things take more organization
-than they might with 2D characters.
+engineered but as I wrote each new feature I'd run into a problem that needed a
+solution I'm used to from other games I've written. In other words each new
+solution seemed important so I'll try to show why. Of course the smaller your
+game the less you might need some of the solutions shown here but this is a
+pretty small game and yet with the complexities of 3D characters many things
+take more organization than they might with 2D characters.
+
+As an example if you're making PacMan in 2D, when PacMan turns a corner
+that happens instantly at 90 degrees. There is no in-between step. But
+in a 3D game often we need the character to rotate over several frames.
+That simple change can add a bunch of complexity and require different
+solutions.
 
 The majority of the code here will not really be three.js and
 that's important to note, **three.js is not a game engine**.
@@ -23,7 +29,7 @@ but it does not provide all the other things needed to make a game.
 No collisions, no physics, no input systems, no path finding, etc, etc...
 So, we'll have to provide those things ourselves.
 
-I ended up writing quite a but of code to make this simple *unfinished* 
+I ended up writing quite a bit of code to make this simple *unfinished* 
 game like thing and again, it's certainly possible I over engineered and there
 are simpler solutions but I feel like I actually didn't write
 enough code and hopefully I can explain what I think is missing.
@@ -263,7 +269,7 @@ function init() {
 }
 ```
 
-Above for each model we clone the `gltf.scene` we loaded and we parent that
+Above, for each model, we clone the `gltf.scene` we loaded and we parent that
 to a new `Object3D`. We need to parent it to another object because when
 we play animations the animation will apply animated positions to the nodes
 in the loaded scene which means we won't have control over those positions.
@@ -274,7 +280,7 @@ An `AnimationMixer` contains 1 or more `AnimationAction`s. An
 have all kinds of settings for playing then chaining to another
 action or cross fading between actions. Let's just get the first 
 `AnimationClip` and create an action for it. The default is for
-an action the play its clip in a loop forever.
+an action to play its clip in a loop forever.
 
 ```js
 +const mixers = [];
@@ -498,7 +504,7 @@ const component = new TypeOfComponent(gameObject);
 gameObject.addComponent(component);
 ```
 
-Is it better that this is shorter and more automated or is it worse
+Is it better that the first way is shorter and more automated or is it worse
 because it looks out of the ordinary? I don't know.
 
 `GameObject.getComponent` looks up components by type. That has
@@ -509,7 +515,7 @@ look up the first one without adding some other API.
 It's common for one component to look up another and when looking them up they
 have to match by type otherwise you might get the wrong one. We could instead
 give each component a name and you could look them up by name. That would be
-more flexible in that could have more than one component of the same type but it
+more flexible in that you could have more than one component of the same type but it
 would also be more tedious. Again, I'm not sure which is better.
 
 On to the components themselves. Here is their base class.
@@ -531,14 +537,14 @@ leave it up to each component to do whatever it wants in its constructor
 knowing that the first argument is always the component's gameobject.
 If it doesn't care about gameobject it wouldn't store it. I kind of feel like this
 common base is good though. It means if you have a reference to a
-component you know you can find it's parent gameobject always and from its
-parent you can easily look up other components as well is look at its
+component you know you can find its parent gameobject always and from its
+parent you can easily look up other components as well as look at its
 transform.
 
 To manage the gameobjects we probably need some kind of gameobject manager. You
 might think we could just keep an array of gameobjects but in a real game the
 components of a gameobject might add and remove other gameobjects at runtime.
-For example a gun gameobject might add a bullet gameobject ever time the gun
+For example a gun gameobject might add a bullet gameobject every time the gun
 fires. A monster gameobject might remove itself if it has been killed. We then
 would have an issue that we might have code like this
 
@@ -982,8 +988,8 @@ parented to something else <a class="footnote" href="#parented" id="parented-bac
 
 We also added a global `moveSpeed` and based a `turnSpeed` on the move speed.
 The turn speed is based on the move speed to try to make sure a character
-can turn sharply enough to meet it's target. If turns speed so too small
-a character will turn around and around circling it's target but never
+can turn sharply enough to meet its target. If `turnSpeed` so too small
+a character will turn around and around circling its target but never
 hitting it. I didn't bother to do the math to calculate the required
 turn speed for a given move speed. I just guessed.
 
@@ -1267,7 +1273,8 @@ class Animal extends Component {
 ```
 
 The code above sets the `AnimationMixer.timeScale` to set the playback
-speed of the animations relative to the move speed.
+speed of the animations relative to the move speed. This way if we
+adjust the move speed the animation will speed up or slow down as well.
 
 To start we could setup one of each type of animal
 
@@ -1551,7 +1558,7 @@ class Player extends Component {
 +    globals.playerRadius = model.size / 2;
 ```
 
-Thinking about now it would probably have been smarter
+Thinking about it now it would probably have been smarter
 for the animals to just target the head of the conga line
 instead of the player specifically. Maybe I'll come back
 and change that later.
@@ -1722,7 +1729,7 @@ And with that we get the kind of start of a game
 
 Originally I set out to make a [snake game](https://www.google.com/search?q=snake+game)
 where as you add animals to your line it gets harder because you need to avoid
-them. I'd also have put some obstacles in the scene and maybe a fence or some
+crashing into them. I'd also have put some obstacles in the scene and maybe a fence or some
 barrier around the perimeter.
 
 Unfortunately the animals are long and thin. From above here's the zebra.
@@ -1775,19 +1782,19 @@ to detect collision.
 If you're looking for a solution some of the three.js examples use
 [ammo.js](https://github.com/kripken/ammo.js/) so that might be one.
 
-One other solution might have been the place the obstacles on a grid
+One other solution might have been to place the obstacles on a grid
 and try to make it so each animal and the player just need to look at
-the grid. What would be performant I felt that's best left as an exercise
+the grid. While that would be performant I felt that's best left as an exercise
 for the reader 😜
 
 One more thing, many game systems have something called [*coroutines*](https://www.google.com/search?q=coroutines).
-Coroutines are routines that and pause while running and continue later.
+Coroutines are routines that can pause while running and continue later.
 
 Let's make the main character emit musical notes like they are leading
 the line by singing. There are many ways we could implement this but for now
 let's do it using coroutines.
 
-First, here's a class the manage coroutines
+First, here's a class to manage coroutines
 
 ```js
 function* waitSeconds(duration) {
@@ -1862,7 +1869,7 @@ It does things similar to `SafeArray` to make sure that it's safe to add or remo
 coroutines while other coroutines are running. It also handles nested coroutines.
 
 To make a coroutine you make a [JavaScript generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*).
-A generator function has preceded by the keyword `function*` (the asterisk is important!)
+A generator function is preceded by the keyword `function*` (the asterisk is important!)
 
 Generator functions can `yield`. For example