Welcome to the first Corona SVG Level Builder tutorial! First and foremost I want to simplify your reading: I’ll just write Builder or SLB instead of Corona SVG Level Builder since that’s a big name!
In this tutorial I’ll show you the basic mechanics of the Builder so you can start making any kind of game with it! I’ll show you:
- How setup Inkscape.
- How to draw a simple level with a few elements and a few layers.
- How to add life and gameplay to this level by adding touch and collision events.
- The 3 ways of identifying and getting in your Lua code the bodies you draw in Inkscape: by a body ID, by a layer name and by a material name.
The game built will be a single level Save The Totem game where you have to clean the blocks that are holding the totem, and make sure the totem falls safely to the bottom.
Notice: this tutorial can take from 30 to 50 minutes mainly because it teaches you every little aspect to setup everything in order to build levels to be loaded with the Corona SVG Level Builder and the basics on how to get and deal with what you draw. Since you are getting the base, after this you probably will be making any kind of level and level based game very fast.
To make things easier to follow I recommend opening the Builder documentation: http://levelbuilder.karnakgames.com/doc or you can open the file that comes in the zip file if you already purchased it.
In this tutorial I’ll try to explain every step in detail, but if I write something you didn’t understand you can check in the documentation (every aspect of the Builder is there!) or ask me by dropping a comment below!
- Download Inkscape 0.47. You can see the download links to the 0.47 version in the documentation on the Getting Started section: http://levelbuilder.karnakgames.com/doc/#gettingStarted. Unfortunately Inkscape 0.48+ is not supported due to the way these new versions save path information.
- Before creating any level you have to set some Inkscape Preferences. In Inkscape go to File, Inkscape Preferences and set these Transform options:
And also some SVG output options:
- Resize the Inkscape document to have the same dimensions as your base game dimensions according to your game default content size and orientation from your Corona project config.lua (iPad, iPhone Retina, etc). On most cases you will be going with the default iPhone dimensions: 480×320 (or portrait 320×480), since with these dimensions your levels will be then scaled for the other devices (iPhone 4, iPad, iPad 3 and Android devices). On our case, we are going with the default iPhone dimensions. Go to File, Document Properties and set the document size (in “Custom Size”):
Inkscape Layers and XML Editor
You will draw your levels inside Inkscape layers. With the layers you can have different kinds of elements and then easily filter them later in your game code according to the layer name.
Make sure the first layer (and every new layer you create) doesn’t have a transform attribute. Every object you draw in a layer with a transform is positioned relative to this transform, and then when the Builder loads the level it will position these objects obeying this relative positioning, which will make them further away from screen, thus looking like there is no level.
In order to edit attributes in Inkscape you have to open its XML Editor: go to Edit, XML Editor or just click its button in the toolbar:
In the XML Editor, click the Layer 1 node on the left, click the transform attribute on the right, and delete it clicking the toolbar icon:
What folder inside your game folder are you going to place your SVG levels? Backgrounds? Graphics? You have to know this in order to pointer the Builder where it will look for everything you make.
By default the SLB looks for the following folders in your Corona project:
- assets/backgrounds (background images)
- assets/graphics (individual objects graphics and sprites)
- assets/levels (the SVG files you create and Inkscape – your level files)
In this tutorial we are going with these default folders.
Note: If you want to use different folders, open the SLB file slb-svgparser.lua and adjust the folder names in the variables DEFAULT_MAPS_FOLDER, DEFAULT_GRAPHICS_FOLDER and DEFAULT_BACKGROUNDS_FOLDER. More information here: http://levelbuilder.karnakgames.com/doc/#gameSettings.
About our Game
Everything is set and waiting to be used to make levels. But before making the levels we have to define what our game will be about and how we will play it.
The objective of the game is to save the totem (the statue) by dropping it from an altitude to a safe place. If the totem falls on the bottom it will broke and then it will be game over.
- A background image.
- The altitude will be created by placing the totem above orange and red blocks, that we can arrange and order when drawing our level. They will be dynamic physics bodies and have default physics properties.
- The safe place will be a thin blue block that will hold all the other blocks. It will be placed above the ground. It will be a static physics body.
- The bottom line will be an invisible static physics body.
- We will also place a snowed ground image, so it will look like the blocks and the totem are falling on a real snow ground. This body will be just an image without physical attributes (since behind it we will already have the collision bottom line).
In order to drop the statue from the blocks we have to remove them! So we are going to add a touch event to all orange and red blocks.
And how do we detect if the totem fell to the ground or to the safe place? By adding a collision event to it!
Download the assets and the base project
Now that we are going to produce the game, download the base/skeleton project with a config.lua, build.settings and main.lua skeleton files as well the folder structure and the graphical assets .
Graphics by Vick Wenderlich.
Drawing the Level
I made a video on this next part of the tutorial, since it is easier for you to follow a drawing process by video instead of a written tutorial, and then the next section (programming part) continues written. So watch the video and then come back here to follow to the next part.
Developing the Game
Identify the statue by Id
In the video I told you to add the statue in its own layer. That’s a way of identifying it. But now let’s change the plan and identify it by id. Since there are just one statue, which is unique and required in our game, we can go on via the ID way (Documentation: Identifiying Bodies: ID).
Now open the main.lua file and declare a variable statue and a gameActive in the Variables section right after where you imported the SVG parser:
------------------- -- Variables ------------------- local svg = require("slb-svgparser") local statue -- Can we play the game? local gameActive = true
Go down a little in the “Load the Level” section, after where you loaded the level and get the statue from the loaded level:
local level = svg:new("level01") -- Get the body with the "statue" id statue = level.bodies.statue
Identifying bodies according to their Inkscape Layer
We need to add a touch event to every red and orange blocks we place. But how do we know how many of each is draw in a level? And how do we get them from our loaded level?
First, let’s understand something about layers: every layer you create in Inkscape is transformed in a Corona Display Group by the Builder. And everything you draw in a Inkscape layer is a child of the layer Display Group. These Display Groups are returned to you as a parent Display Group once you load your level. See more on the documentation: Multiple Layers and how to filter and add categories to the elements of your level.
In our case we loaded the level and passed it to the variable level. So we can access the parent Display Group by indexing the variable level with “group”. Update your code:
local level = svg:new("level01") local levelGroup = level.group
The Display Groups are passed with an id attribute which is the layer name. With that in mind we can iterate through the display groups until we find the blocks Layer (Display Group) and add a touch event to every child of it.
Add this loop to the bottom of main.lua:
for g = 1, levelGroup.numChildren do local innerGroup = levelGroup[g] local layerId = innerGroup.id
This will iterate through all the children Display Groups. We are also getting the inner group and the inner group ID.
Next we will check if the layer is the blocks layer:
-- Blocks layer if layerId == "blocks" then
Adding a Touch event to all red and orange blocks
Now we need to iterate through all children of the blocks group and add a touch event to them.
Add this inside the earlier if:
-- Get the amount of blocks we placed in this level local blocksAmount = innerGroup.numChildren -- Loop through all blocks and add a touch event to each one of them for b = 1, blocksAmount do local block = innerGroup[b] -- ADD TOUCH block:addEventListener("touch", onBlockTouch) end
As you can see this is a simple for that iterates through all the bodies of the blocks Display Group and adds a touch event to all of them. The touch event redirects to the onBlockTouch function that we will create next.
Don’t forget to close the if and the outer loop (end). Our layers loop will look like this for now:
-------------------------------------------------- -- Loop through all level layers and add related events -------------------------------------------------- for g = 1, levelGroup.numChildren do local innerGroup = levelGroup[g] local layerId = innerGroup.id -- Blocks layer if layerId == "blocks" then -- Get the amount of blocks we placed in this level local blocksAmount = innerGroup.numChildren -- Loop through all blocks and add a touch event to each one of them for b = 1, blocksAmount do local block = innerGroup[b] -- ADD TOUCH block:addEventListener("touch", onBlockTouch) end end end
Writing the touch function
Add the function onBlockTouch above the earlier loop code:
local function onBlockTouch(event) -- We can only touch if the game is still going on if gameActive then local phase = event.phase local target = event.target
We also added an indexed access to the phase and target (the touched block) of the event table. Now we set the touched block as the focus, so we touch only one at once (common Corona SDK behavior):
if phase == "began" then display.getCurrentStage():setFocus( target, event.id ) target.isFocus = true end
Next we make sure it is the focused block and that the finger has been lifted from the screen. Then it is time to deactivate its physics behavior and remove it from the game:
if target.isFocus then -- Finger lifted from screen if phase == "ended" then -- Remove the block target.isBodyActive = false target:removeSelf() end -- Block removed. Remove focus from it. So we can touch another block. if ("ended" == phase or "cancelled" == phase) then display.getCurrentStage():setFocus( target, nil ) target.isFocus = false end return true end end end
Save and test the game. You can now touch the red and orange blocks and remove them from level, making the statue fall. But how do we know if the statue fell on safe place or on the ground? That’s what we are going to do next: write the statue collision event!
Writing the collision function
We need to detect if the statue hits either the safe place (totem saved, game won) or the bottom line (totem fell, game over).
In our collision function we will use the third way of detecting and getting game bodies from an Inkscape level: by their material names.
Add the following function code right below your onBlockTouch function, around line 56:
local function onStatueCollision(self, event) if event.phase == "began" then -- Hit the Bottom Line: game over if event.other.material == "bottomLine" then print("GAME OVER!") gameActive = false -- Hit the Safe Place: game won elseif event.other.material == "safePlace" then print("TOTEM SAVED!") gameActive = false end end end
As you can see, this is a generic Corona collision event, except that it detects if the statue collided with a body of a certain material. In this case if it collides with a body with the material “bottomLine” it means Game Over, and if it collides with a body with the material “safePlace” means we saved it.
Notice you can always get the material name of a body by indexing it with material. In the case of our statue we can index it like this: statue.material.
After detecting with what material we collided with, we disable the controls (gameActive = false).
Adding the Collision event to the statue
To listen to collisions on the statue we simply pass the onStatueCollision function pointer to its collision index then add the collision event. Add the following code right below your onStatueCollision function:
statue.collision = onStatueCollision statue:addEventListener("collision", statue)
Wrapping things up
And that’s it for this first Corona SVG Level Builder tutorial!
The game developed is not perfect. Depending on how you drop the statue you will see many TOTEM SAVED! messages and even right after a GAME OVER! message, that’s why we keep detecting collisions, we never stop them. We also don’t keep track if the totem hits the safe place and then falls off. But making a perfect game wasn’t my objective. With this simple game I wanted to show you the basics aspects of the Corona SVG Level Builder!
I hope you could learn the basics of it, but mostly important, that you understand how easy and fast is to make games with it after going through this initial learning and setup steps.
You can see Corona SVG Level Builder is all about creating some materials and identifying in your code. You never have to worry about loading image, positioning them and dealing with physics code (with the exception of some advanced games, that may require some physics code here and there) – but notice there are way more features than only that, check the features list and the documentation!
Also you saw that grouping bodies in a Layer or by a Material allows you to group common elements and properties and then easily identify and deal with them in your code. And if you have specific and unique uses, you can set an unique ID to the bodies and get them directly from the bodies table.
Again, you can download the tutorial files:
NOTICE: The Corona SVG Level Builder is not available inside the tutorial files, you have to purchase it and then copy to the project folder.