├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── _config.yml
├── dist
├── CharacterController.d.ts
├── CharacterController.js
├── CharacterController.js.map
├── CharacterController.max.js
└── CharacterController.max.js.map
├── package-lock.json
├── package.json
├── src
└── CharacterController.ts
├── tsconfig.json
├── tst
├── ground
│ ├── ground-normal.png
│ ├── ground.jpg
│ └── ground_heightMap.png
├── player
│ ├── Vincent-backFacing.babylon
│ ├── Vincent-backFacing.blend
│ ├── Vincent-backFacing.glb
│ ├── Vincent-frontFacing.babylon
│ ├── Vincent-frontFacing.blend
│ ├── Vincent-frontFacing.glb
│ ├── Vincent_texture_image.jpg
│ └── starterAvatars.babylon
├── sounds
│ ├── footstep_carpet_000.ogg
│ └── footstep_concrete_000.ogg
├── test.html
├── testAnimationGroup.html
├── testAnimationGroup.js
├── testAnimationRange.html
├── testAnimationRange.js
├── testCommandControl.html
├── testCommandControl.js
├── testNPC.html
├── testNPC.js
└── w3.css
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | nbproject
2 | node_modules
3 | lib
4 | *.bat
5 | ig_*
6 | **/ig_*.*
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | nbproject
2 | node_modules
3 | lib
4 | src
5 | tst
6 | _config.yml
7 | *.bat
8 | **/ig_*.*
9 |
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | [](https://npmjs.org/package/babylonjs-charactercontroller)
2 | [](https://npmjs.org/package/babylonjs-charactercontroller)
3 |
4 | # BabylonJS-CharacterController
5 |
6 | A 3rd person CharacterController for use in [BabylonJS](http://www.babylonjs.com/) (a 3D HTML Webgl framework) applications.
7 | It uses the collider and moveWithCollision() function to move the character around. It uses physics kinematic equations to calculate movements like jump, fall, slide. It does not use any physics engine. It does not react to forces but does apply forces to other physics object. The force applied cannot be controlled.
8 | For demo see
9 | https://ssatguru.github.io/BabylonJS-CharacterController-Samples/demo/
10 |
11 | ## About
12 |
13 | It currently supports
14 |
15 | - idle
16 | - idleJump
17 | - walk
18 | - walkBack
19 | - walkBackFast
20 | - run
21 | - runJump
22 | - fall
23 | - turnRight
24 | - turnRightFast
25 | - turnLeft
26 | - turnLeftFast
27 | - strafeLeft
28 | - strafeLeftFast
29 | - strafeRight
30 | - strafeRightFast
31 | - slideDown
32 |
33 | It supports two modes or ways of moving the avatar.
34 | One suitable for third/first person kind of game
35 | and the other suitable for top down isometric kind of game.
36 | Further within the third/first person mode, two "submodes" are supported.
37 | In one submode the left and right keys make the avatar turn left or right and the back key makes the avatar walk backward with back facing the camera.
38 | In the other submode the left and right keys make the avatar face and move left or right and the back keys makes the avatar turn around and move towards the camera.
39 | See "setMode" and "Turning On/Off" below.
40 |
41 | Further it supports constraining avatar from traversing slopes inclined at certain angles.
42 |
43 | It also supports camera "elasticity". In other words if a mesh comes between the camera and avatar/player, the camera snaps to
44 | a position in front of the mesh. This way the avatar/player is always in view.
45 |
46 | It can also enter first person view if the camera comes very close to the avatar/player
47 |
48 | ### Breaking change with 0.2.0
49 |
50 | Instead of "jump" animation it expects "idleJump" and "runJump" animations.
51 |
52 | Version 0.2.0 converts the project from a plain vanilla JavaScript project to a module based JavaScript project.
53 | With this change, the way to load the application has changed.
54 | In JavaScript, instead of
55 |
56 | ```
57 | var CharacterControl = org.ssatguru.babylonjs.component.CharacterController;
58 | var characterControl = new CharacterControl(player, camera, scene);
59 | ```
60 |
61 | now do
62 |
63 | ```
64 | var characterControl = new CharacterController(player, camera, scene);
65 | ```
66 |
67 | In TypeScript, instead of
68 |
69 | ```
70 | import CharacterController = org.ssatguru.babylonjs.component.CharacterController;
71 | ```
72 |
73 | now do
74 |
75 | ```
76 | import {CharacterController} from "babylonjs-charactercontroller";
77 | ```
78 |
79 | See below for more details.
80 |
81 | ## Quick start
82 |
83 | 1. add the following dependencies
84 |
85 | ```
86 |
87 |
88 | ```
89 |
90 | See INSTALL below to find where you can get "CharacterController.js".
91 |
92 | 2. if your mesh rotation is in quaternion then switch to euler.
93 | NOTE: The GLTF/GLB files have rotation in quaternion
94 |
95 | ```
96 | // character controller needs rotation in euler.
97 | // if your mesh has rotation in quaternion then convert that to euler.
98 | player.rotation = player.rotationQuaternion.toEulerAngles();
99 | player.rotationQuaternion = null;
100 |
101 | ```
102 |
103 | 3. instantiate charcater controller and start it.
104 |
105 | ```
106 | //------------------Character Controller -------------------------------------------------
107 | //fourth parm agMap is optional and is used when animation groups rather than animation ranges
108 | //are used.
109 | var cc = new CharacterController(player, camera, scene, agMap);
110 | cc.start();
111 | ```
112 |
113 | see "BabylonJS-CharacterController-Samples" [https://github.com/ssatguru/BabylonJS-CharacterController-Samples](https://github.com/ssatguru/BabylonJS-CharacterController-Samples) for a few simple samples to help you get going
114 |
115 | ## INSTALL
116 |
117 | You can get the "CharacterController.min.js" from its git repository "dist" folder or "releases" section
118 | [https://github.com/ssatguru/BabylonJS-CharacterController/tree/master/dist](https://github.com/ssatguru/BabylonJS-CharacterController/tree/master/dist)
119 | [https://github.com/ssatguru/BabylonJS-CharacterController/releases](https://github.com/ssatguru/BabylonJS-CharacterController/releases)
120 |
121 | You can also install it from npm
122 |
123 | ```
124 | npm install babylonjs-charactercontroller
125 | ```
126 |
127 | ## Usage
128 |
129 | This has been built as an UMD module which means you can use it as a CommonJS/NodeJS module, AMD module or as a global object
130 | loaded using the script tag.
131 |
132 | Project "BabylonJS-CharacterController-Samples" [https://github.com/ssatguru/BabylonJS-CharacterController-Samples](https://github.com/ssatguru/BabylonJS-CharacterController-Samples) has a
133 | collection of sample projects to show how to use this from TypeScript, NodeJs, AMD or plain vanilla JavaScript applications.
134 |
135 | Below is a quick summary of how you can use this as different module types.
136 |
137 | TypeScript
138 |
139 | ```
140 | // TypeScript
141 | import * as BABYLON from "babylonjs";
142 | import {CharacterController} from "babylonjs-charactercontroller";
143 | ...
144 | let engine = new BABYLON.Engine(canvas, true);
145 | ...
146 | let cc = new CharacterController(player, camera, scene);
147 | ```
148 |
149 | CommonJS/NodeJS Module
150 |
151 | ```
152 | let BABYLON = require("babylonjs");
153 | let CharacterController = require("babylonjs-CharacterController").CharacterController;
154 | ...
155 | let engine = new BABYLON.Engine(canvas, true);
156 | ...
157 | let characterController = new CharacterController(player, camera, scene);
158 | ...
159 |
160 | ```
161 |
162 | AMD Module
163 |
164 | ```
165 |
166 |
184 | ```
185 |
186 | Global Module
187 |
188 | ```
189 |
190 |
191 |
198 | ```
199 |
200 | ## API ( version 0.4.4 )
201 |
202 | #### To Instantiate
203 |
204 | ```
205 | // JavaScript
206 |
207 | // if using animation ranges
208 | var cc = new CharacterController(player, camera, scene);
209 |
210 | // if using animation groups (.glb files use animation groups)
211 | var cc = new CharacterController(player, camera, scene, agMap);
212 | //agMap is a Map which maps an "animation name" to "animationGroup object".
213 |
214 | // if the avatar face is forward facing (positive Z direction)
215 | var cc = new CharacterController(player, camera, scene, agMap, true);
216 | ```
217 |
218 | ```
219 | // TypeScript
220 |
221 | import {CharacterController} from "babylonjs-charactercontroller";
222 |
223 | // if using animation ranges
224 | let cc = new CharacterController(player, camera, scene);
225 |
226 | // if using animation groups (.glb files use animation groups)
227 | let cc = new CharacterController(player, camera, scene, agMap);
228 | //agMap is a Map which maps an "animation name" to "animationGroup object".
229 |
230 | // if the avatar face is forward facing (positive Z direction)
231 | let cc = new CharacterController(player, camera, scene, agMap, true);
232 | ```
233 |
234 | Takes five parms
235 |
236 | - player - the player mesh containing a skeleton with appropriate animations as listed below
237 | - camera - arc rotate camera
238 | - scene - scene
239 | - agMap - This is optional and is only needed if using animation groups instead of animation ranges. ".glb" files have animation groups.
240 | It is a Map which maps an "animation name" to "animationGroup object" .
241 | In this Map the key would be the character controller animation name and
242 | the key value would be the animationGroup object.
243 | example:
244 |
245 | ```
246 | let myWalkAnimationGroup:AnimationGroup = ...;
247 | let agMap:{} = {
248 | "walk": myWalkAnimationGroup,
249 | "run": ...,
250 | }
251 | ```
252 |
253 | - forwardFacing - Optional. If the avatar's face is forward facing (positive Z direction) set this to true. By default it is false.
254 |
255 | Note: If camera is set to null then the camera will not follow the character and keybaord will not controll the character. You can use this for an NPC which you can move around programmatically. See the section on "Controlling Avatar programmatically".
256 |
257 | If using animation ranges the player skeleton is expected to have the animation ranges named as follows
258 |
259 | - idle
260 | - idleJump
261 | - walk
262 | - walkBack
263 | - walkBackFast
264 | - run
265 | - runJump
266 | - fall
267 | - turnRight
268 | - turnRightFast
269 | - turnLeft
270 | - turnLeftFast
271 | - strafeLeft
272 | - strafeLeftFast
273 | - strafeRight
274 | - strafeRightFast
275 | - slideDown
276 |
277 | If a particular animation is not provided then the controller will not play that animation and will continue playing the animation it was playing just before.
278 | Note that if no animations are provided then no animations will be played. This, thus, can be used to move an non skeleton based mesh around.
279 |
280 | Note that there are some animations with name ending with string "Fast".
281 | If these are not present then the controller will play the non-fast version but at twice the speed.
282 | So for example lets say you provided "strafeLeft" but not "strafeLeftFast" then the controller will play the "stafeLeft" animation whenever it has to play the "strafeLeftFast" but at twice the speed of "strafeLeft".
283 |
284 | The "Fast" animations are played when the user presses the "mod" key (usually "shift key) along with the normal key.
285 | Example: to play "strafeLeft" if the key is set to "q" then to play "strafeLeftFast" the key would be "q" and "shift".
286 |
287 | Now if your animation range is named differently from those mentioned above then use the setWalkAnim(..), setWalkBackAnim(..) etc API to specify your animation range name.
288 |
289 | If instead of animation ranges you have animation groups then you will have to provide a map of animation name to animation group object. This is explained further down below.
290 |
291 | NOTE :
292 | If your mesh rotation is in quaternion then switch to euler before creating character controller.
293 | The GLTF/GLB files have rotation in quaternion.
294 |
295 | ```
296 | player.rotation = player.rotationQuaternion.toEulerAngles();
297 | player.rotationQuaternion = null;
298 | ```
299 |
300 | #### To start/stop controller
301 |
302 | ```
303 | cc.start();
304 | cc.stop();
305 | ```
306 |
307 | #### To pause playing any animations
308 |
309 | Sometimes you might want to stop the character controller from playing
310 | any animation on the character and instead play your animation instead
311 | Example instead of idle animation you might want to play a shoot animation.
312 | Use the following to pause or resume
313 |
314 | ```
315 | cc.pauseAnim();
316 | cc.resumeAnim();
317 | ```
318 |
319 | #### To Change Mode
320 |
321 | The CharacterController can run in one of two modes - 0 or 1.
322 |
323 | - Mode 0 is the default mode.
324 | This is suitable for First Person and Third Person kind of games.
325 | Here the camera follows the movement and rotation of the Avatar.
326 | Rotating the camera around the Avatar also rotates the Avatar.
327 | - Mode 1 is suitable for top down, isometric type of games.
328 | Here the camera just follows the movement of the Avatar.
329 | It is not effected by or effects the rotation of the Avatar
330 |
331 | ```
332 | cc.setMode(n: number); // 0 or 1
333 | ```
334 |
335 | ##### Turning on/off
336 |
337 | Use this to set turning on/off.
338 | When turining is off
339 | a) turn left or turn right keys result in avatar facing and moving left or right with respect to camera rather then just turning left or right
340 | b) walkback/runback key results in avatar facing back, towards the camera and walking/running towards camera rather than walking backwards with back to the camera
341 |
342 | This setting has no effect when mode is 1.
343 |
344 | ```
345 | cc.setTurningOff(true/false);
346 | ```
347 |
348 | default is false
349 |
350 | #### To change animation range name / animation group and their parameters
351 |
352 | Takes three parms
353 |
354 | - rangeName or Animation group Object
355 | - rate - rate of speed at which to play the aniamtion
356 | - loop - whether the animation should be looped or stop at end.
357 |
358 | To leave any parameter unchanged set its value to null.
359 |
360 | ```
361 | cc.setIdleAnim(name: string|AnimationGroup, rate: number, loop: boolean);
362 | cc.setIdleJumpAnim(name: string|AnimationGroup, rate: number, loop: boolean);
363 |
364 | cc.setWalkAnim(name: string|AnimationGroup, rate: number, loop: boolean);
365 | cc.setWalkBackAnim(name: string|AnimationGroup, rate: number, loop: boolean);
366 | cc.setWalkBacFastkAnim(name: string|AnimationGroup, rate: number, loop: boolean);
367 |
368 | cc.setRunAnim(name: string|AnimationGroup, rate: number, loop: boolean);
369 | cc.setRunJumpAnim(name: string, rate: number, loop: boolean);
370 |
371 | cc.setFallAnim(name: string|AnimationGroup, rate: number, loop: boolean);
372 |
373 | cc.setTurnRightAnim(name: string|AnimationGroup, rate: number, loop: boolean);
374 | cc.setTurnLeftAnim(name: string|AnimationGroup, rate: number, loop: boolean);
375 |
376 | cc.setTurnRightFastAnim(name: string|AnimationGroup, rate: number, loop: boolean);
377 | cc.setTurnLeftFastAnim(name: string|AnimationGroup, rate: number, loop: boolean);
378 |
379 | cc.setStrafeRightAnim(name: string|AnimationGroup, rate: number, loop: boolean);
380 | cc.setStrafeLeftAnim(name: string|AnimationGroup, rate: number, loop: boolean);
381 |
382 | cc.setStrafeRightFastAnim(name: string|AnimationGroup, rate: number, loop: boolean);
383 | cc.setStrafeLeftFastAnim(name: string|AnimationGroup, rate: number, loop: boolean);
384 |
385 | cc.setSlideBackAnim(name :string|AnimationGroup, rate: number, loop: boolean);
386 | ```
387 |
388 | So lets say your walk animation range is called "myWalk" and you want to play it at half speed and loop it continuoulsy then
389 |
390 | ```
391 | cc.setWalkAnim("myWalk", 0.5, true);
392 | //if you donot want to change the name or the rate then use below instead
393 | cc.setWalkAnim(null, null, true);
394 | ```
395 |
396 | If animation Group
397 |
398 | ```
399 | let myWalkAnimationGroup:AnimationGroup = ...;
400 | cc.setWalkAnim(myWalkAnimationGroup, 0.5, true);
401 | ```
402 |
403 | #### To change key binding
404 |
405 | By default the controller uses WASDQE, space, Capslock and arrow keys to controll your Avatar.
406 |
407 | | KEY/KEYS | ACTION |
408 | | ----------------- | -------------------------------------------------------- |
409 | | w and up arrow | walk forward |
410 | | Shift + w | run |
411 | | CapsLock | locks the Shift key and thus pressing "w" results in run |
412 | | s and down Arrow | walk backward |
413 | | a and left Arrow | turn left |
414 | | d and right Arrow | turn right |
415 | | q | strafe left |
416 | | e | strafe right |
417 | | " " | jump |
418 |
419 | To change these use
420 |
421 | ```
422 | cc.setWalkKey(string: key);
423 | cc.setWalkBackKey(string: key);
424 | cc.setTurnLeftKey(string: key);
425 | cc.setTurnRightKey(string: key);
426 | cc.setStrafeLeftKey(string: key);
427 | cc.setStrafeRightKey(string: key);
428 | cc.setJumpKey(string: key);
429 | ```
430 |
431 | Example: To use "x" key to walkback do
432 |
433 | ```
434 | cc.setWalkBackKey("x");
435 | ```
436 |
437 | To specify spacebar key use " ". Example cc.setJumpKey(" ")
438 | If targetting IE11 and previous use the word "spacebar".
439 | Example:
440 |
441 | ```
442 | var ua = window.navigator.userAgent;
443 | var isIE = /MSIE|Trident/.test(ua);
444 | if (isIE) {
445 | //IE specific code goes here
446 | cc.setJumpKey("spacebar");
447 | }
448 |
449 | ```
450 |
451 | Note: Currently you cannot reassign Shift, Capslock or Arrow Keys to other actions. This is on TODO list
452 |
453 | #### Controlling Avatar programmatically
454 |
455 | In addition to keyboard, as show above, the Avatar's movement can also be controlled from script using the following methods.
456 | You might use these to controll movement using say UI, Mouse Clicks, Touch Controllers etc.
457 |
458 | ```
459 | cc.walk(b: boolean);
460 | cc.walkBack(b: boolean);
461 | cc.run(b: boolean);
462 | cc.turnLeft(b: boolean);
463 | cc.turnRight(b: boolean);
464 | cc.strafeLeft(b: boolean);
465 | cc.strafeRight(b: boolean);
466 | cc.jump(b: boolean);
467 | cc.fall();
468 | ```
469 |
470 | Example:
471 |
472 | ```
473 | cc.walk(true); // will start walking the Avatar.
474 | cc.walk(false); // will stop walking the Avatar.
475 | ```
476 |
477 | A word about cc.fall(). The CharacterController doesn't constantly check if the user is "grounded". This is to prevent needless computation. Once the Avatar is on a ground/floor it assumes the Avatar will continue to stand on that ground/floor until the user uses keys to move the Avatar.
478 | In some use cases the ground/floor might move away and thus leave the Avatar hanging in mid air. In such cases use cc.fall() to force the Avatar to fall to the next gound/floor below.
479 |
480 |
481 | #### Enabling/Disabling the KeyBoard controll
482 |
483 | Sometimes, when you are controlling the movement of the Avatar programmatically as shown above, you might want to disable the keyboard.
484 | Use the following method to enable disable the keyboard.
485 |
486 | ```
487 | cc.enableKeyBoard(b: boolean);
488 | ```
489 |
490 | cc.enableKeyBoard(true) enables the keyboard
491 | cc.enableKeyBoard(false) disables the keyboard
492 |
493 | #### To change gravity or speed at which avatar/player is moved
494 |
495 | Speed is specified in meters/second
496 |
497 | ```
498 | setGravity(n: number); //default 9.8 m/s^2
499 | setWalkSpeed(n: number); //default 3 m/s
500 | setRunSpeed(n: number); //default 6 m/s
501 | setBackSpeed(n: number); //default 3 m/s
502 | setBackFastSpeed(n: number); //default 6 m/s
503 | setJumpSpeed(n: number); //default 6 m/s
504 | setLeftSpeed(n: number); //default 3 m/s
505 | setLeftFastSpeed(n: number); //default 6 m/s
506 | setRightSpeed(n: number); //default 3 m/s
507 | setRightFastSpeed(n: number); //default 6 m/s
508 | setTurnSpeed (n:number);//default PI/8 degree/s
509 | setTurnFastSpeed (n:number);//default PI/4 degree/s
510 | ```
511 |
512 | #### To change the slope the avatar can traverse
513 |
514 | ```
515 | setSlopeLimit(minSlopeLimit: number, maxSlopeLimit: number); //the slope is specified in degrees
516 | ```
517 |
518 | Example
519 |
520 | ```
521 | setSlopeLimit(45, 55);
522 | ```
523 |
524 | Here if the avatar is on a slope with angle between 45 and 55 degrees then it will start sliding back when it stops moving.
525 | If the slope is 55 or more then avatar will not be able to move up on it.
526 |
527 | #### To change the height of steps the avatar can climb
528 |
529 | ```
530 | setStepOffset(stepOffset: number);
531 | ```
532 |
533 | Example
534 |
535 | ```
536 | setStepOffset(0.5);
537 | ```
538 |
539 | The avatar can only move up a step if the height of the step is less than or equal to the "stepOffset".
540 | By default the value is 0.25.
541 |
542 | #### To set/change the setup step sound.
543 |
544 | ```
545 | setSound(Babylon.Sound);
546 | ```
547 |
548 | Example
549 |
550 | ```
551 | let sound = new BABYLON.Sound(
552 | "footstep",
553 | "./sounds/footstep_carpet_000.ogg",
554 | scene,
555 | () => {
556 | cc.setSound(sound);
557 | },
558 | { loop: false }
559 | );
560 | ```
561 |
562 | The above will load sound from file "footstep_carpet_000.ogg" and when loaded will set the Avatar step sound to that.
563 | This sound will be played for all actions except idle.
564 | The sound will be played twice per cycle of the animation.
565 | The rate will be set automatically based on frames and fps of animation
566 |
567 | #### To change avatar or skeleton at
568 |
569 | ```
570 | setAvatar(avatar: Mesh);
571 | setAvatarSkeleton(skeleton: Skeleton);
572 | ```
573 |
574 | #### To change camera behavior
575 |
576 | By default the camera focuses on the avatar/player origin. To focus on a different position on the avatar/player use
577 |
578 | ```
579 | setCameraTarget(v: Vector3);
580 | ```
581 |
582 | Lets say your avatar origin is at its feet but instead of focusing on its feet you would like camera to focus on its head then, assuming the the head is 1.8m above ground, you would do
583 |
584 | ```
585 | cc.setCameraTarget(new BABYLON.Vector3(0, 1.8, 0);
586 | ```
587 |
588 | By default the camera behaves "elastically". In other words if something comes between the camera and avatar the camera snaps to
589 | a position in front of that something. This way the avatar/player is always in view.
590 | To turn this off use
591 |
592 | ```
593 | setCameraElasticity(false);
594 | ```
595 |
596 | You can use the arc rotate camera's "lowerRadiusLimit" and "upperRadiusLimit" property to controll how close or how far away from the avatar the camera can get.
597 | Example setting
598 |
599 | ```
600 | camera.lowerRadiusLimit = 2;
601 | camera.upperRadiusLimit = 20;
602 | ```
603 |
604 | will restrict the camera between 2 and 20m from the avatar/player.
605 | When the camera comes to the "lowerRadiusLimit" the controller switches to first person view. In other words it makes the avatar/player invisible and the camera collision is disabled. Pulling camera back restores the third person view.
606 | To prevent this use
607 |
608 | ```
609 | setNoFirstPerson(true);
610 | ```
611 |
612 | ## Build
613 |
614 | If not already installed, install node js.
615 | Switch to the project folder.
616 | Run "npm install", once, to install all the dependencies.
617 |
618 | ### To build
619 |
620 | 1. Run "npm run build"
621 | This will create a production build.
622 | This will both compile, minify and store the build called CharacterController.js in "dist" folder.
623 | 2. Run "npm run build-dev"
624 | This will create a development build.
625 | This will compile and create a non minified build called CharacterController.max.js in "dist" folder.
626 |
627 | ### To test
628 |
629 | Two ways to test.
630 |
631 | 1. using the webpack-dev-server.
632 | Start the development server
633 | "npm run start"
634 | This will start the live dev server on port 8080 (could be different if this port is already in use) and open the browser pointing at http://localhost:8080/tst/test.html.
635 | The dev server will live recompile your code any time you make changes.
636 | Note: The dev server does not write the build to disk, instead it just builds and serves from memory. In our case it builds "CharacterController.max.js" in memory and serves it from url http://localhost:8080/dist. (see "devserver.devMidleware.publicPath" in wepack.config.js file).
637 |
638 | 2. using any other http server.
639 | Start the server , say http-server, from the project root folder (not from within "/tst " folder).
640 | Goto http://localhost:8080/tst/test.html (assuming the server was started on port 8080).
641 | Everytime you make changes you will have to build using "npm start build-dev".
642 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-cayman
--------------------------------------------------------------------------------
/dist/CharacterController.d.ts:
--------------------------------------------------------------------------------
1 | import { Skeleton, ArcRotateCamera, Vector3, Mesh, Scene, AnimationGroup, Sound, LinesMesh } from "babylonjs";
2 | export declare class CharacterController {
3 | private _avatar;
4 | private _skeleton;
5 | private _camera;
6 | private _scene;
7 | getScene(): Scene;
8 | private _gravity;
9 | private _minSlopeLimit;
10 | private _maxSlopeLimit;
11 | private _sl1;
12 | private _sl2;
13 | private _stepOffset;
14 | private _vMoveTot;
15 | private _pauseCam;
16 | private _vMovStartPos;
17 | private _actionMap;
18 | private _cameraElastic;
19 | private _cameraTarget;
20 | private _noFirstPerson;
21 | private _down;
22 | setSlopeLimit(minSlopeLimit: number, maxSlopeLimit: number): void;
23 | setStepOffset(stepOffset: number): void;
24 | setWalkSpeed(n: number): void;
25 | setRunSpeed(n: number): void;
26 | setBackSpeed(n: number): void;
27 | setBackFastSpeed(n: number): void;
28 | setJumpSpeed(n: number): void;
29 | setLeftSpeed(n: number): void;
30 | setLeftFastSpeed(n: number): void;
31 | setRightSpeed(n: number): void;
32 | setRightFastSpeed(n: number): void;
33 | setTurnSpeed(n: number): void;
34 | setTurnFastSpeed(n: number): void;
35 | setGravity(n: number): void;
36 | setAnimationGroups(agMap: {}): void;
37 | setAnimationRanges(arMap: {}): void;
38 | setActionMap(inActMap: ActionMap): string;
39 | getActionMap(): ActionMap;
40 | getSettings(): CCSettings;
41 | setSettings(ccs: CCSettings): void;
42 | private _setAnim;
43 | enableBlending(n: number): void;
44 | disableBlending(): void;
45 | setWalkAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
46 | setRunAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
47 | setWalkBackAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
48 | setWalkBackFastAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
49 | setSlideBackAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
50 | setIdleAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
51 | setTurnRightAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
52 | setTurnRightFastAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
53 | setTurnLeftAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
54 | setTurnLeftFastAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
55 | setStrafeRightAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
56 | setStrafeRightFastAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
57 | setStrafeLeftAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
58 | setStrafeLeftFastAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
59 | setIdleJumpAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
60 | setRunJumpAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
61 | setFallAnim(rangeName: string | AnimationGroup, rate: number, loop: boolean): void;
62 | _stepSound: Sound;
63 | setSound(sound: Sound): void;
64 | setWalkKey(key: string): void;
65 | setWalkBackKey(key: string): void;
66 | setTurnLeftKey(key: string): void;
67 | setTurnRightKey(key: string): void;
68 | setStrafeLeftKey(key: string): void;
69 | setStrafeRightKey(key: string): void;
70 | setJumpKey(key: string): void;
71 | setCameraElasticity(b: boolean): void;
72 | setElasticiSteps(n: number): void;
73 | makeObstructionInvisible(b: boolean): void;
74 | setCameraTarget(v: Vector3): void;
75 | cameraCollisionChanged(): void;
76 | setNoFirstPerson(b: boolean): void;
77 | private _checkAnimRanges;
78 | private _checkFastAnims;
79 | private _copySlowAnims;
80 | private _mode;
81 | private _saveMode;
82 | setMode(n: number): void;
83 | getMode(): number;
84 | setTurningOff(b: boolean): void;
85 | isTurningOff(): boolean;
86 | private _isLHS_RHS;
87 | private _signLHS_RHS;
88 | private _setRHS;
89 | private _ffSign;
90 | private _rhsSign;
91 | private _ff;
92 | private _av2cam;
93 | setFaceForward(b: boolean): void;
94 | isFaceForward(): boolean;
95 | private checkAGs;
96 | private _containsAG;
97 | private _getRoot;
98 | private _started;
99 | start(): void;
100 | stop(): void;
101 | private _stopAnim;
102 | pauseAnim(): void;
103 | resumeAnim(): void;
104 | private _prevActData;
105 | private _avStartPos;
106 | private _pickStartY;
107 | private _grounded;
108 | private _freeFallDist;
109 | private _fallFrameCountMin;
110 | private _fallFrameCount;
111 | private _inFreeFall;
112 | private _wasWalking;
113 | private _wasRunning;
114 | private _moveVector;
115 | private _isAvFacingCamera;
116 | private _moveAVandCamera;
117 | private _soundLoopTime;
118 | private _sndId;
119 | private _jumpStartPosY;
120 | private _jumpTime;
121 | private _doJump;
122 | private _calcJumpDist;
123 | private _endJump;
124 | private _areVectorsEqual;
125 | private _verticalSlope;
126 | private _movFallTime;
127 | private _sign;
128 | private _isTurning;
129 | private _noRot;
130 | private _steps;
131 | private _doMove;
132 | private _isNearGround;
133 | private _isNearGround_old;
134 | _aLine: LinesMesh;
135 | private _drawLines;
136 | private _rotateAV2C;
137 | private _rotateAVnC;
138 | private _endFreeFall;
139 | private _idleFallTime;
140 | private _doIdle;
141 | private _groundFrameCount;
142 | private _groundFrameMax;
143 | private _groundIt;
144 | private _unGroundIt;
145 | private _savedCameraCollision;
146 | private _inFP;
147 | private _updateTargetValue;
148 | private _makeMeshInvisible;
149 | private _visiblityMap;
150 | private _restoreVisiblity;
151 | private _ray;
152 | private _rayDir;
153 | private _cameraSkin;
154 | private _prevPickedMeshes;
155 | private _pickedMeshes;
156 | private _makeInvisible;
157 | private _elasticSteps;
158 | private _alreadyInvisible;
159 | private _handleObstruction;
160 | private _isSeeAble;
161 | private _move;
162 | anyMovement(): boolean;
163 | private _onKeyDown;
164 | private _onKeyUp;
165 | private _ekb;
166 | isKeyBoardEnabled(): boolean;
167 | enableKeyBoard(b: boolean): void;
168 | private _addkeylistener;
169 | private _removekeylistener;
170 | walk(b: boolean): void;
171 | walkBack(b: boolean): void;
172 | walkBackFast(b: boolean): void;
173 | run(b: boolean): void;
174 | turnLeft(b: boolean): void;
175 | turnLeftFast(b: boolean): void;
176 | turnRight(b: boolean): void;
177 | turnRightFast(b: boolean): void;
178 | strafeLeft(b: boolean): void;
179 | strafeLeftFast(b: boolean): void;
180 | strafeRight(b: boolean): void;
181 | strafeRightFast(b: boolean): void;
182 | jump(): void;
183 | fall(): void;
184 | idle(): void;
185 | private _act;
186 | private _renderer;
187 | private _handleKeyUp;
188 | private _handleKeyDown;
189 | private _isAG;
190 | isAg(): boolean;
191 | private _findSkel;
192 | private _root;
193 | private _getAbstractMeshChildren;
194 | setAvatar(avatar: Mesh, faceForward?: boolean): boolean;
195 | private _ellipsoid;
196 | showEllipsoid(show: boolean): void;
197 | getAvatar(): Mesh;
198 | setAvatarSkeleton(skeleton: Skeleton): void;
199 | private _skelDrivenByAG;
200 | getSkeleton(): Skeleton;
201 | private _hasAnims;
202 | private _hasCam;
203 | private _avChildren;
204 | constructor(avatar: Mesh, camera: ArcRotateCamera, scene: Scene, actionMap?: {}, faceForward?: boolean);
205 | }
206 | export declare class ActionData {
207 | id: string;
208 | speed: number;
209 | ds: number;
210 | sound: Sound;
211 | key: string;
212 | dk: string;
213 | name: string;
214 | ag: AnimationGroup;
215 | loop: boolean;
216 | rate: number;
217 | exist: boolean;
218 | constructor(id?: string, speed?: number, key?: string);
219 | reset(): void;
220 | }
221 | export declare class ActionMap {
222 | walk: ActionData;
223 | walkBack: ActionData;
224 | walkBackFast: ActionData;
225 | idle: ActionData;
226 | idleJump: ActionData;
227 | run: ActionData;
228 | runJump: ActionData;
229 | fall: ActionData;
230 | turnLeft: ActionData;
231 | turnLeftFast: ActionData;
232 | turnRight: ActionData;
233 | turnRightFast: ActionData;
234 | strafeLeft: ActionData;
235 | strafeLeftFast: ActionData;
236 | strafeRight: ActionData;
237 | strafeRightFast: ActionData;
238 | slideBack: ActionData;
239 | reset(): void;
240 | }
241 | export declare class CCSettings {
242 | faceForward: boolean;
243 | gravity: number;
244 | minSlopeLimit: number;
245 | maxSlopeLimit: number;
246 | stepOffset: number;
247 | cameraElastic: boolean;
248 | elasticSteps: number;
249 | makeInvisble: boolean;
250 | cameraTarget: Vector3;
251 | noFirstPerson: boolean;
252 | topDown: boolean;
253 | turningOff: boolean;
254 | keyboard: boolean;
255 | sound: Sound;
256 | }
257 |
--------------------------------------------------------------------------------
/dist/CharacterController.js:
--------------------------------------------------------------------------------
1 | !function(t,i){if("object"==typeof exports&&"object"==typeof module)module.exports=i(require("babylonjs"));else if("function"==typeof define&&define.amd)define(["babylonjs"],i);else{var s="object"==typeof exports?i(require("babylonjs")):i(t.BABYLON);for(var h in s)("object"==typeof exports?exports:t)[h]=s[h]}}(self,(t=>(()=>{"use strict";var i={247:i=>{i.exports=t}},s={};function h(t){var n=s[t];if(void 0!==n)return n.exports;var e=s[t]={exports:{}};return i[t](e,e.exports,h),e.exports}h.n=t=>{var i=t&&t.t?()=>t.default:()=>t;return h.d(i,{a:i}),i},h.d=(t,i)=>{for(var s in i)h.o(i,s)&&!h.o(t,s)&&Object.defineProperty(t,s,{enumerable:!0,get:i[s]})},h.o=(t,i)=>Object.prototype.hasOwnProperty.call(t,i),h.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"t",{value:!0})};var n={};return(()=>{h.r(n),h.d(n,{ActionData:()=>e,ActionMap:()=>r,CCSettings:()=>u,CharacterController:()=>i});var t=h(247),i=function(){function i(i,h,n,e,u){void 0===u&&(u=!1);var a=this;this.i=null,this.h=null,this.u=9.8,this.l=30,this.v=45,this.M=Math.PI*this.l/180,this.k=Math.PI*this.v/180,this.p=.25,this.j=0,this.g=!1,this.O=t.Vector3.Zero(),this.A=new r,this.B=!0,this.C=t.Vector3.Zero(),this.F=!1,this.L=t.Vector3.DownReadOnly,this.R=0,this.S=0,this.q=!1,this.I=-1,this.J=!1,this._=!1,this.D=null,this.N=t.Vector3.Zero(),this.T=0,this.Y=!1,this.G=0,this.H=20,this.K=0,this.P=!1,this.U=!1,this.V=!1,this.W=700,this.X=null,this.Z=0,this.$=0,this.tt=0,this.it=1,this.st=!1,this.ht=!1,this.nt=!0,this.et=null,this.rt=0,this.ut=0,this.ot=10,this.ft=!0,this.ct=!1,this.lt=new Map,this.vt=new t.Ray(t.Vector3.Zero(),t.Vector3.One(),1),this.bt=t.Vector3.Zero(),this.wt=.5,this.Mt=new Array,this.dt=!1,this.kt=50,this.yt=!1,this.jt=!0,this.gt=!1,this.Ot=null,this.At=!1,this.xt=!0,this.Bt=h,null==this.Bt&&(this.xt=!1,this.setMode(1)),this.Ct=n,this.setAvatar(i,u)||console.error("unable to set avatar");null!=e&&this.setActionMap(e),this.gt||null==this.h||this.Ft(this.h),this.gt,this.xt&&(this.ft=this.Bt.checkCollisions),this.Lt=new s,this.Rt=function(){a.St()},this.qt=function(t){a.It(t)},this.Jt=function(t){a._t(t)}}return i.prototype.getScene=function(){return this.Ct},i.prototype.setSlopeLimit=function(t,i){this.l=t,this.v=i,this.M=Math.PI*this.l/180,this.k=Math.PI*this.v/180},i.prototype.setStepOffset=function(t){this.p=t},i.prototype.setWalkSpeed=function(t){this.A.walk.speed=t},i.prototype.setRunSpeed=function(t){this.A.run.speed=t},i.prototype.setBackSpeed=function(t){this.A.walkBack.speed=t},i.prototype.setBackFastSpeed=function(t){this.A.walkBackFast.speed=t},i.prototype.setJumpSpeed=function(t){this.A.idleJump.speed=t,this.A.runJump.speed=t},i.prototype.setLeftSpeed=function(t){this.A.strafeLeft.speed=t},i.prototype.setLeftFastSpeed=function(t){this.A.strafeLeftFast.speed=t},i.prototype.setRightSpeed=function(t){this.A.strafeRight.speed=t},i.prototype.setRightFastSpeed=function(t){this.A.strafeLeftFast.speed=t},i.prototype.setTurnSpeed=function(t){this.A.turnLeft.speed=t*Math.PI/180,this.A.turnRight.speed=t*Math.PI/180},i.prototype.setTurnFastSpeed=function(t){this.A.turnLeftFast.speed=t*Math.PI/180,this.A.turnRightFast.speed=t*Math.PI/180},i.prototype.setGravity=function(t){this.u=t},i.prototype.setAnimationGroups=function(t){null!=this.D&&this.D.exist&&this.D.ag.stop(),this.gt=!0,this.setActionMap(t)},i.prototype.setAnimationRanges=function(t){this.gt=!1,this.setActionMap(t)},i.prototype.setActionMap=function(i){for(var s,h=!1,n=0,r=Object.keys(this.A);n-1)return!0}return!1},i.prototype.Qt=function(t){return null==t.parent?t:this.Qt(t.parent)},i.prototype.start=function(){this.J||(this.J=!0,this.Lt.reset(),this.tt=0,this.rt=.001,this.Y=!1,this.Ut(),this.jt&&this.Vt(),this.Ct.registerBeforeRender(this.Rt))},i.prototype.stop=function(){this.J&&(this.J=!1,this.Ct.unregisterBeforeRender(this.Rt),this.Wt(),this.D=null)},i.prototype.pauseAnim=function(){this._=!0,null!=this.D&&this.D.exist&&(this.gt?this.D.ag.stop():this.Ct.stopAnimation(this.h),null!=this.D.sound&&this.D.sound.stop(),clearInterval(this.X),this.Ct.unregisterBeforeRender(this.Rt))},i.prototype.resumeAnim=function(){this._=!1,this.D=null,this.Ct.registerBeforeRender(this.Rt)},i.prototype.Xt=function(){return this.xt?t.Vector3.Dot(this.i.forward,this.i.position.subtract(this.Bt.position))<0?1:-1:1},i.prototype.St=function(){this.N.copyFrom(this.i.position);var t=null,i=this.Ct.getEngine().getDeltaTime()/1e3;if(this.Lt.Zt&&!this.P?(this.j=0,this.g=!1,this.Y=!1,this.rt=0,t=this.$t(i)):this.anyMovement()||this.P?(this.Y=!1,this.rt=0,t=this.ti(i)):this.P||(t=this.ii(i)),!this._&&this.At&&null!=t&&this.D!==t){if(t.exist){var s=void 0,h=30;if(this.gt)null!=this.D&&this.D.exist&&this.D.ag.stop(),t.ag.start(t.loop,t.rate),h=t.ag.targetedAnimations[0].animation.framePerSecond,s=t.ag.to-t.ag.from;else h=this.h.beginAnimation(t.name,t.loop,t.rate).getAnimations()[0].animation.framePerSecond,s=this.h.getAnimationRange(t.name).to-this.h.getAnimationRange(t.name).from;null!=this.D&&null!=this.D.sound&&this.D.sound.stop(),clearInterval(this.X),null!=t.sound&&(t.sound.play(),this.X=setInterval((function(){t.sound.play()}),1e3*s/(h*Math.abs(t.rate)*2)))}this.D=t}this.Ut()},i.prototype.$t=function(i){var s=null;s=this.A.runJump,0===this.$&&(this.Z=this.i.position.y),this.$=this.$+i;var h,n=0,e=0;if(this.V||this.U?(this.V?n=this.A.run.speed*i:this.U&&(n=this.A.walk.speed*i),(h=this.si.clone()).y=0,(h=h.normalize()).scaleToRef(n,h),e=this.hi(this.A.runJump.speed,i),h.y=e):(e=this.hi(this.A.idleJump.speed,i),h=new t.Vector3(0,e,0),s=this.A.idleJump),this.i.moveWithCollisions(h),e<0)if(this.i.position.y>this.N.y||this.i.position.y===this.N.y&&h.length()>.001)this.ni();else if(this.i.position.y0?this.A.strafeLeftFast:this.A.strafeRightFast):h=-this.Kt*n>0?this.A.strafeLeft:this.A.strafeRight,this.si=this.i.calcMovePOV(n*e,-this.G,0),s=!0;break;case this.Lt.li:n=-this.I*this.Xt(),e=this.A.strafeRight.speed*t,this.Lt.ci?(e=this.A.strafeRightFast.speed*t,h=-this.Kt*n>0?this.A.strafeLeftFast:this.A.strafeRightFast):h=-this.Kt*n>0?this.A.strafeLeft:this.A.strafeRight,this.si=this.i.calcMovePOV(n*e,-this.G,0),s=!0;break;case this.Lt.vi||this.ht&&0==this.R:this.Lt.ci?(this.V=!0,e=this.A.run.speed*t,h=this.A.run):(this.U=!0,e=this.A.walk.speed*t,h=this.A.walk),this.si=this.i.calcMovePOV(0,-this.G,this.Kt*e),s=!0;break;case this.Lt.bi:e=this.A.walkBack.speed*t,this.Lt.ci?(e=this.A.walkBackFast.speed*t,h=this.A.walkBackFast):h=this.A.walkBack,this.si=this.i.calcMovePOV(0,-this.G,-this.Kt*e),s=!0}}if(s&&this.si.length()>.001){this.i.moveWithCollisions(this.si);var r=this.i.position.subtract(this.N),u=this.ri(r);if(this.i.position.y-this.N.y>.01)if(0==u.slope){if(this.p>0){if(0==this.j)this.O.copyFrom(this.N),u.y-this.O.y>this.p&&this.i.position.copyFrom(this.O);this.j=this.i.position.y-this.O.y,this.j>this.p&&(this.i.position.copyFrom(this.O),this.g=!0,this.j=0)}}else{this.j=0;var a=u.slope;a>=this.k&&u.y>this.T?(this.i.position.copyFrom(this.N),this.wi(),this.T=0):(this.T=u.y,a>this.M?(this.K=0,this.P=!1):this.wi())}else this.N.y>this.i.position.y?(this.j=0,u.y>=this.i.position.y?u.slope<=this.M?this.wi():(this.K=0,this.P=!1):(this.i.position.y-u.y>1||!u.hit)&&(this.g=!1,this.P=!0,h=this.A.fall)):(this.j=0,this.wi())}return h},i.prototype.ri=function(i){var s,h=this,n=this.i.position.y-this.N.y,e=!0;(e=Math.abs(n)<.006||n>.01,i.y=0,0==i.x&&0==i.z)?s=!0:s=t.Vector3.Dot(this.i.forward,i.normalize())>=0;var r=e&&s||!e&&!s?1:-1;this.i.forward.scaleToRef(this.i.ellipsoid.x*r,this.vt.origin),this.vt.origin.addToRef(this.i.position,this.vt.origin),this.vt.origin.addToRef(this.i.ellipsoidOffset,this.vt.origin),this.vt.length=2*this.i.ellipsoid.y,this.vt.direction=this.L,this.Mi(this.vt.origin,this.vt.origin.add(new t.Vector3(0,-this.vt.length,0)));var u=this.Ct.pickWithRay(this.vt,(function(t){return!h.di.includes(t)&&!!t.checkCollisions}));if(null!=u&&u.hit){var a=u.getNormal(!0,!0),o=Math.PI/2-Math.asin(Math.abs(a.y));return{name:u.pickedMesh.name,ground:!0,slope:o,y:u.pickedPoint.y,hit:!0}}return{name:"",ground:!1,slope:0,y:0,hit:!1}},i.prototype.ki=function(){var t=this;this.i.position.addToRef(this.i.ellipsoidOffset,this.vt.origin),this.vt.origin.y=this.vt.origin.y-this.i.ellipsoid.y,this.vt.length=this.i.ellipsoid.y/2,this.vt.direction=this.L;var i=this.Ct.multiPickWithRay(this.vt,(function(i){return i!=t.i&&!!i.checkCollisions}));if(i.length>0){var s=i[0],h=s.getNormal(!0,!0),n=Math.PI/2-Math.asin(Math.abs(h.y));return{name:s.pickedMesh.name,ground:!0,slope:n}}return{name:"",ground:!1,slope:0}},i.prototype.Mi=function(i,s){null!=this.et&&this.et.dispose();var h={points:[i,s],updatable:!0};this.et=t.MeshBuilder.CreateLines("lines",h)},i.prototype.ai=function(){if(this.xt&&1!=this.R){var t=this.xt?this.Ht-this.Bt.alpha:0;if(this.ht)switch(!0){case this.Lt.vi&&this.Lt.pi:this.i.rotation.y=t+this.Gt*Math.PI/4;break;case this.Lt.vi&&this.Lt.yi:this.i.rotation.y=t-this.Gt*Math.PI/4;break;case this.Lt.bi&&this.Lt.pi:this.i.rotation.y=t+3*this.Gt*Math.PI/4;break;case this.Lt.bi&&this.Lt.yi:this.i.rotation.y=t-3*this.Gt*Math.PI/4;break;case this.Lt.vi:this.i.rotation.y=t;break;case this.Lt.bi:this.i.rotation.y=t+Math.PI;break;case this.Lt.pi:this.i.rotation.y=t+this.Gt*Math.PI/2;break;case this.Lt.yi:this.i.rotation.y=t-this.Gt*Math.PI/2}else this.xt&&(this.i.rotation.y=t)}},i.prototype.oi=function(t,i,s){if((!this.ht||0!=this.R)&&!this.Lt.fi&&!this.Lt.li&&(this.Lt.yi||this.Lt.pi)){var h=this.A.turnLeft.speed*s;this.Lt.ci&&(h*=2);var n=void 0;1==this.R?(this.st||(this.it=-this.Kt*this.Xt(),this.q&&(this.it=-this.it),this.st=!0),n=this.it,this.Lt.yi?this.Lt.vi||(this.Lt.bi?n=-this.it:t=this.it>0?this.A.turnRight:this.A.turnLeft):this.Lt.vi?n=-this.it:this.Lt.bi||(n=-this.it,t=this.it>0?this.A.turnLeft:this.A.turnRight)):(n=1,this.Lt.yi?(this.Lt.bi&&(n=-1),i||(t=this.A.turnLeft)):(this.Lt.vi&&(n=-1),i||(n=-1,t=this.A.turnRight)),this.xt&&(this.Bt.alpha=this.Bt.alpha+this.Gt*h*n)),this.i.rotation.y=this.i.rotation.y+h*n}return t},i.prototype.wi=function(){this.tt=0,this.K=0,this.P=!1},i.prototype.ii=function(i){if(this.Y)return this.A.idle;this.U=!1,this.V=!1,this.tt=0;var s=this.A.idle;if(this.K=0,0===i)this.G=5;else{var h=this.rt*this.u;this.G=h*i+this.u*i*i/2,this.rt=this.rt+i}if(this.G<.01)return s;var n=new t.Vector3(0,-this.G,0);if(this.i.moveWithCollisions(n),this.i.position.y>this.N.y||this.i.position.y===this.N.y){var e=this.i.position.subtract(this.N);this.ri(e).slope<=this.M?(this.ji(),this.i.position.copyFrom(this.N)):(this.mi(),s=this.A.slideBack)}else if(this.i.position.ythis.ot&&(this.Y=!0,this.rt=0)},i.prototype.mi=function(){this.Y=!1,this.ut=0},i.prototype.Ut=function(){this.xt&&(this.g?this.O.addToRef(this.C,this.Bt.target):this.i.position.addToRef(this.C,this.Bt.target),this.Bt.radius>this.Bt.lowerRadiusLimit&&(this.B||this.dt)&&this.gi(),this.Bt.radius<=this.Bt.lowerRadiusLimit?this.F||this.ct||(this.Oi(this.i),this.Bt.checkCollisions=!1,this.S=this.R,this.R=0,this.ct=!0):this.ct&&(this.ct=!1,this.R=this.S,this.Ai(this.i),this.Bt.checkCollisions=this.ft))},i.prototype.Oi=function(i){var s=this;this.lt.set(i,i.visibility),i.visibility=0,i.getChildMeshes(!1,(function(i){return i instanceof t.Mesh&&(s.lt.set(i,i.visibility),i.visibility=0),!1}))},i.prototype.Ai=function(i){var s=this;i.visibility=this.lt.get(i),i.getChildMeshes(!1,(function(i){return i instanceof t.Mesh&&(i.visibility=s.lt.get(i)),!1}))},i.prototype.gi=function(){var t=this;this.Bt.position.subtractToRef(this.Bt.target,this.bt),this.vt.origin=this.Bt.target,this.vt.length=this.bt.length(),this.vt.direction=this.bt.normalize();var i=this.Ct.multiPickWithRay(this.vt,(function(i){return!t.di.includes(i)&&!!i.isPickable}));if(this.dt)if(this.xi=this.Mt,i.length>0){this.Mt=new Array;for(var s=0,h=i;s0){if(!(1!=i.length||this.Bi(i[0].pickedMesh)||i[0].pickedMesh.checkCollisions&&this.Bt.checkCollisions))return;for(var f=null,c=0;c0?h[0].skeleton:null},i.prototype.Fi=function(t){return null==t.parent?t:this.Fi(t.parent)},i.prototype.Li=function(i){var s=new Array;return i instanceof t.AbstractMesh&&s.push(i),i.getChildren((function(i){return i instanceof t.AbstractMesh&&s.push(i),!1}),!1),s},i.prototype.setAvatar=function(i,s){void 0===s&&(s=!1);var h=this.Fi(i);return h instanceof t.Mesh?(this.i=h,this.di=this.Li(h),this.h=this.Ci(i),this.gt=this.Pt(i,this.Ct.animationGroups,!0),this.A.reset(),this.gt||null==this.h||this.Ft(this.h),this.zt(i),this.setFaceForward(s),!0):(console.error("Cannot move this mesh. The root node of the mesh provided is not a mesh"),!1)},i.prototype.showEllipsoid=function(i){if(!i)return null!=this.Ot&&this.Ot.dispose(),void(this.Ot=null);for(var s=new t.TransformNode("ellipsoid",this.Ct),h=this.i.ellipsoid.x,n=this.i.ellipsoid.y,e=[],r=-Math.PI/2;r",
14 | "license": "Apache-2.0",
15 | "contributors": [],
16 | "main": "dist/CharacterController.js",
17 | "types": "dist/CharacterController.d.ts",
18 | "devDependencies": {
19 | "babylonjs": "^8.4.0",
20 | "babylonjs-inspector": "^8.4.0",
21 | "babylonjs-loaders": "^8.4.0",
22 | "terser-webpack-plugin": "^5.3.6",
23 | "ts-loader": "^9.4.2",
24 | "typescript": "^4.9.4",
25 | "webpack": "^5.75.0",
26 | "webpack-cli": "^5.0.1",
27 | "webpack-dev-server": "^4.11.1"
28 | },
29 | "scripts": {
30 | "dev": "webpack serve --open /tst/test.html",
31 | "build-dev": "webpack --mode=development",
32 | "build": "webpack --mode=production"
33 | }
34 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "declaration":true,
4 | "target": "es5",
5 | "module": "es2015",
6 | "moduleResolution": "node",
7 | "sourceMap": true,
8 | "emitDecoratorMetadata": true,
9 | "experimentalDecorators": true,
10 | "removeComments": true,
11 | "noImplicitAny": false,
12 | "outDir":"dist"
13 | },
14 | "include": ["src/**/*.ts"],
15 | "lib":["dom"]
16 | }
17 |
18 |
--------------------------------------------------------------------------------
/tst/ground/ground-normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/ground/ground-normal.png
--------------------------------------------------------------------------------
/tst/ground/ground.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/ground/ground.jpg
--------------------------------------------------------------------------------
/tst/ground/ground_heightMap.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/ground/ground_heightMap.png
--------------------------------------------------------------------------------
/tst/player/Vincent-backFacing.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/player/Vincent-backFacing.blend
--------------------------------------------------------------------------------
/tst/player/Vincent-backFacing.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/player/Vincent-backFacing.glb
--------------------------------------------------------------------------------
/tst/player/Vincent-frontFacing.blend:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/player/Vincent-frontFacing.blend
--------------------------------------------------------------------------------
/tst/player/Vincent-frontFacing.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/player/Vincent-frontFacing.glb
--------------------------------------------------------------------------------
/tst/player/Vincent_texture_image.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/player/Vincent_texture_image.jpg
--------------------------------------------------------------------------------
/tst/sounds/footstep_carpet_000.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/sounds/footstep_carpet_000.ogg
--------------------------------------------------------------------------------
/tst/sounds/footstep_concrete_000.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ssatguru/BabylonJS-CharacterController/1132bbda84a1cf3ba8397af19d602f6941646155/tst/sounds/footstep_concrete_000.ogg
--------------------------------------------------------------------------------
/tst/test.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
16 |
17 |