When I heard about the New Year's Game Jam, I thought it would be perfect for my first game of the year. Unfortunately, I had some other plans for New Year's Eve which meant that I had a shorter period of time to develop this game. This is the postmortem for that game.
What went right
When I went to the NYGJ site to find out how the challenge worked, I noticed that they did not specify a theme. Having the option to do anything is nice but if you can't decide what you want to do then there is little chance you will finish a project within such a short timeframe. Having a plan, at least in your head, is important for really time-restricted projects. Thankfully the site had a theme generator (1GAM had not released their January theme yet so I couldn't use that). While the theme I was given, click the button, was rather generic, it was enough to get me to focus on a whack-a-mole style of game.
Mixed blessings
Knowing that I was going to only have a short period of time to work on this game was both a disadvantage and an advantage. By anticipating a short development time I opted to go with a much simpler game than I would have liked to but it also meant that I was able to finish the game and even get a slight polishing pass.
What went wrong
Perhaps anticipating a New Years Eve party is what caused me to make a rookie mistake but a simple order order of execution bug stumped me. With Flash, it is important to remember that the last playhead adjustment is the one that gets executed. This means a gotoAndPlay() followed by a stop() is not going to work well. This is a fairly obvious bug, but in my case things were a slight bit more complicated so obvious sequence was hidden from me.
For the lights I dispatch an event when an animation sequence finished playing then going to the default "off" animation to wait for orders to change the color of the lights. The problem is that the event dispatcher actually calls the event handling functions before returning. This means I tell my main game that it is time to start the next animation, which calls the light to set the color to the new value causing a gotoAndPlay() call to the appropriate color appearing animation. When the dispatcher returns, the light goes to the default off animation. Simply by moving the gotoAndPlay("off") call to before the dispatchEvent call solved the problem.
This bug is an important reminder that it is important to think about when things get executed. As the trend of having more cores instead of faster speeds continue, future speed gains will come from taking advantage of multiple cores, meaning that I expect to have to write more threaded code in the future. This makes order of execution issues even more prevalent.
Showing posts with label Debugging. Show all posts
Showing posts with label Debugging. Show all posts
Friday, January 10, 2014
Friday, August 9, 2013
Steam Trading Cards
I have been thinking about the Steam Trading Cards quite a bit lately as my free evenings have been spent playing games in order to collect the free card drops for games that have trading cards. I have received quite a few cards and have been selling the duplicates on the steam marketplace. Overall, I think it was an interesting marketing idea but at it's current implementation is a flawed system. As a programmer, I am use to debugging things so figured I would debug the Steam trading card system. Unfortunately, I do not work at Valve so my thoughts will lead to nothing but the exceeding remote chance that someone at Valve will somehow read this post and agree with my opinions.
Marketing wise, I am not sure that the addition of trading cards will actually sway any purchasing decisions very much for most people. That said, interest in the game generated by people playing the game more to gather trading cards will lead other people to buy the game so from an extended sales perspective this system could be potentially valuable. Unfortunately, due to the way the system is designed, it does not really do this but instead focuses on making commission profit from the marketplace. Why do I say this, well lets look at how the cards work.
There are a set of cards for a game, the number of cards varies but I have seen 5 to 15 Half that number of cards are earned by card drops from simply playing the game. This is the brilliant part of the scheme as poorer players earn stuff simply for playing which encourages them to play. There is the problem of people simply running the game and not actually playing it, but I don't consider it a real problem as the vast majority of people will actually play the game. Once the player has earned the drops from the game, they need to trade with other people, buy cards from the market, or wait for booster packs. Booster packs are only eligible to people who have used all their drops. This actually is a good idea. The problem is that the booster packs gives you cards immediately instead of adding more card drops. This means that once you have received all the card drops you never have to play the game again. This means that instead of encouraging players to play games longer and benefit from the word-of-mouth sales from people continuing to play older games, they are only making a few cents of commission from the marketplace when people sell cards.
The obvious solution is to make booster packs card drops. Still, I am not sure this is the best solution. Getting free cards is really nice and encourages people to continually log on to Steam which could lead to more sales. A much better solution is to keep the random booster packs, but also to give people an extra drop each week capped at the half-the-cards limit. People with drops would no longer be eligible for booster packs which would encourage players to play the older games keeping the communities for those games more active and resulting in more sales. While this would mean more people would earn badges, it would also mean more people trading cards on the market so the market commission profit would not go away plus there would be more sales of trading-card related games.
Such a very simple change would actually make the trading card scheme interesting instead of resulting in people simply playing games to gather the trading cards then not bothering with that game anymore.
Marketing wise, I am not sure that the addition of trading cards will actually sway any purchasing decisions very much for most people. That said, interest in the game generated by people playing the game more to gather trading cards will lead other people to buy the game so from an extended sales perspective this system could be potentially valuable. Unfortunately, due to the way the system is designed, it does not really do this but instead focuses on making commission profit from the marketplace. Why do I say this, well lets look at how the cards work.
There are a set of cards for a game, the number of cards varies but I have seen 5 to 15 Half that number of cards are earned by card drops from simply playing the game. This is the brilliant part of the scheme as poorer players earn stuff simply for playing which encourages them to play. There is the problem of people simply running the game and not actually playing it, but I don't consider it a real problem as the vast majority of people will actually play the game. Once the player has earned the drops from the game, they need to trade with other people, buy cards from the market, or wait for booster packs. Booster packs are only eligible to people who have used all their drops. This actually is a good idea. The problem is that the booster packs gives you cards immediately instead of adding more card drops. This means that once you have received all the card drops you never have to play the game again. This means that instead of encouraging players to play games longer and benefit from the word-of-mouth sales from people continuing to play older games, they are only making a few cents of commission from the marketplace when people sell cards.
The obvious solution is to make booster packs card drops. Still, I am not sure this is the best solution. Getting free cards is really nice and encourages people to continually log on to Steam which could lead to more sales. A much better solution is to keep the random booster packs, but also to give people an extra drop each week capped at the half-the-cards limit. People with drops would no longer be eligible for booster packs which would encourage players to play the older games keeping the communities for those games more active and resulting in more sales. While this would mean more people would earn badges, it would also mean more people trading cards on the market so the market commission profit would not go away plus there would be more sales of trading-card related games.
Such a very simple change would actually make the trading card scheme interesting instead of resulting in people simply playing games to gather the trading cards then not bothering with that game anymore.
Sunday, June 5, 2011
DDTe2 hours 16 to 17 Infinite Loop Bug
This is the final installment of my making of Dozen Days of Tiles episode 2. At this point in time, the game has been created but a showstopper bug has been discovered.
Finding bugs is never nice, but the very nature of programming makes bugs pretty much an inevitable thing. Bugs are often the result of a very minor mistake, such as was the case with this bug. Thankfully, with tools such as FireBug available, finding the cause of the bug was very easy. By being able to stop the program while it was in an infinite loop allowed me to take a look at the puzzle data at the time the infinite loop was happening which is where I discovered that the puzzle generation would occasionally result in a puzzle that had invalid data in it.
The solution to this problem was to add a sanity check to the fifth phase of the puzzle generation. Instead of simply returning the finished puzzle, phase 5 added the following puzzle verification checking code:
var cntrRow, cntrCol;
done = true; // assume valid until proven otherwise
for (cntrRow = 1; cntrRow < 10; ++cntrRow)
for (cntrCol = 1; cntrCol < 10; ++cntrCol)
if (this._model.getValue(cntrRow, cntrCol) == 0)
done = false;
if ( ! done )
this._phase = 1;
Problem solved. Many programmers would consider their job done. Good programmers, and those who want to become good programmers, know that there is still a bug in the code. This is when a serious look at the puzzle generation phases happens. I like to try and work through what the code is doing to find puzzles, though certainly walking through the code using breakpoints and stepping over/through statements will work.
As I worked through the code in my head, the problem hit me like a flying brick. What a dumb mistake! Setting the phase back to 1 when there is an error is fine, but for some reason, I also set it to the next phase if the row is valid. The next phase change should not happen until after all three rows in the phase have been successfully completed. When I wrote the code I was thinking that I was at the end of the generation, not just the end of the loop. A simple mistake, but that is all it takes.
What was happening was that the first or second row would not be able to generate a valid combination that would work with the puzzle. The loop would continue and if the last row was able to generate a valid combination then the next phase would be triggered. The real bug fix, then, is to take the next phase setting out of the row loop (which it shouldn’t have been in to begin with) and only go to the next phase if the phase has not been set to 1. Likewise, because there may be more iterations in the row loop, when the puzzle is invalid, the row loop should be broken out of.
The problem solved means that the project is finished. For the next episode, I am considering putting a twist on the game in a day challenge. Instead of developing a game in under 24 hours (development time not real time) I am going to instead see how many games I can create in under 24 hours.
Finding bugs is never nice, but the very nature of programming makes bugs pretty much an inevitable thing. Bugs are often the result of a very minor mistake, such as was the case with this bug. Thankfully, with tools such as FireBug available, finding the cause of the bug was very easy. By being able to stop the program while it was in an infinite loop allowed me to take a look at the puzzle data at the time the infinite loop was happening which is where I discovered that the puzzle generation would occasionally result in a puzzle that had invalid data in it.
The solution to this problem was to add a sanity check to the fifth phase of the puzzle generation. Instead of simply returning the finished puzzle, phase 5 added the following puzzle verification checking code:
var cntrRow, cntrCol;
done = true; // assume valid until proven otherwise
for (cntrRow = 1; cntrRow < 10; ++cntrRow)
for (cntrCol = 1; cntrCol < 10; ++cntrCol)
if (this._model.getValue(cntrRow, cntrCol) == 0)
done = false;
if ( ! done )
this._phase = 1;
Problem solved. Many programmers would consider their job done. Good programmers, and those who want to become good programmers, know that there is still a bug in the code. This is when a serious look at the puzzle generation phases happens. I like to try and work through what the code is doing to find puzzles, though certainly walking through the code using breakpoints and stepping over/through statements will work.
As I worked through the code in my head, the problem hit me like a flying brick. What a dumb mistake! Setting the phase back to 1 when there is an error is fine, but for some reason, I also set it to the next phase if the row is valid. The next phase change should not happen until after all three rows in the phase have been successfully completed. When I wrote the code I was thinking that I was at the end of the generation, not just the end of the loop. A simple mistake, but that is all it takes.
What was happening was that the first or second row would not be able to generate a valid combination that would work with the puzzle. The loop would continue and if the last row was able to generate a valid combination then the next phase would be triggered. The real bug fix, then, is to take the next phase setting out of the row loop (which it shouldn’t have been in to begin with) and only go to the next phase if the phase has not been set to 1. Likewise, because there may be more iterations in the row loop, when the puzzle is invalid, the row loop should be broken out of.
The problem solved means that the project is finished. For the next episode, I am considering putting a twist on the game in a day challenge. Instead of developing a game in under 24 hours (development time not real time) I am going to instead see how many games I can create in under 24 hours.
Subscribe to:
Posts (Atom)
