Created
July 23, 2025 02:00
-
-
Save agrancini-sc/61fcf6888fb6071446bb736c6041714e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// INSTANTIATE | |
// @typename Instantiator | |
// @input Instantiator instantiator | |
// @input Instantiator instantiator1 | |
//@input Component.SceneObject sceneRoot | |
//@input Component.SceneObject sceneRoot1 | |
//@input Component.ScriptComponent prefabAccessorA | |
//@input Component.ScriptComponent prefabAccessorB | |
//@input Asset.ObjectPrefab[] prefabs | |
// Dictionary to keep track of instantiated prefabs | |
var instantiatedPrefabs = {}; | |
// Function to instantiate a prefab based on name | |
function instantiatePrefab(prefabName) { | |
// Destroy any existing prefab first to avoid duplicates | |
// if (instantiatedPrefabs[prefabName]) { | |
// destroyPrefab(prefabName); | |
// } | |
// Switch case for different crate instantiation | |
switch (prefabName) { | |
case "crateB1": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[0]); | |
break; | |
case "crateB1a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[2]); | |
break; | |
case "crateB2": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[1]); | |
break; | |
case "crateB2a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[3]); | |
break; | |
case "crateXL": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[12]); | |
break; | |
case "crateXLa": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[13]); | |
break; | |
case "crateM1": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[4]); | |
break; | |
case "crateM1a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[11]); | |
break; | |
case "crateM2": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[5]); | |
break; | |
case "crateM2a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[6]); | |
break; | |
case "crateM3": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[7]); | |
break; | |
case "crateM3a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[8]); | |
break; | |
case "crateM4": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[9]); | |
break; | |
case "crateM4a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[10]); | |
break; | |
// Add Slices objects | |
case "SlicesP1": | |
case "sliceP1": | |
print("DEBUG: Attempting to instantiate SlicesP1 with prefab index 14"); | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[14]); | |
break; | |
case "SlicesP1a": | |
case "sliceP1a": | |
print("DEBUG: Attempting to instantiate SlicesP1a with prefab index 15"); | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[15]); | |
break; | |
case "SlicesP2": | |
case "sliceP2": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[16]); | |
break; | |
case "SlicesP2a": | |
case "sliceP2a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[17]); | |
break; | |
case "SlicesP3": | |
case "sliceP3": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[18]); | |
break; | |
case "SlicesP3a": | |
case "sliceP3a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[19]); | |
break; | |
// Add Ballons objects | |
case "BallonsM1": | |
case "ballonM1": | |
print("DEBUG: Attempting to instantiate BallonsM1 with prefab index 20"); | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[20]); | |
break; | |
case "BallonsM1a": | |
case "ballonM1a": | |
print("DEBUG: Attempting to instantiate BallonsM1a with prefab index 21"); | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[21]); | |
break; | |
case "BallonsM2": | |
case "ballonM2": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[22]); | |
break; | |
case "BallonsM2a": | |
case "ballonM2a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[23]); | |
break; | |
case "BallonsM3": | |
case "ballonM3": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[24]); | |
break; | |
case "BallonsM3a": | |
case "ballonM3a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[25]); | |
break; | |
case "BallonsM4": | |
case "ballonM4": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[26]); | |
break; | |
case "BallonsM4a": | |
case "ballonM4a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[27]); | |
break; | |
case "BallonsM5": | |
case "ballonM5": | |
script.prefabAccessorA.InstantiatorPrefab(script.prefabs[28]); | |
break; | |
case "BallonsM5a": | |
case "ballonM5a": | |
script.prefabAccessorB.InstantiatorPrefab(script.prefabs[29]); | |
break; | |
default: | |
print("No specific instantiation logic for: " + prefabName); | |
return null; | |
} | |
} | |
// Function to destroy a specific prefab instance | |
function destroyPrefab(prefabName, PA) { | |
try { | |
// Check if the prefab is currently instantiated | |
if (script.prefabAccessorA && script.prefabAccessorB ) { | |
// PrefabDestroy.destroy(); | |
// delete instantiatedPrefabs[prefabName]; | |
if(PA == 1){ | |
script.prefabAccessorA.destroyInstances(prefabName, PA); | |
}else if (PA == 2){ | |
script.prefabAccessorB.destroyInstances(prefabName, PA); | |
} | |
// print(prefabName +" prefab destroyed"); | |
} else { | |
print("No instantiated prefab found with name: " + prefabName); | |
} | |
} catch (error) { | |
print("Error destroying prefab " + prefabName + ": " + error); | |
} | |
} | |
function instantiatePrefabx(prefabName) { | |
// Destroy any existing prefab first to avoid duplicates | |
// if (instantiatedPrefabs[prefabName]) { | |
// destroyPrefab(prefabName); | |
// } | |
// Switch case for different crate instantiation | |
switch (prefabName) { | |
case "crateB1": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[0]); | |
break; | |
case "crateB1a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[2]); | |
break; | |
case "crateB2": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[1]); | |
break; | |
case "crateB2a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[3]); | |
break; | |
case "crateXL": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[12]); | |
break; | |
case "crateXLa": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[13]); | |
break; | |
case "crateM1": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[4]); | |
break; | |
case "crateM1a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[11]); | |
break; | |
case "crateM2": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[5]); | |
break; | |
case "crateM2a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[6]); | |
break; | |
case "crateM3": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[7]); | |
break; | |
case "crateM3a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[8]); | |
break; | |
case "crateM4": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[9]); | |
break; | |
case "crateM4a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[10]); | |
break; | |
// Add Slices objects for InstantiatorPrefabx | |
case "SlicesP1": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[14]); | |
break; | |
case "SlicesP1a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[15]); | |
break; | |
case "SlicesP2": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[16]); | |
break; | |
case "SlicesP2a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[17]); | |
break; | |
case "SlicesP3": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[18]); | |
break; | |
case "SlicesP3a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[19]); | |
break; | |
// Add Ballons objects for InstantiatorPrefabx | |
case "BallonsM1": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[20]); | |
break; | |
case "BallonsM1a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[21]); | |
break; | |
case "BallonsM2": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[22]); | |
break; | |
case "BallonsM2a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[23]); | |
break; | |
case "BallonsM3": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[24]); | |
break; | |
case "BallonsM3a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[25]); | |
break; | |
case "BallonsM4": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[26]); | |
break; | |
case "BallonsM4a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[27]); | |
break; | |
case "BallonsM5": | |
script.prefabAccessorA.InstantiatorPrefabx(script.prefabs[28]); | |
break; | |
case "BallonsM5a": | |
script.prefabAccessorB.InstantiatorPrefabx(script.prefabs[29]); | |
break; | |
default: | |
print("No specific instantiation logic for: " + prefabName); | |
return null; | |
} | |
} | |
// Expose functions globally | |
global.instantiatePrefab = instantiatePrefab; | |
global.destroyPrefab = destroyPrefab; | |
global.instantiatePrefabx = instantiatePrefabx; | |
// global.destroyPrefab("crateB1"); | |
// PREFAB ACCESSOR | |
import {InstantiationOptions, Instantiator} from "./SpectaclesSyncKit/Components/Instantiator" | |
import {NetworkRootInfo} from "./SpectaclesSyncKit/Core/NetworkRootInfo" | |
import {SyncKitLogger} from "./SpectaclesSyncKit/Utils/SyncKitLogger" | |
import { SyncEntity } from "./SpectaclesSyncKit/Core/SyncEntity" | |
@component | |
export class InstantiateTestA extends BaseScriptComponent { | |
private readonly log: SyncKitLogger = new SyncKitLogger( | |
InstantiateTestA.name | |
) | |
@input() instantiator: Instantiator | |
@input() claimOwnership: boolean = false | |
instantiatedObjects: SceneObject[]=[] | |
@input("Component.ScriptComponent") Surface: any; | |
@input("Component.ScriptComponent") stageManager: any; | |
i = 0; | |
private syncEntity: SyncEntity = null | |
onAwake() { | |
this.syncEntity = new SyncEntity(this) | |
} | |
InstantiatorPrefab(prefab) { | |
const options = new InstantiationOptions() | |
options.claimOwnership = this.claimOwnership | |
// Get the transform to access current position | |
const transform = this.sceneObject.getTransform(); | |
const groundPosition = transform.getWorldPosition(); | |
// Get the Y position from the Surface | |
let Y = this.Surface.getYPos(); | |
print(Y); | |
// Set the position in the options using original X and Z coordinates with Y from Surface | |
options.worldPosition = new vec3(groundPosition.x, Y-140, groundPosition.z); | |
this.instantiator.instantiate(prefab, options, (instantiatedEntity) => { | |
if (!instantiatedEntity) { | |
print("Failed to instantiate the prefab.") | |
return | |
} | |
print("Prefab instantiated successfully.") | |
// Store instantiated prefab into an array | |
this.instantiatedObjects.push(instantiatedEntity.sceneObject) | |
if(this.i == 6){ | |
this.instantiatedObjects.forEach((obj) => { | |
print("In Objects: " + obj.name); | |
var index = this.instantiatedObjects.findIndex(obj => { | |
// Extract the base name by splitting at colon and underscore | |
print("Object Instantiated Name"+ obj.name ); | |
const parts = obj.name.split(':'); | |
// if (parts.length < 2) return false; | |
const baseName = parts[1].split('_')[0]; | |
print(baseName); | |
}); | |
}); | |
}else{ | |
this.i++; | |
} | |
print(instantiatedEntity.sceneObject.getChildrenCount()) | |
}) | |
} | |
InstantiatorPrefabx(prefab) { | |
const options = new InstantiationOptions() | |
options.claimOwnership = this.claimOwnership | |
// Get the transform to access current position | |
const transform = this.sceneObject.getTransform(); | |
const groundPosition = transform.getWorldPosition(); | |
// Get the Y position from the Surface | |
let Y = this.Surface.getYPos(); | |
print(Y); | |
// Set the position in the options using original X and Z coordinates with Y from Surface | |
options.worldPosition = new vec3(groundPosition.x, Y+70, groundPosition.z); | |
this.instantiator.instantiate(prefab, options, (instantiatedEntity) => { | |
if (!instantiatedEntity) { | |
print("Failed to instantiate the prefab.") | |
return | |
} | |
print("Prefab instantiated successfully.") | |
// Store instantiated prefab into an array | |
this.instantiatedObjects.push(instantiatedEntity.sceneObject) | |
if(this.i == 6){ | |
this.instantiatedObjects.forEach((obj) => { | |
print("In Objects: " + obj.name); | |
var index = this.instantiatedObjects.findIndex(obj => { | |
// Extract the base name by splitting at colon and underscore | |
print("Object Instantiated Name"+ obj.name ); | |
const parts = obj.name.split(':'); | |
// if (parts.length < 2) return false; | |
const baseName = parts[1].split('_')[0]; | |
print(baseName); | |
}); | |
}); | |
}else{ | |
this.i++; | |
} | |
print(instantiatedEntity.sceneObject.getChildrenCount()) | |
}) | |
} | |
destroyInstances(prefabName: string, PA) { | |
try { | |
// First, log all object names to see what we're working with | |
print("Looking for prefab with name: " + prefabName); | |
// Try a more flexible search pattern | |
const index = this.instantiatedObjects.findIndex(obj => { | |
// Log the full name first | |
print("Checking object: " + obj.name); | |
// Try various ways to extract the base name | |
const colonParts = obj.name.split(':'); | |
const namePart = colonParts.length > 1 ? colonParts[1] : obj.name; | |
const baseName = namePart.split('_')[0]; | |
print("Extracted base name: " + baseName); | |
// Check if the base name contains or matches the target prefab name | |
return baseName === prefabName || baseName.includes(prefabName) || prefabName.includes(baseName); | |
}); | |
if (index !== -1) { | |
const obj = this.instantiatedObjects[index]; | |
print("Found object to destroy: " + obj.name); | |
if (!isNull(obj)) { | |
// Completely destroy the object instance | |
print("Destroying object instance: " + obj.name); | |
obj.destroy(); | |
// Remove the prefab from the array | |
this.instantiatedObjects.splice(index, 1); | |
} | |
return true; | |
} else { | |
print("Prefab with name '" + prefabName + "' not found after searching."); | |
return false; | |
} | |
} catch (error) { | |
print("Error in destroyInstances for " + prefabName + ": " + error); | |
return false; | |
} | |
} | |
} | |
// SET HIT STATE | |
// SetHitState.js | |
// Version: 0.1.0 | |
// Event: Initialized | |
// Description: This script sets Chick from Kinematic State to Hit State. | |
//@input SceneObject hit | |
//@input SceneObject cameraNear | |
//@input SceneObject rayEnd | |
//@input vec3 physicsApplyForceForceValue | |
//@input string physicsApplyForceSpace "Local to Object" | |
//@input SceneObject physicsApplyForceObjectSpace | |
//@input Component.ScriptComponent SyncTransR2D2 | |
//@input Component.ScriptComponent characterHealthManager // Reference to the CharacterHealthManager script | |
// @input Component.AudioComponent pullAudio | |
// @input Component.AudioComponent pushAudio | |
// @input Component.ScriptComponent R2D2Movement | |
//@input Component.ScriptComponent forceEnergyManager // Reference to the ForceEnergyManager script | |
//@input Component.ScriptComponent stageManager // Reference to the StageManager script | |
// Custom force values for different object types | |
//@input vec3 balloonForceValue | |
//@input vec3 sliceForceValue | |
var CanPull = true; | |
global.HitOnce = 0; | |
var obj = script.getSceneObject(); | |
script.hit.enabled = false; | |
script.pullF = function(){ | |
global.ForceState = "pull"; | |
global.HitOnce = 0; | |
} | |
script.pushF = function(){ | |
global.ForceState = "push"; | |
} | |
script.noneF = function(){ | |
global.ForceState = "none"; | |
} | |
// Set phyics body to dynamic, detach rotating parent with current position and pause the animation | |
script.setHitState = function(bodyComponent) { | |
if(!bodyComponent){ | |
// No body component detected | |
} else if(bodyComponent){ | |
var objectName = bodyComponent.getSceneObject().name; | |
if(global.ForceState == "pull" && script.forceEnergyManager.hasEnoughEnergy(objectName)){ | |
// Check if we have enough force energy for pulling this object | |
script.hit.enabled = true; | |
if(global.HitOnce == 0){ | |
global.prevModel = bodyComponent; | |
pull(bodyComponent); | |
global.HitOnce=1; | |
} else if(global.HitOnce == 1){ | |
// Already pulling something | |
} | |
} else if(global.ForceState == "push"){ | |
// Check if we have enough force energy for pushing this object | |
script.hit.enabled = true; | |
global.HitOnce=0; | |
EventStatusPull = "off"; | |
} else if(global.ForceState == "none"){ | |
script.hit.enabled = false; | |
} | |
} | |
}; | |
function pull(bodyComponent){ | |
let object = bodyComponent.getSceneObject(); | |
let nameObj = bodyComponent.getSceneObject().name; | |
script.forceEnergyManager.consumeEnergyCopy(nameObj); | |
print(nameObj); | |
switch (nameObj) { | |
case "R2D2": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
script.SyncTransR2D2.startFullSynchronization(); | |
script.R2D2Movement.stopMovement(); | |
break; | |
case "crateB1": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateB1 = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateB1.startFullSynchronization(); | |
break; | |
case "crateB2": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateB2 = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateB2.startFullSynchronization(); | |
break; | |
case "crateXL": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateXL = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateXL.startFullSynchronization(); | |
break; | |
case "crateM1": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM1 = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM1.startFullSynchronization(); | |
break; | |
case "crateM2": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM2 = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM2.startFullSynchronization(); | |
break; | |
case "crateM3": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM3 = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM3.startFullSynchronization(); | |
break; | |
case "crateM4": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM4 = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM4.startFullSynchronization(); | |
break; | |
case "crateB1a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateB1a = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateB1a.startFullSynchronization(); | |
break; | |
case "crateB2a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateB2a = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateB2a.startFullSynchronization(); | |
break; | |
case "crateXLa": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateXLa = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateXLa.startFullSynchronization(); | |
break; | |
case "crateM1a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM1a = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM1a.startFullSynchronization(); | |
break; | |
case "crateM2a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM2a = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM2a.startFullSynchronization(); | |
break; | |
case "crateM3a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM3a = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM3a.startFullSynchronization(); | |
break; | |
case "crateM4a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTransCrateM4a = object.getComponent('Component.ScriptComponent'); | |
SyncTransCrateM4a.startFullSynchronization(); | |
break; | |
// Handle balloon objects | |
case "BallonsM1": | |
case "ballonM1": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM2": | |
case "ballonM2": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM3": | |
case "ballonM3": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM4": | |
case "ballonM4": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM5": | |
case "ballonM5": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM1a": | |
case "ballonM1a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM2a": | |
case "ballonM2a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM3a": | |
case "ballonM3a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM4a": | |
case "ballonM4a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "BallonsM5a": | |
case "ballonM5a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
// Handle slice objects | |
case "SlicesP1": | |
case "sliceP1": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "SlicesP2": | |
case "sliceP2": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "SlicesP3": | |
case "sliceP3": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "SlicesP1a": | |
case "sliceP1a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "SlicesP2a": | |
case "sliceP2a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
case "SlicesP3a": | |
case "sliceP3a": | |
var parent1 = object.getParent(); | |
var parentMain = parent1.getParent(); | |
var SyncTrans = object.getComponent('Component.ScriptComponent'); | |
if (SyncTrans) SyncTrans.startFullSynchronization(); | |
break; | |
default: | |
print("No matching animation found."); | |
} | |
script.pullAudio.play(1); | |
// Define start and end positions | |
var colliderObj = bodyComponent.getSceneObject(); | |
var transform = colliderObj.getTransform(); | |
print("Hit object: " + colliderObj.name); | |
var startPosition = transform.getWorldPosition(); | |
var transform1 = script.cameraNear.getTransform(); | |
print(startPosition); | |
var endPosition = transform1.getWorldPosition(); | |
print(endPosition); | |
// Define speed (units per second) | |
var speed = 650.0; | |
// Calculate direction | |
var direction = endPosition.sub(startPosition).normalize(); | |
global.EventStatusPull = "on"; | |
// Initialize current position | |
var currentPosition = startPosition; | |
roats(bodyComponent); | |
global.onTrack = true; | |
// Update function to be called every frame | |
function update(eventData) { | |
// Calculate the distance to move this frame | |
var distance = speed * eventData.getDeltaTime(); | |
// Update current position | |
currentPosition = currentPosition.add(direction.uniformScale(distance)); | |
// Check if the object has reached or passed the end position | |
if (currentPosition.distance(endPosition) < distance) { | |
EventStatusPull = "off"; | |
} | |
// Set the object's position | |
if(EventStatusPull == "on"){ | |
colliderObj.getTransform().setWorldPosition(currentPosition); | |
} else if(EventStatusPull == "off"){ | |
if(global.onTrack == true){ | |
currentPosition = transform1.getWorldPosition(); | |
colliderObj.getTransform().setWorldPosition(currentPosition); | |
} else { | |
updateEvent.enabled = false; | |
} | |
} | |
} | |
// Register the update function | |
var updateEvent = script.createEvent("UpdateEvent"); | |
updateEvent.bind(update); | |
} | |
function roats(bodyComponent){ | |
// Define start and end positions | |
var colliderObj = bodyComponent.getSceneObject(); | |
var transformto = colliderObj.getTransform(); | |
var transformfrom = script.cameraNear.getTransform(); | |
global.onRotate = true; | |
var rots; | |
// Update function to be called every frame | |
function update(eventData) { | |
if(global.onRotate == true){ | |
rots = transformfrom.getWorldRotation(); | |
transformto.setWorldRotation(transformfrom.getWorldRotation()); | |
} else { | |
transformto.setWorldRotation(rots); | |
updateEventR.enabled = false; | |
} | |
} | |
// Register the update function | |
var updateEventR = script.createEvent("UpdateEvent"); | |
updateEventR.bind(update); | |
} | |
function triggerPhysicsApplyForce(colliderObj1, physicsBody) { | |
//var body = getFallbackComponent(script.physicsApplyForceBody, "Physics.BodyComponent"); | |
var physicsApplyForceMode = "Set Velocity"; | |
if (!physicsBody) { | |
debugPrint("Physics Body must be set or present on SceneObject!"); | |
return; | |
} | |
script.pushAudio.play(1); | |
var velocityPropName; | |
var forceMethodName; | |
var physicsApplyForceForceType = "Position"; | |
switch (physicsApplyForceForceType) { | |
case "Position": | |
default: | |
velocityPropName = "velocity"; | |
forceMethodName = "addForce"; | |
break; | |
case "Rotation": | |
velocityPropName = "angularVelocity"; | |
forceMethodName = "addTorque"; | |
break; | |
} | |
// Get the default force value from script | |
var forceToApply = script.physicsApplyForceForceValue; | |
// Check object name to apply different force values | |
var objectName = colliderObj1.name.toLowerCase(); | |
// Use custom force values from script inputs if available | |
if (objectName.indexOf("ballon") !== -1 || objectName.indexOf("balloon") !== -1) { | |
// Use custom balloon force from script input if available | |
if (script.balloonForceValue) { | |
forceToApply = script.balloonForceValue; | |
print("Applying custom balloon force to: " + colliderObj1.name + " - " + forceToApply); | |
} | |
} else if (objectName.indexOf("slice") !== -1 || objectName.indexOf("pizza") !== -1) { | |
// Use custom slice force from script input if available | |
if (script.sliceForceValue) { | |
forceToApply = script.sliceForceValue; | |
print("Applying custom slice force to: " + colliderObj1.name + " - " + forceToApply); | |
} | |
} | |
// Otherwise, use the default force value from script.physicsApplyForceForceValue | |
var magnitude; | |
switch (script.physicsApplyForceSpace) { | |
case "World": | |
default: | |
break; | |
case "Local to Object": | |
magnitude = forceToApply.length; | |
forceToApply = (script.physicsApplyForceObjectSpace || colliderObj1).getTransform().getWorldTransform().multiplyDirection(forceToApply).normalize().uniformScale(magnitude); | |
break; | |
} | |
switch (physicsApplyForceMode) { | |
case "Force": | |
physicsBody[forceMethodName](forceToApply, Physics.ForceMode.Force); | |
break; | |
case "Acceleration": | |
physicsBody[forceMethodName](forceToApply, Physics.ForceMode.Acceleration); | |
break; | |
case "Impulse": | |
default: | |
physicsBody[forceMethodName](forceToApply, Physics.ForceMode.Impulse); | |
break; | |
case "VelocityChange": | |
physicsBody[forceMethodName](forceToApply, Physics.ForceMode.VelocityChange); | |
break; | |
case "Set Velocity": | |
physicsBody[velocityPropName] = forceToApply; | |
break; | |
} | |
} | |
// Helper function to destroy an object directly | |
function destroyObjectDirectly(objectName, PA) { | |
print("Attempting to destroy object: " + objectName + " with PA: " + PA); | |
// Add debug logging to check if prefabAccessors exist | |
if (!script.prefabAccessorA) { | |
print("ERROR: prefabAccessorA is not set!"); | |
} | |
if (!script.prefabAccessorB) { | |
print("ERROR: prefabAccessorB is not set!"); | |
} | |
// Directly destroy the prefab instance without scaling | |
try { | |
// Check if global.destroyPrefab exists before calling it | |
if (typeof global.destroyPrefab !== 'function') { | |
print("ERROR: global.destroyPrefab is not a function!"); | |
return; | |
} | |
global.destroyPrefab(objectName, PA); | |
print("Successfully called destroyPrefab for: " + objectName); | |
} catch (e) { | |
print("ERROR destroying object: " + e); | |
} | |
} | |
function pushin(){ | |
global.onRotate = false; | |
global.onTrack = false; | |
if(!global.prevModel) { | |
return; | |
} else if(global.prevModel.getSceneObject()) { | |
var colliderObj1 = global.prevModel.getSceneObject(); | |
var physicsBody = colliderObj1.getComponent("Physics.BodyComponent"); | |
let nameObjPush = global.prevModel.getSceneObject().name; | |
print(nameObjPush); | |
if(script.forceEnergyManager.hasEnoughEnergy(nameObjPush)) { | |
script.forceEnergyManager.consumeEnergyCopy(nameObjPush); | |
switch (nameObjPush) { | |
case "R2D2": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
print("d"); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateB1": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
print("rest"); | |
destroyObjectDirectly("cratesB1", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateB2": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesB2", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateXL": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesXL", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM1": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM1", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM2": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM2", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM3": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM3", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM4": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM4", 1); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateB1a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesB1a", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateB2a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesB2a", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateXLa": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesXLa", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM1a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM1a", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM2a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM2a", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM3a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM3a", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
case "crateM4a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("cratesM4a", 2); | |
}); | |
delayedEvent.reset(4); | |
break; | |
// Handle balloon objects | |
case "BallonsM1": | |
case "ballonM1": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM1s", 1); | |
}); | |
delayedEvent.reset(6); // Longer time before destruction | |
break; | |
case "BallonsM2": | |
case "ballonM2": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM2s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM3": | |
case "ballonM3": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM3s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM4": | |
case "ballonM4": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM4s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM5": | |
case "ballonM5": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM5s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM1a": | |
case "ballonM1a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM1as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM2a": | |
case "ballonM2a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM2as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM3a": | |
case "ballonM3a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM3as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM4a": | |
case "ballonM4a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM4as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "BallonsM5a": | |
case "ballonM5a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("BallonsM5as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
// Handle slice objects | |
case "SlicesP1": | |
case "sliceP1": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("SlicesP1s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "SlicesP2": | |
case "sliceP2": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("SlicesP2s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "SlicesP3": | |
case "sliceP3": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("SlicesP3s", 1); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "SlicesP1a": | |
case "sliceP1a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("SlicesP1as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "SlicesP2a": | |
case "sliceP2a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("SlicesP2as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
case "SlicesP3a": | |
case "sliceP3a": | |
var delayedEvent = script.createEvent("DelayedCallbackEvent"); | |
delayedEvent.bind(function(eventData) { | |
destroyObjectDirectly("SlicesP3as", 2); | |
}); | |
delayedEvent.reset(6); | |
break; | |
default: | |
print("No matching animation found."); | |
} | |
physicsBody.dynamic = true; | |
physicsBody.massOrDensity = 5.0; | |
physicsBody.density = 5.0; | |
triggerPhysicsApplyForce(colliderObj1, physicsBody); | |
script.forceEnergyManager.objectPushed(); | |
} | |
else if(!script.forceEnergyManager.hasEnoughEnergy(nameObjPush)) { | |
physicsBody.dynamic = true; | |
physicsBody.massOrDensity = 5.0; | |
physicsBody.density = 5.0; | |
script.forceEnergyManager.objectPushed(); | |
} | |
} else { | |
print("failed"); | |
} | |
} | |
script.api.pushin = pushin; | |
script.api.pull = pull; | |
// HEALTH MANAGER | |
// CharacterHealthManager.js | |
// Version: 1.0.6 | |
// Event: Initialized | |
// Description: Manages the health of the player, reducing health when sabers hit opponent players | |
// Updated to work with player1/player2 objects instead of characters | |
// | |
// Version 1.0.5 Changes: | |
// - Added specific saber name detection for Player1Saber1, Player1Saber2, Player2Saber1, Player2Saber2 | |
// - Set individual damage values for each saber (10 damage each) | |
// - Added collision cooldown to prevent spam damage from movement lag | |
// - Improved saber ownership detection to prevent self-collision | |
// - Added safety checks to prevent friendly fire damage | |
// | |
// Version 1.0.6 Changes: | |
// - Fixed health regeneration not updating on remote player's screen | |
// - Added network synchronization for regenerated health values | |
// - Separated regeneration events from damage events for better tracking | |
// - Enhanced safety checks in opponent hit handler to prevent self-collision | |
// - Added detailed logging for regeneration and collision events | |
//@input Component.Text healthTextOpp // Text component to display current opponent health | |
//@input Component.Text healthTextOur // Text component to display current health | |
//@input Component.Text healthTextOpp2 // Text component to display second opponent health | |
//@input Component.Image healthBarOpp // Optional visual bar representation | |
//@input Component.Image healthBarOur // Optional visual bar representation | |
//@input Component.Image healthBarOpp2 // Optional visual bar representation for second opponent | |
//@input float maxHealth = 100.0 // Maximum health | |
//@input SceneObject player1 // Reference to player1 object | |
//@input SceneObject player2 // Reference to player2 object | |
//@input SceneObject[] sabers // Reference to saber objects for collision detection | |
//@input bool enableInvulnerabilityFrames = true // Whether to enable temporary invulnerability after taking damage | |
//@input float invulnerabilityDuration = 1.0 // How long the character stays invulnerable after taking damage (in seconds) | |
//@input Component.AudioComponent damageSoundEffect // Sound to play when taking damage | |
//@input Component.AudioComponent deathSoundEffect // Sound to play when health reaches zero | |
//@input SceneObject gameOverScreen // Reference to game over UI to enable when health reaches zero | |
// Health regeneration settings | |
//@input bool enableHealthRegeneration = true // Whether health regeneration is enabled | |
//@input float regenerationDelay = 2.0 // Time in seconds before regeneration starts after taking damage | |
//@input float regenerationRate = 0.10 // Amount of health to regenerate per second | |
//@input Component.AudioComponent regenerationSoundEffect // Optional sound to play when regeneration begins | |
//@input Component.Text EndText | |
//@input SceneObject Hands | |
//@input SceneObject Bodys | |
//@input SceneObject MainScene | |
//@input SceneObject Saber1 | |
//@input SceneObject Saber2 | |
//@input SceneObject Saber3 | |
//@input SceneObject Saber4 | |
// Object damage amounts - how much damage each object deals on collision | |
var player1State; | |
var player2State; | |
var localPlayerNumber; // Track which player is local ("player1" or "player2") | |
var syncEntityPlayer1; | |
var syncEntityPlayer2; | |
var syncEntityDeath; | |
// Track last sent health values to avoid sending duplicate updates | |
var lastSentHealth = { | |
player1: -1, | |
player2: -1 | |
}; | |
// Track last displayed health values to avoid updating UI unnecessarily | |
var lastDisplayedHealth = { | |
our: -1, | |
opp: -1, | |
opp2: -1 | |
}; | |
// Function to check if an object is a saber | |
function isSaberObject(objectName) { | |
// Specific saber names (exact match required) | |
var specificSaberNames = [ | |
"Player1Saber1", "Player1Saber2", "Player2Saber1", "Player2Saber2" | |
]; | |
// Legacy saber names for backward compatibility | |
var legacySaberNames = [ | |
"player1saber1", "player1saber2", "player2saber1", "player2saber2", | |
"saber1", "saber2", "saber3", "lightsaber", "Saber", "Lightsaber", | |
"OurSaber1", "OurSaber2", "OppSaber1", "OppSaber2" | |
]; | |
// First check for exact matches with specific saber names | |
for (var i = 0; i < specificSaberNames.length; i++) { | |
if (objectName === specificSaberNames[i]) { | |
return true; | |
} | |
} | |
// Then check for exact matches with legacy saber names | |
for (var j = 0; j < legacySaberNames.length; j++) { | |
if (objectName === legacySaberNames[j]) { | |
return true; | |
} | |
} | |
// Finally check if the object name contains "saber" (case insensitive) - but be more restrictive | |
var lowerName = objectName.toLowerCase(); | |
if (lowerName.indexOf("saber") !== -1 || lowerName.indexOf("lightsaber") !== -1) { | |
// Additional check to prevent false positives - make sure it's not just any object with "saber" in the name | |
return true; | |
} | |
return false; | |
} | |
// Function to determine if a saber belongs to the local player | |
function isLocalPlayerSaber(objectName) { | |
// print("Checking if saber is local: " + objectName + " (Local player: " + localPlayerNumber + ")"); | |
if (!localPlayerNumber) { | |
// print("Warning: localPlayerNumber not set, cannot determine saber ownership"); | |
return false; | |
} | |
var isLocal = false; | |
// Direct name-based check for specific saber names | |
if (localPlayerNumber === "player1") { | |
isLocal = (objectName === "Player1Saber1" || objectName === "Player1Saber2" || | |
objectName === "player1saber1" || objectName === "player1saber2"); | |
// print("Player1 direct name check - matches: " + isLocal); | |
} else if (localPlayerNumber === "player2") { | |
isLocal = (objectName === "Player2Saber1" || objectName === "Player2Saber2" || | |
objectName === "player2saber1" || objectName === "player2saber2"); | |
// print("Player2 direct name check - matches: " + isLocal); | |
} | |
// If direct name check didn't work, fall back to parent-based check | |
if (!isLocal) { | |
var sceneObject = null; | |
// Try to get the scene object by name | |
try { | |
sceneObject = global.scene.getSceneObject(objectName); | |
} catch (e) { | |
// print("Warning: Could not find scene object: " + objectName); | |
return false; | |
} | |
if (sceneObject) { | |
// Get the parent object | |
var parent = sceneObject.getParent(); | |
if (parent) { | |
var parentName = parent.name.toLowerCase(); | |
// print("Parent object name: " + parentName); | |
// Check if the parent name matches the local player | |
if (localPlayerNumber === "player1") { | |
isLocal = parentName.indexOf("player1") !== -1; | |
// print("Player1 parent check - matches: " + isLocal); | |
} else if (localPlayerNumber === "player2") { | |
isLocal = parentName.indexOf("player2") !== -1; | |
// print("Player2 parent check - matches: " + isLocal); | |
} | |
} | |
} | |
} | |
// print("Final result: " + isLocal); | |
return isLocal; | |
} | |
// Function to determine if a player object is the local player | |
function isLocalPlayer(objectName) { | |
if (!localPlayerNumber) { | |
// print("Warning: localPlayerNumber not set, cannot determine player ownership"); | |
return false; | |
} | |
return objectName === localPlayerNumber; | |
} | |
// Function to get the owner of a saber based on its name | |
function getSaberOwner(saberName) { | |
// Check specific saber names first | |
if (saberName === "Player1Saber1" || saberName === "Player1Saber2" || | |
saberName === "player1saber1" || saberName === "player1saber2") { | |
return "player1"; | |
} | |
if (saberName === "Player2Saber1" || saberName === "Player2Saber2" || | |
saberName === "player2saber1" || saberName === "player2saber2") { | |
return "player2"; | |
} | |
// Check for generic saber names by examining the name pattern | |
var lowerName = saberName.toLowerCase(); | |
if (lowerName.indexOf("player1") !== -1) { | |
return "player1"; | |
} else if (lowerName.indexOf("player2") !== -1) { | |
return "player2"; | |
} | |
// If no clear owner can be determined, return null | |
return null; | |
} | |
var objectDamageAmounts = { | |
// Small objects (low damage) | |
"crateB1": 5, | |
"crateB2": 5, | |
"crateM1": 7, | |
"crateM2": 7, | |
"crateM3": 7, | |
"crateM4": 7, | |
"crateB1a": 5, | |
"crateB2a": 5, | |
"crateM1a": 7, | |
"crateM2a": 7, | |
"crateM3a": 7, | |
"crateM4a": 7, | |
"Object_15": 5, | |
"mesh_0_002": 5, | |
// Add Ballons objects (low damage like crateM) | |
"BallonsM1": 7, | |
"BallonsM2": 7, | |
"BallonsM3": 7, | |
"BallonsM4": 7, | |
"BallonsM5": 7, | |
"BallonsM1a": 7, | |
"BallonsM2a": 7, | |
"BallonsM3a": 7, | |
"BallonsM4a": 7, | |
"BallonsM5a": 7, | |
"ballonM1": 7, | |
"ballonM2": 7, | |
"ballonM3": 7, | |
"ballonM4": 7, | |
"ballonM5": 7, | |
// Medium objects (medium damage) | |
"crateXL": 15, | |
"crateXLa": 15, | |
"R2D2": 20, | |
// Add Slices objects (medium damage like crateXL) | |
"SlicesP1": 15, | |
"SlicesP2": 15, | |
"SlicesP3": 15, | |
"SlicesP1a": 15, | |
"SlicesP2a": 15, | |
"SlicesP3a": 15, | |
"sliceP1": 15, | |
"sliceP2": 15, | |
"sliceP3": 15, | |
// Large objects (high damage) | |
"AT-STtes": 30, | |
"tieCube": 25, | |
"xwing_sfoil3": 25, | |
"millennium_falcon": 40, | |
// Specific saber damage (individual damage values) | |
"Player1Saber1": 10, | |
"Player1Saber2": 10, | |
"Player2Saber1": 10, | |
"Player2Saber2": 10, | |
// Legacy saber names (for backward compatibility) | |
"player1saber1": 10, | |
"player1saber2": 10, | |
"player2saber1": 10, | |
"player2saber2": 10, | |
"saber1": 10, | |
"saber2": 10, | |
"saber3": 10, | |
"lightsaber": 10 | |
}; | |
// Default damage if object is not in the list | |
var defaultDamage = 10; | |
// Initialize the current health | |
var currentHealth = script.maxHealth; | |
// Track opponent's health locally (for attacking player) | |
var opponentHealth = script.maxHealth; | |
// Flag to track if character is currently invulnerable | |
var isInvulnerable = false; | |
// Health regeneration variables | |
var isRegenerating = false; | |
var regenerationEvent = null; | |
var regenerationUpdateEvent = null; | |
// Collision cooldown to prevent spam damage from movement lag | |
var lastCollisionTime = {}; | |
var collisionCooldown = 0.5; // 0.5 seconds between damage from same object | |
const textureControlOppHealth = script.healthBarOpp.getMaterial(0).getPass(0).baseTex.control; | |
const textureControlOurHealth = script.healthBarOur.getMaterial(0).getPass(0).baseTex.control; | |
const textureControlOpp2Health = script.healthBarOpp2.getMaterial(0).getPass(0).baseTex.control; | |
var ReceivedHealth; | |
var ReceivedHealthOpp2; | |
// Global variables to track timing | |
let lastUpdateTime = 0; | |
const updateInterval = 0.5; // Reduced to 0.5 second interval for more responsive updates | |
// Update the UI display of health and send to other players if changed | |
function updateHealthDisplay(forceUpdate) { | |
// Get current time | |
const currentTime = getTime(); | |
// Ensure health is never below 0 for display purposes | |
var displayHealth = Math.max(0, Math.floor(currentHealth)); | |
// Check if interval has passed since last update, or if we're forcing an update | |
if (forceUpdate || currentTime - lastUpdateTime >= updateInterval) { | |
// Update the last update time | |
lastUpdateTime = currentTime; | |
// Execute health display logic - only update local player's own health display | |
if (script.healthBarOur) { | |
let localPlayerHealth = displayHealth; | |
// Update our own health display (healthTextOur + healthBarOur) | |
if (forceUpdate || lastDisplayedHealth.our !== localPlayerHealth) { | |
script.healthTextOur.text = "Health: " + localPlayerHealth + "/" + script.maxHealth; | |
var frameIndex = Math.max(0, localPlayerHealth - 1); | |
textureControlOurHealth.pauseAtFrame(frameIndex); | |
lastDisplayedHealth.our = localPlayerHealth; | |
// print(localPlayerNumber + " updated own health display: " + localPlayerHealth); | |
} | |
} | |
} | |
} | |
// Legacy function - kept for backward compatibility but no longer used | |
function updateWithDelayPlayer() { | |
// print("updateWithDelayPlayer called - this function is deprecated in the new health system"); | |
} | |
// Apply damage to a specific player and handle health synchronization | |
// NEW LOGIC: Attacking player reduces opponent's health locally first, then sends the new health | |
function applyDamageToPlayer(targetPlayer, damageAmount, objectName, impactVelocity) { | |
// print("=== APPLYING DAMAGE ==="); | |
// print("Target Player: " + targetPlayer); | |
// print("Damage Amount: " + damageAmount); | |
// print("Caused by: " + objectName); | |
// print("Local Player: " + localPlayerNumber); | |
// Determine if we're damaging the local player or opponent | |
var isDamagingLocalPlayer = (targetPlayer === localPlayerNumber); | |
// Check if the damage is caused by a balloon or slice | |
var objectNameLower = objectName.toLowerCase(); | |
var hitAnimationType = null; | |
if (objectNameLower.indexOf("ballon") !== -1) { | |
hitAnimationType = "balloon"; | |
// If we're being hit, play animation locally | |
if (isDamagingLocalPlayer && global.playBalloonHitAnimation) { | |
// print("Playing balloon hit animation locally (we were hit)"); | |
global.playBalloonHitAnimation(); | |
} | |
// If we're hitting opponent, send message to opponent to play animation | |
else if (!isDamagingLocalPlayer) { | |
// print("Sending balloon hit animation message to opponent"); | |
sendHitAnimationToOpponent("balloon"); | |
} | |
} else if (objectNameLower.indexOf("slice") !== -1) { | |
hitAnimationType = "slice"; | |
// If we're being hit, play animation locally | |
if (isDamagingLocalPlayer && global.playSliceHitAnimation) { | |
// print("Playing slice hit animation locally (we were hit)"); | |
global.playSliceHitAnimation(); | |
} | |
// If we're hitting opponent, send message to opponent to play animation | |
else if (!isDamagingLocalPlayer) { | |
// print("Sending slice hit animation message to opponent"); | |
sendHitAnimationToOpponent("slice"); | |
} | |
} | |
if (isDamagingLocalPlayer) { | |
// We're being damaged by opponent - apply damage locally | |
// print("Local player taking damage"); | |
applyLocalDamage(damageAmount, objectName, impactVelocity); | |
} else { | |
// We're attacking the opponent - reduce their health locally, then send the new health | |
// print("Local player attacking opponent - reducing opponent health locally"); | |
applyDamageToOpponent(damageAmount, objectName, impactVelocity); | |
} | |
} | |
// Function to send hit animation message to opponent | |
function sendHitAnimationToOpponent(animationType) { | |
// print("🚀 SENDING HIT ANIMATION TO OPPONENT: " + animationType); | |
// print("🔍 Local Player: " + localPlayerNumber); | |
var animationData = { | |
type: animationType, | |
targetPlayer: localPlayerNumber === "player1" ? "player2" : "player1" // Explicitly specify target | |
}; | |
// print("📦 Animation Data: " + JSON.stringify(animationData)); | |
// Send animation event based on local player - use direct event sending | |
if (localPlayerNumber === "player1" && syncEntityPlayer1) { | |
// If we're player1, send to player2 to play animation | |
syncEntityPlayer1.sendEvent('PlayHitAnimationOnOpponent', animationData, true); | |
// print("✅ Sent hit animation event via Player1 sync to player2"); | |
} else if (localPlayerNumber === "player2" && syncEntityPlayer2) { | |
// If we're player2, send to player1 to play animation | |
syncEntityPlayer2.sendEvent('PlayHitAnimationOnOpponent', animationData, true); | |
// print("✅ Sent hit animation event via Player2 sync to player1"); | |
} else { | |
// print("❌ Error: Could not send hit animation event - incorrect sync entity configuration"); | |
// print(" Local player: " + localPlayerNumber); | |
// print(" Player1 sync available: " + (syncEntityPlayer1 ? "YES" : "NO")); | |
// print(" Player2 sync available: " + (syncEntityPlayer2 ? "YES" : "NO")); | |
} | |
} | |
// Apply damage to the local player | |
function applyLocalDamage(damageAmount, objectName, impactVelocity) { | |
// If character is invulnerable, ignore damage | |
if (isInvulnerable) { | |
// print("Local player is invulnerable - ignoring damage"); | |
return; | |
} | |
// Use the passed damage amount directly (already calculated) | |
var finalDamageAmount = damageAmount; | |
// Factor in velocity to increase damage for faster moving objects (optional) | |
var velocityFactor = impactVelocity / 10; // Adjust divisor to balance impact | |
velocityFactor = Math.min(Math.max(velocityFactor, 0.5), 2.0); // Clamp between 0.5x and 2x | |
// Calculate final damage | |
var finalDamage = finalDamageAmount * velocityFactor; | |
// Store previous health to check if anything changed | |
var previousHealth = currentHealth; | |
// Apply damage | |
currentHealth = Math.max(0, currentHealth - finalDamage); | |
// Only proceed if damage actually changed the health | |
if (currentHealth < previousHealth) { | |
// print("Local player took " + finalDamage.toFixed(1) + " damage from " + objectName); | |
// print("Health: " + previousHealth + " -> " + currentHealth); | |
// Force immediate health display update since damage was taken | |
updateHealthDisplay(true); | |
// Play damage sound effect | |
if (script.damageSoundEffect) { | |
script.damageSoundEffect.play(1); | |
} | |
// Apply screen shake or visual feedback | |
applyDamageVisualEffects(finalDamage); | |
// Reset health regeneration timer when taking damage | |
stopRegeneration(); | |
// Schedule regeneration if enabled | |
if (script.enableHealthRegeneration && currentHealth > 0 && currentHealth < script.maxHealth) { | |
scheduleRegeneration(); | |
} | |
// Check if character died | |
if (currentHealth <= 0) { | |
handleCharacterDeath(); | |
} else if (script.enableInvulnerabilityFrames) { | |
// Apply invulnerability frames | |
setInvulnerable(true); | |
var invulnerabilityEvent = script.createEvent("DelayedCallbackEvent"); | |
invulnerabilityEvent.bind(function() { | |
setInvulnerable(false); | |
}); | |
invulnerabilityEvent.reset(script.invulnerabilityDuration); | |
} | |
} else { | |
// print("No health change - damage may have been blocked or health already at minimum"); | |
} | |
} | |
// Apply damage to opponent locally and send the new health value | |
function applyDamageToOpponent(damageAmount, objectName, impactVelocity) { | |
// print("Applying damage to opponent locally"); | |
// Factor in velocity to increase damage for faster moving objects (optional) | |
var velocityFactor = impactVelocity / 10; // Adjust divisor to balance impact | |
velocityFactor = Math.min(Math.max(velocityFactor, 0.5), 2.0); // Clamp between 0.5x and 2x | |
// Calculate final damage | |
var finalDamage = damageAmount * velocityFactor; | |
// Store previous opponent health | |
var previousOpponentHealth = opponentHealth; | |
// Apply damage to opponent health (tracked locally) | |
opponentHealth = Math.max(0, opponentHealth - finalDamage); | |
// print("Opponent health: " + previousOpponentHealth + " -> " + opponentHealth + " (damage: " + finalDamage.toFixed(1) + ")"); | |
// Update opponent's health display locally | |
updateOpponentHealthDisplay(); | |
// Send the new health value to the opponent | |
sendHealthToOpponent(opponentHealth); | |
// Check if opponent died | |
if (opponentHealth <= 0) { | |
// print("Opponent has been defeated!"); | |
handleOpponentDeath(); | |
} | |
} | |
// Send opponent's new health value to them | |
function sendHealthToOpponent(newHealth) { | |
// print("Sending opponent's new health: " + newHealth); | |
var healthData = { | |
newHealth: newHealth, | |
isDirectHealthSet: true | |
}; | |
// Send health update based on local player | |
if (localPlayerNumber === "player1" && syncEntityPlayer1) { | |
syncEntityPlayer1.sendEvent('HealthSetEvent', healthData, true); | |
// print("Sent health set event via Player1 sync"); | |
} else if (localPlayerNumber === "player2" && syncEntityPlayer2) { | |
syncEntityPlayer2.sendEvent('HealthSetEvent', healthData, true); | |
// print("Sent health set event via Player2 sync"); | |
} else { | |
// print("Error: Could not send health set event - sync entity not available"); | |
} | |
} | |
// Send regenerated health to opponent (different from damage-based health updates) | |
function sendRegeneratedHealthToOpponent(newHealth) { | |
// print("🔋 Sending regenerated health to opponent: " + newHealth); | |
var healthData = { | |
newHealth: newHealth, | |
isDirectHealthSet: true, | |
isRegeneration: true // Flag to indicate this is regeneration, not damage | |
}; | |
// Send health update based on local player | |
if (localPlayerNumber === "player1" && syncEntityPlayer1) { | |
syncEntityPlayer1.sendEvent('HealthSetEvent', healthData, true); | |
// print("🔋 Sent regeneration health event via Player1 sync"); | |
} else if (localPlayerNumber === "player2" && syncEntityPlayer2) { | |
syncEntityPlayer2.sendEvent('HealthSetEvent', healthData, true); | |
// print("🔋 Sent regeneration health event via Player2 sync"); | |
} else { | |
// print("❌ Error: Could not send regeneration health event - sync entity not available"); | |
// print(" Local player: " + localPlayerNumber); | |
// print(" Player1 sync available: " + (syncEntityPlayer1 ? "YES" : "NO")); | |
// print(" Player2 sync available: " + (syncEntityPlayer2 ? "YES" : "NO")); | |
} | |
} | |
// Set local health directly (when opponent has reduced our health) | |
function setLocalHealthDirectly(newHealth) { | |
var previousHealth = currentHealth; | |
currentHealth = Math.max(0, Math.min(script.maxHealth, newHealth)); | |
// print("Health set directly: " + previousHealth + " -> " + currentHealth); | |
// Update local health display | |
updateHealthDisplay(true); | |
// Apply visual effects for taking damage | |
if (currentHealth < previousHealth) { | |
var damageAmount = previousHealth - currentHealth; | |
applyDamageVisualEffects(damageAmount); | |
// Play damage sound effect | |
if (script.damageSoundEffect) { | |
script.damageSoundEffect.play(1); | |
} | |
// Reset health regeneration timer when taking damage | |
stopRegeneration(); | |
// Schedule regeneration if enabled | |
if (script.enableHealthRegeneration && currentHealth > 0 && currentHealth < script.maxHealth) { | |
scheduleRegeneration(); | |
} | |
// Apply invulnerability frames | |
if (script.enableInvulnerabilityFrames && currentHealth > 0) { | |
setInvulnerable(true); | |
var invulnerabilityEvent = script.createEvent("DelayedCallbackEvent"); | |
invulnerabilityEvent.bind(function() { | |
setInvulnerable(false); | |
}); | |
invulnerabilityEvent.reset(script.invulnerabilityDuration); | |
} | |
} | |
// Check if we died | |
if (currentHealth <= 0) { | |
handleLocalPlayerDeath(); | |
} | |
} | |
// Handle local player death | |
function handleLocalPlayerDeath() { | |
// print("Local player has died!"); | |
// Stop regeneration if it's running | |
stopRegeneration(); | |
// Play death sound | |
if (script.deathSoundEffect) { | |
script.deathSoundEffect.play(1); | |
} | |
// Show defeat message | |
if (script.EndText) { | |
script.EndText.text = "You Lost"; | |
} | |
// Show game over screen | |
if (script.gameOverScreen) { | |
script.gameOverScreen.enabled = true; | |
} | |
} | |
// Update opponent health display locally | |
function updateOpponentHealthDisplay() { | |
var displayHealth = Math.max(0, Math.floor(opponentHealth)); | |
// print("=== updateOpponentHealthDisplay ==="); | |
// print("displayHealth: " + displayHealth); | |
// print("localPlayerNumber: " + localPlayerNumber); | |
// print("lastDisplayedHealth.opp: " + lastDisplayedHealth.opp); | |
// print("lastDisplayedHealth.opp2: " + lastDisplayedHealth.opp2); | |
// print("script.healthTextOpp exists: " + (script.healthTextOpp ? "yes" : "no")); | |
// print("script.healthTextOpp2 exists: " + (script.healthTextOpp2 ? "yes" : "no")); | |
// BOTH players should update BOTH text components to ensure visibility | |
// Update primary opponent text (healthTextOpp) | |
if (lastDisplayedHealth.opp !== displayHealth) { | |
// print("Updating primary opponent text to: Health: " + displayHealth + "/" + script.maxHealth); | |
if (script.healthTextOpp) { | |
script.healthTextOpp.text = "Health: " + displayHealth + "/" + script.maxHealth; | |
// print("Primary opponent text updated successfully"); | |
} else { | |
// print("ERROR: script.healthTextOpp is null/undefined!"); | |
} | |
var frameIndex = Math.max(0, displayHealth - 1); | |
textureControlOppHealth.pauseAtFrame(frameIndex); | |
lastDisplayedHealth.opp = displayHealth; | |
} | |
// Update secondary opponent text (healthTextOpp2) | |
if (lastDisplayedHealth.opp2 !== displayHealth) { | |
// print("Updating secondary opponent text to: Health: " + displayHealth + "/" + script.maxHealth); | |
if (script.healthTextOpp2) { | |
script.healthTextOpp2.text = "Health: " + displayHealth + "/" + script.maxHealth; | |
// print("Secondary opponent text updated successfully"); | |
} else { | |
// print("ERROR: script.healthTextOpp2 is null/undefined!"); | |
} | |
var frameIndex2 = Math.max(0, displayHealth - 1); | |
textureControlOpp2Health.pauseAtFrame(frameIndex2); | |
lastDisplayedHealth.opp2 = displayHealth; | |
} | |
// print("Updated opponent health display: " + displayHealth + " (Player: " + localPlayerNumber + ")"); | |
} | |
// Handle opponent death | |
function handleOpponentDeath() { | |
// print("Opponent has died - local player wins!"); | |
// Play victory sound or effects here | |
if (script.deathSoundEffect) { | |
script.deathSoundEffect.play(1); | |
} | |
// Show victory message | |
if (script.EndText) { | |
script.EndText.text = "You Won"; | |
} | |
// Show game over screen | |
if (script.gameOverScreen) { | |
script.gameOverScreen.enabled = true; | |
} | |
} | |
// Set character invulnerability state | |
function setInvulnerable(state) { | |
isInvulnerable = state; | |
} | |
// Schedule health regeneration | |
function scheduleRegeneration() { | |
// Cancel any existing regeneration | |
stopRegeneration(); | |
// Schedule regeneration to start after delay | |
regenerationEvent = script.createEvent("DelayedCallbackEvent"); | |
regenerationEvent.bind(function() { | |
startRegeneration(); | |
}); | |
regenerationEvent.reset(script.regenerationDelay); | |
} | |
// Start the actual health regeneration | |
function startRegeneration() { | |
if (isRegenerating || currentHealth >= script.maxHealth || currentHealth <= 0) { | |
return; | |
} | |
isRegenerating = true; | |
// Play regeneration sound if available | |
if (script.regenerationSoundEffect) { | |
script.regenerationSoundEffect.play(1); | |
} | |
// Visual indicator that regeneration has started | |
// print("Health regeneration started"); | |
// Create an update event to regenerate health gradually | |
regenerationUpdateEvent = script.createEvent("UpdateEvent"); | |
regenerationUpdateEvent.bind(function(eventData) { | |
// Calculate how much health to add this frame | |
var healthToAdd = script.regenerationRate * eventData.getDeltaTime(); | |
// Previous health value before adding | |
var previousHealth = currentHealth; | |
// Add health | |
currentHealth = Math.min(script.maxHealth, currentHealth + healthToAdd); | |
// Only update if health changed by at least 1 point | |
if (Math.floor(previousHealth) < Math.floor(currentHealth)) { | |
// print("🔋 HEALTH REGENERATION UPDATE:"); | |
// print(" Previous: " + Math.floor(previousHealth)); | |
// print(" Current: " + Math.floor(currentHealth)); | |
// print(" Player: " + localPlayerNumber); | |
// Force an immediate health display update | |
updateHealthDisplay(true); | |
// Send regenerated health to opponent so they can see the update | |
sendRegeneratedHealthToOpponent(Math.floor(currentHealth)); | |
} | |
// Check if we've reached max health | |
if (previousHealth < script.maxHealth && currentHealth >= script.maxHealth) { | |
// print("🔋 HEALTH REGENERATION COMPLETE - Full health reached"); | |
// Force immediate update when reaching max health | |
updateHealthDisplay(true); | |
// Send final health value to opponent | |
sendRegeneratedHealthToOpponent(script.maxHealth); | |
stopRegeneration(); | |
} else if (currentHealth >= script.maxHealth) { | |
// Stop regeneration if health is full | |
stopRegeneration(); | |
} | |
}); | |
} | |
// Stop health regeneration | |
function stopRegeneration() { | |
isRegenerating = false; | |
// Cancel the scheduled regeneration if it exists | |
if (regenerationEvent) { | |
regenerationEvent.enabled = false; | |
regenerationEvent = null; | |
} | |
// Cancel the update event if it exists | |
if (regenerationUpdateEvent) { | |
regenerationUpdateEvent.enabled = false; | |
regenerationUpdateEvent = null; | |
} | |
} | |
// Handle character death with proper player-specific logic | |
function handleCharacterDeath() { | |
// print("Character has died!"); | |
// Stop regeneration if it's running | |
stopRegeneration(); | |
// Play death sound | |
if (script.deathSoundEffect) { | |
script.deathSoundEffect.play(1); | |
} | |
// Show game over screen | |
if (script.gameOverScreen) { | |
script.gameOverScreen.enabled = true; | |
} | |
// Get correct health values, ensuring they're numeric | |
var ourHealthValue = parseInt(ReceivedHealth) || 0; | |
var oppHealthValue = Math.floor(currentHealth) || 0; | |
var opp2HealthValue = parseInt(ReceivedHealthOpp2) || 0; | |
// Prevent multiple executions | |
if (typeof handleCharacterDeath.hasExecuted === 'undefined') { | |
handleCharacterDeath.hasExecuted = true; | |
// Debug output to help understand the state | |
// print("Death handler - Our health: " + ourHealthValue + | |
// ", Opp health: " + oppHealthValue + | |
// ", Opp2 health: " + opp2HealthValue + | |
// ", Player1State: " + player1State + | |
// ", Player2State: " + player2State); | |
// Player-specific win/loss determination | |
if (player1State === true) { | |
// Player 1 specific logic | |
if (oppHealthValue <= 0) { | |
// Player 1's opponent (Player 2) has zero health, Player 1 wins | |
script.EndText.text = "You Won"; | |
// print("Player 1 wins - opponent health is " + oppHealthValue); | |
} else if (ourHealthValue <= 0) { | |
// Player 1's health is zero, Player 1 loses | |
script.EndText.text = "You Lost"; | |
// print("Player 1 loses - own health is " + ourHealthValue); | |
} | |
} else if (player2State === true) { | |
// Player 2 specific logic | |
if (oppHealthValue <= 0) { | |
// Player 2's opponent (Player 1) has zero health, Player 2 wins | |
script.EndText.text = "You Won"; | |
// print("Player 2 wins - opponent health is " + oppHealthValue); | |
} else if (ourHealthValue <= 0) { | |
// Player 2's health is zero, Player 2 loses | |
script.EndText.text = "You Lost"; | |
// print("Player 2 loses - own health is " + ourHealthValue); | |
} | |
} | |
// Always send death event regardless of who died | |
syncEntityDeath.sendEvent('Death', { | |
player1Health: player1State ? ourHealthValue : oppHealthValue, | |
player2Health: player2State ? ourHealthValue : oppHealthValue | |
}, true); | |
// Disable game elements | |
script.MainScene.enabled = false; | |
script.Hands.enabled = false; | |
script.Bodys.enabled = false; | |
script.Saber1.enabled = false; | |
script.Saber2.enabled = false; | |
script.Saber3.enabled = false; | |
script.Saber4.enabled = false; | |
} | |
} | |
// Apply visual effects when taking damage | |
function applyDamageVisualEffects(damageAmount) { | |
// Implement screen shake, flash, or other effects | |
// This is just a stub - implement specific effects as needed | |
var damageEffect = script.createEvent("DelayedCallbackEvent"); | |
damageEffect.bind(function() { | |
// Reset any visual effects | |
}); | |
damageEffect.reset(0.3); // Brief effect duration | |
} | |
// Handle collision event - could be connected to a collision event or called from other scripts | |
function onCollisionHandler(eventData) { | |
// print("=== COLLISION HANDLER CALLED ==="); | |
// print("Event data structure: " + JSON.stringify(Object.keys(eventData))); | |
// Debug: Print all available properties | |
for (var key in eventData) { | |
// print("EventData." + key + ": " + (typeof eventData[key])); | |
} | |
// Handle different collision event structures | |
var collidingObject = null; | |
var hitTarget = null; | |
// Try different collision event formats | |
if (eventData.collision) { | |
// print("Using eventData.collision format"); | |
collidingObject = eventData.collision.collider; | |
hitTarget = eventData.collision.otherCollider; | |
} else if (eventData.collider) { | |
// print("Using direct eventData.collider format"); | |
collidingObject = eventData.collider; | |
hitTarget = eventData.otherCollider; | |
} else if (eventData.other) { | |
// print("Using eventData.other format"); | |
collidingObject = eventData.collider; | |
hitTarget = eventData.other; | |
} | |
// print("Colliding object exists: " + (collidingObject ? "YES" : "NO")); | |
// print("Hit target exists: " + (hitTarget ? "YES" : "NO")); | |
// If we still don't have hitTarget, try alternative approaches | |
if (collidingObject && !hitTarget) { | |
// print("Trying alternative collision detection..."); | |
// In some collision systems, we might need to determine the hit target differently | |
// For now, let's assume any collision with a player object is valid | |
var objectName = collidingObject.getSceneObject().name; | |
// print("Colliding object name: " + objectName); | |
// If this is a saber hitting something, we need to determine what it hit | |
if (isSaberObject(objectName)) { | |
// print("Saber collision detected, but hit target unknown"); | |
// For now, let's skip this collision since we can't determine what was hit | |
return; | |
} | |
} | |
if (collidingObject && hitTarget) { | |
var objectName = collidingObject.getSceneObject().name; | |
var hitTargetName = hitTarget.getSceneObject().name; | |
// print("==================== COLLISION DETAILS ===================="); | |
// print("🎯 COLLISION: " + objectName + " hit " + hitTargetName); | |
// print("📍 Local player: " + localPlayerNumber); | |
// print("⚔️ Colliding object type: " + (isSaberObject(objectName) ? "SABER" : "ENVIRONMENTAL")); | |
// print("🎭 Hit target type: " + (hitTargetName.indexOf("player") !== -1 ? "PLAYER" : "OTHER")); | |
if (isSaberObject(objectName)) { | |
var saberOwner = getSaberOwner(objectName); | |
// print("👤 Saber owner: " + saberOwner); | |
// print("🏠 Is local saber: " + isLocalPlayerSaber(objectName)); | |
} | |
// print("========================================================"); | |
// Get collision velocity | |
var collisionVelocity = 10.0; // Default if not available | |
var sceneObject = collidingObject.getSceneObject(); | |
var physicsBody = sceneObject.getComponent("Physics.BodyComponent"); | |
if (physicsBody) { | |
// collisionVelocity = physicsBody.velocity.length(); | |
} | |
// Determine which player was hit | |
var hitPlayer = null; | |
// print("🔍 ANALYZING HIT TARGET:"); | |
// print(" Target name: " + hitTargetName); | |
// print(" Player1 object: " + (script.player1 ? script.player1.name : "NOT ASSIGNED")); | |
// print(" Player2 object: " + (script.player2 ? script.player2.name : "NOT ASSIGNED")); | |
if (script.player1 && (hitTargetName === script.player1.name || hitTargetName.indexOf("player1") === 0)) { | |
hitPlayer = "player1"; | |
// print("✅ Hit target identified as: PLAYER1"); | |
} else if (script.player2 && (hitTargetName === script.player2.name || hitTargetName.indexOf("player2") === 0)) { | |
hitPlayer = "player2"; | |
// print("✅ Hit target identified as: PLAYER2"); | |
} | |
if (!hitPlayer) { | |
// print("❌ Hit target is NOT a player object: " + hitTargetName); | |
// print(" Available players: " + (script.player1 ? script.player1.name : "none") + ", " + (script.player2 ? script.player2.name : "none")); | |
// print(" This collision will be IGNORED"); | |
return; | |
} | |
// print("🎯 FINAL RESULT: " + objectName + " hit " + hitPlayer); | |
// print(" Local player: " + localPlayerNumber); | |
// print(" Is hitting opponent: " + (hitPlayer !== localPlayerNumber)); | |
// Check if the colliding object is a saber or environmental object | |
var damageAmount = 0; | |
var shouldApplyDamage = false; | |
if (isSaberObject(objectName)) { | |
// print("⚔️ SABER COLLISION ANALYSIS:"); | |
// print(" Saber: " + objectName + " hit " + hitPlayer); | |
// Additional safety check: prevent collision if saber belongs to same player as target | |
var saberOwner = getSaberOwner(objectName); | |
// print(" 👤 Saber owner: " + saberOwner); | |
// print(" 🎯 Target player: " + hitPlayer); | |
// Prevent self-collision (saber hitting its own owner) | |
if (saberOwner === hitPlayer) { | |
// print(" 🛡️ SELF-COLLISION DETECTED - BLOCKING!"); | |
// print(" ❌ " + objectName + " belongs to " + hitPlayer + " - preventing friendly fire"); | |
return; | |
} | |
// Check if this saber belongs to the local player | |
var isLocalSaber = isLocalPlayerSaber(objectName); | |
// print(" 🏠 Is local player's saber: " + isLocalSaber); | |
// print(" 📱 Local player: " + localPlayerNumber); | |
// print(" 🎯 Target is opponent: " + (hitPlayer !== localPlayerNumber)); | |
var shouldApplyDamageCheck = (isLocalSaber && hitPlayer !== localPlayerNumber); | |
// print(" 💥 Should apply damage: " + shouldApplyDamageCheck); | |
// Only apply damage if local player's saber hits opponent | |
if (isLocalSaber && hitPlayer !== localPlayerNumber) { | |
damageAmount = objectDamageAmounts[objectName] || 10; | |
shouldApplyDamage = true; | |
// print(" ✅ LOCAL SABER HIT OPPONENT - applying " + damageAmount + " damage"); | |
} else if (isLocalSaber && hitPlayer === localPlayerNumber) { | |
// print(" ❌ LOCAL SABER HIT LOCAL PLAYER - no friendly fire damage"); | |
} else if (!isLocalSaber) { | |
// print(" ⏸️ REMOTE SABER COLLISION - damage handled by remote player"); | |
} | |
} | |
// Environmental objects (crates, etc.) can damage any player they hit | |
else if (objectDamageAmounts[objectName]) { | |
// print("🏗️ ENVIRONMENTAL COLLISION:"); | |
// print(" Object: " + objectName); | |
// print(" Hit player: " + hitPlayer); | |
damageAmount = objectDamageAmounts[objectName]; | |
shouldApplyDamage = true; | |
// print(" ✅ ENVIRONMENTAL DAMAGE - applying " + damageAmount + " damage"); | |
} else { | |
// print("🤷 UNKNOWN OBJECT COLLISION:"); | |
// print(" Object: " + objectName + " (not in damage list)"); | |
// print(" Hit player: " + hitPlayer); | |
// print(" ❌ NO DAMAGE - object not configured for damage"); | |
} | |
// Apply damage if conditions are met | |
if (shouldApplyDamage && damageAmount > 0) { | |
// Check collision cooldown to prevent spam damage from movement lag | |
var currentTime = getTime(); | |
var collisionKey = objectName + "_" + hitPlayer; | |
if (lastCollisionTime[collisionKey] && | |
(currentTime - lastCollisionTime[collisionKey]) < collisionCooldown) { | |
// print("⏰ COLLISION COOLDOWN ACTIVE:"); | |
// print(" 🔄 Ignoring damage from " + objectName + " to " + hitPlayer); | |
// print(" ⏱️ Last collision: " + (currentTime - lastCollisionTime[collisionKey]).toFixed(2) + "s ago"); | |
// print(" ⏳ Cooldown time: " + collisionCooldown + "s"); | |
// print(" ❌ DAMAGE BLOCKED BY COOLDOWN"); | |
return; | |
} | |
// Update last collision time | |
lastCollisionTime[collisionKey] = currentTime; | |
// print("💥 DAMAGE BEING APPLIED:"); | |
// print(" 🎯 Object: " + objectName); | |
// print(" 👤 Target: " + hitPlayer); | |
// print(" 💔 Damage: " + damageAmount); | |
// print(" 🏃 Velocity: " + collisionVelocity); | |
// print(" ⏰ Time: " + currentTime.toFixed(2) + "s"); | |
// print(" ✅ ALL CONDITIONS MET - APPLYING DAMAGE!"); | |
// Apply damage to the hit player | |
applyDamageToPlayer(hitPlayer, damageAmount, objectName, collisionVelocity); | |
// Play damage sound effect | |
if (script.damageSoundEffect) { | |
script.damageSoundEffect.play(1); | |
} | |
} else { | |
// print("❌ CONDITIONS NOT MET - NO DAMAGE APPLIED:"); | |
// print(" 🎯 Object: " + objectName); | |
// print(" 👤 Target: " + hitPlayer); | |
// print(" ✅ Should apply: " + shouldApplyDamage); | |
// print(" 💔 Damage amount: " + damageAmount); | |
// print(" 🚫 COLLISION IGNORED"); | |
} | |
// print("================== END COLLISION =================="); | |
} | |
} | |
// Initialize | |
script.initialize = function(player1Statein, player2Statein, localPlayerNumberIn) { | |
print("=== HEALTH MANAGER INITIALIZATION ==="); | |
print("Player1 State: " + player1Statein); | |
print("Player2 State: " + player2Statein); | |
print("Local Player Number: " + localPlayerNumberIn); | |
// Initialize health bars to full health | |
textureControlOurHealth.pauseAtFrame(100-1); | |
script.healthTextOur.text = "Health: " + "100" + "/" + script.maxHealth; | |
textureControlOppHealth.pauseAtFrame(100-1); | |
script.healthTextOpp.text = "Health: " + "100" + "/" + script.maxHealth; | |
textureControlOpp2Health.pauseAtFrame(100-1); | |
script.healthTextOpp2.text = "Health: " + "100" + "/" + script.maxHealth; | |
// Set last displayed health values to initial values | |
lastDisplayedHealth.our = 100; | |
lastDisplayedHealth.opp = 100; | |
lastDisplayedHealth.opp2 = 100; | |
print("Health UI initialized"); | |
function onUpdate() { | |
// Check if we have enough players | |
if (global.sessionController.getUsers().length == 2) { | |
player1State = player1Statein; | |
player2State = player2Statein; | |
localPlayerNumber = localPlayerNumberIn; | |
print("Health Manager initialized with local player: " + localPlayerNumber); | |
// Create the SyncEntities if they don't exist yet | |
if (!syncEntityPlayer1) { | |
syncEntityPlayer1 = new SyncEntity(script, null, true); | |
syncEntityPlayer1.notifyOnReady(function() { | |
print("SyncEntity health player1 is ready"); | |
}); | |
// Legacy event handlers - replaced by new health system | |
syncEntityPlayer1.onEventReceived.add('Player1OppHealth', function(messageInfo) { | |
print("Legacy Player1OppHealth event received - using new health system instead"); | |
}); | |
syncEntityPlayer1.onEventReceived.add('Player1Opp2Health', function(messageInfo) { | |
print("Legacy Player1Opp2Health event received - using new health system instead"); | |
}); | |
// Handle incoming health set events (when opponent reduces our health or regenerates) | |
syncEntityPlayer1.onEventReceived.add('HealthSetEvent', function(messageInfo) { | |
var healthData = messageInfo.data; | |
print("Received health set event: " + JSON.stringify(healthData)); | |
if (healthData.isDirectHealthSet) { | |
if (healthData.isRegeneration) { | |
// print("🔋 Received opponent's regenerated health: " + healthData.newHealth); | |
// Update the opponent's health display locally | |
opponentHealth = healthData.newHealth; | |
updateOpponentHealthDisplay(); | |
} else { | |
// print("💔 Setting local health directly to: " + healthData.newHealth); | |
setLocalHealthDirectly(healthData.newHealth); | |
} | |
} | |
}); | |
// Legacy health update handler - no longer used in new system | |
syncEntityPlayer1.onEventReceived.add('Player2HealthUpdate', function(messageInfo) { | |
print("Legacy Player2HealthUpdate received - using new health system instead"); | |
}); | |
// Handle hit animation events from opponent | |
syncEntityPlayer1.onEventReceived.add('PlayHitAnimationOnOpponent', function(messageInfo) { | |
var animationData = messageInfo.data; | |
print("⚡ Received PlayHitAnimationOnOpponent event on Player1 sync: " + JSON.stringify(animationData)); | |
// Only play the animation if we're player2 (the target) | |
if (localPlayerNumber === "player2") { | |
print("✅ Playing hit animation on player2 (target)"); | |
if (animationData.type === "balloon") { | |
if (global.playBalloonHitAnimation) { | |
print("🎬 Playing balloon hit animation on player2"); | |
global.playBalloonHitAnimation(); | |
} else { | |
print("⚠️ Warning: playBalloonHitAnimation function not found in global scope"); | |
} | |
} else if (animationData.type === "slice") { | |
if (global.playSliceHitAnimation) { | |
print("🎬 Playing slice hit animation on player2"); | |
global.playSliceHitAnimation(); | |
} else { | |
print("⚠️ Warning: playSliceHitAnimation function not found in global scope"); | |
} | |
} | |
} else { | |
print("⏭️ Not playing animation - we are not the target (we are " + localPlayerNumber + ")"); | |
} | |
}); | |
// Remove old event handler | |
syncEntityPlayer1.onEventReceived.remove('HitAnimationEvent'); | |
} | |
if (!syncEntityPlayer2) { | |
syncEntityPlayer2 = new SyncEntity(script, null, true); | |
syncEntityPlayer2.notifyOnReady(function() { | |
print("SyncEntity health player2 is ready"); | |
}); | |
// Legacy event handlers - replaced by new health system | |
syncEntityPlayer2.onEventReceived.add('Player2OppHealth', function(messageInfo) { | |
print("Legacy Player2OppHealth event received - using new health system instead"); | |
}); | |
syncEntityPlayer2.onEventReceived.add('Player2Opp2Health', function(messageInfo) { | |
print("Legacy Player2Opp2Health event received - using new health system instead"); | |
}); | |
// Handle incoming health set events (when opponent reduces our health or regenerates) | |
syncEntityPlayer2.onEventReceived.add('HealthSetEvent', function(messageInfo) { | |
var healthData = messageInfo.data; | |
print("Received health set event: " + JSON.stringify(healthData)); | |
if (healthData.isDirectHealthSet) { | |
if (healthData.isRegeneration) { | |
// print("🔋 Received opponent's regenerated health: " + healthData.newHealth); | |
// Update the opponent's health display locally | |
opponentHealth = healthData.newHealth; | |
updateOpponentHealthDisplay(); | |
} else { | |
// print("💔 Setting local health directly to: " + healthData.newHealth); | |
setLocalHealthDirectly(healthData.newHealth); | |
} | |
} | |
}); | |
// Legacy health update handler - no longer used in new system | |
syncEntityPlayer2.onEventReceived.add('Player1HealthUpdate', function(messageInfo) { | |
print("Legacy Player1HealthUpdate received - using new health system instead"); | |
}); | |
// Handle hit animation events from opponent | |
syncEntityPlayer2.onEventReceived.add('PlayHitAnimationOnOpponent', function(messageInfo) { | |
var animationData = messageInfo.data; | |
print("⚡ Received PlayHitAnimationOnOpponent event on Player2 sync: " + JSON.stringify(animationData)); | |
// Only play the animation if we're player1 (the target) | |
if (localPlayerNumber === "player1") { | |
print("✅ Playing hit animation on player1 (target)"); | |
if (animationData.type === "balloon") { | |
if (global.playBalloonHitAnimation) { | |
print("🎬 Playing balloon hit animation on player1"); | |
global.playBalloonHitAnimation(); | |
} else { | |
print("⚠️ Warning: playBalloonHitAnimation function not found in global scope"); | |
} | |
} else if (animationData.type === "slice") { | |
if (global.playSliceHitAnimation) { | |
print("🎬 Playing slice hit animation on player1"); | |
global.playSliceHitAnimation(); | |
} else { | |
print("⚠️ Warning: playSliceHitAnimation function not found in global scope"); | |
} | |
} | |
} else { | |
print("⏭️ Not playing animation - we are not the target (we are " + localPlayerNumber + ")"); | |
} | |
}); | |
// Remove old event handler | |
syncEntityPlayer2.onEventReceived.remove('HitAnimationEvent'); | |
} | |
if (!syncEntityDeath) { | |
syncEntityDeath = new SyncEntity(script, null, true); | |
// Set up death event handler | |
syncEntityDeath.onEventReceived.add('Death', function(messageInfo) { | |
print("Received Opponent death event"); | |
handleCharacterDeath(); | |
}); | |
} | |
// Update health display on initialization | |
updateHealthDisplay(true); | |
// Initialize opponent health display | |
updateOpponentHealthDisplay(); | |
// Set up collision handlers for both player objects | |
setupPlayerCollisionDetection(); | |
// Set up collision handlers for saber objects | |
setupSaberCollisionDetection(); | |
// Disable the update event once everything is set up | |
updateEvent.enabled = false; | |
} | |
} | |
// Create the update event and bind it to the onUpdate function | |
var updateEvent = script.createEvent('UpdateEvent'); | |
updateEvent.bind(onUpdate); | |
}; | |
// Set up collision detection for opponent player only | |
function setupPlayerCollisionDetection() { | |
print("=== SETTING UP OPPONENT COLLISION DETECTION ==="); | |
print("Local player: " + localPlayerNumber); | |
// Hide local player's visual components to prevent self-collision | |
hideLocalPlayerVisuals(); | |
// IMPORTANT: Only set up collision detection for the OPPONENT player | |
// Local player will NEVER have collision events - only the opponent can be hit | |
var opponentPlayer = null; | |
var opponentName = ""; | |
if (localPlayerNumber === "player1") { | |
// Player 1 is local - set up collision ONLY for Player 2 (opponent) | |
opponentPlayer = script.player2; | |
opponentName = "player2"; | |
print("Player 1 is local - setting up collision detection for Player 2 only"); | |
} else if (localPlayerNumber === "player2") { | |
// Player 2 is local - set up collision ONLY for Player 1 (opponent) | |
opponentPlayer = script.player1; | |
opponentName = "player1"; | |
print("Player 2 is local - setting up collision detection for Player 1 only"); | |
} | |
if (opponentPlayer) { | |
var opponentCollider = opponentPlayer.getComponent("Physics.ColliderComponent"); | |
if (opponentCollider) { | |
// This collision event will ONLY fire when the OPPONENT gets hit | |
// The local player will never trigger collision events | |
opponentCollider.onCollisionEnter.add(function (e) { | |
print(">>> OPPONENT " + opponentName + " got hit (NOT local player) <<<"); | |
// Handle opponent taking damage | |
onOpponentHitHandler(opponentName, e.collision); | |
}); | |
print("✓ Collision detection set up ONLY for opponent: " + opponentName); | |
print("✓ Local player (" + localPlayerNumber + ") will NOT trigger collision events"); | |
} else { | |
print("✗ Warning: Opponent has no ColliderComponent"); | |
} | |
} else { | |
print("✗ Warning: No opponent player object found"); | |
} | |
} | |
// Hide local player's visual mesh and physics collider to prevent self-collision | |
function hideLocalPlayerVisuals() { | |
print("=== HIDING LOCAL PLAYER VISUALS ==="); | |
print("Local player: " + localPlayerNumber); | |
var localPlayer = null; | |
if (localPlayerNumber === "player1") { | |
localPlayer = script.player1; | |
} else if (localPlayerNumber === "player2") { | |
localPlayer = script.player2; | |
} | |
if (localPlayer) { | |
print("Hiding visuals for local player: " + localPlayer.name); | |
// Hide all RenderMeshVisual components on the local player and its children | |
hideRenderMeshVisuals(localPlayer); | |
// Disable physics collider for the local player to prevent self-collision | |
var localCollider = localPlayer.getComponent("Physics.ColliderComponent"); | |
if (localCollider) { | |
localCollider.enabled = false; | |
print("✓ Disabled physics collider for local player: " + localPlayer.name); | |
} else { | |
print("⚠ No physics collider found on local player: " + localPlayer.name); | |
} | |
print("✓ Local player visuals hidden successfully"); | |
} else { | |
print("✗ Warning: Local player object not found"); | |
} | |
} | |
// Recursively hide RenderMeshVisual components on an object and its children | |
function hideRenderMeshVisuals(sceneObject) { | |
if (!sceneObject) return; | |
// Hide RenderMeshVisual components on this object | |
var renderMeshVisuals = sceneObject.getComponents("Component.RenderMeshVisual"); | |
for (var i = 0; i < renderMeshVisuals.length; i++) { | |
renderMeshVisuals[i].enabled = false; | |
print("✓ Disabled RenderMeshVisual on: " + sceneObject.name); | |
} | |
// Recursively hide visuals on child objects | |
var childCount = sceneObject.getChildrenCount(); | |
for (var j = 0; j < childCount; j++) { | |
var child = sceneObject.getChild(j); | |
hideRenderMeshVisuals(child); | |
} | |
} | |
// Function to show local player visuals (for debugging or special cases) | |
function showLocalPlayerVisuals() { | |
print("=== SHOWING LOCAL PLAYER VISUALS ==="); | |
print("Local player: " + localPlayerNumber); | |
var localPlayer = null; | |
if (localPlayerNumber === "player1") { | |
localPlayer = script.player1; | |
} else if (localPlayerNumber === "player2") { | |
localPlayer = script.player2; | |
} | |
if (localPlayer) { | |
print("Showing visuals for local player: " + localPlayer.name); | |
// Show all RenderMeshVisual components on the local player and its children | |
showRenderMeshVisuals(localPlayer); | |
// Re-enable physics collider for the local player | |
var localCollider = localPlayer.getComponent("Physics.ColliderComponent"); | |
if (localCollider) { | |
localCollider.enabled = true; | |
print("✓ Enabled physics collider for local player: " + localPlayer.name); | |
} | |
print("✓ Local player visuals shown successfully"); | |
} else { | |
print("✗ Warning: Local player object not found"); | |
} | |
} | |
// Recursively show RenderMeshVisual components on an object and its children | |
function showRenderMeshVisuals(sceneObject) { | |
if (!sceneObject) return; | |
// Show RenderMeshVisual components on this object | |
var renderMeshVisuals = sceneObject.getComponents("Component.RenderMeshVisual"); | |
for (var i = 0; i < renderMeshVisuals.length; i++) { | |
renderMeshVisuals[i].enabled = true; | |
print("✓ Enabled RenderMeshVisual on: " + sceneObject.name); | |
} | |
// Recursively show visuals on child objects | |
var childCount = sceneObject.getChildrenCount(); | |
for (var j = 0; j < childCount; j++) { | |
var child = sceneObject.getChild(j); | |
showRenderMeshVisuals(child); | |
} | |
} | |
// Simple handler when opponent gets hit - reduce their health locally and send update | |
function onOpponentHitHandler(opponentName, eventData) { | |
print("=== OPPONENT HIT ==="); | |
print("Opponent: " + opponentName + " got hit"); | |
// Use simple collision detection like old health manager | |
var collidingObject = eventData.collider; | |
if (collidingObject) { | |
var objectName = collidingObject.getSceneObject().name; | |
print("Hit by object: " + objectName); | |
// Get damage amount | |
var damageAmount = objectDamageAmounts[objectName] || defaultDamage; | |
print("Applying " + damageAmount + " damage to opponent"); | |
// Reduce opponent's health locally | |
applyDamageToOpponent(damageAmount, objectName, 10.0); | |
// Play damage sound effect | |
if (script.damageSoundEffect) { | |
script.damageSoundEffect.play(1); | |
} | |
// Send appropriate hit animation to opponent based on object type | |
if (objectName.toLowerCase().includes("ballon")) { | |
// Send balloon hit animation message to opponent instead of playing locally | |
sendHitAnimationToOpponent("balloon"); | |
} else if (objectName.toLowerCase().includes("slice")) { | |
// Send slice hit animation message to opponent instead of playing locally | |
sendHitAnimationToOpponent("slice"); | |
} | |
} else { | |
print("✗ No colliding object found"); | |
} | |
} | |
// Set up collision detection for saber objects | |
function setupSaberCollisionDetection() { | |
print("=== SETTING UP SABER COLLISION DETECTION ==="); | |
print("Sabers array exists: " + (script.sabers ? "YES" : "NO")); | |
print("Sabers array length: " + (script.sabers ? script.sabers.length : "N/A")); | |
if (script.sabers && script.sabers.length > 0) { | |
for (var i = 0; i < script.sabers.length; i++) { | |
var saber = script.sabers[i]; | |
if (saber) { | |
print("Setting up collision for saber: " + saber.name); | |
var saberCollider = saber.getComponent("Physics.ColliderComponent"); | |
if (saberCollider) { | |
// Create a closure to capture the saber name | |
(function(saberName) { | |
saberCollider.onCollisionEnter.add(function (e) { | |
print(">>> Saber collision detected: " + saberName + " <<<"); | |
onCollisionHandler(e); | |
}); | |
})(saber.name); | |
print("✓ Saber collision handler set up for: " + saber.name); | |
} else { | |
print("✗ Warning: Saber " + saber.name + " has no ColliderComponent"); | |
} | |
} else { | |
print("✗ Warning: Saber at index " + i + " is null"); | |
} | |
} | |
} else { | |
print("✗ Warning: No saber objects assigned or empty array"); | |
} | |
} | |
// Function to set the local player number (can be called externally) | |
script.setLocalPlayerNumber = function(playerNumber) { | |
localPlayerNumber = playerNumber; | |
print("Local player number set to: " + localPlayerNumber); | |
}; | |
// DEBUG: Test function to manually trigger damage | |
script.testDamage = function() { | |
print("=== MANUAL DAMAGE TEST ==="); | |
print("Current health: " + currentHealth); | |
print("Local player: " + localPlayerNumber); | |
// Test local damage | |
print("Testing local damage..."); | |
applyLocalDamage(10, "TEST_OBJECT", 5); | |
// Test opponent damage (if we have an opponent) | |
if (localPlayerNumber === "player1") { | |
print("Testing opponent damage to player2..."); | |
applyDamageToPlayer("player2", 15, "TEST_SABER", 8); | |
} else if (localPlayerNumber === "player2") { | |
print("Testing opponent damage to player1..."); | |
applyDamageToPlayer("player1", 15, "TEST_SABER", 8); | |
} | |
}; | |
// DEBUG: Test function to simulate collision | |
script.testCollision = function() { | |
print("=== MANUAL COLLISION TEST ==="); | |
// Create a mock collision event | |
var mockEvent = { | |
collision: { | |
collider: { | |
getSceneObject: function() { | |
return { | |
name: localPlayerNumber === "player1" ? "player1saber1" : "player2saber1" | |
}; | |
} | |
}, | |
otherCollider: { | |
getSceneObject: function() { | |
return { | |
name: localPlayerNumber === "player1" ? script.player2.name : script.player1.name | |
}; | |
} | |
} | |
} | |
}; | |
print("Simulating collision: " + mockEvent.collision.collider.getSceneObject().name + " hits " + mockEvent.collision.otherCollider.getSceneObject().name); | |
onCollisionHandler(mockEvent); | |
}; | |
// Make functions available to other scripts | |
script.applyDamageToPlayer = applyDamageToPlayer; | |
script.getCurrentHealth = function() { return Math.max(0, currentHealth); }; // Ensure health is never reported as below 0 | |
script.setCurrentHealth = function(value) { | |
var previousHealth = currentHealth; | |
currentHealth = Math.max(0, Math.min(script.maxHealth, value)); | |
// Only update if the health actually changed | |
if (previousHealth !== currentHealth) { | |
updateHealthDisplay(true); | |
// Check if health regeneration should be scheduled or stopped | |
if (script.enableHealthRegeneration && currentHealth < script.maxHealth && currentHealth > 0) { | |
scheduleRegeneration(); | |
} else if (currentHealth >= script.maxHealth) { | |
stopRegeneration(); | |
} | |
} | |
}; | |
script.restoreHealth = function(amount) { | |
var previousHealth = currentHealth; | |
currentHealth = Math.min(script.maxHealth, currentHealth + amount); | |
// Only update if health actually changed | |
if (previousHealth !== currentHealth) { | |
updateHealthDisplay(true); | |
// Stop regeneration if health is full | |
if (currentHealth >= script.maxHealth) { | |
function delayedFunction(eventData) { | |
currentHealth = script.maxHealth; | |
updateHealthDisplay(true); | |
stopRegeneration(); | |
} | |
// Create a DelayedCallbackEvent | |
var delayedEvent = script.createEvent('DelayedCallbackEvent'); | |
// Set the delay time in seconds | |
delayedEvent.bind(delayedFunction); | |
delayedEvent.reset(2.0); | |
} | |
} | |
}; | |
script.resetHealth = function() { | |
var previousHealth = currentHealth; | |
currentHealth = script.maxHealth; | |
// Only update if health actually changed | |
if (previousHealth !== currentHealth) { | |
updateHealthDisplay(true); | |
stopRegeneration(); | |
} | |
}; | |
// New functions to control regeneration from outside | |
script.enableRegeneration = function(enable) { | |
script.enableHealthRegeneration = enable; | |
if (!enable) { | |
stopRegeneration(); | |
} else if (currentHealth < script.maxHealth && currentHealth > 0) { | |
scheduleRegeneration(); | |
} | |
}; | |
script.setRegenerationRate = function(rate) { | |
script.regenerationRate = rate; | |
}; | |
script.setRegenerationDelay = function(delay) { | |
script.regenerationDelay = delay; | |
}; | |
// Public functions to control player visibility | |
script.hideLocalPlayerVisuals = function() { | |
hideLocalPlayerVisuals(); | |
}; | |
script.showLocalPlayerVisuals = function() { | |
showLocalPlayerVisuals(); | |
}; | |
// Function to get current local player number | |
script.getLocalPlayerNumber = function() { | |
return localPlayerNumber; | |
}; | |
// NATIVE LOGGER | |
import LogLevelProvider from "../Providers/InteractionConfigurationProvider/LogLevelProvider" | |
import SIKLogLevelProvider from "../Providers/InteractionConfigurationProvider/SIKLogLevelProvider" | |
import {logWithTag} from "./logger" | |
import {LogLevel} from "./LogLevel" | |
export default class NativeLogger { | |
private sikLogLevelProvider = SIKLogLevelProvider.getInstance() | |
private tag: string | |
private logger: (...args: any[]) => void | |
private logLevelFilter: LogLevel | |
private logLevelProvider: LogLevelProvider | |
constructor(tag: string, logLevelProvider?: LogLevelProvider) { | |
this.tag = tag | |
this.logger = logWithTag(tag) | |
this.logLevelProvider = logLevelProvider ?? this.sikLogLevelProvider | |
this.logLevelFilter = this.logLevelProvider.logLevel | |
// Add error handling around event subscription | |
try { | |
if (this.logLevelProvider && this.logLevelProvider.onLogLevelChanged && typeof this.logLevelProvider.onLogLevelChanged.add === 'function') { | |
this.logLevelProvider.onLogLevelChanged.add(this.updateLogLevel.bind(this)) | |
} | |
} catch (error) { | |
// Silently handle the error to prevent crashes during prefab destruction | |
print(`Failed to subscribe to log level changes for tag: ${tag}`) | |
} | |
} | |
i(message: string): void { | |
if (!this.shouldLog(LogLevel.Info)) { | |
return | |
} | |
this.logger(this.tag, message) | |
} | |
d(message: string): void { | |
if (!this.shouldLog(LogLevel.Debug)) { | |
return | |
} | |
this.logger(this.tag, message) | |
} | |
e(message: string): void { | |
if (!this.shouldLog(LogLevel.Error)) { | |
return | |
} | |
this.logger(this.tag, message) | |
} | |
w(message: string): void { | |
if (!this.shouldLog(LogLevel.Warning)) { | |
return | |
} | |
this.logger(this.tag, message) | |
} | |
v(message: string): void { | |
if (!this.shouldLog(LogLevel.Verbose)) { | |
return | |
} | |
this.logger(this.tag, message) | |
} | |
private shouldLog(logLevel: LogLevel): boolean { | |
return logLevel <= this.logLevelFilter | |
} | |
private updateLogLevel(logLevel: LogLevel): void { | |
this.logLevelFilter = logLevel | |
} | |
} | |
// EVENT WRAPPER | |
import {SyncKitLogger} from "../Utils/SyncKitLogger" | |
const TAG = "EventWrapper" | |
/** | |
* Simple implementation of an event class. Add callbacks to be notified when the event is triggered. | |
* @class | |
* @template T | |
*/ | |
export class EventWrapper<T extends any[]> { | |
private log = new SyncKitLogger(TAG) | |
private _callbacks: ((...args: T) => void)[] = [] | |
/** | |
* Add a callback function to this event. The callback function will be executed when this event is triggered. | |
* @param {(...args: T) => void} callback Callback function to execute | |
*/ | |
add(callback: (...args: T) => void): (...args: T) => void { | |
if (typeof callback === "function") { | |
this._callbacks.push(callback) | |
return callback | |
} else { | |
throw "Trying to add invalid callback type to EventWrapper. You must add a function." | |
} | |
} | |
/** | |
* Remove a callback function from this event. | |
* @param {(...args:T) => void} callback Callback function to remove | |
*/ | |
remove(callback: (...args: T) => void): void { | |
const ind = this._callbacks.indexOf(callback) | |
if (ind > -1) { | |
this._callbacks.splice(ind, 1) | |
} else { | |
this.log.e( | |
"Trying to remove callback from EventWrapper, but the callback hasn't been added." | |
) | |
} | |
} | |
/** | |
* Trigger the event so that all callbacks are executed. | |
* All arguments given will be passed to the callbacks. | |
* @param {T} args Arguments to pass to callbacks | |
*/ | |
trigger(...args: T): void { | |
const callbacks = this._callbacks.slice() | |
for (let i = 0; i < callbacks.length; i++) { | |
try { | |
if (typeof callbacks[i] === 'function') { | |
callbacks[i](...args) | |
} | |
} catch (error) { | |
// Handle errors during callback execution to prevent crashes | |
this.log.e(`Error in event callback: ${error}`) | |
} | |
} | |
} | |
} | |
// These exports exist for javascript compatibility, and should not be used from typescript code. | |
;(global as any).EventWrapper = EventWrapper |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment