0 votes

I'm trying to make my dungeon auto-generate randomly and such, which includes the floor. I have a few floor tiles I want to use, but I want one to appear more often than the others, I want my first one to have like a 70% or 80% chance to be the tile spawned and then my other ones to have like 5% or 10% chance to be the one that spawns. What way would I go about this other than adding a bunch of duplicates to my tilemap and using a normal random number generator?

Godot version 3.2.3
in Engine by (12 points)

1 Answer

0 votes

Adding a bunch of tiles would be imo the most elegant solution but not for that disparate of percentages. Otherwise, you could create a tuple of [tile_type, percent_chance] and select one randomly. The only stipulations for this implementation is that the integer percent chances are in descending order as demonstrated AND that none of the chances are the same integer. This implementation assumes higher roll = better or more rare.

var tile_rarities = [[0, 80], [1, 10], [2, 5], [3,4]]
# list = [[tile_type, integer_percent_chance], [tile_type, integer_percent_chance],...]
func get_random_tile_type(list):
    var total = 0
    for pair in list:
        total += pair[1]

    randomize()
    var roll = randi() % int(total) + 1
    # default value just in case
    var chosen_tile = list[0][0]

    for pair in list:
        if roll <= pair[1]:
            chosen_tile = pair[0]
            break
        else:
            roll -= pair[1]

    return chosen_tile
by (3,707 points)

Hmm, I don't think I could fit all of that where I'm trying to put it. I mean, I was just trying to ass this into my auto-generated floor. Which is already in a function, and if I'm not mistaken, I can't throw a function within a function. I guess I'll do it the dumb way I said before, I could always use what you typed for loot drops or something.

You can call a function from within a function though...

extends TileMap

func generate_map():
    var tile_rarities = [[0, 80], [1, 10], [2, 5], [3,4]]
    for row in range(_max_rows):
        for col in range(_max_cols):
            var selected_tile_type = get_random_tile_type(tile_rarities)
            self.set_cell(row, col, selected_tile_type)

func get_random_tile_type(list):
    var total = 0
    for pair in list:
        total += pair[1]

    randomize()
    var roll = randi() % int(total) + 1
    # default value just in case
    var chosen_tile = list[0][0]

    for pair in list:
        if roll <= pair[1]:
            chosen_tile = pair[0]
            break
        else:
            roll -= pair[1]

    return chosen_tile

That's in fact how you should write code, it makes it more modular, maintainable and readable.

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 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 webmaster@godotengine.org with your username.