基本上我想做的是使用存储的默认值重置玩家统计信息。问题是当玩家恢复活力并恢复其统计信息时,当我没有更改其值时,默认统计信息最终就会更改。
我尝试使用复制构造函数并分别设置每个变量,并且它可以工作。直接设置它的某些方法最终导致了该错误。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
* things to do:
* 1. respawn point
* 2. fix this strange bug
*/
namespace Outbreak
{
public class LivingEntity : MonoBehaviour, IDamageable
{
public Stats defaultStats;
public event System.Action OnDeath;
protected Stats stats;
public Stats Stats
{
get
{
return stats;
}
}
protected virtual void Awake()
{
stats = new Stats(defaultStats);
}
// Start is called before the first frame update
protected virtual void Start()
{
}
// Update is called once per frame
protected virtual void Update()
{
}
public void TakeDamage(float damage)
{
Debug.Log(defaultStats.IsDead);
//if not dead
if (stats.IsDead == false)
{
//and it still has health left
if (stats.Health > 0)
{
//take damage
stats.Health -= damage;
}
//after taking damage check if health is depleted.
if (stats.Health <= 0)
{
//pronouce it dead
Die();
}
}
}
protected virtual void Die()
{
//set its status to dead
stats.IsDead = true;
//broadcast to all listener that this player is dead
if (OnDeath != null)
{
OnDeath();
}
//make player invisible
gameObject.GetComponent<MeshRenderer>().enabled = false;
//prevent any collision
gameObject.GetComponent<CapsuleCollider>().enabled = false;
//prevent player detecting collision
gameObject.GetComponent<Rigidbody>().detectCollisions = false;
//set to kinematic
gameObject.GetComponent<Rigidbody>().isKinematic = true;
}
protected IEnumerator DelayedRevival()
{
yield return new WaitForSeconds(3.0f);
Revive();
yield return null;
}
protected virtual void Revive()
{
//2. reset to default stats
//stats = new Stats(defaultStats);
//stats.IsDead = false;
//stats.Health = 3;
//stats.MovementSpeed = 10;
stats = defaultStats;
//1. set position to last respawn point location
transform.position = Vector3.zero + (Vector3.up * 1.5f);
//make player visible
gameObject.GetComponent<MeshRenderer>().enabled = true;
//allow for collision
gameObject.GetComponent<CapsuleCollider>().enabled = true;
//allow player to detect collision
gameObject.GetComponent<Rigidbody>().detectCollisions = true;
//set to dynamic
gameObject.GetComponent<Rigidbody>().isKinematic = false;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Outbreak
{
[RequireComponent(typeof(CharacterController), typeof(CharacterInput))]
public class Character : LivingEntity
{
protected override void Awake()
{
base.Awake();
}
// Start is called before the first frame update
protected override void Start()
{
base.Start();
}
// Update is called once per frame
protected override void Update()
{
base.Update();
}
protected override void Die()
{
base.Die();
gameObject.GetComponent<CharacterInput>().enabled = false;
gameObject.GetComponent<CharacterController>().enabled = false;
StartCoroutine(DelayedRevival());
}
protected override void Revive()
{
base.Revive();
gameObject.GetComponent<CharacterInput>().enabled = true;
gameObject.GetComponent<CharacterController>().enabled = true;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace Outbreak
{
[System.Serializable]
public class Stats
{
[SerializeField]
private float health;
[SerializeField]
private float movementSpeed;
[SerializeField]
private bool isDead;
public Stats()
{
health = 3.0f;
movementSpeed = 5.0f;
isDead = false;
}
public Stats(Stats stats)
{
health = stats.health;
movementSpeed = stats.movementSpeed;
isDead = stats.isDead;
}
public float Health
{
set
{
health = value;
}
get
{
return health;
}
}
public float MovementSpeed
{
set
{
movementSpeed = value;
}
get
{
return movementSpeed;
}
}
public bool IsDead
{
set
{
isDead = value;
}
get
{
return isDead;
}
}
}
}
我希望不要更改默认值,但最终结果会更改默认值。
答案 0 :(得分:1)
您的问题专线是
stats = defaultStats;
由于类型Stats
是引用类型而不是值类型,因此该分配使stats
与{{ 1}} =>它们现在指向一个相同的对象。
您将来对其中之一所做的任何更改都会对一个相同的引用defaultStats
对象进行。
您应该像在Stats
中那样进行作业:
Awake
将复制值。
或者,也可以使 stats = new Stats(defaultStats);
而不是Stats
而是class
,它将其转换为值类型
struct
提示:如评论中所述,您应该在所有[Serializable]
public struct Stats
{
...
}
电话中仅进行一次呼叫,例如GetComponent
,并在以后重新使用商店引用,例如
Awake
稍后,您将重用这些存储的引用,例如
private MeshRenderer meshRenderer;
private CapsuleCollider capsuleCollider;
private Rigidbody rigidBody;
private void Awake()
{
meshRenderer = GetComponent<MeshRenderer>();
capsuleCollider = GetComponent<CapsuleCollider>();
rigidBody = GetComponent<RigidBody>();
}
在meshRenderer.enabled = false;
capsuleCollider.enabled = false;
rigidBody.detectCollisions = false;
rigidBody.isKinematic = true;
中,您对Character
和CharacterInput
进行相同操作。