Suspended Object Trap
Introduction
This tutorial explains the process of creating a trap consisting of a heavy object suspended by a dynamic rope which can then be triggered to fall with devastating effect. This is an advanced tutorial covering entity creation, parenting, I/O configuration, keyframe editing, and flag manipulation. Overall completion time is estimated at 45 minutes to 1 hour.
The Source Hammer editor does not allow a user to directly attach an object to a rope. However, there is a workaround. The basic idea involves parenting the end of a rope to a secondary entity. This secondary entity is then used in conjunction with a few physics entities that measure the movement of the secondary entity and translate its movements back to the rope. We'll also be creating a trigger that will break the rope when it gets damaged causing the previously suspended object to crash down! Sounds complicated but don't worry, it'll make sense once it's done. Let's get started!
Entity Creation
Create the following entities:
- A move_rope,
- a keyframe_rope,
- a phys_lengthconstraint,
- a env_spark (required due to this problem),
- a prop_physics_override or a func_physbox,
- a logic_measure_movement,
- a brush with the same or as-near-as-possible dimensions of the prop_physics_override / func_physbox, tied (Ctrl+T) to a func_button entity.
Entity Placement
Place the following entities or brushes:
- Place the move_rope to where you'd like to anchor the rope.
- Place the prop_physics_override / func_physbox to where you'd like the object to hang from.
- This tutorial will be using a prop instead of a physbox, but both can be used.
- Place the keyframe_rope to where you'd like to anchor the rope to the prop_physics_override or func_physbox.
- Hint: Just inside the surface of the prop or brush works best.
- Remember your physics: once in game, the center of gravity of the prop and the anchor point will interact and your prop will reach a balance point accordingly.
- Place the phys_lengthconstraint in the exact same location of the keyframe_rope and drag the lengthconstraint's small white circle to the center of the move_rope.
- Place the env_spark in the exact same location of the keyframe_rope.
- Place the logic_measure_movement off to the side for easy access.
- Place the func_button in the same location as the prop_physics_override / func_physbox.
Entity Properties Configuration
Naming
Naming your entities is arbitrary - you can choose what names you want. For the purposes of this tutorial the nomenclature is:
- move_rope : dynamic01_move_rope
- keyframe_rope : dynamic01_keyframe_rope
- phys_lengthconstraint : dynamic01_phys_lengthconstraint
- env_spark : dynamic01_env_spark
- prop_physics_override / func_physbox : dynamic01_prop_physics_override
- logic_measure_movement : dynamic01_logic_measuremovement
- func_button : dynamic01_func_button
As you can see, each entity has the prefix dynamicXX, followed by a descriptive suffix. This is a useful naming system when you have several dynamic systems and need to keep them separate.
Keyvalues for Rope Workaround
Here comes the tricky part where most errors are made. Set the keyvalues of the entities like this:
Class: move_rope | ||
Keyvalues | Comments | |
Name | dynamic01_move_rope | The name of the move_rope entity in this tutorial. |
Next KeyFrame | dynamic01_keyframe_rope | The name of the keyframe_rope entity in this tutorial. |
Slack | 0 | No slack. |
Class: keyframe_rope | ||
Keyvalues | Comments | |
Name | dynamic01_keyframe_rope | The name of the keyframe_rope entity in this tutorial. |
Slack | 0 | No slack here either. |
Class: env_spark | ||
Keyvalues | Comments | |
Name | dynamic01_env_spark | The name of the env_spark entity in this tutorial. |
Parent | dynamic01_prop_physics_override | Tie the spark effect to the prop_physics_override entity. |
Class: phys_lengthconstraint | ||
Keyvalues | Comments | |
Name | dynamic01_phys_lengthconstraint | The name of the phys_lengthconstraint entity in this tutorial. |
Entity1 | dynamic01_prop_physics_override | Tie the lengthconstraint to the prop_physics_override entity too. |
Class: logic_measure_movement | ||
Keyvalues | Comments | |
Name | dynamic01_logic_measuremovement | The name of the logic_measure_movement entity in this tutorial. |
Entity to Measure | dynamic01_env_spark | Tie the env_spark entity to the logic entity to measure the movement of the parented prop. |
Measure Reference | dynamic01_move_rope | Tie the move_rope entity to the logic entity as a measure refence. |
Entity to Move | dynamic01_keyframe_rope | Send along the measured movements of the env_spark relative to the move_rope. |
Movement Reference | dynamic01_move_rope | Tie the move_rope entity to the logic entity as a movement refence. |
Trap Trigger Creation
Time to change the func_button. First, texture it in inivs and then change its keyvalues like this:
Class: func_button | ||
Keyvalues | Comments | |
Name | dynamic01_func_button | The name of the func_button entity in this tutorial. |
Parent | dynamic01_prop_physics_override | Tie this entity to the prop_physics_override. |
Disable Receiving Shadows | Yes | Shadows are disabled otherwise the objects near the trigger have a shadow but no visible source of one. |
Move Direction (Pitch Yaw Roll) | 0 0 0 | To ensure the button will not move. |
Speed | 0 | To ensure the button will not move. |
Lip | 0 | To ensure the button will not move. |
Now change its flags like this:
Flag | ||||
Don't move | ||||
Toggle | ||||
Touch Activates | ||||
Damage Activates | Will fire outputs when takes damage. | |||
Use Activates | ||||
Starts locked | ||||
Sparks | ||||
...and finally give it the following outputs:
My output | Target entity | Target input | Parameter | Delay | Only once | Comments | ||
OnDamaged | dynamic05_logic_measure_movement | Disable | 0.00 | No | Disable the logic_measure_movement. | |||
OnDamaged | dynamic05_keyframe_rope1 | Break | 0.00 | No | OPTIONAL output, in multiplayer do not break, in singleplayer set to break. | |||
OnDamaged | dynamic05_phys_lengthconstraint | Break | 0.00 | No | Break phys_lengthconstraint. | |||
OnDamaged | dynamic05_env_spark | Kill | 0.00 | No | Kill the env_spark. | |||
OnDamaged | dynamic05_func_button | Kill | 0.00 | No | Kill the button itself to prevent any complications. | |||