• Listen to a special audio message from Bill Roper to the Hive Workshop community (Bill is a former Vice President of Blizzard Entertainment, Producer, Designer, Musician, Voice Actor) 🔗Click here to hear his message!
  • Read Evilhog's interview with Gregory Alper, the original composer of the music for WarCraft: Orcs & Humans 🔗Click here to read the full interview.

Terrain Generation

Level 2
Joined
Jun 25, 2009
Messages
19
If this is the wrong section please move it. Thanks :)

Hey everybody! This is my first JASS script, so don't expect it to be fail-free.

It takes an empty map and generates a terrain for it, placing tiles, height and trees (destructibles). Of course it does not look really well done, but it can be useful with maps that just require a random forest or something like that. I'd really like feedback on what can be improved in it, as it is my first script.

Todo:
  • Possibility to only generate only in a specified area
  • Try to make the tiles more natural (not thick grass next to dirt etc.)


Here's the code: and here's a demo map for download: View attachment Terrain Generator Demo.w3m
(the []'s in the code screws up here for some reason)

JASS:
function Terrain_Generator takes nothing returns nothing
    local integer array tiles
    local integer array trees
    local integer seed
    local integer treeseed
    local integer gen
    local integer loop1
    local integer loop2
    local integer loop3
    local real x
    local real y
    local integer array xx
    local integer array yy
    local group units = CreateGroup()
    local real height = GetRectMaxY(bj_mapInitialPlayableArea) - GetRectMinY(bj_mapInitialPlayableArea)
    local real width = GetRectMaxX(bj_mapInitialPlayableArea) - GetRectMinX(bj_mapInitialPlayableArea)
    local string prefix = "|c00ffcc00[Terrain Generator]|r "
    local string color = "|r|c00999999"

    set seed = 100        // Lower number = More variation in terrain and more bumps
    set treeseed = 10     // 0 - 100. 0 = No trees, 100 = WAY too many trees

    set tiles[1] = 'Lrok' // Lordaeron Summer Rock
    set tiles[2] = 'Ldro' // Lordaeron Summer Rough Dirt
    set tiles[3] = 'Ldrt' // Lordaeron Summer Dirt
    set tiles[4] = 'Ldrg' // Lordaeron Summer Grassy Dirt
    set tiles[5] = 'Lgrs' // Lordaeron Summer Grass
    set tiles[6] = 'Lgrd' // Lordaeron Summer Dark Grass

    set trees[1] = 'LTlt' // Lordaeron Summer Tree Wall
    set trees[2] = 'ATtr' // Ashenvale Tree Wall
    set trees[3] = 'ATtc' // Ashenvale Canopy Tree

    set xx[1] = 1
    set xx[2] = -1
    set xx[3] = 1
    set xx[4] = -1
    set yy[1] = 1
    set yy[2] = 1
    set yy[3] = -1
    set yy[4] = -1

    call DisplayTimedTextToPlayer(GetLocalPlayer(), 0, 0, 10, prefix + color + "Created by|r |c00ff0000xHPx|r" + color + ". Starting generation...")
    
    set gen = 1
    loop
        exitwhen gen > 2
            set loop1 = 1
        loop
            exitwhen loop1 > width / seed
            
            set loop2 = 1
            loop
                exitwhen loop2 > height / seed
                     set loop3 = 1
                     loop
                         exitwhen loop3 > 4
                         set x = I2R(loop1) * I2R(seed) * xx[loop3]
                         set y = I2R(loop2) * I2R(seed) * yy[loop3]
                         if (gen == 1) and (GetTerrainType(x, y) == 'Ldrt') then
                             call SetTerrainType(x, y, tiles[GetRandomInt(1, 6)], -1, GetRandomInt(1,5), 0)
                             call TerrainDeformCrater(x, y, GetRandomReal(0, 512), GetRandomReal(-64, 64), 1, true)
                         endif
                         if (gen == 2) and (GetRandomInt(0, 100) < treeseed) and (not (GetTerrainType(x, y) == 'Lrok')) then
                             call GroupEnumUnitsInRange(units, x, y, 150, null)
                             set bj_groupCountUnits = 0
                             call ForGroup(units, function CountUnitsInGroupEnum)
                             if (not (bj_groupCountUnits > 0)) then
                                 call CreateDestructable(trees[GetRandomInt(1, 3)], x, y, GetRandomReal(1, 360), GetRandomReal(0.75, 1.25), 0)
                             endif
                             call DestroyGroup(units)
                         endif  
                         set loop3 = loop3 + 1
                     endloop
                set loop2 = loop2 + 1
            endloop
            call TriggerSleepAction(0.01)
        set loop1 = loop1 + 1
        endloop
    set gen = gen + 1
    endloop

    call DisplayTextToPlayer(GetLocalPlayer(), 0, 0, prefix + color + "Terrain generation complete.")
endfunction
 
  • Your units group leaks, you need to set it to null at the end of your trigger.
  • This script needs to be ported to vJASS, this way it would allow for max configurablity.
  • If you port to vJASS you should make the group global and recycle it, instead of creating a new group.
  • Your GroupEnumUnitsInRange leaks, you can't pass null as a filter else it will leak.
 
Level 8
Joined
Aug 4, 2006
Messages
357
This is really good for your first JASS script.

However, I don't think it could be useful. It does not look very nice, and the user will have no idea where is a "safe" place to put units since they might end up trapped in trees or something. Even in test maps, I would not want to use this system. I'd rather take a few minutes to lay out stuff according to my needs rather than end up with terrain that inhibits my testing. The only way this could really be useful is if you could copy the generated terrain and paste it into world editor (which I think is impossible). Even then, you would have to work at this system a lot more to make it generate terrain that would be worth keeping.

I know a bunch of games generate their terrain. For example, many of Diablo 2's levels are laid out randomly when you create a game. It could be great programming practice to try to generate realistic terrain in world editor, but do not count on it becoming anything more than practice.
 
Level 21
Joined
Aug 21, 2005
Messages
3,699
I once tried to make a realistic terrain generating script, but the problem is the LAG. If you use too many "terrain deformations", the map lags like hell, so you're limited to using only a few, which gives you less room for more interesting terrain.

I've made terrain generators and I have easily generated over 100k terrain deformations without any lag... And my computer is by no means "high-end". Make sure you don't make terrain deformations "temporary" with 0 seconds duration, because that does lag, even after creating 1 deformation. They must be "permanent".
 
[Double post to make it obvious I added a reply]

I made it run in 1.24 by searching for returns in the middle of functions and removing them, replacing them with "set toReturn = <value>" and returning "toReturn" at the end of the function. I also updated Table to 3.0, the 1.24-compatible one, but it doesn't seem to generate any terrain...

EDIT: I just realised you have to type "-barrens" or "-ashenvale" in game to get it to work. You could have told me that. Well, I'm actually really impressed by this. It generates decent terrain without lag after generation is complete. I guess I tried to make realistic "islands" by practically spamming terrain deforms. I should have used a method similar to yours instead.

It would be fabulous if it could generate water too (by making it on a map that was originally underwater, but had its height increased to hide the water, if you know what I mean, and adding some "crater" deformations which actually sink the terrain, revealing the water). Why not submit this kind of thing?
 

Attachments

  • Random Terrain Generation.w3x
    155.9 KB · Views: 97
Last edited:
Level 21
Joined
Aug 21, 2005
Messages
3,699
EDIT: I just realised you have to type "-barrens" or "-ashenvale" in game to get it to work. You could have told me that. Well, I'm actually really impressed by this. It generates decent terrain without lag after generation is complete. I guess I tried to make realistic "islands" by practically spamming terrain deforms. I should have used a method similar to yours instead.

Sorry, should've said the actual command is:

- ashenvale #number
#number is the seed. Each time you enter the same seed, the same terrain is generated.
Due to other projects & real life stuff this is currently on-hold. Feel free to expand it if you wish.

P.s. I think I should stop hi-jacking this thread. The OP's code is pretty good for a first script.
 
Level 2
Joined
Jun 25, 2009
Messages
19
I also have a version that generates creeps as well, with different levels depending on the distance from the center of the map. I'll post if you are interested.
 
On big maps this takes ages to finish. You should probably be using timers to speed up the process.
Furthermore, your group still leaks and this should really be ported to vJass.
Forcing the user to edit the source code is just begging for trouble, vJass gets around that with global configuration.

If you port it to vJass, and fixing the things I said, I will revive this.
 
Top