|
The first part of our
updatePlayerPhysics() function is an alignToVector() call which slowly
re-orients our player back to the upright position. The parameters ( 0, 1, 0,
2, 0.05) dictate that our character will be aligned full upright along the
Y-axis at a speed of 0.05, or very slowly. As the player tumbles through
portals, the character's alignment gets constantly re-arranged.
Anyone who's
played Portal should realize the developers' extra special attention to
detail in this regard, as the player and camera are constantly being adjusted
to keep the experience as intuitive as possible. In this demo, the player is
slowly rotated back to the upright position, which is something to take notice
of while tumbling through the puzzles in Portal.
The next part of the code is
where the interesting bits lay. There is a check for portal collision. If it
returns true, we will set our player collision type to static and search for
the other end of our portal.
Afterwards, we reposition our
player at the entrance of the opposing portal (or the exit of the portal we had
previously collided with).
Then we calculate our player's total velocity and
break it down into components relative to the portal we're coming out of -- by
multiplying the player's total velocity by the surface normals of the exit
portal.
This is what gives us the "waterslide" effect of entering in
one direction and exiting at the same speed but in an entirely new direction.
The rest of the code within
the first conditional helps create a smooth transition from one portal to the
other. The first part sets the character's orientation with respect to its
rotation upon entering the portal.
Afterward, the player is positioned out away
from the exit portal an appropriate amount to avoid choppiness or repeated
collision, once our player is returned to dynamic collision status.
Finally, a
capture, update, and render are completed to avoid any choppiness in the
visuals. Portal is especially slick in this regard, as it is virtually
seamless when it teleports the player character about.
The final section of the
updatePlayerPhysics() function is the flipside of the portal collision
conditional. All it does is stop the player upon a static collision or otherwise pull the
player down due to gravity.
The most interesting component of this is the
collision normal conditional, which only stops the character from falling if
they are on flat enough ground. Without that, the player can climb walls.
Portal is a landmark title. It's deceptively simple at a
glance, but in truth is the implementation is a highly polished and complex system,
which this article only begins to scratch the surface of. As stated above, the
story was entertaining and the rendering was nothing short of pure eye candy.
However,
without the mechanics Portal would not have been nearly as compelling.
The title really conveys the feeling of partaking in the empirical process of
groundbreaking science.
Just reading about something like this in a Michael
Crichton novel or watching a sci-fi flick with great CG effects would not have
had the same impact. Portal's mechanics distinguished it from other
games this year, and more importantly, they distinguished games as a whole from
the rest of contemporary media.
And now I'm going to grab a
piece of cake from my rehearsal dinner and I'm not lying! Until next time... do not step into the... ...
... ... it may cause permanent malfunctions such as death.
[To download the
associated demo and code sample for Portal Demystified, please click here.]
|
Knowing how stuff really works is glorious.
Thanks for choosing to publish this, Gamasutra editors!
I also honestly hope that people won't start to say that anyone could have made Portal, notably because it's not that hard to "find" the code behind the rule. This is something recurrent you hear from jaleous mouths, but the point is that one guy did it, you others didn't, and too bad for you.
I suggest one slight modification to the transformation of the player velocity : instead of changing the velocity direction to the normal of the exit portal, thus changing any movement at a right angle to the portal normal into forward motion, i propose projecting the velocity vector onto the basis vectors of the entrance portal. This gives back the players velocity relative to the entrance portal's orientation. This new velocity can then be multiplied with the basis vectors of the exit portal, resulting in the "correct" transition.
Might be a few more lines of code (and a bit more of a hassle with setting up the basis vectors), but allows far more possibilities when playing around with portals.
Things could even be taken further when using different sizes of portals (ie differing, non-normalized basis vectors for the entrance and exit portals), in combination with scaling of objects passing through a portal. For a very nice example of this, see Peter Molyneux's GDC 2005 "Room" demo ( http://www.youtube.com/watch?v=vGiPUx9Zgi0 ).
PS: Very looking forward to you next article!
The Room from GDC 2005 is really interesting. I did not get whether they included this mechanic in BW2???
Maybe the next installment of the column could come back to Portal and analyze that part as well.
If not, I'd like to see the next one be about Braid's time rewinding mechanics! Seems like Jon Blow has described how he did it enough times that it would be easy to reverse-engineer. But even when you know you could do it yourself if you had to, there's something about seeing someone else actually implement it and share the code - even if it's a non-refined implementation - that gets the creative juices flowing. Thanks for the articles Jeremy!