Corona™ SVG Level Builder Documentation
Documentation version: 1.2.1 (Dec 16, 2012), Parser 1.5.5.

Table of Contents

License and Copyright

DO NOT DISTRIBUTE THIS FILE. DO NOT DISTRIBUTE PORTIONS OF THIS FILE.
DO NOT SELL THIS FILE. DO NOT SELL PORTIONS OF THIS FILE. THE SAME RULES APPLY
TO ALL SOURCE FILES THAT ARE PART OF THE CORONA™ SVG LEVEL BUILDER AND SVG PARSER
EXCEPT FOR THIRD PARTY LIBRARIES (XmlParser and SpriteGrabber) .

IF YOU ARE GOING TO USE THIS IN A PROJECT THAT ISN'T YOURS, e.g. CLIENT/CONTRACT WORK,
EVERY PART INVOLVED MUST BUY A NEW LICENSE AND A NEW COPY OF THIS PRODUCT.

A LOT OF WORK, EXPERTISE, AND EFFORT HAS BEEN PUT INTO THIS PROJECT, THEN:
(A) IF YOU HAVE FOUND THE SVG PARSER SOURCE CODE ON A DIFFERENT PLACE OTHER THAN THE OFFICIAL SITES:
http://www.karnakgames.com AND/OR http://levelbuilder.karnakgames.com, PLEASE CONTACT ME
ASAP AND POINT ME WHERE YOU HAVE DOWNLOADED THE CODE FROM, OR WHERE THE CODE/PRODUCT
IS BEING SHOWCASED OTHER THAN THE OFFICIAL SITE.

(B) IF YOU DIDN'T PURCHASE IT, PLEASE MAKE SURE YOU BUY IT.

EVERY ONE THAT BUYS THE PRODUCT GETS CONSTANT UPDATES, AS WELL SUPPORT.
ALSO WITH YOUR SUPPORT I MAY CONTINUE WORKING TO IMPROVE THE LIBRARY,
THE DOCUMENTATION AS WELL ADD NEW FEATURES (Game Templates, etc).

The Corona and Corona SDK are a trademark of Ansca, Inc. Copyright © 2009-2012 Ansca, Inc.

The Corona™ SVG Level Builder and SVG Parser were developed and are maintained by Alfred Reinold Baudisch:
http://www.karnakgames.com, http://levelbuilder.karnakgames.com, contact@karnakgames.com.
Copyright © 2011-2012. Auriumsoft Tecnologia e Video LTDA.

Some of the graphics and art are from the free art packs made by Vicki Wenderlich - http://www.vickiwenderlich.com/.

Introduction

With the Corona SVG Level Builder you can create and edit Corona SDK physics based games and levels by just drawing in Inkscape and then setting physics properties, spritesheets and custom attributes with the built in Inkscape XML editor. Corona SVG Level Builder allows you to create very simple levels with just a few elements to very complex levels with lots of physics curves and complex terrains.

Examples of games that can be created:

  1. Platformers.
  2. Top view racing games.
  3. Labyrinths and mazes.
  4. Slingshot based games.

Basically: any physics game with hand made levels.

Getting Started

In order to work with the Corona™ SVG Level Builder, you will need:

  1. Corona SDK at least Build 2011.484 (Mac OS X) and Build 2011.528 (Windows). Of course you can always use a newer version. Download the latest version here:
    Mac OS X: https://developer.anscamobile.com/downloads/coronasdk.
    Windows: you will still need to download from the Daily Builds section: http://developer.anscamobile.com/release/2011/528

  2. Install the free and open source vector graphics editor Inkscape. As for now you will need Inkscape 0.47 only. Inkscape 0.48+ isn't supported for now. Download it from one of the following links:
    Mac OS X: http://sourceforge.net/projects/inkscape/files/inkscape/0.47/Inkscape-0.47-1.LEOPARD%2B.dmg/download
    Windows: http://sourceforge.net/projects/inkscape/files/inkscape/0.47/Inkscape-0.47-3.exe/download

  3. Define your default content size and scaling in your game config.lua (if you have doubts about that, please refer to the Corona SDK documentation).

How is this documentation organized

The documentation first shows you how to load and unload the levels you create, how to access the bodies in the loaded levels, then it will show how to setup and use Inkscape for the purpose of level creation and then it will completely describe each aspect of Corona SVG Level Builder body and level setup and creation.

NOTE: the documentation assumes you know about Corona Display Objects, Display Groups and mostly important, that you known about its Physics API. An advanced knowledge of the Physics API is not required, but you need to know about the different body types, physical attributes (density, friction, etc) and how to add Collision Listeners. You can learn everything about the Corona Physics API easily (and in a short amount of time) in the official documentation.

Loading the SVG levels

To load and parse the level you first need to include the SVG Parser module:

local svg = require("slb-svgparser")

Then you create a new SVG level instance passing the level svg file name in svgparser:new:

local level = svg:new("level01")

The file will be loaded from the path you set in DEFAULT_MAPS_FOLDER in the Game Settings.

svgparser:new supports another parameter which is a table with one or more configuration arguments:

Example on how to pass a configuration table:

local level = svg:new("level01", {drawMode = "debug", dragMap = true})

Getting bodies and attributes from a SVG level

The instances of all bodies and paths from a SVG level/, as well level attributes are returned once you call svgparser:new. That's why you always have to assign a variable once you create a new level instance: local level = svg:new("levelFileName").

The returned table has the following fields:

Examples

1) The most common technique: do something with all bodies from a specific named layer.

2) Apply a transition to a body named "monster":

local levelBodies = svg:new("levelX")
local monster = levelBodies.bodies["monster"]
transition.to(monster, {time = 1000, x = monster.x + 100})

3) Hide all bodies that are set with material "coin":

local levelBodies = svg:new("map", {drawMode="debug"})
for idx, body in pairs(levelBodies.bodies) do
    if body.material == "coin" then
        body.isVisible = false
    end
end

Working with the returned tables is the only way to interact with the elements of your game. Example: you can detect if the player hits a trap, picks up a coin, if a racing car collides with another, etc.

Naming your bodies, assigning materials and/or placing them in separated named layers are the different ways of filtering content and making the correct actions and detections.

Loading additional SVG files in the same scene

You can load additional SVG levels/files in the same scene. That is useful when you have different definitions accross different files, if you want to switch elements while the game is running, games with downloadable content, infinite games, etc.

Example: In a Running game, you could allow the player to select different characters and scenarios. In this case you would have a SVG file for each kind of character and for each kind of scenarios.

Before loading an additional SVG file, you first need to load one with the default method as seem above. Then to load another file, you call svgparser:parseSvgFile. It accepts the same configuration arguments as svgparser:new.

An example is available in the examples/multipleSVGs folder.

Unloading a Level

To unload a level and clean the resources used by it, simply call svgparser:cleanUp in your SVG object. It won't clear persistent spritesheets, as expected, so once you load another level the spritesheet (or spritesheets) will already exist.

Example:

local level = svg:new("levelX")
svg:cleanUp()

It is very important to do this step when you have a level loaded and then want to load another, or simply once you don't need a previous loaded level anymore.

If you call it with a true argument it will also unloaded and clear the persistent spritesheets:

-- Clean everything!
svg:cleanUp(true)
In the case of multiple loaded SVG files, you can just clean a specific file with svgparser:cleanUpFile(svgFile, cleanPersistentData):
-- Load and parse the main SVG file
local game = svg:new("game")

-- Load and parse another one!
local character = svg:parseSvgFile("character", config)

-- Do anything...

-- Clean the character SVG file!
svg:cleanUpFile(character.svgFile)

Creating and Cloning bodies

You may want to create additional copies of a body in runtime (a bullet, additional blocks, etc). To create a new instance of a loaded and defined body, you can use svgparser:createBody(bodyId, addToLayerGroup, exposeRawAttributes, svgFile):

You can also directly clone an existing body by calling the clone method in the body. The clone method will simply call createBody passing the body ID, so you don't have to worry about the body's id.

An example is available in the examples/cloning folder.

Getting all bodies IDs and instances from an Inkscape layer

If you want to get a list of bodies IDs from an Inkscape defined layer, you can call svgparser:bodiesIdsFromLayer(layerId, svgFile). Why would you want to do that? As an example, we could have a SVG file with a layer named "powerups". Then in this layer you defined some powerups. Calling this method will return all powerup's IDs, and then you can make a function to randomly spawn a powerup based on the list of IDs.

You can also get all bodies that are instantiated in a given layer ID: svgparser:bodiesFromLayer(layerId, svgFile). This is a shortcut to the default way with loops.

Loading a SVG file as a definition table

The default and common behavior of Corona SVG Level Builder is to load and show all bodies at once when a SVG file is parsed (after loading, all bodies are available in the bodies table). But you could just want to have the bodies information at hand, without showing them when loading the game. Maybe in a non level based game, or just additional bodies in an earlier loaded level (example a SVG file with the definitions for powerups).

To just parse a SVG file without showing the bodies, load it with the parseOnly = true attribute. Then create bodies with the svgparser:createBodyfunction as seem above.

Inkscape Preferences

Open Inkscape and go to Preferences (SHIFT + CONTROL + P | File, Inkscape Preferences...).

  1. Set the "Transform" options exactly as the screenshot:
    Transforms

  2. The same for "SVG Output":
    SVG Output

Inkscape Document Setup

In order to create a level to be loaded with the Corona SVG Level Builder, you will need to setup your Inkscape document. An Inkscape document is known as a map or level in Corona SVG Level Builder. Follow the steps:

  1. Create a new Inkscape document (CTRL+N | File, New, Default).

  2. Go to File, Document Properties (SHIFT + CTRL + D) and set the document size (in "Custom Size") according to your game default content size and orientation from your Corona project config.lua (iPad, iPhone Retina, etc).
    In the following example, the level will be sized to the default iPhone screen in Landscape orientation:



  3. Save your map inside the folder you defined in your Game Settings, in the DEFAULT_MAPS_FOLDER variable (see Game Settings).

  4. Set the zoom to 100%, to the actual document size (1 | View, Zoom, Zoom 1:1).

  5. Open the Inkscape XML Editor (SHIFT + CONTROL + X | Edit, XML Editor... | ).

  6. Click the "Layer 1" node (<svg:g id="layer1" inkscape:label="Layer 1">).

  7. If this node has a transform attribute on the right panel, click it and then press Delete attribute on the toolbar. Remember this step for all levels you create. If you don't do this, elements will be placed on random wrong positions.


  8. Close the XML Editor and make sure "Layer 1" is selected. You can check that in the Layers Panel (SHIFT + CONTROL + L | Layer, Layers...). You can create and draw inside any amount of layers and name them anything except "bg, "background" nor "ignore". Just remember removing the transform attribute and make sure a layer is always selected before you draw:


  9. Now with a layer selected, you can start drawing the level, as we will see next.

Resolution Independent Levels

Once you choose what is your default content size, all your levels have to have this size as the document size. Draw your levels only once and they will work for all resolutions, loading related graphics for the resolution.

Example: if your content size is the default iPhone 480x320, all your levels document size HEIGHT have to be 320, and the width has to be at least 480. Of course your levels can be bigger than that on terms of content, but the document size has to be the default content size if you want to have resolution independent levels.

If you want to achieve "true" resolution independence, i.e. if you want to run on all iOS devices, as well Android phones and tablets you have to create 6 different assets sizes with the following name suffixes:

  1. Default 1x scale (based on 480x320). Suffix: none
  2. 1.5x scale. Suffix: @1_5x
  3. 1.8x scale. Suffix: -fire
  4. 2x scale. Suffix: @2x
  5. iPad scale. Suffix: -ipad
  6. iPad 3 scale: Suffix: @4x

Normally game elements can be created only in 1x, 1.5x, 2x and 4x, since the 1.5x scale is used for Android Phones and the 2x scale is used for iPhone Retina, iPad and Android tablets.

On all cases, backgrounds have to be created on the 6 different scales if you want to have smooth backgrounds.

Check the resolution-independent and resolution-independent-2 examples to see the different spritesheets and backgrounds sizes and names.

Lower and Upper position limits to place elements

Don't go below the bottom left corner, place everything above it and to the right of it. The lower limit is 0,0, so place everything in positive coordinates:

Lower Limit

If your level is bigger than the document size (which will be most of the cases) you can place the elements above and to the right of the bottom left corner. There is no upper limit.

Camera starting position

The camera is default positioned at 0,0 for all loaded levels.

What if you want to start the game in a different position that the lower left corner: let's say the starting point is in the top middle. As an example, the starting point is the player that is the red circle:

Upper Limit

By simply loading this SVG level, your camera will be positioned in the lower left corner.

You can easily start in the red circle by adjusting the camera (the main Display Group) to be centered there on startup. See the basicExamples source code, item "Camera centered in the player".

Assigning a Background to a Level

In most cases (or probably, always) you will want to assign a background to a level, be it with a color, a background image or a composition of images, which could be just a decorative background (e.g. the environment), as well an image of the level itself (e.g. a map you drew with Tiled and then exported as PNG). Also you can draw in Inkscape with this image on the background of your drawing, in a way it can guide you on what you are drawing:

Tiled

With a map SVG file opened in Inkscape, create a new Layer (SHIFT + CONTROL + N | Layer, Add Layer), name it bg or background remove any transform attribute as shown earlier on Inkscape Document Setup. Now move the background layer to the bottom order: make sure the layer is selected (within the Layers panel: SHIFT + CONTROL + L | Layer, Layers...) and go to Layer, Layer to Bottom.

Background Types

There are three types of level backgrounds:

To set the background type, select your background layer, open the XML Editor and add an attribute type to the background node. Then set it with one of the above types. Then to create the background according to the type:

  1. A standalone image:
    Go to File, Import... (CTRL + I) and select the image file. Position it in 0,0 (by typing in the toolbar above the drawing) or drag and drop to where you want to position it (you can position anywhere).
    0,0

  2. A color: there are two ways of creating a color only background:
    - Add an attribute "style" to the layer node and as value "fill:HEXADECIMAL_COLOR", example: fill:#ffffff
    - Add a rectantagle or ellipse to the background layer, with any size, but with your desired background color.

  3. A composition: just draw anything in the background layer, you can even add elements with materials, name, id, etc and even access them in your game code, i.e. to animate, create transitions, etc. Just notice that the bodies in the background layer won't have any kind of physical property, they are purely display objects.

Multiple Layers and Z-Ordering

You can draw your level elements inside any amount of layers in a SVG file. The order you place your layers in Inkscape is exactly the order in which your elements will be ordered in your game (z-ordering):

Layer Ordering

Drawing the Level

Corona SVG Level Builder supports mostly Inkscape drawings and attributes. All drawings are transformed into Box2D (Corona SDK physics engine) bodies or paths, which you can manage and detect in your game code (we will see later how to do this).

Supported Inkscape drawing tools and supported actions:

Tool Draw Scale Rotate Move Tool Icon
Rectangles and squares Yes Yes Yes
Circles and ellipses Yes Yes Yes Yes
Bezier curves and straight lines Yes Yes Yes Yes
Calligraphic and brush strokes Yes Yes Yes Yes
Stars and polygons Yes No No No
Spirals Yes No No No
Freehand lines (not recommended) Yes Yes Yes Yes

Everything you draw will either be parsed as a physics static body or path (later we will see about dynamic and kinematic bodies). You can also draw to only create display objects (i.e. game objects without physics properties), by adding a noPhysics attribute to the body/material.

You may draw any amount of bodies and paths, but be warned that your game performance will decrease as the amount of bodies and paths increase. On Corona at around 30 dynamic bodies and 60 static bodies the performance starts to decrease.

The size you draw is the size that will be considered for the element dimensions. If you want to always force specific dimensions to a given body type you can add a width and height attribute to its material, this way you don't need to worry about the size of your drawing elements.

If you draw a rectangle, the body will be a rectangle, if you draw an ellipse, the body will be a circle. If you want to force a body to be a circle add the isCircle attribute to its material. Even if it is a rectangular body, it will be added as a circle physics body. If you add the isCircle attribute you also need to add a radius attribute to the material, to be companion to isCircle. If not given, it will be taken given width.

Here is an example of a drawing with a bezier path, 3 rectangles and a spiral, and then how it is loaded in Corona as 3 static bodies and 2 paths:

Drawing and then physics bodies

Drawing helper elements and the Ignore Layer

Most levels have many different body types, with different attributes. Settings attributes every time you draw a new element; even repeating ones, can be a tedious task. The SVG Parser already support materials, to group similar attributes under the same property name. But even setting the material name for all bodies all the time is very time consuming.

For that reason, you can create "helper elements", which are simply all the bodies you can add to a level, but in a layer that they won't be loaded into the game. This way you have a "drag and drop" panel, similar to a file browser, in which you can select an element, copy and paste it into a game layer.

The layer name you have to add the helper elements is ignore:

Ignore Layer

Physics Properties

Corona SVG Level Builder supports all Corona SDK physical properties/attributes. Some properties you can set only for the Physics Engine startup (gravity) and most for the bodies themselves (most properties).

Here is the list of properties you can set for your physics bodies direct into Inkscape:

Booleans:

You can also disable physics behaviour in a body by adding the noPhysics attribute to it.

Levels and Types of Attributes Settings

Attributes in Corona SVG Level Builder are basically physical attributes (as seen above: density, friction, angular velocity, etc), but it also include paths, image names, custom values, etc. Corona SVG Level Builder works with five levels of attributes settings:

  1. Game Settings: these settings affect all bodies in all levels.

  2. Game Materials: these settings affect all bodies that are of a material type defined as a game material. Game Materials are defined and loaded only once in the slb-gamematerials.lua file. That means you don't have to keep defining materials accross your levels.

  3. Level Settings: these settings affect all bodies in the level that defines them. If a level defines an attribute that was already defined in the game settings, the level attribute will override the game attribute.

  4. Level Material Settings: these settings affect all bodies that are of this material type. A level material attribute overrides game materials, level and game attributes.

  5. Body Settings: these settings are set in a body and affect only the body that defines them. An attribute defined in a body overrides the same game, level and material attribute. It is specific to this body only.

To make things clearer, let's see some examples:

  1. A game with Game Settings only and defined friction = 0.5. All bodies in all levels will have friction = 0.5.

  2. Game Settings: friction = 0.5 and density = 0.8. And then let's say we have Level 01 which doesn't define any attribute and Level 02 which defines friction = 0.3.
    - All bodies in Level 01 will have friction = 0.5 and density = 0.8.
    - All bodies in Level 02 will have friction = 0.3 and density = 0.8.

  3. Game Settings: friction = 0.5 and density = 0.8. And then let's say we have Level 01 which doesn't define any attribute and Level 02 which defines friction = 0.3, Level 03 which defines friction = 1.0 and also defines a material = ice with friction = 0.1 and density = 12.
    - All bodies in Level 01 will have friction = 0.5 and density = 0.8.
    - All bodies in Level 02 will have friction = 0.3 and density = 0.8.
    - In Level 03 all bodies with no assigned material will have friction = 1.0, density = 0.8. Bodies set as material = ice will have friction = 0.1 and density = 12.

  4. Game Settings: friction = 0.5 and density = 0.8. And then let's say we have Level 01 which doesn't define any attribute and Level 02 which defines friction = 0.3, Level 03 which defines friction = 1.0 and also defines a material = ice with friction = 0.1 and density = 12, Level 04 which has a material = wood with friction = 0.8 and has a body set as wood, but with its own settings as density = 12.
    - All bodies in Level 01 will have friction = 0.5 and density = 0.8.
    - All bodies in Level 02 will have friction = 0.3 and density = 0.8.
    - In Level 03 all bodies with no assigned material will have friction = 1.0, density = 0.8. Bodies set as material = ice will have friction = 0.1 and density = 12.
    - In Level 04 all bodies with no assigned material will have friction = 0.5 and density 0.8. Bodies set as material = wood will have friction = 0.8 and density = 0.8. This level has also a body which is material = wood and defines its own density, so it will look like: friction = 0.8 and density = 12.

A may have attributes from all levels of settings, let's see an example:
Game Settings: density = 10
Level Settings: friction = 0.6
Material Settings: ice, image = iceBlock.png
Body Settings: isSensor = true, material = ice

This body will have the following attributes:
density = 10, friction = 0.6, image = iceBlock.png, isSensor = true

You could also override any attribute: Body Settings: isSensor = true, material = ice, density = 8, so the body will have the following attributes:
density = 8, friction = 0.6, image = iceBlock.png, isSensor = true

As you can see the deeper the settings definition, the more it will override earlier settings levels. That means attributes can be very specific as well very generalist - a flexible tool. You can work with them in any amount and level, just adjust as you need. That means you can have levels with dozens of materials, levels with no materials but having lots of body settings and so on.

Attributes Aliases

Before we dive in about each kind of attributes settings, let's learn about a feature in Corona SVG Level Builder that makes you type less: aliases.

Almost every attribute has an alias in Corona SVG Level Builder. Per example, instead of typing bounce = 0.2, you can simply type b = 0.2. You can freely use aliases, they don't affect performance nor memory.

The complete list of attributes and what they are translated to:

AliasAttribute
activeisBodyActive
adangularDamping
avangularVelocity
bbounce
bgdirbgsDir
bgDirbgsDir
bgsdirbgsDir
bodyActiveisBodyActive
bulisBullet
bulletisBullet
c custom
cust custom
dampinglinearDamping
dedensity
dendensity
dirdirectory
ffriction
fixedRotationisFixedRotation
fixedrotationisFixedRotation
frisFixedRotation
h height
iimage
ibisBullet
ifisFixedRotation
imgimage
isisSensor
ldlinearDamping
lineardampinglinearDamping
mmaterial
matmaterial
sensorisSensor
sheet spriteSheet
sleepisSleepingAllowed
ss spriteSheet
tbodyType
typebodyType
vvertices
velxvelocityX
velXvelocityX
velyvelocityY
velYvelocityY
vertsvertices
vxvelocityX
vyvelocityY
w width

Body Types

You can also alias the Physics Body Types: static, dynamic, or kinematic.

You probably won't need to set a body as static, since all bodies are static by default. But once you assign a density to a material or direct into a body, the body will be automatically dynamic. Also if you need it to be kinematic you need to set it by yourself with bodyType = kinematic.

Alias Body Type
d dynamic
dyn dynamic
k kinematic
kin kinematic
s static
sta static

Examples:

Game Settings

To change the Game Settings attributes, open slb-svgparser.lua and change the SETTINGS variable (around line 63-65) as you need:

local SETTINGS = {
	-- Physics properties
	DEFAULT_FRICTION 			= 0.2,
	DEFAULT_DENSITY 			= 5,
	DEFAULT_BOUNCE				= 0.8,
	DEFAULT_GRAVITYX			= 0,
	DEFAULT_GRAVITYY			= 9.8,
	DEFAULT_SCALE				= 30,
	DEFAULT_POSITION_ITERATIONS	= 8,
	DEFAULT_VELOCITY_ITERATIONS	= 3,
    
    -- Paths
	DEFAULT_MAPS_FOLDER			= "",
	DEFAULT_GRAPHICS_FOLDER 	= "graphics",
	DEFAULT_BACKGROUNDS_FOLDER  = "backgrounds"
    
    -- Default color for colored background / vector rectangles and ellipses
	DEFAULT_FILL_COLOR			= "#ffffff",
    
    -- Spritesheets file names preffix, example: x-gameobjects.png
	SPRITESHEETS_PREFIX			= "x-",
	SPRITESHEETS_IPAD_OWN_VERSION = true,
	SUFFIX_IPAD					= "-ipad",
    
    -- Content scaling
	MAPS_SCALE					= 1,
}

The _FOLDER attributes have to contain a folder name with a path relative to the root folder. So if you store the maps (levels) inside assets/maps, change DEFAULT_MAPS_FOLDER to: "assets/maps". On the other side if you want to store in the root folder, just change to ""(empty string).

IMPORTANT NOTICE: If you want your game to run on Android devices, you have to store your SVG files in the root folder, so leave DEFAULT_MAPS_FOLDER an empty string: DEFAULT_MAPS_FOLDER = "" and save all your SVG files in the root folder. That is a limitation from Corona itself.

Level Settings

To set the attributes of a level, open the level svg file in Inkscape, open the XML Editor (SHIFT + CONTROL + X | Edit, XML Editor... | ), click the first node (the svg:svg one) and add a level attribute. For the content, you have to type one or more attribute (or its alias) from the list, separated by a comma (,), with their respective values:

Here is an example of how you should enter the value (remember: you always have to click Set once you make any change within an attribute in the XML Editor):
Level Settings

Notice that you can also override the default Graphics and Backgrounds folder with the attribute graphicsDir and bgsDir respectively. This can be useful if a level has assets in a different folder other than the default one.

Level Materials Settings

Materials allow you to group related attributes and assets in one property, and then you just have to assign a material name to your elements (bodies) that share these same properties, saving time, and allowing an easy way to update these attributes later, since you just need to update the material settings, not each body settings.

Think of a material as a real element, e.g. ice, wood, fire, etc. Ice, anywhere shares the same properties: low friction, it's blue and white, it is made of water, etc. Wood has moderate to high friction, brown, etc. On terms of Corona SVG Level Builder, you can create a material which defines any of the supported Physics Properties as well any of the extra attributes: image, frames, custom attributes, notDrawn, etc. Example of elements that share common attributes and may be defined as materials: blocks for a platformer, doors, traps, pickup items, etc. You can create any amount of materials.

Examples:
Material = ice, attributes:
friction = 0.2, image = iceBlock, isSensor = false

Material = coin, attributes:
image = coin, type = kinematic

To create materials, with a SVG file opened, open the XML Editor (SHIFT + CONTROL + X | Edit, XML Editor... | ), click the first node (the one that starts with <svg:svg) and on the right panel in the small text box, type MATname where "name" is the name you want for this material. Then on the big text box, type the attributes separated by comma (,). Once you are finished, click Set.

NOTE: You have to put an attribute bodyType (or its aliases type or t) if you want a material to set a body as Dynamic or Kinematic. A material with density doesn't make a body dynamic (as opposite to setting a density direct into the body).

To assign a material to a body, just add a material (or mat) attribute to it with the material name. See Body Attributes and Settings.

Here is an example of a material definition:
Material Definition

Game Materials Settings

Level Materials are useful but you need to define them in the header of each level. That is ok if each level uses their own set of elements.

What about games where the levels share the same elements? With only "Level Materials" you would need to define the same materials in each level, even if they are the same!

That's why you can also have "Game Materials": materials that are defined only once and shared along all of your levels. You define game materials in the file slb-gamematerials.lua inside the table gameMaterials. This file is automatically loaded by the SVG Parser and you have access to these materials across all your levels.

As an example let's consider a game where you have a zombie and a type of block to construct the levels. This is what the slb-gamematerials.lua file for this game could look like :

local gameMaterials = {
	brick = {
		t = "static",
		i = "brickImageName",
		width = 45,
		height = 20,
		friction = 0.5,
		bounce = 0
	},
	
	zombie = {
		t = "dynamic",
		i = "zombie",
		frames = "idle:1:1:100:0; walking:2:5:200:0",
		width = 40,
		height = 100,
		
		custom = {
			health = 120,
			
			lootRate = {
				coin = 10,
				ammo = 20
			}
		}
	}
}

To assign a game material to a body you follow the same steps as assigning a level material: adding a material attribute to it, followed by the material name, example: material = zombie.

Body Attributes and Settings

Setting body attributes is probably the most important step when working with the Corona SVG Level Builder. With that you give life and behavior to what you are drawing in Inkscape. As said on Levels and Types of Attributes Settings there are four ways of setting attributes. Game and Level settings affects all bodies without custom attributes and Materials affect only the bodies of a material kind. Now it is time to direct finally set the bodies attributes or assign a material.

You can direct assign any of the Physics Properties to a body, assign a material and assign an image.

To set and change a body's attributes, select an element you drew (click on it), open the XML Editor (SHIFT + CONTROL + X | Edit, XML Editor... | ) and the body's node will be selected. On the right panel you can enter the attribute name (in the smaller text box) and the attribute value (in the bigger text box).

Example of a body with an attribute image = h (using the alias i) and density = 10:
Body Attributes

To assign a material, just add an attribute named material (or any of the aliases), and put the material name as value:
Assigning a Material

As seem on Levels and Types of Attributes Settings, remember that you can have a body with its own attributes and a material assigned. The body attributes will override any attribute that is present in the material.

Custom Body Attributes

Consider an example game where you add coins, and then you want to set the value of the coin. The "value" can be set as a custom attribute, additionally to all attributes you already add. Other examples could be the health of an enemy type, the score for a breakable block, etc.

Put your custom body attributes inside the custom XML attribute separated by commas:
Custom Body Attributes

A material can also have custom attributes. As the default SVG Parser behavior, a body custom attribute will override the material ones. But if there are attributes in the material that aren't present on the body custom attributes list, the material attributes will still exist in the body's context.

To access a custom attribute in your code, index the body with the custom key and then the attribute name:

body.custom.value
body.custom.shouldSpin

Custom Game Material Attributes

Since Game Materials are set in a lua file and not in a SVG node, their custom attributes can contain lua tables. This is useful when a material has to define lots of different values.

An example is a block in a slingshot game and you want to set different forces, from different sources that can make the block break, as well set the score value for this block:

blockWoodBig = {
	t = "dynamic",
	i = "woodBig",
	frames = "normal:1:1:100:0; hurt:2:1:100:0;",
	w = 24,
	h = 24,
	density = 2,
	
	custom = {		
		score = 50,
		
		forceToDestroy = {
			default = 20,
			bigBall = 10,
			midBall = 15,
			smallBall = 18
		}
	}
}

To access custom material attributes you follow the same route as the custom body attributes:

body.custom.forceToDestroy.bigBall
body.custom.score

Custom Level Attributes

You can also add custom attributes that you can read once the level is parsed. Examples of level attributes are the OpenFeint Leaderboard ID, Level Speed, Highscore ranks (10.000 = 1 star, 12.000 = 2 stars), whenever you need on a higher level just after loading the level.

Set them in the level's root node, inside the level attribute, separated by comma:

Level Custom Attributes

To access the custom attributes, refer to the attributes index of your loaded level:

local level = svg:new("levelFile")
level.attributes.openfeintLeaderboard
level.attributes.anotherCustomAttribue
-- etc...

Assigning Images from Files

There are two that you can also easily assign images and graphics to your elements: direct from file and from spritesheets.

To assign an image from file to an element, select the element/body in your SVG file in Inkscape, open the XML Editor (SHIFT + CONTROL + X | Edit, XML Editor... | ) and add an attribute image (or its aliases i or img). For the value, type the image name with extension, example: image = platform1.png, but if the image is the default type (PNG), then you don't have to type the extension, just the name, example: img = platform1.
Assigning Images

You can also point a subfolder name, example: img = platforms/platform1.

Your images (and also any subfolders) have to be inside the graphicsDir you set for the level (level specific) or if you haven't set Level Settings the image has to be inside DEFAULT_GRAPHICS_FOLDER from the Game Settings (more about this on Levels and Types of Attributes Settings, Game Settings and Level Settings).

If your game or level has a default spritesheet but you want an image to be loaded from a file instead, add the attribute fromFile = true to the element; this will force the image to be loaded from file and the spritesheet won't be considered for this body.

Introduction to Spritesheets

With spritesheets you can have your bodies graphics in one big image file, as well you can easily create animations and state changes with frames. Also there will be only one image loaded into the Texture Memory, and just one process to load this image, instead of loading dozens of smaller images. NOTICE: The Corona documentation calls spritesheets as "2D animations packed as multiple frames into a single texture image", but notice that you can and should use spritesheets in any game, even to standalone game elements.

You can safely create games only with spritesheets, with the exception of some external background images.

Corona SVG Level Builder supports spritesheets exported from TexturePacker and deals with them with the SpriteGrabber library. It can then load one or multiple spritesheets for a level or for the whole game.

A spritesheet will be unloaded from memory once you unload a level, except when you set it as a persistent spritesheet, which should be most of the cases for memory and performance issues.

There are 3 ways of loading them:

  1. Game spritesheets (loaded in your SVG Parser instance and shared accross all levels of this instance).
  2. Level specific (defined as a level attribute and loaded only when the level is loaded).
  3. Externally (loaded by you manually and shared accross all levels, used in conjunction with game spritesheets).

Game Spritesheets

A game spritesheet is loading with your SVG Parser instance. To load one or more game spritesheets you have to provide their name in the svgparser:new configuration table.

To load one spritesheet with your level add the attribute spriteGrabber to the loading configuration table with the spritesheet name. The name can't contain the SPRITESHEETS_PREFFIX you set in the Game Settings:

-- Load the level with the spritesheet "x-game"
local level = svg:new("levelFile", {spriteGrabber = "game"})
To load more than one, separate the names with commas:
-- Load the level with the spritesheets "x-game" and "x-map"
local level = svg:new("levelFile", {spriteGrabber = "game,map"})
But even altought they are game spritesheets, they will be unloaded once you call svgparser:cleanUp and loaded again once you call svgparser:new for a new level. To avoid that behavior, load them as persistent, by putting a true argument after their name. This way you can keep loading levels with the spritesheet that was loaded only once:
-- Load the level with the persistent spritesheets "x-game"
local level = svg:new("levelFile", {spriteGrabber = "game=true"})

Level Spritesheets

You can load a spritesheet direct from a level, in cases of spritesheets unique to a level or some more, so they aren't loaded for all levels. To load a spritesheet from a level add a spritegrabber attribute to the level's root node with the same format as you set Game Spritesheets: name = persistent:
Level Spritesheet

It may look senseless to set a Level Spritesheet as persistent, but if they are used across lots of levels, setting it persistent will keep them in memory and loaded only once. If it is used accross all levels, then it is best to with a Game Spritesheet.

External Spritesheets

There are cases in which you share a spritesheet accross all your game (GUI, tutorials, etc), not only the levels. This means you can't rely on the SVG Parser to load and create the spritesheet, you create it by yourself with SpriteGrabber. But then when loading a level, the SVG Parser would end up creating the spritesheet again.

To avoid that and save memory and performance resources, you can set a spritesheet to be external when loading a level. In your level configuration table add the spriteGrabber attribute as in the Game Spritesheets and the externalSpriteGrabber one, which is a table in which you point to your SpriteGrabber grabSprite and spritesheet variables:

-- Import SpriteGrabber
local grabber = require("SpriteGrabber")

-- SpriteGrabber helper
function createGrabSprite(sheetName)
	local nameSuffix = suffix
	local sprites = grabber.grabSheet("x-" .. sheetName .. nameSuffix)
	
	return function(name, sequence)	
		local sprite = sprites:grabSprite(name, true, sequence)
		sprite.xScale, sprite.yScale = scale, scale
		sprite:setReferencePoint(display.CenterReferencePoint)
		return sprite
	end, sprites
end

-- Create the grabSprite helper function and a pointer to the spritesheet
local grabSprite, spritesheet = createGrabSprite(sheetName)

-- Use the spritesheet somewhere...
-- etc...

-- Now load the level with spritesheet name and external variables
local level = svg:new("level", {spriteGrabber = "game=true", 
	externalSpriteGrabber = {
		grabber = grabSprite,
		sheet = spritesheet
	}
})

Assigning a Spritesheet to a body or material

Since Corona SVG Level Builder supports multiple spritesheets, before you set a sprite or frames to a body or a material, you need to tell them what spritesheet they have to look the sprite from, even when ytou have only one spritesheet. You do that by adding a spriteSheet = name (or sheet or ss) attribute to the body or material.

But that can be time consuming if you have only one spritesheet or the same spritesheet name is required all over the elements. You can set a spritesheet to be the default one, then when assigning a sprite name to a body, you don't need to tell what the spritesheet is the sprite from.

You define a default spritesheet adding a defaultSpriteSheet attribute to you the level attribute of your level root node or in the level creation configuration table:

-- Load the level with the spritesheets "x-game" and set it as default
local level = svg:new("levelFile", {spriteGrabber = "game", defaultSpriteSheet = "game"})

Or in the level root node:
Default SpriteSheet

Assigning Images from Sprites

Once you loaded your spritesheets and assigned a spritesheet name to a body or material, you can set a body or material image to be from the spritesheet.

To do that you simply put the name of the sprite in the image attribute (in the same way you assign an image from file) of your body or material. Instead of loading from file, the image will be taken from the spritesheet:

Assigning Sprite

Assigning Frames and Animations

The most powerful use of spritesheets is to output animations. To do that, after all the spritesheet steps (loading, setting a default one or a spritesheet name and assigning a image) you add a frames attribute to the body or material.

Note that even with frames, you have to assign an image attribute to the body or material, in this case the image has to be the first image from the frames list.

The value of the frames attribute has to be in the SpriteGrabber format:
poseName:FIRST_FRAME_POSITION:AMOUNT_OF_FRAMES:DURATION:REPEAT

The FIRST_FRAME_POSITION is relative to the image you assigned to the body. So let's say you have 6 frames, where the names are coin1, coin2, etc, you assign the body with image = coin1 and then the FIRST_FRAME_POSITION is 1 (since you want the first image to be part of the animation) and the AMOUNT_OF_FRAMES is 6.

Separate poses with ;. To play a pose you have to call body:pauseClip("poseName") in your code. To pause, you call body:pause().

Let's see a step by step example:

Assume you have a walking monkey with two poses: walk to the right and walk to the left. Each pose has 2 frames (1 and 2 for right, 3 and 4 for left):
Monkey Sprites

We create the body with the frames. Notice that right starts with the first frame (right:1) and has 2 frames. Left starts with the third frame (left:3) and has 2 frames:
Monkey Poses in a Body

Or the same in a game material:

local gameMaterials = {
	monkey = {
		t = "static",
		
		-- We need to set an image as the first and default frame
		img = "monkey_walk_1",
		
		-- The frames
		frames = "right:1:2:200:0; left:3:2:200:0",
		
		width = 70,
		height = 84
	}
}

return gameMaterials

Then we load the level and animate the body:

-- Load level with spritesheet
local level = svg:new(actualExampleName, {spriteGrabber = "game=true", defaultSpriteSheet = "game"})	

-- Do something with the level..
-- .....

-- Grab the body with the ID you set
local monkeyNpc = level.bodies.monkeyNpc
-- Call playClip with the pose name
monkeyNpc:playClip("left")

Automatically playing a pose animation

If you want a body to animate automatically by default, you can add an attribute playClip = "poseName" to your body or material settings, instead of calling body:playClip():
Play Clip Attribute

Even if this body's animation starts automatically you can still call body:playClip() in your code to change poses.

You can also add a pause = true attribute to a body or material, so even if it has a default playClip it will start paused.

Displaying level bodies as Vector Graphics

You can also display what you draw as Corona vector graphics (i.e. primitives). That means you don't need to always assign images, if that applies to your game or style your are seeking.

Notice that if the body has an image assigned, its vector version won't be shown. Also to show vector graphics you have to take care of 2 possible attributes:

  1. Loading you level with the drawVector = true attribute in the configuration table.
  2. Adding a drawVector = true attribute to the body or to the material.

The body will be drawn with the same color and stroke as you drew it in Inkscape.

If there are bodies that you don't want them to be drawn, you can add a notDrawn attribute to them. An example is a bezier path in which you drew only to add collisions to your level background; you don't want the path to be drawn, just that the collisions work, so in this case set as notDrawn.

Images as Bodies

Other than drawing the bodies you can also import images to serve as bodies (Go to File, Import... (CTRL + I) and select the image file). But notice that this will be treated as a rectangle body, except if you assign a material for it with the isCircle attribute.

Importing images is a fast way of assigning an image attribute, and seeing part of the final result. Other than that you can assign all other attributes normally.

Identifiying Bodies: ID

An ID identifies the body instance. Id's must be unique, there shouldn't be two ore more bodies with the same body id. An ID is set automatically by Inkscape to each element you draw in your level:

Naming Bodies

You can actually change the ID of a body, just make sure it is unique. If you need to identify similar items: change their names or material instead; or put them in the same layer.

Identifying Bodies: Name

You can add a name attribute to your body. The name can be set directly into the body instance or in the material, this way all bodies from this material will share the same name.

If you don't set a name attribute, the body name will be the material name. Notice: not the material name attribute, but the material name itself.

Examples:

  1. Material: Ice. And this material has an attribue name = "iceBlock". iceBlock will be the body name.
  2. Material: Fire. And this material doesn't have an attribue name. So bodies set to this material will have the name Fire.

And if your body doesn't have a name attribute nor an assigned material, its name will be its id.

Identifying Bodies: Layers

See Multiple Layers and how to filter and add categories to the elements of your level.

Multiple Layers and how to filter and add categories to the elements of your level

Each Inkscape layer will represent a Display Group. Every element you draw inside this layer will then be part of its display group. With that in mind you can consider each layer to be of a different category.

Consider you are making a platform game and in your level you want to put the level blocks, targets and powerups. For each one of these groups you are going to create a layer:

Layer Names

Then when you load the level let's say you want to access only the targets to add an AI behavior to each of them. You can do that by simply getting the display group with id "targets" and then you can loop through all of its bodies.

Example:

-- Load the level
local level = svg:new("platform1")
	
-- Loop through all the level groups (layers)
for i=1, level.group.numChildren do
    local innerGroup = level.group[i]
    
    -- The id attribute is the layer name you put in Inkscape
    local groupName = innerGroup.id
    
    -- Enemies
    if groupName == "targets" then
    
        -- Loop through enemies/do anything you want with the Display Group
        for enemyIdx = 1, innerGroup.numChildren do
        	local enemy = innerGroup[enemyIdx]
            doSomething()
        end
    
    -- Powerups
    elseif groupName == "powerups" then
    	-- Hide the powerups
        innerGroup.isVisible = false
        
    -- etc...
    end
end

Custom Shaped Bodies

Along with having rectangles, ellipses and all kind of paths, you can also have custom shaped bodies, with custom vertices. To do so, draw a rectangle or an ellipse and add a vertices (or its aliases v or verts) attribute to a body or a material. For the value, put the vertices coordinates, comma separated. The total number of vertices has to be even.

For now, Corona SVG Level Builder supports only vertices from the free Ludicrous Software's Corona Physics Shape Panel for Fireworks.

Custom Bodies