Skip to content

Commit

Permalink
💥 Merge version 3 development branch to main
Browse files Browse the repository at this point in the history
Merge pull request #4 from ma1ted/development
  • Loading branch information
malted committed Aug 17, 2022
2 parents 6f5473a + 5fb8867 commit 2be7eee
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 150 deletions.
107 changes: 59 additions & 48 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# charactercontroller

A first person character controller for the Three.js graphics library

![GitHub Lint Workflow Status](https://img.shields.io/github/workflow/status/ma1ted/charactercontroller/CI?label=Lint)
Expand All @@ -11,9 +12,11 @@ A first person character controller for the Three.js graphics library
## [Demo](https://controller.malted.dev)

## Installation

`npm install charactercontroller`

## Usage

```javascript
import CharacterController from "charactercontroller";

Expand All @@ -22,64 +25,72 @@ import CharacterController from "charactercontroller";
const controller = new CharacterController(scene, options);

function animate() {
requestAnimationFrame(animate);
// ...
controller.update();
renderer.render(scene, controller.camera);
requestAnimationFrame(animate);
// ...
controller.update();
renderer.render(scene, controller.camera);
}
```
* `scene`
+ An instance of `THREE.Scene` that the Character Controller is to become a child of.

* `options`
+ An object defining options for the Character Controller. The valid fields are described below
- `scene`

- An instance of `THREE.Scene` that the Character Controller is to become a child of.

- `options`
- An object defining options for the Character Controller. The valid fields are described below

## Constructor Options
* `walkSpeed`
+ The rate at which the controller is translated in the scene in response to player inputs, when the sprint key (left shift) **is not** being pressed.
+ Default: `5`
* `sprintSpeed`
+ The rate at which the controller is translated in the scene in response to player inputs, when the sprint key (left shift) **is** being pressed.
+ Default: `10`
* `floorDistance`
+ How far above a surface the controller can get before stopping falling.
+ Could be interpreted as the height of the player.
+ Default: `1`
* `gravity`
+ How quickly the controller is pulled down when there is no surface beneath it.
+ Default: `-9.81`
* `jumpPower`
+ With how much force the controller is projected upwards when a jump is initiated.
+ Default: `5`
* `sensitivity`
+ `x`

- `walkSpeed`
- The rate at which the controller is translated in the scene in response to player inputs, when the sprint key (left shift) **is not** being pressed.
- Default: `5`
- `sprintSpeed`
- The rate at which the controller is translated in the scene in response to player inputs, when the sprint key (left shift) **is** being pressed.
- Default: `10`
- `floorDistance`
- How far above a surface the controller can get before stopping falling.
- Could be interpreted as the height of the player.
- Default: `1`
- `gravity`
- How quickly the controller is pulled down when there is no surface beneath it.
- Default: `-9.81`
- `jumpPower`
- With how much force the controller is projected upwards when a jump is initiated.
- Default: `5`
- `sensitivity`
- `x`
- How much the camera should move in response to the player moving the mouse left and right.
- Default: `0.1`
+ `y`
- `y`
- How much the camera should move in response to the player moving the mouse up and down.
- Default: `0.1`
* `lookLimit`
+ `down`
- `lookLimit`
- `down`
- The angle in degrees that the camera's `x` rotation should be clamped to when looking down
- Default: `0`
+ `up`
- `up`
- The angle in degrees that the camera's `x` rotation should be clamped to when looking up
- Default: `180`
* `cameraFov`
+ The field of view of the camera attatched to the character controller.
+ Default: `75`
* `inputs`
+ The `KeyboardEvent.code`s that control the character controller. An array of `code`s are used to support multiple keys controlling the same actions; primarily for accessability reasons.
+ `forwards`
- Default: [`KeyW`, `ArrowUp`]
+ `backwards`
- Default: [`KeyS`, `ArrowDown`]
+ `left`
- Default: [`KeyA`, `ArrowLeft`]
+ `right`
- Default: [`KeyD`, `ArrowRight`]
+ `jump`
- Default: [`Space`]
+ `sprint`
- Default: [`ShiftLeft`, `ShiftRight`]

- `cameraFov`
- The field of view of the camera attatched to the character controller.
- Default: `75`
- `inputMappings`

- The input mapping schema has changed in version 3. The docs are currently being rewitten to reflect this. In the meantime, look at the `inputMappings` property in `/src/index.js` for the new schema.

<!--
- The `KeyboardEvent.code`s that control the character controller. An array of `code`s are used to support multiple keys controlling the same actions; primarily for accessability reasons.
+ `forwards`
- Default: [`KeyW`, `ArrowUp`]
+ `backwards`
- Default: [`KeyS`, `ArrowDown`]
+ `left`
- Default: [`KeyA`, `ArrowLeft`]
+ `right`
- Default: [`KeyD`, `ArrowRight`]
+ `jump`
- Default: [`Space`]
+ `sprint`
- Default: [`ShiftLeft`, `ShiftRight`]
-- >
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 34 additions & 34 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
{
"name": "charactercontroller",
"version": "2.1.0",
"description": "A first person character controller for the Three.js graphics library",
"main": "src/index.js",
"scripts": {
"lint": "eslint src/index.js",
"format": "prettier --write src/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ma1ted/charactercontroller.git"
},
"keywords": [
"threejs",
"fps",
"controller"
],
"author": "malted",
"license": "MIT",
"bugs": {
"url": "https://github.com/ma1ted/charactercontroller/issues"
},
"homepage": "https://github.com/ma1ted/charactercontroller#readme",
"devDependencies": {
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.6.2"
},
"dependencies": {
"three": "^0.141.0"
},
"publishConfig": {
"registry": "https://registry-url"
}
"name": "charactercontroller",
"version": "3.0.0",
"description": "A first person character controller for the Three.js graphics library",
"main": "src/index.js",
"scripts": {
"lint": "eslint src",
"format": "prettier --write src"
},
"repository": {
"type": "git",
"url": "git+https://github.com/ma1ted/charactercontroller.git"
},
"keywords": [
"threejs",
"fps",
"controller"
],
"author": "malted",
"license": "MIT",
"bugs": {
"url": "https://github.com/ma1ted/charactercontroller/issues"
},
"homepage": "https://github.com/ma1ted/charactercontroller#readme",
"devDependencies": {
"eslint": "^8.16.0",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.6.2"
},
"dependencies": {
"three": "^0.141.0"
},
"publishConfig": {
"registry": "https://registry-url"
}
}
78 changes: 27 additions & 51 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Group, Clock, PerspectiveCamera, Raycaster, Vector3, MathUtils } from "three";
import * as PlayerUtils from "./playerUtils.js";
import * as InputUtils from "./inputUtils.js";

export default class CharacterController {
constructor(
Expand All @@ -19,13 +20,21 @@ export default class CharacterController {
up: 180,
},
cameraFov = 75,
inputs = {
forwards: ["KeyW", "ArrowUp"],
backwards: ["KeyS", "ArrowDown"],
left: ["KeyA", "ArrowLeft"],
right: ["KeyD", "ArrowRight"],
jump: ["Space"],
sprint: ["ShiftLeft", "ShiftRight"],
inputMappings = {
scalar: {
horizontalAxis: [
{ inputs: ["KeyA", "ArrowLeft"], value: -1 },
{ inputs: ["KeyD", "ArrowRight"], value: 1 },
],
verticalAxis: [
{ inputs: ["KeyS", "ArrowDown"], value: -1 },
{ inputs: ["KeyW", "ArrowUp"], value: 1 },
],
},
discrete: {
jump: ["Space"],
sprint: ["ShiftLeft", "ShiftRight"],
},
},
}
) {
Expand All @@ -39,7 +48,7 @@ export default class CharacterController {
this.sensitivity = sensitivity;
this.lookLimit = lookLimit;
this.cameraFov = cameraFov;
this.inputs = inputs;
this.inputMappings = inputMappings;

this.player = new Group();
this.clock = new Clock();
Expand All @@ -52,7 +61,11 @@ export default class CharacterController {
this.camera.rotation.x = MathUtils.degToRad(90);
this.player.add(this.camera);

// A raw list of all the keys currently pressed. Internal use only.
this.keysDown = {};

// A processed list of inputs corresponding to the input mappings.
this.inputs = {};
this.mouse = { x: 0, y: 0 };

this.isGrounded;
Expand All @@ -65,59 +78,22 @@ export default class CharacterController {
this.floorDistance
);

document.addEventListener("keydown", (e) => {
this.keysDown[e.code] = true;
});
document.addEventListener("keyup", (e) => {
this.keysDown[e.code] = false;
});

this.cancelDriftTimeout;
window.addEventListener("mousemove", (e) => {
clearTimeout(this.cancelDriftTimeout);
this.mouse.x = e.movementX;
this.mouse.y = e.movementY;
this.cancelDriftTimeout = setTimeout(() => {
this.mouse.x = this.mouse.y = 0;
}, 10);
});
InputUtils.registerMouseMoveEvent.call(this);

this.clock.start();
}
InputUtils.registerKeyEvents.call(this);

get horizontalAxis() {
let res = 0;
this.inputs.left.forEach((key) => {
if (this.keysDown[key]) res = -1;
});
this.inputs.right.forEach((key) => {
if (this.keysDown[key]) res = 1;
});
return res;
}
get verticalAxis() {
let res = 0;
this.inputs.forwards.forEach((key) => {
if (this.keysDown[key]) res = 1;
});
this.inputs.backwards.forEach((key) => {
if (this.keysDown[key]) res = -1;
});
return res;
}
get sprintKeyPressed() {
let res = false;
this.inputs.sprint.forEach((key) => {
if (this.keysDown[key]) res = true;
});
return res;
this.clock.start();
}

update() {
const clock = this.clock;
const elapsed = this.clock.elapsedTime;
const delta = clock.getDelta();

// Update the player's currently activated inputs for this frame.
InputUtils.checkInputs.call(this);

// Cast a ray straight down from the player's position.
this.raycaster.set(this.player.position, new Vector3(0, 0, -1));

Expand Down
36 changes: 36 additions & 0 deletions src/inputUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
export function registerKeyEvents() {
document.addEventListener("keydown", (e) => {
this.keysDown[e.code] = true;
});
document.addEventListener("keyup", (e) => {
this.keysDown[e.code] = false;
});
}

export function registerMouseMoveEvent() {
window.addEventListener("mousemove", (e) => {
clearTimeout(this.cancelDriftTimeout);
this.mouse.x = e.movementX;
this.mouse.y = e.movementY;
this.cancelDriftTimeout = setTimeout(() => {
this.mouse.x = this.mouse.y = 0;
}, 10);
});
}

export function checkInputs() {
// Check scalar values
Object.entries(this.inputMappings.scalar).forEach(([axisName, axisInfo]) => {
this.inputs[axisName] = 0;
axisInfo.forEach((axisInput) => {
if (axisInput.inputs.some((code) => this.keysDown[code])) {
this.inputs[axisName] += axisInput.value;
}
});
});

// Check discrete values
Object.entries(this.inputMappings.discrete).forEach(([eventName, eventCodes]) => {
this.inputs[eventName] = eventCodes.some((code) => this.keysDown[code]);
});
}
Loading

0 comments on commit 2be7eee

Please sign in to comment.