Soccer Components.
This commit is contained in:
parent
f8259670e7
commit
b06a158523
@ -20,6 +20,7 @@ import workerUrl from "./worker?worker&url";
|
||||
import {DiagramEventType} from "./diagram/diagramEntity";
|
||||
import {PeerjsNetworkConnection} from "./integration/peerjsNetworkConnection";
|
||||
import {DiagramExporter} from "./util/diagramExporter";
|
||||
import {Field} from "./soccer/field";
|
||||
|
||||
|
||||
export class App {
|
||||
@ -116,6 +117,7 @@ export class App {
|
||||
camera.attachControl(canvas, true);
|
||||
new HemisphericLight("light1", new Vector3(1, 1, 0), scene);
|
||||
|
||||
|
||||
environment.groundMeshObservable.add(async (ground) => {
|
||||
const xr = await WebXRDefaultExperience.CreateAsync(scene, {
|
||||
floorMeshes: [ground],
|
||||
@ -137,8 +139,8 @@ export class App {
|
||||
});
|
||||
});
|
||||
|
||||
xr.baseExperience.onStateChangedObservable.add((state) => {
|
||||
|
||||
xr.baseExperience.onStateChangedObservable.add((state) => {
|
||||
if (state == WebXRState.IN_XR) {
|
||||
scene.audioEnabled = true;
|
||||
xr.baseExperience.camera.position = new Vector3(0, 1.6, 0);
|
||||
@ -153,6 +155,10 @@ export class App {
|
||||
});
|
||||
import('./controllers/rigplatform').then((rigmodule) => {
|
||||
const rig = new rigmodule.Rigplatform(scene, xr, diagramManager, controllers);
|
||||
setTimeout(() => {
|
||||
const field = new Field(scene);
|
||||
field.addControllers(controllers);
|
||||
}, 5000);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import {
|
||||
AbstractMesh,
|
||||
HavokPlugin,
|
||||
Mesh,
|
||||
PhysicsMotionType,
|
||||
Scene,
|
||||
TransformNode,
|
||||
@ -108,17 +109,27 @@ export class Base {
|
||||
}
|
||||
|
||||
private grab() {
|
||||
const mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
|
||||
let mesh = this.xr.pointerSelection.getMeshUnderPointer(this.controller.uniqueId);
|
||||
if (!mesh) {
|
||||
return;
|
||||
}
|
||||
let player = false;
|
||||
const template = mesh?.metadata?.template;
|
||||
if (!template) {
|
||||
if (mesh?.metadata?.handle == true) {
|
||||
mesh && mesh.setParent(this.controller.motionController.rootMesh);
|
||||
this.grabbedMesh = mesh;
|
||||
} else {
|
||||
return;
|
||||
if (mesh?.parent?.parent?.metadata?.grabbable) {
|
||||
if (mesh?.parent?.parent?.parent) {
|
||||
mesh = (mesh?.parent?.parent?.parent as Mesh);
|
||||
this.grabbedMesh = mesh;
|
||||
player = true;
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
if (template == '#connection-template') {
|
||||
@ -131,7 +142,7 @@ export class Base {
|
||||
this.previousScaling = mesh?.scaling.clone();
|
||||
this.previousPosition = mesh?.position.clone();
|
||||
|
||||
if ("toolbox" != mesh?.parent?.parent?.id) {
|
||||
if (("toolbox" != mesh?.parent?.parent?.id) || player) {
|
||||
if (mesh.physicsBody) {
|
||||
const transformNode = setupTransformNode(mesh, this.controller.motionController.rootMesh);
|
||||
mesh.physicsBody.setMotionType(PhysicsMotionType.ANIMATED);
|
||||
@ -196,7 +207,7 @@ export class Base {
|
||||
this.previousRotation = null;
|
||||
this.previousPosition = null;
|
||||
this.grabbedMesh = null;
|
||||
if (mesh?.metadata?.template.indexOf('#') == -1) {
|
||||
if (mesh?.metadata?.template && (mesh?.metadata?.template.indexOf('#') == -1)) {
|
||||
return;
|
||||
}
|
||||
const entity = toDiagramEntity(mesh);
|
||||
|
||||
@ -29,7 +29,8 @@ export enum ControllerEventType {
|
||||
UP_DOWN = 'updown',
|
||||
TRIGGER = 'trigger',
|
||||
MENU = 'menu',
|
||||
MOTION = 'motion'
|
||||
MOTION = 'motion',
|
||||
GAZEPOINT = 'gazepoint',
|
||||
}
|
||||
|
||||
export class Controllers {
|
||||
|
||||
@ -124,6 +124,26 @@ 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:
|
||||
console.log(JSON.stringify(event));
|
||||
this.buildKickLine(event.startPosition, event.endPosition);
|
||||
|
||||
@ -37,7 +37,7 @@ export function diagramEventHandler(event: DiagramEvent,
|
||||
case DiagramEventType.DROPPED:
|
||||
break;
|
||||
case DiagramEventType.DROP:
|
||||
if (mesh.metadata.template.indexOf('#') > -1) {
|
||||
if (mesh?.metadata?.template && (mesh.metadata.template.indexOf('#') > -1)) {
|
||||
TextLabel.updateTextNode(mesh, entity.text);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -52,8 +52,9 @@ export class Ball {
|
||||
this.scene?.getPhysicsEngine()?.getPhysicsPlugin()) {
|
||||
console.log("creating physics aggregate");
|
||||
this.physicsAggregate = new PhysicsAggregate(this.parent,
|
||||
PhysicsShapeType.SPHERE, {mass: 1, restitution: .5, friction: .6}, this.scene);
|
||||
this.physicsAggregate.body.setLinearDamping(.2);
|
||||
PhysicsShapeType.SPHERE, {mass: 1, restitution: .6, friction: .6}, this.scene);
|
||||
this.physicsAggregate.body.setLinearDamping(.3);
|
||||
this.physicsAggregate.body.setAngularDamping(2);
|
||||
this.mesh.setParent(this.physicsAggregate.transformNode);
|
||||
this.mesh.position.y = 0;
|
||||
return;
|
||||
|
||||
@ -1,31 +1,61 @@
|
||||
import {InstancedMesh, Mesh, MeshBuilder, Scene, StandardMaterial, Vector2, Vector3} from "@babylonjs/core";
|
||||
import {
|
||||
InstancedMesh,
|
||||
Mesh,
|
||||
MeshBuilder,
|
||||
Scene,
|
||||
StandardMaterial,
|
||||
TransformNode,
|
||||
Vector2,
|
||||
Vector3
|
||||
} from "@babylonjs/core";
|
||||
import {Ball} from "./ball";
|
||||
import {Rigplatform} from "../controllers/rigplatform";
|
||||
import {Team} from "./team";
|
||||
import {ControllerEventType, Controllers} from "../controllers/controllers";
|
||||
|
||||
export class Field {
|
||||
private readonly scene: Scene;
|
||||
private ball: Ball;
|
||||
private rig: Rigplatform;
|
||||
private controllers: Controllers;
|
||||
private goalMesh: Mesh;
|
||||
private material: StandardMaterial;
|
||||
private team1: Team;
|
||||
private readonly fieldCenter: TransformNode;
|
||||
private team2: Team;
|
||||
private gazePoint: Vector3;
|
||||
|
||||
constructor(scene: Scene) {
|
||||
this.scene = scene;
|
||||
this.fieldCenter = new TransformNode("fieldCenter", this.scene);
|
||||
this.team1 = new Team(scene, 1, "one");
|
||||
this.team2 = new Team(scene, -1, "two");
|
||||
|
||||
this.goalMesh = MeshBuilder.CreateCylinder("goalPost", {diameter: .1, height: 1}, this.scene);
|
||||
this.material = new StandardMaterial("material", this.scene);
|
||||
this.material.diffuseColor.set(1, 1, 1);
|
||||
this.material.alpha = .5;
|
||||
this.goalMesh.material = this.getMaterial();
|
||||
this.goalMesh.setEnabled(false);
|
||||
this.ball = new Ball(this.scene);
|
||||
this.buildField();
|
||||
}
|
||||
|
||||
public addBall(ball: Ball) {
|
||||
this.ball = ball;
|
||||
}
|
||||
public addControllers(controllers: Controllers) {
|
||||
this.controllers = controllers;
|
||||
this.controllers.controllerObserver.add((event) => {
|
||||
switch (event.type) {
|
||||
case ControllerEventType.MOTION:
|
||||
this.ball.kick(event.startPosition.clone().subtract(event.endPosition).normalize(), event.duration / 100);
|
||||
break;
|
||||
case ControllerEventType.GAZEPOINT:
|
||||
if (event.endPosition) {
|
||||
this.gazePoint = event.endPosition.clone();
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
public addRig(rig: Rigplatform) {
|
||||
this.rig = rig;
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +73,6 @@ export class Field {
|
||||
this.buildLine(new Vector2(-18.33, -50 + 8.25), new Vector2(width, 16.5 - width));
|
||||
this.buildLine(new Vector2(18.33, -50 + 8.25), new Vector2(width, 16.5 - width));
|
||||
|
||||
|
||||
this.buildLine(new Vector2(0, -50), new Vector2(70 - width, width));
|
||||
this.buildLine(new Vector2(0, 50), new Vector2(70 - width, width));
|
||||
|
||||
@ -83,6 +112,7 @@ export class Field {
|
||||
}
|
||||
goalPost.scaling.y = length;
|
||||
goalPost.visibility = 1;
|
||||
goalPost.setParent(this.fieldCenter);
|
||||
}
|
||||
|
||||
private buildCircle(position: Vector2) {
|
||||
@ -92,6 +122,7 @@ export class Field {
|
||||
circle.position.y = .01;
|
||||
circle.rotation.x = Math.PI / 2;
|
||||
circle.material = this.getMaterial();
|
||||
circle.setParent(this.fieldCenter);
|
||||
}
|
||||
|
||||
private buildArc(position: Vector2, arc: number = Math.PI, rotation: number = 0) {
|
||||
@ -109,6 +140,7 @@ export class Field {
|
||||
circle.position.x = position.x;
|
||||
circle.position.z = position.y;
|
||||
circle.rotation = new Vector3(0, rotation, 0);
|
||||
circle.setParent(this.fieldCenter);
|
||||
}
|
||||
|
||||
private getMaterial(): StandardMaterial {
|
||||
@ -125,5 +157,6 @@ export class Field {
|
||||
line.position.y = .01;
|
||||
line.position.x = position.x;
|
||||
line.position.z = position.y;
|
||||
line.setParent(this.fieldCenter);
|
||||
}
|
||||
}
|
||||
@ -1,60 +1,137 @@
|
||||
import {
|
||||
AbstractMesh,
|
||||
AnimationGroup,
|
||||
AssetContainer,
|
||||
Mesh,
|
||||
MeshBuilder,
|
||||
Observable,
|
||||
PhysicsAggregate,
|
||||
PhysicsMotionType,
|
||||
PhysicsShapeType,
|
||||
Scene,
|
||||
SceneLoader,
|
||||
TransformNode,
|
||||
Skeleton,
|
||||
Vector2,
|
||||
Vector3
|
||||
} from "@babylonjs/core";
|
||||
|
||||
export class PlayerFactory {
|
||||
public onReadyObservable: Observable<any> = new Observable();
|
||||
private readonly scene: Scene;
|
||||
private container: AssetContainer;
|
||||
|
||||
constructor(scene: Scene) {
|
||||
this.scene = scene;
|
||||
SceneLoader.LoadAssetContainer("/assets/models/",
|
||||
"player2.glb",
|
||||
this.scene,
|
||||
(container: AssetContainer) => {
|
||||
this.container = container;
|
||||
this.onReadyObservable.notifyObservers(this);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
public buildPlayer(position: Vector3, number: number, teamName: string = "team"): Player {
|
||||
return new Player(this.scene, position, this.container, number, teamName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class Player {
|
||||
public readonly onReadyObservable: Observable<any> = new Observable();
|
||||
private readonly scene: Scene;
|
||||
private readonly position: Vector3;
|
||||
private mesh: TransformNode;
|
||||
private position: Vector3;
|
||||
private mesh: Mesh;
|
||||
private parent: AbstractMesh;
|
||||
private animationGroup: AnimationGroup;
|
||||
private physicsAggregate: PhysicsAggregate;
|
||||
private skeleton: Skeleton;
|
||||
private number: number;
|
||||
private teamName: string;
|
||||
private forward = true;
|
||||
private destination: Vector2;
|
||||
|
||||
constructor(scene: Scene, position: Vector3) {
|
||||
constructor(scene: Scene, position: Vector3, container: AssetContainer, number: number = 0, teamName: string = "team") {
|
||||
this.scene = scene;
|
||||
this.position = position;
|
||||
this.number = number;
|
||||
this.teamName = teamName;
|
||||
const data = container.instantiateModelsToScene(undefined, false, {doNotInstantiate: true});
|
||||
this.mesh = (data.rootNodes[0] as Mesh);
|
||||
this.skeleton = data.skeletons[0];
|
||||
this.animationGroup = data.animationGroups[6];
|
||||
this.buildPlayer();
|
||||
}
|
||||
|
||||
buildPlayer() {
|
||||
SceneLoader.ImportMesh(null, "/assets/models/", "player2.glb", this.scene,
|
||||
(meshes, particleSystems, skeletons, animationGroups) => {
|
||||
this.mesh = meshes[0];
|
||||
this.parent = MeshBuilder.CreateCylinder("playerParent", {diameter: .5, height: 1.6}, this.scene);
|
||||
this.parent.position = this.position;
|
||||
this.parent.isVisible = false;
|
||||
this.physicsAggregate = new PhysicsAggregate(this.parent,
|
||||
PhysicsShapeType.CYLINDER, {mass: 50, restitution: .02, friction: 0}, this.scene);
|
||||
animationGroups[0].stop();
|
||||
public lookAt(location: Vector2) {
|
||||
const body = this.physicsAggregate.body;
|
||||
|
||||
this.animationGroup = animationGroups[6];
|
||||
this.animationGroup.start(false, 1, 266, 266);
|
||||
this.mesh.setParent(this.physicsAggregate.transformNode);
|
||||
this.mesh.position.x = 3;
|
||||
this.mesh.position.y = -.84;
|
||||
this.onReadyObservable.notifyObservers(this);
|
||||
});
|
||||
body.disablePreStep = false;
|
||||
|
||||
body.transformNode.lookAt(new Vector3(location.x, body.transformNode.position.y, location.y));
|
||||
this.scene.onAfterRenderObservable.addOnce(() => {
|
||||
|
||||
this.physicsAggregate.body.disablePreStep = true;
|
||||
this.animationGroup.stop();
|
||||
this.animationGroup.onAnimationGroupEndObservable.add(() => {
|
||||
if (this.forward) {
|
||||
this.animationGroup.start(false, .1, 256, 267);
|
||||
} else {
|
||||
this.animationGroup.start(false, .1, 267, 256);
|
||||
}
|
||||
this.forward = !this.forward;
|
||||
}, -1, false, this);
|
||||
this.animationGroup.start(false, .1, 256, 267);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
public runTo(location: Vector2) {
|
||||
this.animationGroup.stop();
|
||||
this.animationGroup.start(true, 1.5, 0, 250);
|
||||
this.physicsAggregate.body.transformNode.lookAt(new Vector3(location.x, 2, location.y));
|
||||
const speed = location.normalize().scale(2);
|
||||
this.physicsAggregate.body.setLinearVelocity(new Vector3(0, 0, 3));
|
||||
//this.physicsAggregate.body.setAngularVelocity(new Vector3(0, .1, 0));
|
||||
|
||||
this.destination = location;
|
||||
const body = this.physicsAggregate.transformNode.physicsBody;
|
||||
body.setMotionType(PhysicsMotionType.ANIMATED);
|
||||
body.disablePreStep = false;
|
||||
body.transformNode.lookAt(new Vector3(location.x, body.transformNode.position.y, location.y));
|
||||
const vel = new Vector3(location.x, body.transformNode.position.y, location.y);
|
||||
this.scene.onBeforeRenderObservable.addOnce(() => {
|
||||
body.setLinearVelocity(vel.subtract(body.transformNode.position).normalize().scale(2));
|
||||
});
|
||||
this.scene.onAfterRenderObservable.addOnce(() => {
|
||||
this.physicsAggregate.body.disablePreStep = true;
|
||||
this.animationGroup.stop();
|
||||
this.animationGroup.start(true, 1.0, 0, 250);
|
||||
});
|
||||
this.scene.onAfterPhysicsObservable.add(() => {
|
||||
if (body.getLinearVelocity().length() > .1) {
|
||||
console.log(this.destination.subtract(new Vector2(body.transformNode.position.x,
|
||||
body.transformNode.position.z)).length());
|
||||
if (this.destination.subtract(new Vector2(body.transformNode.position.x,
|
||||
body.transformNode.position.z)).length() < .1) {
|
||||
body.setLinearVelocity(Vector3.Zero());
|
||||
body.setMotionType(PhysicsMotionType.DYNAMIC);
|
||||
this.animationGroup.stop();
|
||||
this.animationGroup.start(false, .1, 256, 267);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private buildPlayer() {
|
||||
this.parent = MeshBuilder.CreateCylinder(`team${this.teamName}player${this.number}`, {
|
||||
diameter: .5,
|
||||
height: 1.6
|
||||
}, this.scene);
|
||||
this.parent.position = this.position;
|
||||
this.parent.isVisible = false;
|
||||
this.physicsAggregate = new PhysicsAggregate(this.parent,
|
||||
PhysicsShapeType.CYLINDER, {mass: 100, restitution: .02, friction: .3}, this.scene);
|
||||
this.physicsAggregate.body.setAngularDamping(.5);
|
||||
|
||||
this.mesh.parent = this.physicsAggregate.transformNode;
|
||||
this.mesh.metadata = {type: "player", grabbable: true};
|
||||
this.mesh.position.x = 3;
|
||||
this.mesh.position.y = -.84;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
import {Player, PlayerFactory} from "./player";
|
||||
import {Scene, Vector2, Vector3} from "@babylonjs/core";
|
||||
|
||||
export class Team {
|
||||
private readonly scene: Scene;
|
||||
private players: Player[] = [];
|
||||
private goalSide: number = -1;
|
||||
private playerFactory: PlayerFactory;
|
||||
private positions: Vector2[] = [
|
||||
new Vector2(3, 1),
|
||||
new Vector2(-3, 1),
|
||||
new Vector2(5, 2),
|
||||
new Vector2(15, 5),
|
||||
new Vector2(-15, 5),
|
||||
new Vector2(2, 10),
|
||||
new Vector2(-2, 15),
|
||||
new Vector2(15, 20),
|
||||
new Vector2(-15, 20),
|
||||
new Vector2(0, 35),
|
||||
new Vector2(0, 47),
|
||||
];
|
||||
|
||||
private name: string;
|
||||
|
||||
constructor(scene: Scene, side: number = 1, name: string = "team") {
|
||||
this.scene = scene;
|
||||
this.goalSide = side;
|
||||
this.name = name;
|
||||
this.playerFactory = new PlayerFactory(this.scene);
|
||||
this.playerFactory.onReadyObservable.add(() => {
|
||||
this.buildTeam();
|
||||
this.players[5].runTo(new Vector2(3, -3 * this.goalSide));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private buildTeam() {
|
||||
for (let i = 0; i < 11; i++) {
|
||||
const player = this.playerFactory
|
||||
.buildPlayer(new Vector3(this.positions[i].x * this.goalSide, 1, this.positions[i].y * this.goalSide), i,
|
||||
this.name);
|
||||
player.lookAt(new Vector2(0, -50 * this.goalSide))
|
||||
this.players.push(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user