简体   繁体   中英

C# - RandomRangeInt is not allowed to be called from a MonoBehaviour constructor

In the code for player attack, I tried to add a critical chance and a critical multiply system. The code for which is below

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Mirror;

public class PlayerCombat : NetworkBehaviour
{
/*public enum weaponType : int
{
    dagger = 0,
    shortSword = 0,
    longSword = 0,

    spear = 1,
    halberd = 1,

    battleAxe = 2,
    morningStar = 2
}*/
/*public enum shieldType : int
{
    basic = 0,
}*/

public enum cardinalDirection : int
{
    Up = 0,
    Right = 1,
    Down = 2,
    Left = 3
}

[Header("Weapon")]
public MeleeWeapon currentWeapon;

public Vector2 attackCenter =  new Vector2(0, -0.2f);

private bool attacking = false;
private bool cooldownOver = true;

[Header("Critical")]
public float critChance = 75;
public int critMultiplier = 20;
public int randValue = Random.Range (0,101);

[Header("Shield")]
public Shield currentShield;

[HideInInspector]
public bool shielding = false;


//Other
[HideInInspector]
public cardinalDirection attackDirection;
private Animator anim;
private PlayerController controller;

[Header("Utility-")]
[SerializeField]
private bool drawGizmos = false;

void Start() 
{
    anim = GetComponent<Animator>();
    controller = GetComponent<PlayerController>();
}

void Update()
{
    anim.SetInteger("Shield Type", (int)currentShield.type);
    anim.SetInteger("Attack Type", (int)currentWeapon.type);

    attackDirection = (cardinalDirection)controller.cardinalFaceDirection;

    if (!isLocalPlayer) return;

    if (Input.GetButtonDown("Attack") && !attacking && cooldownOver && !shielding)
    {
        anim.SetTrigger("Attack");

        StartCoroutine("Attack");
    }

    if (Input.GetButton("Shield") && !attacking)
    {
        //Animation stuff

        shielding = true;
    }
    else
    {
        shielding = false;
    }

    if (attacking || shielding)
    {
        controller.canMove = false;
    }
    else
    {
        controller.canMove = true;
    }

    ManageShield();
}

int damageCalc()
{
    if(randValue < critChance)
    {
        return currentWeapon.damage*critMultiplier;
    }
    else
    {
        return currentWeapon.damage;
    }
}

IEnumerator Attack()
{
    attacking = true;
    cooldownOver = false;

    //Quick delay to make the attack feel more natural
    yield return new WaitForSeconds(0.1f);

    //Attack Logic
    Collider2D[] hits = Physics2D.OverlapCircleAll((Vector2)transform.position + 
attackCenter, currentWeapon.range);
    
    foreach (Collider2D currentHit in hits)
    {
        if(currentHit.tag == "Enemy")
        {
            if (attackDirection == 
(cardinalDirection)controller.CardinalDirection(currentHit.transform.position - 
transform.position))
            {
                
                Vector2 hitDirection = currentHit.gameObject.transform.position - 
transform.position;
                currentHit.gameObject.GetComponent<BasicZombie> 
()?.TakeDamage(currentWeapon.damage, hitDirection, currentWeapon.knockback);
            }
            else
            {
                Debug.Log("Facing wrong direction");
            }
        }
    }

    //The rest of the delay
    yield return new WaitForSeconds(0.2f);
    attacking = false;
    //Weapon cooldown delay
    yield return new WaitForSeconds(currentWeapon.cooldown);
    cooldownOver = true;
}

void ManageShield()
{
    if(shielding)
    {
        anim.SetBool("Shielding", true);
    }
    else
    {
        anim.SetBool("Shielding", false);
    }
}


void OnDrawGizmos()
{
    if(!drawGizmos) return;
    Gizmos.DrawWireSphere((Vector2)transform.position + attackCenter, 
currentWeapon.range);
}

}

When this is used in Unity I get the errors

UnityException: RandomRangeInt is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour 'PlayerCombat'. See "Script Serialization" page in the Unity Manual for further details. UnityEngine.Random.Range (System.Int32 minInclusive, System.Int32 maxExclusive) (at <07c89f7520694139991332d3cf930d48>:0) PlayerCombat..ctor () (at Assets/Scripts/PlayerCombat.cs:44)

and

UnityException: RandomRangeInt is not allowed to be called from a MonoBehaviour constructor (or instance field initializer), call it in Awake or Start instead. Called from MonoBehaviour 'PlayerCombat'. See "Script Serialization" page in the Unity Manual for further details. UnityEngine.Random.Range (System.Int32 minInclusive, System.Int32 maxExclusive) (at <07c89f7520694139991332d3cf930d48>:0) PlayerCombat..ctor () (at Assets/Scripts/PlayerCombat.cs:44)

I am new to coding and working on a game with my friend, if I leave the int damageCalc empty or the if statements empty I get no errors. But no matter what I try what I add in it brings back errors.

(sorry if this is formatted bad first question on StackOverflow)

Just exactly as the error tells you, you can not do

public int randValue = Random.Range (0,101);

on field declaration time but rather need to assign this on runtime via eg

public int randValue;

// private void Awake()
// or
private void Start()
{
     randValue = Random.Range (0,101);

     ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM