From 0e6e0bdd1f13cac85da94ee28f14e9dacb0c85da Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Sun, 17 Sep 2023 09:16:56 -0500 Subject: [PATCH] Soccer Components. --- src/soccer/ball.ts | 71 ++++++++++++++++++++++++ src/soccer/field.ts | 129 +++++++++++++++++++++++++++++++++++++++++++ src/soccer/player.ts | 60 ++++++++++++++++++++ src/soccer/team.ts | 0 4 files changed, 260 insertions(+) create mode 100644 src/soccer/ball.ts create mode 100644 src/soccer/field.ts create mode 100644 src/soccer/player.ts create mode 100644 src/soccer/team.ts diff --git a/src/soccer/ball.ts b/src/soccer/ball.ts new file mode 100644 index 0000000..6083634 --- /dev/null +++ b/src/soccer/ball.ts @@ -0,0 +1,71 @@ +import { + AbstractMesh, + MeshBuilder, + PhysicsAggregate, + PhysicsShapeType, + Scene, + SceneLoader, + TransformNode, + Vector3 +} from "@babylonjs/core"; +import {ControllerEventType, Controllers} from "../controllers/controllers"; + +export class Ball { + private readonly scene: Scene; + private transformNode: TransformNode; + private mesh: AbstractMesh; + private position: Vector3 = new Vector3(0, .5, 0); + private parent: AbstractMesh; + private controllers: Controllers; + private physicsAggregate: PhysicsAggregate; + + constructor(scene: Scene) { + this.scene = scene; + this.buildBall(); + } + + public setControllers(controllers: Controllers) { + this.controllers = controllers; + this.controllers.controllerObserver.add((event) => { + if (event.type == ControllerEventType.MOTION) { + + } + }); + } + + public kick(direction: Vector3, force: number) { + this.physicsAggregate.body.applyImpulse(direction.scale(force), Vector3.Zero()); + } + + private buildBall() { + SceneLoader.ImportMesh(null, "/assets/models/", "ball.gltf", this.scene, + (meshes, particleSystems, skeletons, animationGroups) => { + console.log('ball loaded'); + this.mesh = meshes[0]; + this.parent = MeshBuilder.CreateSphere("ballParent", {diameter: .17}, this.scene); + + this.parent.isVisible = false; + this.parent.position = this.position; + + this.scene.onBeforeRenderObservable.add(() => { + if (!this.physicsAggregate && + 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); + this.mesh.setParent(this.physicsAggregate.transformNode); + this.mesh.position.y = 0; + return; + } + }, -1, false, this, false); + + //animationGroups[0].stop(); + + //this.animationGroup = animationGroups[6]; + //this.animationGroup.start(false, 1, 266, 266); + + + }); + } +} \ No newline at end of file diff --git a/src/soccer/field.ts b/src/soccer/field.ts new file mode 100644 index 0000000..8210230 --- /dev/null +++ b/src/soccer/field.ts @@ -0,0 +1,129 @@ +import {InstancedMesh, Mesh, MeshBuilder, Scene, StandardMaterial, Vector2, Vector3} from "@babylonjs/core"; +import {Ball} from "./ball"; +import {Rigplatform} from "../controllers/rigplatform"; + +export class Field { + private readonly scene: Scene; + private ball: Ball; + private rig: Rigplatform; + private goalMesh: Mesh; + private material: StandardMaterial; + + constructor(scene: Scene) { + this.scene = scene; + 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.buildField(); + } + + public addBall(ball: Ball) { + this.ball = ball; + } + + public addRig(rig: Rigplatform) { + this.rig = rig; + + } + + private buildField() { + const width = .08; + this.buildLine(new Vector2(35, 0), new Vector2(width, 100)); + this.buildLine(new Vector2(-35, 0), new Vector2(width, 100)); + this.buildLine(new Vector2(-9.16, 50 - 2.75), new Vector2(width, 5.5 - width)); + this.buildLine(new Vector2(9.16, 50 - 2.75), new Vector2(width, 5.5 - width)); + this.buildLine(new Vector2(-9.16, -50 + 2.75), new Vector2(width, 5.5 - width)); + this.buildLine(new Vector2(9.16, -50 + 2.75), new Vector2(width, 5.5 - width)); + + 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(-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)); + + this.buildLine(new Vector2(0, -44.5), new Vector2(18.32 + width, width)); + this.buildLine(new Vector2(0, 44.5), new Vector2(18.32 + width, width)); + + this.buildLine(new Vector2(0, -33.5), new Vector2(36.66 + width, width)); + this.buildLine(new Vector2(0, 33.5), new Vector2(36.66 + width, width)); + + this.buildCircle(new Vector2(0, 50 - 11)); + this.buildCircle(new Vector2(0, -50 + 11)); + + + this.buildLine(new Vector2(0, 0), new Vector2(70 - width, width)); + this.buildArc(new Vector2(0, 0)); + this.buildArc(new Vector2(0, 50 - 11), Math.PI / 11, Math.PI / 1.275); + this.buildArc(new Vector2(0, -50 + 11), Math.PI / 11, (Math.PI / 1.275) - Math.PI); + this.buildGoalPost(new Vector2(3.66, -50)); + this.buildGoalPost(new Vector2(-3.66, -50)); + this.buildGoalPost(new Vector2(3.66, 50)); + this.buildGoalPost(new Vector2(-3.66, 50)); + this.buildGoalPost(new Vector2(0, 50), false, 7.32, 2.44); + this.buildGoalPost(new Vector2(0, -50), false, 7.32, 2.44); + + + } + + private buildGoalPost(position: Vector2, vertical: boolean = true, length: number = 2.44, y: number = 0) { + const goalPost = new InstancedMesh("goalPost", this.goalMesh); + goalPost.position.x = position.x; + goalPost.position.z = position.y; + if (!vertical) { + goalPost.rotation.z = Math.PI / 2; + goalPost.position.y = y; + } else { + goalPost.position.y = length / 2; + } + goalPost.scaling.y = length; + goalPost.visibility = 1; + } + + private buildCircle(position: Vector2) { + const circle = MeshBuilder.CreateDisc("disc", {radius: .25, tessellation: 180}, this.scene); + circle.position.x = position.x; + circle.position.z = position.y; + circle.position.y = .01; + circle.rotation.x = Math.PI / 2; + circle.material = this.getMaterial(); + } + + private buildArc(position: Vector2, arc: number = Math.PI, rotation: number = 0) { + const myShape = [ + new Vector3(1, 0, 0), + new Vector3(1, 0, 1.012), + new Vector3(.975, 0, 1.012) + ]; + const circle = MeshBuilder.CreateLathe("lathe", { + arc: arc, + shape: myShape, radius: 9.15, tessellation: 180 + }, this.scene); + circle.material = this.getMaterial(); + circle.position.y = 0.01; + circle.position.x = position.x; + circle.position.z = position.y; + circle.rotation = new Vector3(0, rotation, 0); + } + + private getMaterial(): StandardMaterial { + const material = new StandardMaterial("material", this.scene); + material.diffuseColor.set(1, 1, 1); + material.alpha = .5; + return material; + } + + private buildLine(position: Vector2, shape: Vector2) { + const line = MeshBuilder.CreatePlane("line", {width: shape.x, height: shape.y}, this.scene); + line.material = this.getMaterial(); + line.rotation.x = Math.PI / 2; + line.position.y = .01; + line.position.x = position.x; + line.position.z = position.y; + } +} \ No newline at end of file diff --git a/src/soccer/player.ts b/src/soccer/player.ts new file mode 100644 index 0000000..9bde462 --- /dev/null +++ b/src/soccer/player.ts @@ -0,0 +1,60 @@ +import { + AbstractMesh, + AnimationGroup, + MeshBuilder, + Observable, + PhysicsAggregate, + PhysicsShapeType, + Scene, + SceneLoader, + TransformNode, + Vector2, + Vector3 +} from "@babylonjs/core"; + +export class Player { + public readonly onReadyObservable: Observable = new Observable(); + private readonly scene: Scene; + private readonly position: Vector3; + private mesh: TransformNode; + private parent: AbstractMesh; + private animationGroup: AnimationGroup; + private physicsAggregate: PhysicsAggregate; + + constructor(scene: Scene, position: Vector3) { + this.scene = scene; + this.position = position; + 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(); + + 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); + }); + } + + 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)); + + + } +} \ No newline at end of file diff --git a/src/soccer/team.ts b/src/soccer/team.ts new file mode 100644 index 0000000..e69de29