Dynamic terrain

All topics about ZGameEditor goes here.

Moderator: Moderators

Post Reply
jinxtengu
Posts: 122
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Dynamic terrain

Post by jinxtengu »

Hi

I am interested in making
an fps (in terms of the games perspective, there may be no actual shooting involved)
in this hypothetical fps the ground that the player traverses is of variable
height and somewhat dynamic.

It seems easy enough to create, a doom style game in Z game editor,
where all the floors are flat, but I am wondering how is it possible to
have some more dynamic terrain underfoot?


I have seen some Z game examples, that demonstrated that
this is possible to do, so I am curious to find out how.

So lets say for example that we created
a hilly landscape in blender and then imported it into
z game editor. Now how would we then go about calculating some sort of hit detection based
on angle of vertices?

or would it make more sense to apply a material texture, that
somehow holds data for a height map.

I currently don't understand how to implement either of these ideas,
but I would be very interested in any talk or suggestions
or example code that would lead me towards finding a way to
generate some dynamic terrain for a game.

Im excited about making games with, a naturalistic environment,
and in nature there are rarely (if ever) any uniformly flat surfaces.
So figuring this out is key to making the sorts of games that I would enjoy playing, and therefor making.

Thoughts? :mrgreen:
User avatar
VilleK
Site Admin
Posts: 2277
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Dynamic terrain

Post by VilleK »

I'm sure Kjell has a demo of this somewhere but he doesn't want to share it ;)

Searching for "terrain" on these forums does show a few interesting hits. Have you read those posts?
jinxtengu
Posts: 122
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Dynamic terrain

Post by jinxtengu »

That's fair enough, considering the amount of code and assistance he's already most graciously provided.
Also it does create an incentive to try to figure out a solution myself.

I did do a few forum searches for "terrain", and I'll continue to read what has already been posted. Testing precise vertices in and around the player object to determine, gravity and inertia and such seems like it would involve calculations that are currently a bit beyond my understanding, however generating values based on a height map using a gradient scale with white being highest, black being lowest, and having that map match the dimensions of a landscape, seems like it would be alot easier to code and also potentially cheaper cpu wise.
If I make any progress I'll post back.
Thanks for all the support! :)
I'm having a look at 3D Physics with ZgeBullet. I see that there have been some terrain examples already posted, unfortunately some of the older links are no longer available.
User avatar
Kjell
Posts: 1883
Joined: Sat Feb 23, 2008 11:15 pm

Re: Dynamic terrain

Post by Kjell »

Hi jinxtengu,
jinxtengu wrote: Sun May 07, 2023 7:23 amSo lets say for example that we created a hilly landscape in blender and then imported it into z game editor. Now how would we then go about calculating some sort of hit detection based on angle of vertices?
The first obstacle you'll encounter is that you can't easily access the vertex & triangle data of imported meshes. Additionally you can't easily unload meshes ( you don't want to leave tons of unused data in VRAM ). Then you'd need some sort of space partitioning ( quad-tree / BSP-tree ) to not kill performance, and finally you need a bit of math. Judging from your other questions this might all be a bit much to DIY.
jinxtengu wrote: Sun May 07, 2023 7:23 amor would it make more sense to apply a material texture, that somehow holds data for a height map.
If you can get away with using a height-map ( or similar ) it would simplify things a lot. Below is a basic example that uses a 2D height-array representing a uniform grid of which the two triangles are always "sliced" in the same direction. You could make the "slice" variable if needed ( this is actually rather useful for topology ) but then i'd recommend against using the Mesh component.

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" AmbientLightColor="0 0 0 1" CameraPosition="4 1.26 6" CameraRotation="0.0748 0 0" LightPosition="1 1 1" MouseVisible="255" FileVersion="2">
  <OnLoaded>
    <ZExpression>
      <Expression>
<![CDATA[// Fill 2D map with random height values

for(int x=0; x<8; x++)
{
  for(int y=0; y<8; y++)
  {
    Map[x,y] = rnd()*0.5;
  }
}]]>
      </Expression>
    </ZExpression>
    <RefreshContent Component="TerrainMesh"/>
    <SpawnModel Model="Terrain"/>
    <SpawnModel Model="Player"/>
  </OnLoaded>
  <Content>
    <Array Name="Axis" SizeDim1="2"/>
    <Array Name="Map" Dimensions="1" SizeDim1="8" SizeDim2="8"/>
    <Model Name="Player" Position="4 0.26 4">
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[// Move player using mouse

float dt = App.DeltaTime;

Player.Position.X += App.MousePosition.X*dt;
Player.Position.Z -= App.MousePosition.Y*dt;

// Solve collision with terrain

float x, z;

x = Player.Position.X;
z = Player.Position.Z;

if(x >= 0 && x < 7 && z >= 0 && z < 7)
{
  int x1, x2, z1, z2;

  x1 = x;
  z1 = z;

  x2 = x+1;
  z2 = z+1;

  float fx, fz, y1, y2, y3;

  fx = frac(x);
  fz = frac(z);

  y1 = Map[x1,z1];
  y3 = Map[x2,z2];

  if(fx > fz)
  {
    y2 = Map[x2,z1];
    Player.Position.Y = y1+(y2-y1)*fx+(y3-y2)*fz;
  }
  else
  {
    y2 = Map[x1,z2];
    Player.Position.Y = y1+(y2-y1)*fz+(y3-y2)*fx;
  }
}

// Set camera position relative to player

App.CameraPosition.X = Player.Position.X;
App.CameraPosition.Y = Player.Position.Y+1;
App.CameraPosition.Z = Player.Position.Z+2;]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="PlayerMaterial"/>
        <RenderMesh Mesh="PlayerMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="PlayerMesh">
      <Producers>
        <MeshBox XCount="15" YCount="1" Grid2DOnly="255"/>
        <MeshExpression Scale="0.125 0.125 0.125" AutoNormals="0">
          <Expression>
<![CDATA[//

float a = V.X*PI;

V.X = sin(a);
V.Z = cos(a);

N.X = V.X;
N.Y = 0;
N.Z = V.Z;

if(V.Y == 0)
{
  V = 0;
}]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Material Name="PlayerMaterial" Color="1 0 0 1" DrawBackFace="255"/>
    <Model Name="Terrain">
      <OnRender>
        <UseMaterial Material="TerrainMaterial"/>
        <RenderMesh Mesh="TerrainMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="TerrainMesh">
      <Producers>
        <MeshBox Scale="0.5 0.5 1" XCount="6" YCount="6" Grid2DOnly="255"/>
        <MeshExpression>
          <Expression>
<![CDATA[//

int x, y;

x = round((V.X+0.5)*7);
y = round((0.5-V.Y)*7);

V.X = x;
V.Y = Map[x,y];
V.Z = y;]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Bitmap Name="TerrainBitmap" Filter="2">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

if(1-X > Y)
{
  Pixel.B = 1;
}
else
{
  Pixel = 1;
}]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Material Name="TerrainMaterial" Shading="1">
      <Textures>
        <MaterialTexture Texture="TerrainBitmap" TextureScale="7 7 1" TextureWrapMode="1" TexCoords="1" Origin="0 0 0"/>
      </Textures>
    </Material>
  </Content>
</ZApplication>
Could you name some game(s) that are in the ballpark of what you're trying to achieve?

K
jinxtengu
Posts: 122
Joined: Wed Oct 14, 2009 2:05 pm
Contact:

Re: Dynamic terrain

Post by jinxtengu »

Once again thanks for the example Kjell.

This will probably suffice for what I had in mind, if I can figure out
a few additional parameters.

The sort of game engine I had in mind was something
akin to Kings field 2 on the PSX,
or Tale of the sun, also on the PSX. In both these
games you can traverse hills.

having uneven polygonal surfaces that you can traverse lends itself
to greater verisimilitude.


Looking at the example,
I see the map array is populated by random values, Onloaded
that is used to generate the terrain mesh, and calculate
collision with the terrain on the player update.

Now In order for this to be really useful for me
it would be good to be able to generate
a few distinctive shapes and landscape patterns
rather than always populated the map array randomly
for example having Inclines/ramps, half spheres etc.

This obviously could be done with the calculation used to fill
the "map" array, but I wouldn't be able
to come up with the formulas needed to
generate terrain shapes.

The next thing that would help is
a way to position these maps
using the txt loading method that was
demonstrated in the file demo/fps demo.

My thought would be to use the example you just posted
for certain areas of terrain,
in conjunction with other areas made up of
simple cube/sphere shapes,
thereby constructing larger, more dynamic landscapes.

The last thing that would need to be sorted,
is how to use this demo in conjunction with gravity.

My thought is that this could be solved via the addition of
a variable that sets itself to a grounded state when the
collision with the
terrain is calculated,
and if the player is not grounded, it calculates some form of inertia,
relative to app.deltatime.


Here's a demo that I put together over the last
couple of days that should also give you an indication of what I'm working to achieve.

https://www.revengeofthesunfish.com/fps.txt
It's needs bass Dll to run, or you could remove the bass function at the start.

you can walk around with wasd.

After walking for a bit, I'd like the player to encounter
a hill and some lumpy, (but not randomized) terrain.

That would make it feel more "real"

Hope this helps :D
User avatar
Kjell
Posts: 1883
Joined: Sat Feb 23, 2008 11:15 pm

Re: Dynamic terrain

Post by Kjell »

Hi jinxtengu,
jinxtengu wrote: Tue May 09, 2023 9:12 amLooking at the example, I see the map array is populated by random values
That's just for demonstration purposes, you can just as easily populate the map array using a mesh made in Blender ( or similar ). Below is the same example as before but using the data of a exported mesh.

Image

Code: Select all

<?xml version="1.0" encoding="iso-8859-1" ?>
<ZApplication Name="App" Caption="ZGameEditor application" AmbientLightColor="0 0 0 1" CameraPosition="4 1 6" CameraRotation="0.0748 0 0" LightPosition="1 1 1" MouseVisible="255" FileVersion="2">
  <OnLoaded>
    <SpawnModel Model="Terrain"/>
    <SpawnModel Model="Player"/>
  </OnLoaded>
  <Content>
    <Array Name="Axis" SizeDim1="2"/>
    <Array Name="Map" Dimensions="1" SizeDim1="8" SizeDim2="8" Persistent="255">
      <Values>
<![CDATA[78DA6360A03AB047C3A4CA6353634F847D64C90300CC060430]]>
      </Values>
    </Array>
    <Model Name="Player" Position="4 0.26 4">
      <OnUpdate>
        <ZExpression>
          <Expression>
<![CDATA[// Move player using mouse

float dt = App.DeltaTime;

Player.Position.X += App.MousePosition.X*dt;
Player.Position.Z -= App.MousePosition.Y*dt;

// Solve collision with terrain

float x, z;

x = Player.Position.X;
z = Player.Position.Z;

if(x >= 0 && x < 7 && z >= 0 && z < 7)
{
  int x1, x2, z1, z2;

  x1 = x;
  z1 = z;

  x2 = x+1;
  z2 = z+1;

  float fx, fz, y1, y2, y3;

  fx = frac(x);
  fz = frac(z);

  y1 = Map[x1,z1];
  y3 = Map[x2,z2];

  if(fx > fz)
  {
    y2 = Map[x2,z1];
    Player.Position.Y = y1+(y2-y1)*fx+(y3-y2)*fz;
  }
  else
  {
    y2 = Map[x1,z2];
    Player.Position.Y = y1+(y2-y1)*fz+(y3-y2)*fx;
  }
}

// Set camera position relative to player

App.CameraPosition.X = Player.Position.X;
App.CameraPosition.Y = Player.Position.Y+1;
App.CameraPosition.Z = Player.Position.Z+2;]]>
          </Expression>
        </ZExpression>
      </OnUpdate>
      <OnRender>
        <UseMaterial Material="PlayerMaterial"/>
        <RenderMesh Mesh="PlayerMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="PlayerMesh">
      <Producers>
        <MeshBox XCount="15" YCount="1" Grid2DOnly="255"/>
        <MeshExpression Scale="0.125 0.125 0.125" AutoNormals="0">
          <Expression>
<![CDATA[//

float a = V.X*PI;

V.X = sin(a);
V.Z = cos(a);

N.X = V.X;
N.Y = 0;
N.Z = V.Z;

if(V.Y == 0)
{
  V = 0;
}]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Material Name="PlayerMaterial" Color="1 0 0 1" DrawBackFace="255"/>
    <Model Name="Terrain">
      <OnRender>
        <UseMaterial Material="TerrainMaterial"/>
        <RenderMesh Mesh="TerrainMesh"/>
      </OnRender>
    </Model>
    <Mesh Name="TerrainMesh">
      <Producers>
        <MeshImport HasVertexColors="1">
          <MeshData>
<![CDATA[78DAEDD0B111C2300C856141057B680FD26A0D7A2DA3613400256403356C22FC63682838FA605F3E27B9675BF6222267F96CF765707A8DAF168A6A988E1658895ED83D53188A6A988E1658895ED83DD7C35054C374B5EE317558895ED83D77C65054C3F474F258895EC8BF77A563B1208FE96861411EBD90AF6E6AE4249C4C0DD3D1022BD10B99471E43B903354C470B1C851409EC679B63286F9C8A3C52C1DC7BAE484EE42807D9FDD0F7CFBECDE4ADAF7DE9FF2D7DEFEBBAF6969F0778F083F8]]>
          </MeshData>
        </MeshImport>
        <MeshExpression AutoNormals="0" HasTexCoords="255">
          <Expression>
<![CDATA[//

int x, y;

x = round(V.X);
y = round(V.Z);

Map[x,y] = V.Y;

//

TexCoord.X =  V.X;
TexCoord.Y = -V.Z;]]>
          </Expression>
        </MeshExpression>
      </Producers>
    </Mesh>
    <Bitmap Name="TerrainBitmap" Filter="2">
      <Producers>
        <BitmapExpression>
          <Expression>
<![CDATA[//

if(1-X > Y)
{
  Pixel.B = 1;
}
else
{
  Pixel = 1;
}]]>
          </Expression>
        </BitmapExpression>
      </Producers>
    </Bitmap>
    <Material Name="TerrainMaterial" Shading="1">
      <Textures>
        <MaterialTexture Texture="TerrainBitmap" TextureWrapMode="1" TexCoords="1" Origin="0 0 0"/>
      </Textures>
    </Material>
  </Content>
</ZApplication>
jinxtengu wrote: Tue May 09, 2023 9:12 amThe next thing that would help is a way to position these maps using the txt loading method that was demonstrated in the file demo/fps demo.
Personally I wouldn't use a txt file for this. If you simply use the raw binary data of your maps you can load straight into a array using the File component ( attached is a example of this ). If you want / need to support various map dimensions you can store additional values at the end of your binary data that represent the width & height of your map ( or derive the height using length / width ).
jinxtengu wrote: Tue May 09, 2023 9:12 amThe last thing that would need to be sorted, is how to use this demo in conjunction with gravity.
In my example i calculate the height of the terrain at the x,z coordinates of the player and simply set the player y coordinate to that ( so the player sticks to the floor ). So while your player is jumping, compare the y coordinate of the player with the height of the terrain, if it's lower that means the player has landed / collided with the terrain.

K
Attachments
Terrain.zip
(1.43 KiB) Downloaded 324 times
User avatar
VilleK
Site Admin
Posts: 2277
Joined: Mon Jan 15, 2007 4:50 pm
Location: Stockholm, Sweden
Contact:

Re: Dynamic terrain

Post by VilleK »

That's a very nice example Kjell.
Post Reply