Custom Pink Rings Demo
Back
The Goal
Recall how "pink rings" work in the xar package of Fractal Block World.
When you use pink rings you will grow until you reach a chunk
containing a pink sphere.
That is, we consider the chunk containing the pink rings,
and we find its finest ancestor chunk
which contains pink spheres.
The point of this guide is to explain how to make your own
pink rings, without relying on any special hardcoded
functionality of the engine.
We will make "striped" pink rings.
With this package, you can use the striped pink rings by
looking at them and pressing "F" (assuming that is how
your keybindings are set up).
We will make a package that you install in the
Data/Packages
folder of the game.
So, you will be able to start a new game and fly around
this new world.
We will just go over the interesting parts of the package
we are making.
Pink Sphere Basic Entity (Destination)
First, in the BasicEnts folder of our package,
we create a file called
bent_ring_pink_striped_dest.lua
which should read as follows:
function p.__get_mesh() return "sphere_pink_striped" end
function p.__get_pulsates() return false end
function p.__get_scale() return 0.7 end
This is a very simple entity.
It uses the mesh named
sphere_pink_striped
(which we must add to the
Meshes/mesh_names.txt
file).
You can set up that mesh the same way the
base package sets up the "sphere_pink" mesh.
Note that we could have just as easily used a "block"
instead of a "basic entity" for the pink destination entity.
This is what the basic entity looks like:
Pink Rings Basic Entity (Source)
Now we must define the pink rings entity.
When the player uses this entity, they are teleported to
a striped pink sphere.
What we do is create a file called
bent_ring_pink_striped_source.lua
in the BasicEnts folder and have it read as follows:
function p.__get_mesh() return "" end
function p.payload(level, bp)
--Will play a sound of worked.
local chunk_id = ga_bp_to_parent_chunk_id(level, bp)
game_tele_pink_striped.tele(chunk_id) --In this package.
end
function p.__on_touch(level, bp)
local dist = ga_block_dist_to_viewer(level, bp)
if (dist > 0.4) then return end
p.payload(level, bp)
end
function p.__get_can_use(level, bp)
return true
end
function p.__get_use_msg(level, bp)
return "Grow until find pink striped sphere"
end
function p.__on_use(level, bp)
p.payload(level, bp)
end
function p.__render(level, bp)
local cur_time = ga_get_game_time()
local speed_mod = 1.0
--
local angle1 = cur_time * 50.0 * speed_mod
local axis1 = std.vec(1.0, 0.0, 0.0)
ga_render_matrix_rotated(angle1, axis1)
ga_render_mesh("ring_pink_striped_large")
--
local angle2 = cur_time * 70.0 * speed_mod
local axis2 = std.vec(0.0, 1.0, 0.0)
ga_render_matrix_rotated(angle2, axis2)
ga_render_mesh("ring_pink_striped_med")
--
local angle3 = cur_time * 90.0 * speed_mod
local axis3 = std.vec(1.0, 0.0, 0.0)
ga_render_matrix_rotated(angle3, axis3)
ga_render_mesh("ring_pink_striped_small")
end
Let us break this down.
The __get_mesh function
returns the empty string,
because the entity uses a custom render function.
The functions
__on_touch
and
__on_use
both call the
payload
function,
which makes the teleportation request.
The request works by calling a function of a script
called game_tele_pink_striped
,
which we will go over in the next section.
Teleportation Script
In the Game folder of the package,
create the file
game_tele_pink_striped.lua
and have it read as follows:
-------------------------------------------------------------------------------
-- Pink teleportation API
-------------------------------------------------------------------------------
--This is the only part of this script which can be called from the outside.
--Starts a "pink" teleportation for the specified block pos.
--That is, we start at the given chunk_id, then we move up the
--chunk tree (towards the root) until we reach a chunk with
--a "pink sphere" bent there.
--Will play a sound if worked.
function p.tele(source_chunk_id)
ga_debug_push("game_tele_pink_striped.tele")
--The hard work.
local should_tele = true
local target_chunk_id = p.tele_pink_helper(source_chunk_id, should_tele)
local worked = (target_chunk_id >= 0)
--Playing a sound.
if( worked ) then
ga_play_sound("pink_ring") --Sound in the base package.
else
ga_play_sound("error") --Sound in the base package.
end
ga_debug_pop("game_tele_pink_striped.tele")
end
--This can be called from the outside.
--Returns -1 if the dest chunk does not exist.
function p.get_pink_dest_chunk_id(source_chunk_id)
local should_tele = false
return p.tele_pink_helper(source_chunk_id, should_tele)
end
--This can be called from the outside.
--Returns -1 if the dest chunk does not exist.
--Does not actually teleport.
function p.get_pink_dest_level(source_chunk_id)
local target_chunk_id = p.get_pink_dest_chunk_id(source_chunk_id)
if( target_chunk_id < 0 ) then return -1 end
local target_level = ga_chunk_id_to_level(target_chunk_id)
return target_level
end
-------------------------------------------------------------------------------
-- Helper function
-------------------------------------------------------------------------------
--Do NOT call this from outside this script.
--Helper function.
--Returns the chunk id of the dest chunk (if it worked),
--and returns -1 otherwise.
function p.tele_pink_helper(source_chunk_id, should_tele)
local bent_type = "bent_ring_pink_striped_dest"
local cur_chunk_id = source_chunk_id
while( cur_chunk_id >= 0 ) do
local data = ga_search_for_bent_in_chunk(cur_chunk_id, bent_type)
if( data.is_valid ) then
--Found the bent.
local bent_lbp = data.value
local target_offset = std.block_center(bent_lbp) --Use a different function name?
local target_chunk_path = ga_chunk_id_to_path(cur_chunk_id)
if( should_tele ) then
ga_tele(target_chunk_path, target_offset);
end
return cur_chunk_id
end
local parent_chunk_id = ga_chunk_id_to_parent_chunk_id(cur_chunk_id)
cur_chunk_id = parent_chunk_id
end
return -1
end
We do not need the functions
get_pink_dest_chunk_id
and
get_pink_dest_level
,
but you might find them useful.
The function tele_pink_helper
is the fundamental algorithm.
We start at a given chunk_id.
Then, we keep on passing to the
parent of the "chunk we are in"
until we reach a chunk which contains
a basic entity of type
bent_ring_pink_striped_dest
.
The way we go from a chunk to
its parent (in this function) is with
ga_chunk_id_to_parent_chunk_id
.
The way we search for whether a chunk has
a given basic entity is with the
ga_search_for_bent_in_chunk
function.
Note that there is also the function
ga_search_for_bt_in_chunk
to search for a block type inside of a chunk.
That is it!
A Comment
This all is relatively simple because we are able
to teleport right away in one function call.
That is, we crawl up the chunk tree to find what we need
and then teleport if appropriate.
On the other hand,
blue rings are much more complicated
because we need to have the engine expand the chunk tree (explore)
while we query the newly created chunks to see
what to do next and determine if we are done.
An important ingredient for doing this is the "explore while loop"
which we will explain in the guide about custom blue rings.
Download
Here is the package we created.