简体   繁体   中英

Pre-generating pseudo-random terrain in JS

I'm working on a simple JS/canvas game. In this game I want the users to be able to navigate a world that is generated by the client according to the same seed every time. So while the world is random, every user gets the same.

So for that I'm looking for a way to do the following:

var some_seed = "abcdefg" // For instance
function get_world_rect(ab, cd) { ... }

get_world_rect([0,0], [9,9])
// Yields the following: 
[[0, 0, 0, 0, 0, 0, "some_feature", 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, "rock", 0, 0, "bush", 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, "bush", 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, "bush", 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 
 [0, 0, "rare_flower", 0, 0, 0, 0, 0, 0, 0], 
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]

The two important bits here are that I want to be able to generate the same "map" every time on every client and control the "rarity" of certain features. So I'm able to say that the map has an X chance of spawning "bush" and Y chance of spawning "rare_flower".

I used a custom random number generator. I then fed it a seed plus some calculation based on the tile's x and y.

Not sure if this is the best I can do but it works.

A snippet appears below.

generate_map = function(chunk_x, chunk_y) {
    // The MersenneTwister object is from code this link: https://gist.github.com/banksean/300494
    // this.base seed is some int.
    // a "map chunk" is a square of tile containing this.map_chunk_size tiles.
    // chunk_x and chunk_y are that chunk's X and Y.
    g = new MersenneTwister(this.base_seed + chunk_x*1000000 + chunk_y)
    tiles = []
    for(var x = 0; x < this.map_chunk_size; x++) {
        for(var y = 0; y < this.map_chunk_size; y++) {
            var k = g.random()
            /* 
            Objects:
            0 - empty
            1 - something 1
            2 - something 2
            */
            var obj = 0
            if (k < 0.001) {
                // Something rare
                obj = 2
            } else if (k < 0.1) {
                obj = 1
            }
            tiles.push(obj)
        }
    }
    return tiles
}

This way it's predictable across browsers and OSes (as far as I can tell so far) and I don't have to generate on the server and keep a lot of data.

Impact on performance is minimal from what I can tell.

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