[ZScript] Destructible geometry material handler

Post your example zscripts/ACS scripts/etc here.

[ZScript] Destructible geometry material handler

Postby dodopod » Fri Mar 08, 2019 2:38 pm



This script makes it easier to use GZDoom's new (v3.7) destructible geometry feature. It does this by providing an event handler, which assigns materials to lines, floors, ceilings and 3D floors based on texture (though they can also be assigned manually). Materials, like actors, have Health and DamageFactor properties, allowing level geometry to have strengths and weaknesses to different damage types. The event handler also defines several new events, allowing you to customize a material's behavior when it's damaged or destroyed.

GitLab repo (Includes a tutorial. Better documentation will come soon.)
Downloads:
dodopod
 
Joined: 04 Oct 2017

Re: [ZScript] Destructible geometry material handler

Postby ReformedJoe » Mon Mar 25, 2019 6:17 pm

Been tinkering with it for a bit now. This is so cool.
I had an idea for a project with destructible environments that I shelved because it would have been a pain in the ass, but this opens up many new possibilities.
Great stuff.
User avatar
ReformedJoe
 
Joined: 21 May 2018

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Mon Mar 30, 2020 11:11 am

This is very great! I just don't have experience on ZScript.. I was thinking how to make a brick wall. Problem would be how to avoid bricks floating in the air or just always "falling" to ground..
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby Caligari87 » Mon Mar 30, 2020 11:26 am

Unfortunately this doesn't work for something like a brick wall as it doesn't add any sort of true dynamic geometry. The level still has to be constructed out of sectors, which cannot have their 2D geometry modified at runtime, only floor and ceiling heights. This just makes it easier to trigger sector effects based on damage from weapons.
8-)
User avatar
Caligari87
I'm just here for the community
User Accounts Assistant
 
Joined: 26 Feb 2004
Location: Salt Lake City, Utah, USA
Discord: Caligari87#3089

Re: [ZScript] Destructible geometry material handler

Postby dodopod » Mon Mar 30, 2020 12:39 pm

Caligari's mostly right -- you can trigger line effects too, but that's about it. I'm not entirely sure what you're going for. The less dynamic it is, the easier it would be to do, but you might be able to pull off something more complex with some tricks.

If you just want a destructible wall, the best way to do it is the Duke Nukem way. You have a 2-sided line, which blocks everything, representing the wall. When the wall is destroyed, the texture changes to one with a big hole in it, and the blocks everything flag is turned off. The downsides are that the wall is paper thin, and that it isn't very dynamic -- it's either destroyed or not. You could get fancy with it in a number of ways: shoot out debris when the wall is destroyed; use sectors instead of a line, so the wall has some thickness; divide up the line into sections, so only parts of the wall are destroyed at a time; make the wall go through different stages of destruction; animate the wall's destruction. The limit is your ingenuity.

On the other hand, it sounds like you want to be able to destroy it brick-by-brick. That would be much more difficult. You might be able to do something along the lines of making each brick into a 3D floor. That's tedious, but might be doable. I remember there being some problems with 3D floors taking damage. Of course, like you mentioned, you would need to keep the bricks from floating. You might be able to make it so that when a brick is destroyed, it informs the brick above it. That brick then checks whether it's floating, and if so, either falls to the ground, or vanishes (by which I mean teleports beneath the ground, since 3D floors can't actually disappear).
dodopod
 
Joined: 04 Oct 2017

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Tue Mar 31, 2020 3:04 am

Now I'm understanding its limitations. It think this could be used as destructive walls like this:



Upper part is just lowered ceiling to get a shape so everything can't be destroyed.






Maybe change block resolution to 24 pixels and limit destructable area so it wont show that tetris-like effect. I would do the brick wall only to be destructible with explosives so it hides tetris-effect also. Change destructable walls texture to another one so player can see which can be destructed. Add spawning brick debris.. One problem will be the dig-height. Maybe putting 3D-floors on lower part.. But soon it will be too complex and tedious for larger gameplay element. One solution would be to do 5-20 pre-built walls which could be copy pasted and offsetted with "height offset" if height variation is needed..
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Tue Mar 31, 2020 7:05 am

If I would like to spawn debris I think it should have been done here, see comment:

Code: Select allExpand view
class DirtHandler : MaterialHandler
{
    override void OnRegister()
    {
        health = 20;
        textures.Push("FLAT10");
        textures.Push("GRASS1");
    }

    override void MaterialFloorDestroyed(WorldEvent e)
    {
        Super.MaterialFloorDestroyed(e);

        // Dig
        int newHeight = e.damageSector.floorPlane.ZAtPoint(e.damageSector.centerSpot) - 32;
        e.damageSector.MoveFloor(1, -newHeight, 0, 1, false, true);

        // Mow the lawn
        e.damageSector.SetTexture(Sector.floor, TexMan.CheckForTexture("FLAT10", TexMan.Type_Flat));

        // Reset health so we can dig some more
        e.newDamage = (e.newDamage - e.damageSector.GetHealth(SECPART_Floor)) % health;
        e.damageSector.SetHealth(SECPART_Floor, health);
   
      //Spawn debris here
    }
}


I've coded last time like 12 years ago so I'm stuck how exactly it should be done.

Hexen pack has this code to spawn debris:

Code: Select allExpand view
class DestructableDecorationBase : Actor
{
   Default
   {
    Radius 32;
    Height 32;
   Mass 100;
   Friction 1;
   Health 100;
    +SOLID
   +PUSHABLE
   +DROPOFF
   +SLIDESONWALLS
   +CANPASS
   +ACTLIKEBRIDGE
   +FLOORCLIP;
   +SHOOTABLE;
   +NOBLOOD;
   +NEVERTARGET;
   PushFactor 0.25;
   }

   void A_BitsExplode(int ammount ,string bit)
   {
      Actor mo = null;
      int i;

      for(i = ammount; i; i--)
      {
         mo = Spawn (bit, Pos, ALLOW_REPLACE);
         if (mo)
         {
            mo.SetState (mo.SpawnState + random[Pottery](0, 4));
            mo.Vel.X = random2[Pottery]() / 64.;
            mo.Vel.Y = random2[Pottery]() / 64.;
            mo.Vel.Z = random[Pottery](5, 12) * 0.75;
         }
      }
   }
}


I can't straight call A_BitsExplode(int ammount ,string bit) because it belongs to DestructableDecorationBase.. How I could do a generic debris function?
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby dodopod » Tue Mar 31, 2020 7:39 am

It would be almost the same, probably something like this:

Code: Select allExpand view
void EjectDebris(int amount, class<Actor> debrisCls, Vector3 pos, float maxVel)
{
    for (int i = 0; i < amount; i++)
    {
        let mo = Actor.Spawn(debrisCls, pos);
       
        mo.vel.x = frandom(-maxVel, maxVel);
        mo.vel.y = frandom(-maxVel, maxVel);
        mo.vel.z = frandom(-maxVel, maxVel);
    }
}


Then, in MaterialFloorDestroyed, something along these lines:

Code: Select allExpand view
override void MaterialFloorDestroyed(WorldEvent e)
{
    Super.MaterialFloorDestroyed(e);

    // Dig
    int newHeight = e.damageSector.floorPlane.ZAtPoint(e.damageSector.centerSpot) - 32;
   
    // btw you can solve the dig-height problem like this
    // 0 might not be the right number, but it keeps you from digging down forever
    if (newHeight < 0) return;
   
    e.damageSector.MoveFloor(1, -newHeight, 0, 1, false, true);

    // Mow the lawn
    e.damageSector.SetTexture(Sector.floor, TexMan.CheckForTexture("FLAT10", TexMan.Type_Flat));

    // Reset health so we can dig some more
    e.newDamage = (e.newDamage - e.damageSector.GetHealth(SECPART_Floor)) % health;
    e.damageSector.SetHealth(SECPART_Floor, health);

    //Spawn debris here
    Vector3 pos = (e.damageSector.centerSpot, newHeight + 16);  // center of the part just destroyed
    EjectDebris(8, "BrickDebris", pos, 64);
}
dodopod
 
Joined: 04 Oct 2017

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Tue Mar 31, 2020 8:14 am

Tried, got error messages

ZSCRIPT error in "material-demo-v1.0.pk3\zscript.zc", line 52. Expected preprocessor statement, const, enum or class declaraction, got <Token.Identifier (void)>.

Tried Const:
ZSCRIPT error in "material-demo-v1.0.pk3\zscript.zc", line 54. Expected =, got <Token.Identifier (EjectDebris)>.

Tried Class:
ZSCRIPT error in "material-demo-v1.0.pk3\zscript.zc", line 54. Unexpected token <Token.Identifier (maxVel)>.

Code: Select allExpand view
class void EjectDebris(int amount, class<Actor> debrisCls, Vector3 pos, float maxVel)
{
    for (int i = 0; i < amount; i++)
    {
        let mo = Actor.Spawn(debrisCls, pos);
       
        mo.vel.x = frandom(-maxVel, maxVel);
        mo.vel.y = frandom(-maxVel, maxVel);
        mo.vel.z = frandom(-maxVel, maxVel);
    }
}
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby dodopod » Tue Mar 31, 2020 8:16 am

Oh, EjectDebris needs to be inside the DirtHandler class.
dodopod
 
Joined: 04 Oct 2017

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Tue Mar 31, 2020 8:22 am

Nice, works perfectly. Thank you very much!
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Fri Apr 03, 2020 6:02 am

I figured out how to prevent more the tetris-like effect. When breakable wall also breaks upwards it is more better.

Code: Select allExpand view
 
   override void MaterialCeilingDestroyed(WorldEvent e)
    {
        Super.MaterialCeilingDestroyed(e);

        // Move ceiling up
        int newHeight = e.damageSector.ceilingPlane.ZAtPoint(e.damageSector.centerSpot) + 16;
      
      //Limit how far up ceiling breaks
      //if (newHeight > 128) return;
        e.damageSector.MoveCeiling(1, newHeight, 0, -1, false);

        // Change the ceiling texture to represent "broken" state
        e.damageSector.SetTexture(Sector.ceiling, TexMan.CheckForTexture("CRATOP2", TexMan.Type_Flat));

        // Reset health so a new block can be breaked
        e.newDamage = (e.newDamage - e.damageSector.GetHealth(SECPART_Ceiling)) % health;
        e.damageSector.SetHealth(SECPART_Ceiling, health);
      
      Vector3 pos = (e.damageSector.centerSpot, newHeight - 8);  // center of the part just destroyed
      EjectDebris(8, "WoodenBit", pos, 32);      
    }


BTW, where you find all the actors, classes, usable functions and methods? Some are found here:
https://github.com/marrub--/zscript-doc ... gDestroyed

I guessed "MaterialCeilingDestroyed". Also definitions and ranges for many variables would be useful, like speed etc.
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Sat Apr 04, 2020 11:43 pm

[Edit, now I figured out the solution! If you do height check against adjacent sector it will work dynamically!
Code: Select allExpand view
   
       //Limit how far down floor breaks, this it keeps you from digging down forever
      Double  lowestNearFloor = e.damageSector.FindLowestFloorSurrounding();
      if (newHeight < lowestNearFloor) return;   

https://github.com/marrub--/zscript-doc/blob/8081cd640bb2805a95918c142144751a00249bf4/api/level/Sector.md


...Original post...Now mostly futile, deleted most of it.

A brickwall example:
Spoiler:

Another question. At last I learned some Blender and did that brick model.

So I spawn one brick model:
EjectDebris(1, "breakableBrick04", pos, 8);

Can I rotate the brick randomly by some code?
Or do I use just different blocks like this:

Now I have 4 different brick models. So I could just do something like:
int x = random(1,4);
and then like:
if ( x == 1) EjectDebris(1, "breakableBrick01", pos, 8);
if ( x == 2) EjectDebris(1, "breakableBrick02", pos, 8);
if ( x == 3) EjectDebris(1, "breakableBrick03", pos, 8);
if ( x == 4) EjectDebris(1, "breakableBrick04", pos, 8);

but it would look kinda ugly?
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby Jaska » Sun Apr 05, 2020 12:52 pm

Seems like I'm not going to solve this problem.

How do I spawn debris for destroyed 3D-floor? It spawns the debris into a control sector.

Spoiler:
Jaska
 
Joined: 17 Dec 2019
Operating System: Windows 10/8.1/8/201x 64-bit
OS Test Version: No (Using Stable Public Version)
Graphics Processor: nVidia (Legacy GZDoom)

Re: [ZScript] Destructible geometry material handler

Postby dodopod » Sun Apr 05, 2020 2:37 pm

I think I might know how to do that. The control sector has one line that defines it as a 3D floor. That line's first argument is the tag of the sectors where that 3D floor appears. So, what you need to do is iterate over e.damageSector.lines, until you find the one where special == 160 (i.e. Sector_Set3DFloor). Then, you create a SectorTagIterator, and use that to find all the sectors where the tag is equal to args[0]. So something like this:

Code: Select allExpand view
class WoodHandler : MaterialHandler
{
    const Sector_Set3DFloor = 160;

    // ...

    override void Material3DDestroyed(WorldEvent e)
    {
        Super.Material3dDestroyed(e);
       
        int tag;
        for (int i = 0; i < e.damageSector.lines.Size(); i++)
        {
            Line l = e.damageSector.lines[i];
           
            if (l.special == Sector_Set3DFloor)
            {
                tag = l.args[0]
                break;
            }
        }
       
        let it = level.CreateSectorTagIterator(tag);
        int idx;
        while (idx = it.Next())
        {
            Sector s = level.sectors[idx];
           
            Vector3 pos = (s.centerSpot, s.floorPlane.ZAtPoint(s.centerSpot));
            EjectDebris(8, "WOODGIB", pos, 32);   //Alternate debris, use this WoodenBit
        }
       
        e.damageSector.MoveFloor(1, 1024, 0, 1, false, true);
        e.damageSector.MoveCeiling(1, -1024, 0, 1, false);
    }
}


As for rotating bricks, randomly, you can create a method in BreakableBrick to increment angle, pitch, and roll. Call that method every frame during the Spawn state. When velocity < 4, say, jump to the Death state, or whatever you want to call it, where the brick just sits there. You'll want set the angle, pitch, and roll speeds, when the brick is initialized, maybe by overriding PostBeginPlay. One other thing: with angle and roll, you can just increment them every frame. Pitch is tricky. I think it's clamped to between +/- 90 degrees. So when pitch goes over 90, you need to add 180 to the angle, and multiply pitchSpeed (or whatever you want to call it) by -1. I think you might also need to set +ROLLSPRITE -- I'm not sure if that applies to 3D models. I'm not honestly sure whether that will work, since 3D rotation is very confusing.
dodopod
 
Joined: 04 Oct 2017

Next

Return to Script Library

Who is online

Users browsing this forum: No registered users and 3 guests