Gamasutra is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.

Games Demystified: Portal
June 2, 2020
Press Releases
June 2, 2020
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

Question — Remote, California, United States
[05.30.20]

Senior Gameplay Engineer (Unreal Engine, Work from Home)
Question — Remote, California, United States
[05.30.20]

Senior Network Engineer (Unreal Engine, Work from Home)
Remedy Entertainment — Espoo, Finland
[05.29.20]

Senior Programmer
Remedy Entertainment — Espoo, Finland
[05.29.20]

Senior Rigging Artist