Unity - 构建后在output_log.txt中抛出奇怪的StackOverflow异常

问题描述 投票:0回答:1

今天我来找你,因为我有一个奇怪的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);
    }
}

提前感谢您的帮助。问候!

unity3d stack-overflow unityscript
1个回答
0
投票

对于那些有这样问题的人。

我解决了这个问题。我在更新功能中有一个.onMoneyChanged,导致游戏崩溃。我将它移动到onEnable和onDisable方法,现在它工作得很好。

© www.soinside.com 2019 - 2024. All rights reserved.