martes, 29 de diciembre de 2015

Parallax Scrolling in Love2d. Part 3: Different Camera Spaces

Hi!

This is the last installment of the series on parallax scrolling in Love2d. In the previous posts, we first discussed how we could implement this technique by defining a camera component and the concept of layers, and how we could reason about the two different coordinate systems that we had: the world and the camera coordinate systems. Consider reading these previous posts before going on, because this installment builds upon them.

We will see now how we can represent an object that is in a given camera space in another camera space, which can be useful for multiplayer games. The problem statement is depicted in Figure 1. We see that we have two cameras, each one representing a fragment of the same world. One of the cameras (camera 1) is in the position (x1, y1), whereas camera 2 is in (x2, y2). Again, for the sake of simplicity, we will focus on the X dimension, but the same reasoning applies to the Y dimension. Each camera follows a different player, namely player 1 and player 2, which have their positions in their camera spaces posPlayer1_cam1 and posPlayer2_cam2, respectively. Now, assume that we want to represent a ghost version of  player 2 in the camera space of player 1, so that player 1 can see the position of player 2. Which is the position of player 2 in the reference system of camera 1, that is, which is the value of posPlayer2_cam1?


 Figure 1. Problem statement

At first sight, the problem seems trivial, and for most cases, it actually is. We simply need to represent the (world) position of player 2 in relation to the camera. Therefore, if the position of player 2 is posPlayer2, and as usual we assume that players belong to layers with scale = 1, we know that:

posPlayer2_cam1 = posPlayer2 - posCamera1 (1) 

Likewise, the position where the player will be drawn would be:

posPlayer2_draw = posCamera1 + posPlayer2 - posCamera1 = posPlayer2 (2)

And that's it. This is what works in most of the cases.

However, there is a situation that we need to consider. Assume that there are obstacles with which the players can collide. If these obstacles belong to a layer with scale = 1, then everything works as we've just described. However, if obstacles belong to layers with a different scale, weird things happen. Suppose that obstacles belong to a layer with scale = 2. Then, as we saw in the previous post, advancing the camera u units result in the object being moved 2u units to the left. Therefore, if we used simply (1) or (2), player 1 would have the impression that player 2 collides (stops) before reaching the obstacle, as depicted in Figure 2. 


 Figure 2. Player 2 reaches the obstacle before it is perceived by player 1

This is happening because whereas the obstacles are moving with a rate of 2u units to the left, player 2 is being moved in camera 1 at a rate of 1u unit to the right. Therefore, player 2 reaches the obstacle in camera 2 before it reaches it in camera 1. The solution is moving player 2 in camera 1 at the same rate as the obstacles move but in opposite direction, that is, 2u units to the right. 

If obstacles belong to layers with scale = n, 0<n<1, then player 2 would reach the obstacle in camera 1 before it reaches it in camera 2, and player 1 would therefore perceive as if player 2 had run through the obstacle, as depicted in Figure 3.


Figure 3. Player 1 perceives that player 2 run through the obstacle

Therefore, the solution consists of correcting this displacement: player 2 has to move in camera 1 at the same rate than obstacles. If camera 1 remains still and camera 2 advance u units, player 2 has to be moved 2u units to the right in camera 1. If camera 2 remains still and camera 1 advance u units, player 2 has to be moved 2u units to the left in camera 1. So the general pattern is: for every unit u of difference between the positions of camera 2 and camera 1, the position of player 2 has to advance 2u units. 

posPlayer2_cam1 = posPlayer2_cam2 + 2*(x2 - x1) = posPlayer2 - x2 + 2*(x2 - x1)  (3)
posPlayer2_draw = x1 + posPlayer2_cam1 = x1 + posPlayer2 - x2 + 2*(x2-x1) (4)

We can simplify (3) and (4) as follows:

posPlayer2_cam1 = posPlayer2 + x2 - 2 * x1
posPlayer2_draw = posPlayer2 + x2 - x1

Finally, we can generalize the formulas for a player in a layer with scale = n, and obstacles in a layer with scale = m:

posPlayer2_cam1 = posPlayer2 + (m - n)*x2 - m*x1
posPlayer2_draw = posPlayer2 + (m - n)*x2 + (1 - m)*x1

And this is all! Hope you enjoyed this series of posts as much as I enjoyed writing it. As I mentioned in the first post, these are the considerations that I took into account while developing the parallax scrolling system for our game to come, Breaking Fast, the result of which you can watch in the following video:



See you!

jueves, 10 de diciembre de 2015

Parallax Scrolling in Love2d. Part 2: Testing Collisions in different Layers

Hi all!

This is the second installment of the series on parallax scrolling for Love2d. In the previous post, we discussed how we could implement parallax scrolling in Love2d, by defining a camera component that was in charge of managing the different layers. In this post, we are going to provide further insight on this implementation and we are going to discuss how we can detect collisions happening between objects that belong to different layers. The gist here is noticing that we have two different, interrelated coordinate systems, and that in order to detect collisions, we must compare the positions of the objects in the same reference frame. 

Let's start by defining the two coordinate systems that we have, namely the camera coordinate system, and the world coordinate system. An object will have different values of its position in each system, although it is possible to move from one system to the other by simple mathematical operations. Let's assume that we follow up the example of the last post, in which we wanted the camera to track the player in the center of the screen. Figure 1 shows a diagram that relates the world coordinates with the camera coordinates of the player. We will focus only on the X dimension, but the same reasoning would apply to the Y dimension. Note that we define a world of 10000 x 10000 pixels, where the origin of such world is at the top left corner of the screen. The camera has a dimension of 1920 x 1080 pixels, which corresponds with the standard resolution of most screens today. Every object contained in the camera (the red rectangle) will be visible. As you can see, assuming that the position of the camera in the world is (x, y), the player will have different coordinates in camera space (960) and in world space (x + 960).

Figure 1. The player position in camera and world spaces 

In our example, we assume that the camera is updated as a consequence of the movement of the player (which is logical if we want the camera to track the player). Therefore, this is what happens in each frame:
  1. The player presses the right key, which increases the world position of the player by a rate depending on the speed we want the character to have. 
  2. As a consequence of the update on the character position, we have to update the world position of the camera, which is advanced the same units as the player has moved. That is, if the player has moved 50 units, the camera will move 50 units. The fact that the camera moves at the same rate as the player is due to the fact that the player belongs to a layer with scale = 1, as we will analyse further in the following.
Given that we update the camera when we update the player, we can consider that the world position* of the camera is a function of the world position of the player, and this function is as follows:

posCamera = posPlayer - 960 (1)

* From now on, we will simply say position when we refer to world position.

In general, if we have an object that belongs to a layer with a scale = n, the relationship between the position of the object in world and camera space is given by:

posObject_cam = posObject - posCamera * n (2)

In particular, think of the player, who belongs to a layer of scale = 1. From (1), we have that:
  
posPlayer = posCamera + 960

Substituting this in (2), we have:

posPlayer_cam = posCamera + 960 - posCamera * 1 = 960

As we can see, the position of the player in camera space does not depend on the position of the camera, because it is always the same: the center of the screen. Any other object that belongs to a layer with scale = 1 will meet (from (2)):

posObject_cam = posObject - posCamera (2a)

This means that the position in camera space of the object will change at the same rate that the camera moves. Consider for example a stationary object at position 50. If the camera initially is at position 0, then the object position in camera space will be 50. Now if the camera moves 10 units to the right, the position of the object in camera space would be 50 - 10 = 40. Moving the camera forward u units is equivalent to moving the object backward u units. In the case of the player, it is not a stationary object, but it moves at the same rate as the camera moves, and in particular, the position of the player in camera space is 960 because the difference between the position of the player and the position of the camera is always 960.

Consider now the case of stationary objects that belong to a layer with scale = 0. Then, we would have:

posObject_cam = posObject - posCamera * 0 = posObject (3)

This means that positions of objects that belong to these layers are not affected by changes in the position of the camera: their positions in camera space correspond always to their positions in world space. Or said another way: if a stationary object has the position 10 in camera space, it will keep that same position forever, being the net effect that the object moves at the same rate and same direction as the camera. 

Think now of stationary objects that belong to a layer with scale = 2. Then, we have:

posObject_cam = posObject - posCamera * 2 (4)

Let us suppose that the camera moves 10 units to the right. This means that the object in camera space moves -20 units (or 20 units to the left). In general, moving u units the camera to the right is equivalent to moving the object 2u units to the left.

Once we know how the position of any object in camera space is calculated, let's see something different. Now, we are going to calculate where the objects are actually drawn on the screen. The diagram in Figure 2 helps explaining this:


Figure 2. Object positions in different spaces

Let posObject_draw be the position where an object is drawn on the screen. Clearly, from the diagram above, we have the following:

posObject_draw = posCamera + posObject_cam 

, where posCamera in the X dimension is x.

And if we substitute posObject_cam from (2), we get:

posObject_draw = posCamera + posObject - posCamera * n (5)

, where n is the scale to which the object belongs.

Let us instantiate (5) for the player:

posPlayer_draw = posCamera + posPlayer - posCamera * 1 = posPlayer

This means that the player is drawn exactly in its world coordinates. If the player advances u units to the right, the player will be drawn these same u units to the right. In the case of stationary objects, this means that they will be drawn always in the same position. Therefore, if the camera advances u units to the right, in order for the object to be in the same position, the object will be drawn u units to the left. Note that this is consistent with the analysis performed on (2a).

If we instantiate (5) for a stationary object that belongs to a layer with scale = 0, then we have:

posObject_draw = posCamera + posObject - posCamera * 0 = posCamera + posObject

This means that the position where this object is drawn moves at the same rate as the camera and in the same direction. The net effect is that the position of the object is not affected by the position of the camera and the object seems to be still. This is consistent with what (3) expressed.

If we now instantiate an object that belongs to a layer with scale = 2, we would have:

posObject_draw = posCamera + posObject - posCamera * 2 = posObject - posCamera

This is expressing that moving u units the camera to the right causes the object to be moved u units to the left, being the net effect that the object is moved 2u units to the left, as the analysis in (4) concluded.

Once we understand how everything works, it is time to detect collisions among objects in different layers. The key idea here is that we must compare positions of the same type. Let us suppose that we want to check whether two objects A and B, belonging to layers with scales n and m, respectively, are colliding. We have two options:
  1. Compare positions in camera space.
  2. Compare positions where the objects are actually drawn.
In option 1, the steps would be as follows:

posA_cam = posA - posCamera * n
posB_cam = posB - posCamera * m
if (colliding(posA_cam, posB_cam)) then ...

In option 2, we would perform the following steps:

posA_draw = posA + posCamera * (1 - n)
posB_draw = posB + posCamera * (1 - m)
if (colliding(posA_draw, posB_draw)) then ...

Note that given that world coordinates of the objects do not account for the displacement that occurs each frame because of the parallax effect, we cannot use these world coordinates directly for the collision detection. For example, consider two stationary objects A and B that are initially placed in the same (world) position: 500, but A belongs to a layer with scale = 1 whereas B belongs to a layer with scale = 2. If we used the world positions to detect collisions between these objects and any other object C that moves toward them, we would detect that C collides with them at the same time, but this is a mistake. Actually, C will reach B in half the time that it will reach A, because B moves twice as faster than A in relation to the camera. In summary: we are using the world position only as an intermediate value to compute the actual position where the objects are drawn (or their position in camera space).

And this is all for now. In the last installment of the series, we will discuss how we can represent the same object in different camera spaces. This is useful for multiplayer games, where each player has a different view of the world.

Hope you found this interesting and see you soon!

sábado, 5 de diciembre de 2015

Breaking Fast Programming: Press Start Animation

Hi all!

I recently uploaded the latest video on the series "Breaking Fast Programming", where we explain how we can achieve an animation for the typical "Press Start" text at the beginning of most games. 
 
As a comment mentioned (thanks, @judelco), there is an error in the final expression:

theta = theta + 4 * dt % 360

, since it should be:

theta = (theta + 4 * dt) % 360

Otherwise, we are implicitly writing:

theta = theta + (4 * dt % 360) 

because of operator precedence, and theta would grow indefinitely.  


See you!
FM

miércoles, 2 de diciembre de 2015

Breaking Fast Programming on Youtube

Hi all!

I am glad to announce that I will be uploading a series of videos on the development of Breaking Fast, our current project. For now, you can take a look at the first video, which serves as an introduction to the main programmer (ehem, myself...) and to the game. Although most of the videos will revolve around technical and programming stuff, some videos will explore the development of the art and music of the game. I will keep you posted on new videos to come!




viernes, 27 de noviembre de 2015

Parallax Scrolling in Love2d. Part 1: Data Structures and Programming

Hi all!

This is the first post of a series in which I'll explain how we can implement parallax scrolling in Love2d. The code that I'll share is similar to the one I'm using for Breaking Fast, our next game to come.

The implementation builds on the tutorial that you can find here. Actually, I advise you to take a look at this tutorial first, because it covers the fundamental principles behind the implementation. Then, we will perform some extensions, so come back here. 

The implementation starts with the idea of creating a data structure that represents the camera. So now, we will focus on a camera.lua file that implements the camera data and functionalities.

camera.lua
 local camera = {}  
 camera.__index = camera  
 return camera  

What data must a camera have? Well, the first and most important one is the (x,y) coordinates that represent its position. It could also hold data regarding scaling in both directions, and its orientation. If we want the camera to support parallax (and we certainly do), it must also contain a list of layers, where each layer will contain its own objects to be drawn. With this in mind, we can create the camera constructor, as follows:

camera.lua

 local function construct()  
  local self = setmetatable({x = 0, y = 0, scaleX = 1, scaleY = 1, rotation = 0, layers={}}, camera)  
  return self  
 end  
   
 setmetatable(camera, {__call = construct})  

As you can see, we are creating a camera with an empty list of layers. Also, with the setmetatable function, we are instructing that if, from some client code, we use the table camera as a function, the method to which __call points is to be invoked. This means that if we want to create two different cameras from client code, we only need to do the following:

some client code.lua
 local Camera = require "camera"  
 myCamera1 = Camera()  
 myCamera2 = Camera()  

Love2d uses three functions to transform the current coordinate system:

love.graphics.rotate( rotation )
love.graphics.scale( x_scale, y_scale )
love.graphics.translate ( dx, dy )

Let's focus on the last one. According to the documentation: When this function is called with two numbers, dx, and dy, all the following drawing operations take effect as if their x and y coordinates were x+dx and y+dy.

So, assume we have a square in the coordinate (1, 0), as shown on the left part of Figure 1. After performing love.graphics.translate( -1, 0 ), we would have the square in the coordinate (1 + (-1), 0 + 0) = (0, 0), because even when we are actually moving the coordinate system, this is equivalent to moving the square in the opposite direction, as depicted on the right side of Figure 1.


 Figure 1

This is the fundamental mechanism that we can use in order to implement traditional scrolling, where the dx and dy values correspond to the position of the camera with negative sign. The same applies for the scaling and the rotation. We can encapsulate all this in two functions as follows:

camera.lua

 function camera:set()  
  love.graphics.push()  
  love.graphics.rotate(-self.rotation)  
  love.graphics.scale(1 / self.scaleX, 1 / self.scaleY)  
  love.graphics.translate(-self.x, -self.y)  
 end  
   
 function camera:unset()  
  love.graphics.pop()  
 end  

The push() function saves the current transformation on top of a stack, whereas pop() sets the current transformation to the one on top of the stack. The strategy to draw is therefore something similar to this:

camera.lua

 function camera:draw()  
   self:set()
   -- draw stuff  
   self:unset()  
 end  

Obviously, prior to calling self:set(), we could modify properties of the camera, in such a way that each draw call behaves different in terms of scaling, rotation or movement/position.

Let's focus now on the parallax effect. For such effect, we have to turn our attention to the layers. What data must a layer have? First, the layer must be able to draw itself, so it must have a reference to a function that will draw the objects in such a layer. Given that we want that each layer can move at different rates (in order to achieve the parallax effect), each layer must hold a rate or scale value. Finally, it would be interesting that we could decide a relative order among layers, in such a way that we can specify the order in which different layers are drawn. The function that builds a new layer is shown next:

camera.lua

 function camera:newLayer(order, scale, func)  
  local newLayer = {draw = func, scale = scale, order = order}  
  table.insert(self.layers, newLayer)  
  table.sort(self.layers, function(a,b) return a.order < b.order end)  
  return newLayer  
 end  

Note that after inserting the new layer into the table of layers, we order them according to the order value. Now, we can complete the draw function as follows:

camera.lua 

 function camera:draw()  
  local bx, by = self.x, self.y  
  for _, v in ipairs(self.layers) do  
   self.x = bx * v.scale  
   self.y = by * v.scale  
   self:set()  
   v.draw()  
   self:unset()  
  end  
  self.x, self.y = bx, by  
 end  

The draw function iterates over all the layers defined for the camera, it then applies a layer scale to the current position of the camera, which makes each layer to be drawn in a possibly different position, depending on the value of this scale. Finally, the draw function of the layer is called. In order to preserve the original position of the camera, we use the temporary variables bx and by.

Note that given that we are using the product of the layer scale and the current position, stationary objects in layers with scale = 0 will have no movement. Therefore, any static background of the game will belong to a layer with such a scale. A layer with scale = 1 will contain objects that move at the same rate as the camera (but in the opposite direction). If we want to track a character controlled by the player, a good strategy is including it in a layer with scale = 1 and moving it at the same rate as the camera, as we will see later. Anything that moves at a faster or slower rates than the camera will belong to layers with scales greater or lower than 1, respectively. The following post in the series will provide further insight on these statements, but for now, let's see now how some client code can use all of this. Let's assume that we have four layers, that we want to draw in the following order:
  1. Static background layer.
  2. Background layer that moves slowly.
  3. Player layer.
  4. Foreground layer with objects moving much faster than the rate at which the player moves.
The order is important because elements in the layer n+1 will occlude elements in the layer j, 1<=j<n+1 (basically, in all previous layers).

some client code.lua

 myCamera1 = Camera()  
 myCamera1:newLayer(-10, 0, function()    
                love.graphics.setColor(255, 255, 255)   
                love.graphics.draw(staticBackground)  
              end)  
 myCamera1:newLayer(-5, 0.3, function()   
                 love.graphics.setColor(255, 255, 255)  
                 love.graphics.draw(slowBackground)   
                end)  
 myCamera1:newLayer(0, 1.0, function()   
                 love.graphics.setColor(255, 255, 255)  
                 love.graphics.draw(player)   
                end)  
 myCamera1:newLayer(10, 1.5, function()   
                 love.graphics.setColor(255, 255, 255)  
                 love.graphics.draw(foreground)   
                end)  

Of course this is not the end of the story. Client code is responsible for updating and drawing the contents of the camera. Fortunately, this is easy, as it is shown next:

some client code.lua

 function love.draw()  
   myCamera1:draw()  
 end  
   
 function love.update(dt)  
  myCamera1:update(dt, player1.posX)  
 end  

love.draw and love.update(dt) are two framework callbacks provided by Love2d and which developers can override in order to customize their behaviours. The former will essentially call the draw function that we implemented in the camera.lua module, whereas the update function will in turn call an update function in the camera module, which we haven't discussed yet. In this example, we assume that we want the camera to follow the player when it is in the center of the screen. Achieving this requires adding the following lines to the camera.lua file:

camera.lua

 local intendedWidth = 1920  
   
 function camera:setPosition(x, y)  
  self.x = x or self.x  
  self.y = y or self.y  
 end  
   
 function camera:update(dt, posX)  
  if posX > intendedWidth / 2 then  
   self:setPosition(posX - intendedWidth / 2)  
  else  
   self:setPosition(0)  
  end  
 end  

Assuming a resolution (intendedWidth) of 1920 pixels in the horizontal dimension, we want to reposition the camera as soon as the player moves past half of this resolution (center of the screen). From that moment onwards, the camera is repositioned each frame to center the player on the screen. As the player belongs to a layer with scale = 1, the player will remain always in the same position in relation to the camera. This again will be further discussed and mathematically proved in the following post of the series.

And this is for now! I hope you found this tutorial useful. In the next installments of the tutorial, I intend to discuss and provide further insight on three aspects: reasoning about layers scales and their relation with the positions of objects, detecting collisions among objects in different layers and representing objects in different cameras, for example, for local multiplayer games.

See you!

lunes, 16 de noviembre de 2015

To full-time indie...

Hi all!

A couple of weeks ago, I achieved a milestone that I though it would never arrived: I got my Ph.D. degree in Computer Science. So yes, now I'm a doctor, but not one of those who can prescribe drugs!

This means that a part of my professional life has finished, and now, new opportunities emerge. In particular, this means that I intend to go full-time into indie games development. Of course, this decision entails quite a lot of risks, which are pretty well materialized in a good deal of failure cases and in the so-called indipocalypse. However, I find myself now in a stage in my life in which I'm willing (and capable) of taking up these risks and the new challenges that are to come.

This also means that I expect to be more active in this blog and in social networks in order to promote our projects, the first of which is the already mentioned Breaking Fast. Also, I intend to upload some videos to Youtube in which I will be implementing some new features of this game.

I have set myself a "reflective" deadline of one year, which means that after that year, I will perform a cost-benefit analysis of  my decision and I'll take a course of action depending on the outcome of such balance.



So yes, there is no time to lose! I will bring you news about Breaking Fast as soon as I have them. Also you can check our webpage, which is in a very early stage of development and lack lots of contents yet.

See you!
FM

miércoles, 14 de octubre de 2015

Angry milk and cookies... This is Breaking Fast!

Hi all!

It's my pleasure to announce our new game: Breaking Fast (those who think the name is a pun are completely wrong...).

The game can be described as a competitive runner, or even better, as a Mario Kart-like game, where players have to run as fast as they can, avoiding obstacles as well as the attacks received from other players. As usual in our games, the mood of the game revolves around drinks and food, with a casual and friendly artistic style conceived by Manuela, and music and sounds by Oliver.

Breaking Fast is in an early development state as we are still adding new elements and mechanics to make it even more fun and challenging. Recently, we had the chance to showcase the game in an event for game makers and the feedback was fantastic. People were really hooked on the game and enjoyed playing dirty tricks on their rivals. We also received a good amount of tips to improve the game, and we are currently integrating them. 

The video below presents a coarse-grained view of the development process, starting from the conception on pen and paper. We started to think about the game during the last week of July in order to gain some knowledge about the Löve2d framework, which we intended to use for the August edition of Ludum Dare. However, we didn't advance much and ended up leaving it aside. Once Ludum Dare finished, we retook it because we were really hopeful about the potential of the game.


The development of Breaking Fast along three different phases
 
From its conception, our goal with the game has been targeting the core of fun and competitiveness, providing tight controls that pose a good trade-off between reward and frustration. Once the game is in a more polished state, we intend to submit it to Steam Greenlight, where we expect to receive even more feedback to finish off the last details.

Currently, the game only supports two players but it is our intent to include support for up to four players. Whether the game will have an online mode will largely depend on the feedback that we receive once in Steam Greenlight, due to the overhead in effort and infrastructure that adding online multiplayer may entail.

 

People from all ages and genres enjoying the game

This time Cookie beat Milk

Hope that we aroused your curiosity. We just created a twitter account through which you can follow us to stay tuned on the latest updates of Breaking Fast.

See you.
FM

domingo, 27 de septiembre de 2015

Drunkula: Yet Another Post-Mortem (with nice pictures :))

This is an after-the-fact analysis of our experience during our first Ludum Dare, which is divided into three different testimonies coming from three different members/roles in our team.



Welcome to the 33rd edition of Ludum Dare!

Music & Sound by Oliver

I've been participating in game jams during this year for the first time, and LD is the third one. Drunkula is the eighth soundtrack that I've made for a videogame. And although everything can be improved, I'm really satisfied with the outcome.

My intention with Drunkula's music was clear: I didn't want a mere background music, but an interesting composition that conveyed the dark atmosphere bound to a vampiric night together with the drunkennes feeling of the main character.





Setting up our workplace

The composition was the first thing that I did, since it is the most difficult and which takes the longest time. The original instruments are those used for the first two levels. Then, I changed the orchestration to evoke the inners of the chapel (third level) without the need to compose any more pieces. 

For the menu, I cut out a fragment from the theme, changed the instrument of the main theme and I added some audio effects to make it sound like being at the door of a disco. For the credits screen I used a long note in order to simulate that annoying ringing after a night party. 

The serious side of the composition is given by:
  • The choice of D minor because it conveys the feeling of dead and solemnity, like in the Mozart's Réquiem. 
  • The 3/4 beat because it evokes the feeling of an aristocracy hall, like in any J. Strauss' waltz. 
  • The higher dense than usual counterpoint in a jam game in order to convey the overloaded aesthetics usually associated to the vampire's castle, like in the well-known Bach's Toccata and Fugue. 
The comical and grotesque side comes from:
  • The instrumentation, specially with the first two levels trying to represent the outside with wind instruments, and synthesizers and beatbox drums.
  • The continuous apparent lack of rhythmical beat aims to evoke the drunkennes feeling. For some players, I understand that they felt the music kind of grating, but that was actually the pursued effect. 
  • The slightly funky style of some accompaniments suggests the party mood where the guy that was bitten by the protagonist was. 
Some curiosities: 
  • Just before closing the loop you can hear the famous "Mmmmm" by Morshu, a character from CDI's Zelda and one of the most parodied characters ever in a videogame. 
  • Hidden among the counterpoint you can here the main theme from Japanese horror movie Hausu (1977), a psychedelic masterpiece that we watched a couple of times during the jam. 
  • The central part has a sequence of chords taken from the beautiful Valse Triste by the Finnish composer Jean Sibelius. 
Regarding the sound effects and as I did in the two previous game jams in which I participated, I put off the sound effects till the last day. I used a micro to record elements in the house where we were working and then I edited the sounds in my computer. In this regard, I must thank the level designer because the voices are hers and she assisted me with the foley. To make the voices sound more masculine, I simply lowered the tone by software. Given that the sound effects are the last feature to be implemented, their volume are not so well tuned. The forest environment hardly is perceivable and it's a pity, because that day was very windy and I could record that sound in a natural way with the micro. 

Level Design by Esther

The first level was just a tutorial to settle the most basic mechanic of the game: point and click. The second level was about combining two objects to solve the level. In the third screen I introduced another object to solve the level. In this last level I tried to make the game more interesting by increasing a bit the difficulty; hopefully I made it!


I set up the levels with Tiled map editor, although I designed them previously with diagrams using pixels as units of measurement.

I also aimed to take care of the coherence of spaces between screens; that's why the first screen is on a path, the second one is at the entrance of the fortress and the third one is inside the fortress, not the castle yet but the chapel. I would have liked to have more time to introduce more levels, in a cemetery for example and other screens inside the castle itself: things that I keep in mind if we decide to go on with this game ^_^. I also would have liked to have made some sketches of the environment of the screens, not only the diagram of the level, in order to match the background and the platforms completely in a logical way.

The best thing of the jam for me is that we have learned so much in such a short period of time and have earned lots of experience. I have learned how important is to establish a clear and constant communication with all the members of the team (especially with the artists and the programmers).

Programming by Manuela and Francisco

We used the Löve2d framework (https://love2d.org) because we were interested in grasping a better understanding of Lua, a programming language that has been gaining traction among the game development communities during the last years. The main advantage of this choice is that we actually learned a lot about Lua, but the setback (and we were aware of it) is that we needed to build almost everything up from scratch. Given that we had no previous experience with a game jam, and that we had no pre-existing modules or data structures, we were a bit scared that we couldn’t make it to the deadline. Fortunately, this same deadline gave us the productivity boost that we needed to finish everything off. That’s definitely a good thing about jams!

The workflow that we used was the following. The artists handed their assets to the level designer, who used the Tiled Map Editor to set up the level. Then, the level, together with collision information, was exported to a lua format that we could read and show on screen. 


Having a strong breakfast was important!

As for the programming tasks, we started off by loading a simplified version of a level and showing a placeholder sprite for the main character (in particular, an 8-bit Mario sprite…). Then, we made sure that we could read an actual level from the Tiled Map Editor application and that we could show it on screen. Later, we added the main character and the basic collision systems to keep it from falling. In parallel, we tested the anim8 library for loading and showing some animations packed in grids (i.e. spritesheets). Also in parallel, we created the transition system for the different screens and for the introduction, and we integrated the music and sound effects in the last hours. Finally, we had to face some bugs with the change of direction of gravity, but we mostly fixed them all.


Stuff that we liked:

- The workflow was well established from the beginning, and all the members of the team took up their roles perfectly.
- We learned a lot about the Lua language, and the Löve2d framework, which has proven to be very useful not only for game prototyping, but also for the creation of full-fledged games. 

Improvable stuff:

- We didn’t take advantage of all the features of Tiled Map Editor, since we only used it to set up the map and the polylines for simple collisions.
- More play testing would have been beneficial, as some silly bugs could have been identified easily before release.


In the end, this was our results: we were in Q1, which is pretty cool being the first time






viernes, 4 de septiembre de 2015

Drunkula, our Ludum Dare Game

Hi!

It's my pleasure to introduce you Drunkula, a game that I made with a team of friends in 72 hours for the Ludum Dare. As I explained in an earlier post, Ludum Dare is an excellent way of forcing yourself to start and finish a game, and I advise any game developer to participate in this and other game jams. Our experience has been fantastic and I intend to write a post about this experience and what it took to make the game in the near future.


For now, you can take a look at the game and leave us a honest feedback if you please. Yes, it is short. Yes, there are glitches. But I think that the overall result is more than good for such tight deadline. :)

Drunkula is a puzzle adventure about a drunk vampire (because he bit a drunk guy) who wants to get back to his coffin in his castle. You have to help him by clicking objects on the screen. You can also check the game on GameJolt.

There are also a couple of Let's play videos uploaded by Youtubers, in case you prefer to take a quick look. You can watch one of these below.

See you!
FM

jueves, 20 de agosto de 2015

Starting Engines for Ludum Dare

Hi!

These days I've been getting ready for the Ludum Dare game jam, the theme of which will be announced next Saturday at 3 a.m. (Spanish local time). As part of my training, I've been learning a little bit about Love2d, a Lua-based game framework that is proving to be a powerful tool not only for mechanics prototyping but also for full-fledged game development. 

As part of this training, I'm developing (again together with Manuela) a local multiplayer game, which I'll show you more about after the jam, because I'll likely not have time to finish it off before this weekend. However, I can share with you some early art created by Manuela. Yes yes yes... more food... again :)


See you!
FM

lunes, 27 de julio de 2015

Gamepolis 2015: An Overview

Hi all!

As promised, here it is my experience during the 2015 edition of Gamepolis. (To check my course during the previous editions, click here and here). 

The event came this year with some interesting novelties:

1) More national and international projection: not only did the number of attendees increase, but also the variety of their origin, which encompassed many Spanish regions. Long lines, especially during the morning, showed the increasing interest in this event, as shown in Figure 1. Also, the invited speaker Petro Tyschtschenko provided the international flavour with his nostalgic speech about the Amiga in its 30th anniversary. 


Figure 1. Tons of people lined up to access the premises, and more than half of the line 
cannot be seen from this perspective!

2) GameInvest Forum: co-located with Gamepolis, GameInvest provided a forum where developers could show their games to investors. As part of the agenda, there were some interesting talks on game investment and financial aids. Particularly interesting was a roundtable discussion about the aspects that investors often examine when making investment decisions. The main conclusion was that the game developer experience is usually graded with the highest priority. Thus, when an investor is faced with whether to invest in an unexperienced game developer with a brilliant idea, or in an experienced developer with a not so good idea, the odds will mostly be in favour of the latter (in many cases, unfortunately). 


Figure 2. GameInvest Forum

3) Game Jam: MalagaJam is a young association targeted at game developers, which is based in Malaga physically and in Internet digitally. Two weeks ago, they organized their second Game Jam, the awards of which were announced during a Gamepolis session on Sunday afternoon. The list of games and their download links are here. One of the most successful games, Panspermia, achieved The Most Outstanding Visuals and to The Best Audio and Music awards, the latter of which was thanks to my friend Oliver (Figure 4). 


Figure 3. The auditorium was completely crowded during the jam awards ceremony


Figure 4. Panspermia team receiving The Best Audio and Music award.

Contrary to the previous editions, in which I tried to turn up at almost all the conferences, this year I could barely attend any one. The reason is that I participated in GameInvest with a project called GalaxyNumbers (Figures 5 and 6), for which I'm the programmer. The game combines match-3 mechanics (Tetris) with a Candy Crush aesthetics and presents an interesting mathematical twist. According to the people that could play the game during the event, it is fun and addictive, and these people would repeatedly ask us whether the game was already available for download. Unfortunately, we always had to answer "not yet". Precisely the idea of participating in GameInvest was to request investment to polish the last details and to integrate the last features, and also to cover marketing efforts. For now, we are happy to have received very positive feedback from a broad range of users.


Figure 5. The stand of Galaxy Numbers


Figure 6. The presentation of Galaxy Numbers

As a wrap-up, this edition of Gamepolis has provided a bigger focus on developers and has widened its impact by bringing an international, well-known speaker, which were two aspects that remained uncovered in the two previous editions and which I criticized in those posts.


Figure 7. A 3D printer making cool stuff. Actually, the game jam awards were printed!

Something to improve? Well, there are some sources that have complained about the lack of respect of a reduced number of attendees during some conferences, who would not stop their chattering. I would therefore suggest enforcing a bigger control during the presentations, as well as continuing the effort towards a wider internationalization.


Figure 8. A minute of silence was observed in memory of Mr. Iwata, followed by a huge ovation.  RIP.

miércoles, 22 de julio de 2015

Gamepolis 2015 is coming!

Hi all!

Gamepolis 2015, the biggest and most important videogames event in Malaga, is coming back this weekend. 


As I did in the 2013 and 2014 edition, I will cover my experiences along the days of the event. This year, Gamepolis brings along a nice novelty: GameInvest, a forum where investors will evaluate different projects and will finance the best ones. And guess what! A project in which I'm working will be there! So wish me luck! 

In the next post, I'll tell you more about this project and about my course during the event. 

See you,
FM 

miércoles, 3 de junio de 2015

Correct Compositional Design in Cocos2d-x

Hi all!

Today I want to share with you an important caveat about composition in the context of Cocos2d-x. Composition is an object-oriented technique where a class contains (is composed of) another class to which it delegates functionality related to the latter. 

This technique is frequently suggested as an alternative to inheritance in complex hierarchies in order to avoid tangled structures, specially in those languages that do not support multiple inheritance (i.e. a class cannot have more than one parent class), such as Java. More information about the composition-inheritance binomial can be read here

In the context of Cocos2d-x, composition could be realized through a class that contains a Sprite object as part of its private members, for example:

 class Ball  
 {  
 public:  
   explicit Ball( const BallType &bt )  
   {  
      switch(bt)  
      {  
         case BallType::Hard:  
            ballSprite = Sprite::create("Balls/Hard.png");  
            break;  
         //more cases...  
      }  
   }  
   ~Ball()
   {
       //Clean-up by removing heap-allocated data
   }
   inline cocos2d::Sprite *getBallSprite() { return ballSprite; } 
 
 private:   
    cocos2d::Sprite *ballSprite;  
    //more data
 };  

In this case, the Ball constructor simply takes a scoped enum value and creates a sprite object depending on the type. We also provide a getter function to retrieve the pointer to the sprite object. The destructor, as always, should clean up the memory allocated by the object.

At this point, you may be tempted to place a delete ballSprite statement, but this would yield a compiler error, because Cocos2d-x uses its own reference counter for managing the memory of its objects. Therefore, when a Cocos2d-x object (such as a Sprite) is no longer referenced by any other object, the former is automatically deleted.

Now, a client class (e.g. a cocos2d::Layer ) could use the Ball class as follows:

 //A method in our layer class  
{  
   //start some loop
  {
    BallType bt = getRandomType();
    //balls is a member variable of type std::vector<std::unique_ptr<Ball>>
    std::unique_ptr newBall = std::make_unique<Ball>(bt); 
    layer -> addChild( newBall -> getSpriteBall() ); 
    balls.pushBack( std::move(newBall) );  
 
    //... process balls    
  }
  //All balls destroyed; all  
  Director::getInstance() -> replaceScene( AnotherScene::create() );
} //end of method


In a loop, this method creates balls of random types, adds the balls sprites to the layer to actually show the sprites on screen, and processes them (maybe it detects touches and so on). Upon termination of the loop, there is a change of Cocos2d-x scene, which means that all the children of the current layer (including the sprites of the balls) are safely deleted. Also, as the vector of balls goes out of scope, the destructor of the std::vector class is called, which in turns calls the destructor of the std::unique_ptr objects, which in turn calls the destructor of each Ball object. Everything perfect so far.

However, consider the following scenario. In this scenario, we want to show only on screen some balls of a specific type, whereas other types of balls should be stored and shown at a later time, for example upon termination of the loop. The code to perform this could be:

 //Method in our layer class  
{  
  //start a loop
  {
    BallType bt = getRandomType();
    std::unique_ptr newBall = std::make_unique<Ball>(bt); 

    if ( bt == BallType::Hard )
    {
      layer -> addChild( newBall -> getSpriteBall() );  
      balls.pushBack( std::move(newBall) );  
    } 
    else 
    {
      ballsToShowLater.pushBack( std::move(newBall) );
    }
    //... process balls      
  }
  //end of the loop
  //show hidden balls
  for (const auto& b : ballsToShowLater)
  { 
      layer -> addChild( b -> getSpriteBall() );  
  }   
  //..some more stuff with the new balls shown
  
  Director::getInstance() -> replaceScene( AnotherScene::create() );

} //end of the method

This code, which seems ok at a first glance, has an important flaw. The problem arises because of the automatic reference counting mechanism of Cocos2d-x, which we are not using properly. When we create a Sprite object in our Ball, the reference counter is still 0, because there is no object pointing at it. This means that if right after creating the Ball object we don't add the associated Sprite object to the layer hierarchy (via addChild() ), the next iteration of the framework will detect that the reference counter is 0 and will remove the Sprite object. However, if we add the Sprite to the layer hierarchy, we increase the reference counter by 1, which prevents the framework from deleting the Sprite.

In the first example, there was no problem because right after the creation of a Ball object, unconditionally, we added the Sprite to the layer hierarchy. However, in the following example, we are creating Ball objects and we are deferring the inclusion of their sprites in the hierarchy of the layer. Therefore, most likely, when we try to retrieve the Sprite object in the for loop, we simply retrieve garbage, because the pointer is dangling.

How to fix this? The solution is easy and fast. We simply need that Ball object reclaims (shared) ownership of its Sprite. Basically, we need that a Ball object is capable of expressing: "hey, I need the Sprite object, so don't remove it even if nobody else is using it". This is where the Cocos2d-x functions retain() and release() come into play, as shown next:

 class Ball  
 {  
 public:  
   explicit Ball( const BallType &bt )  
   {  
      switch(bt)  
      {  
         case BallType::Hard:  
            ballSprite = Sprite::create("Balls/Hard.png");  
            break;  
         //more cases...  
      }  
      ballSprite -> retain(); //This is my sprite, so don't mess up with it!
   }  
   ~Ball()
   {
       //Clean-up by removing heap-allocated data
       ballSprite -> release(); //I don't need this sprite object anymore
   }
   inline cocos2d::Sprite *getBallSprite() { return ballSprite; } 
 
 private:   
    cocos2d::Sprite *ballSprite;  
    //more data
 };  

So this is the main consideration when using composition with Cocos2d-x objects! Easy, right?

Hope you enjoyed it!
FM

Tweet: Don't miss this interesting read on #programming and #gamedev. Correct Compositional Design with #cocos2d-x (http://ctt.ec/hIFi9+)

sábado, 25 de abril de 2015

Technical Take-aways from Limball

Hi!

In this post I want to summarize some of the technical issues I had to face while developing Limball. 

The first thing to highlight is that it has been my first experience, at least in a complete game, with Cocos2d-x, the framework that I have used for the implementation. In my first game, Chubby Buddy, I had used Cocos2d (now renamed to Cocos2d-SpriteBuilder), which uses Objective-C and is targeted exclusively at iOS developers. Cocos2d-x is written in C++ and targets both iOS and Android developers. I must say that the learning curve has been very smooth. The API is practically the same, so if you know how to call a certain function from Objective-C, you know almost intuitively how to call it from C++. Of course, a previous background on C++ is fundamental in order to get the most out of it as fast as posible, but you can use also other languages (e.g. Lua).



Developing for multiple platforms is made really easy thanks to Cocos2d-x, which allows keeping the same C++ codebase. Nonetheless, at some points I needed to do something different in the two platforms. For example, when integrating with Game Center, the social platform for iOS gamers, I noticed that the achievements and leaderboard sections were well integrated under a common interface. However, Google Play Game Services, the Android counterpart, does not integrate the two services under the same interface. This means that two different buttons are required in Android (one for the leaderboards, another one for the achievements), while in iOS does just fine with one button. In order to avoid lots of code duplication, I resorted to preprocessor macros. Cocos2d-x defines the macro CC_TARGET_PLATFORM, which may be assigned a value according to the platform where the code is to be executed. As a consequence, there are several parts in the code with the following pattern:

 #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
  //do iOS-related stuff  
 #else  
  //do Android-related stuff  
 #endif  

Something else that I learnt is how to use the social platforms for gamers on iOS and Android. The integration with the former was smoother, also due to the easier integration between C++ and Objective-C. An example on how this C++/Objective-C integration can be painlessly achieved is discussed in an earlier post on localization.

As an example, consider the following code that unlocks an achievement on both platforms:

 #if CC_TARGET_PLATFORM == CC_PLATFORM_IOS  
       GKHWrapperCpp gkh;  
       gkh.reportAchievement( "Triple_Chain", 100.0, false );  
 #elif CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID  
       GooglePlayHelper::UnlockAchievement( COMBO_KIDDIE );  
 #endif  

GKHWrapperCpp is a class that belongs to a open source library that you can find here and that simplifies the management of Game Center related stuff. GooglePlayHelper is a utility class that I made in order to manage interactions to Android-specific features through the Java Native Interface (JNI).

JNI is not difficult to use, provided you have the previous background on Java and C++, but it is easy to make some small mistakes that are almost impossible to debug. In my case, I was experiencing a game crash only on Nexus 5 running Android 5.0.1. I even tested on the same device running a lower version of Android and it worked perfectly. For some time, I had no clue on what was happening and I ended up blaming the OpenGL implementation on that device for that version of Android. In the end though, it turned out that I was making a memory management mistake: I wasn't removing a local reference that I had created:

 jbyteArray bArray = t.env -> NewByteArray( key.length() );  
 jbyte bytes[50];  
 for( int i = 0; i < key.length(); ++i )  
 {  
    bytes[i] = key[i];  
 }  
 t.env -> SetByteArrayRegion( bArray, 0, key.length(), bytes );  
 res = (jstring) t.env -> CallStaticObjectMethod( t.classID, t.methodID, bArray );  
 t.env -> DeleteLocalRef(t.classID);  
 t.env -> DeleteLocalRef( bArray );  

Adding the last line of the previous snippet did the trick, just one day before the intended release date..

Another example of system-specific feature is in-app purchases. In Limball, you can remove the ads banners and interstitials (full-screen ads) by buying a non-ads product from inside the app. Both iOS and Android offer a simple way to tackle this, so that was not a problem. In the case of Android, I used the In-app Billing v3 workflow, which basically comes down to the following snippet of code:

 buyIntentBundle = _appActivity.mService.  
           getBuyIntent( 3, _appActivity.getPackageName(), productId, "inapp", "noads" );  
           //If everything is fine, then proceed with the transaction  
           if ( buyIntentBundle.getInt( "RESPONSE_CODE" ) == 0 )  
           {  
             _appActivity.pauseGame();  
             PendingIntent pendingIntent = buyIntentBundle.getParcelable( "BUY_INTENT" );  
             _appActivity.startIntentSenderForResult( pendingIntent.getIntentSender(),   
                                  REQUEST_INAPP_CODE,  
                                  new Intent(),   
                                  Integer.valueOf( 0 ),   
                                  Integer.valueOf( 0 ),  
                                  Integer.valueOf( 0 ) );  
           }  

On iOS, the strategy (as usual) is to create a delegate that will manage the purchase with the following calls:

 SKMutablePayment *payment = [SKMutablePayment paymentWithProduct: productToBuy ];  
 [[SKPaymentQueue defaultQueue] addPayment: payment];  

It first create the payment with product id, and it introduces it in the queue. Then, the payment is processed by the payment queue delegate, typically as part of the AppController. This delegate is in charge of looking at the state of the transaction and to deliver the functionality once the transaction is in the SKPaymentTransactionStatePurchased state, as depicted in the following code:

 - (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions  
 {  
   for ( SKPaymentTransaction* transaction in transactions )  
   {  
     switch ( transaction.transactionState ) {  
       case SKPaymentTransactionStatePurchasing:  
         ConfigManager::GetInstance() -> PauseGame();  
         break;  
       case SKPaymentTransactionStatePurchased:  
         ConfigManager::GetInstance() -> EnableNoAds();  
         ConfigManager::GetInstance() -> ResumeGame();  
         [[SKPaymentQueue defaultQueue] finishTransaction: transaction];  
         break;  
      //...  

For the inclusion of advertisements, I have used the iAd network on iOS and Google's Admob. Actually, on iOS the strategy is to prioritize iAd, and only if it is unavailable, fall back to Admob.  Given that iAd does not provide interstitials for iPhones, I used the Admob feature for that purpose. Again, the integration was smooth, because the frameworks provide usable APIs. In this earlier post, I explained how you could integrate a Cocos2d-x project with iAD.

And these are the most important technical issues I have learnt about. Hope you found them useful.
See you!

Tweet: Technical take-aways from making #Limball. Take a look: http://ctt.ec/Nb893+ #gamedev #indiedev