#Stencyl:
Zerg terrain infection
Part
3: Creating tiles, infecting first tiles
Topics:
Adding
new matrices
Adding
tiles actors
Marking
tiles occupied by buildings
Infecting
tiles around buildings
Changing
animation of
infected tiles
Extras:
Is it ok to place building using tile logic
- Extras:
Infect area outside of screen
Behaviors
used in part III
Behavior
Events:
- main scene behavior (scene behavior)
- tile_behavior (actor behavior)
- building_behavior (actor behavior)
- matrix_support_behavior (scene behavior)
- infection_behavior (scene behavior)
- infect
- animate
- animate_me
Main
variables:
- main scene behavior (scene behavior)
- tile_list - List; as elements contains tiles actors
- tile_size - Number; width/height of tile, often used to translate position in pixels to position in matrix coordinates
- matrix_behavior (scene behavior)
- ground_list - Matrix; contains value which corresponds to status of tile (uninfected, occupied by building, infected)
- tile_list - Matrix; contains indexes to list <tile_list> in <main_scene_behavior>, indirectly stores tiles actors
- tile_behavior (actor behavior)
- index - Number; actors knows that he is being stored in list <tile_list> in <main_scene_behavior> as <tile_list[index]>
- infection_behavior (scene behavior)
- x - Number; X position in <ground_list> matrix
- y - Number; Y position in ground_list matrix
- return - Number; status of tile before the infection
- infected_list - List; stores as elements infected tiles that make edge of infected area
- top, down, left, right - Number; status of neighbouring tile, needed for choice of animation
Adding
new matrices
->
main_scene_behavior
-> when created
We
will need two more matrices: <ground_list> matrix and
<tile_list> matrix.
Values
in <ground_list> matrix will correspond to status of tile
<tile_list>
matrix will indirectly contain tiles actors. In <tile_list>
matrix as elements there will be indexes pointing to list <tile_list>
of <main_scene_behavior>. <tile_list>
of
<main_scene_behavior> is the list that will contain tiles actors
themselves.
We
add matrices in <when created> of <main_scene_behavior>. We fill
them both with 0s so that we can use <set_value_by_index>
later on. Size of places in matrices to be filled is equal to number of tiles.
We
wrap whole creating of matrices in <do after> because Stencyl
doesn't allow to use trigger events of scene behavior in <when
created> of scene behavior.
Filling
matrix with 0s is required because:
It's
good to have some initial state, it makes debugging easier
<set_value_by_index>
of <matrix_behavior> requires that record exists before it
will set specific value in that record
<when
created> of <main_scene_behavior> completed with part of
code adding <tile_list> and <ground_list> matrices.
Adding
tiles actors
->
main_scene_behavior
-> when created
->
tile_behavior -> index_declare
In
<when created> we create tile actors so that they cover the
screen. As we create them we add them to list <tile_list> of
<main_scene_behavior>. We let the tile actor know under which
index is he hold in the list by setting <index>.
The
if statement allows us to go to the next row while creating tile
actors.
If
you find placing actors tiles to be confusing read section "Creating
a matrix of cards" from "Match game" post:
<when
created> of <main_scene_behavior> completed with part of
code responsible for creating tiles
actors.
After
adding the tile we force it to update <tile_list > matrix with
its index by triggering <index_declare>.
Information
about index which holds the tile actor is given to tile so that it
knows it. Since it's the last actor added to the list it's index =
Length of List - 1.
Tile
actor calculates where he should put information about its index in
the matrix based on it's <X position>, <Y position>,
<tile size>.
Tile
actor puts the information into the matrix since it knows everything
it needs to do it.
Trigger
event <index_declare>. Tile actor using
information about its position and <tile_size> learns where to
put its index into the matrix. The tile actor then puts the index
into the matrix.
Marking
tiles occupied by buildings
->
building_behavior -> placed_on_map
->
matrix_support_behavior -> rectangle_fill_by_index
After
we placed the building we need to update <ground_list> so that
it will mark the tiles covered by building. We already have a trigger
event that is executed as building is placed called <placed_on_map>.
We add part responsible for matrix update.
The
added code sends information about corners of the building as matrix
positions to <matrix_support_behavior>. Upon
triggering <rectangle_fill_by_index> information is used to
fill matrix with 1s in rectangle pattern - this way marking in
matrix the tiles covered by building.
Send
information from <placed_on_map> about corners of the building
as matrix coordinates to <matrix_support_behavior>
Trigger
event <rectangle_fill_by_index> fills matrix <ground_list>
with 1s in area described by corners.
Infecting
tiles around buildings
->
building_behavior -> placed_on_map
->
infection_behavior -> infect
After
placing the building we want to infect tiles around the building. To
do this we add another part to <placed_on_map> trigger event.
We go through each tile covered by the building and if this tile
makes edge of the building it tries to infect one of the tiles around
it (left,right, above, or down of it depending on edge).
Trying
to infect means sending crucial information (in this case position in
<ground_list> matrix) to infection_behavior which will do
infection upon triggering <infect>.
Building
checks its tiles. If they are edge tiles they try to infect tiles
around it. Back of the arrow shows the source tile on the edge and head of the arrow points the
tile that is being infected.
<placed_on_map>
with added part that checks tiles covered by building in order infect
tiles around it.
<placed_on_map>
doesn't infect tiles. It just sends request for tile at <x>,
<y> position in <ground_list> matrix to be infected. The
infection itself is handled by <infect> of <
infection_behavior>.
<infect>
of < infection_behavior> - trigger event responsible for
handling the infection of tile at <x>, <y> position.
Before
going to infecting tile itself let's make one thing clear: we don't
want to infect tile that's already infected because it doesn't make
sense. The second thing is that we assume that tiles covered by
building are infected. If player doesn't see them it doesn't matter
if they are infected or not so it's ok to assume such thing.
As
first thing we assume that tile we are willing to infect is already
infected (<return>=1). We ask if position of tile we want to
infect is inside boundaries of the map. If the tile position is
outside of the boundaries <return> remain equal to 1 and
nothing happens because later if requires <return> = 0.
If
tile position is inside the boundaries of the map we ask what's the
status of the tile by asking the value in <ground_list>. If
it's equal to 0, meaning uninfected, (in code: if <return> = 0)
we proceed with infecting it.
We
want to know which index of the list <tile_list>
of <main_scene_behavior>
stores the tile actor we are about to infect. We learn it by asking
<tile_list>
matrix of <matrix_behavior>
what value it holds at <x>, <y> position. Now we can get
newly infected tile actor as element under the index we learned in
<tile_list>
of <main_scene_behavior>.
We
change animation of the newly infected tile actor to <Animation 0>
which is one of the infected tiles animations (fully infected
square). We add newly infected tile actor to <infected_list> -
we will need this list later. Since we have infected the tile we need
to mark the fact that tile has changed status from uninfected to
infected. We do it by setting value in <ground_list>
matrix at
<x>, <y> position
to 1.
Changing
animation of
infected tiles
->
infection_behavior -> animate
->
infection_behavior -> animate_me
What
we want to do now is add some variety to our infected tiles. We will
do it by changing animation of the tile based on its surrounding.
There are some basic states that tile can have. Once we have basic
states all other can be achieved by rotating the basic states.
States
that tile can have based on its surrounding. Brown - uninfected,
purple - infected.
(1)
4 sides uninfected, (2) 1 side infected (3) 2 sides infected on
opposite sites (4) 2 sides infected on neighbouring sites (5) 3
sides infected (6) 4 sides infected
For
animating tile actor we will use <animate>
from <infection_behavior >.
Side
note: if tile has as its neighbour tile outside of the screen we
assume that this tile out-of-boundaries is infected.
Trigger
event <animate> from <infection_behavior >.
The
big while at the beginning let us do animation change for each
element of <infected_list>. This means we will perform
following code for each edge tile of infected area.
The
neighbourhood of tile is represented by variables
<top>,<down>,<left>,<right>. They are 0 if
neighbouring tile in given direction is uninfected and 1 if it's
infected. There is a variable <sum> which says how many tiles
around current tile are infected. <sum> makes choosing
animation simpler but is not obligatory for solving the problem
itself.
Once
we have chosen the edge tile we ask if neighbour in chosen direction
is on map. If not we consider it to be infected and set proper
direction variable to 1. At the same time we add 1 to <sum>. If
neighbouring tile is on the map we ask its status by getting value
from <ground_list> of <matrix_ behavior>. The tile is
infected if value in list equals 1(covered by building) or 2(infected
but not covered by building). If statement ( >0) checks both of
the possibilities. If the tile is infected we set proper direction
variable to 1 and we add 1 to <sum>.
After
we get all info about status of neighbourhood we trigger <animate_me>
which will set proper animation to the tile based on values of
<top>,<down>,<left>,<right>.
Trigger
event <animate_me> uses values of <top>,<down>,<left>,<right>
to set animation to edge infected tile.
Extras:
Is it ok to place building using tile logic
In
part II we learned how to place the building. The approach we used
didn't use tiles. This part presents alternative approach to problem
of checking if it's ok to place building using tiles and
<ground_list> matrix.
Example
of trying to place building(green frame) over building already on
map. On right it is visible how the <ground_list> matrix looks like as we
try to place the building; 0 - free place, 1- covered by building
In
alternative approach we check if in area we are about to place the
building (green) are any occupied places (represent by 1). If yes
that means we can't place building. If no it's ok to place building
and we place it.
Pros:
The approach from part II is ok if our buildings are rectangles or we
can assume that they are more or less of that shape. This generally
works. By using getting values in matrix we can place buildings that
are triangles or other more exotic shapes.
Cons:
As we place building in this approach we will need to associate with
each type of building a shape equivalent in matrix. Both setting the
building and checking if its ok to place are therefore more
difficult.
Extras:
Infect area outside of screen
We
decided that area outside of screen is considered infected. This is
ok but we can do it better by not assuming anything. All we need to
do is add 2 additional columns and 2 rows to the matrix so that they
can represent tiles outside of screen. This however creates offset
between actor position and its position in matrix what can be
painful to use.
Left picture
shows map with building placed in top left corner of the map. Middle
- matrix as used in project. Right - matrix with added record to
cover outside of screen, this causes (1,1) offset.
To
choose other part follow the link: