From 7cfe2fe257e5f1ae71475831f5ab6c3387f4ac11 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Tue, 19 Sep 2023 15:25:02 -0500 Subject: [PATCH] Updated soccer menu....moved soccer specific code to soccer. --- src/controllers/controllers.ts | 3 +- src/controllers/left.ts | 16 +++++ src/controllers/right.ts | 32 ++------- src/controllers/rigplatform.ts | 33 +-------- src/soccer/ball.ts | 8 ++- src/soccer/soccerMenu.ts | 120 ++++++++++++++++++++++++++++----- src/soccer/team.ts | 1 - 7 files changed, 136 insertions(+), 77 deletions(-) diff --git a/src/controllers/controllers.ts b/src/controllers/controllers.ts index 54a510a..113985e 100644 --- a/src/controllers/controllers.ts +++ b/src/controllers/controllers.ts @@ -1,4 +1,4 @@ -import {AbstractMesh, Observable, TransformNode, Vector3} from "@babylonjs/core"; +import {AbstractMesh, Observable, TransformNode, Vector3, WebXRInputSource} from "@babylonjs/core"; export type ControllerEvent = { type: ControllerEventType, @@ -7,6 +7,7 @@ export type ControllerEvent = { endPosition?: Vector3, duration?: number, gripId?: string; + controller?: WebXRInputSource; } export enum ControllerEventType { diff --git a/src/controllers/left.ts b/src/controllers/left.ts index 383b258..37a2460 100644 --- a/src/controllers/left.ts +++ b/src/controllers/left.ts @@ -27,6 +27,7 @@ export class Left extends Base { }); this.initXButton(init.components['x-button']); this.initYButton(init.components['y-button']); + this.initTrigger(init.components['xr-standard-trigger']); init.components['xr-standard-thumbstick'].onButtonStateChangedObservable.add((value) => { if (value.pressed) { log.trace('Left', 'thumbstick changed'); @@ -40,6 +41,21 @@ export class Left extends Base { }); } + + private initTrigger(trigger: WebXRControllerComponent) { + if (trigger) { + trigger + .onButtonStateChangedObservable + .add((button) => { + this.controllers.controllerObserver.notifyObservers({ + type: ControllerEventType.TRIGGER, + value: button.value, + controller: this.controller + }); + }, -1, false, this); + } + } + private initXButton(xbutton: WebXRControllerComponent) { if (xbutton) { xbutton.onButtonStateChangedObservable.add((button) => { diff --git a/src/controllers/right.ts b/src/controllers/right.ts index d5d043a..30d7414 100644 --- a/src/controllers/right.ts +++ b/src/controllers/right.ts @@ -22,6 +22,7 @@ export class Right extends Base { }); } } + private startTime: number = null; private endPosition: Vector3 = null; @@ -46,32 +47,11 @@ export class Right extends Base { trigger .onButtonStateChangedObservable .add((button) => { - if (button.pressed) { - this.controllers.controllerObserver.notifyObservers({ - type: ControllerEventType.TRIGGER, - value: button.value - }); - if (!this.startTime) { - this.startTime = new Date().getTime(); - this.startPosition = this.controller.pointer.absolutePosition.clone(); - } - - } else { - this.endPosition = this.controller.pointer.absolutePosition.clone(); - if (this.startTime && this.startPosition) { - const duration = new Date().getTime() - this.startTime; - - this.controllers.controllerObserver.notifyObservers({ - type: ControllerEventType.MOTION, - startPosition: this.startPosition, - endPosition: this.endPosition, - duration: duration - }); - this.startTime = null; - this.startPosition = null; - } - - } + this.controllers.controllerObserver.notifyObservers({ + type: ControllerEventType.TRIGGER, + value: button.value, + controller: this.controller + }); }, -1, false, this); } } diff --git a/src/controllers/rigplatform.ts b/src/controllers/rigplatform.ts index 4654521..bddcd82 100644 --- a/src/controllers/rigplatform.ts +++ b/src/controllers/rigplatform.ts @@ -1,4 +1,4 @@ -import {Angle, Color3, Mesh, MeshBuilder, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; +import {Angle, Mesh, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {Right} from "./right"; import {Left} from "./left"; import {EditMenu} from "../menus/editMenu"; @@ -124,45 +124,16 @@ export class Rigplatform { case ControllerEventType.MENU: this.bMenu.toggle(); break; - case ControllerEventType.TRIGGER: - const worldRay = this.scene.activeCamera.getForwardRay(); - worldRay.origin = this.scene.activeCamera.globalPosition; - const pickInfo = this.scene.pickWithRay(worldRay, null); - if (pickInfo?.hit) { - const circle = MeshBuilder.CreateSphere("circle", {diameter: .02}, this.scene); - circle.position = pickInfo.pickedPoint; - setTimeout(() => { - circle.dispose(); - }, 500); - if (pickInfo?.pickedMesh?.name == 'Football Ball.001') { - this.controllers.controllerObserver.notifyObservers({ - type: ControllerEventType.GAZEPOINT, - endPosition: pickInfo.pickedPoint, - startPosition: this.xr.baseExperience.camera.globalPosition - }) - } - } - break; case ControllerEventType.MOTION: this.logger.debug(JSON.stringify(event)); - this.buildKickLine(event.startPosition, event.endPosition); + break; } }); } } - private buildKickLine(start: Vector3, end: Vector3) { - if (end.y < start.y) { - const line = MeshBuilder.CreateLines("kickLine", {points: [start, end]}, this.scene); - line.color = new Color3(1, 0, 0); - line.isPickable = false; - setTimeout(() => { - line.dispose(); - }, 2000); - } - } private initializeControllers() { this.xr.input.onControllerAddedObservable.add((source) => { diff --git a/src/soccer/ball.ts b/src/soccer/ball.ts index 38f652c..b928597 100644 --- a/src/soccer/ball.ts +++ b/src/soccer/ball.ts @@ -16,7 +16,7 @@ export class Ball { private readonly scene: Scene; private transformNode: TransformNode; private mesh: AbstractMesh; - private position: Vector3 = new Vector3(0, .5, 0); + _position: Vector3 = new Vector3(0, .5, 0); private parent: AbstractMesh; private controllers: Controllers; private physicsAggregate: PhysicsAggregate; @@ -39,6 +39,10 @@ export class Ball { this.physicsAggregate.body.applyImpulse(direction.scale(force), Vector3.Zero()); } + public get position(): Vector3 { + return this.physicsAggregate.transformNode.absolutePosition; + } + private buildBall() { SceneLoader.ImportMesh(null, "/assets/models/", "ball.gltf", this.scene, (meshes, particleSystems, skeletons, animationGroups) => { @@ -47,7 +51,7 @@ export class Ball { this.parent = MeshBuilder.CreateSphere("ballParent", {diameter: .17}, this.scene); this.parent.isVisible = false; - this.parent.position = this.position; + this.parent.position = this._position; this.scene.onBeforeRenderObservable.add(() => { if (!this.physicsAggregate && diff --git a/src/soccer/soccerMenu.ts b/src/soccer/soccerMenu.ts index 95bfcce..8e2b6aa 100644 --- a/src/soccer/soccerMenu.ts +++ b/src/soccer/soccerMenu.ts @@ -1,9 +1,10 @@ -import {Scene, WebXRDefaultExperience} from "@babylonjs/core"; +import {Color3, MeshBuilder, Quaternion, Scene, Vector3, WebXRDefaultExperience} from "@babylonjs/core"; import {AbstractMenu} from "../menus/abstractMenu"; -import {ControllerEventType, Controllers} from "../controllers/controllers"; +import {ControllerEvent, ControllerEventType, Controllers} from "../controllers/controllers"; import {GUI3DManager, PlanePanel} from "@babylonjs/gui"; import log, {Logger} from "loglevel"; import {Field} from "./field"; +import {getFrontPosition} from "../util/functions/getFrontPosition"; enum SoccerMenuState { PLAY, @@ -18,29 +19,114 @@ export class SoccerMenu extends AbstractMenu { private state: SoccerMenuState = SoccerMenuState.NONE; private readonly field: Field; private logger: Logger = log.getLogger('SoccerMenu') + private startTime: number; + private startPosition: Vector3; constructor(scene: Scene, xr: WebXRDefaultExperience, controllers: Controllers) { super(scene, xr, controllers); this.field = new Field(this.scene); this.manager = new GUI3DManager(this.scene); - this.controllers.controllerObserver.add((event) => { - switch (event.type) { - case ControllerEventType.MOTION: - this.field.ball.kick(event.startPosition.clone().subtract(event.endPosition).normalize(), event.duration / 100); - break; - case ControllerEventType.GAZEPOINT: - if (event.endPosition) { - this.field.gazePoint = event.endPosition.clone(); - } - break; - - } - - }); + this.controllers.controllerObserver.add(this.controllerEventHandler, -1, false, this); this.buildMenu(); } + private controllerEventHandler(event: ControllerEvent) { + switch (this.state) { + case SoccerMenuState.PLAY: + this.playControllerEventHandler(event); + break; + case SoccerMenuState.PLAN: + break; + case SoccerMenuState.TRAIN: + break; + case SoccerMenuState.NONE: + break + } + + } + + private playControllerEventHandler(event: ControllerEvent) { + switch (event.type) { + case ControllerEventType.TRIGGER: + if (event.value > .8) { + if (!this.startTime) { + this.startTime = new Date().getTime(); + this.startPosition = event.controller.pointer.position.clone(); + } + } else { + if (this.startTime) { + const endPosition = event.controller.pointer.position.clone(); + if (this.startTime && this.startPosition) { + const duration = new Date().getTime() - this.startTime; + + this.controllers.controllerObserver.notifyObservers({ + type: ControllerEventType.MOTION, + startPosition: this.startPosition, + endPosition: endPosition, + duration: duration + }); + this.startTime = null; + this.startPosition = null; + } + } + } + const worldRay = this.scene.activeCamera.getForwardRay(); + worldRay.origin = this.scene.activeCamera.globalPosition; + const pickInfo = this.scene.pickWithRay(worldRay, null); + if (pickInfo?.hit) { + const circle = MeshBuilder.CreateSphere("circle", {diameter: .04}, this.scene); + circle.position = pickInfo.pickedPoint; + setTimeout(() => { + circle.dispose(); + }, 1500); + + if (pickInfo?.pickedMesh?.name == 'Football Ball.001') { + this.controllers.controllerObserver.notifyObservers({ + type: ControllerEventType.GAZEPOINT, + endPosition: pickInfo.pickedPoint, + startPosition: this.xr.baseExperience.camera.globalPosition + }) + } + } + const mesh = this.scene.getPointerOverMesh(); + if (mesh) { + const meta = mesh?.parent?.parent?.parent + if (meta) { + console.log(meta.id); + } + } + break; + case ControllerEventType.MOTION: + const start = event.startPosition.clone(); + const direction = start.subtract(event.endPosition); + const force = direction.length() * 10; + const dir = direction.normalize(); + const e = this.xr.baseExperience.camera.absoluteRotation.toEulerAngles(); + direction.applyRotationQuaternionInPlace(Quaternion.FromEulerAngles(0, e.y, 0)); + + this.buildKickLine(dir, force); + this.field.ball.kick(dir, force); + break; + case ControllerEventType.GAZEPOINT: + if (event.endPosition) { + this.field.gazePoint = event.endPosition.clone(); + } + break; + } + } + + private buildKickLine(direction: Vector3, force: number) { + const start = this.field.ball.position.clone(); + const line = MeshBuilder.CreateLines("kickLine", {points: [start, start.add(direction.scale(force))]}, this.scene); + line.color = new Color3(1, 1, .5); + line.isPickable = false; + setTimeout(() => { + line.dispose(); + }, 2000); + + } + makeButton(name: string, id: string) { const button = super.makeButton(name, id); button.onPointerClickObservable.add(this.handleClick, -1, false, this); @@ -56,7 +142,9 @@ export class SoccerMenu extends AbstractMenu { panel.addControl(this.makeButton("Train", "Train")); panel.addControl(this.makeButton("Modify", "modify")); this.manager.rootContainer.children[0].node.position.y = .2; + this.manager.controlScaling = .2; this.createHandle(this.manager.rootContainer.children[0].node); + this.handle.mesh.position = getFrontPosition(3, this.scene).add(new Vector3(0, .5, 0)); } private handleClick(_info, state) { diff --git a/src/soccer/team.ts b/src/soccer/team.ts index 87292f9..e4da896 100644 --- a/src/soccer/team.ts +++ b/src/soccer/team.ts @@ -29,7 +29,6 @@ export class Team { this.playerFactory = new PlayerFactory(this.scene); this.playerFactory.onReadyObservable.add(() => { this.buildTeam(); - this.players[5].runTo(new Vector2(3, -3 * this.goalSide)); }); }