Games Demystified: Portal
February 21, 2019
February 21, 2019
Press Releases
February 21, 2019
Games Press

If you enjoy reading this site, you might also want to check out these UBM Tech sites:

# Games Demystified: Portal

August 26, 2008 Page 2 of 3

In order to break this down we will visit our old friend velocity, which is a vector. A vector is a magnitude coupled with a direction. Velocity is a vector whose magnitude is representative of speed. When the player collides with a portal we can extract the speed component of our velocity and redirect it to form a new velocity vector.

Now what term from the last column do we remember most of all? Those who remembered "surface normal" get a pat on the back along with a cookie. When a portal is applied to a wall, floor, or ramp in the game, the surface normal of the surface is communicated to the portal inhabiting it.

We then take the velocity we entered a portal with, and break it down into components. To do this we multiply by the surface normals of the exit portal.

In the end, Portal uses the traditional teleportation mechanic with a velocity and orientation change. Here's a simple code snippet, again written in Blitz3D, which is an excellent tool for quick prototyping like this.

;====== UPDATE PLAYER PHYSICS ======

Function updatePlayerPhysics()

player.playerClass = Object.playerClass( localPlayer )

AlignToVector( player\skeleton, 0, 1, 0, 2, 0.05 )

portalCollision = EntityCollided( player\skeleton, PORTALSTATIC )
If ( portalCollision <> 0 And portalOpen() )

EntityType( player\skeleton, STATIC )

For portal.portalClass = Each portalClass
If portal\entrance <> portalCollision Then Exit
Next

PositionEntity( player\skeleton, EntityX( portal\entrance ), EntityY( portal\entrance ), EntityZ( portal\entrance ) )

velocity# = Sqr( player\vX# ^ 2 + player\vY# ^ 2 + player\vZ# ^ 2 )

player\vX# = portal\nX# * velocity# * 1.2
player\vY# = portal\nY# * velocity# * 1.2
player\vZ# = portal\nZ# * velocity# * 1.2

RotateEntity( player\skeleton, VectorPitch( portal\nX#, portal\nY#, portal\nZ# ), EntityYaw( portal\entrance ) + 180 - ( EntityYaw( portalCollision ) - EntityYaw( player\skeleton ) ), 0 )
TranslateEntity( player\skeleton, 10 * portal\nX#, 10 * portal\nY#, 10 * portal\nZ# )

EntityType( player\skeleton, DYNAMIC )

CaptureWorld()
UpdateWorld()
RenderWorld( 1 )

Else

If ( EntityCollided( player\skeleton, STATIC ) )
player\vX# = 0
player\vZ# = 0
If ( CollisionNY( player\skeleton, 1 ) > 0.5 )
player\vY# = 0
MoveEntity( player\skeleton, player\mX#, 0, player\mZ# )
player\jumpTimer = MilliSecs()
EndIf
Else
player\vX# = player\vX#
player\vY# = player\vY# - 1
player\vZ# = player\vZ#
TranslateEntity( player\skeleton, player\vX#, player\vY#, player\vZ# )
MoveEntity( player\skeleton, player\mX#, 0, player\mZ# )
EndIf

If player\jumpTimer + 250 > MilliSecs() Then player\vY# = player\vY# + player\mY#

EndIf

End Function

;======

Page 2 of 3

### Related Jobs

Sucker Punch Productions — Bellevue, Washington, United States
[02.20.19]

Visual Effects (VFX) Artist
Wizards of the Coast — Renton, Washington, United States
[02.20.19]

Sr Software Engineer
Wizards of the Coast — Renton, Washington, United States
[02.20.19]