• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Terrain Generation

Status
Not open for further replies.
In my map, Impossible Odds, I generate all my terrain randomly. Right now it can create a terrain with rocks, dead trees, flowers, & ferns that looks really nice. When players reach a very high wave (difficulty peak is at its max) and they survive I want to have em' "fly off" and everything blacks out, then a new terrain is generated, and they are in a 'new area'.

I can't seem to generate anything else in a nice way though. I've been experimenting with different ways to generate forests, fields, and so on but nothing is working out really well. I think part of the problem is the models selection...

I also can't figure out a way to modify terrain height or textures. I also want to have a weather system & be able to change the day-light settings.

Here's my current script for generating forests:
JASS:
void gf_ForestGenerator (string lp_plant) {
    // Implementation
    const fixed lv_xEnd     = 116;
    const fixed lv_yEnd     = 106;
    const fixed lv_xStart   = 12;
    const fixed lv_yStart   = 10;
    fixed       lv_x        = lv_xStart;
    fixed       lv_y        = lv_yStart;
    int         lv_i        = 1;
    int         lv_i2;
    point       lv_pt;
    unit        lv_u;
    point[12]   lv_dpt;
    
    fixed       lv_distance2;
    fixed       lv_distance;
    
    while(lv_i < 12) {
        lv_dpt[lv_i] = Point(RandomFixed(lv_xStart, lv_xEnd), RandomFixed(lv_yStart, lv_yEnd));
        lv_i += 1;
    }
    
    while(lv_y <= lv_yEnd) {
        lv_pt = PointWithOffset(Point(lv_x, lv_y), RandomFixed(-0.5, -.5), RandomFixed(-0.5, 0.5));
        
        lv_distance2 = 10000.0;
        lv_i = 1;
        while(lv_i < 12) {
            lv_distance = DistanceBetweenPoints(lv_pt, lv_dpt[lv_i]);
            if (lv_distance < lv_distance2) {
                lv_distance2 = lv_distance;
            }
            lv_i += 1;
        }
        
        lv_i = RandomInt(0, 100);
        if ((lv_distance2*lv_distance2 / 520)*20 >= lv_i) {
            UnitCreate(1, "DeadTree", 0, 0, lv_pt, RandomFixed(0.0, 360.0));
            lv_u  = UnitLastCreated();
            lv_i2 = RandomInt(65, 110);
            libNtve_gf_UnitSetVariation(lv_u, lp_plant, RandomInt(1, 5), "");
            UnitSetScale(lv_u, lv_i2 + RandomInt(-15, 15), lv_i2 + RandomInt(-15, 15), lv_i2 + RandomInt(-15, 15));
        }
        lv_x += 1.0;
        if (lv_x > lv_xEnd) {
            lv_x = lv_xStart;
            lv_y += 1.0;
            Wait(0.0, c_timeGame);
        }
    }
}

This is I use for creating crops:
JASS:
void gf_CropGenerator (string lp_plant, int lp_angle, point lp_point, fixed lp_size) {
    // Implementation
    const fixed lv_xEnd     = 116;
    const fixed lv_yEnd     = 106;
    const fixed lv_xStart   = 12;
    const fixed lv_yStart   = 10;
    fixed       lv_x        = lv_xStart;
    fixed       lv_y        = lv_yStart;
    region      lv_reg      = RegionRect(PointGetX(lp_point) - (lp_size/2), PointGetY(lp_point) - (lp_size/2), PointGetX(lp_point) + (lp_size/2), PointGetY(lp_point) + (lp_size/2));
    int         lv_crov     = RandomInt(1, 5);
    int         lv_i        = 1;
    int         lv_i2;
    point       lv_pt;
    unit        lv_u;
    
    lp_angle = lp_angle - (lp_angle%45);
    gf_DebugMsg("lp_angle = " + IntToString(lp_angle));
    gf_DebugMsg("lv_crov = " + IntToString(lv_crov));
    
    CameraPan(1, lp_point, 1.0, -1, 10, false);
    while(lv_y <= lv_yEnd) {
        lv_pt = PointWithOffset(Point(lv_x, lv_y), RandomFixed(-0.5, -.5), RandomFixed(-0.5, 0.5));
        if (RegionContainsPoint(lv_reg, lv_pt)) {
            UnitCreate(1, "Plants", 0, 0, lv_pt, lp_angle);
            lv_u  = UnitLastCreated();
            lv_i2 = RandomInt(100, 120);
            libNtve_gf_UnitSetVariation(lv_u, lp_plant, lv_crov, "");
            UnitSetScale(lv_u, lv_i2 + RandomInt(-15, 15), lv_i2 + RandomInt(-15, 15), lv_i2 + RandomInt(-15, 15));
        }
        lv_x += 1.0;
        if (lv_x > lv_xEnd) {
            lv_x = lv_xStart;
            lv_y += 1.0;
            Wait(0.0, c_timeGame);
        }
    }
}

This is what I do to generate the terrain I currently use:

JASS:
//--------------------------------------------------------------------------------------------------
// Trigger: Terrain Generator
//--------------------------------------------------------------------------------------------------
bool gt_TerrainGenerator_Func (bool testConds, bool runActions) {
    // Variable Declarations
    int lv_i;
    int lv_i2;
    int lv_i3;
    int lv_i4;
    point lv_pt;
    unit lv_u;
    const fixed lv_xStart = 12.0;
    const fixed lv_xEnd = 116.0;
    const fixed lv_yStart = 10.0;
    const fixed lv_yEnd = 106.0;

    // Variable Initialization
    lv_i = 1;
    lv_i2 = 1;
    lv_i3 = 1;
    lv_i4 = 1;
    lv_pt = null;
    lv_u = null;

    // Actions
    if (!runActions) {
        return true;
    }

    gf_CreateStartingUnits();
    libNtve_gf_SetPlayerGroupAlliance(gv_team1, 2);
    // Dead Trees
    while (lv_i <= 50) {
        UnitCreate(1, "DeadTree", 0, 0, PointWithOffset(gv_waveSpawnPoint, RandomInt(-60, 60), RandomInt(-60, 60)), RandomFixed(0.0, 360.0));
        Wait(0.0, c_timeGame);
        CameraPan(1, UnitGetPosition(UnitLastCreated()), 0.0, -1, 10, false);
        lv_i += 1;
    }
    // Rocks
    lv_i = 1;
    while (lv_i <= 3) {
        lv_pt = PointWithOffset(gv_waveSpawnPoint, RandomInt(-40, 40), RandomInt(-40, 40));
        lv_i2 = 1;
        while (lv_i2 <= 12) {
            UnitCreate(1, "DeadTree", 0, 0, PointWithOffset(lv_pt, RandomFixed(-8.0, 8.0), RandomFixed(-8.0, 8.0)), RandomFixed(0.0, 360.0));
            lv_u = UnitLastCreated();
            libNtve_gf_UnitSetVariation(lv_u, "Rock", RandomInt(1, 14), "");
            UnitSetScale(lv_u, RandomInt(80, 150), RandomInt(80, 150), RandomInt(80, 160));
            UnitSetState(lv_u, c_unitStateInvulnerable, true);
            lv_i2 += 1;
        }
        Wait(0.0, c_timeGame);
        CameraPan(1, UnitGetPosition(UnitLastCreated()), 1.0, -1, 10, false);
        lv_i += 1;
    }
    // Shrubs
    lv_i = 1;
    while (lv_i <= 40) {
        lv_pt = PointWithOffset(gv_waveSpawnPoint, RandomInt(-40, 40), RandomInt(-40, 40));
        lv_i2 = 1;
        lv_i3 = RandomInt(3, 15);
        while (lv_i2 <= lv_i3) {
            UnitCreate(1, "Plants", 0, 0, PointWithOffset(lv_pt, RandomFixed(-3.0, 3.0), RandomFixed(-3.0, 3.0)), RandomFixed(0.0, 360.0));
            lv_u = UnitLastCreated();
            lv_i4 = RandomInt(75, 150);
            if (RandomInt(0, 8) == 0) {
                lv_i4 = RandomInt(55, 85);
                libNtve_gf_UnitSetVariation(lv_u, "BelShirLushShrubs", RandomInt(1, 5), "");
            }
            UnitSetScale(lv_u, lv_i4 + RandomInt(-15, 15), lv_i4 + RandomInt(-15, 15), lv_i4 + RandomInt(-15, 15));
            Wait(0.0, c_timeGame);
            CameraPan(1, UnitGetPosition(UnitLastCreated()), 0.0, -1, 10, false);
            lv_i2 += 1;
        }
        lv_i += 1;
    }
    
    //gf_ForestGenerator("TyphonTree");
    //gf_FieldGenerator("Bush");
    lv_i = 1;
    while (lv_i <= 8) {
        //gf_CropGenerator("AgriaCrops", RandomInt(0, 360), Point(RandomFixed(lv_xStart, lv_xEnd), RandomFixed(lv_yStart, lv_yEnd)), RandomInt(12, 16));
        lv_i += 1;
    }
    return true;
}

//--------------------------------------------------------------------------------------------------
void gt_TerrainGenerator_Init () {
    gt_TerrainGenerator = TriggerCreate("gt_TerrainGenerator_Func");
    TriggerAddEventTimeElapsed(gt_TerrainGenerator, 0.0, c_timeGame);
}

Blizzards terrain textures & the shaders for them are so ugly btw D:.


Edit: nvm what I said about weather, those weather effects really lag the game. I might still be able to do day/night.
 
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
Code:
native void     GameSetLighting (string inId, fixed inBlendTime);
This can be used to change the current lighting model to a different model. The inId is a lighting catalog entry which you can customize in the data editor or the lighting manager. Blend time can be used to make it smoothly change to the specified light model over a period of time (so no sudden change of shadow direction etc).

To modify terrain texture you need to use actors to create decalls ontop of the existing terrain texture.

To modify terrain height I believe actors can also be used (as the buildings do flatten terrain under them).

For a very good terrain generation system you need to think of the structure of each type of environment. The idea is you vectorize the layout of the terrain and then use some algorthim to change those vectors into real terrain objects. A forest area needs to be filled with trees for example. I am sure you can look up good random but dense fill algorthims somewhere.
 
To modify terrain texture you need to use actors to create decalls ontop of the existing terrain texture.

To modify terrain height I believe actors can also be used (as the buildings do flatten terrain under them).

For a very good terrain generation system you need to think of the structure of each type of environment. The idea is you vectorize the layout of the terrain and then use some algorthim to change those vectors into real terrain objects. A forest area needs to be filled with trees for example. I am sure you can look up good random but dense fill algorthims somewhere.

How do you create decals & what are decals?

I think that if I could create different soil-types & raise/lower the terrain I could create a system whereby I just plant a few trees which spread out seeds that have are more likely to germinate & grow well in better soil / more elevated areas / areas with less competition for light from other plants (better plant spacing).
 
A much more barbaric (and yet somehow effective) way of doing this would be to randomly place regions around the map, then customize what you want to spawn in those regions.
Effectively having a "one area is forest-like, one area is baren, one area is town-like".

If you're trying to create new areas, why not just make one big map and have two different locations, cut off by terrain and the minimap? That is unless you're already using a really big map and are using all of it.
Just an idea..
 

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,201
If you're trying to create new areas, why not just make one big map and have two different locations, cut off by terrain and the minimap?
This results in longer map load times for content which might not even be nescescary.

A much more barbaric (and yet somehow effective) way of doing this would be to randomly place regions around the map, then customize what you want to spawn in those regions.
Effectively having a "one area is forest-like, one area is baren, one area is town-like".
Yeh that is prety much how you make random terrain. You specify rules and relations and then some algorthims fill in the defined areas. The problem is actually placing, filling and blending the areas in a realistic and eye pleasing way.
 
Status
Not open for further replies.
Top