This article's documentation is for anything that uses the Source engine. Click here for more information.

Func rotating: Difference between revisions

From Valve Developer Community
Jump to navigation Jump to search
 
(48 intermediate revisions by 26 users not shown)
Line 1: Line 1:
{{base brush|func_rotating}}  
{{tabs|func_rotating|goldsrc=1|source=1|main=source}}
{{CD|CFuncRotating|file1=1}}
{{this is a|brush entity|name=func_rotating}}


==Entity description==
{{bug|Always fire the <code>Stop</code> input on this entity before killing it, otherwise looping sounds may continue playing forever!}}
It is used to create rotating brushes. Compare with [[func_door_rotating]].
{{bug|The maximum degrees this angle can turn is 360000 degrees, at which it stops rotating. Periodically fire the <code>Stop/Start</code> inputs as a workaround}}
{{workaround|Both bugs mentioned above can be fixed in [[VScript]] supported titles with the following [[Entity Scripts|entity script]].
{{ExpandBox|<source lang=js>
// save this to a new file in your /scripts/vscripts/ folder and set the `vscripts` keyvalue on the entity to the filename.
function OnPostSpawn()
{
    // m_angRotation will fail to hit 360,000.0, reset it a bit earlier
    local maxangle = 359000.0
    local xyz = array(3, 0.0)


{{note|This entity behaves strangely in most games. If you parent an entity to a func_rotating sometimes it will not work.}}
    self.ValidateScriptScope()
    local scope = self.GetScriptScope()
 
    // if using your own think function, copy the contents from this function to yours and delete this.
    scope.RotateFixThink <- function() {
 
        for (local i = 0; i < 3; i++)
        {
            xyz[i] = NetProps.GetPropFloat(self, format("m_angRotation[%d]", i))
 
            if ( xyz[i] == 0.0 || xyz[i] < maxangle) continue
 
            xyz[i] %= 360.0
            self.SetLocalAngles(QAngle(xyz[0], xyz[1], xyz[2]))
            break
        }
        return -1
    }
    // remove this if setting your own think separately.
    AddThinkToEnt(self, "RotateFixThink")
 
    scope.noise <- NetProps.GetPropString(self, "m_NoiseRunning")
 
    // see OnDestroy callback on the script functions page.
    scope.setdelegate({}.setdelegate({
        id      = self.GetScriptId()
        index    = self.entindex()
        parent  = scope.getdelegate()
        _delslot = function(k)
        {
            if (k == id)
            {
                local ent = EntIndexToHScript(index)
                StopAmbientSoundOn(ent.GetScriptScope().noise, ent)
            }
            delete parent[k];
        }
    }))
}
</source>}}
}}
{{toc-right}}
 
==Entity Description==
[[File:Hammer Axis visual guide.png|thumb|300px|A visual guide showing the axis in each viewport (Click to enlarge)]]
It is used to create rotating brushes. Compare with {{ent|func_door_rotating}}.
 
===Friction Explanation & Formula===
Fan friction may be a little tricky to understand. Below is an explanation of how it works.
 
If [[Hammer]] has the fanfriction key set to 0 and the game spawns the entity, code sets it to 1 so it doesn't divide by zero.
 
Friction = fanfriction key / 100
 
-----------------------------------------------------------------------------------------
 
{| class="wikitable"
|-
! Key !! Hammer Value !! Code Value
|-
| fanfriction|| 100|| 1
|-
| fanfriction|| 50|| 0.5
|-
| fanfriction|| 0/1|| 0.01
|}
 
-----------------------------------------------------------------------------------------
 
''Note: These formulas get called every 0.1 seconds.''
 
'''Purpose:'''
Think function: Accelerates a <code>func_rotating</code> to a higher angular velocity.
new_speed = fabs( current_speed ) + 0.2 * maxspeed * fanfriction;
 
'''Purpose:'''
Decelerates the rotator from a higher speed to a lower one.
new_speed = fabs( current_speed ) - 0.1 * maxspeed * fanfriction;
 
-----------------------------------------------------------------------------------------
 
'''Conclusion:'''
* A higher <code>fanfriction</code> value will accelerate/deaccelerate faster.
* A lower <code>fanfriction</code> value will accelerate/deaccelerate slower.


== Keyvalues ==
== Keyvalues ==
{{KV|Max Rotation Speed|integer|The maximum rotation speed of the brushes, in degrees per second. Seems to be limited to a number around 2000, after which the rotational speed ignores the last remaining digits (eg: 2500=250).}}
{{Brush rendering note}}
{{KV|Friction (0 - 100%)|integer|The amount of rotational friction. Value must be between 0 and 100 %. The lower the friction is, the slower it spins up and spins down. This is the opposite of how it would work in real life.}}
 
{{KV|Rotating sound WAV|sound|Sound to play while rotating.}}
{{KV Targetname}}
{{KV|Volume (10 {{=}} loudest)|integer|The volume of the rotation sound.}}
{{KV|Max Rotation Speed|intn=maxspeed|float|The maximum rotation speed of the brushes, in degrees per second. Seems to be limited to a number around 2000, after which the rotational speed ignores the last remaining digits (e.g., 2500{{=}}250).}}
{{KV|Minimum Light Level|string|The minimum level of ambient light that hits this brush.}}
{{KV|Friction (0 - 100%)|intn=fanfriction|float|The amount of rotational friction. Value must be between 0 and 100 %. The lower the friction is, the slower it spins up and spins down. This is the opposite of how it would work in real life.}}
{{KV|Blocking Damage|integer|Damage done to any entity that blocks the rotation, per frame.}}
:{{note|Defaults to 100% if set to zero.}}
{{KV|Solid Type|choices|Brush solidity type}}
{{KV|Rotating sound WAV|intn=message|sound|Sound to play while rotating.{{bug|Always fire the <code>Stop</code> input on this entity before killing it, otherwise looping sounds may continue playing forever!}}}}
{{KV|Volume (10 {{=}} loudest)|intn=volume|integer|The volume of the rotation sound.}}
{{KV|Blocking Damage|intn=dmg|integer|Damage done to any entity that blocks the rotation, per frame.}}
{{KV|Solid Type|intn=solidbsp|bool|Brush solidity type}}
:* 0 : VPhysics
:* 0 : VPhysics
:* 1 : BSP
:* 1 : BSP
{{KV Targetname}}
{{KV Parentname}}
{{KV Origin}}
{{KV Angles}}
{{KV RenderFields}}
{{KV Shadow}}
{{KV Reflection}}


== Flags ==
== Flags ==
* 1 : Start ON
{{fl|1|Start ON}}
* 2 : Reverse Direction
{{fl|2|Reverse Direction}}
* 4 : X Axis
{{fl|4|X Axis|If enabled, the entity will spin at the X Axis.}}
* 8 : Y Axis
{{fl|8|Y Axis|If enabled, the entity spin at the Y Axis.}}
* 16 : Acc/Dcc - If enabled, the entity will accelerate and decelerate from maximum speed based on the Friction property.
{{fl|16|Acc/Dcc|If enabled, the entity will accelerate and decelerate from maximum speed based on the Friction property.}}
* 32 : Fan Pain - With this enabled, the player will be hurt when coming into contact with the brush.
{{fl|16|Client-side Rotation|Intended to simulate the entity entirely on the client. {{note|{{tf2}} This entity did not rotate visually until the 19/12/2018 patch, due to bugged implementation of the <code>Client-side rotation</code> spawnflag.}}|only={{Tf2}}}}
* 64 : Not Solid
{{fl|32|Fan Pain|With this enabled, the player will be hurt when coming into contact with the brush.}}
* 128 : Small Sound Radius
{{fl|64|Not Solid}}
* 256 : Medium Sound Radius
{{fl|128|Small Sound Radius|Use [[Soundscripts#SoundLevel|ATTN_IDLE]] (60dB).}}
* 512 : Large Sound Radius
{{fl|256|Medium Sound Radius|Use [[Soundscripts#SoundLevel|ATTN_STATIC]] (~67dB).}}
* 1024 : Client-side Animation {{L4D add}}
{{fl|512|Large Sound Radius|Use [[Soundscripts#SoundLevel|ATTN_NORM]] (~75dB). If the other two options are unset, this is used.}}
{{fl|1024|Client-side Animation|since={{l4d}}}}


== Inputs ==
== Inputs ==
{{IO|SetSpeed|Set the speed as a ratio of the specified Max Rotation Speed, where 0 is stopped and 1 is the Max Rotation Speed. Negative values rotate backwards.|param=integer}}
{{I|SetSpeed|param=float|Set the speed as a ratio of the specified Max Rotation Speed, where 0 is stopped and 1 is the Max Rotation Speed. Negative values rotate backwards.<br>If you want to set by degrees per second instead, first fire "Addoutput - Maxspeed X" to this entity, followed by "Start" with a delay of 0.01 seconds.}}
{{IO|Start|Start the rotator rotating.}}
{{I|Start|Start the rotator rotating.}}
{{IO|Stop|Stop the rotator from rotating.}}
{{I|Stop|Stop the rotator from rotating.}}
{{IO|StopAtStartPos|<code>Stop</code> the rotator from rotating when it gets around to the start position again (on its rotation axis).}}
{{I|StopAtStartPos|<code>Stop</code> the rotator from rotating when it gets around to the start position again (on its rotation axis). If the speed is greater than 100 degrees per second, slows down to 100 degrees per second and spins for one extra revolution before stopping.}}
{{IO|StartForward|Start the rotator rotating forward at maximum speed.}}
{{I|StartForward|Start the rotator rotating forward at maximum speed.}}
{{IO|StartBackward|Start the rotator rotating backward at maximum speed.}}
{{I|StartBackward|Start the rotator rotating backward at maximum speed.}}
{{IO|Toggle|Toggle the rotator between rotating and not rotating.}}
{{I|Toggle|Toggle the rotator between rotating and not rotating.}}
{{IO|Reverse|Reverse the direction of rotation of the rotator, preserving the current speed.}}
{{I|Reverse|Reverse the direction of rotation of the rotator, preserving the current speed.}}
{{IO|SnapToStartPos|Snap to the initial position and stop moving.|since=l4d2}}
{{I|SnapToStartPos|Snap to the initial position and stop moving.|since=l4d2}}
{{IO|GetSpeed|Causes the func_rotating to fire its <code>OnGetSpeed</code> output with its current speed.|since=p2}}
{{I|GetSpeed|Causes the <code>func_rotating</code> to fire its <code>OnGetSpeed</code> output with its current speed.|since=p2}}
{{I Targetname}}
{{I Parentname}}
{{I RenderFields}}
{{I Shadow}}
{{I Reflection}}


== Outputs ==
== Outputs ==
{{IO|OnGetSpeed|Fired when the <code>GetSpeed</code> input is called.  The current speed of the func_rotating is passed with this output.|param=integer|since=p2}}
{{O|OnGetSpeed|Fired when the <code>GetSpeed</code> input is called.  The current speed of the <code>func_rotating</code> is passed with this output.|param=integer|since=p2}}
{{O Targetname}}
 
== See also ==
*{{ent|func_door_rotating}}
*{{ent|func_platrot}}
*{{ent|func_rot_button}}
*{{ent|momentary_rot_button}}

Latest revision as of 18:42, 6 May 2025

C++ Class hierarchy
CFuncRotating
CBaseEntity
C++ bmodels.cpp

func_rotating is a brush entity available in all Source Source games.

Icon-Bug.pngBug:Always fire the Stop input on this entity before killing it, otherwise looping sounds may continue playing forever!  [todo tested in ?]
Icon-Bug.pngBug:The maximum degrees this angle can turn is 360000 degrees, at which it stops rotating. Periodically fire the Stop/Start inputs as a workaround  [todo tested in ?]
PlacementTip.pngWorkaround:Both bugs mentioned above can be fixed in VScript supported titles with the following entity script.

// save this to a new file in your /scripts/vscripts/ folder and set the `vscripts` keyvalue on the entity to the filename.
function OnPostSpawn()
{
    // m_angRotation will fail to hit 360,000.0, reset it a bit earlier
    local maxangle = 359000.0
    local xyz = array(3, 0.0)

    self.ValidateScriptScope()
    local scope = self.GetScriptScope()

    // if using your own think function, copy the contents from this function to yours and delete this.
    scope.RotateFixThink <- function() {

        for (local i = 0; i < 3; i++)
        {
            xyz[i] = NetProps.GetPropFloat(self, format("m_angRotation[%d]", i))

            if ( xyz[i] == 0.0 || xyz[i] < maxangle) continue

            xyz[i] %= 360.0
            self.SetLocalAngles(QAngle(xyz[0], xyz[1], xyz[2]))
            break
        }
        return -1
    }
    // remove this if setting your own think separately.
    AddThinkToEnt(self, "RotateFixThink")

    scope.noise <- NetProps.GetPropString(self, "m_NoiseRunning")

    // see OnDestroy callback on the script functions page.
    scope.setdelegate({}.setdelegate({
        id       = self.GetScriptId()
        index    = self.entindex()
        parent   = scope.getdelegate()
        _delslot = function(k)
        {
            if (k == id)
            {
                local ent = EntIndexToHScript(index)
                StopAmbientSoundOn(ent.GetScriptScope().noise, ent)
            }
            delete parent[k];
        }
    }))
}

Entity Description

A visual guide showing the axis in each viewport (Click to enlarge)

It is used to create rotating brushes. Compare with func_door_rotating.

Friction Explanation & Formula

Fan friction may be a little tricky to understand. Below is an explanation of how it works.

If Hammer has the fanfriction key set to 0 and the game spawns the entity, code sets it to 1 so it doesn't divide by zero.

Friction = fanfriction key / 100


Key Hammer Value Code Value
fanfriction 100 1
fanfriction 50 0.5
fanfriction 0/1 0.01

Note: These formulas get called every 0.1 seconds.

Purpose: Think function: Accelerates a func_rotating to a higher angular velocity.

new_speed = fabs( current_speed ) + 0.2 * maxspeed * fanfriction;

Purpose: Decelerates the rotator from a higher speed to a lower one.

new_speed = fabs( current_speed ) - 0.1 * maxspeed * fanfriction;

Conclusion:

  • A higher fanfriction value will accelerate/deaccelerate faster.
  • A lower fanfriction value will accelerate/deaccelerate slower.

Keyvalues

Note.pngNote:For Keyvalues and Inputs affecting brush rendering, see Brush entity/Rendering related keyvalues and inputs


Name (targetname) <string>[ Edit ]
The name that other entities refer to this entity by, via Inputs/Outputs or other keyvalues (e.g. parentname or target).
Also displayed in Hammer's 2D views and Entity Report.
See also:  Generic Keyvalues, Inputs and Outputs available to all entities

Max Rotation Speed (maxspeed) <float>
The maximum rotation speed of the brushes, in degrees per second. Seems to be limited to a number around 2000, after which the rotational speed ignores the last remaining digits (e.g., 2500=250).
Friction (0 - 100%) (fanfriction) <float>
The amount of rotational friction. Value must be between 0 and 100 %. The lower the friction is, the slower it spins up and spins down. This is the opposite of how it would work in real life.
Note.pngNote:Defaults to 100% if set to zero.
Rotating sound WAV (message) <sound>
Sound to play while rotating.
Icon-Bug.pngBug:Always fire the Stop input on this entity before killing it, otherwise looping sounds may continue playing forever!  [todo tested in ?]
Volume (10 = loudest) (volume) <integer>
The volume of the rotation sound.
Blocking Damage (dmg) <integer>
Damage done to any entity that blocks the rotation, per frame.
Solid Type (solidbsp) <boolean>
Brush solidity type
  • 0 : VPhysics
  • 1 : BSP

Flags

Start ON : [1]
Reverse Direction : [2]
X Axis : [4]
If enabled, the entity will spin at the X Axis.
Y Axis : [8]
If enabled, the entity spin at the Y Axis.
Acc/Dcc : [16]
If enabled, the entity will accelerate and decelerate from maximum speed based on the Friction property.
Client-side Rotation : [16] (only in Team Fortress 2)
Intended to simulate the entity entirely on the client.
Note.pngNote:Team Fortress 2 This entity did not rotate visually until the 19/12/2018 patch, due to bugged implementation of the Client-side rotation spawnflag.
Fan Pain : [32]
With this enabled, the player will be hurt when coming into contact with the brush.
Not Solid : [64]
Small Sound Radius : [128]
Use ATTN_IDLE (60dB).
Medium Sound Radius : [256]
Use ATTN_STATIC (~67dB).
Large Sound Radius : [512]
Use ATTN_NORM (~75dB). If the other two options are unset, this is used.
Client-side Animation : [1024] (in all games since Left 4 Dead)

Inputs

SetSpeed <floatRedirectInput/float>
Set the speed as a ratio of the specified Max Rotation Speed, where 0 is stopped and 1 is the Max Rotation Speed. Negative values rotate backwards.
If you want to set by degrees per second instead, first fire "Addoutput - Maxspeed X" to this entity, followed by "Start" with a delay of 0.01 seconds.
Start
Start the rotator rotating.
Stop
Stop the rotator from rotating.
StopAtStartPos
Stop the rotator from rotating when it gets around to the start position again (on its rotation axis). If the speed is greater than 100 degrees per second, slows down to 100 degrees per second and spins for one extra revolution before stopping.
StartForward
Start the rotator rotating forward at maximum speed.
StartBackward
Start the rotator rotating backward at maximum speed.
Toggle
Toggle the rotator between rotating and not rotating.
Reverse
Reverse the direction of rotation of the rotator, preserving the current speed.
SnapToStartPos  (in all games since Left 4 Dead 2)
Snap to the initial position and stop moving.
GetSpeed  (in all games since Portal 2)
Causes the func_rotating to fire its OnGetSpeed output with its current speed.

Outputs

OnGetSpeed <integerRedirectOutput/integer> (in all games since Portal 2)
Fired when the GetSpeed input is called. The current speed of the func_rotating is passed with this output.

See also