hytopia 0.1.54 → 0.1.56
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/server.basecharactercontroller.attach.md +53 -0
- package/docs/server.basecharactercontroller.despawn.md +53 -0
- package/docs/server.basecharactercontroller.detach.md +53 -0
- package/docs/server.basecharactercontroller.md +91 -28
- package/docs/server.basecharactercontroller.onattach.md +13 -0
- package/docs/server.basecharactercontroller.ondespawn.md +13 -0
- package/docs/server.basecharactercontroller.ondetach.md +13 -0
- package/docs/server.basecharactercontroller.onspawn.md +13 -0
- package/docs/server.basecharactercontroller.ontick.md +2 -2
- package/docs/server.basecharactercontroller.ontickwithplayerinput.md +2 -2
- package/docs/server.basecharactercontroller.spawn.md +53 -0
- package/docs/server.basecharactercontroller.tick.md +15 -1
- package/docs/server.basecharactercontroller.tickwithplayerinput.md +17 -1
- package/docs/server.collider.bounciness.md +13 -0
- package/docs/server.collider.bouncinesscombinerule.md +13 -0
- package/docs/server.collider.collisiongroups.md +13 -0
- package/docs/{server.collider.getfriction.md → server.collider.friction.md} +4 -10
- package/docs/server.collider.frictioncombinerule.md +13 -0
- package/docs/server.collider.md +112 -63
- package/docs/server.collider.relativeposition.md +13 -0
- package/docs/server.collider.relativerotation.md +13 -0
- package/docs/{server.collider.setrelativetranslation.md → server.collider.setrelativeposition.md} +6 -6
- package/docs/server.collideroptions.md +6 -6
- package/docs/server.collideroptions.relativeposition.md +13 -0
- package/docs/server.defaultcharactercontroller._constructor_.md +1 -17
- package/docs/server.defaultcharactercontroller.attach.md +53 -0
- package/docs/server.defaultcharactercontroller.md +18 -4
- package/docs/server.defaultcharactercontroller.spawn.md +53 -0
- package/docs/server.defaultcharactercontroller.tickwithplayerinput.md +17 -1
- package/docs/server.entity.md +0 -19
- package/docs/server.entity.setcharactercontroller.md +2 -2
- package/docs/server.entityeventpayload.md +2 -2
- package/docs/server.entityeventpayload.updateposition.entity.md +11 -0
- package/docs/{server.entityeventpayload.updatetranslation.md → server.entityeventpayload.updateposition.md} +5 -5
- package/docs/server.entityeventpayload.updateposition.position.md +11 -0
- package/docs/server.entityeventtype.md +4 -4
- package/docs/server.entityoptions.charactercontroller.md +13 -0
- package/docs/server.entityoptions.md +3 -3
- package/docs/server.md +1 -1
- package/docs/server.movecallback.md +2 -2
- package/docs/server.movecompletecallback.md +1 -1
- package/docs/server.rigidbody.additionalmass.md +13 -0
- package/docs/server.rigidbody.additionalsolveriterations.md +13 -0
- package/docs/server.rigidbody.angulardamping.md +13 -0
- package/docs/server.rigidbody.angularvelocity.md +13 -0
- package/docs/server.rigidbody.directionfromrotation.md +13 -0
- package/docs/server.rigidbody.dominancegroup.md +13 -0
- package/docs/server.rigidbody.effectiveangularinertia.md +13 -0
- package/docs/server.rigidbody.effectiveinversemass.md +13 -0
- package/docs/server.rigidbody.effectiveworldinverseprincipalangularinertiasqrt.md +13 -0
- package/docs/server.rigidbody.enabledpositions.md +13 -0
- package/docs/server.rigidbody.enabledrotations.md +13 -0
- package/docs/server.rigidbody.gravityscale.md +13 -0
- package/docs/server.rigidbody.inversemass.md +13 -0
- package/docs/server.rigidbody.inverseprincipalangularinertiasqrt.md +13 -0
- package/docs/server.rigidbody.lineardamping.md +13 -0
- package/docs/server.rigidbody.linearvelocity.md +13 -0
- package/docs/server.rigidbody.localcenterofmass.md +13 -0
- package/docs/server.rigidbody.lockallpositions.md +17 -0
- package/docs/{server.rigidbody.getmass.md → server.rigidbody.mass.md} +4 -10
- package/docs/server.rigidbody.md +339 -150
- package/docs/server.rigidbody.nextkinematicposition.md +13 -0
- package/docs/server.rigidbody.nextkinematicrotation.md +13 -0
- package/docs/server.rigidbody.position.md +13 -0
- package/docs/server.rigidbody.principalangularinertia.md +13 -0
- package/docs/server.rigidbody.principalangularinertialocalframe.md +13 -0
- package/docs/server.rigidbody.rotation.md +13 -0
- package/docs/{server.rigidbody.setenabledtranslations.md → server.rigidbody.setenabledpositions.md} +6 -6
- package/docs/{server.rigidbody.setnextkinematictranslation.md → server.rigidbody.setnextkinematicposition.md} +6 -6
- package/docs/{server.rigidbody.settranslation.md → server.rigidbody.setposition.md} +6 -6
- package/docs/server.rigidbody.softccdprediction.md +13 -0
- package/docs/server.rigidbody.type.md +13 -0
- package/docs/server.rigidbody.worldcenterofmass.md +13 -0
- package/docs/server.rigidbodyoptions.enabledpositions.md +13 -0
- package/docs/server.rigidbodyoptions.md +19 -19
- package/docs/server.rigidbodyoptions.position.md +13 -0
- package/examples/block-entity/index.ts +3 -3
- package/examples/character-controller/MyCharacterController.ts +190 -119
- package/examples/character-controller/index.ts +5 -10
- package/examples/custom-ui/index.ts +2 -2
- package/examples/payload-game/index.ts +17 -18
- package/package.json +1 -1
- package/server.api.json +1461 -1203
- package/server.d.ts +181 -252
- package/server.js +85 -85
- package/docs/server.basecharactercontroller._constructor_.md +0 -65
- package/docs/server.basecharactercontroller.createcolliders.md +0 -19
- package/docs/server.basecharactercontroller.entity.md +0 -13
- package/docs/server.collider.getbounciness.md +0 -19
- package/docs/server.collider.getbouncinesscombinerule.md +0 -19
- package/docs/server.collider.getcollisiongroups.md +0 -19
- package/docs/server.collider.getfrictioncombinerule.md +0 -19
- package/docs/server.collider.getrelativerotation.md +0 -19
- package/docs/server.collider.getrelativetranslation.md +0 -19
- package/docs/server.collideroptions.relativetranslation.md +0 -13
- package/docs/server.defaultcharactercontroller.createcolliders.md +0 -19
- package/docs/server.entity.createcustomcharactercontroller.md +0 -13
- package/docs/server.entityeventpayload.updatetranslation.entity.md +0 -11
- package/docs/server.entityeventpayload.updatetranslation.translation.md +0 -11
- package/docs/server.entityoptions.createcustomcharactercontroller.md +0 -13
- package/docs/server.rigidbody.getadditionalmass.md +0 -19
- package/docs/server.rigidbody.getadditionalsolveriterations.md +0 -19
- package/docs/server.rigidbody.getangulardamping.md +0 -19
- package/docs/server.rigidbody.getangularvelocity.md +0 -19
- package/docs/server.rigidbody.getdirectionfromrotation.md +0 -19
- package/docs/server.rigidbody.getdominancegroup.md +0 -19
- package/docs/server.rigidbody.geteffectiveangularinertia.md +0 -19
- package/docs/server.rigidbody.geteffectiveinversemass.md +0 -19
- package/docs/server.rigidbody.geteffectiveworldinverseprincipalangularinertiasqrt.md +0 -19
- package/docs/server.rigidbody.getenabledrotations.md +0 -19
- package/docs/server.rigidbody.getenabledtranslations.md +0 -19
- package/docs/server.rigidbody.getgravityscale.md +0 -19
- package/docs/server.rigidbody.getinversemass.md +0 -19
- package/docs/server.rigidbody.getinverseprincipalangularinertiasqrt.md +0 -19
- package/docs/server.rigidbody.getlineardamping.md +0 -19
- package/docs/server.rigidbody.getlinearvelocity.md +0 -19
- package/docs/server.rigidbody.getlocalcenterofmass.md +0 -19
- package/docs/server.rigidbody.getnextkinematicrotation.md +0 -19
- package/docs/server.rigidbody.getnextkinematictranslation.md +0 -19
- package/docs/server.rigidbody.getprincipalangularinertia.md +0 -19
- package/docs/server.rigidbody.getprincipalangularinertialocalframe.md +0 -19
- package/docs/server.rigidbody.getrotation.md +0 -19
- package/docs/server.rigidbody.getsoftccdprediction.md +0 -19
- package/docs/server.rigidbody.gettranslation.md +0 -19
- package/docs/server.rigidbody.gettype.md +0 -19
- package/docs/server.rigidbody.getworldcenterofmass.md +0 -19
- package/docs/server.rigidbody.lockalltranslations.md +0 -17
- package/docs/server.rigidbodyoptions.enabledtranslations.md +0 -13
- package/docs/server.rigidbodyoptions.translation.md +0 -13
@@ -1,41 +1,102 @@
|
|
1
1
|
import {
|
2
2
|
Audio,
|
3
3
|
BaseCharacterController,
|
4
|
-
CollisionGroup,
|
5
|
-
Collider,
|
6
|
-
Entity,
|
7
4
|
ColliderShape,
|
8
5
|
CoefficientCombineRule,
|
6
|
+
CollisionGroup,
|
7
|
+
Entity,
|
8
|
+
PlayerEntity,
|
9
9
|
BlockType,
|
10
10
|
} from 'hytopia';
|
11
11
|
|
12
12
|
import type {
|
13
13
|
PlayerInput,
|
14
14
|
PlayerCameraOrientation,
|
15
|
-
Vector3,
|
16
15
|
} from 'hytopia';
|
17
16
|
|
17
|
+
/** Options for creating a MyCharacterController instance. @public */
|
18
|
+
export interface MyCharacterControllerOptions {
|
19
|
+
/** The upward velocity applied to the entity when it jumps. */
|
20
|
+
jumpVelocity?: number;
|
21
|
+
|
22
|
+
/** The normalized horizontal velocity applied to the entity when it runs. */
|
23
|
+
runVelocity?: number;
|
24
|
+
|
25
|
+
/** The normalized horizontal velocity applied to the entity when it walks. */
|
26
|
+
walkVelocity?: number;
|
27
|
+
|
28
|
+
/** A function allowing custom logic to determine if the entity can jump. */
|
29
|
+
canJump?: () => boolean;
|
30
|
+
|
31
|
+
/** A function allowing custom logic to determine if the entity can walk. */
|
32
|
+
canWalk?: () => boolean;
|
33
|
+
|
34
|
+
/** A function allowing custom logic to determine if the entity can run. */
|
35
|
+
canRun?: () => boolean;
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* A custom character controller implementation.
|
40
|
+
*
|
41
|
+
* @remarks
|
42
|
+
* This class extends {@link BaseCharacterController}
|
43
|
+
* and implements the default movement logic for a
|
44
|
+
* character entity.
|
45
|
+
*
|
46
|
+
* @public
|
47
|
+
*/
|
18
48
|
export default class MyCharacterController extends BaseCharacterController {
|
49
|
+
/** The upward velocity applied to the entity when it jumps. */
|
19
50
|
public jumpVelocity: number = 10;
|
51
|
+
|
52
|
+
/** The normalized horizontal velocity applied to the entity when it runs. */
|
20
53
|
public runVelocity: number = 8;
|
54
|
+
|
55
|
+
/** The normalized horizontal velocity applied to the entity when it walks. */
|
21
56
|
public walkVelocity: number = 4;
|
22
57
|
|
23
|
-
|
24
|
-
|
25
|
-
|
58
|
+
/**
|
59
|
+
* A function allowing custom logic to determine if the entity can walk.
|
60
|
+
* @param myCharacterController - The character controller instance.
|
61
|
+
* @returns Whether the entity of the character controller can walk.
|
62
|
+
*/
|
63
|
+
public canWalk: (myCharacterController: MyCharacterController) => boolean = () => true;
|
26
64
|
|
27
|
-
|
28
|
-
|
65
|
+
/**
|
66
|
+
* A function allowing custom logic to determine if the entity can run.
|
67
|
+
* @param myCharacterController - The character controller instance.
|
68
|
+
* @returns Whether the entity of the character controller can run.
|
69
|
+
*/
|
70
|
+
public canRun: (myCharacterController: MyCharacterController) => boolean = () => true;
|
29
71
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
72
|
+
/**
|
73
|
+
* A function allowing custom logic to determine if the entity can jump.
|
74
|
+
* @param myCharacterController - The character controller instance.
|
75
|
+
* @returns Whether the entity of the character controller can jump.
|
76
|
+
*/
|
77
|
+
public canJump: (myCharacterController: MyCharacterController) => boolean = () => true;
|
78
|
+
|
79
|
+
/** @internal */
|
80
|
+
private _stepAudio: Audio | undefined;
|
81
|
+
|
82
|
+
/** @internal */
|
83
|
+
private _groundContactCount: number = 0;
|
84
|
+
|
85
|
+
/** @internal */
|
86
|
+
private _platform: Entity | undefined;
|
37
87
|
|
38
|
-
|
88
|
+
/**
|
89
|
+
* @param options - Options for the controller.
|
90
|
+
*/
|
91
|
+
public constructor(options: MyCharacterControllerOptions = {}) {
|
92
|
+
super();
|
93
|
+
|
94
|
+
this.jumpVelocity = options.jumpVelocity ?? this.jumpVelocity;
|
95
|
+
this.runVelocity = options.runVelocity ?? this.runVelocity;
|
96
|
+
this.walkVelocity = options.walkVelocity ?? this.walkVelocity;
|
97
|
+
this.canWalk = options.canWalk ?? this.canWalk;
|
98
|
+
this.canRun = options.canRun ?? this.canRun;
|
99
|
+
this.canJump = options.canJump ?? this.canJump;
|
39
100
|
}
|
40
101
|
|
41
102
|
/** Whether the entity is grounded. */
|
@@ -48,41 +109,51 @@ export default class MyCharacterController extends BaseCharacterController {
|
|
48
109
|
public get platform(): Entity | undefined { return this._platform; }
|
49
110
|
|
50
111
|
/**
|
51
|
-
*
|
112
|
+
* Called when the controller is attached to an entity.
|
113
|
+
* @param entity - The entity to attach the controller to.
|
52
114
|
*/
|
53
|
-
public
|
54
|
-
|
55
|
-
|
56
|
-
|
115
|
+
public attach(entity: Entity) {
|
116
|
+
this._stepAudio = new Audio({
|
117
|
+
uri: 'audio/sfx/step.wav',
|
118
|
+
loop: true,
|
119
|
+
volume: 0.1,
|
120
|
+
attachedToEntity: entity,
|
121
|
+
});
|
122
|
+
|
123
|
+
entity.lockAllRotations(); // prevent physics from applying rotation to the entity, we can still explicitly set it.
|
124
|
+
};
|
57
125
|
|
58
|
-
|
126
|
+
/**
|
127
|
+
* Called when the controlled entity is spawned.
|
128
|
+
* In MyCharacterController, this function is used to create
|
129
|
+
* the colliders for the entity for wall and ground detection.
|
130
|
+
* @param entity - The entity that is spawned.
|
131
|
+
*/
|
132
|
+
public spawn(entity: Entity) {
|
133
|
+
if (!entity.isSpawned) {
|
134
|
+
throw new Error('CharacterController.createColliders(): Entity is not spawned!');
|
135
|
+
}
|
59
136
|
|
60
|
-
|
61
|
-
|
62
|
-
* It assumes a cylinder shape and is positioned manually
|
63
|
-
* relative to the default entity rigid body as defined
|
64
|
-
* by the DEFAULT_ENTITY_RIGID_BODY_OPTIONS constant of
|
65
|
-
* the hytopia package.
|
66
|
-
*/
|
67
|
-
colliders.push(new Collider({
|
137
|
+
// Ground sensor
|
138
|
+
entity.createAndAddChildColliderToSimulation({
|
68
139
|
shape: ColliderShape.CYLINDER,
|
69
|
-
radius: 0.
|
140
|
+
radius: 0.23,
|
70
141
|
halfHeight: 0.125,
|
71
142
|
collisionGroups: {
|
72
143
|
belongsTo: [ CollisionGroup.ENTITY_SENSOR ],
|
73
144
|
collidesWith: [ CollisionGroup.BLOCK, CollisionGroup.ENTITY ],
|
74
145
|
},
|
75
146
|
isSensor: true,
|
76
|
-
|
147
|
+
relativePosition: { x: 0, y: -0.75, z: 0 },
|
77
148
|
tag: 'groundSensor',
|
78
149
|
onCollision: (_other: BlockType | Entity, started: boolean) => {
|
79
150
|
// Ground contact
|
80
151
|
this._groundContactCount += started ? 1 : -1;
|
81
152
|
|
82
|
-
if (!this._groundContactCount) {
|
83
|
-
|
153
|
+
if (!this._groundContactCount) {
|
154
|
+
entity.startModelOneshotAnimations([ 'jump_loop' ]);
|
84
155
|
} else {
|
85
|
-
|
156
|
+
entity.stopModelAnimations([ 'jump_loop' ]);
|
86
157
|
}
|
87
158
|
|
88
159
|
// Platform contact
|
@@ -94,15 +165,11 @@ export default class MyCharacterController extends BaseCharacterController {
|
|
94
165
|
this._platform = undefined;
|
95
166
|
}
|
96
167
|
},
|
97
|
-
})
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
* sticking and friction to blocks as a player moves, creating
|
103
|
-
* a smooth slide effect on walls that we jump into, etc.
|
104
|
-
*/
|
105
|
-
colliders.push(new Collider({
|
168
|
+
});
|
169
|
+
|
170
|
+
|
171
|
+
// Wall collider
|
172
|
+
entity.createAndAddChildColliderToSimulation({
|
106
173
|
shape: ColliderShape.CAPSULE,
|
107
174
|
halfHeight: 0.30,
|
108
175
|
radius: 0.37,
|
@@ -113,101 +180,109 @@ export default class MyCharacterController extends BaseCharacterController {
|
|
113
180
|
friction: 0,
|
114
181
|
frictionCombineRule: CoefficientCombineRule.Min,
|
115
182
|
tag: 'wallCollider',
|
116
|
-
})
|
117
|
-
|
118
|
-
return colliders;
|
119
|
-
}
|
183
|
+
});
|
184
|
+
};
|
120
185
|
|
121
186
|
/**
|
122
|
-
*
|
123
|
-
*
|
124
|
-
*
|
187
|
+
* Ticks the player movement for the character controller,
|
188
|
+
* overriding the default implementation.
|
189
|
+
*
|
190
|
+
* @param entity - The entity to tick.
|
191
|
+
* @param input - The current input state of the player.
|
192
|
+
* @param cameraOrientation - The current camera orientation state of the player.
|
193
|
+
* @param deltaTimeMs - The delta time in milliseconds since the last tick.
|
125
194
|
*/
|
126
|
-
public tickWithPlayerInput(input: PlayerInput, cameraOrientation: PlayerCameraOrientation, deltaTimeMs: number) {
|
127
|
-
if (!
|
195
|
+
public tickWithPlayerInput(entity: PlayerEntity, input: PlayerInput, cameraOrientation: PlayerCameraOrientation, deltaTimeMs: number) {
|
196
|
+
if (!entity.isSpawned || !entity.world) return;
|
128
197
|
|
129
|
-
super.tickWithPlayerInput(input, cameraOrientation, deltaTimeMs);
|
198
|
+
super.tickWithPlayerInput(entity, input, cameraOrientation, deltaTimeMs);
|
130
199
|
|
131
|
-
const { w, a, s, d, sp, sh, ml
|
132
|
-
const { yaw } = cameraOrientation;
|
133
|
-
const currentVelocity =
|
200
|
+
const { w, a, s, d, sp, sh, ml } = input;
|
201
|
+
const { yaw } = cameraOrientation;
|
202
|
+
const currentVelocity = entity.linearVelocity;
|
134
203
|
const targetVelocities = { x: 0, y: 0, z: 0 };
|
135
204
|
const isRunning = sh;
|
136
205
|
|
137
|
-
//
|
138
|
-
if (w || a || s || d) {
|
206
|
+
// Temporary, animations
|
207
|
+
if (this.isGrounded && (w || a || s || d)) {
|
139
208
|
if (isRunning) {
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
this.entity.startModelLoopedAnimations([ 'run' ]);
|
144
|
-
// Manually set a playback rate of our step audio to audibly sync to our walk speed.
|
145
|
-
this._stepAudio.setPlaybackRate(0.83);
|
209
|
+
entity.stopModelAnimations(Array.from(entity.modelLoopedAnimations).filter(v => v !== 'run'));
|
210
|
+
entity.startModelLoopedAnimations([ 'run' ]);
|
211
|
+
this._stepAudio?.setPlaybackRate(0.83);
|
146
212
|
} else {
|
147
|
-
|
148
|
-
|
149
|
-
this._stepAudio
|
213
|
+
entity.stopModelAnimations(Array.from(entity.modelLoopedAnimations).filter(v => v !== 'walk'));
|
214
|
+
entity.startModelLoopedAnimations([ 'walk' ]);
|
215
|
+
this._stepAudio?.setPlaybackRate(0.5);
|
150
216
|
}
|
151
217
|
|
152
|
-
this._stepAudio
|
218
|
+
this._stepAudio?.play(entity.world, !this._stepAudio?.isPlaying);
|
153
219
|
} else {
|
154
|
-
this._stepAudio
|
155
|
-
|
156
|
-
|
220
|
+
this._stepAudio?.pause();
|
221
|
+
entity.stopModelAnimations(Array.from(entity.modelLoopedAnimations).filter(v => v !== 'idle'));
|
222
|
+
entity.startModelLoopedAnimations([ 'idle' ]);
|
157
223
|
}
|
158
224
|
|
159
|
-
// Play a simple interact animation on left mouse click then clear the input.
|
160
225
|
if (ml) {
|
161
|
-
|
162
|
-
|
163
|
-
|
226
|
+
entity.startModelOneshotAnimations([ 'simple_interact' ]);
|
227
|
+
|
228
|
+
// break a block
|
229
|
+
const ray = entity.world.simulation.raycast(
|
230
|
+
entity.position,
|
231
|
+
entity.player.camera.facingDirection,
|
232
|
+
10,
|
233
|
+
{ filterExcludeRigidBody: entity.rawRigidBody },
|
234
|
+
);
|
235
|
+
|
236
|
+
if (ray?.hitBlock) {
|
237
|
+
// Remove the block
|
238
|
+
entity.world.chunkLattice.setBlock(ray.hitBlock.globalCoordinate, 0);
|
239
|
+
}
|
164
240
|
|
165
|
-
|
166
|
-
if (mr) {
|
167
|
-
targetVelocities.y = 20;
|
168
|
-
input.mr = false;
|
241
|
+
input.ml = false;
|
169
242
|
}
|
170
243
|
|
171
244
|
// Calculate target horizontal velocities (run/walk)
|
172
|
-
|
245
|
+
if ((isRunning && this.canRun(this)) || (!isRunning && this.canWalk(this))) {
|
246
|
+
const velocity = isRunning ? this.runVelocity : this.walkVelocity;
|
173
247
|
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
248
|
+
if (w) {
|
249
|
+
targetVelocities.x -= velocity * Math.sin(yaw);
|
250
|
+
targetVelocities.z -= velocity * Math.cos(yaw);
|
251
|
+
}
|
252
|
+
|
253
|
+
if (s) {
|
254
|
+
targetVelocities.x += velocity * Math.sin(yaw);
|
255
|
+
targetVelocities.z += velocity * Math.cos(yaw);
|
256
|
+
}
|
257
|
+
|
258
|
+
if (a) {
|
259
|
+
targetVelocities.x -= velocity * Math.cos(yaw);
|
260
|
+
targetVelocities.z += velocity * Math.sin(yaw);
|
261
|
+
}
|
262
|
+
|
263
|
+
if (d) {
|
264
|
+
targetVelocities.x += velocity * Math.cos(yaw);
|
265
|
+
targetVelocities.z -= velocity * Math.sin(yaw);
|
266
|
+
}
|
193
267
|
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
268
|
+
// Normalize for diagonals
|
269
|
+
const length = Math.sqrt(targetVelocities.x * targetVelocities.x + targetVelocities.z * targetVelocities.z);
|
270
|
+
if (length > velocity) {
|
271
|
+
const factor = velocity / length;
|
272
|
+
targetVelocities.x *= factor;
|
273
|
+
targetVelocities.z *= factor;
|
274
|
+
}
|
200
275
|
}
|
201
276
|
|
202
277
|
// Calculate target vertical velocity (jump)
|
203
|
-
if (sp) {
|
204
|
-
if (this.isGrounded && currentVelocity.y <= 3) {
|
278
|
+
if (sp && this.canJump(this)) {
|
279
|
+
if (this.isGrounded && currentVelocity.y > -0.001 && currentVelocity.y <= 3) {
|
205
280
|
targetVelocities.y = this.jumpVelocity;
|
206
281
|
}
|
207
282
|
}
|
208
283
|
|
209
284
|
// Apply impulse relative to target velocities, taking platform velocity into account
|
210
|
-
const platformVelocity = this._platform ? this._platform.
|
285
|
+
const platformVelocity = this._platform ? this._platform.linearVelocity : { x: 0, y: 0, z: 0 };
|
211
286
|
const deltaVelocities = {
|
212
287
|
x: targetVelocities.x - currentVelocity.x + platformVelocity.x,
|
213
288
|
y: targetVelocities.y + platformVelocity.y,
|
@@ -219,11 +294,11 @@ export default class MyCharacterController extends BaseCharacterController {
|
|
219
294
|
Math.abs(currentVelocity.y) > this.jumpVelocity ||
|
220
295
|
Math.abs(currentVelocity.z) > this.runVelocity;
|
221
296
|
|
222
|
-
if (!hasExternalVelocity) { // allow external velocities
|
297
|
+
if (!hasExternalVelocity) { // allow external velocities to resolve, otherwise our deltas will cancel them out.
|
223
298
|
if (Object.values(deltaVelocities).some(v => v !== 0)) {
|
224
|
-
const mass =
|
299
|
+
const mass = entity.mass;
|
225
300
|
|
226
|
-
|
301
|
+
entity.applyImpulse({ // multiply by mass for the impulse to result in applying the correct target velocity
|
227
302
|
x: deltaVelocities.x * mass,
|
228
303
|
y: deltaVelocities.y * mass,
|
229
304
|
z: deltaVelocities.z * mass,
|
@@ -231,11 +306,11 @@ export default class MyCharacterController extends BaseCharacterController {
|
|
231
306
|
}
|
232
307
|
}
|
233
308
|
|
234
|
-
// Apply rotation
|
309
|
+
// Apply rotation
|
235
310
|
if (yaw !== undefined) {
|
236
311
|
const halfYaw = yaw / 2;
|
237
312
|
|
238
|
-
|
313
|
+
entity.setRotation({
|
239
314
|
x: 0,
|
240
315
|
y: Math.fround(Math.sin(halfYaw)),
|
241
316
|
z: 0,
|
@@ -243,8 +318,4 @@ export default class MyCharacterController extends BaseCharacterController {
|
|
243
318
|
});
|
244
319
|
}
|
245
320
|
}
|
246
|
-
|
247
|
-
public tickPathfindingMovement(_destination: Vector3, _deltaTimeMs: number) {
|
248
|
-
console.log('Non-player pathfinding not implemented!');
|
249
|
-
}
|
250
321
|
}
|
@@ -11,6 +11,10 @@ startServer(world => {
|
|
11
11
|
// Uncomment this to visualize physics vertices, will cause noticable lag.
|
12
12
|
// world.simulation.enableDebugRendering(true);
|
13
13
|
|
14
|
+
// Visualize raycasts, like block breaking for our
|
15
|
+
// character controller.
|
16
|
+
world.simulation.enableDebugRaycasting(true);
|
17
|
+
|
14
18
|
world.loadMap(worldMap);
|
15
19
|
|
16
20
|
world.onPlayerJoin = player => {
|
@@ -20,18 +24,9 @@ startServer(world => {
|
|
20
24
|
modelUri: 'models/player.gltf',
|
21
25
|
modelLoopedAnimations: [ 'idle' ],
|
22
26
|
modelScale: 0.5,
|
27
|
+
characterController: new MyCharacterController(), // attach our character controller
|
23
28
|
});
|
24
29
|
|
25
|
-
// Assign a custom character controller factory to the player entity.
|
26
|
-
// This must be assigned before spawning the entity.
|
27
|
-
// createCustomCharacterController if set will be handled internally when
|
28
|
-
// .spawn() is called.
|
29
|
-
playerEntity.createCustomCharacterController = () => {
|
30
|
-
console.log('Creating custom player entity character controller...');
|
31
|
-
|
32
|
-
return new MyCharacterController(playerEntity);
|
33
|
-
};
|
34
|
-
|
35
30
|
playerEntity.spawn(world, { x: 0, y: 10, z: 0 });
|
36
31
|
console.log('Spawned player entity!');
|
37
32
|
|
@@ -45,7 +45,7 @@ startServer(world => {
|
|
45
45
|
const randomY = Math.random() * 13 + 2; // Random between 2 and 15
|
46
46
|
const randomZ = Math.random() * 40 - 20; // Random between -20 and 20
|
47
47
|
|
48
|
-
playerEntity.
|
48
|
+
playerEntity.setPosition({ x: randomX, y: randomY, z: randomZ });
|
49
49
|
}
|
50
50
|
};
|
51
51
|
};
|
@@ -75,7 +75,7 @@ function updatePlayerList() {
|
|
75
75
|
// For each player, return their username and current position
|
76
76
|
return {
|
77
77
|
username: player.username,
|
78
|
-
position: entity.
|
78
|
+
position: entity.position, // Gets x,y,z coordinate
|
79
79
|
};
|
80
80
|
});
|
81
81
|
|
@@ -151,7 +151,7 @@ startServer(world => { // Perform our game setup logic in the startServer init c
|
|
151
151
|
// physics engine we use where entities despawned to not trigger a collision
|
152
152
|
// event for leaving a sensor. This is a workaround till a better solution is found.
|
153
153
|
world.entityManager.getAllPlayerEntities(player).forEach(entity => {
|
154
|
-
entity.
|
154
|
+
entity.setPosition({ x: 0, y: 100, z: 0 });
|
155
155
|
setTimeout(() => entity.despawn(), 50); // Despawn after a short delay so we step the physics after translating it so leaving the sensor registers.
|
156
156
|
});
|
157
157
|
|
@@ -254,8 +254,8 @@ function spawnBullet(world: World, coordinate: Vector3Like, direction: Vector3Li
|
|
254
254
|
// Apply knockback, the knockback effect is less if the spider is larger, and more if it is smaller
|
255
255
|
// because of how the physics simulation applies forces relative to automatically calculated mass from the spider's
|
256
256
|
// size
|
257
|
-
const bulletDirection = bullet.
|
258
|
-
const mass = otherEntity.
|
257
|
+
const bulletDirection = bullet.directionFromRotation;
|
258
|
+
const mass = otherEntity.mass;
|
259
259
|
const knockback = 14 * mass;
|
260
260
|
|
261
261
|
otherEntity.applyImpulse({
|
@@ -266,7 +266,7 @@ function spawnBullet(world: World, coordinate: Vector3Like, direction: Vector3Li
|
|
266
266
|
|
267
267
|
if (enemyHealth[otherEntity.id!] <= 0) {
|
268
268
|
// YEET the spider before despawning it so it registers leaving the sensor
|
269
|
-
otherEntity.
|
269
|
+
otherEntity.setPosition({ x: 0, y: 100, z: 0 });
|
270
270
|
setTimeout(() => { otherEntity.despawn(); }, 50); // Despawn after a short delay so we step the physics after translating it so leaving the sensor registers.
|
271
271
|
}
|
272
272
|
|
@@ -293,7 +293,7 @@ function spawnPayloadEntity(world: World) {
|
|
293
293
|
}
|
294
294
|
|
295
295
|
payloadEntity = new Entity({
|
296
|
-
|
296
|
+
characterController: new SimpleCharacterController(),
|
297
297
|
name: 'Payload',
|
298
298
|
modelUri: 'models/payload.gltf',
|
299
299
|
modelScale: 0.7,
|
@@ -350,7 +350,7 @@ function spawnSpider(world: World, coordinate: Vector3Like) {
|
|
350
350
|
const targetPlayers = new Set<PlayerEntity>();
|
351
351
|
|
352
352
|
const spider = new Entity({
|
353
|
-
|
353
|
+
characterController: new SimpleCharacterController(),
|
354
354
|
name: 'Spider',
|
355
355
|
modelUri: 'models/spider.gltf',
|
356
356
|
modelLoopedAnimations: [ 'walk' ],
|
@@ -399,7 +399,7 @@ function spawnSpider(world: World, coordinate: Vector3Like) {
|
|
399
399
|
|
400
400
|
spider.onEntityCollision = (spider: Entity, entity: Entity, started: boolean) => { // If the spider hits a player, deal damage and apply knockback
|
401
401
|
if (started && entity instanceof PlayerEntity && entity.isSpawned) {
|
402
|
-
const spiderDirection = spider.
|
402
|
+
const spiderDirection = spider.directionFromRotation;
|
403
403
|
const knockback = 4 * randomScaleMultiplier;
|
404
404
|
|
405
405
|
entity.applyImpulse({
|
@@ -466,19 +466,19 @@ function onTickPathfindEnemy(entity: Entity, targetPlayers: Set<PlayerEntity>, s
|
|
466
466
|
const targetPlayer = targetPlayers.values().next().value as PlayerEntity | undefined;
|
467
467
|
|
468
468
|
enemyPathfindingTargets[entityId] = targetPlayer?.isSpawned
|
469
|
-
? targetPlayer.
|
470
|
-
: payloadEntity.
|
469
|
+
? targetPlayer.position
|
470
|
+
: payloadEntity.position;
|
471
471
|
|
472
472
|
enemyPathfindAccumulators[entityId] -= PATHFIND_ACCUMULATOR_THRESHOLD;
|
473
473
|
|
474
474
|
// Make the spider jump if its close to the target player
|
475
|
-
const currentPosition = entity.
|
475
|
+
const currentPosition = entity.position;
|
476
476
|
const dx = enemyPathfindingTargets[entityId].x - currentPosition.x;
|
477
477
|
const dz = enemyPathfindingTargets[entityId].z - currentPosition.z;
|
478
478
|
const distance = Math.sqrt(dx * dx + dz * dz);
|
479
479
|
|
480
480
|
if (distance < 10) {
|
481
|
-
const mass = entity.
|
481
|
+
const mass = entity.mass;
|
482
482
|
entity.applyImpulse({ x: 0, y: (10 * Math.random() + 5) * mass, z: 0 });
|
483
483
|
}
|
484
484
|
|
@@ -495,13 +495,12 @@ function onTickPathfindEnemy(entity: Entity, targetPlayers: Set<PlayerEntity>, s
|
|
495
495
|
enemyPathfindAccumulators[entityId]++;
|
496
496
|
}
|
497
497
|
|
498
|
-
function onTickWithPlayerInput(this: DefaultCharacterController, input: PlayerInput, cameraOrientation: PlayerCameraOrientation, _deltaTimeMs: number) {
|
499
|
-
if (!
|
498
|
+
function onTickWithPlayerInput(this: DefaultCharacterController, entity: PlayerEntity, input: PlayerInput, cameraOrientation: PlayerCameraOrientation, _deltaTimeMs: number) {
|
499
|
+
if (!entity.world) return;
|
500
500
|
|
501
501
|
if (input.ml) {
|
502
|
-
const world =
|
503
|
-
const
|
504
|
-
const direction = Vector3.fromVector3Like(entity.getDirectionFromRotation());
|
502
|
+
const world = entity.world;
|
503
|
+
const direction = Vector3.fromVector3Like(entity.directionFromRotation);
|
505
504
|
|
506
505
|
direction.y = Math.sin(cameraOrientation.pitch);
|
507
506
|
|
@@ -513,10 +512,10 @@ function onTickWithPlayerInput(this: DefaultCharacterController, input: PlayerIn
|
|
513
512
|
// Normalize the direction vector to unit length
|
514
513
|
direction.normalize();
|
515
514
|
|
516
|
-
|
515
|
+
entity.startModelOneshotAnimations([ 'shoot' ]);
|
517
516
|
|
518
517
|
// Adjust bullet origin roughly for camera offset so crosshair is accurate
|
519
|
-
const bulletOrigin = entity.
|
518
|
+
const bulletOrigin = entity.position;
|
520
519
|
bulletOrigin.y += 0.65;
|
521
520
|
|
522
521
|
const bullet = spawnBullet(world, bulletOrigin, direction);
|