Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

21. February 2017

 

Somewhat delayed from the rest of the Defold Engine tutorial series, I realized there was a major gap in subjects we covered... GUI programming.  Defold actually has some really solid UI functionality built in, and in this tutorial we are going to look at the basics of handling a UI in Defold. Well very conventional in it’s approach, if you’ve gotten accustomed to the Defold way of doing things, you will find Defold’s approach to handling UI remarkably consistent to the way you do just about everything else using the Defold game engine.

 

As always, there is an HD video version of this tutorial available here.

 

In this tutorial we are going to implement the simplest of UI, but all of the concepts of a much more complicated interface can easily be extrapolated from what we cover here. We are going to create a UI that pops up when the user hits the ESC key, dimming the existing screen, showing the UI, handling input, then un-dimming the UI.  There is a ton more UI functionality available in Defold, but it should be fairly easy to pick it up once you’ve got the basics down.  So without further ado, lets jump right in.

 

A UI in Defold consists of two different file types, a .gui and a .gui_script file.  A gui_script file is just a traditional lua script file, but has access to the gui namespace.    Let’s take a step by step look at creating a UI that appears when you hit the ESC key and handles a simple button being clicked.

 

First we need a font, drag any applicable TTF file to your project.  I personally created a folder called MyFont and dragged it there.  Next I created a Font file in the same folder.

image

 

Next open the newly created Font file and select the ttf file you just imported.  Please note that the filter is broken and you should manually type *.ttf to locate your font.

image

After selecting the font I also increased the size to 30pts.  This is aesthetic and purely optional.

 

Now that we have a font selected, we need to define an Input map.  I fully describe the process here for more information on how Input Maps work in Defold.  This are the bindings I created:

image

 

Next we create our gui file.  Simply select Gui File:

image

 

We can use the Gui File to arrange the controls that make up our UI.  Here are the options:

image

 

In this simple UI we are simply going to create a button by creating a box then adding a text label to it.  We will also create a label telling the user to click the button.  First we need to set up our font that we created earlier.  In the GUI editor, right click Fonts and select Add Font:

image

 

When prompted, select the font you just created:

image

 

Now right click Nodes and add a Box.  Once created it can be positioned by hitting W then moving manually.

TransformBox

 

Next right click the newly created box node and create a child Text field:

image

 

Child nodes automatically inherit the position of their parents.  With the Text node selected, lets set it’s font and text, like so:

image

 

I also created another Text field telling the user to click the button.  This one in the root of the GUI hierarchy and not parented to the box.  You’re outline should look something like:

image

 

While your Gui layout should look something like:

image

 

Now that we have a gui file, let’s right a script that will display it.  In our main.collection I simply create a new script and attach it to the default logo objecct.

image

 

Now of course we need to add the UI to our game object.  Create a new root level GameObject named UI, then add component from file and select our gui file:

image

 

So now you main.collection should look something like:

image

Now we enter the following code for main.script:

function init(self)
	-- we want focus and to hide our UI until needed
    msg.post(".", "acquire_input_focus")
    msg.post("UI","disable");
end


function on_message(self, message_id, message, sender)
	-- Wait for a message from the UI layer that the UI has been dismissed
	-- un-dim our sprite
    if(message_id == hash("DONE_UI")) then
    	go.set("#sprite","tint.w",1.0)
    end
end

function on_input(self, action_id, action)
	-- If the user hits the ESC show the UI and dim our sprite
    if(action_id == hash("ESC") and action.released) then
    	-- UI needed now, reenable
    	msg.post("UI","enable")
    	go.set("#sprite","tint.w",0.2)
	end
end

 

This code does a couple things, first on input it tells Defold we want to get input messages.  We also start out by disabling the UI, by sending it the built-in message disable.  When the user actually hits the escape key, we send a message to re-enable the UI layer.  We also dim the logo sprite so it’s not visually in focus when the UI is active.  Also note we wait for the DONE_UI message to undim our sprite.  This is sent by the UI script, which we will create now.

 

If you select your .gui file, in the properties you will notice there is a setting for Script.

image

 

There is a special kind of script, .gui_script, that is used to control gui objects, the Gui Script File.  Let’s create one in the same folder as our .gui file:

image

 

This is a standard lua script, but it has access to the gui namespace.  Once you’ve created your gui_script, set it as the script for your gui file.  Now enter the following script:

function init(self)
	-- We want input control.  AKA, pump input to the UI
    msg.post(".", "acquire_input_focus")
    
end

function on_message(self, message_id, message, sender)
	-- Expect to be enabled by main when needed.  Acquire focus and set text back to click me
	if(message_id == hash("enable")) then 
		msg.post(".", "acquire_input_focus")
		gui.set_text(gui.get_node("text"),"Click Me")
	end
end

function on_input(self, action_id, action)
	-- handle left clicks.  On left click, see if click was within box
	-- if so change our text (this wont actually be seen), disable ourself and pass a message back
	-- to logo that we are done so it can undim itself
	if(action_id == hash("LEFT_CLICK") and action.released == true) then
		local box = gui.get_node("box")
		if(gui.pick_node(box,action.x,action.y)) then
			local text = gui.get_node("text")
			gui.set_text(text,"Clicked")
			msg.post(".","disable")
			msg.post(".","release_input_focus")
			msg.post("/logo",hash("DONE_UI"))
			
		end
	end
end

 

This code waits for the enable message then sets input focus so the gui can receive input messages from Defold.  It also illustrates how you could change the text of a component within the gui.  The most important logic is in the on_input event handler.  We wait for the LEFT_CLICK input.  We then check to see if the click was within our box, if so we set the text of our control ( which is somewhat pointless as it’s about to be hidden! ) to “Clicked”, disable our self, release input focus then send the message DONE_UI back to main.script.  Now if you run the code:

GIF

 

Of course we only scratched the surface of what you can do in a Defold gui, but that should certainly get you started!

 

The Video

Programming , ,

3. October 2016

 

Welcome to the next part in our ongoing Defold Game Engine tutorial series.  In this tutorial we are looking at working with the integrated Box2D physics engine built into the Defold engine.

 

As always there is an HD video version of this tutorial available here or embedded below.

 

The Defold engine makes it extremely easy to work with physics but is rather minimal in it’s implementation.  Let’s jump right in.

 

Creating a Collision Object

 

The heard of implementing physics in Defold is the Collision component.  This is composed of two part, the Collision Component that describes the physical attributes of a game object, and the Physics shape, which defines it’s dimensions.  I start off by creating this simple Gameobject, the image used in the sprite is 128x128 pixels:

image

 

Now we simple add a new physics component to the game object.  Right click the Game Object in the Outline, select Add Component, then select Collision Object:

image

 

Here are the default properties of a Collision Object:

image

 

Type is important and we will cover that shortly.  Mass is the weight of the object relative to dimensions, friction is how one surface reacts to another ( think traction ), restitution is the “bouncy-ness” of an object, linear damping and angular damping determine how motion of the object degrades over time, locked rotation determines if the physics simulation will rotate the attached game object or not.  Group and Mask are used to determine which collision objects interact with other collision objects.  Objects in the same group will collide, while objects not in the same group, or if that particular group isn’t added to the Group value ( comma separated ) will not interact.  So think of Group as the physics identity or type(s) this object belongs to, while Mask is the groups that object will interact with.

 

Next we need to define the shape of our physics object.  Simply right click the Collision Object and select Add Shape:

image

Next pick Box:

image

 

In the properties, set the Width and Height to match the size of our source image.  Depth is the value along the z-axis and can be left at the default value in most cases.

image

 

Now that we have our Collision object define, simply create a couple instances of our game object in the scene and the results are immediately demonstrated.

GIF

 

You probably didn’t want the boxes just dropping out of the world now do you?  So we need to create a physics body for the “floor”.  We can easily do this by creating a new Game Object in main and adding a physics body to it.  Like so:

image

image

 

The problem here is, our newly created floor will be effected by gravity, just like every other object in the scene!  This is where the Type of the Collision Object becomes important:

image

 

So far we have only used the default, Dynamic.  A dynamic object is a fully simulated physics object.  It will take part in the simulation, will be part of the simulation and will be affected by the simulation.  Static is what we want in this situation.  A static object will be part of the simulation, but will not be effected by it.  This is your proverbial unmovable force!  So other objects in the simulation will be able to hit the collision object and they will be affected by the collision, but the static object will not be changed in any way.  Kinematic objects are special objects that are generally moved directly by the character or code but also take part in the physics simulation and will be affected by it ( think that players sprite for example ).  Triggers on the other hand are simply shapes in the world that can detect a collision and can be hit, but wont have any affect on anything in the world.  They are often used to detect movement, for example the goal area in an air hockey game.

 

Now with our floor object set to static, our updated results!

gif2

 

So, how exactly do we control global physics properties, such as gravity?  These settings are available in the .project file:

image

 

Physics and Code

Now that we know how to set up a physics simulation, let’s look at how to deal with it in code.  For we are going to look at how you respond to a collision in code.  As you might be able to guess, messages are used.  Let’s look at a simple program that responds when a collision occurs.  Attach a script to your box object and add the following code:

 

function on_message(self, message_id, message, sender)
    if message_id == hash("contact_point_response") then
    	msg.post("@render:","draw_line", { 
    		start_point = vmath.vector3(message.position.x -40, message.position.y - 
    		40, 0),
    		end_point = vmath.vector3(message.position.x +40, message.position.y + 40, 
    		0), 
    		color = vmath.vector4(1,0,0,1) })
    	msg.post("@render:","draw_line", { 
    		start_point = vmath.vector3(message.position.x -40, message.position.y + 
    		40, 0),
    		end_point = vmath.vector3(message.position.x +40, message.position.y - 40, 
    		0), 
    		color = vmath.vector4(1,0,0,1) })	
    end
end

This code simply listens for the contact_point_response message which is sent when a collision occurs with the attached game object.  When such a collision occurs, this code draws an X centered about the collision point by sending the draw_line message to the render subsystem.

There is a great deal of information about the collision passed along in the message parameter:

image

As you can see, information on what object was collided with, how fast, groups, velocity, mass etc are all available in the contact_point_response message.

 

On final topic to cover is occasionally you are going to want to be able to apply force directly to a physics object using code.  This is also easily accomplished using the following code:

    	msg.post("#collisionobject", "apply_force", { 
    		force = vmath.vector3(0,5000,0),
    		position = go.get_world_position()})

Again using Defold’s messaging system, we send the apply_force message to our Collision Object component.  This applies 5000 newton of force along the Y axis.  Added inside our collision handler, it makes for some interesting results!

gif3

 

The Video

Programming ,

12. September 2016

 

Welcome to the next part in our ongoing Defold Game Engine tutorial series.  Today’s tutorial is going to show an area where the Defold engine really shines, creating 2D tile based levels.  This way of creating levels is to paint levels in a data structure called a tilemap, which itself is a collection of tiles.  A tile is simply a portion of an image that can be drawn over and over, much like you could use Lego blocks to create a castle.

 

As always there is an HD video version of this tutorial available here.

 

For this tutorial we need a tileset to work with.  This is simply an image composed of tiles, in this case with no spaces or padding between them.  I personally am using the tiles from opengameart.org in the Free Platformer Game tileset.  I have taken these individual tiles and merged them together into a single image you can download below.  (Be sure to click the image to get the full sized version.  In this example size does matter! ).

 

tilesThis is a 1024x512 pixel image composed of 64x64 pixel tiles.  Of course you can use whatever image you want, just be aware that if there is padding or different sized tiles your version is going to be different.

 

As always I assume you have gone through the prior tutorials in the series.  Alright, now that we are set up, let’s get going.

 

Creating a Tile Source

 

First things first, we need to create a directory for our level, tiles, images, etc.  I simply created a folder called level.  Inside this folder I created a directory called images and dragged the image above into that folder, like so:

image

 

Now we need to create a tile source.  You can think of this as the palette or selection of tiles we are going to paint with.  Don’t worry, it’s exceedingly easy.  Simply right click level, select New->Tile Source File

image

 

Called it tiles.tilesource like so:

image

 

Now in Outline make sure Tile Source is selected:

image

 

Now in the Properties panel, select the image file we added earlier for the Image property, then set Tile Height and Tile Width to 64.  Obviously if you used a different image you may have different settings here.

image

 

Now in your viewport you should see your tiles, with the grid drawn nicely around them like so:

image

 

All done creating our tilesource.  Make not of the collision property... we will come back for that in the next tutorial.  Make sure you save.

 

Creating a Tile Map

Now it’s time to actually create our tile map.  Once again right click the level folder and select New->Tile Map File.  Name this one map.tilemap:

image

 

Now in Outline make sure Grid is selected:

image

 

Now in the properties, pick out tilesource:

image

 

Now select layer1 in the outline window and we can begin painting!

 

In the viewport use the spacebar to bring up the tile source, then left click to select the active tile.  Now hit space again to hide the tile source and paint using the left mouse button.  You can also use the right mouse button to select multiple painted tiles to easily clone and reproduce compound tiles.

GIF2

 

If you need to paint tiles on top of other tiles, simply create another layer, right click Layers and select add:

image

 

The z order determines the draw order of tile layers:

image

 

Right click an empty space then left click to delete a tile if required.  Save before continuing on!

 

Using a Tile Map

Finally it’s time to put our newly created tilemap to use.  This is also simple.  Open your main.collection in the editor then add a new game object just like we did in the past.  Right click the game object and select Add Component From File:

image

 

Select your .tilemap file, and voila:

image

 

The Video

Design, Programming ,

24. August 2016

 

Welcome back to the ongoing Defold Game Engine tutorial series looking at all aspects of game development using the Defold game engine.  In this tutorial we are going to look at the process of playing sound and music in Defold.

 

There is an HD video version of this tutorial available here.

 

Playing sound in the Defold engine is simple, which is a double edged sword.  It’s extremely easy to add and play a sound file.  On the other hand the functionality provided is also quite simple.  Many things you may want to accomplish ( callback on sound end, fast forwarding/rewinding a playing audio file, positional audio, etc. ) simply aren’t supported.

Let’s start by adding some audio files to the project.  In my case I added a folder named audio and dragged in an ogg file and a wav file from Windows Explorer to Defold.  These are the two file formats supported.  The ogg file is an Ogg Vorbis file, a compressed streamed format similar to mp3 format but not patent encumbered.  Wav files are almost entirely uncompressed but require less processing power.  In a nutshell for longer form audio files, such as music, use an ogg.  For sound effects, use wav.  The end result should look something like:

image

 

Next we go ahead and create a sound component for our game.  You could parent your sound components to whatever game object you wish.  If it makes sense to create a music player game object and attach all the sounds to it, you could.  Or if you want your game objects (for example, the player) to own their own sound components, that’s alright too.  Select whatever game object you want to add the sound to, right click and select Add Component.

image

 

Next select Sound from the component list.

image

 

Here I am creating one for the music file first:

image

 

Hit the … button beside Sound and select the ogg file you dropped in earlier.  Notice in this case I changed the Group to music.  I repeat the same process for the wav file, instead named sfx. 

 

Now playing the sound effect using code is extremely easy and once again uses messages like so:

msg.post("#music","play_sound")

 

Simply post the play_sound message to the music component of our current game object.  Playing the sound effect file is the exact same process but instead post the message to the #sfx component like so:

msg.post("#sfx","play_sound")

 

We can also control the volume of the sound component, like so:

msg.post("#music","set_gain", { gain = volume })

 

Volume is a value from 0.0 to 1.0, where 0.0 is no volume, while 1.0 represents full volume.  Remember earlier when I changed the group for our music file from “master” to “music”.   Groups enable you to control several sound effects at once, for example muting all the playing songs or sound effects.  For example, we could mute all the sounds in the group music with the following call:

sound.set_group_gain(hash("music"), 0.0)

 

Here is the full source for this example:

-- Local variable for volume. 0 is none, 1 is full
local volume = 1.0

function init(self)
  msg.post(".","acquire_input_focus")
  -- start playing the background music
  msg.post("#music","play_sound")
end

function on_input(self, action_id, action)
  if(action_id == hash("SPACE_PRESSED") and action.pressed == true) then
    -- if user hits the spacebar play the soundfx file. 
    -- multiple presses will play multiple instances.
    msg.post("#sfx","play_sound")
  elseif(action_id == hash("ESC") and action.pressed == true) then
    -- on ESC mute the entire group "music"
    sound.set_group_gain(hash("music"), 0.0)
  elseif(action_id == hash("DOWN_ARROW") and action.pressed == true) then
    if volume >= 0 then
      volume = volume - 0.1
    end
    -- lower the volume of our music
    msg.post("#music","set_gain", { gain = volume })
  elseif(action_id == hash("UP_ARROW") and action.pressed == true) then
    if volume <= 1 then
      volume = volume + 0.1
    end
    -- increase the volume of our music
    msg.post("#music","set_gain", { gain = volume })    
  end
end

 

The Video

Programming

15. August 2016

 

Welcome back to the ongoing Defold Game Engine tutorial series, today we are going to build on the Sprites and Animation tutorial and look at three critical aspects of Defold game programming, scripting and messages.  Defold is programmed using the Lua scripting language which is beyond the scope of what we will be covering in this tutorial.  However we have already completed a Lua programming course for beginners available here.  If you are unfamiliar with Lua, it will teach you everything you need to know to get started with the language.

As with all tutorials in this series, there is an HD video version available here.

 

Setting up Input

 

If you created a default project, you will see a folder named Input, like so:

image

If for some reason you don’t have this input_binding file, you can create one by right clicking, selecting New->Input Binding File

image

The Input Binding File is a special file that maps various input devices to a text string that identifies the action to perform when that input occurs.  Double click the game.input_binding file and it will open in the editor:

image

You will notice there is a category for keys, mouse, gamepad, touch and text.  Right click the category you want to add an input control for and select the Add ___ trigger option.

image

 

This will create a new entry.  In the input value, drop it down and select the key/button/action you want to bind.  In the value name it.  In this example I’ve mapped KEY_SPACE to the event toggle_move.

image

 

The cool thing about this approach is you can map multiple input devices to the same action, like so:

image

 

Now the spacebar and left mouse button with both fire off the toggle_move action.  You will see how this works in just a split second.

 

Scripting

 

Now that we have some input firing, lets set up a script to handle it.  Building on the project we made in the last tutorial, add a script file to your game.  In my case it looks like:

image

 

We already covered the basics of creating a script in this earlier tutorial if you need to details on how to proceed creating a script.  In the previous tutorial we created an animation called walk.  Create another one called “Idle” using the same process, but add just a single frame of animation, so it looks like this:

image

 

We are now going to add the code to toggle between the two animation states.  In your freshly created .script file, add the following code:

local currentAnimation = 0

function init(self)
  msg.post(".","acquire_input_focus")
end

function on_input(self, action_id, action)
    if action_id == hash("toggle_move") and action.pressed == true then
      print("ACTION")
      if self.currentAnimation == 1 then
        msg.post("#sprite","play_animation", {id = hash("walk")})
        self.currentAnimation = 0
      else
        msg.post("#sprite","play_animation", {id = hash("idle")})
        self.currentAnimation = 1
      end
      
      return true -- input handled.
    end
end

 

There are a couple key things here… first you notice the local variable currentAnimation.  This is simply going to track which animation is playing so we can switch between them.

 

Next we have the init() callback function.  This function is called ONCE by the Defold game engine, when the game object this script is attached to is created.  This is where you would do your various initialization and setup logic.  In this case we are telling Defold that we want to have input sent to this game object.  That way when you hit the keyboard or press a mouse for example, this scripts on_input() function will be called.  This is done by sending a message, message passing is very important and we will cover it shortly.  For now know that the first parameter in the post() call is where to send the message.  “.” is shortcode for “to the object this script is attached”.  Meanwhile ‘#’ is shorthand for “to this script itself”.  Dont worry, we will cover this in more detail in a moment.  The second parameter is the message we want to send.   In this case we are sending the message “acquire_input”, which is a predefined message type in GameObject.

 

Now that we’ve told Defold we respond to input, we not implement the on_input() callback function.  First we check to see what the action id is, but this value will be encoded, so simply pass it into the hash() function.  Basically we test to see if our toggle_move action that we defined earlier has been fired.  Remember, this is wired to the left mouse button or spacebar being hit.  We also check to make sure it’s a pressed event (as opposed to a release).  Next we toggle our input, if our currentAnimation value is 0 we are currently walking so now we want to change to the idle animation, and vice versa.  Notice that we change the animation once again by using a message.  In this case we are passing the message “play_animation” to the object “#sprite”.  This refers to a fragment, part of an underlying message url… dont worry, it’ll make sense in a moment.  For now just think of #sprite as saying, send this message to the sprite component of this object. 

image

 

If you look at the documentation for any given class… such as Sprite, you will see the various messages it will respond to.

image

 

Sending and receiving messages is the core of how objects in Defold communicate.  It’s a way of having different objects able to communicate and share data or respond to actions or events, while remaining loosely coupled.

 

Now if you run this code, it will start with the player walking.  Hitting space bar or left clicking will fire off the toggle_move event, and the animation should now switch.  Let’s look a bit closer at how you can send messages between objects.

What I did is created a new folder named other, inside of which I created a game object named other and attached a script to it, named inventively enough other.script, like so:

image

 

In your main.collection, add an instance of other, like so:

image

 

Other does absolutely nothing, but is going to illustrate how two game objects can communicate with … um… each other.  Ugh.

In other.script, add the following code:

function update(self, dt)
  msg.post("main:/character", "marco", { msg = "You out there?", meaningOfLife = 42 })
end

 

The update() function is the callback called by the Defold engine every single pass through your game loop.  In this case we are simple sending a message to our character game object in the main folder.  The message is called “marco” (for marco/polo).  You will notice we also pass a table with some pretty useful data in it…  msg and meaningOfLife, the first a string the second a number.  The data you fill in this table is completely optional… in fact you dont need to pass data at all.

 

The important part to understand is the URL we are using to post the message to.  It’s a lot like the URL you use to go to a website.  The first part (in this case) is referring to the collection the target is in, the second part is the name itself.  It doesn’t work exactly like what you might expect though, as here is the structure:

image

The folder name has ZERO importance in this scenario… it’s just there as a handy way for you to organize things.  The root of the url (main:/) refers entirely to the name of the collection, then the remainder of the URL, refer to values within that collection.

So we are sending this message to the character game object inside main.collection:

image

 

If we had instead wanted to send the message directly to the sprite attached to the character, we could have sent the message to main:/character#sprite

 

Now we can modify our code inside main to listen for this message:

function on_message(self, message_id, message, sender)
  pprint(message)
    if(message_id == hash("marco")) then
      print("Polo")
  end
end

 

The on_message() function is called when the object your script is attached to receives a message.  In this case we check to see if the message was “marco”.  Again we encode it using the hash() function.  If you run this code you will see Polo written over and over in the console.  You will also see the data that was sent in the message, remember that table we encoded earlier.   Note the use of pprint().  This is a handy function that performs a pretty print of a table you pass in.  Basically it prints the table out in a nice easily read form.

 

There are a couple special message targets available as well.  @physics, @render and @system.  These actually send messages to the Defold game engine itself, the physics, rendering and system sub systems respectively.  For example, we can see that the render subsystem responds to the following messages:

image

 

So we could easily change the background color sending a message valued clear_color to @render like so:

msg.post("@render:","clear_color", { color = vmath.vector4(0,0,1,1) })

In this case our data is a Vector4 with the value (0,0,1,1).  This is an RGBA color value, basically saying no red, no green, full blue and full opacity.  AKA… blue.  This will cause our background color to be blue instead of black.

 

This messaging system may at first seem very alien, but it quickly becomes intuitive.  You do have to keep the reference handy to see what messages each object responds to.

 

Properties

 

Finally let’s look quickly at the concept of Properties before moving on.  You’ve already dealt with several built in properties.  For example, when you created a game object, it had several built in properties already defined:

image

 

You can also easily create your own properties.  This is a great way to make code reusable, or set it to so that a coder can code, but expose some data to a designer.  The process is simple, in our script file, simply add:

go.property("MyProperty",42)

To the top of the script file.

f you are wondering just where the heck go.property() came from, it’s simply a member of Game Object which you can think of as your base class.

 

You can define a property anywhere, except inside the various different Defold callbacks (such as Init()).  Now you can use this property anywhere just like any other local variable, like so:

print(self.MyProperty)

 

The cool part however is, now if you check in the Editor for that script, you will see the property is exposed and can easily be overriden:

image

 

The Video

Programming

Month List

Popular Comments