Floor button: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
mNo edit summary
(Rewrite)
Line 2: Line 2:
|ru=Creating a button and door:ru
|ru=Creating a button and door:ru
}}
}}
__NOTOC__
This tutorial will show step-by-step how to create the '''floor button''', a test element commonly seen throughout the [[Portal]] test chambers. The floor button is activated by a [[Box dropper|weighted storage cube]] being placed on it, or when a player stands on it, and it can be used to trigger other test elements such as doors, platforms and elevators.


[[Image:Buttonanddoor6.jpg|right|thumb|350px|The final product.]]
== Creation ==
=== Step 1 ===
[[File:Floor button base.png|200px|thumb|right|The base brush]]
Create a <code>128w*128l*8h</code> [[brush]] and tie it to a <code>[[func_detail]]</code>. Texture the sides of the brush with <code>signage/hazard_orange_03b</code>, texture the top with <code>concrete/concrete_modular_floor001a</code>, and texture the bottom with <code>[[Tool_textures#nodraw|tools/toolsnodraw]]</code>.
{{clr}}


In this tutorial you will learn how to create a '''1500-Megawatt Aperture Science Heavy-Duty Supercolliding Superbutton''' which when stepped on or weighted down with a weighted storage cube will open a specified door.
=== Step 2 ===
[[File:Floor button overlays.png|200px|thumb|right|Overlays]]
Place four [[Hammer Overlay Tool|overlays]] with the texture <code>signage/overlay_button_accent</code> on top of the brush. Position them in the corners and rotate them so they look like in the picture on the right.
{{clr}}


== The door setup ==
=== Step 3 ===
First thing is to make the door which will open on activation of the button.
[[File:Floor button prop base.png|200px|thumb|right|Button base prop]]
Create a <code>[[prop_static]]</code> entity and set its ''World Model'' to <code>models/props/button_base_reference.mdl</code>. Position it in the middle on top of the base brush. Rotate it so that the sign with a box and an arrow on the rim of the button faces the way the player will enter the room.
{{clr}}


=== Door frame ===
=== Step 4 ===
Create a [[prop_static]] in the doorway. The ''World Model'' should be set to "<code>models/props/door_01_frame_reference.mdl</code>" or "<code>models/props/door_01_frame_wide_reference.mdl</code>" (either one works).
[[File:Floor button door.png|200px|thumb|right|The door brush]]
{{tip|Change the Mod Filter from "All Mods" to "portal" and select the top level "MDL Files" then in the Filter textbox at the bottom type "props\door" without the quotes.}}
Create <code>60w*60l*8h</code> 8-sided [[Primitive#Cylinder|cylinder]] textured with <code>tools/toolsnodraw</code> above the base brush, in the same place as the button base prop. Tie this brush to a <code>[[func_door]]</code> entity and set the following keyvalues:
 
{| class="standard-table sortable"
=== Doors ===
[[Image:Buttonanddoor1.jpg|right|thumb|How to align the <code>func_door</code>.]]
1. Create a [[prop_dynamic]] with the following settings:
::{| class=standard-table
!  Property Name || Value
|-
|-
| World Model || models/props/door_01_lftdoor_reference.mdl
! Property Name !! Value
|-
|-
| Name || door_left_model
| Name || floor_button_door
|}
Align it to the left, inside of the door frame.
 
2. Create a <code>56Lx8Wx104H</code> block brush with texture [[nodraw]] centered and inside the door model. Tie it to a [[func_door]] entity by selecting the object and using the menu option "Tie to Entity".  The func_door entity should have the following settings:
::{| class=standard-table
!  Property Name || Value
|-
|-
| Name || door_left
| Speed || 25
|-
| Speed || 250
|-
| Stop Sound || Doors.FullClose8
|-
| Delay before Reset || -1
|-
|-
| Lip || 12
| Delay Before Reset || -1
|-
|-
| Move Direction || (This will be different for which way your door is facing)
| Move Direction || {{vec3|90|0|0}}
|}
|}
Also make sure that you un-check ''Touch opens'' under ''Flags''.


3. Select Move Direction in the [[Hammer_Object_Properties_Dialog|Properties Dialog]]. When you tie a brush to func_door the direction the door is pointing at and the Move Direction are both initialized to <code>0 0 0</code>. Which means in the 2D top (x/y) view the func_door is pointing at and will move to the right as indicated in the the circular indicator of the Properties dialog. The only number we are concerned with for this door is the Yaw (middle number) which can be changed by dragging the pointer around in the Angle Compass [[image:Hammer_AngleCompass.png|24px]] or typing an angle into the combobox to the left of it. Common angles are 0, 90, 180, and 270 which moves the door right, up, left, or down respectively when viewed in the 2D top (x/y) view.
Next, go to the flags section and make sure that all flags are unchecked.
{{tip|Click the "Point At" button then in the 3D view click on a point in the direction you want the door to move toward.  A new Property named "angles" will appear and the 2D views will display a line indicating the direction of movement toward that point.  The angles for this line indicator can be edited manually by unselecting the [[Hammer_Object_Properties_Dialog#SmartEdit|SmartEdit Mode]] in the Properties dialog.}}
{{clr}}
{{note|You can also put a blocking damage if you don't want the player to get stuck inside it. Also, you can turn on Forced Closed for it to close even if the player tried to jam it open with a camera or cube.}}
 
[[Image:Buttonanddoor2.jpg|right|thumb|Final door.]]
=== Step 5 ===
4. Repeat steps 1-3 but change the following:
[[File:Floor button prop button.png|200px|thumb|right|The button prop]]
For the <code>prop_dynamic</code>:
[[File:Floor button origins.png|200px|thumb|right|Positioning of the button prop]]
::{| class=standard-table
Create a <code>[[prop_dynamic]]</code> entity. Set its ''World Model'' to <code>models/props/button_top_reference.mdl</code>, set its ''Pitch Yaw Roll (Y Z X)'' to the same as the button base prop's and set its ''Parent'' to <code>floor_button_door</code>. Finally, position it in the same place as the base prop, except the origin of the button prop should be 2 units above the origin of the base prop.
!  Property Name || Value
{{clr}}
|-
 
| World Model || models/props/door_01_rtdoor_reference.mdl
=== Step 6 ===
|-
[[File:Floor button triggers.png|200px|thumb|right|The trigger brushes]]
| Name || door_right_model
Create a <code>48w*48l*2h</code> brush textured with <code>[[Tool textures#trigger|tools/toolstrigger]]</code>. Tie this brush to a <code>[[trigger_multiple]]</code> entity and set its ''Name'' to <code>floor_button_trigger_player</code>. Go to its flags and make sure ''Clients'' is the only flag that is checked.
|}
 
And for the func_door:
::{| class=standard-table
!  Property Name || Value
|-
| Name || door_right
|-
| Move Direction || (The opposite of the move direction for the left door)
|}


5. Set the parent of <code>door_left_model</code> (the <code>prop_dynamic</code>) to "door_left". Also set the parent of <code>door_right_model</code> to "door_right".
Next create a <code>8w*8l*2h</code> 8-sided cylinder brush, also textured with <code>tools/toolstrigger</code> in the same place as the <code>floor_button_trigger_player</code> brush and tie it to a <code>trigger_multiple</code> entity. Set its ''Name'' to <code>floor_button_trigger_box</code> and make sure only the ''Physics Objects'' flag is checked. Next, set its ''Filter Name'' to <code>filter_boxes</code>. If you have created a [[box dropper]] in your level, you should already have this entity, but if you don't, create a new <code>[[filter_activator_name]]</code> entity with the ''Name'' <code>filter_boxes</code> and set its filter to the name of your weighted storage cube.


== The button ==
=== Models ===
[[Image:Buttonanddoor3.jpg|right|thumb|How to align the button models.]]
1. Create a <code>prop_static</code> with a ''World Model'' of "<code>models/props/button_base_reference.mdl</code>".
{{tip|Rotate the button base until the instruction segment [[File:Hammer PortalButtonInstruction.png|29px]] is facing the direction your player will approach it.}}
2. Create a <code>prop_dynamic</code> aligned on top of the <code>prop_static</code> with the following settings:
::{| class=standard-table
!  Property Name || Value
|-
| World Model || models/props/button_top_reference.mdl
|-
| Name || button_top_model
|}
{{tip|Align the bottom red/yellow line of this <code>prop_dynamic</code> with the bottom of the <code>prop_static</code> then move it up 1 unit to avoid getting stuck down.}}


=== Movement ===
Now add the following outputs to <code>floor_button_trigger_player</code>:
1. Next create a <code>58Wx58Lx9H</code> [[Primitive#Cylinder|cylinder brush]] with 8 sides and textured with [[Tool textures|nodraw]]. Move this brush right underneath your <code>prop_dynamic</code>. Tie the cylinder to a [[func_door]] with the following settings:
{| {{OutputsTable}}
::{| class=standard-table
!  Property Name || Value
|-
|-
| Name || button_top_door
| [[Image:Io11.png]] || OnEndTouchAll || floor_button_door || Close || &nbsp; || 0.00 || No
|-
|-
| Speed || 25
| [[Image:Io11.png]] || OnEndTouchAll || floor_button_trigger_box || Enable || &nbsp; || 0.00 || No
|-
|-
| Delay before Reset || -1
| [[Image:Io11.png]] || OnTrigger || floor_button_door || Open || &nbsp; || 0.00 || No
|-
|-
| Move Direction || 90 0 0 (or Down)
| [[Image:Io11.png]] || OnTrigger || floor_button_trigger_box || Disable || &nbsp; || 0.00 || No
|}
|}
Also make sure "Passable" is checked under ''Flags''.


2. Set the Parent of <code>button_top_model</code> to be "button_top_door".


=== Triggers ===
Next, add the following outputs to <code>floor_button_trigger_box</code>:
[[Image:Buttonanddoor4.jpg|right|thumb|The larger trigger_multiple.]]
{| {{OutputsTable}}
1. Create a <code>48Wx48Lx1H</code> block brush with [[Tool textures|trigger texture]] applied. Place it right on top of the <code>button_top_model</code>. Tie this brush to a [[trigger_multiple]] with the following settings:
::{| class=standard-table
!  Property Name || Value
|-
|-
| Name || button_trigger_player
| [[Image:Io11.png]] || OnEndTouchAll || floor_button_door || Close || &nbsp; || 0.00 || No
|}
We will set up the Output later. Also make sure to only have the flag: ''Clients'' set.
{{tip|Using a block brush is how Valve did it, but if you create a <code>60Wx60Lx1H</code> 8 sided cylinder brush the button will have a more consistent response from all angles.}}
[[Image:Buttonanddoor5.jpg|right|thumb|The smaller trigger_multiple.]]
2. Next create a <code>7Wx7Lx2H</code> cylinder brush with 8 sides and textured with trigger texture. Put this brush directly on top and in the center of the <code>button_top_model</code> and tie it to a <code>trigger_multiple</code> with the following settings:
::{| class=standard-table
!  Property Name || Value
|-
|-
| Name || button_trigger_box
| [[Image:Io11.png]] || OnEndTouchAll || floor_button_trigger_player || Enable || &nbsp; || 0.00 || No
|}
And only the following Flags are checked:
 
* Physics Objects
 
We will set up the Output later.
 
3. Create a [[filter_activator_name]] nearby your button with the following settings:
::{| class=standard-table
!  Property Name || Value
|-
|-
| Name || button_filter_boxes
| [[Image:Io11.png]] || OnTrigger || floor_button_door || Open || &nbsp; || 0.00 || No
|-
|-
| Filter Name || (The name your box entity has)
| [[Image:Io11.png]] || OnTrigger || floor_button_trigger_player || Disable || &nbsp; || 0.00 || No
|}
|}
{{note|If you don't have a box yet, then create a prop_pysics entity with models/props/metal_box.mdl}}
{{clr}}
4. Select your <code>button_trigger_box</code> trigger and set the Filter Name to "button_filter_boxes".


5. Create two [[ambient_generic]] entities and give one the following settings:
=== Step 7 ===
::{| class=standard-table
[[File:Floor button ambients.png|200px|thumb|right|The <code>ambient_generic</code> entities]]
! Property Name || Value
Create two <code>[[ambient_generic]]</code> entities near the button. Set the following keyvalues on the first one:
{| class="standard-table sortable"
|-
! Property Name !! Value
|-
|-
| Name || button_down
| Name || button_down
Line 142: Line 91:
| Sound Name || Portal.button_down
| Sound Name || Portal.button_down
|-
|-
| Source Entity Name || button_top_model
| SourceEntityName || floor_button_door
|}
|}
and the other with
 
::{| class=standard-table
Set the following keyvalues on the second <code>ambient_generic</code>:
! Property Name || Value
{| class="standard-table sortable"
|-
! Property Name !! Value
|-
|-
| Name || button_up
| Name || button_up
Line 152: Line 103:
| Sound Name || Portal.button_up
| Sound Name || Portal.button_up
|-
|-
| Source Entity Name || button_top_model
| SourceEntityName || floor_button_door
|}
|}


6. Now go back and select the cylinder <code>func_door</code> brush under the button, "button_top_door" and setup the Outputs as below:
 
::{| class=standard-table
Next, add the following outputs to <code>floor_button_door</code>:
!  || My Output || Target Entity || Target Input || Parameter || Delay || Only Once
{| {{OutputsTable}}
|-
| [[Image:Io11.png]] || OnClose || door_left || Close || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnClose || door_right || Close || <none> || 0.00 || No
|-
|-
| [[Image:Io11.png]] || OnClose || button_up || PlaySound || <none> || 0.00 || No
| [[Image:Io11.png]] || OnClose || button_up || PlaySound || &nbsp; || 0.00 || No
|-
|-
| [[Image:Io11.png]] || OnOpen || door_left || Open || <none> || 0.00 || No
| [[Image:Io11.png]] || OnOpen || button_down || PlaySound || &nbsp; || 0.00 || No
|-
| [[Image:Io11.png]] || OnOpen || door_right || Open || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnOpen || button_down || PlaySound || <none> || 0.00 || No
|}
|}
{{clr}}


7. Select the larger <code>trigger_multiple</code>, "button_trigger_player" and setup the Output as below:
=== Step 8 ===
::{| class=standard-table
[[File:Floor button light.png|200px|thumb|right|The <code>light</code> entity]]
!  || My Output || Target Entity || Target Input || Parameter || Delay || Only Once
Create a <code>[[light]]</code> entity in the middle of the base prop, 8 units above the base brush. Set the following keyvalues on it:
{| class="standard-table sortable"
|-
|-
| [[Image:Io11.png]] || OnEndTouchAll || button_trigger_box || Enable || <none> || 0.00 || No
! Property Name !! Value
|-
| [[Image:Io11.png]] || OnEndTouchAll || button_top_door || Close || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnStartTouch || button_trigger_box || Disable || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnStartTouch || button_top_door || Open || <none> || 0.00 || No
|}
8. Select the smaller, cylinder <code>trigger_multiple</code>, "button_trigger_box" and setup the Output as below:
::{| class=standard-table
!   || My Output || Target Entity || Target Input || Parameter || Delay || Only Once
|-
| [[Image:Io11.png]] || OnEndTouchAll || button_trigger_player || Enable || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnEndTouchAll || button_top_door || Close || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnStartTouch || button_trigger_player || Disable || <none> || 0.00 || No
|-
| [[Image:Io11.png]] || OnStartTouch || button_top_door || Open || <none> || 0.00 || No
|}
[[Image:Buttonanddoor6.jpg|right|thumb|The final product.]]
9. Finally, create a [[light]] entity underneath the top of the button but still inside the base. Give it the following properties:
::{| class=standard-table
Property Name || Value
|-
|-
| Brightness || 251 159 57 30
| Brightness || 251 159 57 30
Line 205: Line 127:
| BrightnessHDR || 251 159 57 20
| BrightnessHDR || 251 159 57 20
|}
|}
{{Note|The light should be '''2''' Units above the original base ground that the main base Button model is on, in order to cast correctly.}}


You have now created a button which will open a door by a player standing on the button or a box weighing it down. Only those two things will work on it.
 
The button is now finished and ready to be implemented in a map.
{{clr}}
{{clr}}


==Making a hole in the wall to fit the door==
== Implementation ==
While this step is optional, and your door may be fully functional without it, your map will look especially awkward if you just have a door in the middle of a space, and even more so if you don't have walls around it to block the player before opening the door.  This step is simple enough, so it is recommended that you try it out by following the next tutorial on [[Portal_Door_Frame_Using_the_Clipping_Tool|Creating a door frame using the Clipping Tool]].
[[File:Floor button ingame.png|300px|thumb|right|The floor button in-game]]
=== Step 1 ===
Place the button where it should be in the map.


Usable prefab of the door frame: [[Creating a button and door/DoorFrame.vmf]].
=== Step 2 ===
 
Add the outputs that should fire when the button is activated. The outputs that should be fired when the button is pressed should be the ''OnOpen'' output on <code>floor_button_door</code>, and the ''OnClose'' output when the button is released.
== The theory ==
{{clr}}
This is the most basic button and door setup. You can also have the triggers turn off or on other things in the map, have them trigger a [[logic_choreographed_scene]] or just about anything. For the Portal feel you can have them trigger [[Creating indicator lights|Indicator Lights]] based on the button up or down status.
 
If you do decide to use [[Creating indicator lights|Indicator Lights]], then make sure to have the [[func_door]] (The Nodraw cylinder) Set Outputs when it closes, and opens. When it opens, set the texture Index to 1, and when it closes, set the texture index to 0, via a [[env_texturetoggle]] that controls the lights.
 
== See also ==
* [[Portal Level Creation]]


== External links ==
== See Also ==
* [http://forums.thinkingwithportals.com/downloads.php?view=detail&df_id=186 Example map] Example map using this tutorial. VMF included.
* [[Button (Portal 2)]] - Portal 2 variant
* [[Creating a switch]] - Pedestal button


[[Category:Level Design Tutorials]]
[[Category:Level Design Tutorials]]
[[Category:Portal]]
[[Category:Portal]]

Revision as of 10:50, 13 July 2018

Template:Otherlang2

This tutorial will show step-by-step how to create the floor button, a test element commonly seen throughout the Portal test chambers. The floor button is activated by a weighted storage cube being placed on it, or when a player stands on it, and it can be used to trigger other test elements such as doors, platforms and elevators.

Creation

Step 1

The base brush

Create a 128w*128l*8h brush and tie it to a func_detail. Texture the sides of the brush with signage/hazard_orange_03b, texture the top with concrete/concrete_modular_floor001a, and texture the bottom with tools/toolsnodraw.

Step 2

Overlays

Place four overlays with the texture signage/overlay_button_accent on top of the brush. Position them in the corners and rotate them so they look like in the picture on the right.

Step 3

Button base prop

Create a prop_static entity and set its World Model to models/props/button_base_reference.mdl. Position it in the middle on top of the base brush. Rotate it so that the sign with a box and an arrow on the rim of the button faces the way the player will enter the room.

Step 4

The door brush

Create 60w*60l*8h 8-sided cylinder textured with tools/toolsnodraw above the base brush, in the same place as the button base prop. Tie this brush to a func_door entity and set the following keyvalues:

Property Name Value
Name floor_button_door
Speed 25
Delay Before Reset -1
Move Direction 90 0 0

Next, go to the flags section and make sure that all flags are unchecked.

Step 5

The button prop
Positioning of the button prop

Create a prop_dynamic entity. Set its World Model to models/props/button_top_reference.mdl, set its Pitch Yaw Roll (Y Z X) to the same as the button base prop's and set its Parent to floor_button_door. Finally, position it in the same place as the base prop, except the origin of the button prop should be 2 units above the origin of the base prop.

Step 6

The trigger brushes

Create a 48w*48l*2h brush textured with tools/toolstrigger. Tie this brush to a trigger_multiple entity and set its Name to floor_button_trigger_player. Go to its flags and make sure Clients is the only flag that is checked.


Next create a 8w*8l*2h 8-sided cylinder brush, also textured with tools/toolstrigger in the same place as the floor_button_trigger_player brush and tie it to a trigger_multiple entity. Set its Name to floor_button_trigger_box and make sure only the Physics Objects flag is checked. Next, set its Filter Name to filter_boxes. If you have created a box dropper in your level, you should already have this entity, but if you don't, create a new filter_activator_name entity with the Name filter_boxes and set its filter to the name of your weighted storage cube.


Now add the following outputs to floor_button_trigger_player:

  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnEndTouchAll floor_button_door Close   0.00 No
Io11.png OnEndTouchAll floor_button_trigger_box Enable   0.00 No
Io11.png OnTrigger floor_button_door Open   0.00 No
Io11.png OnTrigger floor_button_trigger_box Disable   0.00 No


Next, add the following outputs to floor_button_trigger_box:

  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnEndTouchAll floor_button_door Close   0.00 No
Io11.png OnEndTouchAll floor_button_trigger_player Enable   0.00 No
Io11.png OnTrigger floor_button_door Open   0.00 No
Io11.png OnTrigger floor_button_trigger_player Disable   0.00 No

Step 7

The ambient_generic entities

Create two ambient_generic entities near the button. Set the following keyvalues on the first one:

Property Name Value
Name button_down
Sound Name Portal.button_down
SourceEntityName floor_button_door

Set the following keyvalues on the second ambient_generic:

Property Name Value
Name button_up
Sound Name Portal.button_up
SourceEntityName floor_button_door


Next, add the following outputs to floor_button_door:

  My Output Target Entity Target Input Parameter Delay Only Once
Io11.png OnClose button_up PlaySound   0.00 No
Io11.png OnOpen button_down PlaySound   0.00 No

Step 8

The light entity

Create a light entity in the middle of the base prop, 8 units above the base brush. Set the following keyvalues on it:

Property Name Value
Brightness 251 159 57 30
BrightnessHDR 251 159 57 20


The button is now finished and ready to be implemented in a map.

Implementation

The floor button in-game

Step 1

Place the button where it should be in the map.

Step 2

Add the outputs that should fire when the button is activated. The outputs that should be fired when the button is pressed should be the OnOpen output on floor_button_door, and the OnClose output when the button is released.

See Also