【问题标题】:Same script, different object, different shuffle result相同的脚本,不同的对象,不同的随机播放结果
【发布时间】:2016-05-10 05:09:01
【问题描述】:

我有一个脚本来改变对象的行为。假设行为 1 坐、2 跳、3 走、4 跑。然后有一个附加到对象的脚本来改变对象的行为。例如,洗牌行为是 3-1-2-4。当我复制对象时,所有复制的对象都具有相同的随机播放结果,因此所有对象的行为都是相同的。我想要的是不同的对象有不同的随机播放结果。我能想到的就是为每个对象制作一个不同的脚本,但这并不高效。

[edit] 这是附加到对象的脚本

using UnityEngine;
using System.Collections;

public class StudentScript : MonoBehaviour {

private System.Random _random = new System.Random();
private Animator animator;
float sec;
int[] array = { 1, 2, 3, 4, 5};
int m;
public GameManage gm;
public Animator pengawasAnim;
public Animator signAnim;

void Start () {
    animator = GetComponent<Animator> ();
    sec = 0f;
    m = 0;
    Shuffle(array);
    foreach (int value in array)
    {
        Debug.Log(value);
    }
}

void Update () {
    sec+=Time.deltaTime;
    if (sec >= 3f && m<5 && animator.GetInteger ("Behav") == 0) { 
        StudentBehaviour(array[m]);
    }
    //Debug.Log ("sec "+sec);
    if (animator.GetInteger ("Behav") != 0) {
        if (sec >= 5)
            animator.SetTrigger ("ToDont");
        if (sec >= 10)
            animator.SetTrigger ("ToEffect");
    }
}

public void StudentBehaviour(int n){
    animator.SetInteger ("Behav", n);
    sec = 0f;
    Debug.Log ("jadi "+n);
}

public void ResetStudentBehaviour(){
    if (animator.GetInteger ("Behav") != 0) {
        pengawasAnim.SetTrigger("Approach");
        if (sec >= 0f && sec <=5f) {
            signAnim.SetTrigger ("ToYellow");
            animator.SetTrigger ("Told1");
            gm.AddScore (5);
        }else if (sec >= 5f && sec <=10f) {
            signAnim.SetTrigger ("ToOrange");
            animator.SetTrigger ("Told2");
            animator.ResetTrigger ("ToDont");
            gm.AddScore (3);
        }else if (sec >= 10f) {
            signAnim.SetTrigger ("ToRed");
            animator.SetTrigger ("Told3");
            animator.ResetTrigger ("ToEffect");
            gm.AddScore (1);
        }
        animator.SetInteger ("Behav", 0);
        sec = 0f;
        Debug.Log ("reset");
        if (m < 5) {
            m++;
        } 
        Debug.Log ("m = " + m);
        Debug.Log ("sec "+sec);
    }else
        Debug.Log ("student done <3");
}

void Shuffle(int[] array){
    int p = array.Length;
    for (int n = p-1; n > 0 ; n--)
    {
        int r = _random.Next(0, n);
        int t = array[r];
        array[r] = array[n];
        array[n] = t;
    }
}   

我想要的是复制学生(带护目镜的那个),这样每个学生的行为都会不同

【问题讨论】:

  • 但是如果没有您的代码,我们如何为您提供帮助?怎么能看到你是如何复制你的对象的?
  • @Programmer 已编辑。对不起:)
  • 没问题。您用来复制学生的代码在哪里?这对于查明问题非常重要。
  • 但我手动复制学生
  • 来自编辑?不是来自代码?如果这是真的,那么你的洗牌代码就坏了

标签: c# unity3d 2d


【解决方案1】:

问题出在private System.Random _random = new System.Random(); 行。

只需在该行前面添加 static 关键字即可。

static private System.Random _random = new System.Random();

这解决了问题。尽管有时,来自不同 Object 实例的随机数是相同的,但这种情况很少见。为了减少不同对象获得相同随机数的概率,为Shuffle(int[] array) 函数指定一个类和游戏对象,然后从StudentScript 类的许多实例中调用该函数。

所以创建一个名为RandomGen 的类并创建一个游戏对象并将其命名为RANDOMOBJ。将 RandomGen 脚​​本附加到 RANDOMOBJ 游戏对象。

不要复制它(RANDOMOBJ)。应该有其中之一。

您的RandomGen 脚本:

public class RandomGen : MonoBehaviour
{
    static private System.Random _random = new System.Random();


    public void Shuffle(int[] array)
    {
        int p = array.Length;
        for (int n = p - 1; n > 0; n--)
        {
            int r = _random.Next(0, n);
            int t = array[r];
            array[r] = array[n];
            array[n] = t;
        }
    }
}

您的StudentScript 脚本。

public class StudentScript : MonoBehaviour
{
    RandomGen randomGen;

    private Animator animator;
    float sec;
    int[] array = { 1, 2, 3, 4, 5 };
    int m;
    public GameManage gm;
    public Animator pengawasAnim;
    public Animator signAnim;

    void Start()
    {
        animator = GetComponent<Animator>();
        sec = 0f;
        m = 0;
        randomGen = GameObject.Find("RANDOMOBJ").GetComponent<RandomGen>();

        randomGen.Shuffle(array);
        foreach (int value in array)
        {
            Debug.Log(value);
        }
    }

//.... Put your other functions below, except the Shuffle function
}

【讨论】:

  • 为什么不直接使用 UnityEngine.Random?只是出于好奇。
  • @yes 1。我用那个,因为那是她用的。我不知道她是否需要使用它。 2. UnityEngine.RandomSystem.Random 是一回事。 3. using System.Random 不是代码不工作的原因。
  • 如果您在短时间内创建多个实例,至少您不会无意中为 UnityEngine.Random 播种相同的值。 (因为你不能实例化它)这不是你在上面的代码中发生的事情吗?
  • 我只是想知道,因为通过阅读你的答案,我可以告诉你更多关于统一甚至 c# 的知识。
  • @是的,我使用它是因为 OP 使用了它。就灵活性而言,UnityEngine.Random System.Random 也是如此。 UnityEngine.Random 缺少许多函数,例如 Next 函数,这是使 OP 的代码工作所必需的。请记住,OP 使用的是Random.Next 而不是Random.Range。这是两个不同的东西。
【解决方案2】:

用途:

int r =  Random.value*n;

或:

int r = Random.Range(0,n);

代替:

int r = _random.Next(0, n);

在你的 Shuffle() 方法中

【讨论】:

  • 她使用int r = _random.Next(0, n); 是因为她希望数组中的所有值都不同。我也认为洗牌功能是问题,但我认为这不能解决问题。
  • @Programer 你是对的。你说得对。我的错误是认为 Random.next 给出了预定义的随机数序列。我已经做了一些测试。唯一的区别是 Random.Range() 返回浮点数
  • Random.Range 有一个整数的重载,它也返回整数。
【解决方案3】:

将此方法添加到您的 GameObject 并在 Start() 中调用它

int[] shuffleArray(int[] OriginalArray)
{
    int[] tempCopy = (int[])OriginalArray.Clone();
    int[] tempCopy2 = (int[])OriginalArray.Clone();
    int[] shuffledArray = new int[OriginalArray.Length];

    for (int n = 0; n < shuffledArray.Length; n++)
    {
        //Asign a random OriginalArray's data to the n data of shuffledArray
        int randomValue = _random.Next(0, tempCopy.Length);
        print("n="+n+" randomValue="+randomValue+ " tempCopy.lenght="+ tempCopy.Length);
        shuffledArray[n] = tempCopy[randomValue];

        //Erase the data extracted and reduce the copy of OriginalArray in one
        if (tempCopy2.Length != 0)
        {
            tempCopy2 = new string[tempCopy2.Length - 1];
            for (int m = 0; m < randomValue; m++) tempCopy2[m] = tempCopy[m];
            for (int m = randomValue; m < tempCopy.Length-1; m++) tempCopy2[m] = tempCopy[m + 1];
        }
        tempCopy = tempCopy2;
    }

    return shuffledArray;
}

此代码返回您提供的 Array 的随机副本。

【讨论】:

  • 在一个简单的函数中用tempCopy,tempCopy2shuffledArray分配内存3次。在函数中返回分配的内存也不好。这是不好的。每次调用shuffleArray,都会发生不必要的内存分配。这就是为什么原始函数将数组作为参数,这样可以在不分配内存的情况下将混洗结果返回给该参数。
  • 感谢阅读我的答案@Programmer。但是您的解决方案不起作用,因为函数 random.Next(0, n);可以两次返回相同的值。我还认为 random.Next() 返回一个预定义的随机序列,但是您的代码可以在此处的循环中始终覆盖相同的值:----'array[r] = array[n]; --- 因为 r 可以一直得到相同的值
  • ofc 随机可以返回相同的值两次,甚至三次,这可能发生。但是对于像 OP 那样对数组进行洗牌并不重要,因为随机值仅用于要切换的元素的索引。
  • 但是您的解决方案不起作用,因为函数 random.Next(0, 10);可以两次返回相同的值。。我认为您不是OP的问题。 OP 问题中的 Shuffle 函数 100% 有效.... Shuffle 函数不是问题。它将数组 n 中的数字打乱,并将结果返回给传入的数组。因此,该函数不需要分配 3 次内存,并且不会返回一个更快且内存友好的新数组。跨度>
  • OP 遇到的问题是,当有多个脚本实例时,随机播放仍然有效,但两个实例将具有相同的随机播放编号。 instance1 shuffledNumbers == instance2 shuffledNumbers。 OP 希望每个实例的数字都不同。建议将 Random 类设为静态,并且 ALMOST 解决了该问题。它大部分时间都有效。要真正解决问题,请确保有一个 System.Random 实例正在运行,然后您可以从其他类访问它。这完全解决了问题,不再重复。
猜你喜欢
  • 1970-01-01
  • 2021-09-23
  • 2018-07-01
  • 2019-05-31
  • 1970-01-01
  • 2013-05-23
  • 2019-05-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多