czwartek, 6 sierpnia 2015

#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)
      • when created
    •  tile_behavior (actor behavior)
      • index_declare
    •  building_behavior (actor behavior)
      • placed_on_map
    •  matrix_support_behavior (scene behavior)
      • rectangle_fill_by_index
    •  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
    • 0 - tile is uninfected and free
    • 1 - tile is occupied by building (we consider them to be infected as well)
    • 2 - tile is infected

    <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.

    If you find indirectly placing actors into matrix to be confusing read section "Storing in matrix something different than numbers" from "Matrix behavior" post: 
    http://t4upl.blogspot.com/2015/08/stencylmatrix-behavior-topics-download.html

    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:

    Brak komentarzy:

    Prześlij komentarz