浏览代码
Feature/wave spawner (#30)
Feature/wave spawner (#30)
wave spawner for networked objects with modifiable wave params, state tracked with networkspawnerstate, spawner prefab, spawner visualization tracks hits/main
GitHub
4 年前
当前提交
83af5e62
共有 8 个文件被更改,包括 601 次插入 和 0 次删除
-
232Assets/BossRoom/Prefabs/EnemySpawner.prefab
-
7Assets/BossRoom/Prefabs/EnemySpawner.prefab.meta
-
54Assets/BossRoom/Scripts/Client/ClientSpawnerVisualization.cs
-
11Assets/BossRoom/Scripts/Client/ClientSpawnerVisualization.cs.meta
-
258Assets/BossRoom/Scripts/Server/ServerWaveSpawner.cs
-
11Assets/BossRoom/Scripts/Server/ServerWaveSpawner.cs.meta
-
17Assets/BossRoom/Scripts/Shared/NetworkSpawnerState.cs
-
11Assets/BossRoom/Scripts/Shared/NetworkSpawnerState.cs.meta
|
|||
%YAML 1.1 |
|||
%TAG !u! tag:unity3d.com,2011: |
|||
--- !u!1 &4132435922419856147 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 9136068542165043480} |
|||
- component: {fileID: 8205974096611502342} |
|||
m_Layer: 0 |
|||
m_Name: Client_Visuals |
|||
m_TagString: Untagged |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &9136068542165043480 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 4132435922419856147} |
|||
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_Children: |
|||
- {fileID: 3784477753691126980} |
|||
m_Father: {fileID: 8727022540156222958} |
|||
m_RootOrder: 0 |
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
|||
--- !u!114 &8205974096611502342 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 4132435922419856147} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: 65e25a152b731564ebb6096eb5e9f0ed, type: 3} |
|||
m_Name: |
|||
m_EditorClassIdentifier: |
|||
m_NetworkSpawnerState: {fileID: 9132488263322830174} |
|||
m_Animator: {fileID: 0} |
|||
--- !u!1 &6205854018081152875 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 8727022540156222958} |
|||
- component: {fileID: 7323075965458333149} |
|||
- component: {fileID: -1287160331463954971} |
|||
- component: {fileID: 4844841199312666291} |
|||
- component: {fileID: 9132488263322830174} |
|||
m_Layer: 6 |
|||
m_Name: EnemySpawner |
|||
m_TagString: Untagged |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &8727022540156222958 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6205854018081152875} |
|||
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_Children: |
|||
- {fileID: 9136068542165043480} |
|||
m_Father: {fileID: 0} |
|||
m_RootOrder: 0 |
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
|||
--- !u!136 &7323075965458333149 |
|||
CapsuleCollider: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6205854018081152875} |
|||
m_Material: {fileID: 0} |
|||
m_IsTrigger: 0 |
|||
m_Enabled: 1 |
|||
m_Radius: 0.5 |
|||
m_Height: 2 |
|||
m_Direction: 1 |
|||
m_Center: {x: 0, y: 0, z: 0} |
|||
--- !u!114 &-1287160331463954971 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6205854018081152875} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3} |
|||
m_Name: |
|||
m_EditorClassIdentifier: |
|||
NetworkedInstanceId: 0 |
|||
PrefabHash: 15589198230175896383 |
|||
PrefabHashGenerator: Spawner |
|||
AlwaysReplicateAsRoot: 0 |
|||
DontDestroyWithOwner: 0 |
|||
--- !u!114 &4844841199312666291 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6205854018081152875} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: 49b962917cae99f48a2a598485996b8d, type: 3} |
|||
m_Name: |
|||
m_EditorClassIdentifier: |
|||
m_NetworkSpawnerState: {fileID: 9132488263322830174} |
|||
m_NetworkedPrefab: {fileID: -7852138837387268381, guid: f520174fcd7d61441aa46a9923655dcd, type: 3} |
|||
m_BlockingMask: |
|||
serializedVersion: 2 |
|||
m_Bits: 1 |
|||
m_PlayerProximityValidationTimestep: 2 |
|||
m_NumberOfWaves: 2 |
|||
m_SpawnsPerWave: 2 |
|||
m_TimeBetweenSpawns: 0.5 |
|||
m_TimeBetweenWaves: 5 |
|||
m_RestartDelay: 10 |
|||
m_ProximityDistance: 30 |
|||
m_DormantCooldown: 10 |
|||
--- !u!114 &9132488263322830174 |
|||
MonoBehaviour: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6205854018081152875} |
|||
m_Enabled: 1 |
|||
m_EditorHideFlags: 0 |
|||
m_Script: {fileID: 11500000, guid: 4cfeccaf46c46e1458c3f7351d6753b3, type: 3} |
|||
m_Name: |
|||
m_EditorClassIdentifier: |
|||
--- !u!1 &6882351788430859438 |
|||
GameObject: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
serializedVersion: 6 |
|||
m_Component: |
|||
- component: {fileID: 3784477753691126980} |
|||
- component: {fileID: 1033544756360169842} |
|||
- component: {fileID: 4871652750507758710} |
|||
m_Layer: 0 |
|||
m_Name: Capsule |
|||
m_TagString: Untagged |
|||
m_Icon: {fileID: 0} |
|||
m_NavMeshLayer: 0 |
|||
m_StaticEditorFlags: 0 |
|||
m_IsActive: 1 |
|||
--- !u!4 &3784477753691126980 |
|||
Transform: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6882351788430859438} |
|||
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_Children: [] |
|||
m_Father: {fileID: 9136068542165043480} |
|||
m_RootOrder: 0 |
|||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} |
|||
--- !u!33 &1033544756360169842 |
|||
MeshFilter: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6882351788430859438} |
|||
m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} |
|||
--- !u!23 &4871652750507758710 |
|||
MeshRenderer: |
|||
m_ObjectHideFlags: 0 |
|||
m_CorrespondingSourceObject: {fileID: 0} |
|||
m_PrefabInstance: {fileID: 0} |
|||
m_PrefabAsset: {fileID: 0} |
|||
m_GameObject: {fileID: 6882351788430859438} |
|||
m_Enabled: 1 |
|||
m_CastShadows: 1 |
|||
m_ReceiveShadows: 1 |
|||
m_DynamicOccludee: 1 |
|||
m_MotionVectors: 1 |
|||
m_LightProbeUsage: 1 |
|||
m_ReflectionProbeUsage: 1 |
|||
m_RayTracingMode: 2 |
|||
m_RayTraceProcedural: 0 |
|||
m_RenderingLayerMask: 1 |
|||
m_RendererPriority: 0 |
|||
m_Materials: |
|||
- {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} |
|||
m_StaticBatchInfo: |
|||
firstSubMesh: 0 |
|||
subMeshCount: 0 |
|||
m_StaticBatchRoot: {fileID: 0} |
|||
m_ProbeAnchor: {fileID: 0} |
|||
m_LightProbeVolumeOverride: {fileID: 0} |
|||
m_ScaleInLightmap: 1 |
|||
m_ReceiveGI: 1 |
|||
m_PreserveUVs: 0 |
|||
m_IgnoreNormalsForChartDetection: 0 |
|||
m_ImportantGI: 0 |
|||
m_StitchLightmapSeams: 1 |
|||
m_SelectedEditorRenderState: 3 |
|||
m_MinimumChartSize: 4 |
|||
m_AutoUVMaxDistance: 0.5 |
|||
m_AutoUVMaxAngle: 89 |
|||
m_LightmapParameters: {fileID: 0} |
|||
m_SortingLayerID: 0 |
|||
m_SortingLayer: 0 |
|||
m_SortingOrder: 0 |
|||
m_AdditionalVertexStreams: {fileID: 0} |
|
|||
fileFormatVersion: 2 |
|||
guid: a6647793a8bc7c846abba94be1d257e5 |
|||
PrefabImporter: |
|||
externalObjects: {} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using MLAPI; |
|||
using UnityEngine; |
|||
|
|||
namespace BossRoom |
|||
{ |
|||
public class ClientSpawnerVisualization : NetworkedBehaviour |
|||
{ |
|||
[SerializeField] |
|||
NetworkSpawnerState m_NetworkSpawnerState; |
|||
|
|||
// TODO: Integrate visuals (GOMPS-123)
|
|||
[SerializeField] |
|||
Animator m_Animator; |
|||
|
|||
public override void NetworkStart() |
|||
{ |
|||
if (!IsClient) |
|||
{ |
|||
enabled = false; |
|||
return; |
|||
} |
|||
|
|||
m_NetworkSpawnerState.Broken.OnValueChanged += BrokenStateChanged; |
|||
m_NetworkSpawnerState.HitPoints.OnValueChanged += HitPointsChanged; |
|||
} |
|||
|
|||
void BrokenStateChanged(bool previousValue, bool newValue) |
|||
{ |
|||
if (newValue) |
|||
{ |
|||
if (previousValue == false) |
|||
{ |
|||
// spawner is newly broken
|
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (previousValue) |
|||
{ |
|||
// spawner is newly revived
|
|||
} |
|||
} |
|||
} |
|||
|
|||
void HitPointsChanged(int previousValue, int newValue) |
|||
{ |
|||
if (previousValue > newValue && newValue > 0) |
|||
{ |
|||
// received a hit
|
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 65e25a152b731564ebb6096eb5e9f0ed |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System.Collections; |
|||
using UnityEngine; |
|||
using MLAPI; |
|||
|
|||
namespace BossRoom.Server |
|||
{ |
|||
/// <summary>
|
|||
/// Component responsible for spawning prefab clones in waves on the server.
|
|||
/// </summary>
|
|||
[RequireComponent(typeof(Collider))] |
|||
public class ServerWaveSpawner : NetworkedBehaviour |
|||
{ |
|||
[SerializeField] |
|||
NetworkSpawnerState m_NetworkSpawnerState; |
|||
|
|||
// amount of hits it takes to break any spawner
|
|||
const int k_MaxHealth = 3; |
|||
|
|||
// networked object that will be spawned in waves
|
|||
[SerializeField] |
|||
NetworkedObject m_NetworkedPrefab; |
|||
|
|||
// cache reference to our own transform
|
|||
Transform m_Transform; |
|||
|
|||
// track wave index and reset once all waves are complete
|
|||
int m_WaveIndex; |
|||
|
|||
// keep reference to our wave spawning coroutine
|
|||
Coroutine m_WaveSpawning; |
|||
|
|||
// cache array of RaycastHit as it will be reused for player visibility
|
|||
RaycastHit[] m_Hit; |
|||
|
|||
int m_PlayerLayerMask; |
|||
|
|||
// cache Collider array of OverlapSphere results for player proximity
|
|||
Collider[] m_Colliders; |
|||
|
|||
[Tooltip("Select which layers will block visibility.")] |
|||
[SerializeField] |
|||
LayerMask m_BlockingMask; |
|||
|
|||
[Tooltip("Time between player distance & visibility scans, in seconds.")] |
|||
[SerializeField] |
|||
float m_PlayerProximityValidationTimestep; |
|||
|
|||
[Header("Wave parameters")] |
|||
[Tooltip("Total number of waves.")] |
|||
[SerializeField] |
|||
int m_NumberOfWaves; |
|||
[Tooltip("Number of spawns per wave.")] |
|||
[SerializeField] |
|||
int m_SpawnsPerWave; |
|||
[Tooltip("Time between individual spawns, in seconds.")] |
|||
[SerializeField] |
|||
float m_TimeBetweenSpawns; |
|||
[Tooltip("Time between waves, in seconds.")] |
|||
[SerializeField] |
|||
float m_TimeBetweenWaves; |
|||
[Tooltip("Once last wave is spawned, the spawner waits this long to restart wave spawns, in seconds.")] |
|||
[SerializeField] |
|||
float m_RestartDelay; |
|||
[Tooltip("A player must be withing this distance to commence first wave spawn.")] |
|||
[SerializeField] |
|||
float m_ProximityDistance; |
|||
[Tooltip("After being broken, the spawner waits this long to restart wave spawns, in seconds.")] |
|||
[SerializeField] |
|||
float m_DormantCooldown; |
|||
|
|||
void Awake() |
|||
{ |
|||
m_Transform = transform; |
|||
m_PlayerLayerMask = LayerMask.GetMask("PCs"); |
|||
} |
|||
|
|||
public override void NetworkStart() |
|||
{ |
|||
base.NetworkStart(); |
|||
|
|||
if (!IsServer) |
|||
{ |
|||
enabled = false; |
|||
return; |
|||
} |
|||
|
|||
ReviveSpawner(); |
|||
m_Hit = new RaycastHit[1]; |
|||
m_Colliders = new Collider[8]; |
|||
StartCoroutine(ValidatePlayersProximity(StartWaveSpawning)); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Coroutine for continually validating proximity to players and invoking an action when any is near.
|
|||
/// </summary>
|
|||
/// <param name="validationAction"></param>
|
|||
/// <returns></returns>
|
|||
IEnumerator ValidatePlayersProximity(System.Action validationAction) |
|||
{ |
|||
while (true) |
|||
{ |
|||
if (m_NetworkSpawnerState.Broken.Value) |
|||
{ |
|||
yield return new WaitForSeconds(m_DormantCooldown); |
|||
ReviveSpawner(); |
|||
} |
|||
|
|||
if (m_WaveSpawning == null) |
|||
{ |
|||
if (IsAnyPlayerNearbyAndVisible()) |
|||
{ |
|||
validationAction(); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
// do nothing, a wave spawning routine is currently underway
|
|||
} |
|||
|
|||
yield return new WaitForSeconds(m_PlayerProximityValidationTimestep); |
|||
} |
|||
} |
|||
|
|||
void StartWaveSpawning() |
|||
{ |
|||
StopWaveSpawning(); |
|||
|
|||
m_WaveSpawning = StartCoroutine(SpawnWaves()); |
|||
} |
|||
|
|||
void StopWaveSpawning() |
|||
{ |
|||
if (m_WaveSpawning != null) |
|||
{ |
|||
StopCoroutine(m_WaveSpawning); |
|||
} |
|||
m_WaveSpawning = null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Coroutine for spawning prefabs clones in waves, waiting a duration before spawning a new wave.
|
|||
/// Once all waves are completed, it waits a restart time before termination.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
IEnumerator SpawnWaves() |
|||
{ |
|||
m_WaveIndex = 0; |
|||
|
|||
while (m_WaveIndex < m_NumberOfWaves) |
|||
{ |
|||
yield return SpawnWave(); |
|||
|
|||
yield return new WaitForSeconds(m_TimeBetweenWaves); |
|||
} |
|||
|
|||
yield return new WaitForSeconds(m_RestartDelay); |
|||
|
|||
m_WaveSpawning = null; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Coroutine that spawns a wave of prefab clones, with some time between spawns.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
IEnumerator SpawnWave() |
|||
{ |
|||
for (int i = 0; i < m_SpawnsPerWave; i++) |
|||
{ |
|||
SpawnPrefab(); |
|||
|
|||
yield return new WaitForSeconds(m_TimeBetweenSpawns); |
|||
} |
|||
|
|||
m_WaveIndex++; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Spawn a NetworkedObject prefab clone.
|
|||
/// </summary>
|
|||
void SpawnPrefab() |
|||
{ |
|||
if (m_NetworkedPrefab == null) |
|||
{ |
|||
throw new System.ArgumentNullException("m_NetworkedPrefab"); |
|||
} |
|||
|
|||
// spawn clone right in front of spawner
|
|||
var spawnPosition = m_Transform.position + m_Transform.forward; |
|||
var clone = Instantiate(m_NetworkedPrefab, spawnPosition, Quaternion.identity); |
|||
if (!clone.IsSpawned) |
|||
{ |
|||
clone.Spawn(); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Determines whether any player is within range & visible through RaycastNonAlloc check.
|
|||
/// </summary>
|
|||
/// <returns> True if visible and within range, else false. </returns>
|
|||
bool IsAnyPlayerNearbyAndVisible() |
|||
{ |
|||
var spawnerPosition = m_Transform.position; |
|||
|
|||
var ray = new Ray(); |
|||
|
|||
int hits = Physics.OverlapSphereNonAlloc(spawnerPosition, |
|||
m_ProximityDistance, m_Colliders, m_PlayerLayerMask); |
|||
|
|||
if (hits == 0) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
// iterate through players and only return true if a player is in range
|
|||
// and is not occluded by a blocking collider.
|
|||
foreach (var playerCollider in m_Colliders) |
|||
{ |
|||
var playerPosition = playerCollider.transform.position; |
|||
var direction = playerPosition - spawnerPosition; |
|||
|
|||
ray.origin = spawnerPosition; |
|||
ray.direction = direction; |
|||
|
|||
var hit = Physics.RaycastNonAlloc(ray, m_Hit, |
|||
Mathf.Min(direction.magnitude, m_ProximityDistance),m_BlockingMask); |
|||
if (hit == 0) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
void ReviveSpawner() |
|||
{ |
|||
m_NetworkSpawnerState.HitPoints.Value = k_MaxHealth; |
|||
m_NetworkSpawnerState.Broken.Value = false; |
|||
} |
|||
|
|||
// TODO: David will create interface hookup for receiving hits on non-NPC/PC objects (GOMPS-ID TBD)
|
|||
void ReceiveHP(ServerCharacter inflicter, int HP) |
|||
{ |
|||
if (!IsServer) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
m_NetworkSpawnerState.HitPoints.Value += HP; |
|||
|
|||
if (m_NetworkSpawnerState.HitPoints.Value <= 0) |
|||
{ |
|||
m_NetworkSpawnerState.Broken.Value = true; |
|||
StopWaveSpawning(); |
|||
} |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 49b962917cae99f48a2a598485996b8d |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using MLAPI; |
|||
using MLAPI.NetworkedVar; |
|||
using UnityEngine; |
|||
|
|||
namespace BossRoom |
|||
{ |
|||
/// <summary>
|
|||
/// Contains all NetworkedVars of a spawner.
|
|||
/// This component is present on both client and server objects.
|
|||
/// </summary>
|
|||
public class NetworkSpawnerState : NetworkedBehaviour |
|||
{ |
|||
public NetworkedVarInt HitPoints { get; } = new NetworkedVarInt(); |
|||
|
|||
public NetworkedVarBool Broken { get; } = new NetworkedVarBool(); |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 4cfeccaf46c46e1458c3f7351d6753b3 |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue