From 8a805ce1a07eb20dd06bfad2fad36fe4405fffc9 Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Tue, 24 Jun 2025 23:43:07 -0400 Subject: [PATCH 1/7] Added Regular Bounce Animation: Not currently working yet --- ai_animation/src/units/animate.ts | 46 +++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index 79452cb..066a0bd 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -10,6 +10,9 @@ import { PowerENUM, ProvinceENUM } from "../types/map"; import { UnitTypeENUM } from "../types/units"; import { sineWave, getTimeInSeconds } from "../utils/timing"; + + + function getUnit(unitOrder: UnitOrder, power: string) { if (power === undefined) throw new Error("Must pass the power argument, cannot be undefined") let posUnits = gameState.unitMeshes.filter((unit) => { @@ -83,6 +86,42 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN return anim } +//Animation for bounce + +function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: ProvinceENUM): Tween { + const start = unitMesh.position.clone(); + const end = getProvincePosition(attemptedDestination); + if (!end) throw new Error(`No position found for attempted destination: ${attemptedDestination}`); + + unitMesh.userData.isAnimating = true; + + let bounceOut = new Tween(unitMesh.position) + .to({ x: end.x, y: 10, z: end.z }, config.effectiveAnimationDuration / 2) + .easing(Easing.Quadratic.Out) + .onComplete(() => { + console.log('bounceOut finished, should now trigger bounceBack'); + bounceBack.start(); + }); + + let bounceBack = new Tween(unitMesh.position) + .to({ x: start.x, y: 10, z: start.z }, config.effectiveAnimationDuration / 2) + .onStart((() => { + console.log('bounceBack started'); + })) + .onComplete(() => { + unitMesh.position.set(start.x, 10, start.z); + unitMesh.userData.isAnimating = false; + }); + + + bounceOut.start(); + + gameState.unitAnimations.push(bounceOut,bounceBack); + return bounceOut; +} + + + /** * Creates animations for unit movements based on orders from the previous phase * @@ -152,8 +191,11 @@ export function createAnimationsForNextPhase() { break; case "bounce": - // TODO: implement bounce animation - break; + if (unitIndex < 0) throw new Error("Unable to find unit for order " + order.raw) + if (!order.destination) throw new Error("Bounce order without destination") + createBounceAnimation(gameState.unitMeshes[unitIndex], order.destination as ProvinceENUM); + break; + case "hold": //TODO: Hold animation, maybe a sheild or something? break; From 7a8ae69c47dea420a30dbf1cbbc33f7adfe28254 Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Tue, 24 Jun 2025 23:45:58 -0400 Subject: [PATCH 2/7] Added Regular Bounce Animation: Not Currently Working --- ai_animation/src/units/animate.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index 066a0bd..8ead066 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -99,8 +99,7 @@ function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: Prov .to({ x: end.x, y: 10, z: end.z }, config.effectiveAnimationDuration / 2) .easing(Easing.Quadratic.Out) .onComplete(() => { - console.log('bounceOut finished, should now trigger bounceBack'); - bounceBack.start(); + console.log('bounceOut finished, should now trigger bounceBack');; }); let bounceBack = new Tween(unitMesh.position) @@ -113,7 +112,7 @@ function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: Prov unitMesh.userData.isAnimating = false; }); - + bounceOut.chain(bounceBack); bounceOut.start(); gameState.unitAnimations.push(bounceOut,bounceBack); From 316159ca6517a7ad10b3d42e8ace3d3220a908ae Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Sat, 28 Jun 2025 15:25:47 -0400 Subject: [PATCH 3/7] Basic Bounce Animation + Pointer Arrows on basic moves --- ai_animation/src/units/animate.ts | 46 ++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index 8ead066..a3d4052 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -12,6 +12,29 @@ import { sineWave, getTimeInSeconds } from "../utils/timing"; +//create an arrow from the unit’s current pos toward the target +function createMoveArrow( + scene: THREE.Scene, + unitMesh: THREE.Group, + destination: ProvinceENUM +): THREE.ArrowHelper { + const startPos = unitMesh.position.clone(); + const endPos = getProvincePosition(destination)!; + + // compute direction & length + const dir = new THREE.Vector3() + .subVectors(endPos, startPos) + const length = startPos.distanceTo(endPos) - 2; //subtract a bit so arrow tip doesn't overlap the unit + + const color = 0xFF0000 + + const arrow = new THREE.ArrowHelper(dir, startPos, length, color, 1, 0.5); + scene.add(arrow); + + unitMesh.userData.moveArrow = arrow; + return arrow; +} + function getUnit(unitOrder: UnitOrder, power: string) { if (power === undefined) throw new Error("Must pass the power argument, cannot be undefined") @@ -57,6 +80,8 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN // Store animation start time for consistent wave motion const animStartTime = getTimeInSeconds(); + const arrow = createMoveArrow(gameState.scene, unitMesh, orderDestination as ProvinceENUM); + let anim = new Tween(unitMesh.position) .to({ x: destinationVector.x, @@ -79,6 +104,10 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN unitMesh.rotation.z = 0; unitMesh.rotation.x = 0; } + if (unitMesh.userData.moveArrow) { + gameState.scene.remove(arrow); + delete unitMesh.userData.moveArrow; + } unitMesh.userData.isAnimating = false }) .start(); @@ -89,7 +118,7 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN //Animation for bounce function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: ProvinceENUM): Tween { - const start = unitMesh.position.clone(); + //const start = unitMesh.position.clone(); const end = getProvincePosition(attemptedDestination); if (!end) throw new Error(`No position found for attempted destination: ${attemptedDestination}`); @@ -98,24 +127,15 @@ function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: Prov let bounceOut = new Tween(unitMesh.position) .to({ x: end.x, y: 10, z: end.z }, config.effectiveAnimationDuration / 2) .easing(Easing.Quadratic.Out) + .repeat(1) + .yoyo(true) .onComplete(() => { console.log('bounceOut finished, should now trigger bounceBack');; }); - let bounceBack = new Tween(unitMesh.position) - .to({ x: start.x, y: 10, z: start.z }, config.effectiveAnimationDuration / 2) - .onStart((() => { - console.log('bounceBack started'); - })) - .onComplete(() => { - unitMesh.position.set(start.x, 10, start.z); - unitMesh.userData.isAnimating = false; - }); - - bounceOut.chain(bounceBack); bounceOut.start(); - gameState.unitAnimations.push(bounceOut,bounceBack); + gameState.unitAnimations.push(bounceOut); return bounceOut; } From d24fda8ae70549798ee17ea197e60e64bb862460 Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Sun, 29 Jun 2025 16:36:42 -0400 Subject: [PATCH 4/7] Bounce + Regular Move Arrows Given Unique Colors --- ai_animation/src/units/animate.ts | 40 +++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index a3d4052..9c1fe81 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -11,7 +11,6 @@ import { UnitTypeENUM } from "../types/units"; import { sineWave, getTimeInSeconds } from "../utils/timing"; - //create an arrow from the unit’s current pos toward the target function createMoveArrow( scene: THREE.Scene, @@ -21,10 +20,36 @@ function createMoveArrow( const startPos = unitMesh.position.clone(); const endPos = getProvincePosition(destination)!; + + // compute direction & length const dir = new THREE.Vector3() .subVectors(endPos, startPos) - const length = startPos.distanceTo(endPos) - 2; //subtract a bit so arrow tip doesn't overlap the unit + const length = startPos.distanceTo(endPos) - 2; //subtracted a bit so the arrow tip doesn't overlap the unit + + const color = 0x00FF00 + + const arrow = new THREE.ArrowHelper(dir, startPos, length, color, 1, 0.5); + scene.add(arrow); + + unitMesh.userData.moveArrow = arrow; + return arrow; +} + + +//Different color arrow for bounce to differentate moves (red=bounce, green=regular move) +function createBounceArrow( + scene: THREE.Scene, + unitMesh: THREE.Group, + destination: ProvinceENUM) + : THREE.ArrowHelper { + const startPos = unitMesh.position.clone(); + const endPos= getProvincePosition(destination)!; + + // compute direction & length + const dir = new THREE.Vector3() + .subVectors(endPos, startPos) + const length = startPos.distanceTo(endPos) - 2; //subtracted a bit so arrow tip doesn't overlap the unit const color = 0xFF0000 @@ -33,7 +58,7 @@ function createMoveArrow( unitMesh.userData.moveArrow = arrow; return arrow; -} + } function getUnit(unitOrder: UnitOrder, power: string) { @@ -118,19 +143,24 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN //Animation for bounce function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: ProvinceENUM): Tween { - //const start = unitMesh.position.clone(); const end = getProvincePosition(attemptedDestination); if (!end) throw new Error(`No position found for attempted destination: ${attemptedDestination}`); unitMesh.userData.isAnimating = true; + const arrow = createBounceArrow(gameState.scene, unitMesh, attemptedDestination as ProvinceENUM); + let bounceOut = new Tween(unitMesh.position) .to({ x: end.x, y: 10, z: end.z }, config.effectiveAnimationDuration / 2) .easing(Easing.Quadratic.Out) .repeat(1) .yoyo(true) .onComplete(() => { - console.log('bounceOut finished, should now trigger bounceBack');; + console.log('bounceOut finished, should now trigger bounceBack'); + if (unitMesh.userData.moveArrow) { + gameState.scene.remove(arrow); + delete unitMesh.userData.moveArrow; + } }); bounceOut.start(); From 17f249402656dbb170da873266fa6d32a25baa54 Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Sat, 12 Jul 2025 15:25:54 -0400 Subject: [PATCH 5/7] Added New Arrow Design + Grow Arrow Animation for Regular Movement --- ai_animation/src/units/animate.ts | 108 ++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 20 deletions(-) diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index 9c1fe81..dcd9f58 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -11,17 +11,39 @@ import { UnitTypeENUM } from "../types/units"; import { sineWave, getTimeInSeconds } from "../utils/timing"; +function buildFancyArrow(length: number, colorDeter: string): THREE.Mesh { + + const tw = 3.5; + const headLength = tw * 4; + const hw = tw * 4; + + const shape = new THREE.Shape() + .moveTo(0,tw/2) + .lineTo(length- headLength,tw/2) + .lineTo(length-headLength,hw/2) + .lineTo(length,0) + .lineTo(length-headLength,-hw/2) + .lineTo(length-headLength,-tw/2) + .lineTo(0,-tw/2) + .closePath(); + + const extrude= new THREE.ExtrudeGeometry(shape, {depth: 1}) + let mat: THREE.Material; + + if (colorDeter=='Move') { + mat = new THREE.MeshStandardMaterial({color: 0x00FF00}) + } else if (colorDeter=='Bounce') { + mat = new THREE.MeshStandardMaterial({color: 0xFF0000}) + } + const mesh= new THREE.Mesh(extrude, mat) + return mesh; +} + //create an arrow from the unit’s current pos toward the target -function createMoveArrow( - scene: THREE.Scene, - unitMesh: THREE.Group, - destination: ProvinceENUM -): THREE.ArrowHelper { +function createMoveArrow(scene: THREE.Scene, unitMesh: THREE.Group, destination: ProvinceENUM): THREE.ArrowHelper { const startPos = unitMesh.position.clone(); const endPos = getProvincePosition(destination)!; - - // compute direction & length const dir = new THREE.Vector3() .subVectors(endPos, startPos) @@ -105,9 +127,34 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN // Store animation start time for consistent wave motion const animStartTime = getTimeInSeconds(); - const arrow = createMoveArrow(gameState.scene, unitMesh, orderDestination as ProvinceENUM); + const start = new THREE.Vector3(); + //prevents the arrow mesh from using local coords which mess with the alignment + unitMesh.getWorldPosition(start); + const end = getProvincePosition(orderDestination)!; + //lines to determine direction and length of the arrow, minus a little from the length so it's offset + const direct= new THREE.Vector3().subVectors(end, start); + const length= Math.max(direct.length() - 2, 0); + const arrowMesh= buildFancyArrow(length,'Move'); + const dir = direct.clone().normalize(); + + arrowMesh.position.copy(start); - let anim = new Tween(unitMesh.position) + //Core of the arrow alignment, won't work without this + const q = new THREE.Quaternion().setFromUnitVectors( + new THREE.Vector3(1, 0, 0),dir + ); + arrowMesh.setRotationFromQuaternion(q); + + arrowMesh.scale.set(0, 1, 1); + + gameState.scene.add(arrowMesh); + unitMesh.userData.moveArrow = arrowMesh; +//Value beside x:1 controls the speed of the growth +const ArrowGrow = new Tween(arrowMesh.scale) + .to({ x: 1 }, 300) + .easing(Easing.Quadratic.Out) + .onComplete(() => { + const anim = new Tween(unitMesh.position) .to({ x: destinationVector.x, y: 10, @@ -129,37 +176,58 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN unitMesh.rotation.z = 0; unitMesh.rotation.x = 0; } - if (unitMesh.userData.moveArrow) { - gameState.scene.remove(arrow); - delete unitMesh.userData.moveArrow; - } + gameState.scene.remove(arrowMesh); + delete unitMesh.userData.moveArrow; unitMesh.userData.isAnimating = false }) .start(); - gameState.unitAnimations.push(anim); - return anim + gameState.unitAnimations.push(anim);}) + .start() + gameState.unitAnimations.push(ArrowGrow) + return ArrowGrow } //Animation for bounce function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: ProvinceENUM): Tween { - const end = getProvincePosition(attemptedDestination); + const end = getProvincePosition(attemptedDestination)!; if (!end) throw new Error(`No position found for attempted destination: ${attemptedDestination}`); unitMesh.userData.isAnimating = true; - const arrow = createBounceArrow(gameState.scene, unitMesh, attemptedDestination as ProvinceENUM); + + const start = new THREE.Vector3(); + //prevents the arrow mesh from using local coords which mess with the alignment + unitMesh.getWorldPosition(start); + //lines to determine direction and length of the arrow, minus a little from the length so it's offset + const direct= new THREE.Vector3().subVectors(end, start); + const length= Math.max(direct.length() - 2, 0); + const arrowMesh= buildFancyArrow(length,'Bounce'); + const dir = direct.clone().normalize(); + + arrowMesh.position.copy(start); - let bounceOut = new Tween(unitMesh.position) + //Core of the arrow alignment, won't work without this + const q = new THREE.Quaternion().setFromUnitVectors( + new THREE.Vector3(1, 0, 0), dir + ); + arrowMesh.setRotationFromQuaternion(q); + + //arrowMesh.scale.set(0, 1, 1); + + gameState.scene.add(arrowMesh); + unitMesh.userData.moveArrow = arrowMesh; + + const bounceOut = new Tween(unitMesh.position) .to({ x: end.x, y: 10, z: end.z }, config.effectiveAnimationDuration / 2) .easing(Easing.Quadratic.Out) .repeat(1) .yoyo(true) .onComplete(() => { - console.log('bounceOut finished, should now trigger bounceBack'); if (unitMesh.userData.moveArrow) { - gameState.scene.remove(arrow); + gameState.scene.remove(arrowMesh); delete unitMesh.userData.moveArrow; + unitMesh.userData.isAnimating = false } }); From 1b0a768603410f0705642ffc6bbe3a08c90411b1 Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:57:39 -0400 Subject: [PATCH 6/7] Added Hold Animation + Implemented Arrow Grow for Bounce Animation + Fixed Event Queue/ Pause Button --- ai_animation/src/types/events.ts | 7 +-- ai_animation/src/units/animate.ts | 80 ++++++++++++++++++++++++++++--- 2 files changed, 75 insertions(+), 12 deletions(-) diff --git a/ai_animation/src/types/events.ts b/ai_animation/src/types/events.ts index a3c98b5..e70d2e8 100644 --- a/ai_animation/src/types/events.ts +++ b/ai_animation/src/types/events.ts @@ -61,12 +61,7 @@ export class EventQueue { * Remove resolved events from the queue */ cleanup(): void { - let clearedQueue = this.events.filter(event => !event.resolved); - if (clearedQueue.length <= 1) { - console.log(this.events) - throw new Error("We've cleared all the messages out of the queue") - } - this.events = clearedQueue + this.events = this.events.filter(e => !e.resolved); } /** diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index dcd9f58..c47e6f1 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -9,10 +9,12 @@ import { config } from "../config"; // Assuming config is defined in a separate import { PowerENUM, ProvinceENUM } from "../types/map"; import { UnitTypeENUM } from "../types/units"; import { sineWave, getTimeInSeconds } from "../utils/timing"; +//import { color } from "chart.js/helpers"; +//import { depth } from "three/tsl"; function buildFancyArrow(length: number, colorDeter: string): THREE.Mesh { - +//Specs to change arrow size const tw = 3.5; const headLength = tw * 4; const hw = tw * 4; @@ -36,9 +38,38 @@ function buildFancyArrow(length: number, colorDeter: string): THREE.Mesh { mat = new THREE.MeshStandardMaterial({color: 0xFF0000}) } const mesh= new THREE.Mesh(extrude, mat) + //(Potential Addition: Outline of arrow) return mesh; } +function createShield() { + +//Shield Specs +const BSH= 10 +const SW= 10 +const TSH= 10 + + +const outL= new THREE.Shape() + .moveTo(0, TSH) + .lineTo(SW, TSH) + .lineTo(SW, 0) + .quadraticCurveTo(SW, -BSH, 0, -BSH) + .quadraticCurveTo(-SW, -BSH, -SW, 0) + .lineTo(-SW,TSH) + .lineTo(0, TSH) + .closePath(); + +const SExtrude= new THREE.ExtrudeGeometry(outL, {depth: 5}) + +const SMat= new THREE.MeshStandardMaterial({color: 0x00FF00}) + +const SMesh= new THREE.Mesh(SExtrude, SMat ) + +return SMesh + +} + //create an arrow from the unit’s current pos toward the target function createMoveArrow(scene: THREE.Scene, unitMesh: THREE.Group, destination: ProvinceENUM): THREE.ArrowHelper { const startPos = unitMesh.position.clone(); @@ -151,7 +182,7 @@ function createMoveAnimation(unitMesh: THREE.Group, orderDestination: ProvinceEN unitMesh.userData.moveArrow = arrowMesh; //Value beside x:1 controls the speed of the growth const ArrowGrow = new Tween(arrowMesh.scale) - .to({ x: 1 }, 300) + .to({ x: 1 }, 1000) .easing(Easing.Quadratic.Out) .onComplete(() => { const anim = new Tween(unitMesh.position) @@ -213,11 +244,15 @@ function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: Prov ); arrowMesh.setRotationFromQuaternion(q); - //arrowMesh.scale.set(0, 1, 1); + arrowMesh.scale.set(0, 1, 1); gameState.scene.add(arrowMesh); unitMesh.userData.moveArrow = arrowMesh; - + const growBounce= new Tween (arrowMesh.scale) + //Number beside x:1 controls speed in ms + .to({ x: 1 }, 1000) + .easing(Easing.Quadratic.Out) + .onComplete(() => { const bounceOut = new Tween(unitMesh.position) .to({ x: end.x, y: 10, z: end.z }, config.effectiveAnimationDuration / 2) .easing(Easing.Quadratic.Out) @@ -233,11 +268,43 @@ function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: Prov bounceOut.start(); - gameState.unitAnimations.push(bounceOut); - return bounceOut; + gameState.unitAnimations.push(bounceOut);}) + growBounce.start() + gameState.unitAnimations.push(growBounce) + return growBounce; } +function createHoldAnimation(unitMesh: THREE.Group): Tween { + +const newshield= createShield() + +const worldPos = new THREE.Vector3(); +unitMesh.getWorldPosition(worldPos); +newshield.position.set(worldPos.x, -20, worldPos.z+8); + gameState.scene.add(newshield); + unitMesh.userData.newshield = newshield; + +unitMesh.userData.isAnimating = true +const RiserS= new Tween (newshield.position) + .to({ x: worldPos.x, y: 20, z: worldPos.z+8}, 2000) + .easing(Easing.Quadratic.Out) + .onComplete(() => { + // parent under the unit so it moves with them + gameState.scene.remove(newshield); + delete unitMesh.userData.newshield; + unitMesh.userData.isAnimating = false + }) + .start(); + + // 5) make sure it's updated each frame + gameState.unitAnimations.push(RiserS); + + + + return RiserS; +} + /** * Creates animations for unit movements based on orders from the previous phase @@ -315,6 +382,7 @@ export function createAnimationsForNextPhase() { case "hold": //TODO: Hold animation, maybe a sheild or something? + createHoldAnimation(gameState.unitMeshes[unitIndex]) break; case "convoy": From 6e136d9c4e2b413b05e6ece4b6877dbe18668dfd Mon Sep 17 00:00:00 2001 From: zbates26 <156824196+zbates26@users.noreply.github.com> Date: Tue, 29 Jul 2025 09:58:55 -0400 Subject: [PATCH 7/7] Finished Shield + Quality of Life Changes --- .vscode/launch.json | 6 +-- .vscode/tasks.json | 14 +++++ ai_animation/src/units/animate.ts | 85 +++++++------------------------ 3 files changed, 36 insertions(+), 69 deletions(-) create mode 100644 .vscode/tasks.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 274ae86..e5eaf8a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,11 +4,11 @@ { "type": "pwa-chrome", "request": "launch", - "name": "Chrome Debug 5179", - "url": "http://localhost:5179", + "name": "Chrome Debug 5173", + "url": "http://localhost:5173", "webRoot": "${workspaceFolder}/ai_animation/", "sourceMapPathOverrides": { - "http://localhost:5179/*": "${webRoot}/*" + "http://localhost:5173/*": "${webRoot}/*" }, "runtimeArgs": [ "--remote-debugging-port=9223" diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..8497252 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,14 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Run Game", + "type": "shell", + "command": "npm start", + "presentation": { + "panel": "shared" + }, + "problemMatcher": [] + } + ] + } \ No newline at end of file diff --git a/ai_animation/src/units/animate.ts b/ai_animation/src/units/animate.ts index c47e6f1..0264808 100644 --- a/ai_animation/src/units/animate.ts +++ b/ai_animation/src/units/animate.ts @@ -70,50 +70,6 @@ return SMesh } -//create an arrow from the unit’s current pos toward the target -function createMoveArrow(scene: THREE.Scene, unitMesh: THREE.Group, destination: ProvinceENUM): THREE.ArrowHelper { - const startPos = unitMesh.position.clone(); - const endPos = getProvincePosition(destination)!; - - // compute direction & length - const dir = new THREE.Vector3() - .subVectors(endPos, startPos) - const length = startPos.distanceTo(endPos) - 2; //subtracted a bit so the arrow tip doesn't overlap the unit - - const color = 0x00FF00 - - const arrow = new THREE.ArrowHelper(dir, startPos, length, color, 1, 0.5); - scene.add(arrow); - - unitMesh.userData.moveArrow = arrow; - return arrow; -} - - -//Different color arrow for bounce to differentate moves (red=bounce, green=regular move) -function createBounceArrow( - scene: THREE.Scene, - unitMesh: THREE.Group, - destination: ProvinceENUM) - : THREE.ArrowHelper { - const startPos = unitMesh.position.clone(); - const endPos= getProvincePosition(destination)!; - - // compute direction & length - const dir = new THREE.Vector3() - .subVectors(endPos, startPos) - const length = startPos.distanceTo(endPos) - 2; //subtracted a bit so arrow tip doesn't overlap the unit - - const color = 0xFF0000 - - const arrow = new THREE.ArrowHelper(dir, startPos, length, color, 1, 0.5); - scene.add(arrow); - - unitMesh.userData.moveArrow = arrow; - return arrow; - } - - function getUnit(unitOrder: UnitOrder, power: string) { if (power === undefined) throw new Error("Must pass the power argument, cannot be undefined") let posUnits = gameState.unitMeshes.filter((unit) => { @@ -276,43 +232,40 @@ function createBounceAnimation(unitMesh: THREE.Group, attemptedDestination: Prov function createHoldAnimation(unitMesh: THREE.Group): Tween { + // 1) Build the shield mesh + const shield = createShield(); -const newshield= createShield() + // 2) Figure out where the unit’s feet are + const worldPos = new THREE.Vector3(); + unitMesh.getWorldPosition(worldPos); -const worldPos = new THREE.Vector3(); -unitMesh.getWorldPosition(worldPos); -newshield.position.set(worldPos.x, -20, worldPos.z+8); - gameState.scene.add(newshield); - unitMesh.userData.newshield = newshield; + shield.position.set(worldPos.x, 16, worldPos.z+8); + shield.scale.set(1, 0, 1); // collapse height -unitMesh.userData.isAnimating = true -const RiserS= new Tween (newshield.position) - .to({ x: worldPos.x, y: 20, z: worldPos.z+8}, 2000) + gameState.scene.add(shield); + unitMesh.userData.newshield = shield; + unitMesh.userData.isAnimating = true; + + const growTween = new Tween(shield.scale) + .to({ x: 1, y: 1, z: 1 }, 2000) .easing(Easing.Quadratic.Out) .onComplete(() => { - // parent under the unit so it moves with them - gameState.scene.remove(newshield); - delete unitMesh.userData.newshield; - unitMesh.userData.isAnimating = false + gameState.scene.remove(shield); + unitMesh.userData.isAnimating = false; }) .start(); - // 5) make sure it's updated each frame - gameState.unitAnimations.push(RiserS); - - - - return RiserS; -} - + gameState.unitAnimations.push(growTween); + return growTween; + } /** * Creates animations for unit movements based on orders from the previous phase * **/ export function createAnimationsForNextPhase() { let previousPhase = gameState.gameData?.phases[gameState.phaseIndex == 0 ? 0 : gameState.phaseIndex - 1] - + // const sequence = ["build", "disband", "hold", "move", "bounce", "retreat"] // Safety check - if no previous phase or no orders, return if (!previousPhase) { logger.log("No previous phase to animate");