I was playing a round-based map (a lot) and started feeling like seeing the same terrain over and over was getting kinda stale. So I thought, "Wouldn't it be cool if we got a different terrain every run? Or even better - every round?"
I took it personally and decided to figure out a way to change the terrain during runtime. I ended up developing a couple of tools (in Python) that let me build multiple terrains for the same map.
I was really happy with the result. The whole process was much smoother than I expected. I can create several terrains (one in each map) and then use the tool to “combine” them into a single map. The terrains can then be swapped via triggers. Currently it supports terrain tiles, height and doodads.
Obviously, I'm pushing the game to its limits (and maybe even a bit beyond hehe). Understandably, there are some hurdles. I was wondering if anyone knows a better way to handle this.
I call this once for every vertex in the terrain on the map.
Visually, it looks great. It is completely indistinguishable from regular "terraining". However, there are two issues with this approach.
This can be fixed via triggers. I found an old thread that already worked out all the math, and I used the interpolation method from that thread to manually update the camera's Z-offset. Essentially, I do this:
Basically, I manually compute the correct Z-offset every 0.03 seconds. The calculation itself seemsnear-perfect. The only real issue is the 0.03-second periodic trigger. Suddenly moving the camera via the minimap can cause a very brief (just a few frames) and slightly janky camera update. Other than that, it works perfectly.
Are there better approaches to this? Having dynamic terrain changes would add a really nice touch to the map.
EDIT: I'm aware that terrain deformations can generally cause desyncs. However, since I'm manually setting every vertex to a specific height, this shouldn't be an issue.
I took it personally and decided to figure out a way to change the terrain during runtime. I ended up developing a couple of tools (in Python) that let me build multiple terrains for the same map.
I was really happy with the result. The whole process was much smoother than I expected. I can create several terrains (one in each map) and then use the tool to “combine” them into a single map. The terrains can then be swapped via triggers. Currently it supports terrain tiles, height and doodads.
Obviously, I'm pushing the game to its limits (and maybe even a bit beyond hehe). Understandably, there are some hurdles. I was wondering if anyone knows a better way to handle this.
1. Heightmap
I am using the following native to change the terrain:
JASS:
call TerrainDeformCrater(x, y, 1, delta, 1, true)
Visually, it looks great. It is completely indistinguishable from regular "terraining". However, there are two issues with this approach.
First: Camera Z-offset
Updating the terrain using the native above does not update the camera's Z-offset. If the deformation creates tall hills, the camera can even end up moving under the terrain!This can be fixed via triggers. I found an old thread that already worked out all the math, and I used the interpolation method from that thread to manually update the camera's Z-offset. Essentially, I do this:
JASS:
private function UpdateCamera takes nothing returns nothing
local real x = GetCameraTargetPositionX()
local real y = GetCameraTargetPositionY()
call SetCameraField(CAMERA_FIELD_ZOFFSET, GetCorrectHeight(x, y), 0.03)
endfunction
private function Init takes nothing returns nothing
local trigger t = CreateTrigger()
call TriggerRegisterTimerEvent(t, 0.03, true)
call TriggerAddAction(t, function UpdateCamera)
endfunction
Basically, I manually compute the correct Z-offset every 0.03 seconds. The calculation itself seems
Second: Performance in classic
Reforged seems to have improved terrain handling a lot. Especially the way terrain deformations interact with doodads. On classic (1.26), however, it's very slow and causes a noticeable lag spike. Depending on the number of doodads on the map, even a single call can take quite a while. Thankfully, this isn't an issue in Reforged, and the transition is completely smooth.2. Water
The only native that seems to interact with water during runtime isSetWaterDeforms native, but I haven't found any practical way to use it. Since we can't directly manipulate water, we run into a few problems:- Water level must remain constant - in every terrain, the water level stays the same. This is an acceptable limitation most of the time.
- Water transparency - Water transparency doesn't seem to respond to terrain deformations. As a result, all water appears as deep water and becomes completely opaque.
- Waves - Shore waves seem to be calculated at the start of the game (or in the editor). Terrain deformations don’t affect them. This isn't a huge issue, since it can be worked around.
Are there better approaches to this? Having dynamic terrain changes would add a really nice touch to the map.
EDIT: I'm aware that terrain deformations can generally cause desyncs. However, since I'm manually setting every vertex to a specific height, this shouldn't be an issue.
Last edited:
