There is no spoon


From Unreal Wiki, The Unreal Engine Documentation Site
Jump to: navigation, search

--Freefall –

Freefall is a mutator that turns off the gravity. I've given the players the ability to bounce off walls, or really any available surface that's near enough. Just face away from a wall and press space to push off.

I don't reccommend using this on a large open-air map, it would be quite deadly to be caught drifting slowly through the sky so anyone can get a potshot at you.

The idea is basically from the book Ender's Game by Orson Scott Card in which children train in a battle school in Earth's orbit fighting within student-headed armies with Lasertag-esque guns in zero gravity.

The concept gives first person shooter combat an extra spice. It can be tricky to get used to it, especially since I've removed any ability to move other then bouncing or rotating, but I've found with practice I could move around quite well.

There are a few things I want to play around with more. It would be nice to be able to play against AI controlled bots; they have no clue what to do and just sit there letting you shoot them. That's quite a challenge. It would also be great to be able to unlimit the player's yaw movement. I find it annoying in a zero-G environment that a player view can't push beyond a fully "up" or "down" position as in normal FPS play although solving that problem will be tricky. I imagine getting rid of that might not be popular with players so used to the concept of up and down. I might try to tweak how the bounce angle works to make it easier on the player to judge the way he goes; currently the acceleration is just using vector addition. I'm thinking of angling it a bit more away from the current direction of movement as some sort of correction scheme. Also it would be cool to have different weapons kick you back different rates when they're fired. Currently explosions will toss you around as will the shield glove if you use it against a wall.

I've probably done a no-no by subclassing PlayerController like it says NOT to do on theMaintaining Compatibility but I couldn't find a good way to get the massive changes in movement to work. I would appreciate any advice on the subject since I'm sure I'm probably going about some things in the wrong way. I almost wish I choose an easier mutator to implement for my first go because this was a real bear.

Please download the latest version (Version 101, 3/11/03) of the UMOD file here:

Just for fun's sake I'll include the source (old):


class MutZeroG extends Mutator;
var name FreefallState;
function bool MutatorIsAllowed() {
	return true;
function PreBeginPlay() {
  local class<Pawn> GamePawnClass< SEMI >
  log("MutZeroG:PreBeginPlay()", 'FF');
  if (Level.Game!=None) {
    Level.Game.default.PlayerControllerClassName = "Freefall.ZeroGxPlayer";
    Level.Game.PlayerControllerClass = class<PlayerController>(DynamicLoadObject("Freefall.ZeroGxPlayer", class'Class'));
    GamePawnClass = class<Pawn>( DynamicLoadObject( Level.Game.DefaultPlayerClassName, class'Class' ) );
    GamePawnClass.default.LandMovementState = FreefallState;
  log("MutZeroG:PreBeginPlay() done", 'FF');
function PostBeginPlay() {
  log("MutZeroG:PostBeginPlay()", 'FF');
	Level.DefaultGravity = 0.0;
  log("MutZeroG:PostBeginPlay() done", 'FF');
function bool CheckReplacement(Actor other, out byte bSuperRelevant) {
  local PhysicsVolume PV;
  PV = PhysicsVolume(other);
	if ( PV != None ) {
    PV.Gravity.Z = 0.0;
	return true;
  Description="No Gravity."


class ZeroGxPlayer extends xPlayer;
var float fBounceAcceleration;
var float fBounceDistance;
var float fBounceAntiDrag;
function EnterStartState() {
  local name NewState;
  log("ZeroGxPlayer:EnterStartState()", 'FF');
  NewState = 'PlayerFreefall';
  if (IsInState(NewState)) {
  else {
  log("ZeroGxPlayer:EnterStartState() done", 'FF');
state PlayerFreefall {
  ignores SeePlayer, HearNoise, Bump;
  function PlayerMove(float DeltaTime) {
    local vector view, endPoint, acc;
    //log("ZeroGxPlayer:PlayerMove()", 'FF');
    if (bPressedJump) {
      bPressedJump = false;
      view = Vector(Pawn.GetViewRotation());
      endPoint = Pawn.Location - (view * fBounceDistance);
      if (!Pawn.FastTrace(endPoint)) {
        acc = fBounceAcceleration * view;
      Pawn.Acceleration = acc;
    else {
      Pawn.Acceleration *= 0.9;
      if (VSize(Pawn.Acceleration) < VSize(Pawn.Velocity * fBounceAntiDrag)) {
        Pawn.Acceleration = Pawn.Velocity * fBounceAntiDrag;
    // Update rotation.
    UpdateRotation(DeltaTime, 2);
    if ( Role < ROLE_Authority ) { // then save this move and replicate it
      //log("ZeroGxPlayer:PlayMove ReplicateMove", 'FF');
      ReplicateMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
    else {
      //log("ZeroGxPlayer:PlayMove ProcessMove", 'FF');
      ProcessMove(DeltaTime, Pawn.Acceleration, DCLICK_None, rot(0,0,0));
    //log("ZeroGxPlayer:PlayMove done", 'FF');
  function BeginState() {
    log("ZeroGxPlayer:beginning Freefall state", 'FF');
    //Pawn.Velocity.Z = 1.0;
    log("ZeroGxPlayer:beginning Freefall state done", 'FF');
defaultproperties {
  fBounceAcceleration = 1500.0;
  fBounceDistance = 150.0;
  fBounceAntiDrag = 0.15;

–Code Notes –

I was originally using PHYS_Falling for the player state. Seemed to make since for a FreeFALL mutator. It was a bit tough since the physics engine wanted to set the player in PHYS_Walking whenever he touched the floor. Getting around that wasn't too difficult since I just could override the landed() method (I think that's the name) as well as change the physics back to PHYS_Falling if it was in anything else. One interesting thing to note about PHYS_Falling is that it completely ignores any acceleration in the Z direction. I imagine it only takes into account the effects of the gravity in the particular zone the pawn is in. After trying many different ways of getting around that limitation with little to no effect I decided to go with PHYS_Flying. The problem with that physics mode is that is automatically reduces the pawn's velocity over time kind of like you'd see with some manner of friction. The effect was very noticible and unacceptable. I believe the cheat-Flying mode that allows the user to stop on a dime has something to do with this effect. The code above that deals with fBounceAntiDrag eliminates this problem by keeping an acceleration vector on the pawn in the same direction as the pawn was traveling to counteract the drag. I came at using 0.15 for a multiplier just by trial and error.

→Comments →

Mecha: It's a good start. It really seems like it needs custom maps; I can do a bit of free-fall follies in DM-Oceanic, but static meshes tend to trip you up when you catch on them. It'd also be interesting to have a grapple or jetpack to boost yourself around with, since x-loc'ing doesn't change your momentum.

I sympathise with maintaining compatibility. I smashed my head against getting the pawns to register hitwalls(without changing the pawn/playercontroller) for a solid month before giving up.

Code notes
  • All you need to do to change the playercontroller is in PostBeginPlay. There's not much reason to use Pre, and could potentially cause problems on a network.
  • Replacing only the actual PlayerController does weird things to the bots. I've managed to shock them out of the standstill(which is probably because they're trying to move regularly), and if they touch the floor, they will get set to PHYS_Walking, and run around like normal–until they try to jump, where they stop again since PHYS_Falling is probably getting confused.
  • You shouldn't be replacing the default player controller or movement state–once the mutator is used, players(not bots!) will be unable to move until they quit and restart the game itself, even if switching gametypes and removing the mutator.

So get rid of the PreBeginPlay function, and your PostBeginPlay function should look something like this:

function PostBeginPlay() {
  log("MutZeroG:PostBeginPlay()", 'FF');
  Level.DefaultGravity = 0.0;
  log("MutZeroG:PostBeginPlay() done", 'FF');

and that will take care of any lingering effects.

Piglet: Really pretty cool, it's just ashame the bots dont like it much, oh well. By lasertag style guns do you mean simmilar to my Piglet/LaserTag mutator, i've tested them together and the work fairly well together (except I of course couldn't play with bots and we've only one computer fast enough for UT2003 so i couldnt play networked either :( ). Anyway a very nice idea, though it would probably be even cooler with some form of jetpacky thing (maybe replacement for shieldguns crappy secondary fire) and new maps.

SocratesJohnson: Hey thanks for the feedback! Mecha, I haven't had a chance to implement that code change, I have seen that problem requiring a restart like you said, that change should do the trick. I agree with the custom maps, although I don't really have any experience mapping. Please be my guest if anyone is interested!  :D I'm going to have to try and do something to get the bots to understand what's going on but I imagine it will be a bit tricky. Piglet, the guns in the novel would freze portions of the suit everyone was wearing, so a hit to the arm would disable that arm (BTW it's a fantastic book!). I'll have to try it with your mutator as well, I'm glad to hear they played nice! I think jetpacks might be a bit much but I like the idea of a grappling hook. Does a mutator exist for grappling hooks yet? If not I'd love to try and implement one, maybe replace the shieldgun's crappy secondary fire like you said. :) I think I have some time to work on this stuff tonight. Once again, thanks for the input!

Mecha: Captain Kewl has notes on building a grapple in his journal. It's not a terribly hard concept, but might take some practice. He also has some notes on correctly replicating client acceleration, which may answer the questions you posed to dma.

For teaching the bots what to do, you will probably need to change how they react to physics and hitwalls before actually changing their Orders function. Botpathing may also be a big factor in trying to get them to go places. I know that the author of Greed complained that invalid results for FindPathToward() in a bot will slow down the engine considerably; Epic is supposedly fixing this in the next patch.

SocratesJohnson: Implemented your suggested change and it works like a charm! Thanks! I'll create a new UMOD file tonight hopefully. I also started work on a grapple mutator, just laid some preliminary framework based on the TransLauncher and related code. Thanks for the pointers!

SocratesJohnson: Updated the UMOD file with version 101 a week ago but forgot to mention it here. :D The source on this page is still old, I'll update it when I get a chance.

Mysterial:FindPathToward() appears to be fixed since the 2217 beta patch.