今天我来找你,是因为我有一个奇怪的StackOverflow异常,根本不知道如何解决...
首先,这似乎只在我制作游戏后才在Windows上发生。 这是我在output_log.txt中看到的:
onMoneyChanged is being called! (4145)
UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
Player:set_Money(Int32) (at /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs:89)
Coin:OnPickup(ItemCollector) (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/Coin.cs:12)
ItemCollector:Update() (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/ItemCollector.cs:35)
(Filename: /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs Line: 89)
onMoneyChanged is being called! (4150)
UnityEngine.DebugLogHandler:Internal_Log(LogType, String, Object)
UnityEngine.DebugLogHandler:LogFormat(LogType, Object, String, Object[])
UnityEngine.Logger:Log(LogType, Object)
UnityEngine.Debug:Log(Object)
Player:set_Money(Int32) (at /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs:89)
Coin:OnPickup(ItemCollector) (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/Coin.cs:12)
ItemCollector:Update() (at /Users/Name/Desktop/My Game/Assets/Scripts/Items/ItemCollector.cs:35)
(Filename: /Users/Name/Desktop/My Game/Assets/Scripts/Mobs/Player.cs Line: 89)
Uploading Crash Report
StackOverflowException: The requested operation caused a stack overflow.
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
at (wrapper delegate-invoke) System.Action:invoke_void__this__ ()
我到处都看过,似乎无法理解它的来源。我可能看不到非常简单的东西...
以下是播放器脚本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Linq;
using UnityEngine;
using UnityEngine.Events;
using PixelUtilities;
public class Player : Mob, IUpgradable, IXmlSerializable {
#region Static Section
private static readonly AnimationParameter Skill2SpeedId = "Skill 2 Speed";
private static readonly string[] AttackAxisNames = new string[] {
null,
"Attack1",
"Attack2",
"Attack3"
};
//It seems this must be longer in duration than the transition into the attack state, due to the potential transition interruption sources!
private const float AttackUnjoggableTime = 0.65f;
#endregion
[Header("Player")]
[SerializeField] private float skill2Speed = 1;
[SerializeField] private Transform groundCheck;
[SerializeField] private float groundCheckRadius = 0.25f;
[SerializeField] private LayerMask groundLayers;
[SerializeField] private bool isGrounded;
[SerializeField] GameObject weaponSpecial;
private new Rigidbody2D rigidbody;
private new BoxCollider2D collider;
private float horizontal;
private float smoothedHorizontal;
private Vector3 velocity;
private int superCharge; //Represents the number of enemies defeated that counts towards allowing the player to use their super attack.
private bool canIncreaseSuperCharge = true;
private bool canSuperSmash;
private int money = 0;
//private int roundMoney = 0;
private int[] levels = new int[2];
//DO NOT show in the inspector. That will make it changeable without actually updating the data
//that needs to change based based on this upgradeLevel.
private int baseDamage;
private float timeLastAttacked;
public event Action onMoneyChanged;
public bool CanSuperSmash {
get { return canSuperSmash; }
set {
//Prevent from redundant setting, because we'll need to know
//just when the value changed from false to true
if (canSuperSmash == value)
return;
canSuperSmash = value;
weaponSpecial.SetActive(value);
if (value)
superCharge = GameManager.Mage.SpecialEnemyCount;
}
}
public BoxCollider2D Collider {
get { return collider; }
}
public int SuperCharge {
get { return superCharge; }
}
public int LevelCount {
get { return levels.Length; }
}
public int Money {
get { return money; }
set {
if (GameManager.IsDebugMode)
Debug.Log("Setting the player's money from " + money + " to " + value + ".");
money = value;
Debug.Log("onMoneyChanged is being called! (" + money + ")");
if (onMoneyChanged != null)
onMoneyChanged();
}
}
//public int RoundMoney {
// get { return roundMoney; }
// set {
// roundMoney = value;
// Debug.Log("roundMoney has been set to " + roundMoney + ".");
// }
//}
public override void Reset() {
base.Reset();
groundLayers = LayerMask.GetMask("Ground");
}
public override void Awake() {
base.Awake();
collider = GetComponentInChildren<BoxCollider2D>();
HPStatus.onDeath += OnDeath;
baseDamage = StandTallCurves.GetNthStepInEnemyHealthCurve(0) / 2;
}
public override void Start() {
rigidbody = GetComponent<Rigidbody2D>();
}
public int GetLevel(int levelIndex) {
return levels[levelIndex];
}
public void SetLevel(int levelIndex, int value) {
value = Mathf.Max(0, value);
levels[levelIndex] = value;
switch (levelIndex) {
case 0:
baseDamage = StandTallCurves.GetNthStepInEnemyHealthCurve(value) / 2;
break;
case 1:
HPStatus.HP = HPStatus.MaxHP = StandTallCurves.GetNthStepInEnemyHealthCurve(value);
break;
}
}
public override void StartAttack(int attackNumber) {
base.StartAttack(attackNumber);
timeLastAttacked = Time.time;
}
protected override void OnUpdate() {
isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayers);
if (CanPerformActions)
AcceptAttackInput();
AcceptMovementInput();
//AcceptJumpInput();
//AcceptRotationalInput();
if (GameManager.IsDeveloperMode) {
if (Input.GetKeyDown(KeyCode.C)) {
Money += 1000;
}
if (Input.GetKeyDown(KeyCode.Y)) {
CanSuperSmash = true;
}
if (Input.GetKeyDown(KeyCode.T) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.LeftCommand))) {
Time.timeScale = (Time.timeScale == 1) ? 5 : 1;
}
}
}
private void AcceptMovementInput() {
horizontal = hInput.GetAxis("Horizontal");
//smoothedHorizontal = Input.GetAxis("Horizontal");
velocity = rigidbody.velocity;
velocity.x = Mathf.Sign(horizontal) * FinalMovementSpeed;
rigidbody.velocity = velocity;
//Section for updating their rotation
if (horizontal < 0) {
Quaternion newRotation = transform.rotation;
newRotation.y = 180;
transform.rotation = newRotation;
}
if (horizontal > 0) {
Quaternion newRotation = transform.rotation;
newRotation.y = 0;
transform.rotation = newRotation;
}
}
private void AcceptAttackInput() {
for (int i = 1; i <= 2; i++) {
if (hInput.GetButtonDown(AttackAxisNames[i])) {
StartAttack(i);
return;
}
}
//Attack 3 is special for the player -- their super smash -- and is handled differently.
if (hInput.GetButtonDown(AttackAxisNames[3])) {
if (canSuperSmash) {
StartSuperSmash();
} else {
if (GameManager.IsDebugMode) {
Debug.Log("Attempted to super smash, but " + name + " was unable to super smash!");
}
}
}
}
protected override float CalculateFinalMovementSpeed() {
float finalMovementSpeed = Mathf.Abs(horizontal) * MoveSettings.MoveSpeed;
finalMovementSpeed *= MovementFactor;
return finalMovementSpeed;
}
protected override void UpdateContinuousAnimatorParameters() {
animator.SetBool(Animations.IsMovingId, Time.time - timeLastAttacked > AttackUnjoggableTime && Mathf.Abs(horizontal) > 0.08f && Mathf.Abs(velocity.x) > 0.08f);
//animator.SetFloat(Skill2SpeedId, skill2Speed);
}
/* Uncomment to enable jumping
private void AcceptJumpInput() {
if (Input.GetButtonDown("Jump") && isGrounded) {
rigidbody.velocity = new Vector3(rigidbody.velocity.x, JumpFactor * MoveSettings.JumpSpeed, 0);
if (JumpFactor > 0)
animator.SetTrigger(JumpId);
}
}*/
/// <summary>
/// This tells the whether or not the super charge count can be increased.
/// </summary>
public void SetSuperChargeActive(bool value) {
canIncreaseSuperCharge = value;
}
public bool GainSuperCharge() {
return GainSuperCharge(1);
}
public bool GainSuperCharge(int amount) {
//If they're already charged up, then don't allow superCharge to increment
if (!GameManager.Mage.gameObject.activeSelf || !canIncreaseSuperCharge || canSuperSmash)
return false;
superCharge = Mathf.Clamp(superCharge + amount, 0, GameManager.Mage.SpecialEnemyCount);
if (superCharge == GameManager.Mage.SpecialEnemyCount) {
CanSuperSmash = true; //Important to call the C# property here, NOT directly access the field, "canSuperSmash".
}
return true;
}
private void StartSuperSmash() {
SetSuperChargeActive(false);
CanSuperSmash = false;
StartCoroutine(AttackAfterDelay(3, 0)); //0 was initially 0.8f;
}
public void ClearSuperCharge() {
if (GameManager.IsDebugMode)
Debug.Log("superCharge set to 0!");
superCharge = 0;
}
private IEnumerator AttackAfterDelay(int attackNumber, float initialDelay) {
if (initialDelay > 0)
yield return new WaitForSeconds(initialDelay);
StartAttack(attackNumber);
}
public override void OnDrawGizmosSelected() {
base.OnDrawGizmosSelected();
if (groundCheck != null) {
Gizmos.color = new Color(0.6f, 1, 0, 1);
Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius);
}
attackChecker.DrawGizmos(Color.red);
}
private void InstantKillAllInView() {
Camera camera = Camera.main;
Vector3 cameraPos = camera.transform.position;
float height = 2 * camera.orthographicSize;
float width = height * camera.aspect; //h * (w/h) = w
RaycastHit2D[] hits = Physics2D.BoxCastAll((Vector2) cameraPos, new Vector2(width, height), 0, Vector2.right, 0.01f, enemyLayers, -0.01f, 0.01f);
for (int i = 0; i < hits.Length; i++) {
Mob target = hits[i].transform.GetComponent<Mob>();
if (target == null)
continue;
target.InstantSuperKill(this);
}
}
public void DamageOthersInRangeFromPlayer() {
DamageOthersInRange(baseDamage);
}
private void OnDeath(DamageInfo finalDamage) {
GameManager.StartGameOverScreen();
}
public void Load(XElement element) {
if (element == null)
return;
int intValue;
XElement child = element.Element("Money");
if (child != null && int.TryParse(child.Value, out intValue))
Money = intValue;
child = element.Element("HealthUpgrade");
if (child != null) {
//Old serialized layout
//if (int.TryParse(child.Value, out intValue))
// HealthUpgradeLevel = intValue;
//child = element.Element("DamageUpgrade");
//if (child != null && int.TryParse(child.Value, out intValue))
// DamageUpgradeLevel = intValue;
} else {
//New serialized layout
child = element.Element("Levels");
if (child != null)
LoadLevels(child, ref levels);
}
}
public XElement Save() {
XElement element = new XElement(GetType().Name);
element.Add(new XElement("Money", money));
//e.Add(new XElement("HealthUpgrade", healthUpgradeLevel));
//e.Add(new XElement("DamageUpgrade", damageUpgradeLevel));
element.Add(SaveLevels(ref levels));
return element;
}
#region Public Animator Methods
public void AnimatorAllowSuperSmashToRestart() {
ClearSuperCharge();
SetSuperChargeActive(true);
}
#endregion
}
以下是硬币脚本:
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Coin : MonoBehaviour, IItem {
[SerializeField] private int moneyAmount = 5;
public void OnValidate() {
moneyAmount = Mathf.Max(0, moneyAmount);
}
public void OnPickup(ItemCollector collector) {
collector.Owner.Money += moneyAmount;
//collector.Owner.RoundMoney += moneyAmount;
}
}
最后,是itemCollector脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ItemCollector : MonoBehaviour {
[SerializeField] private float radius = 0.5f;
[SerializeField] private LayerMask itemMask;
private Player owner;
private Collider2D[] results = new Collider2D[16];
private int resultsCount;
public Player Owner {
get { return owner; }
}
public void Awake() {
owner = GetComponentInParent<Player>();
if (owner == null) {
if (GameManager.IsDebugMode) {
Debug.LogError(" require a " + typeof(Player).Name + " to be in a parent!" +
"\nThe " + GetType().Name + " will be destroyed, as it would not be able to function.");
}
DestroyImmediate(gameObject);
}
}
public void Update() {
resultsCount = Physics2D.OverlapCircleNonAlloc(transform.position, radius, results, itemMask);
for (int i = 0; i < resultsCount; i++) {
IItem item = results[i].GetComponent<IItem>();
if (item != null) {
MonoBehaviour m = item as MonoBehaviour;
if (m != null && m.enabled) {
item.OnPickup(this);
m.enabled = false;
GameObject.Destroy(m.gameObject);
}
}
}
}
public void OnDrawGizmosSelected() {
Gizmos.DrawWireSphere(transform.position, radius);
}
}
在此先感谢您的帮助。 问候!
答案 0 :(得分:0)
对于有此类问题的任何人。
我解决了这个问题。我在更新功能中有一个.onMoneyChanged,这使游戏崩溃。 我将其移至onEnable和onDisable方法,现在可以正常使用了。