sábado, 31 de diciembre de 2016

Becoming Indie Developer: A 2016 Retrospective

Hi buddies!

I still remember it as if it was yesterday when I started this blog. It was April 2013 and I was doing my Ph.D. stay in Rennes, France. By that time, I was a full-time researcher at the University of Malaga and my main goal was to finish my stay, write my last journal articles and defend my Ph.D. However, for a very long time I had had an itch for making games.

My experience with games development started surprisingly early, when I was around 14 years old. By that time, my grandfather, who knew how much I wanted to learn this stuff, gave me a Darkbasic pack as a birthday present. I still remember how, during high school classes, I would daydream about the amazing games I was about to make. I can perfectly remember thinking to myself about making a Matrix-style game where the main character would avoid bullets bending over himself, just like Neo, and I would naively think that it wouldn't take me long to reach such level of expertise. Of course, reality imposed itself, and there were so many new terms I had no clue about, that it took me a long time to just make a Pong clone (with some additional cool features like moving obstacles).

By that time and until finishing high school I made some very simple games, and when I started the Computer Science degree at the University, the demanding subjects drifted me away from my dream. Yet I still read about games programming and with the new knowledge acquired I could understand more and more about how a videogame is built from the ground-up. Life circumstances (which were really driven by luck and momentum, as they usually are) geared me to start working in the Computer Science department, where I would take a 4 years Ph.D. grant after finishing the degree. Over this period, I overlapped my Ph.D. with the creation of small video games: in 2014, I released Chubby Buddy on iOS, and in 2015, Limball on iOS and Android (both of them together with Manuela).

All that time was a great experience and I don't regret any of the choices I made, but the truth is that the moment of making games for real never seemed to come. And this is where, during the Ph.D. stay, I made my decision: I would finish my Ph.D., but right after doing so, I would quit research and become full-time game developer. And creating this blog was the first step towards convincing myself of walking down this risky and uncertain path...

And here I am now, after one year, I can really claim that I have become an indie game developer, doing justice to the name of the blog. I wish I could add that it's been a profitable decision, but I cannot claim that, not at least for now. I'm currently finishing Breaking Fast, which I've been developing (together with Manuela, as usual, but also with Oliver and David) for almost a year and which we've financed with the savings accumulated over the aforementioned years of working in the research area. During this time, I've observed some things I want to mention now.

Cool things or things that I think we've done alright

One of the typical problems of unexperienced game developers is delaying the marketing actions to the release date. I think I can clearly claim that we haven't made such mistake. From the very first moment we had a playable version of the game, we attended game events to show it and receive feedback from players. In our case, our first event was PAX East (not bad to be the first one, uh?), and from that event, which took place in April, we have attended more than 10 events over the year. As for marketing in social networks, we have populated our accounts with new contents nearly every day since we started. Believe us: all of this (events and social networks) is a huge amount of work. We estimate that around 50-60% of the time has been devoted to these activities, leaving the 40-50% remaining time to the actual development of the game. The conclusion we draw is the following: if you have the resources, hire someone to manage all this stuff (especially, your social networks).

Another thing we did alright was to establish and adhere to a work routine. This is especially important when you work from home, as we do. We would set weekly goals and monitor whether we fulfill those goals. The only setback is that sometimes we finished working too late, precisely because the border between our personal and professional lives became fuzzy as a consequence of working from home.

Difficulties

Now I want to mention some things that have been difficult for us. First, and as I mentioned before, PR and marketing are really time-consuming activities, especially because we had to learn on the go lots of stuff: how to write press releases, how to find our target audience, how to connect emotionally with such audience, etc.

Our initial plans was to keep this blog and our Youtube profile updated with fresh contents but it hasn't been possible. Maintaining a development blog is a tough work, especially if you're interested in writing about technical details of the development, which requires beforehand planning. In the end, I've basically written some posts about the events we have attended, but that is not what the blog was meant for initially. Something similar has happened to our Youtube profile: creating and editing videos is a harder activity than we had anticipated.

Things to improve

We have identified some things that we should improve either in the next year or in future projects. First, we intend to choose events with more criteria in the future. Attending so many events as we have this year has been a great experience in many aspects, but they require money and time (preparing the material, booking the flights and hotel, etc). In relation to this, we also failed to make some time predictions correctly because we didn't factor in the time of these events appropriately. This is the reason why we first scheduled the release of Breaking Fast in the end of 2016, but we've had to put it off by the beginning of Spring 2017...

Also, although from the very beginning we had built a contact list, we didn't use it until very recently, which has been a wasted opportunity to engage with our potential customers sooner. Sending newsletters is an important activity that we should have started much earlier.

Although we can state that we are more or less well-known in Spain, with several articles in different specialized media, we fail to be known outside Spain. And this is a real problem because most of our sales are expected to be made abroad, especially in USA and Russia. Therefore, one of the goals for the beginning of the year is to contact these international media in order to raise a wide awareness of Breaking Fast.

Finally, I leave you with a video summary of our 2016:


Thanks for being there and reading these posts. We really wish you a happy 2017: the year of Breaking Fast! :D

lunes, 17 de octubre de 2016

Gamepolis Indie Zone: A Summary

Hi folks!

It's been too long since the last post, so first things first: sorry about the delay. As you may know, we're working hard to meet several deadlines with our game Breaking Fast, about which I'll write something more technically-oriented soon.

By the end of July we attended Gamepolis. But unlike in the previous years in which we participated as general audience, this year we were presenting our own game: Breaking Fast.

Our stand at Gamepolis. From right to left, Óliver, Manuela and myself

The Indie Zone, which was located close to the entry doors, consisted of a circular area in which 16 indie studios were showcasing their games, most of them, if not all, still in development. As usual, the two main benefits of attending an event like Gamepolis, which is targeted at a broad audience, are obtaining feedback and raising awareness of your game, and getting to know other professionals who have the same dreams and aspirations as us. As for the last point, we're very happy that we could meet the developers of great games like Cubotrox, Hive, Noahmund, Crimson Breath or Charlie Beard, among others. We even went out for a dinner one night after the show!




Pictures with some of the other studios that participated in Gamepolis

The other advantage of participating in this event, that is, exposing your game to a big audience, turned out a fantastic experience. People of all ages (although especially kids and teenagers) would play for a really long time, and they'd come back later bringing more friends to show that 'crazy game with breakfast food'.



People enjoying the Breaking Fast experience. Locomalito and Gryzor also enjoyed it!

We even organized a tournament in which the best three players would win an official Breaking Fast tee. The initiative was really welcome, and hundreds of participants signed up for it. Knowing potential fans of your game is very rewarding, and we took a good deal of pictures with them. Some of them covered Breaking Fast on their Youtube channels, which is something that we, as indie developers, always appreciate a lot.




Some of our more loyal fans. Thanks so much!

Finally, as part of the participation, we were eligible for different awards, and good news are... we won the Public Choice Award! Even when the economic value of the award cannot be dismissed for a low-budget studio, the real value comes in the form of motivation and inspiration to continue improving the game. It's a certainty right now that people enjoy Breaking Fast, and enjoy it a lot. It's just a matter of polishing it well. The other awards went to Noahmund (best sound), Hive (best game as chosen by the jurors), Crimson Breath (best visuals) and Cubotrox (most innovative game).




If you want to read something very cool (and deep) about Gamepolis and about the indie scene in general, check this out (in Spanish, sorry).

See you!

miércoles, 17 de agosto de 2016

Mallorca Game and Gamelab 2016

I want to discuss today our experience during two videogames events that we had by the end of June: Mallorca Game and Gamelab. These two events are very different from each other, with the former being targeted at a broader audience, and the latter oriented towards professional game developers.

Mallorca Game

The fourth edition of this event brought a big deal of attention from gamers and cosplayers.  It was a two-days event where people could buy almost anything you can imagine from the videogames and manga worlds, and where we, the indie game developers, could showcase our game. We had a long table with enough space to set up everything we needed to present our game Breaking Fast. We hung some posters, prepared our monitor and four controllers, and laid some promotional material on the table, such as flyers and business cards.


We didn't expect such a big audience, and again like in Boston and Cartagena, the feedback was really valuable and positive. People from all ages played our game and especially some kids wouldn't let go the controller for a (too) long period of time.


As part of the event, there were three awards to the three best indie games that were presented at the so-called Mallorca Game Awards. In the gala ceremony, which was held during the last day, we were awarded with the second prize to the best indie game.


We were 'snatched' the first prize by Cubotrox, an amazing and innovative puzzle game created by two twin brothers from Valencia that we got to meet, coincidentally, at Gamelab.

As usual in our trips, we took some time off in order to visit Mallorca and enjoy really nice food.



Gamelab

As I mentioned before, whereas Mallorca Game was targeted at a broad audience, Gamelab was very focused on professional game developers. Actually, the number of attendants seemed to be lower than at Mallorca Game, and the quality of the conferences was amazing (e.g. John Romero...).

 
The feedback that we gained was more polished and concrete, although not so many people played Breaking Fast. David Mariscal, who is collaborating with us, came to help us out.


While in Mallorca we had a long table for us (actually more space than we actually needed), at Gamelab the space was too narrow. Being a multiplayer game, it was kind of annoying when four players wanted to play together, as they'd have to stand too close to each other and still they would take part of the space from the indie games to our right and left.


One of the main benefits of attending an event of recognized prestige like Gamelab (in addition to the feedback) is the possibility of networking with other important indie teams and professionals of different videogames-related areas. And this networking does not boil down to talking during the event, but also after the official time. In particular, a party was organized in a cottage with a big swimming-pool and free beer.
 

Two guys from Machinima SBOC, with whom we had the chance to talk, wanted to record the event live (but they finally couldn't because there was no Wi-Fi available). Yet they made a couple of videos about their experiencie at Gamepolis and they played our game, Breaking Fast! :D


As I said before, we met Cubotrox makers, and although we didn't know them by that time, we would meet them later at Gamepolis (more on this in the following post). You can take a look at other great indie games presented at Gamelab here.

viernes, 8 de julio de 2016

Game Loops with Fixed Simulation Steps

Hi!

Today I want to talk about game loops. If you're a game developer, you surely know what a game loop is. However, let me summarize it with the following image:

Figure 1. Traditional Game Loop (from http://gameprogrammingpatterns.com)

A game loop is basically a sequence of instructions that is repeated continously from the beginning to the end of the game and which is in charge of interpreting input, simulating the world and rendering the world on screen. Very often, there is a 1:1 mapping between the concept of frame, and one execution of the loop, because a frame of the game is rendered each execution of the loop. However, this doesn't need to be the case and you can have different frame rates for the rendering function and for the simulation function. In fact, a common approach in sophisticated, simulation-intensive games is to fix the timestep of the simulation function in order to achieve predictable and deterministic behaviour of the simulation. Meanwhile, the render function is executed as fast as it can run, leading to a higher, variable display rate. You can read more about this decoupling in the following eye-opener posts:


I actually encourage you to read the previous posts (especially the first one) before continuing reading. Otherwise, this post may be difficult to follow.

I had the idea of writing this article because I tried to use the technique suggested in [1] with no success. After failing, I skimmed through the comments of the post and I found two comments (by Nick and Voy) which basically stated that although the technique was really valuable, the implementation suffered an off by one error, which resulted in no simulation step taken at all. This was in fact the problem I was having (entities of the game weren't moving), and therefore I set out to fix it for educational purposes.

Before showing the actual code, let me illustrate with figures how we want the simulation to happen:

 Figure 2
 Figure 3
Figure 4

Figure 2 shows that we divide the time of the game in discrete chunks of the same size. Don't let the concrete numbers fool you: you'll typically want the simulation to take small steps (say 0.01 seconds) in order to reduce numerical errors. The point is that there are concrete, fixed moments over the life of the game at which we want to simulate the world, and we DON'T want to simulate at any other moments between those.

For instance, let's assume that the time is somewhere between the beginning of the game (0) and the first moment at which we want to simulate (1). This corresponds to what Figure 3 shows. The green arrows show different game times at which we can be, whereas the red arrow shows the point that we actually want to simulate for these times. Notice that while we're between point 0 and 1, we simulate at time 1. Similarly, as illustrated in Figure 4, while we are between moments 1 and 2, we want the simulation of time 2. And so on.

At this point, you might be thinking that this is somewhat incorrect, right? Because this wouldn't produce a smooth movement, as we're treating many different times the same way. That is, the position (and velocities) of objects shouldn't be the same for every time value between 0 and 1. If we're on time 0.2 and then the game advances to time 0.5, you want the objects of the game to move a little bit. However, with what I've just told you up to now, objects wouldn't move until the time of the game advances past 1, at which point we would make another simulation.

This is when interpolation comes into play. The key of the approach is the following: we simulate the future and we interpolate proportionally to the distance to this future. Therefore, if we're on time 0.2, we're further away from the future than if we're on time 0.8. The closer to the future, the closer to the simulation. We can achieve this with a linear interpolation in which an alpha value determines how close we're to the future:

position = position * (1 - alpha) + futurePosition * alpha,    0 <= alpha <= 1

Without further ado, here's the C++/SFML code for the simulation:

 //Initialization (out of the loop)
 const auto dt = sf::seconds(0.01f);
 auto accumulator = sf::Time::Zero;
 auto lastTimeUpdated = 1;
 MotionSystem::SimulateFuture(dt.asSeconds(), futurePos, futureVel);

 //In game loop
 accumulator += elapsedTime;  
 double timesDt;  
 const auto fractionToNextFrame = modf(accumulator / dt, &timesDt);  
 if ((timesDt + 1) > lastTimeUpdated)  
 {  
    for (uint16_t i = lastTimeUpdated; i < timesDt + 1; ++i)  
    {  
       MotionSystem::SimulateFuture(dt.asSeconds(), futurePos, futureVel);  
    }  
    lastTimeUpdated = timesDt + 1;  
 }  
 MotionSystem::Interpolate(fractionToNextFrame, futurePos, futureVel);  

The accumulator variable holds the time that has passed since the game started. Then, by using the C++ function modf, we can extract how many times dt has passed and how close we are to the next frame.

Note that before entering the loop, we have made the first simulation, the one corresponding to the first point in time at which we want to simulate. That is, we have simulated the first point in the future and lastTimeUpdated is assigned this information.

Let's lay out an example: consider that the first time the loop executes, accumulator = 0.004. Being dt = 0.01, we're almost halfway between the present and the simulated future. Given that accumulator / dt = 0.4, after the execution of modf, the variable timesDt = 0, and fractionToNextFrame = 0.4. The if condition is not met, and therefore no simulation is performed. We interpolate the current position with the future position according to fractionToNextFrame when we call MotionSystem::Interpolate. Internally, this function does something like the following:


position = position * 0.6 + futurePosition * 0.4

Let's assume that in the following execution of the loop, accumulator = 0.018. Now, timesDt =  1 and fractionToNextFrame = 0.8. The if condition is now met (2 > 1) and in the for loop, we make one simulation of the future, reaching the second simulation point, and updating lastTimeUpdated = 2. Finally, we interpolate as follows:

position = position * 0.2 + futurePosition * 0.8

In case there's a frame drop or the rendering function (which would be executed after this simulation) takes too long, the simulation can catch up in a controlled way because it will be executed all the times it is required in a fixed timestep. You can work out the numbers yourself considering a sudden accumulator = 0.12.

Hope you liked this post. If you notice that something is missing or that I made any mistake, let me know so that I can fix it.

See you!

miércoles, 6 de julio de 2016

Breaking Fast on Steam Greenlight!

Hi buddies!

Breaking Fast is now on Steam Greenlight! I already wrote about this game several posts ago, but here's a quick summary: Breaking Fast is a 2D racing game in which the main characters are pieces of breakfast food, like a toast, a carton of milk or a strip of bacon. Following the lines of masterpieces of  fun like Mario Kart, Breaking Fast proposes frenetic races in delicious scenarios like a kitchen or a picnic. During these races, it's not only a matter of being faster: you also need to be smarter and stronger, because you have to avoid obstacles (all food-related) and the attacks from other players.


The game will come out by the end of 2016. We're working on lots of stuff: polishing animations, creating new scenarios and characters, and on an online mode. Also, we collected a good deal of feedback from users and developers at both Mallorca Game and Gamelab (more about them in future posts), and we'll try to incorporate the best ideas to enhance the gameplay experience.

By the way, we're also very proud that we won the 2nd prize in the Mallorca Game Awards! But as I just mentioned, I'll give more details about this in future posts. 


For now, in addition to upvoting it if you like it, you can watch the trailer we prepared for Steam.


lunes, 13 de junio de 2016

Breaking Fast at BayDevs Retromiranda 2016

Hi!

On May 21st, we presented Breaking Fast at BayDevs, an event held within Retromiranda for showcasing indie games. The event was a great opportunity to gather more feedback and, even more importantly, to get to know other fantastic national indie development studios, in particular,  Sons of a Bit, Calcifer Games and MoreThanGamers.

The former presented its game Isla Bomba, a puzzle platformer with lots of levels in which you have to throw bombs in the water before they explode. For this purpose, you need to combine the abilities of different animals. The game features very nice and polished 3D environments and models in the lines of the last titles of Donkey Kong, together with a fun and engaging gameplay.

As for Calcifer Games, they presented a game called U.F.O. RISE, in which you have to guide an inoffensive alien through a stage in which enemies (furious farmers) spawn continuously. The goal is to gather pieces of its broken spaceship and your only weapon is your ability to turn your enemies into allies so they can fight for you.

Finally, MoreThanGamers presented Crazy Princess, a challenging game where you play the role of a charming prince who is pursued relentlessly by princesses who want to marry him desperately. The game starts out simple, but soon it becomes an interesting challenge because the girls are quite tough and fast.

The participating studios also had the opportunity to give a talk about their studios and their games. In the next video, you can watch part of my talk (in Spanish).


As for Breaking Fast, we are very happy with the feedback received from the organizers and from the attendants. In the next video, you can watch two kids enjoying the game:





Also, we were interviewed for Ruta Gamer, a podcast about videogames hosted by the Catholic University of Murcia. You can listen to us from minute 25.

Finally, we had the chance to visit Cartagena, a really beautiful town with dozens of historical monuments and ruins. That fabulous Roman theater... 


On Sunday, the day after the event, we could even enjoy a day of beach and sun, shellfish and fried fish :).





Hope you have enjoyed reading about our adventure in Cartagena. 
FM

viernes, 13 de mayo de 2016

A Brief PAX East 2016 Post-mortem

Hi folks!

As many of you probably know, we were presenting our game Breaking Fast during PAX East 2016. It has been the first time that we have attended this event, and it has been actually the first time that we have shown Breaking Fast in any game event and in front of such a huge game audience. Without further ado, I am going to summarize our experience during PAX.

Pre-PAX story

Back in the end of February, we were considering whether it would be feasible to attend this event. By that time, the game was in a very raw state, but we did want to take advantage of any opportunity to promote the game, so I filled out the contact form that was available on the PAX website, 'just in case', I told to myself. Some time later, a PAX sales manager contacted us via e-mail to request more information about the game. We sent him what we had at that time: a brief description of the game, a link to our website, and a video where the game was succinctly introduced, shown below.


Some time later, he responded that the game seemed really fun, and he encouraged us to contact him again when we had something more solid. In an outburst of optimism, we told him that we would reach out to him again in two weeks with a playable demo of the game. Of course, we understimated the effort that this goal would entail.

After a month of intense work, by the beginning of April, we had the demo and we had recorded some new gameplay videos in which some friends were playing the game. We had lost our hope to attend PAX because the event would take place in just three weeks. Since I wanted to keep the contact with the sales manager, and also with a view to have some chance for next year, we sent him the demo and the new gameplay video. A big surprise arrived in the form of a reply to our e-mail: "Awesome! I have a 10x10 available at East for you guys if you’re still interested in exhibiting. I know the show is coming up fast.".

At that point, we were a bit in shock, because we really had lost all hope to attend the event, and now we had to decide quickly whether we wanted to make a sudden moderately high investment. Of course, as you may have followed our tweets and Facebook posts, you know that we took the offer.

In two weeks, we had to make all the arrangements. Fortunately, flying to Boston is not too expensive (not at least as expensive as New York), and we found a good offer for a really nice hotel, which turned out to be excellent. However, we still needed to make lots of preparations for the event, including all the material that we would be taking: tee-shirts, posters, x-banner, business cards, flyers, and plenty of electronic devices that we could not afford hiring there. As you can guess, our luggage was kind of heavy...


As part of the registration in PAX, we received a huge list with press contacts that would attend the event. We attempted to reach as many as these contacts as we could, although we knew that it would be difficult to make appointments with such a short antipication. In fact, we only received around 8 replies to the burst of e-mails that we sent.

And of course, and more importantly, we needed to polish the game and we wanted to add more characters. Actually, Manuela (the artist) sketched and designed the bacon during our flight connection in London, and it was the most popular among all the characters!

Bacon, the popular!

During PAX

For those of you who have had the chance to attend PAX, you surely know that it comprises a huge expo floor. We were really amazed while admiring the stands that big companies were setting up upon our arrival. 

Survival of the Fittest featured an awesom T-rex that people could ride for a nice picture. 
When there is budget...

The set-up of the booth was smooth, except for an unfortunate setback: we had taken three PC screens with the idea of using one of them for looping a teaser of the game, and the other two for playing. However, one of the PC screens had apparently suffered a stroke during the flight and was broken. I was a bit irritated, but fortunately, we realized this on Thursday evening, not too late, and we had some time to buy a new one, which was cheaper than it is here in Spain, and which was better; every cloud has a silver lining.


Breaking Fast Teaser

Our general experience during PAX was great, with lots of people willing to play our game and to rate it as "very fun" or "addictive". Some of them were certain that the game would be a hit and were disappointed to know that the game was not available yet. We collected as many e-mails of potentially interested buyers as we could.

There is an important issue that we overlooked at first but that we fortunately corrected soon: the booth distribution. On the first day, Friday, the booth was organized with the table perpendicular to the surface, as you can see below.

Original booth distribution

This seemingly normal distribution turned out to be a psychological barrier for many people who were curious about the game but were reluctant to "come into" the booth to try it. Changing the distribution in such a way that the game was available to any passer-by made a big impact: even when on Friday lots of people played the game, on Saturday and Sunday (days on which we had already changed the distribution) there were peak moments with people linining up to play and watching how others played. This was an important lesson for us: make as easy as possible for players to play your game; don't assume that people who want to play the game will actually do it if they have to engage in a close relationship or a conversation.

Changed distribution: passers-by could play directly the game without entering the booth

As a final note to my PAX experience, I want to boast about something: I could introduce myself and talk a little bit with Ron Gilbert, the creator of a masterpiece known as Monkey Island. He was there presenting his own game called Thimbleweed Park, which is really promising, especially for those lovers of old-school adventure games.

Post-PAX, now what?

Watching hundreds of people playing your game provides an invaluable feedback and you get a good sense of what people like the most and the least. We intend to release the game by the end of summer, and therefore we still have time to improve over the weaker points of the game and to polish the stronger ones.

There are other events coming up and we plan to present the game there; these events include Retromiranda Baydevs, Mallorca Game, and Gamepolis, although we do not discard attending other international events. In the end, we are just seeking the biggest possible feedback as well as to raise awareness of the game so that potentially interested people learn about it before the release.

If you have any specific question about our experience in PAX, do not hesitate to leave a comment.

Thanks for reading and see you!
FM

lunes, 4 de abril de 2016

The Importance of Early Feedback and Testing

Hi all!

How are you doing? We continue working hard on Breaking Fast to make it the best game you've ever played in you life! ...

Last week we had a couple of testing sessions with people external to the development team, and these sessions were quite eye-opening in two senses: first, it allowed us discovering some bugs, which is the tradional goal of testing; but second and more importantly, we noticed that some design aspects were misleading, and others that we didn't consider so important were actually key to the players.

In this post, I intend to emphasize the importance of this early feedback and to summarize the most important changes that we applied as a result of this feedback. You may think that some of the changes are subtle, but sometimes a subtle change may cause a major impact on the overall gaming experience. You may also think that some changes were obviously required, but here's the key to external feedback: once you're very focused on your project, it's easy to lose pespective and you need someone to shove you back so that you can see the complete image instead of the individual pixel.

Why is early feedback that important? In addition to the loss of perspective reason, obtaining feedback may help you not diverting too much from your original goal. Usually, people ask you what your game is about, and you can compare your answer with the impressions that people get when they play your game. If you see they don't match, you can take actions quickly.

Also, it is a well-known principle for software engineers that the difficulty in performing changes on software increases as the development moves forward. This is known as the cost curve, first proposed by Boehm. Therefore, early feedback may result in cheaper development changes.

Figure 1. Boehm's Curve (from http://www.agile-process.org/change.html)

And how did we change Breaking Fast as a result of the early feedback? Here we go with a summary of the most relevant changes:
  1. Position must be always visible: at first, we decided that showing the distance covered by each player was enough. However, thanks to the feedback, it became clear that players expect to see their positions continously. Therefore, we added an element in the HUD to show this information. Still, we need to sort out how to show the relative position with each other player and the distance among players. But now we are sure that this is a problem that is worth the effort.
  2. Throwing stuff is cool: in Breaking Fast, there are two types of boosters; those that activate an attack as soon as they are picked, and others that require the players to throw something explicitly. In our testing session we understood that players felt more rewarded when they could throw somehting they had picked. Therefore, a booster that originally was designed to be activated automatically was re-designed to be thrown.
  3. Physical attacks must stand out: characters in Breaking Fast can attack each other physically. This is a cool and fun mechanic, but players of the testing session agreed that the animations should stand out more, especially because characters in 3 players or 4 players races are small. So we decided to exagerate the animation.
  4. Players want to know that the race is ending: in several races there were a couple of players that didn't realize that the race had ended and felt frustrated because they could not control the character anymore. We have solved this by a) adding an alarm that is triggered when there are 10 seconds remaining; b) by showing these 10 seconds bigger on the screen; c) and by accompanying each of the last 10 seconds with an audible tick sound.
  5. Beginning of the race: we designed the beginning of the race in such a way that players had to press the movement key/button only when the initial countdown had gone to zero; otherwise, characters wouldn't move until they pressed the buttons again. This initial idea was implemented in order to require more precision from the players, but it turned out to give the impression that their controls didn't work, and it wasn't that fun anyway, so we discarded it.
  6. Turbo was a big advantage: characters in Breaking Fast can activate their turbo upon some conditions. However, the original design made the turbo too advantageous for those meeting those conditions and mastering the controls. We therefore redesigned this mechanic to make it harder to exploit.
  7. Bugs detection: of course, we found some bugs that fortunately could be quickly fixed, but we wouldn't have been aware of them hadn't been for the testing session with several players doing lots of stuff concurrently.
And this is it! I hope you're more conviced (if you weren't) to test your game and to retrieve early feedback as soon as possible. In the end, it's in your best interest and will save you development time.

See you!
FM

domingo, 13 de marzo de 2016

Progress of Breaking Fast: Boosters, Animations and Collectables

Hi buddies!

How are you doing? We continue working hard and happy on Breaking Fast. Our goal is to have a playable level for the next week. In this post, I summarize the most important advances that have been accomplished since the last post:

- New boosters: we are always thinking of new ways for players to mess up with their adversaries. We have a very interesting new booster in this direction, but we don't want to spoil it yet. More information very soon!

- Collectables: when we first conceived Breaking Fast, collectables (i.e. items that players can collect during the race) were not considered. However, after thinking more about it and prototyping a bit, we have changed our minds: collectables can add more depth to the gameplay. These collectables now fill the players' enery bars, with which they can run faster for a period of time. Although we don't have the final art for the collectables, we have their tracking behaviour, as you can watch in the following video:


- Animations integration: we added animations for the toasters, the beaters and the player. The following videos show the first two:


 

 

- Refactoring of code for player management: this is not something observable, but it took quite a while and has helped me better understand how to modify the behaviour of players. Before the refactoring, the code for player management was a bit tangled and therefore, adding any new feature to their movements or perform any modification to their behaviours were tasks that really gave me the creeps. To put it simple, the refactoring consists of identifying different and exclusive states (e.g. jumping and rolling) and perform the updates of each state in different functions. That way, I don't need lots of variables to manage the mutable state, but I can make do with a single instance variable that holds the current state.

- Leap against obstacles: the player can now jump against obstacles to reach new places. This is something that would have been very tedious to add and prone to error, hadn't been for the aforementioned refactoring.

More videos with the new features and effects will be available soon on our Youtube channel and the rest of the social networks  You can find more information to keep in contact on our web page, where you can also subscribe to receive the latest news on the advances of Breaking Fast.

FM

lunes, 29 de febrero de 2016

Breaking Fast: Menu Navigation

Hi all!

Breaking Fast is moving forward. This last week we worked on the menu navigation part, which includes the menu screens through which players navigate until the race begins. As for the technical side, I want to discuss the two main issues you have to consider when implementing this aspect of a game: how to manage the flow between screens, and how to pass information among screens. Let's get started!

Flow Management Schemes

There are two main "schemes" (I can't think of a better word) during menu navigation. In the first scheme, each screen is actually a different screen. This implies that, upon changing among screens, we swap the contents of one screen with the contents of the other screen. This can be implemented as a function in the screen manager:

 function changeScreen(newScreen)  
  currentScreen.unload()  
  currentScreen = newScreen  
  currentScreen.load()  
 end  

In order to manage transitions among screens (i.e. the implementation of the screen manager), it is useful to think of Finite State Machines. You can watch a series of two videos that I prepared for gaining insight on the matter.



 
In games it is also very common to use another scheme, in which the contents of different screens are all drawn, but only one of them has the focus at any moment. Think for example of a racing game in which you have to choose a scenario and then, the time of the race. You can implement this by using the aforementioned scheme, but it feels kind of overkill to unload one screen and to load another one just for the purpose of selecting the time. It seems more natural that the same screen presents both options, but that the player can only change one of them at any time. Actually, we can stop thinking of different screens in this situation. This "move the focus" approach can be implemented by means of screen phases or states

In particular, in Lua, we can hold a table of states, and we iterate over this table in order to draw and update the screen. We also have a variable that holds the value of the current state (the current focus), and we delegate the interaction of the player (be it with the keyboard or a gamepad) to the actual focused state. Some self-explanatory code is shown next:

 function load()  
  table.insert(states, state1)  
  table.insert(states, state2)  
  currentStateFocus = state1  
 end  
 function draw()  
  for _, v in ipairs(states) do   
   v.draw()  
  end  
 end  
 function update(dt)  
  for _, v in ipairs(states) do   
   v.update(dt)  
  end  
 end  
 function onKeyPressed(key)  
  currentStateFocus.onKeyPressed(key)  
 end  

Communication between Screens and States

Passing information among screens is essential. In particular for Breaking Fast, consider the following flow of actions:
  1. Players select the characters that will participate in the race.
  2. Players select the scenario in which the race will take place.
  3. Players select the duration of the race.

Consider the figure above, in which we mix the two menu navigation schemes explained before. Each transition among screens and states conveys both new information and the information carried by older transitions. In the end, when we prepare the race screen, we need to know all the options that have been chosen by the players through the different screens. Fortunately, implementing this in Lua is very simple thanks to a powerful feature of the language: function overriding of imported modules. Consider the following module, which models the Time Selection State:

 local timeSelectionState = {}  
   
 -- other functions  
   
 function timeSelectionState.toScenarioSelection()  
 end  
   
 function timeSelectionState.toGame(timeChosen)  
 end  
   
 return timeSelectionState  

As you can see, we are defining two empty functions. Any module that imports this module can re-define (i.e. override) these functions. So for example, consider the Scenario Selection Screen module, which contains the Time Selection State:

 local scenarioSelectionScreen = {}  
   
 -- other functions  
   
 function timeSelectionState.toScenarioSelection()  
      currentStateFocus = scenarioSelectionState  
 end  
   
 function timeSelectionState.toGame(timeChosen)  
      for _, v in ipairs(states) do  
           v.unloadResources()  
      end  
      scenarioSelectionScreen.toGame(numberOfPlayers, playersInfo, scenarioChosen, timeChosen)  
 end  
   
 function scenarioSelectionScreen.toGame(numberOfPlayers, playersInfo, scenarioChosen, timeChosen)  
 end  
   
 return scenarioSelectionScreen  

As you can observe, this module re-defines toScenarioSelction() and toGame() functions. In particular, toGame() unloads all the states of this screen, forwards the racing time that has been chosen by the player, and pads it to more information accumulated during previous phases. In turn, scenarioSelectionScreen defines an empty toGame() function that cam be re-defined by the module importing it. This latter module could therefore add some more information and pass it to the Race Screen.

And this is it! As always, I hope you enjoyed this tutorial, and if you have any question, don't hesitate to ask! Any feedback is also well appreciated.

See you!
FM

domingo, 21 de febrero de 2016

Breaking Fast: From Ad-Hoc to Scalable Local Multiplayer System

Hi!

This week we have been working on the local multiplayer of Breaking Fast. The first version of Breaking Fast, which was playtested several months ago, had an ad-hoc art design for only two players, and therefore neither the art nor the code were scalable for moving easily from 1 to 4 players. Therefore, the main work carried out during this week has consisted of refactoring the code so that it accepts a unique set of assets, and that it scales this set according to the number of players. Also, different viewports are created according to the number of players, as shown later.

As every programmer that is reading this post can figure, even for a medium-sized codebase the aformentioned task entails lots of work, but going step by step is the only way to go. In the following sections, I briefly explain the most important code changes that were performed:

1) Substituting scalar values by arrays of values: in the first version of the post, we had something like:

 local Camera = require "Camera"  
 local camera1 = Camera()  
 local camera2 = Camera()  
 local Player = require "Player"  
 local player1 = Player.new(...)   
 local player2 = Player.new(...)   

Of course, if we want to achieve scalability, this is not the way to go. Therefore, we changed the aforementioned scalar variables into arrays, as follows:

 local Camera = require "Camera"  
 for i = 1, numPlayers do  
   cameras[i] = Camera()  
 end  
 local Player = require "Player"  
 for i = 1, numPlayers do  
   players[i] = Player.new(...)  
 end  

This applies of course to every element that needs to be replicated according to the number of players.

2) Re-designing assets for one player scenario: in the single player mode, there are no viewports (there are no any other player), and therefore the assets need to be as large as they can be. Under any other circumstances (more than one player), the assets need to be scaled down proportionally according to the resolution and aspect ratio for which the game is being developed, 1920x1080 and 16:9, respectively.

In the first prototype of the game, the assets were designed ad-hoc for two players. For example, the background was designed with a resolution of 1920 x 540, and I would place two different backgrounds in different positions:

 background1 = love.graphics.newImage("background.png")  
 love.graphics.draw(background1, 0, 0)  
 background2 = love.graphics.newImage("background.png")  
 love.graphics.draw(background2, 0, 540)  

(This is an oversimplification for several reasons; first, we actually add the background to a layer of a camera, because we want it to scroll a little bit. Read this series of posts to get more information on parallax scrolling. Also, what we actually draw is not the background itself, but a batch of backgrounds that we paste once after another in order minimize draw calls and provide an illusion of infinite scenario).

After the changes, we have only one background with a resolution of 1920 x 1080*, and therefore we don't need to place background for different players in different positions; the viewports will take care of this according to the number of players.

*(Again, although this would be technically possible, we use a larger resolution to support scrolling in the vertical axis and for fixing some problems with different aspect ratios, as discussed later).

3) Designing viewports: if we want that more than one player can play on the same machine, we need to provide each player with a fragment of the screen. Each fragment is called a viewport. In the first prototype, we didn't need to worry about viewports, because everything was drawn ad-hoc for two players. However, now we have a unique set of assets, and depending on the number of players, these assets must be replicated for the different players and must be scaled down appropriately.

For example, for two players, we want that the first player is allocated the upper half of the screen, whereas the second player should be provided with the lower half. In the case of four players, each player should have a quarter of the screen.

In order to implement viewports in Löve, I saw two alternatives: using scissors or canvases. I didn't get to really grasp how to use scissors for this purpose in my first attempts (see video below), so I switched my attention quickly to the second option, which turned out to work great.


Fail with using scissor. The second player viewport was rendered onto the first player one.

Canvases represent an off-screen rendering target. Internally, it creates an OpenGL framebuffer object to which the contents are drawn, instead of drawing the contents to the screen. The process from a high-level perspective is as follows:
  1. Create as many canvases as the number of players (one canvas per camera).
  2. Depending on the number of players, scale the assets that will be drawn to the canvases.
  3. Place each canvas in its correct position according to the number of players.
  4. Draw all the stuff that we used to draw on the screen on the canvases instead, and then, draw the the canvases.
Some simplified code for the three players case is shown next:

 if numPlayers == 3 then   
   cameras[1]:setScale(2, 2)  
   cameras[1]:createCanvas(0.5 * intendedWidth, 0.5 * intentedHeight, 0, 0)  
   cameras[2]:setScale(2, 2)  
   cameras[2]:createCanvas(0.5 * intendedWidth, 0.5 * intentedHeight, 0.5 * intendedWidth, 0)  
   cameras[3]:setScale(2, 2)  
   cameras[3]:createCanvas(0.5 * intendedWidth, 0.5 * intentedHeight, 0.25 * intendedWidth, 0.5 * intentedHeight)  
 ...  

The createCanvas() function, which is added to my camera module, takes the width and height of the canvas, and its top left position. This would yield the following layout for the screen:


As part of this viewport design, we also needed to change the camera code for drawing. However, modifying this code to support drawing on canvases was surprisingly easy.

camera.lua

 function camera:draw()  
  love.graphics.setCanvas(self.canvas)  
  love.graphics.clear()  
  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  
  love.graphics.setCanvas()  
  love.graphics.draw(self.canvas, self.canvasLeft, self.canvasTop)  
 end  

The lines in bold text are the only additions we needed to add in order to make the function work with canvases.

You can watch the result of our work in the following video. Challenge 1: By the way, do you recognize the musical masterpiece that goes with the video? :P


4) Managing aspect ratios: ensuring that Breaking Fast can be played on most aspect ratios is vital, but it is also tricky. The solution requires twofold work from the artistic and code perspectives.

First, let's see what happens when we execute the code for two players for a 16:9 aspect ratio (the aspect ratio for which the game is being developed):


Now, consider the same code but for a resolution of 1280 x 800, which is a 16:10 aspect ratio and very common for a Macbook Pro, for example:


As you can see, the assets within the canvases are not properly scaled. Well, actually, they are properly adjusted to the width (note that the countdown on the top right corner is properly placed), but not to the height, because some part of the scenario is lost, like the legs of the characteres.

In order to solve this, the trick is to scale all the assets down to adjust them to the height of the screen, and given that the assets (e.g. the background) are bigger than the screen, the player will have the impression that the adjustement has been perfectly done in both dimensions, as shown next:


There is only one inconvenience. As we are losing the perfect adjustment to the width, the HUD elements like the energy bar or the countdown are not perfectly in the middle or at the end of the screen, respectively, but they have a small offset to the left.

Assuming that we have a perfect adjustment to the width, the middle of the screen is calculated as:

screenMiddleX = 0.5 * intendedWidth

, where intendedWidth is the width of the design resolution (1920). If we want to correct the position, we need to multiply this value by the following proportion:

screenMiddleX = 0.5 * intendedWidth * (scaleForAdjustToHeight / scaleForAdjustToWidth)

The result would be as follows:


Note that now the HUD elements are now properly placed.  The result for many different aspect ratios is shown in the next video. Challenge 2: again, do you recognize the composition that accompanies the video?


And that's all for now. We'll keep you  posted on the advances of Breaking Fast, so stay tuned!

See you!
FM

viernes, 15 de enero de 2016

Iterator Invalidation in C++11/14 on Vector Erasure

Hi buddies!

How are you doing? I recently started working on another game for mobile platforms, in parallel with Breaking Fast. More news on that very soon, but today I want to share with you a problem that I found while working on a piece of code for that game.

At some point, I wanted to test whether I should remove a laser beam from a vector of laser beams. The context was something similar to the following:

 for (auto itLasers = mPlayerLasers.begin(); itLasers != mPlayerLasers.end(); ++itLasers)  
 {  
     for (auto itEnemies = mEnemies.begin(); itEnemies != mEnemies.end(); )  
     {  
       if (collide(*itLasers, *itEnemies))  
       {  
         itEnemies = mEnemies.erase(itEnemies);  
       } else  
       {  
         ++itEnemies;  
       }  
     } //end nested for  
 } //end outer for  

So basically, I tested every possible laser object against every possible enemy object. If a collision is detected, then I remove the enemy from the vector of enemies.

But wait: I have to remove the laser object that collided with the enemy as well. Assuming that a laser object can hit more than one enemy at a time (which is the behavior I want to implement), I cannot destroy the laser object until I'm done with iterating through all the enemies.

The proper solution is to have a boolean value that is set to false before entering the nested loop, and to set it to true when a collision is detected. Upon exiting the nested loop, we check this variable and update the next iterator accordingly (in the same way I update the itEnemies iterator).  This results in the following code:

 for (auto itLasers = mPlayerLasers.begin(); itLasers != mPlayerLasers.end(); )  
 {  
     bool collision = false;  
     for (auto itEnemies = mEnemies.begin(); itEnemies != mEnemies.end(); )  
     {  
       if (collide(*itLasers, *itEnemies))  
       {  
         collision = true;  
         itEnemies = mEnemies.erase(itEnemies);  
       } else  
       {  
         ++itEnemies;  
       }  
     } //end nested for  
     if (collision)   
     {  
      itLasers = mPlayerLasers.erase(itLasers);  
     } else   
     {  
      ++itLasers;  
     }  
 } //end outer for  

However, the first solution that I implemented was different, and led me to discover an error with iterators handling. This solution consisted of pushing the iterators of those lasers that collided in another vector. Then, after the loop, I would remove the elements of the vector. This is easier shown in code than explained:

 std::vector<std::vector<std::unique_ptr<LaserInfo>>::iterator> toDelete;  
 for (auto itLasers = mPlayerLasers.begin(); itLasers != mPlayerLasers.end(); ++itLasers)  
 {  
     for (auto itEnemies = mEnemies.begin(); itEnemies != mEnemies.end(); )  
     {  
       if (collide(*itLasers, *itEnemies))  
       {
         //Check that it's not already in the vector  
         if (std::find(toDelete.begin(), toDelete.end(), itLasers) == toDelete.end())  
         {  
           toDelete.push_back(itLasers);  
         }  
         itEnemies = mEnemies.erase(itEnemies);  
       } else  
       {  
         ++itEnemies;  
       }  
     } //end nested for  
 } //end outer for  
   
 for (auto it : toDelete)  
 {  
    mPlayerLasers.erase(it);  
 }  

However, and this is the point of this post, this is completely wrong! Why? Because, according to the C++ standard in relation to the erase method:

Iterators, pointers and references pointing to position (or first) and beyond are invalidated, with all iterators, pointers and references to elements before position (or first) are guaranteed to keep referring to the same elements they were referring to before the call.

This implies that when we call erase on it in the second loop, all subsequent iterators are invalidated and cannot be used to erase the rest of elements. f

But what happens if for some reason, we really need to defer the erasure of the laser elements? We can do it with a traditional index, as the following code illustrates: 

 std::vector<int> toDelete;  
 int index = 0;  
 for (auto itLasers = mPlayerLasers.begin(); itLasers != mPlayerLasers.end(); ++itLasers)  
 {  
     for (auto itEnemies = mEnemies.begin(); itEnemies != mEnemies.end(); )  
     {  
       if (collide(*itLasers, *itEnemies))  
       {  
         if (std::find(toDelete.begin(), toDelete.end(), index) == toDelete.end())  
         {  
           toDelete.push_back(index);  
         }  
         itEnemies = mEnemies.erase(itEnemies);  
       } else  
       {  
         ++itEnemies;  
       }  
     } //end nested for  
     ++index;  
 } //end outer for  
   
 int count = 0;  
 for (auto i : toDelete)  
 {  
   mPlayerLasers.erase(mPlayerLasers.begin() + i - count);  
   ++count;  
 }  

Now, we are storing the index of the laser to be removed in the toDelete vector. Then, during the second loop, we access the elements through the index. We need to consider all the elements that have been erased at each execution of the loop by using the count variable, because erase() relocates all the elements that go after the removed element, moving them one position to the left.

And that's all. See you soon!
FM