Compare commits

...

6 Commits

@ -10,13 +10,14 @@ MonoBehaviour:
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4e7350d0607d7cc46a92f7ff596ad88d, type: 3}
m_Name: SlowZoneAbility
m_Name: DashNCrash
m_EditorClassIdentifier:
abilityName: Slowdown Area
abilityKey: Slowdown
keybind: 113
cooldownTime: 3
abilityRadius: 4
abilityDuration: 3
abilityKey: DashNCrash
abilityName: DashNCrash
abilityRadius: 3
abilityMagnitude: 0.3
abilityPrefab: {fileID: 5818330108676053786, guid: 4979352732bf84b44a9c789bef80b18a, type: 3}
abilityDuration: 3
abilityCooldownTime: 3
prefab: {fileID: 5818330108676053786, guid: 4979352732bf84b44a9c789bef80b18a, type: 3}
dashSpeed: 15
dashDuration: 0.5

@ -13,8 +13,9 @@ GameObject:
- component: {fileID: 825873091886110301}
- component: {fileID: 8294231852451494523}
- component: {fileID: 7596904637393423818}
- component: {fileID: 1396255635289861961}
m_Layer: 0
m_Name: SlowDownZonePrefab
m_Name: DashNCrashPrefab
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@ -97,7 +98,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 725408325
GlobalObjectIdHash: 1238939516
InScenePlacedSourceGlobalObjectIdHash: 0
AlwaysReplicateAsRoot: 0
SynchronizeTransform: 1
@ -119,3 +120,25 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
Ability: {fileID: 11400000, guid: e4794e2f71f66a74486c797344695ce7, type: 2}
visualEffectPrefab: {fileID: 3894374618083898175, guid: 63d404b949e644e4a92db7444ae88671, type: 3}
--- !u!135 &1396255635289861961
SphereCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5818330108676053786}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 1
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 3
m_Radius: 3
m_Center: {x: 0, y: 2.46, z: 0}

@ -300,6 +300,9 @@ PrefabInstance:
- targetCorrespondingSourceObject: {fileID: 4600110157238723781, guid: 0d2d836e2e83b754fa1a1c4022d6d65d, type: 3}
insertIndex: -1
addedObject: {fileID: 7049454171559621213}
- targetCorrespondingSourceObject: {fileID: 4600110157238723781, guid: 0d2d836e2e83b754fa1a1c4022d6d65d, type: 3}
insertIndex: -1
addedObject: {fileID: 4321537148236331373}
m_SourcePrefab: {fileID: 100100000, guid: 0d2d836e2e83b754fa1a1c4022d6d65d, type: 3}
--- !u!114 &741733315856861890 stripped
MonoBehaviour:
@ -369,6 +372,7 @@ MonoBehaviour:
m_ServerCharacter: {fileID: 741733315856861890}
m_PhysicsWrapper: {fileID: 6116655102486013040}
m_AbilitySystem: {fileID: 7049454171559621213}
m_UIMessageFeed: {fileID: 0}
--- !u!114 &4887850889182527394
MonoBehaviour:
m_ObjectHideFlags: 0
@ -747,6 +751,18 @@ MonoBehaviour:
abilities:
- {fileID: 11400000, guid: e4794e2f71f66a74486c797344695ce7, type: 2}
currentAbilityIndicator: {fileID: 92142163933926358}
--- !u!114 &4321537148236331373
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6009713983291384756}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a73f85cd904406945a2192aaecb2c310, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &6009713983291384766 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 4600110157238723791, guid: 0d2d836e2e83b754fa1a1c4022d6d65d, type: 3}

@ -1232,6 +1232,72 @@ MonoBehaviour:
ChildScenesToLoadConfig:
- {fileID: 102900000, guid: a542218ba547130469444ba04f9bef35, type: 3}
- {fileID: 102900000, guid: f77e38f2b72c5f649902d637b3a70b42, type: 3}
--- !u!1 &698889474
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 698889477}
- component: {fileID: 698889475}
- component: {fileID: 698889476}
m_Layer: 0
m_Name: ScoreManager
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!114 &698889475
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698889474}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier:
GlobalObjectIdHash: 2391970879
InScenePlacedSourceGlobalObjectIdHash: 0
AlwaysReplicateAsRoot: 0
SynchronizeTransform: 1
ActiveSceneSynchronization: 0
SceneMigrationSynchronization: 1
SpawnWithObservers: 1
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
--- !u!114 &698889476
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698889474}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c42f66f946855da4b99f79c5bde1d545, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!4 &698889477
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 698889474}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &791609700
PrefabInstance:
m_ObjectHideFlags: 0
@ -8597,11 +8663,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1676734515771252668, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalRotation.w
value: 0.8529446
value: 0.85294455
objectReference: {fileID: 0}
- target: {fileID: 1676734515771252668, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalRotation.x
value: 0.39434478
value: 0.3943448
objectReference: {fileID: 0}
- target: {fileID: 1676734515771252668, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalRotation.y
@ -8609,7 +8675,7 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1676734515771252668, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalRotation.z
value: -0.14352977
value: -0.14352979
objectReference: {fileID: 0}
- target: {fileID: 1676734516302391364, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_UpdateMethod
@ -8641,11 +8707,11 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 1676734516695783279, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalRotation.y
value: 0.30972984
value: 0.3097298
objectReference: {fileID: 0}
- target: {fileID: 1676734516695783279, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalRotation.z
value: -0.1450697
value: -0.14506969
objectReference: {fileID: 0}
- target: {fileID: 1676734516724634599, guid: 0193228de87741d40a42e561901c9083, type: 3}
propertyPath: m_LocalPosition.z
@ -8758,15 +8824,15 @@ PrefabInstance:
objectReference: {fileID: 0}
- target: {fileID: 203267159508449512, guid: 36b3ee75677a1544191c0ddaaadd8140, type: 3}
propertyPath: m_LocalRotation.x
value: 0.3943448
value: 0.39434484
objectReference: {fileID: 0}
- target: {fileID: 203267159508449512, guid: 36b3ee75677a1544191c0ddaaadd8140, type: 3}
propertyPath: m_LocalRotation.y
value: 0.31044644
value: 0.3104465
objectReference: {fileID: 0}
- target: {fileID: 203267159508449512, guid: 36b3ee75677a1544191c0ddaaadd8140, type: 3}
propertyPath: m_LocalRotation.z
value: -0.14352976
value: -0.1435298
objectReference: {fileID: 0}
- target: {fileID: 203267159508449512, guid: 36b3ee75677a1544191c0ddaaadd8140, type: 3}
propertyPath: m_LocalEulerAnglesHint.x
@ -9235,6 +9301,7 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
confirmationPanel: {fileID: 125665959027215112}
swapwithname: {fileID: 0}
--- !u!4 &1486746210
Transform:
m_ObjectHideFlags: 0
@ -10669,3 +10736,4 @@ SceneRoots:
- {fileID: 1690610726}
- {fileID: 1486746210}
- {fileID: 396364068}
- {fileID: 698889477}

@ -38,7 +38,7 @@ RenderSettings:
m_ReflectionIntensity: 1
m_CustomReflection: {fileID: 0}
m_Sun: {fileID: 0}
m_IndirectSpecularColor: {r: 0.12731749, g: 0.13414757, b: 0.1210787, a: 1}
m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1}
m_UseRadianceAmbientProbe: 0
--- !u!157 &3
LightmapSettings:
@ -1524,6 +1524,10 @@ PrefabInstance:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 370034730102636685, guid: 4512c09d24f3fa147afb198fa90d63c6, type: 3}
propertyPath: SlowDownAbilityKey
value: DashNCrash
objectReference: {fileID: 0}
- target: {fileID: 370034730102636685, guid: 4512c09d24f3fa147afb198fa90d63c6, type: 3}
propertyPath: m_GeneralSwapActionPrototype
value:

@ -1,28 +1,29 @@
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using UnityEngine;
public abstract class Ability : ScriptableObject
{
[Header("Ability Settings")]
public string abilityName;
public string abilityKey;
public KeyCode keybind; // Key to activate the ability
public float cooldownTime; // Cooldown duration in seconds
public string abilityName;
[Header("Common Ability Settings")]
public float abilityRadius;
public float abilityDuration;
public float abilityMagnitude;
public float abilityDuration;
public float abilityCooldownTime;
[Header("Ability Prefab")]
public GameObject prefab;
[SerializeField]
private GameObject abilityPrefab; // Prefab associated with this ability
/// <summary>
/// Executes the ability's specific behavior.
/// </summary>
public abstract void Execute(ServerCharacter character, Vector3 targetPosition);
/// <summary>
/// Retrieves the prefab associated with this ability.
/// </summary>
public GameObject GetPrefab()
{
return abilityPrefab;
return prefab;
}
public void ActivateAbility(GameObject owner)
{
Activate(owner);
}
protected abstract void Activate(GameObject owner); // Logic for the specific ability
}

@ -1,5 +1,7 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using Unity.Netcode;
using UnityEngine;
@ -8,9 +10,8 @@ public class AbilitySystem : NetworkBehaviour
[Header("Assigned Abilities")]
public List<Ability> abilities = new List<Ability>();
private Ability activeAbility; // Tracks the currently active ability in "spawn mode"
private Ability activeAbility;
private bool isAbilityActive = false;
private HashSet<Ability> abilitiesOnCooldown = new HashSet<Ability>();
[SerializeField] private GameObject currentAbilityIndicator;
@ -27,9 +28,6 @@ public class AbilitySystem : NetworkBehaviour
}
}
/// <summary>
/// Activates an ability by its keybind.
/// </summary>
public void ActivateAbilityByKey(string key)
{
foreach (var ability in abilities)
@ -52,7 +50,7 @@ public class AbilitySystem : NetworkBehaviour
public bool IsAbilityModeActive()
{
return isAbilityActive; // Returns true if an ability mode is currently active
return isAbilityActive;
}
private void ToggleAbilityMode(Ability ability)
@ -71,7 +69,7 @@ public class AbilitySystem : NetworkBehaviour
{
isAbilityActive = true;
activeAbility = ability;
currentAbilityIndicator.SetActive(true);
currentAbilityIndicator?.SetActive(true);
Debug.Log($"Ability {ability.abilityName} activated! Click to use.");
}
@ -79,67 +77,70 @@ public class AbilitySystem : NetworkBehaviour
{
isAbilityActive = false;
activeAbility = null;
currentAbilityIndicator.SetActive(false);
currentAbilityIndicator?.SetActive(false);
Debug.Log("Ability mode deactivated.");
}
private void UseActiveAbility()
public void UseActiveAbility()
{
if (activeAbility != null)
{
var spawnPosition = currentAbilityIndicator.transform.position;
SpawnAbilityServerRpc(activeAbility.abilityKey, spawnPosition);
Debug.Log($"[AbilitySystem] Using active ability {activeAbility.abilityName}.");
Vector3 targetPosition = currentAbilityIndicator.transform.position;
RequestAbilityActivationServerRpc(activeAbility.abilityKey, targetPosition);
StartCoroutine(StartCooldown(activeAbility));
DeactivateAbilityMode();
}
else
{
Debug.LogWarning("[AbilitySystem] No active ability to use.");
}
}
/// <summary>
/// Starts the cooldown coroutine for the ability.
/// </summary>
private IEnumerator StartCooldown(Ability ability)
[ServerRpc(RequireOwnership = false)]
private void RequestAbilityActivationServerRpc(string abilityKey, Vector3 targetPosition, ServerRpcParams rpcParams = default)
{
abilitiesOnCooldown.Add(ability);
Debug.Log($"{ability.abilityName} is now on cooldown for {ability.cooldownTime} seconds.");
ulong ownerClientId = rpcParams.Receive.SenderClientId;
yield return new WaitForSeconds(ability.cooldownTime);
Debug.Log($"[AbilitySystem] Received activation request for ability '{abilityKey}' from client {ownerClientId} at position {targetPosition}.");
abilitiesOnCooldown.Remove(ability);
Debug.Log($"{ability.abilityName} is off cooldown.");
ExecuteAbilityOnServer(abilityKey, ownerClientId, targetPosition);
}
/// <summary>
/// Spawns the requested ability on the server.
/// </summary>
[ServerRpc(RequireOwnership = false)]
private void SpawnAbilityServerRpc(string abilityKey, Vector3 position, ServerRpcParams rpcParams = default)
private void ExecuteAbilityOnServer(string abilityKey, ulong ownerClientId, Vector3 targetPosition)
{
var ability = abilities.Find(a => a.abilityKey == abilityKey);
if (ability == null)
// Find the player's ServerCharacter
var playerObject = NetworkManager.Singleton.SpawnManager.SpawnedObjectsList
.FirstOrDefault(obj => obj.OwnerClientId == ownerClientId && obj.GetComponent<ServerCharacter>());
if (playerObject == null || !playerObject.TryGetComponent(out ServerCharacter character))
{
Debug.LogError($"Ability {abilityKey} not found in the Ability System!");
Debug.LogError($"[AbilitySystem] No ServerCharacter component found for player {ownerClientId}.");
return;
}
var prefab = ability.GetPrefab(); // Ensure your Ability class has a method to get the prefab
if (prefab == null)
// Find the ability
var ability = abilities.Find(a => a.abilityKey == abilityKey);
if (ability == null)
{
Debug.LogError($"Prefab for Ability {abilityKey} is not assigned!");
Debug.LogError($"[AbilitySystem] Ability {abilityKey} not found in the Ability System.");
return;
}
GameObject abilityInstance = Instantiate(prefab, position, Quaternion.identity);
var networkObject = abilityInstance.GetComponent<NetworkObject>();
// Activate the ability
Debug.Log($"[AbilitySystem] Activating ability {ability.abilityName} for player {ownerClientId} at {targetPosition}.");
ability.Execute(character, targetPosition);
}
if (networkObject != null)
{
networkObject.Spawn();
Debug.Log($"Spawned {abilityKey} at {position}.");
}
else
{
Debug.LogError($"Ability prefab {abilityKey} must have a NetworkObject component.");
}
private IEnumerator StartCooldown(Ability ability)
{
abilitiesOnCooldown.Add(ability);
Debug.Log($"{ability.abilityName} is now on cooldown for {ability.abilityCooldownTime} seconds.");
yield return new WaitForSeconds(ability.abilityCooldownTime);
abilitiesOnCooldown.Remove(ability);
Debug.Log($"{ability.abilityName} is off cooldown.");
}
private void UpdateIndicatorPosition()
@ -148,8 +149,11 @@ public class AbilitySystem : NetworkBehaviour
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit))
{
currentAbilityIndicator.transform.position = hit.point;
currentAbilityIndicator.transform.localScale = Vector3.one * activeAbility.abilityRadius;
if (currentAbilityIndicator != null)
{
currentAbilityIndicator.transform.position = hit.point;
currentAbilityIndicator.transform.localScale = Vector3.one * activeAbility.abilityRadius;
}
}
}
}

@ -111,6 +111,8 @@ public class CrowManager : NetworkBehaviour
}
}
/// <summary>
/// RPC to notify clients about the Crow change.
/// </summary>
@ -181,4 +183,5 @@ public class CrowManager : NetworkBehaviour
{
return currentCrow;
}
}

@ -0,0 +1,47 @@
using System.Collections;
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using UnityEngine;
using Unity.Netcode;
[CreateAssetMenu(menuName = "Abilities/DashNCrash")]
public class DashNCrashAbility : Ability
{
[Header("Dash Settings")]
public float dashSpeed = 10f;
public float dashDuration = 0.5f;
public override void Execute(ServerCharacter character, Vector3 targetPosition)
{
Debug.Log($"Executing DashNCrash for character {character.OwnerClientId} at {targetPosition}.");
// Start the dash
character.Movement.StartDash(targetPosition, dashSpeed, dashDuration);
// Delay spawning the slow zone until after the dash
character.StartCoroutine(SpawnSlowZoneAfterDash(character, targetPosition));
}
private IEnumerator SpawnSlowZoneAfterDash(ServerCharacter character, Vector3 position)
{
yield return new WaitForSeconds(dashDuration + 0.25f);
// Spawn the slow zone prefab at the dash's end position
var prefab = GetPrefab();
if (prefab != null)
{
GameObject instance = Instantiate(prefab, character.transform.position, Quaternion.identity);
var networkObject = instance.GetComponent<NetworkObject>();
if (networkObject != null)
{
networkObject.Spawn();
Debug.Log($"Slow Zone spawned at {position}.");
}
else
{
Debug.LogError("Slow Zone prefab must have a NetworkObject component.");
}
}
}
}

@ -0,0 +1,101 @@
using System.Collections;
using System.Collections.Generic;
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using Unity.Netcode;
using UnityEngine;
[RequireComponent(typeof(SphereCollider))]
public class DashNCrashPrefab : NetworkBehaviour
{
[Header("Slow Zone Settings")]
public Ability Ability;
public GameObject visualEffectPrefab; // Prefab for visualizing the area
private HashSet<ServerCharacter> affectedPlayers = new HashSet<ServerCharacter>();
private SphereCollider zoneCollider;
private GameObject visualEffectInstance;
private void Start()
{
zoneCollider = GetComponent<SphereCollider>();
// Spawn the visual effect
if (visualEffectPrefab)
{
visualEffectInstance = Instantiate(visualEffectPrefab, transform.position, Quaternion.identity);
visualEffectInstance.transform.localScale = Vector3.one * Ability.abilityRadius * 2f; // Adjust scale to match the radius
}
// Automatically destroy after the ability duration
StartCoroutine(DelayedDestroy());
}
private void OnTriggerEnter(Collider other)
{
if (other.TryGetComponent<ServerCharacter>(out var player))
{
if (!player.IsCrow && affectedPlayers.Add(player)) // Only affect non-crow players
{
player.Movement.SetSpeedModifier(Ability.abilityMagnitude);
Debug.Log($"{player.name} entered the slow zone. Speed reduced.");
}
}
}
private void OnTriggerExit(Collider other)
{
if (other.TryGetComponent<ServerCharacter>(out var player))
{
if (affectedPlayers.Remove(player))
{
player.Movement.ResetSpeedModifier();
Debug.Log($"{player.name} exited the slow zone. Speed restored.");
}
}
}
private void OnDestroy()
{
// Restore speed for all players when the zone is destroyed
foreach (var player in affectedPlayers)
{
player.Movement.ResetSpeedModifier();
Debug.Log($"{player.name}'s speed restored due to slow zone destruction.");
}
affectedPlayers.Clear();
// Destroy the visual effect
if (visualEffectInstance)
{
Destroy(visualEffectInstance);
}
}
private IEnumerator DelayedDestroy()
{
yield return new WaitForSeconds(Ability.abilityDuration);
if (IsServer)
{
DespawnZone();
}
}
private void DespawnZone()
{
if (IsServer)
{
var networkObject = GetComponent<NetworkObject>();
if (networkObject != null)
{
networkObject.Despawn(true); // Despawn and destroy on the server
Debug.Log("SlowZonePrefab has been despawned and destroyed.");
}
else
{
Debug.LogError("SlowZonePrefab is missing a NetworkObject component!");
}
}
}
}

@ -144,8 +144,12 @@ namespace Unity.BossRoom.Gameplay.GameplayObjects.Character
public ulong? PendingSwapRequest { get; set; }
public int? TargetPlatformId { get; private set; } = null;
public int? CurrentPlatformId { get; private set; } = null;
public int? PreviousPlatformId { get; private set; } = null;
public bool IsOnAPlatform { get; private set; } = false;
public bool IsCrow { get; private set; } = false;
public bool IsSwapping { get; private set; } = false;
public UIStateDisplayHandler uIStateDisplayHandler;
@ -178,49 +182,112 @@ namespace Unity.BossRoom.Gameplay.GameplayObjects.Character
{
Debug.LogError("SwapConfirmationPanel not found in the scene!");
}
//// Show the confirmation panel for the specific player
//var panel = FindObjectOfType<SwapConfirmationPanel>();
//if (panel != null)
//{
// panel.ShowPanel(this); // Pass the current ServerCharacter reference
//}
//else
//{
// Debug.LogError("SwapConfirmationPanel not found in the scene!");
//}
}
}
public void SetKinematic(bool isKinematic)
{
if (physicsWrapper != null)
{
var rigidbody = physicsWrapper.GetComponent<Rigidbody>();
if (rigidbody != null)
{
rigidbody.isKinematic = isKinematic;
}
}
}
public void SetAsCrow(bool status)
{
IsCrow = status;
if (IsServer)
{
IsCrow = status; // Update on the server
UpdateCrowStatusClientRpc(status); // Notify all clients
}
else
{
Debug.LogWarning("SetAsCrow should only be called on the server.");
}
}
[ClientRpc]
private void UpdateCrowStatusClientRpc(bool status)
{
IsCrow = status; // Update the value for all clients
}
public void SetTargetPlatform(int platformId)
{
TargetPlatformId = platformId;
if (IsServer)
{
TargetPlatformId = platformId; // Update on the server
UpdateTargetPlatformClientRpc(platformId); // Notify all clients
}
else
{
Debug.LogWarning("SetTargetPlatform should only be called on the server.");
}
}
public void ClearTargetPlatform()
{
TargetPlatformId = null;
if (IsServer)
{
TargetPlatformId = null; // Update on the server
UpdateTargetPlatformClientRpc(-1); // Notify all clients (use -1 to indicate no platform)
}
else
{
Debug.LogWarning("ClearTargetPlatform should only be called on the server.");
}
}
public void OnArrivalOnPlatform()
[ClientRpc]
private void UpdateTargetPlatformClientRpc(int platformId)
{
TargetPlatformId = platformId != -1 ? platformId : (int?)null; // Update the value for all clients
}
public void OnArrivalOnPlatform(int platformId)
{
ClearTargetPlatform();
SetOnPlatform(true);
SetOnPlatform(true, platformId); // Automatically syncs to all clients
}
public void OnLeavingPlatform(int platformId)
{
SetOnPlatform(false, platformId); // Automatically syncs to all clients
}
public void OnLeavingPlatform()
public void SetOnPlatform(bool status, int platformId)
{
SetOnPlatform(false);
if (IsServer)
{
IsOnAPlatform = status; // Update on the server
UpdatePlatformStatusClientRpc(status, platformId); // Notify all clients
}
else
{
Debug.LogWarning("SetOnPlatform should only be called on the server.");
}
}
public void SetOnPlatform(bool status)
[ClientRpc]
private void UpdatePlatformStatusClientRpc(bool status, int platformId)
{
IsOnAPlatform = status;
IsOnAPlatform = status; // Update the value for all clients
IsSwapping = false;
if (status)
{
CurrentPlatformId = platformId;
}
else
{
PreviousPlatformId = platformId;
CurrentPlatformId = null;
}
}
@ -245,6 +312,7 @@ namespace Unity.BossRoom.Gameplay.GameplayObjects.Character
var pltpos = PlatformManager.Instance.GetPlatformPosition(platform.PlatformID);
pltpos.y = 0;
Debug.Log($"Platform position: {pltpos}.");
IsSwapping = true;
ServerSendCharacterInputRpc(pltpos);
}

@ -91,14 +91,74 @@ namespace Unity.BossRoom.Gameplay.GameplayObjects.Character
m_NavPath.SetTargetPosition(position);
}
public void StartDash(Vector3 targetPosition, float dashSpeed, float duration)
{
if (!IsServer)
{
Debug.LogWarning("[ServerCharacterMovement] StartDash called on a client. This should only run on the server.");
return;
}
if (m_NavMeshAgent == null || m_Rigidbody == null)
{
Debug.LogError("[ServerCharacterMovement] NavMeshAgent or Rigidbody is null. Ensure they are assigned.");
return;
}
Debug.Log($"[ServerCharacterMovement] StartDash initiated. Target position: {targetPosition}, Speed: {dashSpeed}, Duration: {duration}");
Vector3 direction = (targetPosition - transform.position).normalized;
if (direction.sqrMagnitude > 0.001f)
{
transform.rotation = Quaternion.LookRotation(direction);
Debug.Log($"[ServerCharacterMovement] Adjusted rotation towards {targetPosition}.");
}
else
{
Debug.LogWarning("[ServerCharacterMovement] Dash direction vector is too small. Aborting dash.");
return;
}
StartForwardCharge(dashSpeed, duration);
Debug.Log("[ServerCharacterMovement] Dash executed successfully.");
}
public void StartForwardCharge(float speed, float duration)
{
if (!IsServer)
{
Debug.LogWarning("[ServerCharacterMovement] StartForwardCharge called on a client. This should only run on the server.");
return;
}
if (m_NavMeshAgent == null)
{
Debug.LogError("[ServerCharacterMovement] NavMeshAgent is null. Ensure it is assigned.");
return;
}
Debug.Log($"[ServerCharacterMovement] Starting forward charge for {name} with speed {speed} and duration {duration}.");
m_NavPath.Clear();
m_MovementState = MovementState.Charging;
m_ForcedSpeed = speed;
m_SpecialModeDurationRemaining = duration;
}
public void SetKinematic(bool isKinematic)
{
m_Rigidbody.isKinematic = isKinematic;
m_NavMeshAgent.enabled = !isKinematic; // Disable NavMeshAgent while kinematic
if (isKinematic)
{
m_Rigidbody.velocity = Vector3.zero; // Stop ongoing movement
}
}
public void StartKnockback(Vector3 knocker, float speed, float duration)
{
m_NavPath.Clear();

@ -81,7 +81,7 @@ namespace Unity.BossRoom.Gameplay.GameplayObjects
public Action DropActionPrototype => m_DropActionPrototype;
public Action PickUpActionPrototype => m_PickUpActionPrototype;
public string SlowDownAbilityKey = "Slowdown";
public string SlowDownAbilityKey = "DashNCrash";
List<Action> m_AllActions;

@ -44,13 +44,29 @@ namespace Unity.Multiplayer.Samples.BossRoom
return;
}
bool giveScore = player.PreviousPlatformId != PlatformID;
// Check if the player who occupied this platform had this platform as their target platform
if (giveScore)
{
if (player.TargetPlatformId.HasValue && player.TargetPlatformId.Value == PlatformID)
{
// Successful swap
ScoreManager.Instance.AddPlayerScore(player.OwnerClientId, 10);
Debug.Log($"Player {player.OwnerClientId} successfully swapped to Platform {PlatformID}. Awarded 10 score.");
}
else
{
ScoreManager.Instance.AddPlayerScore(player.OwnerClientId, 20);
Debug.Log($"Crow Player {player.OwnerClientId} successfully stole Platform {PlatformID}. Awarded 20 score.");
}
}
IsOccupied = true;
OccupierId.Value = player.OwnerClientId;
player.SetOnPlatform(true);
player.OnArrivalOnPlatform(PlatformID);
Debug.Log($"Platform {PlatformID} is now occupied by Player {player.OwnerClientId}.");
}
public void Vacate(ServerCharacter player)
{
if (!IsServer)
@ -67,7 +83,7 @@ namespace Unity.Multiplayer.Samples.BossRoom
IsOccupied = false;
OccupierId.Value = 0;
player.SetOnPlatform(false);
player.OnLeavingPlatform(PlatformID);
Debug.Log($"Platform {PlatformID} is now vacated.");
}
@ -81,7 +97,6 @@ namespace Unity.Multiplayer.Samples.BossRoom
if (!IsOccupied)
{
Occupy(player);
player.OnArrivalOnPlatform();
}
else
{
@ -102,7 +117,6 @@ namespace Unity.Multiplayer.Samples.BossRoom
if (other.TryGetComponent<ServerCharacter>(out var player) && OccupierId.Value == player.OwnerClientId)
{
Vacate(player);
player.OnLeavingPlatform();
}
}
}

@ -0,0 +1,34 @@
using UnityEngine;
using Unity.Netcode;
public class PlayerScoreComponent : NetworkBehaviour
{
public int CurrentScore { get; private set; }
public override void OnNetworkSpawn()
{
if (IsOwner && IsClient)
{
Debug.Log($"[PlayerScoreComponent] Requesting score initialization for Player {OwnerClientId}");
ScoreManager.Instance?.InitializePlayerScoreServerRpc(OwnerClientId);
}
// For the server player (host), ensure the PlayerScoreComponent is registered properly
if (IsServer && OwnerClientId == NetworkManager.Singleton.LocalClientId)
{
ScoreManager.Instance?.InitializePlayerScoreServerRpc(OwnerClientId);
}
}
public void UpdateScore(int newScore)
{
CurrentScore = newScore;
Debug.Log($"[PlayerScoreComponent] Player {OwnerClientId} score updated to {newScore}.");
UpdateScoreUI();
}
private void UpdateScoreUI()
{
// Update the player's score display in the UI.
Debug.Log($"[PlayerScoreComponent] Updated score UI for Player {OwnerClientId}: {CurrentScore}");
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a73f85cd904406945a2192aaecb2c310
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -0,0 +1,167 @@
using System.Collections;
using System.Collections.Generic;
using Unity.Multiplayer.Samples.BossRoom;
using UnityEngine;
using Unity.Netcode;
public class ScoreManager : NetworkBehaviour
{
public static ScoreManager Instance { get; private set; }
private Dictionary<ulong, int> playerScores = new Dictionary<ulong, int>();
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
public override void OnNetworkSpawn()
{
if (IsServer)
{
StartCrowPenaltyCoroutineServerRpc();
}
}
[ServerRpc(RequireOwnership = false)]
public void InitializePlayerScoreServerRpc(ulong ownerClientId)
{
if (!playerScores.ContainsKey(ownerClientId))
{
playerScores[ownerClientId] = 200;
Debug.Log($"[ScoreManager] Player {ownerClientId} initialized with a starting score of 200.");
UpdatePlayerScoreClientRpc(ownerClientId, 200);
}
else
{
Debug.LogWarning($"[ScoreManager] Player {ownerClientId} already initialized.");
}
}
public void UpdatePlayerScore(ulong ownerClientId, int newScore)
{
if (playerScores.ContainsKey(ownerClientId))
{
playerScores[ownerClientId] = newScore;
Debug.Log($"[ScoreManager] Updating Player {ownerClientId} score to {newScore}.");
UpdatePlayerScoreClientRpc(ownerClientId, newScore);
}
else
{
Debug.LogError($"[ScoreManager] No entry found for Player {ownerClientId}. Cannot update score.");
}
}
public void AddPlayerScore(ulong ownerClientId, int newScore)
{
if (playerScores.ContainsKey(ownerClientId))
{
playerScores[ownerClientId] += newScore;
Debug.Log($"[ScoreManager] Updating Player {ownerClientId} score to {playerScores[ownerClientId]}.");
UpdatePlayerScoreClientRpc(ownerClientId, playerScores[ownerClientId]);
}
else
{
Debug.LogError($"[ScoreManager] No entry found for Player {ownerClientId}. Cannot update score.");
}
}
public void SubtractPlayerScore(ulong ownerClientId, int scoreToSubtract)
{
if (playerScores.ContainsKey(ownerClientId))
{
int value = Mathf.Max(0, playerScores[ownerClientId] - scoreToSubtract);
playerScores[ownerClientId] = value;
Debug.Log($"[ScoreManager] Updating Player {ownerClientId} score to {playerScores[ownerClientId]}.");
UpdatePlayerScoreClientRpc(ownerClientId, playerScores[ownerClientId]);
}
else
{
Debug.LogError($"[ScoreManager] No entry found for Player {ownerClientId}. Cannot update score.");
}
}
public int GetPlayerScore(ulong ownerClientId)
{
if (playerScores.TryGetValue(ownerClientId, out var score))
{
return score;
}
Debug.LogError($"[ScoreManager] No entry found for Player {ownerClientId}.");
return 0; // Default score
}
[ServerRpc]
public void StartCrowPenaltyCoroutineServerRpc()
{
StartCoroutine(ApplyCrowPenaltyCoroutine());
}
private IEnumerator ApplyCrowPenaltyCoroutine()
{
yield return new WaitUntil(() => PlatformManager.Instance != null && PlatformManager.Instance.AreAllPlatformsOccupied());
while (true)
{
var modifications = new List<KeyValuePair<ulong, int>>();
foreach (var entry in playerScores)
{
var ownerClientId = entry.Key;
var score = entry.Value;
// Check if the player is the crow
if (CrowManager.Instance != null && CrowManager.Instance.GetCurrentCrow().OwnerClientId == ownerClientId)
{
var newScore = score - 2;
modifications.Add(new KeyValuePair<ulong, int>(ownerClientId, newScore));
Debug.Log($"[ScoreManager] Applied crow penalty to Player {ownerClientId}. New score: {newScore}");
}
}
// Apply the modifications after the iteration
foreach (var modification in modifications)
{
UpdatePlayerScore(modification.Key, modification.Value);
}
// Wait for the next penalty application
yield return new WaitForSeconds(5f);
}
}
[ClientRpc]
public void UpdatePlayerScoreClientRpc(ulong ownerClientId, int newScore)
{
Debug.Log($"[ScoreManager] Received score update for Player {ownerClientId}: {newScore}");
var playerScoreComponent = FindPlayerScoreComponent(ownerClientId);
if (playerScoreComponent != null)
{
playerScoreComponent.UpdateScore(newScore);
}
else
{
Debug.LogError($"[ScoreManager] Could not find PlayerScoreComponent for Player {ownerClientId}");
}
}
private PlayerScoreComponent FindPlayerScoreComponent(ulong ownerClientId)
{
foreach (var scoreComponent in FindObjectsOfType<PlayerScoreComponent>())
{
if (scoreComponent.OwnerClientId == ownerClientId)
{
return scoreComponent;
}
}
Debug.LogError($"[ScoreManager] Could not find PlayerScoreComponent for Player {ownerClientId}");
return null;
}
}

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c42f66f946855da4b99f79c5bde1d545
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

@ -1,11 +0,0 @@
using UnityEngine;
[CreateAssetMenu(menuName = "Abilities/Slow Zone Ability")]
public class SlowZoneAbility : Ability
{
protected override void Activate(GameObject owner)
{
// No direct logic here, spawning is handled in AbilitySystem
Debug.Log($"SlowZoneAbility activated by {owner.name}.");
}
}

@ -1,86 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using Unity.BossRoom.Gameplay.GameplayObjects.Character;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
public class SlowZonePrefab : NetworkBehaviour
{
[Header("Slow Zone Settings")]
public Ability Ability;
private void Start()
{
// Start the process to slow down players when the zone is spawned
StartCoroutine(ApplySlowEffect());
}
private IEnumerator ApplySlowEffect()
{
// Run the logic once immediately
ApplySlowToPlayers();
// Optionally, repeat the check while the zone exists
yield return new WaitForSeconds(Ability.abilityDuration);
// Destroy the zone after applying the slow effect
DespawnZone();
}
private void ApplySlowToPlayers()
{
// Find all colliders in the zone
Collider[] hitColliders = Physics.OverlapSphere(transform.position, Ability.abilityRadius);
foreach (var collider in hitColliders)
{
if (collider.TryGetComponent<ServerCharacter>(out var player))
{
// Check if the player is NOT the crow
if (!player.IsCrow)
{
// Apply slow effect
StartCoroutine(SlowPlayer(player));
Debug.Log($"{player.name} is slowed down!");
}
}
}
}
private IEnumerator SlowPlayer(ServerCharacter player)
{
// Halve the player's movement speed
player.Movement.SetSpeedModifier(Ability.abilityMagnitude);
// Wait for the slow duration
yield return new WaitForSeconds(Ability.abilityDuration);
// Restore the original speed
player.Movement.ResetSpeedModifier();
Debug.Log($"{player.name}'s speed is restored.");
Destroy(gameObject);
}
private void DespawnZone()
{
if (IsServer)
{
var networkObject = GetComponent<NetworkObject>();
if (networkObject != null)
{
networkObject.Despawn(true); // Despawn and destroy on the server
Debug.Log("SlowZonePrefab has been despawned and destroyed.");
}
else
{
Debug.LogError("SlowZonePrefab is missing a NetworkObject component!");
}
}
}
// Debug visualization for the slow zone in the editor
private void OnDrawGizmos()
{
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere(transform.position, Ability.abilityRadius);
}
}

@ -4,7 +4,7 @@
QualitySettings:
m_ObjectHideFlags: 0
serializedVersion: 5
m_CurrentQuality: 4
m_CurrentQuality: 0
m_QualitySettings:
- serializedVersion: 3
name: Low
@ -29,6 +29,7 @@ QualitySettings:
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 25
lodBias: 0.3
maximumLODLevel: 1
enableLODCrossFade: 1
@ -79,6 +80,7 @@ QualitySettings:
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 25
lodBias: 0.4
maximumLODLevel: 0
enableLODCrossFade: 1
@ -129,6 +131,7 @@ QualitySettings:
billboardsFaceCameraPosition: 1
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 25
lodBias: 1.5
maximumLODLevel: 0
enableLODCrossFade: 1
@ -179,6 +182,7 @@ QualitySettings:
billboardsFaceCameraPosition: 1
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 50
lodBias: 2
maximumLODLevel: 0
enableLODCrossFade: 1
@ -229,6 +233,7 @@ QualitySettings:
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 50
lodBias: 0.4
maximumLODLevel: 1
enableLODCrossFade: 1
@ -278,6 +283,7 @@ QualitySettings:
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 100
lodBias: 1
maximumLODLevel: 0
enableLODCrossFade: 1
@ -327,6 +333,7 @@ QualitySettings:
billboardsFaceCameraPosition: 0
useLegacyDetailDistribution: 1
vSyncCount: 0
realtimeGICPUUsage: 25
lodBias: 1.5
maximumLODLevel: 0
enableLODCrossFade: 1

Loading…
Cancel
Save