The Teleportation Manifesto
Back
The Goal
We will explain the following process
in Fractal Block World:
teleporting the player from chunk A to chunk B,
and then back again if there is a problem.
That catch is that when we start at chunk A,
the chunk B may not be in the active chunk tree yet.
Similarly, when we are at chunk B,
the chunk A may no longer be in the active chunk tree.
This is where the complication arises.
Step 1: Get Destination Path
The player is in chunk A.
Somehow get the block path and lbp (local block position) of
the chunk B we want to teleport to.
We can even work with an "offset" into the
target chunk B rather than an lbp.
Note that chunk B need not exist in the active chunk tree
at this time.
Step 2: Make the Engine Do Teleportation
Call the following functions:
-
ga_move_set_body_spirit()
-
ga_explore_while(lua_func, lua_win)
-
ga_tele(block_path, offset)
Note: these must be called within the SAME frame.
Changing our body mode to "spirit" will make us not
collide with the world.
It also makes us not render the WORLD.
It also makes teleportation faster because
we do not explore as much.
The basic reason why it is so fast is because the following:
If the chunk_id of the player is different from what it was
last frame, then the engine effectively sets the level
radius of each level to 0.
The player needs to be at a chunk for at least
two frames in order for the engine to create chunks
AROUND the viewer's chunk.
So, spirit mode is ideal for "drilling down"
into the chunk tree.
For the ga_explore_while function call,
we pass the (string) name of a Lua function that
functions as a "while loop". That is, the function
is called over and over again until it returns false.
However, this might not have the purpose that
you might expect, which we will explain later.
You can also optionally pass to the ga_explore_while function the
(string) name of a Lua window which is rendered
and gets input every frame until the while loop
function returns false.
The ga_tele function call actually causes
the teleportation to happen, which we explain
in the next step.
Step 3: Wait Until the Engine Finishes Teleportation
Wait.
Because you called ga_tele, the engine will
gradually modify the chunk tree to move the
player to the target block path
(moving the player to chunk B).
While this is happening, the engine renders
a loading screen and does not actually call
any Lua function of the package.
This may take a few seconds.
Step 4: Note That Now Your While Loop Function Is Being Called
The engine will finish the teleportation
and will begin to call Lua code again.
The player is now "in chunk B",
but they are in spirit mode, so they do not
really have a body exactly.
Because you had called the
ga_explore_while function, instead of calling
normal game functions, the engine will
call the "while loop" function you registered
when you called ga_explore_while.
It will also call the input and render functions
of the (optional) window whose name you passed to the
ga_explore_while function.
Step 5: Continue The While Loop Until You Decide If Chunk B Is Safe
At this point, the game will be in
the while loop.
What is the purpose of this loop?
Well, you need to make sure it is safe to
teleport to chunk B.
What if it is completely filled with
solid blocks? What if you wanted to teleport
to a waypoint, but somehow there are no
waypoints in chunk B?
You want to query chunk B
to see if it is suitable.
You might think you can just do this check
in a single frame.
Maybe you can.
However if the player's normal body size is
more than one block tall, there is an issue
that the player's destination would have them
be partially in chunk B but also partially spill over
into an adjacent chunk.
Since we are still in spirit mode,
there might not be any adjacent chunks to the
player's chunk that are loaded!
We must wait a few frames for the engine to
load nearby chunks for us to assess whether
it is really safe to end the teleportation
process.
Once we have enough information,
we need to return false from the while loop function.
Just before we do return false,
we need to do a few things.
Step 6: If Chunk B Is Safe, Finish
If we calculated that the destination
chunk B is OK, we need to do the following:
- Call
ga_move_set_body_spirit_off().
This will reset the player's body mode and dimensions
to what they were just before we called
ga_move_set_body_spirit().
- We could move the player slightly within the chunk.
Theoretically, we could teleport the player
to an adjacent chunk (on the same level)
with the
ga_tele_same_level function.
However, it might be best to keep things
simple and not do this.
We are now done!
Step 7: If Chunk B Is NOT Safe, Perhaps Teleport Back To Chunk A
Suppose we could not do Step 6 because
we calculated that the destination chunk is NOT ok.
We are now in trouble!!!
Theoretically you could do whatever you want,
like display an error screen to the player that says
"bummer dude" and then kill the player and take away
all their ammo.
However what you probably want to do is teleport
the player back to where they started before the
teleportation (chunk A).
To do this, first note that the player is
still in spirit mode.
You want to call the ga_tele function
but giving it the path and lbp of where the player
started. So, you needed to record this information
at the beginning. You could store it in a "global"
variable for example.
Next, you MIGHT want to do another
ga_explore_while
call. Indeed, you could have chosen not to
end the old while loop. In this case after the
engine teleports you back to your starting position,
the engine will continue calling this while loop.
However one could argue that doing any sort of
while loop for the back teleportation
(either part of the original while loop or a second one)
is not needed: the teleportation back SHOULD succeed.
Be careful about being in one while loop
and then setting up another while loop.
The system only has at most one explore while loop.
When you call ga_explore_while(lua_func, lua_win)
from the inside of one while loop, you must return
true from that while loop.
Here is an example, in a file which let's say is called
test.lua:
function p.while_loop_1()
if( SOMETHING_INTERESTING_HAPPENS ) then
local dummy_win = ""
ga_explore_while("test.while_loop_2", dummy_win)
--At this point, the engine thinks we are in "while_loop_2".
return true --Continue "the" while loop (while_loop_2 will be called next).
else
--Do stuff...
return true --Continue the while loop (while_loop_1 will be called again).
end
end
function p.while_loop_2()
if( COMMON_CASE ) then
return true --Continue this while_loop_2 function.
else
return false --End the while loop.
end
end
Step 8: If Teleporting Back To Chunk A Fails, Oh Snap!
If the teleportation BACK to chunk A does not succeed,
you need to decide what is the right thing to do.
Perhaps you should teleport the player to their
current respawn point.
We are now done!
Note: If you have an explore while loop
where the function is called many times,
you may consider having the function call
ga_render_skip_next_frame to pause rendering.
This is done for blue rings, and it speeds up
the teleportation by a factor of 3 or so.
However, since we are using the ga_tele function,
it does not really matter.