day 4
This commit is contained in:
@@ -3,7 +3,7 @@ import { ConfigUiParamsCategories } from "@24tools/ads_common";
|
|||||||
export const globalSettings: ConfigUiParamsCategories[] = [
|
export const globalSettings: ConfigUiParamsCategories[] = [
|
||||||
{
|
{
|
||||||
id: "global",
|
id: "global",
|
||||||
name: "Scene settings",
|
name: "Global settings",
|
||||||
params: [
|
params: [
|
||||||
{
|
{
|
||||||
id: "light_intensity",
|
id: "light_intensity",
|
||||||
@@ -30,7 +30,7 @@ export const globalSettings: ConfigUiParamsCategories[] = [
|
|||||||
values: [
|
values: [
|
||||||
30,
|
30,
|
||||||
150,
|
150,
|
||||||
60
|
50
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -43,17 +43,17 @@ export const globalSettings: ConfigUiParamsCategories[] = [
|
|||||||
[
|
[
|
||||||
-10,
|
-10,
|
||||||
10,
|
10,
|
||||||
0
|
6
|
||||||
|
],
|
||||||
|
[
|
||||||
|
0,
|
||||||
|
8,
|
||||||
|
9
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
-10,
|
-10,
|
||||||
10,
|
10,
|
||||||
1
|
7
|
||||||
],
|
|
||||||
[
|
|
||||||
-10,
|
|
||||||
10,
|
|
||||||
5
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -67,7 +67,7 @@ export const globalSettings: ConfigUiParamsCategories[] = [
|
|||||||
[
|
[
|
||||||
-360,
|
-360,
|
||||||
360,
|
360,
|
||||||
0
|
-5
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
-360,
|
-360,
|
||||||
@@ -88,7 +88,7 @@ export const globalSettings: ConfigUiParamsCategories[] = [
|
|||||||
values: [
|
values: [
|
||||||
30,
|
30,
|
||||||
150,
|
150,
|
||||||
60
|
55
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -101,17 +101,17 @@ export const globalSettings: ConfigUiParamsCategories[] = [
|
|||||||
[
|
[
|
||||||
-10,
|
-10,
|
||||||
10,
|
10,
|
||||||
0
|
2
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
-10,
|
0,
|
||||||
10,
|
8,
|
||||||
1
|
|
||||||
],
|
|
||||||
[
|
|
||||||
-10,
|
|
||||||
10,
|
|
||||||
5
|
5
|
||||||
|
],
|
||||||
|
[
|
||||||
|
-10,
|
||||||
|
10,
|
||||||
|
3
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,20 +1,16 @@
|
|||||||
import { CameraC_internal, Helper, Template } from "@24tools/playable_template";
|
import { CameraC_internal, Helper, Template } from "@24tools/playable_template";
|
||||||
import { PerspectiveCamera, Vector3 } from "three";
|
import { PerspectiveCamera } from "three";
|
||||||
|
|
||||||
export class CameraC extends CameraC_internal {
|
export class CameraC extends CameraC_internal {
|
||||||
static setCamera(portraitOrientation: boolean) {
|
static setCamera(portraitOrientation: boolean) {
|
||||||
const CATEGORY = Template.getCategory("global");
|
const CATEGORY = Template.getCategory("global");
|
||||||
if (this.camera !== null) {
|
if (this.camera !== null) {
|
||||||
let position = portraitOrientation
|
|
||||||
? Helper.returnVectorCamera(CATEGORY["camera_position_p"] as number[])
|
|
||||||
: Helper.returnVectorCamera(CATEGORY["camera_position_l"] as number[]);
|
|
||||||
const rotation = portraitOrientation
|
const rotation = portraitOrientation
|
||||||
? Helper.returnEulerCamera(CATEGORY["camera_rotation_p"] as number[])
|
? Helper.returnEulerCamera(CATEGORY["camera_rotation_p"] as number[])
|
||||||
: Helper.returnEulerCamera(CATEGORY["camera_rotation_l"] as number[]);
|
: Helper.returnEulerCamera(CATEGORY["camera_rotation_l"] as number[]);
|
||||||
this.camera.rotation.x = rotation.x;
|
this.camera.rotation.x = rotation.x;
|
||||||
this.camera.rotation.y = rotation.y;
|
this.camera.rotation.y = rotation.y;
|
||||||
this.camera.rotation.z = rotation.z;
|
this.camera.rotation.z = rotation.z;
|
||||||
this.camera.position.copy(position.clone());
|
|
||||||
if (this.camera instanceof PerspectiveCamera) {
|
if (this.camera instanceof PerspectiveCamera) {
|
||||||
this.camera.fov = portraitOrientation
|
this.camera.fov = portraitOrientation
|
||||||
? Number(CATEGORY["camera_fov_p"])
|
? Number(CATEGORY["camera_fov_p"])
|
||||||
@@ -23,16 +19,4 @@ export class CameraC extends CameraC_internal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static setTopDownCamera() {
|
|
||||||
if (this.camera !== null) {
|
|
||||||
this.camera.position.set(20, 10, -5);
|
|
||||||
this.camera.rotation.set(-5 * Math.PI / 12, 0, 0);
|
|
||||||
this.camera.lookAt(new Vector3(0, 0, 0));
|
|
||||||
if (this.camera instanceof PerspectiveCamera) {
|
|
||||||
this.camera.fov = 55;
|
|
||||||
this.camera.updateProjectionMatrix();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
import { Object3D } from "three";
|
||||||
|
import { ThreeC } from "../ThreeC";
|
||||||
|
import { PhysicsBody, PhysicsLayer } from "../PhysicsC";
|
||||||
|
|
||||||
|
export class Map {
|
||||||
|
static Init() {
|
||||||
|
const mapObject = ThreeC.getObject("map");
|
||||||
|
if (!mapObject) {
|
||||||
|
console.warn("Map model resource not found: map");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapObject.position.set(0, 0, 0);
|
||||||
|
ThreeC.setShadowsStateForChildren(mapObject, true, true);
|
||||||
|
ThreeC.addToScene(mapObject);
|
||||||
|
|
||||||
|
const colliders = mapObject.getObjectByName("Colliders");
|
||||||
|
if (colliders) {
|
||||||
|
colliders.visible = false;
|
||||||
|
this.buildColliders(colliders);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static buildColliders(collidersRoot: Object3D) {
|
||||||
|
collidersRoot.traverse((child) => {
|
||||||
|
if (child === collidersRoot) return;
|
||||||
|
if ((child as any).isMesh) {
|
||||||
|
new PhysicsBody(child, false, 0, PhysicsLayer.Wall, PhysicsLayer.Player);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import { EasyEvent } from "@24tools/playable_template";
|
||||||
|
import { AnimationAction, AnimationClip, AnimationMixer, Color, LoopOnce, LoopRepeat, Mesh, MeshBasicMaterial, Object3D, Vector3 } from "three";
|
||||||
|
import { clone } from "three/examples/jsm/utils/SkeletonUtils";
|
||||||
|
import { ThreeC } from "../../ThreeC";
|
||||||
|
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
|
|
||||||
|
export class Character {
|
||||||
|
tObj: Object3D;
|
||||||
|
animMixer: AnimationMixer;
|
||||||
|
animationList: AnimationClip[] = [];
|
||||||
|
|
||||||
|
// isWalking: boolean = false;
|
||||||
|
curClipAction: null | AnimationAction = null;
|
||||||
|
animStopTimeout: null | NodeJS.Timeout = null
|
||||||
|
|
||||||
|
onAnimLoop: EasyEvent<{}> = new EasyEvent<{}>();
|
||||||
|
onAnimFinish: EasyEvent<{}> = new EasyEvent<{}>();
|
||||||
|
|
||||||
|
constructor(prefab: GLTF, start_position = new Vector3()) {
|
||||||
|
let tObj = clone(prefab.scene);
|
||||||
|
|
||||||
|
tObj.castShadow = true;
|
||||||
|
let animMixer = new AnimationMixer(tObj);
|
||||||
|
|
||||||
|
animMixer.addEventListener('loop', () => {
|
||||||
|
this.onAnimLoop.Invoke({});
|
||||||
|
});
|
||||||
|
animMixer.addEventListener('finished', () => {
|
||||||
|
this.onAnimFinish.Invoke({});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (start_position) tObj.position.copy(start_position);
|
||||||
|
|
||||||
|
this.tObj = tObj;
|
||||||
|
this.animMixer = animMixer;
|
||||||
|
this.animationList = prefab.animations;
|
||||||
|
|
||||||
|
ThreeC.addToScene(tObj);
|
||||||
|
ThreeC.addAnimMixer(animMixer);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
set AnimationSpeed(timeScale: number) {
|
||||||
|
if (this.curClipAction)
|
||||||
|
this.curClipAction.timeScale = timeScale;
|
||||||
|
}
|
||||||
|
|
||||||
|
set AnimationWeight(weight: number) {
|
||||||
|
if (this.curClipAction)
|
||||||
|
this.curClipAction.weight = weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
playAnimation(anim_id: number, one_time: boolean = false, fade = 0.25, randomStart = false) {
|
||||||
|
let oldClipAction: null | AnimationAction = this.curClipAction;
|
||||||
|
var clipAction = this.animMixer.clipAction(this.animationList[anim_id]);
|
||||||
|
|
||||||
|
if (one_time) {
|
||||||
|
clipAction.clampWhenFinished = true;
|
||||||
|
clipAction.setLoop(LoopOnce, 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
clipAction.clampWhenFinished = false;
|
||||||
|
clipAction.setLoop(LoopRepeat, Infinity);
|
||||||
|
}
|
||||||
|
clipAction.timeScale = 1;
|
||||||
|
clipAction.weight = 1;
|
||||||
|
|
||||||
|
clipAction.reset();
|
||||||
|
if (randomStart)
|
||||||
|
clipAction.time = Math.random() * this.animationList[anim_id].duration;
|
||||||
|
clipAction.play();
|
||||||
|
if (oldClipAction && oldClipAction != clipAction)
|
||||||
|
oldClipAction.crossFadeTo(clipAction, fade, true);
|
||||||
|
this.curClipAction = clipAction;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export enum BaseAnimation {
|
||||||
|
Nan = -1,
|
||||||
|
Idle = 0,
|
||||||
|
Run = 1,
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum MeshType {
|
||||||
|
Character = "character",
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export enum ResourcesType {
|
||||||
|
Mesh = "mesh",
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { Vec3 } from "cannon-es";
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vec3(cannon) To Vector3(three)
|
||||||
|
*/
|
||||||
|
export function Vector3CToT(value: Vec3) {
|
||||||
|
return new Vector3(value.x, value.y, value.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vector3(three) To Vec3(cannon)
|
||||||
|
*/
|
||||||
|
export function Vector3TToC(value: Vector3) {
|
||||||
|
return new Vec3(value.x, value.y, value.z);
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
export interface IMoveInput {
|
||||||
|
get CurrentDirection(): Vector3;
|
||||||
|
update(delta);
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
import { Delegate, JoystickC, UpdateController } from "@24tools/playable_template";
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
import { IMoveInput } from "./MoveInput";
|
||||||
|
import { FollowCameraC } from "../Movment/CameraMovment/FollowCamera";
|
||||||
|
|
||||||
|
// type JoystickVectorData = {
|
||||||
|
// vector?: {
|
||||||
|
// x: number;
|
||||||
|
// y: number;
|
||||||
|
// };
|
||||||
|
// };
|
||||||
|
|
||||||
|
// type JoystickPayload = {
|
||||||
|
// event?: Event;
|
||||||
|
// data?: JoystickVectorData;
|
||||||
|
// };
|
||||||
|
|
||||||
|
export class PlayerInput implements IMoveInput {
|
||||||
|
|
||||||
|
|
||||||
|
public static InitJoystick() {
|
||||||
|
const screenSize = window.screenSize;
|
||||||
|
const minSize = Math.min(screenSize.width, screenSize.height);
|
||||||
|
const joystickSizeAspect = 0.2;
|
||||||
|
const fadeTime = 200;
|
||||||
|
const options = {
|
||||||
|
zone: document.getElementById("joystick_zone") as HTMLElement,
|
||||||
|
size: minSize * joystickSizeAspect,
|
||||||
|
restJoystick: true,
|
||||||
|
dynamicPage: true,
|
||||||
|
catchDistance: minSize * joystickSizeAspect / 2,
|
||||||
|
fadeTime: fadeTime,
|
||||||
|
};
|
||||||
|
JoystickC.init(options);
|
||||||
|
|
||||||
|
// JoystickC.onJoysticMove.addDelegate(({ event, data }) => {
|
||||||
|
// console.log('onJoysticMove', event, data);
|
||||||
|
// })
|
||||||
|
}
|
||||||
|
|
||||||
|
protected currentDirection: Vector3 = new Vector3();
|
||||||
|
private updateDelegate: Delegate<number>;
|
||||||
|
private StartDelegate: Delegate<any>;
|
||||||
|
private MoveDelegate: Delegate<any>;
|
||||||
|
private StopDelegate: Delegate<any>;
|
||||||
|
private static threshold = 0.25;
|
||||||
|
|
||||||
|
get CurrentDirection() { return this.currentDirection.clone(); };
|
||||||
|
|
||||||
|
inputaActive: boolean = false;
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.updateDelegate = UpdateController.Instance.onUpdate.addDelegate(this.update.bind(this));
|
||||||
|
|
||||||
|
this.MoveDelegate = JoystickC.onJoysticMove.addDelegate(this.onTouchMove.bind(this));
|
||||||
|
// "down" also carries joystick data in this SDK, useful for first non-zero direction.
|
||||||
|
JoystickC.onJoysticDown.addListener(this.MoveDelegate);
|
||||||
|
|
||||||
|
this.StopDelegate = JoystickC.onJoysticEnd.addDelegate(this.onTouchUp.bind(this));
|
||||||
|
|
||||||
|
|
||||||
|
this.StartDelegate = JoystickC.onJoysticStart.addDelegate(this.onTouchDown.bind(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
update(delta: number) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
onTouchMove(payload: any) {
|
||||||
|
this.currentDirection = this.GetDiraction(payload);
|
||||||
|
if (this.currentDirection.length() <= PlayerInput.threshold)
|
||||||
|
this.currentDirection.multiplyScalar(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
onTouchDown(_event: any) {
|
||||||
|
// console.log(event);
|
||||||
|
|
||||||
|
if (this.inputaActive) return;
|
||||||
|
this.inputaActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
onTouchUp() {
|
||||||
|
if (!this.inputaActive) return;
|
||||||
|
this.inputaActive = false;
|
||||||
|
this.currentDirection.multiplyScalar(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
GetDiraction(payload: any) {
|
||||||
|
// Compatible with old/new nipplejs payloads wrapped by JoystickC:
|
||||||
|
// - { event, data } where data.vector exists
|
||||||
|
// - { event, data: undefined } where event.data.vector exists
|
||||||
|
const normalizedData =
|
||||||
|
payload?.data ??
|
||||||
|
payload?.event?.data ??
|
||||||
|
payload?.event;
|
||||||
|
const vector = normalizedData?.vector;
|
||||||
|
if (!vector) return new Vector3();
|
||||||
|
|
||||||
|
const x = vector.x;
|
||||||
|
const y = vector.y;
|
||||||
|
const dir = new Vector3(-x, 0, y);
|
||||||
|
dir.applyEuler(FollowCameraC.RotationCorection);
|
||||||
|
|
||||||
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
import { Delegate, Helper, Template, UpdateController } from "@24tools/playable_template";
|
||||||
|
import { Object3D, Vector3 } from "three";
|
||||||
|
import { ThreeC } from "../../../ThreeC";
|
||||||
|
import { CameraC } from "../../../CameraC";
|
||||||
|
|
||||||
|
export class FollowCameraC {
|
||||||
|
private static updateDelegate: Delegate<number>;
|
||||||
|
static target: Object3D;
|
||||||
|
static offset: Vector3;
|
||||||
|
|
||||||
|
static mainContainer: Object3D = new Object3D();
|
||||||
|
static cameraContainer: Object3D = new Object3D();
|
||||||
|
static cameraRotation: Object3D = new Object3D();
|
||||||
|
|
||||||
|
/** Normalized movement direction set each frame by the player */
|
||||||
|
static inputDirection: Vector3 = new Vector3();
|
||||||
|
/** How far (world units) the camera shifts ahead of the player */
|
||||||
|
static lookAheadAmount: number = 2;
|
||||||
|
/** Lerp speed for the look-ahead offset (lower = smoother/slower) */
|
||||||
|
static lookAheadLerpSpeed: number = 0.7;
|
||||||
|
|
||||||
|
private static lookAheadCurrent: Vector3 = new Vector3();
|
||||||
|
|
||||||
|
static Init(target: Object3D) {
|
||||||
|
this.target = target;
|
||||||
|
this.offset = this.Offset;
|
||||||
|
|
||||||
|
console.log(target);
|
||||||
|
|
||||||
|
|
||||||
|
this.updateDelegate = new Delegate<number>(this.Update.bind(this));
|
||||||
|
UpdateController.Instance.onUpdate.addListener(this.updateDelegate);
|
||||||
|
|
||||||
|
ThreeC.addToScene(this.mainContainer);
|
||||||
|
this.mainContainer.add(this.cameraContainer);
|
||||||
|
this.cameraContainer.add(this.cameraRotation);
|
||||||
|
this.cameraRotation.add(CameraC.cameraContainer);
|
||||||
|
|
||||||
|
this.cameraRotation.rotateY(Math.PI);
|
||||||
|
|
||||||
|
this.mainContainer.position.copy(target.position);
|
||||||
|
this.mainContainer.position.x += this.Offset.x;
|
||||||
|
this.mainContainer.position.z += this.Offset.z;
|
||||||
|
|
||||||
|
this.cameraContainer.position.y += this.Offset.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Update(delta: number) {
|
||||||
|
if (!this.target.position) return;
|
||||||
|
|
||||||
|
// Lerp look-ahead toward current movement direction (stays at last direction when stopped)
|
||||||
|
const lookAheadTarget = this.inputDirection.clone().multiplyScalar(this.lookAheadAmount);
|
||||||
|
this.lookAheadCurrent.lerp(lookAheadTarget, delta * this.lookAheadLerpSpeed);
|
||||||
|
|
||||||
|
const offset = this.Offset;
|
||||||
|
|
||||||
|
// Base position without look-ahead
|
||||||
|
const basePos = this.target.position.clone();
|
||||||
|
basePos.x += offset.x;
|
||||||
|
basePos.z += offset.z;
|
||||||
|
|
||||||
|
// Final target = base + look-ahead shift
|
||||||
|
const targetPos = basePos.clone();
|
||||||
|
targetPos.x += this.lookAheadCurrent.x;
|
||||||
|
targetPos.z += this.lookAheadCurrent.z;
|
||||||
|
|
||||||
|
// Capture actual previous position BEFORE any mutation
|
||||||
|
const oldPos = this.mainContainer.position.clone();
|
||||||
|
|
||||||
|
// Compute rotation using base position to avoid tilt from look-ahead offset
|
||||||
|
this.mainContainer.position.copy(basePos);
|
||||||
|
this.mainContainer.lookAt(this.target.position);
|
||||||
|
this.cameraContainer.lookAt(this.target.position);
|
||||||
|
|
||||||
|
// Smooth follow lerp from real previous position toward target with look-ahead
|
||||||
|
const lerpSpeed = 10;
|
||||||
|
this.mainContainer.position.lerpVectors(oldPos, targetPos, delta * lerpSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
static get RotationCorection() {
|
||||||
|
const rotation = this.mainContainer.rotation.clone();
|
||||||
|
return rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get Offset() {
|
||||||
|
const portrait = window.screenSize.portrait
|
||||||
|
const values = portrait
|
||||||
|
? Template.getValue<number[]>("global", "camera_position_p")
|
||||||
|
: Template.getValue<number[]>("global", "camera_position_l");
|
||||||
|
const offset = Helper.returnVectorCamera(values);
|
||||||
|
return offset
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
import { Delegate, UpdateController } from "@24tools/playable_template";
|
||||||
|
import { IMoveInput } from "../Input/MoveInput";
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
export class MoveC {
|
||||||
|
private input: IMoveInput;
|
||||||
|
private speed: number = 5;
|
||||||
|
private updateDelegate: Delegate<number>;
|
||||||
|
private moveDiraction: Vector3 = new Vector3();
|
||||||
|
get Diraction() { return this.moveDiraction };
|
||||||
|
get Weight() { return this.moveDiraction.length() / this.speed };
|
||||||
|
|
||||||
|
constructor(Input: IMoveInput, speed: number = 5) {
|
||||||
|
this.updateDelegate = new Delegate<number>(this.update.bind(this));
|
||||||
|
UpdateController.Instance.onUpdate.addListener(this.updateDelegate);
|
||||||
|
this.input = Input;
|
||||||
|
this.speed = speed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(delta: number) {
|
||||||
|
// delta *= TimeC.TimeScale;
|
||||||
|
const moveStep = this.input.CurrentDirection.multiplyScalar(this.speed);
|
||||||
|
this.moveDiraction.copy(moveStep);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import { Delegate, UpdateController } from "@24tools/playable_template";
|
||||||
|
import { IMoveInput } from "../Input/MoveInput";
|
||||||
|
import { Object3D, Quaternion, Vector3 } from "three";
|
||||||
|
|
||||||
|
export class RotationC {
|
||||||
|
private target: Object3D;
|
||||||
|
private input: IMoveInput;
|
||||||
|
private speed: number = 5;
|
||||||
|
private updateDelegate: Delegate<number>;
|
||||||
|
private currentQ: Quaternion = new Quaternion();
|
||||||
|
private targetQ: Quaternion = new Quaternion();
|
||||||
|
|
||||||
|
constructor(target: Object3D, Input: IMoveInput, speed: number = 5) {
|
||||||
|
this.updateDelegate = new Delegate<number>(this.update.bind(this));
|
||||||
|
UpdateController.Instance.onUpdate.addListener(this.updateDelegate);
|
||||||
|
this.input = Input;
|
||||||
|
this.speed = speed;
|
||||||
|
this.target = target;
|
||||||
|
this.currentQ.copy(this.target.quaternion);
|
||||||
|
this.targetQ.copy(this.target.quaternion);
|
||||||
|
}
|
||||||
|
|
||||||
|
private update(delta: number) {
|
||||||
|
const loockAtStep = this.input.CurrentDirection;
|
||||||
|
if (loockAtStep.length() != 0) {
|
||||||
|
const loockAtPoint = this.target.position.clone().add(loockAtStep);
|
||||||
|
this.target.lookAt(loockAtPoint);
|
||||||
|
this.targetQ.copy(this.target.quaternion);
|
||||||
|
this.target.quaternion.copy(this.currentQ);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.target.quaternion.slerp(this.targetQ, delta * this.speed);
|
||||||
|
this.currentQ.copy(this.target.quaternion);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
import { Delegate, ResourcesC, UpdateController } from "@24tools/playable_template";
|
||||||
|
import { Character } from "./Character/Character";
|
||||||
|
import { ResourcesType } from "./Enums/ResourcesType";
|
||||||
|
import { MeshType } from "./Enums/MeshType";
|
||||||
|
import { GLTF } from "three/examples/jsm/loaders/GLTFLoader";
|
||||||
|
import { BaseAnimation } from "./Enums/BaseAnimation";
|
||||||
|
import { PhysicsBody, PhysicsLayer } from "../PhysicsC";
|
||||||
|
import { Object3D } from "three";
|
||||||
|
import { ThreeC } from "../ThreeC";
|
||||||
|
import { PlayerInput } from "./Input/PlayerInput";
|
||||||
|
import { MoveC } from "./Movment/MoveC";
|
||||||
|
import { Vec3 } from "cannon-es";
|
||||||
|
import { contain } from "three/src/extras/TextureUtils";
|
||||||
|
import { Vector3CToT, Vector3TToC } from "./Helper";
|
||||||
|
import { RotationC } from "./Movment/RotationC";
|
||||||
|
import { FollowCameraC } from "./Movment/CameraMovment/FollowCamera";
|
||||||
|
import { Vector3 } from "three";
|
||||||
|
|
||||||
|
export class Player {
|
||||||
|
private static inited: boolean = false;
|
||||||
|
private static isRunning: boolean = false;
|
||||||
|
|
||||||
|
private static updateDelegate: Delegate<number>;
|
||||||
|
|
||||||
|
private static container: Object3D = new Object3D;
|
||||||
|
private static input: PlayerInput;
|
||||||
|
private static movement: MoveC;
|
||||||
|
private static rotation: RotationC;
|
||||||
|
private static spawnPosition: Vector3 = new Vector3(0, 0, 0);
|
||||||
|
|
||||||
|
static character: Character;
|
||||||
|
static physics: PhysicsBody;
|
||||||
|
|
||||||
|
static SetSpawnPosition(position: Vector3) {
|
||||||
|
this.spawnPosition.copy(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Init() {
|
||||||
|
if (this.inited) return;
|
||||||
|
this.inited = true
|
||||||
|
const asset = ResourcesC.getResource<GLTF>(ResourcesType.Mesh, MeshType.Character)
|
||||||
|
this.character = new Character(asset);
|
||||||
|
|
||||||
|
this.container.position.copy(this.spawnPosition);
|
||||||
|
this.character.playAnimation(BaseAnimation.Idle)
|
||||||
|
this.container.add(this.character.tObj);
|
||||||
|
ThreeC.addToScene(this.container);
|
||||||
|
|
||||||
|
this.InitPhisic();
|
||||||
|
const input = new PlayerInput();
|
||||||
|
const moveSpeed = 3;
|
||||||
|
const rotationSpeed = 8;
|
||||||
|
this.movement = new MoveC(input, moveSpeed);
|
||||||
|
this.rotation = new RotationC(this.container, input, rotationSpeed);
|
||||||
|
|
||||||
|
this.updateDelegate = new Delegate<number>((delta) => this.Update(delta));
|
||||||
|
UpdateController.Instance.onUpdate.addListener(this.updateDelegate);
|
||||||
|
|
||||||
|
FollowCameraC.Init(this.container);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static InitPhisic() {
|
||||||
|
this.physics = new PhysicsBody(
|
||||||
|
this.container,
|
||||||
|
false,
|
||||||
|
1,
|
||||||
|
PhysicsLayer.Player,
|
||||||
|
PhysicsLayer.Wall,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StartRunning() {
|
||||||
|
if (this.isRunning) return;
|
||||||
|
this.character.playAnimation(BaseAnimation.Run);
|
||||||
|
this.isRunning = true;
|
||||||
|
}
|
||||||
|
private static StopRunning() {
|
||||||
|
if (!this.isRunning) return;
|
||||||
|
this.character.playAnimation(BaseAnimation.Idle);
|
||||||
|
this.AnimationValue = 1;
|
||||||
|
this.isRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static set AnimationValue(value: number) {
|
||||||
|
this.character.AnimationSpeed = value;
|
||||||
|
this.character.AnimationWeight = value * 12.5 + 87.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Update(delta: number) {
|
||||||
|
const diraction = this.movement.Diraction;
|
||||||
|
const weight = this.movement.Weight;
|
||||||
|
|
||||||
|
if (diraction.length() > 0) {
|
||||||
|
this.StartRunning();
|
||||||
|
this.AnimationValue = weight;
|
||||||
|
FollowCameraC.inputDirection.copy(diraction).normalize();
|
||||||
|
} else {
|
||||||
|
this.StopRunning();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const cPos = Vector3TToC(diraction);
|
||||||
|
|
||||||
|
this.physics.getPhysicsBody().velocity.copy(cPos);
|
||||||
|
this.MoveVisual(delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MoveVisual(delta: number) {
|
||||||
|
const lerpSpeed = 10;
|
||||||
|
const targetPos = (Vector3CToT(this.physics.getPhysicsBody().position));
|
||||||
|
|
||||||
|
this.container.position.lerp(targetPos, delta * lerpSpeed)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,72 +1,52 @@
|
|||||||
import { DirectionalLight, Object3D, Vector3, Mesh, Material } from "three";
|
import { BoxGeometry, Mesh, MeshStandardMaterial, Vector3 } from "three";
|
||||||
import { ThreeC } from "./ThreeC";
|
import { ThreeC } from "./ThreeC";
|
||||||
import { CameraC } from "./CameraC";
|
import { InputC, JoystickC } from "@24tools/playable_template";
|
||||||
import { InputC, UpdateController } from "@24tools/playable_template";
|
import { Player } from "./Presets/Player";
|
||||||
|
import { PhysicsBody, PhysicsLayer } from "./PhysicsC";
|
||||||
|
import { Map } from "./Map/Map";
|
||||||
|
|
||||||
export class TestSceneC {
|
export class TestSceneC {
|
||||||
private static character: Object3D | null = null;
|
|
||||||
|
|
||||||
static init() {
|
static init() {
|
||||||
this.loadMapModel();
|
// this.createPrimitive();
|
||||||
this.loadCharacter();
|
Map.Init();
|
||||||
|
this.InitPlayer();
|
||||||
|
|
||||||
// example of using InputC events
|
// example of using InputC events
|
||||||
InputC.onTouchDown.addDelegate((event) => {
|
// InputC.onTouchDown.addDelegate((event) => {
|
||||||
console.log("onMouseDown", event);
|
// console.log("onMouseDown", event);
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Update loop to follow character with camera
|
// if you have update in your controller
|
||||||
UpdateController.Instance.onUpdate.addDelegate(() => {
|
// UpdateController.Instance.onUpdate.addDelegate(() => {
|
||||||
this.updateCameraFollow();
|
// this.update();
|
||||||
});
|
// });
|
||||||
}
|
}
|
||||||
|
|
||||||
private static loadMapModel() {
|
// private static createPrimitive() {
|
||||||
const mapObject = ThreeC.getObject("map");
|
// const planeSize = new Vector3(10, 0.1, 10);
|
||||||
if (!mapObject) {
|
// const geometryPlane = new BoxGeometry(planeSize.x, planeSize.y, planeSize.z);
|
||||||
console.warn("Map model resource not found: map");
|
// const materialPlane = new MeshStandardMaterial({ color: 0xaaaaaa });
|
||||||
return;
|
// const plane = new Mesh(geometryPlane, materialPlane);
|
||||||
}
|
|
||||||
|
|
||||||
mapObject.position.set(0, 0, 0);
|
// ThreeC.setShadowsStateForChildren(plane, false, true);
|
||||||
|
|
||||||
ThreeC.setShadowsStateForChildren(mapObject, true, true);
|
// plane.position.y = -planeSize.y / 2;
|
||||||
ThreeC.addToScene(mapObject);
|
|
||||||
|
// new PhysicsBody(
|
||||||
|
// plane,
|
||||||
|
// false,
|
||||||
|
// 0,
|
||||||
|
// PhysicsLayer.Wall,
|
||||||
|
// PhysicsLayer.Player,
|
||||||
|
// );
|
||||||
|
|
||||||
|
// ThreeC.addToScene(plane);
|
||||||
|
// }
|
||||||
|
|
||||||
|
private static InitPlayer() {
|
||||||
|
const playerSpawnPoint = new Vector3(4, 0, 27);
|
||||||
|
Player.SetSpawnPosition(playerSpawnPoint);
|
||||||
|
Player.Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static updateCameraFollow() {
|
|
||||||
if (!this.character || !CameraC.camera) return;
|
|
||||||
|
|
||||||
// Position camera at 75 degree angle from horizontal, slightly to the side
|
|
||||||
const charPos = this.character.position;
|
|
||||||
const angle = 70 * (Math.PI / 180); // 75 degrees
|
|
||||||
const distance = 10;
|
|
||||||
const sideOffset = 5; // offset to the left side
|
|
||||||
|
|
||||||
// Calculate vertical and horizontal distances based on 75 degree angle
|
|
||||||
const verticalDistance = distance * Math.sin(angle);
|
|
||||||
const horizontalDistance = distance * Math.cos(angle);
|
|
||||||
|
|
||||||
CameraC.camera.position.set(
|
|
||||||
charPos.x + sideOffset,
|
|
||||||
charPos.y + verticalDistance,
|
|
||||||
charPos.z + horizontalDistance
|
|
||||||
);
|
|
||||||
CameraC.camera.lookAt(charPos.x, charPos.y + 1, charPos.z);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static loadCharacter() {
|
|
||||||
const charObject = ThreeC.getObject("character");
|
|
||||||
if (!charObject) {
|
|
||||||
console.warn("Character model resource not found: character");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Place character near the map center; adjust Y for ground offset
|
|
||||||
charObject.position.copy(new Vector3(0, 0, 32));
|
|
||||||
this.character = charObject;
|
|
||||||
ThreeC.setShadowsStateForChildren(charObject, true, true);
|
|
||||||
ThreeC.addToScene(charObject);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ window.setupConfig = async function (config) {
|
|||||||
redirectOptions: {},
|
redirectOptions: {},
|
||||||
ticker: Template3d.ticker,
|
ticker: Template3d.ticker,
|
||||||
debug: {
|
debug: {
|
||||||
physics: false,
|
physics: true,
|
||||||
// set true if you want to enable physics debugger
|
// set true if you want to enable physics debugger
|
||||||
logger: false // set true if you want to enable logger
|
logger: false // set true if you want to enable logger
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
CameraC_internal,
|
CameraC_internal,
|
||||||
CameraType,
|
CameraType,
|
||||||
// JoystickC,
|
JoystickC,
|
||||||
Physics_internal,
|
Physics_internal,
|
||||||
Template,
|
Template,
|
||||||
Template3d,
|
Template3d,
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from "@24tools/playable_template";
|
} from "@24tools/playable_template";
|
||||||
import { CameraC } from "../controllers/CameraC";
|
import { CameraC } from "../controllers/CameraC";
|
||||||
import { ThreeC } from "../controllers/ThreeC";
|
import { ThreeC } from "../controllers/ThreeC";
|
||||||
|
import { PlayerInput } from "../controllers/Presets/Input/PlayerInput";
|
||||||
import { Color } from "three";
|
import { Color } from "three";
|
||||||
import { Vec3 } from "cannon-es";
|
import { Vec3 } from "cannon-es";
|
||||||
export const beforeResourcesLoadedCb = () => {
|
export const beforeResourcesLoadedCb = () => {
|
||||||
@@ -23,20 +24,22 @@ export const beforeResourcesLoadedCb = () => {
|
|||||||
ThreeC_internal.init();
|
ThreeC_internal.init();
|
||||||
ThreeC.createBaseLights();
|
ThreeC.createBaseLights();
|
||||||
ThreeC.setupDirectionalLight();
|
ThreeC.setupDirectionalLight();
|
||||||
|
PlayerInput.InitJoystick();
|
||||||
|
|
||||||
let physicsWorld = Physics_internal.init(new Vec3(0, -9.81, 0));
|
|
||||||
|
let physicsWorld = Physics_internal.init(new Vec3(0, 0, 0));
|
||||||
|
|
||||||
// example of using joystick. Uncomment if you need joystick
|
// example of using joystick. Uncomment if you need joystick
|
||||||
|
|
||||||
// JoystickC.init({
|
// JoystickC.init({
|
||||||
// zone: document.getElementById("joystick_zone") as HTMLDivElement,
|
// zone: document.getElementById("joystick_zone") as HTMLDivElement,
|
||||||
// fadeTime: 0,
|
// fadeTime: 0,
|
||||||
// mode: "dynamic",
|
// mode: "dynamic",
|
||||||
// restJoystick: true,
|
// restJoystick: true,
|
||||||
// catchDistance: 1,
|
// catchDistance: 1,
|
||||||
// restOpacity: 0,
|
// restOpacity: 0,
|
||||||
// follow: false,
|
// follow: false,
|
||||||
// });
|
// });
|
||||||
|
|
||||||
// JoystickC.onJoysticMove.addDelegate(({event, data}) => {
|
// JoystickC.onJoysticMove.addDelegate(({event, data}) => {
|
||||||
// console.log('onJoysticMove', event, data);
|
// console.log('onJoysticMove', event, data);
|
||||||
|
|||||||
+4949
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user