Snarkpit Articles


<<< Return to part 2


Part 3: building a better boulder

In this final part of the series, I will show you how to turn the boring train we made in part 1 into a fully-featured rolling boulder. There is a lot of work to do, but unlike the last tutorial none of this work will involve complex logical relationships between entities. It will, however, introduce both the Movewith and Locus systems of Spirit. The ripple effect, in particular, is perhaps the most horrendously complex system of entities I have ever made. You have been warned!

Fortunately each effect can be treated separately, so unlike the last tutorial you won?t have to hold all the entity relationships in your head at the same time! We will begin by replacing the visible body of the train ? currently just a box ? with an animated model. We will start with ?map4? from the previous tutorial; this is included in the example maps for part 3, together with the final product, which is called ?map5?.

I assume that you are using Merl?s custom build of Zoner?s compile tools, or XP-Cagey?s custom build of Merl?s tools. These both include the ?null texture?.

Load up the example map ?map4?. Click the ?ignore groups? button and select all the faces on the main train block (not the origin brush). Texture them with ?null?. This will cause the polygons to be totally removed from the game. Toggle ?ignore groups? off.

Create a cycler entity; place it so that the bottom of the cycler (which is marked in the 3 editor orthographic views as a cross) lies exactly over the centre of the train. Select the cycler and give it the following properties:

  • Name cycler
  • Moves with boulder
  • Model models/boulder7.mdl
From now on, the train will have no function except to determine the path of the boulder. All of the effects that evidence the boulder to the players will be made to follow the train around, by means of the Movewith function. Compile the map; you should see that the train has been replaced by a rolling boulder, albeit one that only ever faces in one direction.

Now we will adjust the cycler effect so that the boulder always turns to face the correct direction. I should forewarn you that we are about to have a lot more entities, and as the tutorial progresses you are likely to become confused by the clutter. You can either use VisGroups to hide entities, or you can make new rooms in which to put them. For most of the entities, it doesn?t matter where you put them; I will be quite specific about the location of the others.

We will use a Spirit entity called an env_customize; in fact, we will make 8 of them. At every turn, we will trigger the correct env_customize, which will swap the model of the cycler. For the first one, create an env_customize with:
  • Name cycler_env1
  • Target to affect cycler
  • Set model models/boulder1.mdl
Now clone the entity you?ve just created 7 times to make a total of 8 entities. Change the number suffix on both the ?Name? and ?Set model? fields, so that it ranges from 1-8. ?cycler_env2? is associated with ?boulder2.mdl?, ?cycler_env3? with ?boulder3.mdl? etc.

Now you just need to tell the boulder to turn at each relevant path_corner. Looking at the map from above, in the top editing panel, you can use this image to tell you which way each model rolls:



For example, select both the path_corners ?1? and ?2? and add:
  • Fire on pass cycler_env7
One annoyance inherent in this method is that path_corners can only fire one targetname. For the path_corner called ?5?, select the mm ?path5_mm? instead. Turn off SmartEdit and add:
  • cycler_env4 0
For all the others, you can add in the correct ?cycler_envX? using the ?Fire on pass? key. Leave the path_corners ?start? and ?e? untouched, as well as any other path_corners where the direction does not need changing. Compile the map; the boulder should now turn to face the correct direction.

Now we will make the boulder squash people. Create a trigger_hurt that fits closely around the visible boulder model. The best way to line it up is to use the model-viewing feature in Hammer 3.5, in combination with the 3D view. Give it these properties:
  • Moves with boulder
  • Damage 1000
On compiling, you should find that the boulder can now kill you. Now we will make the earth shake whenever the boulder is close. Create an env_shake with the following properties:
  • Name shake
  • Moves with boulder
  • Amplitude 8
  • Effect radius 500
  • Duration 1
  • 0.1=jerk, 255.0=rumble 255
Place this env_shake in the centre of the boulder. Now create a mm with:
  • Name shake_mm
Turn off SmartEdit and add:
  • shake 0
  • shake_mm 0.5
Set the following flags:
  • Multi-threaded
  • Start on
On compiling you should find that the ground shakes near the boulder.

Our final effects involve a visible trail and a sound. When the boulder is on land, we want it to make a rumbling sound and to leave a trail of dust. When the boulder is in water, we want it to make a splashing sound and leave a trail of ripples. It might also be useful to turn all these effects off, for when the boulder is falling through the air. This isn?t covered in the tutorial, but if you follow the method below it will be an obvious extension.

First let?s set up the rumbling sound. For this we will use an invisible func_rotating. The func_rotating will play a sound only when it is on. We will have it move with the boulder and trigger it when we want to toggle the sound. Make a block textured with the null texture, and put an origin brush in its centre. Turn this into a func_rotating, and set:
  • Name rumble
  • Moves with boulder
  • Wav name boulder1.wav
Tick these flags:
  • Not solid
  • Large radius
Now copy this object, and change the following keys:
  • Name splash
  • Wav name river.wav
Position both of these func_rotatings over the centre of the boulder. Now we will make these sounds play at an appropriate time. Note that there is a more efficient method for switching between just these two sounds, but the method I show you now will extend to any number of different sounds and effects.

Create a mm:
  • Name ground_water
This will determine what gets triggered when the boulder moves from the ground into the water. Turn off SmartEdit and add:
  • rumble 0
  • splash 0
Create another mm:
  • Name water_off
Turn off SmartEdit and add:
  • splash 0
This will be used to turn all the effects off when the boulder exits via the water. Create a third mm:
  • Name off_ground
Turn off SmartEdit and add:
  • rumble 0
Select the mm called ?end_mm?. Turn off SmartEdit and add:
  • water_off 0
Select the path_corner called ?c?. Add:
  • Fire on pass ground_water
Select the path_corner called ?1?. Change:
  • Fire on pass path1_mm
Create a mm:
  • Name path1_mm
Turn off SmartEdit and add:
  • cycler_env7 0
  • off_ground 0
Now compile the map; the sounds should change between ground and water at the right time. Now let?s make a dust trail to follow the boulder. Create an env_shooter with:
  • Name shooter_dust
  • Moves with boulder
  • Number of shots 1
  • Delay between shots 0
  • Gib speed factor 20
  • Course variance 2
  • Shot lifetime 2
  • Fire on spawn (locus=shot) fade
  • Render mode Additive
  • FX amount 255
  • Render color 237 170 80
  • Model or sprite name sprites/ballsmoke.spr
  • Scale 0.5
  • Framerate 10
  • Behaviour of children Noclip
  • Blood color Don?t bleed
  • Material sound none
  • Shot size (X Y Z) 10 10 10
You must also set the angle-chooser (Yaw in Hammer 3.5) to ?Up?. Place the env_shooter centrally at the bottom of the boulder. This is where the dust will come from. Now create a mm with:
  • Name dust_mm
  • Trigger to send on
Turn off SmartEdit and add:
  • shooter_dust 0
  • dust_mm 0.1
Tick the flag:
  • Multi-threaded
Now select the mm called ?off_ground?, turn off SmartEdit and add:
  • dust_mm 0.1
This is how it works: when the mm ?dust_mm? is triggered, it will cause the env_shooter to emit a single puff of smoke. The mm will continue to loop, causing a new puff of smoke to appear every 0.1 seconds. The smoke will rise up and vanish (die) after 2 seconds. This means that there will be 20 puffs alive at any one time.

Compile the example map and observe the trail of smoke. It looks pretty good, but still not quite right. Let?s make it better. For this, we will make use of Spirit?s locus system. Locus is a very clever effects system, but quite hard to understand. It is very versatile. When you set the properties of the env_shooter, you may remember one called ?Fire on spawn (locus=shot)?. We gave this the value ?fade?. Now every time a new smoke puff is spawned, it will become the new ?locus? for this fade entity to act upon. We?re going to use this to make the puffs enlarge and fade out smoothly.

Create an env_render with:
  • Name fade
  • Render mode Additive
  • FX amount 0
  • Scale 3
  • Target to affect (LE) *locus
  • Fade time 2
Tick all and only the following flags:
  • No render FX
  • No render mode
  • No render color
The important key to notice is the ?Target to affect (LE)? key. This can be used to affect any normal enitity, but if you write ?*locus? instead, it will affect whatever the current locus entity is. Compile the map; you should see the dust trail expand and fade out.

The only problem is that the dust trail is still generated when the boulder is over water. This doesn?t make sense; instead, we will make a ripple effect for the water. But first let?s turn off the dust at the appropriate time. This is a lot simpler than you might expect: just select the mm ?dust_mm? and add:
  • Master rumble
The trick here is that, whenever the mm loops (which is every 0.1 seconds), it must check whether its master is active (or the loop will stop). Since the master is the func_rotating that we have already made to make the rumble sound, it follows that whenever the rumble sound is off, the dust trail will turn off too.

There?s just one more effect left to make ? the water ripples. This uses a much more sophisticated application of the locus system, together with a novel use of beam entities. To start with, I?d like you to create an env_sprite:
  • Name sprite1
  • Render mode Additive
  • FX amount 255
  • FX color 16 200 239
  • Sprite name sprites/test.spr
  • Scale 1
Set the angle (Yaw in Hammer 3.5) to be ?up?. Now make 3 copies (for a total of 4), and alter the numerical suffix on the name so that you have sprites called ?sprite1??.. ?sprite4?.

Now create an env_laser with:
  • Name laser
  • Start at (LP) calc1
  • Fire towards calc1
  • Meaning of fire towards Position (LP)
  • Start sprite sprite1
Tick the flag:
  • Start on
Now make 3 copies of this laser for a total of 4 lasers. Change the field "Start sprite" on each of the new lasers to give "sprite2"...."sprite4". You must also change both the fields that read ?calc1? on the first laser to read ?calc2?, ?calc3?, ?calc4? for the others. "calc1" must go with "sprite1" and so on.

You will then have 4 lasers associated with four different calcs. What?s a calc? Well it?s just a name, but here it will represent a truly wonderful entity called a locus_variable. We will use the locus_variable to calculate the position of the boulder, and then tell each beam successively to draw its start sprite at this position. This way, we can reuse the 4 beams endlessly.

Create a locus_variable with:
  • Name calc1
  • Position to record (LP) shooter_dust
Copy this 3 times for a total of 4 entities, and change the name of each accordingly: ?calc2?, ?calc3?, ?calc4?. Now create a mm with:
  • Name ripple_mm
  • Master splash
  • Trigger to send On
Tick the flag:
  • Multi-threaded
Turn off SmartEdit and add:
  • calc1 0
  • laser1_rend 0.1
  • calc2 0.3
  • laser2_rend 0.4
  • calc3 0.6
  • laser3_rend 0.7
  • calc4 0.9
  • laser4_rend 1
  • ripple_mm 1.2
The ?laserX_rend? entities don?t exist yet; we will use them soon to improve the ripple effect. This is how it works: when a ?calc? is triggered, it calculates the position of the boulder and causes (via the locus system) the env_beam to jump to this point. Compile the map and see the ripples following the boulder through the water. They are quite ugly at the moment.

I?d like to give a brief explanation of why it?s not possible to use just the same method for the ripples as we did for the dust trail. The crucial difference is this: the ripples must be axis-locked sprites, whereas the smoke balls were just ordinary sprites that turn to face you. Unfortunately, it is not possible to set the direction in which an axis-locked sprite faces when emitted from an env_shooter (and the default direction is wrong). The beams get around this problem by using the properties of the env_sprites themselves to render their start sprite.

Now let?s finish the ripple effect. Select all four env_sprites and make the change:
  • FX amount 0
This will make the sprites start out invisible. Now create an env_render with:
  • Name laser1_rend
  • Render mode Additive
  • FX Amount 255
  • FX color 16 200 239
  • Scale 0.01
  • Target to affect (LE) sprite1
  • Fade time 0
  • Trigger after fading laser1_rend2
This makes the sprite visible and very small. Make 3 copies (for a total of 4) of this entity, and change the names to be ?laser2_rend?, ?laser3_rend?, ?laser4_rend?. Change the target to ?sprite2?, ?sprite3?, ?sprite4? and change the trigger after fading to ?laser2_rend2?, ?laser3_rend2?, ?laser4_rend2?.

Now create another env_render and add:
  • Name laser1_rend2
  • Render mode Additive
  • FX Amount 0
  • FX color 16 200 239
  • Scale 1
  • Target to affect (LE) sprite1
  • Fade time 1
This expands and fades the sprite.

Again, make 3 copies (total of 4); change the names to be ?laser2_rend2?, ?laser3_rend2?, ?laser4_rend2?. Change the targets to "sprite2?, ?sprite3?, ?sprite4?.

Congratulations, you?re done! Compile the map and see the oh-so-beautiful and oh-so-clever ripple effects in all their glory. Now it?s your turn ? feel free to build on what you?ve learned from these tutorials, and please show me anything that you come up with. I?d love to see any maps that use these ideas. Good luck.




Addendum

There is an alternative method for making ripples that is much simpler. Credit goes to deathz0rz for making this; I don't like it as much but it does save 19 entities:

Delete all of the env_lasers, the env_sprites, the locus_variables and the env_renders (except the "fade" one, which is used for the dust effect).

Select the mm "ripple_mm" and remove all of the keys (except it's targetname). Add:
  • render_ripple 0
  • ripple_mm 0.4
Add an env_shockwave with:

  • Name render_ripple
  • Spritename sprites/shockwave.spr
  • Color 40 128 255
  • Opacity 128
  • Duration 8
  • Final Radius 140
  • Wave height 12
  • Distortion 50
  • Position shooter_dust
Tick the following flags:
  • Centered
  • Repeatable


Post ReplyView Topic
Discussion
There are not yet any comments for this article
Post ReplyView Topic