Randomised nextState function

Hi Guys,

I’m new to the Unity 2d tutorial and am just finishing up the Choose Your Own Adventure section. When I was creating my game I came across a question.

When a player pushes an input key to choose an option, can I have some code that has a 60% chance to get to state A and a 40% chance to get to state B?

Is this something I’ll learn to do later in the course?

I am looking to make a text based choice game with some randomized options at times to add some unpredictability.

Please let me know.

Thanks,
Hersh.

Hi Hersh,

I am doing the same for my adventure game :slight_smile:
Try this out in a stand alone script first. It should give you a 40% /// 60% split probability
I got reference from Microsoft API guide: https://docs.microsoft.com/en-us/dotnet/api/system.random.next?view=netcore-3.1

You will need to re-arrange the script to your scope when you push a keybutton

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




public class RandomTestScript : MonoBehaviour
{

    System.Random gen = new System.Random(); //The Random function is part of System namespace
    
    // Start is called before the first frame update

        // The update method will call runtime the function
    void Update()
    {
        int prob;
        prob = gen.Next(100); //Returns a non-negative random integer that is less than the specified maximum.




        if (prob <= 40)
            {

            Debug.Log(" You have got 40% chance");
        }
       else
        {

            Debug.Log("You have got 60%chance");
        }

    }

}

1 Like

Thanks for the quick solution @attarus! Much appreciated!

I’m new to coding and must say that your code was very easy to understand. Thanks to you I have learnt something new and it seems to work out well in the test.

But I am now trying to figure as to how I can add it to my current tutorial code in order for it to work. Here is the current function I have:

 private void ManageState()
{
    var nextStates = state.GetNextStates();


    for (int index = 0; index < nextStates.Length; index ++)
    {

        if (Input.GetKeyDown(KeyCode.Alpha1 + index))
        {
            state = nextStates[index];
        }

    }

    textComponent.text = state.GetStateStory();

}

I am guessing I need to further distinguish and define which states will need the random function and also find out how I can add the alternate NextStates to them.

Not sure if I have enough knowledge to do it right away : [

Hi Hersh,

Welcome to our community. :slight_smile:

You can accomplish your idea with your current knowledge. What you need is to decide where the alternative state will come from. It’s a matter of your code/project structure.

Unity has got its own random method, which is easier to use than System.Random. Look up Random.Range in the Unity API and scroll down to the integer version.

What you need for your solution:

  • a method that returns something
  • an array
  • if-statements
  • Random.Range or System.Random to generate a random index

You know how to accomplish the first three things, and I am sure that you will be able to figure out the last one. :slight_smile:

A little tip: Start simple and test your code with one state only. Once it works, you can implement the rest if necessary.

1 Like

Hi Nina,

Thanks for the guidance.

I am excited to know that I can solve this issue with my current knowledge and your overview of the solution greatly helps.

I will think and resolve this by myself. Will drop you a message after :slight_smile:

Hi Nina,

Hope you are well.

Here is what I could come up with and it seems to work fine. Can you please have a look and let me know if this is a good one to solve the problem?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class CricketGame : MonoBehaviour {

[SerializeField] Text textComponent;
[SerializeField] State startingState;


State state;
int prob;

// Use this for initialization
void Start () {
    state = startingState;
    textComponent.text = state.GetStateStory();
    //

}

// Update is called once per frame
void Update () {
    ManageStates();
}

/*    private void ManageState()
    {
        var nextStates = state.GetNextStates();

        for (int index = 0; index < nextStates.Length; index ++)
        {
            if (Input.GetKeyDown(KeyCode.Alpha1 + index))
            {
                state = nextStates[index];
            }
        }

        textComponent.text = state.GetStateStory();
    }
    */

private void ManageStates()
{
    var nextStates = state.GetNextStates();
    var altStates = state.GetAltStates();

    for (int index = 0; index < nextStates.Length; index++)
    {
        if (Input.GetKeyDown(KeyCode.Alpha1 + index) && index < altStates.Length)
        {
            probState();

            void probState()
            {
                prob = UnityEngine.Random.Range(1, 11);
            }

            if (prob <= 4)
            {
                state = altStates[index];
            }

            else
            {
                state = nextStates[index];
            }
        }

        else if (Input.GetKeyDown(KeyCode.Alpha1 + index))
        {
            state = nextStates[index];
        }
    }

        textComponent.text = state.GetStateStory();

}

}

Thanks,
Hersh.

Hi Hersh,

Good job on solving the problem. :slight_smile:

I’ve read your code, and it looks fine. If it works, it is a solution by definition.

The local probState() method can be dropped as it contains only one line of code and gets called all the time anyway.

private void ManageStates()
{
    var nextStates = state.GetNextStates();
    var altStates = state.GetAltStates();

    var prob = 0; // could be a local variable

    for (int index = 0; index < nextStates.Length; index++)
    {
        if (Input.GetKeyDown(KeyCode.Alpha1 + index) && index < altStates.Length)
        {
            prob = UnityEngine.Random.Range(1, 11);
           
            if (prob <= 4)
            {
                state = altStates[index];
            }

            else
            {
                state = nextStates[index];
            }
        }

        else if (Input.GetKeyDown(KeyCode.Alpha1 + index))
        {
            state = nextStates[index];
        }
    }

        textComponent.text = state.GetStateStory();
}

And then you could optimise the performance a bit because it is not neccesary to check Input.GetKeyDown(KeyCode.Alpha1 + index) twice.

private void ManageStates()
{
    // if no key was pressed, terminate the method
    if (!Input.anyKey)  { return; }

    var nextStates = state.GetNextStates();
    var altStates = state.GetAltStates();

    for (int index = 0; index < nextStates.Length; index++)
    {
        if (Input.GetKeyDown(KeyCode.Alpha1 + index) 
        {
             if (index < altStates.Length)
             {
                 int prob = UnityEngine.Random.Range(1, 11);
                 
                // ternary operator
                 state = (prob < 5) ? altStates[index] : nextStates[index];
             }

             else
             {
                  state = nextStates[index];
             }
             
             textComponent.text = state.GetStateStory();
             break; // leave the for-loop
        }
    }
}

Does that make sense?

Your solution was perfectly fine. I just showed you how to optimise it because you asked for feedback. Keep up the good work! :slight_smile:

1 Like

Thanks for helping with the optimization Nina. It makes perfect sense.

Learnt a couple of new things here and it gives me better perspective to problem solving in the future.

Just had a question if you could help:

Why do we need to terminate the method if no key was pressed?

We do not need terminate the method if no key was pressed. However, why should we execute the for-loop over and over again and check an if-condition if we know in advance that all of them will be false?

Since we know that everything is false if no key was pressed, we could simply terminate the method instead of executing the rest of its code block.

1 Like

Okay got it.

So basically we are telling the system that until a key is pressed, do not run any code below it.

That correct?

That’s correct. :slight_smile:

if (condition) { return; } is common practice. When reading other people’s code, especially more “advanced” code, you’ll encounter it more often.

1 Like

Awesome!

Thanks Nina :slight_smile:

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms