0 votes

Hi all. Sorry if this was asked before.

I am trying to instance mob scenes from arrays randomly but even with randomize() and randi, they can some times still instance the same one many, many times in a row.

Is there a way to truly randomise instances without it repeating the previous var and without removing it from the array?

This is an example of my own attempt with the shuffle() method but it didn't work. Any advice would be greatly appreciated!

# One of my many mob arrays.
var spawnable_a = [mobs_a3, mobs_a4, mobs_a5, mobs_a6, mobs_a7, mobs_a8]
var spawnable_a_full = []

func _ready():
    randomize()
    spawnable_a_full = spawnable_a.duplicate()
    spawnable_a.shuffle()

func _on_Timer_A_timeout():
    if spawnable_a.empty():
        spawnable_a_full = spawnable_a.duplicate()
        spawnable_a.shuffle()

    if score <= 19:
        var spawn = spawnable_a[randi()%spawnable_a.size()].instance()
        call_deferred("add_child", spawn)
        $Timer_A.start()
Godot version 3.3.4
in Engine by (29 points)

1 Answer

+1 vote
Best answer

Firstly

  1. Randi is better than shuffle and no need to do both
  2. No need to duplicate array
  3. Error in code at line 11 (result is alway false)
  4. Error on line 18 posible infinite loop / not sure if intended?
  5. Fear of removing from original array or tampering with it

Process

  1. Move last_spawned to the front/back of the list
  2. Randomize by ignoring last_spawned position in the list

Code sniplet

# One of my many mob arrays.
var spawnable_a = [mobs_a3, mobs_a4, mobs_a5, mobs_a6, mobs_a7, mobs_a8]

func _ready():
    randomize()
    $Timer_A.start()

func _on_Timer_A_timeout():
    if score <= 19:
        var albert_simmons = spawnable_a[randi() % spawnable_a.size() -1]
        spawnable_a.erase(albert_simmons) #remove
        spawnable_a.push_back(albert_simmons) #put back

        var spawn = albert_simmons.instance()
        call_deferred("add_child", spawn)

Additional reading on randomization
How would i go about picking a random number?

by (6,870 points)
selected by

Thanks for your reply. I get that Albert Simmons reference xD

I tried your codes but unfortunately I still get repeated spawns, some times even from the very first two spawns :(

Btw, line 18 is intended. It stop looping once the score is no longer <= 19. Might this be the reason why it didn't work?

Update:
I think the .push_back() is causing the Vars to get repicked again albeit randomly and therefore still retain the same random chance of getting repeated immediately.

Is there a way to prevent this?

I went with the .empty() and .duplicate() with .erase(). This works after I corrected the error you pointed out but the only problem is that the Vars won't get picked again until the Array is emptied and refilled.

Yes push_back basically reshuffles the array and makes the variant available for selecion again, but is it that you want only one instance of every entity in the array to be spawned?

If so then.

# One of my many mob arrays.
var spawnable_a = [mobs_a3, mobs_a4, mobs_a5, mobs_a6, mobs_a7, mobs_a8]
var nth = spawnable_a.size()

func _ready():
    randomize()

func _on_Timer_A_timeout():
    if score <= 19:
        var albert_simmons = spawnable_a[randi() % nth]
        if nth > 0:
            nth -= 1

        var spawn = albert_simmons.instance()
        call_deferred("add_child", spawn)
        $Timer_A.start()

Otherwise

# observe this line and make sure you have the -1
randi() % spawnable_a.size() -1

Apologies for not being clearer with my question.

I hope to get only one of the variants in the array to be selected on every _timeout (which is on loop till a certain score) but ideally never repeatedly selected back to back with possibility of it being selected again not too long later. E.g.;

mobsa3
mobsa6
mobsa5

This is also okay;
mobsa3
mobsa6
mobsa3

This is not okay (which can still happen with your codes above);
mobsa3
mobsa6
mobsa6

I hope you get what I mean :)

So it appears the fault in my code lies in the way randi() works.
To resolve remove the math by encapsulating it with ()

var albert_simmons = spawnable_a[randi() % (spawnable_a.size() -1)]
Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.