Now that we have a list of objects and positions, we'll add representations of the objects in a map to the scene created from that map. Because a map is only loaded once in the lifecycle of a scene, but the visuals might be purged to conserve memory, we don't simply attach object data to the sprites or images used to display the objects, as we did in simpler projects.
Inside your project directory, find the objects
folder that you copied over when you started the project, and open the file common.lua
in that folder (if you've looked at the map datafiles, you'll notice this file has the same name as the object set used in those files). Notice that this file already loads an image sheet and uses an internal table of sequence lists for sprites.
Find the table constructor assigned to common.campfire
and add a new function definition to this table:
common.campfire = object { Embody = function(self) end; EnterSpace = true; }
This function creates and loads a campfire sprite from the preloaded sheet, which contains several different objects and frames, and defined sequences that specify which frames make up the campfire animations:
Embody = function(self)
return display.newSprite(sheet, sequences.campfire)
end;
In the constructor for the common.barrel
table, add an Embody
function that creates a static image from a frame of the same sheet:
common.barrel = object { Embody = function(self) return display.newImage(sheet, 22) end; EnterSpace = false; }
The Embody
function for treasure chests will be similar to the campfire, so that it can be switched between open and closed visual states:
common.chest = object { Embody = function(self) return display.newSprite(sheet, sequences.chest) end; EnterSpace = false; }
The exit
object won't have an Embody
function, because it doesn't have its own appearance; it simply designates an area of the map as being a trigger. The cave that makes this area obvious to the player will be part of the background.
Now that the object templates can specify their appearances, we need to generate those objects and arrange them in the scene. Save any other files you have open, and open the world.lua
file. This will be the module that scenes use to build the groups that display the contents of their maps.
First, create a subgroup to hold objects, characters, and other local features:
local self = display.newGroup() self.Features = display.newGroup() self:insert(self.Features) function self:View(x, y)
Next, add a function to the world group, which will add a specified object to the world's map at the point you declare:
end function self:Add(object, x, y) local list = self.Map[y][x].Features if not table.indexOf(list, object) then table.insert(list, object) end end return self
If the object is already represented in the world, simply return that representation. Otherwise, be ready to add one if needed.
if not table.indexOf(list, object) then table.insert(list, object) end if self[object] then return self[object] end if object.Embody then end end
This function will call the object's Embody
function as we declared it before and place it within the space of the chosen tile:
if object.Embody then local actor = object:Embody() self.Features:insert(actor) self:Place(actor, x, y) return actor end
Now, add a new function to the new world object, which will load it with the contents of a map created using map.lua
:
end function self:Load(map) end return self
This function will go through each space in the map:
function self:Load(map) for v, row in ipairs(map) do for h, space in ipairs(row) do end end end
It will scan that space for objects, and use the function we declared earlier to create each one within the world, in the center of its tile:
for h, space in ipairs(row) do for i, feature in ipairs(space.Features) do self:Add(feature, h, v) end end
Finally, attach the map
file to the world for future reference:
function self:Load(map)
self.Map = map
for v, row in ipairs(map) do
Save the file. This should be the first point at which you can load the project in the simulator, walk your character around by tapping the various edges of the screen, and see a handful of objects move around you.
The next step will be filling in the background, so that you're not moving among these objects in a featureless void.
We used per-object functions to map image and sprite data to objects in a generalized fashion. We looked at each map space in turn and loaded all the relevant objects for that space in their specified order.
One thing you may want to note is the way the sheet size is specified in the file as being 224 pixels squared, when the actual image is 112 pixels squared. In a case like this where you want to scale up all of the contents (the icons are 16 x 16 but are being used on a map of 32 x 32 tiles), this is a fast and simple way to do it.
Another approach that can be useful in conjunction with sprite sheets and texture atlases is to employ a texture-packing utility. When a texture is loaded into memory, each of its dimensions is increased if needed to make it a power of two; so while a 60 x 120 image will take up memory as if it were 64 x 128, a 550 x 550 image will take up the same texture memory as a 1024 x 1024 background texture! Sometimes tiled textures can be rearranged with a different number of tiles per side, which allows them to reduce one dimension below the next power of two without pushing the other dimension up over its next power of two.
More commonly, however, texture packers help by taking sprites and similar contents that don't take up their entire tile space and squeezing them together to reduce the total area needed for all sprites in the sheet. These utilities can typically export a Lua file that contains all the tables to describe the locations of the different frames, along with their rearranged image file.
3.147.89.85