It's been five days since the end of the competition and I've thought about how things went and what kind of mistakes I made. So I want to talk about those things for a minute.
Let's start with the mistakes and bugs first.
During the introduction sequence of the game a text box pops up which eventually tells the player that the controls are the arrow keys and the X, C and V keys. Problem is, to get to that text box the player would've needed to press either the V or the C button. This is just a little oversight caused by me adding this text pretty late into the game when other things were on my mind.
Also some players didn't realize that they had to go to the northern area first. Although there is a mushroom before the cliffs area that tells you that you need to go north first I originally planned for this path to be blocked at first. That way the player couldn't enter that area under-prepared. Unfortunately I didn't have enough time to implement such a thing.
Another thing I noticed is that the random number generator can really screw the player over. During the UFO fight the UFO is supposed to resurrect the other aliens so that the player can create shockwaves again to damage the UFO. However sometimes this resurrection wouldn't occur for a long time, causing the player to burn through their supply of food items while unable to do any damage. The stupid thing is, I did write a RNG a while ago to deal with this problem. I just plainly forgot about it.
Lastly there was a small graphical glitch on the Intel HD 4600. Apparently it doesn't support a 32 bits depth buffer so some trees appeared in the wrong order.
And on to the things that went well.
I started off with a pixel-art pack that ended up saving me a lot of time. Although I did ended up needing to draw some extra tiles it definitely helped.
Also the original art I made, especially the sprites in the battle, did end up looking pretty okay. Although I will admit that that for the last two enemies, the cube and the recon droid, I intentionally choose easy shapes so I could get them done quickly. It was also necessary at that point because I made them on the last day.
Using Python generators for animations proved to greatly simplify my code. Especially regarding the battle code, where generators are used for pretty much everything that happens over time: the narration, damage flash, text box shaking, fading in/out, just waiting, etc. Although it's hard to say for certain I think that writing code in this way prevented lots of bugs and allowed me to quickly write sequential animations in a single function that would otherwise need a whole lot of state-management.
Lastly I'm glad that I didn't run into any major problems with my engine snowy. The only things I added where some convenience functions to existing classes. So no major technical problems like needing to implement a minimal sound mixer like I needed to do two years ago. Also investing some time to be able to load Tiled maps proved to be worth it. Tiled has greatly improved in the last couple of versions, especially the ability to define your own types is an important one for most games.
Well I think that's about it. If you have any questions let me know in the comments.
So I'm pretty tired at this point, but I managed to add more things than I had originally hoped at the start of the day. So I created a list for them.
- SDL2.dll fix
pysdl2 couldn't find the SDL2.dll on Windows 7, even though it worked fine on Windows 8 and 10. So I helped the searching a bit.
- Story intro
When you start in the cabin, there's a little bit of text being played that describes the alien invasion. It also tells the player the controls.
This is the biggest feature added today. You now have an inventory and can use food items both outside and inside battle.
Speaking of food items, there are now brown mushrooms hidden in the maps that will give you a consumable mushroom item. Just don't take too many okay?
- The magic baseball bat
Harris will now start with an attack power of 1. Which is pretty wimpy. So I've added a new area to the north that contains a baseball bat that will increase the attack power by 1 and will also unlock the shockwaves needed to defeat some enemies.
- Recon droid
The alien gunners are a bit too hard when starting with an attack power of 1. So I created these guys which are handy for leveling up with.
- Floating cube
This is a new enemy in the cliffs map. It can only be damaged by shockwaves and will revive any fallen alien gunners.
- UFO fight improved
Speaking of reviving, this is what the UFO can do now too. Which is a good thing because it needs level 2 shockwaves for it to go down.
Anyway, that's it for me. I'll do a post-mortem later, in a couple or days or so.
Download link: http://www.mediafire.com/file/g48m5osggyb006g/ThunderStruck_v0.0.7.zip
Controls: Arrow keys for movement, V for confirm, C for cancel, X to open the inventory.
Today I've added sound to the game. Music is now played for the aliens and the UFO even has a separate more "boss-battly" track. There are also some sound effects, most notably the aliens and the player getting hit. Nothing for navigating the menus though, I consider that to be a lower priority.
Also I've changed the shader for the level and characters to make things look like they happen at night. Since you can't have a proper creepy alien invasion unless it's at night.
There are also new areas in the game. Now you start in a cabin instead of right in the middle of the woods. The cabin has some interactable items, most importantly the fridge which restores the player's HP. The other area I've added is the cliffs, which is where the UFO boss lurks. It's quite a climb to the boss, so make sure you have gained a few levels.
Lastly, every time you enter a new area the game will save. And when you restart the game you will start from where you entered the area with the stats you had at the that time. The save file is simply named "save.json" so if you want to cheat, go ahead.
Download link: http://www.mediafire.com/file/v57fl1dl299lhgz/ThunderStruck_v0.0.6.zip
Controls: Arrow keys for movement, V for confirm, C for cancel.
So the game has an ending now. It's reached by defeating a flying saucer that can only be damaged by the shockwaves caused by defeating aliens. I'm pretty pleased with the results although I had hoped that I would also had finished a larger part of the map. Right now it's still the starting area and I've just crammed the boss in one of the corners.
Although I did implement level transitioning and a bunch of things that will make it easier to finish the rest of the game.
For tomorrow I will add sound effects and music to the game and also add a way to change the color of the tiles, since the game is, for the most part, supposed to be happening at night.
Download link: http://www.mediafire.com/file/5qkojt9c4q953a4/ThunderStruck_v0.0.5.zip
Controls: Arrow keys for movement, V for confirm, C for cancel.
Today I've implemented the chain-reaction part of the game. In the battles, if you defeat one of the aliens, then it will generate shockwaves that damage the aliens that were standing on the left and right. Even better, if a shockwave manages to defeat an alien it will create a stronger shockwave. And, you guessed it, this can happen one more time, creating the strongest shockwave. I intent this to be the only way to defeat certain enemies later in the game.
I've also added an experience system to the game. So if you defeat enough aliens Harris will level-up and gain extra hitpoints and attack power. Although I'm not sure increasing the attack power this way is a good idea. It seems like you become overpowered really quickly this way.
There are also objects in the game now that can be interacted with. Simply walk up to them and press V. Lastly the game-over screen now displays "GAME OVER" (surprising, I know) and asks if you want to continue.
Tomorrow I plan to implement the boss for this game and change the level to roughly how it should look like in the end. That way I'll have something to submit already.
Download link: http://www.mediafire.com/file/2mvbb3r0bcjkrcn/ThunderStruck_v0.0.4.zip
Controls: Arrow keys for movement, V for confirm, C for cancel.
Yes, that is the name I've decided to give my game. It doesn't make any sense now, but it will one or two days later.
The battle system is coming along nicely, now you can select to either fight or try running away. And it's also displayed which enemy you have selected if you choose to fight. There are also some other text boxes visible in the battle. On the right there is the status screen showing the main character's current HP and at the top is the text box that narrates what happens in the battle.
I've also added a graphical feature that is also part of the battles in Earthbound. The psychedelic backgrounds. In my game it's implemented through a shader instead of a special graphical chip though. Also, you can't see it in the screenshot but the background will also slowly move. I hope the colors aren't too jarring, but if they are I can change them of course.
During development today, I've also managed to crash the Python interpreter. Not a nice exception mind you, but an actual windows-has-stopped-responding-crash. Turns out a Box2D rigid body was destroyed twice because some things were being de-initialized in a dubious order. After I figured that out it was a simple fix.
Tomorrow I hope to start with, and maybe finish, the "chain reaction" part of my game. It should look pretty cool once I have it working.
Download link: http://www.mediafire.com/file/ezehm49wami6s2d/ThunderStruck_v0.0.3.zip
Controls: Arrow keys for movement, V for confirm, C for cancel.
P.S. If you somehow manage to get a game over then you will only see a black screen. Just press Y to restart.
I'm happy to say that I've successfully added one of the two themes I chose to my game. The aliens! They are created at specific points in the map and run towards the player until they collide. At that point the screen will fade out (no battle swirl yet) and a battle will start. It's interesting to note that, just like Earthbound, other aliens can still continue to run towards the player while the screen is fading out. And if they make contact, then they too will be added to the battle.
The battle itself isn't anything special yet though. It just displays the in-battle sprites of the aliens and you can attack by pressing the V button. Also the aliens won't attack back yet, which might be a bit disappointing. You can also change the selected alien by pressing left or right, but which alien is selected isn't displayed in any way yet. So that's not particularly useful. By the way I drew the in-battle sprite for the alien completely by myself. It won't win any awards, but I like to think it's pretty decent.
Another thing to note is that I recently started using co-routines for animations in Python. Effectively they are just generators that use the yield-statement to give control back to the rest of the update-tick. They are quite effective in preventing the need for stateful member variables (fadeTimer, coolDown, etc.). I might write an article about it later if there doesn't exist any yet that already does a proper job at explaining them.
Download link: http://www.mediafire.com/file/ciwguyrx82844l4/main_v0.0.2.zip
(Reminder: press V to attack!)
This year I didn't have any preparation post because I was busy getting Tiled maps to works with my engine. This is because I want to make an Earthbound-like RPG for the Week of Awesome. So you can imagine I'm quite happy with one of the themes being "alien invasion" since that's literally what happens in Earthbound.
The other theme I've chosen is "chain reaction", which will apply to the gameplay although I won't say yet in what way. It's better to keep it a surprise.
Also for this year I wanted to use existing art rather than having to make it myself. Originally I wanted to team up with an artist but since that didn't happen I had to look elsewhere. So it's a good thing I know about opengameart where I found this pixel-art pack in a style very close to that of Earthbound. I did have to tweak the textures here and there though. https://opengameart.org/content/isaiah658s-pixel-pack-1
The game I'm going to make will take place in the woods so I needed to place a lot of trees in the Tiled map. Unfortunately drawing multiple tress over each other proofed to rather difficult. Initially I just tried making multiple layers in Tiled with different depth values, but the problem is you have to keep creating layers if you have a lot of trees in a line from top to bottom. So that gets messy really quickly. The current solution I've come up with is to create a patch of forest in the tile sheet so that I have tilable pieces of forest that I can copy over the map. It's a lot better but very error prone, it's very easy to place a tile in a way that makes it look like part of a tree is missing. Maybe I'll find a better way though.
As for the main character, he can only walk around a simpel map right now. Also the game doesn't have any name yet so the exe is just called "main". I'll come up with the actual game name later.
Download link: http://www.mediafire.com/file/ciizr3ubrizid7d/main_v0.0.1.zip
Tomorrow I hope to get started on the most important part of the game: the turn-based battles with the aliens.
This is my final entry about the week of awesome where I look back on the game I created and comment on how I think things went.
I'm quite happy with the speed of the development overall, though there were some hiccups at the start of the competition. At the start of day two I found out that code that is responsible for rendering the meshes sometimes doesn't render them correctly. It took quite a while of fiddling before I found out that the error was with the way I stored the information to render. I used the mesh objects as a dictionary key, which might look quite harmless, except that this means that behind the scenes the pointers of the objects are used which explains why iterating over the dictionary had different results every time.
Another problem factor was Box2D. I don't know if it's the Python port (The SWIG version not the pure Python version) or if the last version of Box2D itself is this buggy but I came across quite a lot of problems. Changing the friction of the rigid bodies didn't seem to be possible, so I ended up multiplying the velocity of each of them by 0.9 each update. Also contact filtering didn't respond to anything, so if the protagonist tried to carry a bone pile he would collide with the bone pile and be pushed away indefinitely. I ended up placing the rigid body of the bone pile off screen when it's carried to fix this.
I also underestimated the difficulty in using sounds but I already wrote about that in part 5.
Fortunately, there was quite a lot that went well. I'm quite happy how easy it is to tweak the levels, it's because the level format is kept really simple and because I implemented a reload button. The reload button is something I usually implement for games with levels. It really speeds up the development of the levels since you can just tweak a value, save the level file and press reload.
The overall atmosphere is also something I think works well. I'm not sure if the colors all work well together and the textures are a little bit lazy (Hey I'm not an artist!) but the fading in and out and the point lights look quite nice. Also the puzzles should be quite fun to solve. So far I've only heard positive things about them.
Lastly I want to talk about some gameplay features that didn't make it. When I was thinking about what kind of puzzles would be possible, back in the first day, I had the idea of being able to kick bone piles. This would then be used to shoot bone piles through gaps where the protagonist wouldn't fit through. Another feature that didn't make it was some kind of mobile threat. I first thought of creating a ghost that would follow a certain looped path but later decided that receding a springing up spikes could also be used to the same effect. This isn't meant to create puzzles involving timed jumps but rather to demonstrate the ability of simply pushing bone piles and how that could be used to solve puzzles.
Lastly I want to reveal the locations of the secret areas in the game. In spoiler tags of course. :) [spoiler]In the tutorial level, above the hollow tree to the next level.[/spoiler] [spoiler]In the non-tutorial level, to the left of the large pit of spikes.[/spoiler]
This has been the final day of the week of awesome for me. At the time of writing the competition ends in about 8 hours and as I'm typing this the zip file of version 0.1.1 is being uploaded to media fire.
Today wasn't as hectic as I had feared. There was one issue where an exported object from Blender wasn't being loaded correctly but simply triangulating all the faces in that object seemed to fix it. There wasn't much coding today, the biggest feature I implemented was extra lives for the protagonist. For each live the player picks up they can have one extra bonepile on the ground that can be used to solve puzzles.
The main thing I added today though is the level after the tutorial area, which will hopefully provide a challenging experience to the player. At the end of that level the game will simply loop back to the start of the game. In each of the two main areas, the tutorial level and the one I've added today, is a secret area to be found. You will definitely know when you've found one since the style of the game is very different in those areas. I went for the silhouette-shadows-before-colored-background style. Which is a bit lazy if you think about it, since you don't have to fill in the details of the level. I still think it's find it moderation though. One of the first games I played where some of the levels had this style was Super Meat Boy, although there are probably games that did something similar before it.
Okay, that's it for now. The next journal post will contain the post-mortom and I will talk about things that went well, things that didn't went well and features that didn't make it.
For me this has been day 6. I skipped a day because implementing sounds proved to be more difficult than I thought. It does sound simple, doesn't it? You'd think it would be something such as this: s = Sound("path/to/sound.wav")s.play(volume=1.0) But unfortunately the audio interface provided by SDL2 is very low level. You literally have to load the binary buffer of a WAV file and copy bits of it into a stream when its requested by a callback function. Anyway, I do have it working, but only for one sound for now. The music I picked is "Quiet Tension" by Eric Matyas (his website is http://soundimage.org/). I also credited him in the game of course. Simply adding some background music really does wonders for the atmosphere. It feels much more spooky now.
But do you know what also adds a lot of atmosphere? Lighting! Previously everything was shaded fullbright which is pretty ugly. Now every object is lit by two directional lights, front and back, and can also be lit by point lights. Although I haven't added much point lights yet. The reason I went for two directional lights which oppose each another is so you can also color the shadow differently than the front lit side of the object. This looks a lot nicer than just making the other side of the objects darker.
Lastly a big feature I've implemented is transitions between levels, which also means I've added another area. For now I've just added a starting area, but I'm planning to spend most of the last day on making new areas. Otherwise the game will be a bit short. I'm also hoping to add some secret areas, that'll make for a fun challange for the other people following the week of awesome.
This has been day 4. The midway point has been passed and everything seems to be on schedule. I don't think I'll be able to create as much levels as I originally wanted to make but we'll see. Right now it's only the tutorial level anyway.
One of the things I implemented today are fade-ins and fade-outs. It's a relatively a minor thing but it does make the game feel much more professional.
Another graphical feature is that I've animated the protagonist. When he walk his feet walk move back and forth and his arms will rotate. Also when reclaiming the lost lives, so that the player can create bone piles again, the character will wave his hands above his head. It looks a bit silly, as if he's screaming while running away.
The main gameplay feature I've implemented though, is the ability to pickup and drop/throw bone piles the player leaves behind when he gets hit. Implementing this took three tries, because Box2D didn't want to cooperate. I'll spare you the details because I don't want to whine. The thing is, I need to disable collision between the player and the bone piles he picks up. Otherwise the bone pillar will keep pushing the player while the bone pile tries to position itself above the player's head. This has hilarious results when the player tries to pickup a bone pile when they are standing on it; they are launched into space!
Anyway, I'm off to look for some music. The game could really use some to add some atmosphere.
Oh and before I forget, here is the latest build: http://www.mediafire.com/download/nogp1k53b0l8iwi/ADeathADozen_v0.0.4.zip
My game for the week of awesome is coming along nicely, although I don't think I got as much done as the last few days I still got quite a lot of new stuff implemented.
Firstly I've added checkpoints to the game. When the player now walks in front of one them, the eye of the figure on the grave will flash green indicating that the player is now respawned there when they get hit. And, while we are talking about the respawning, I've also made a respawning animation. The player will now rise out of the ground in front of the checkpoint. It still looks a bit silly without dirt particles, but it goes with the theme really well.
Secondly I've tweaked the movement of the player. I haven't released a build before doing this, so let me tell you what was possible before. It was actually possible to jump up walls by holding the arrow key towards the wall and rapidly tapping the jump button and the other arrow key. So I had to remove that of course. (I sincerely apologize to any speedrunner reading this.)
As for technical details, I've also implemented a reload button. This reloads all the assets and the level file itself but keeps the position the player is at. This allows for rapid iteration of level designs. It's something I like to do with each game I make.
So I've made an initial build of A Death a Dozen and you can download it here. (Version 0.0.1 had a bug.) http://www.mediafire.com/download/ha8daq56166vwcw/ADeathADozen_v0.0.2.zip
There's only one level now and no sounds yet. The game doesn't seem to work on nVidia cards. I will try to fix this quickly.
A lot has happened since the last post on my journal. Here is a screenshot that shows the start of the first level.
It already looks kinda decent. The objects look terribly out of place though, since no lighting is done yet. One interesting thing to note is that none of these objects, except the player, have texture coordinates. All the texture coordinates are calculated in the vertex shaders and are based on the vertex position and normals.
The collision for the level is also loaded in a bit unusual way. What I do is this: In Blender I go to the forward facing view (numpad 1) and trace a line of vertices over all the objects that the player should collide with. This way the line of vertices can be imported and converted into a Box2D edge body.
I also got the main game mechanic working, when the player now dies they respawn an leave behind a pile of bones that can be used to cross over spikes and to get to higher ground. I've already got some ideas about how to create fun puzzles with this.
Lastly I want to show the level format. During competitions like this, it's important to keep things a simple as possible. That's why the level format I use is just a JSON file referring to the assets the level uses and the location of some other objects in the level.
So the theme this year is "Death is useful". I already thought of some game ideas involving death prior to the start of this week as a warm-up. One of the themes I let myself work with was "Ashes to ashes" and I came up with the idea of a man in an old mansion finding a device that speeds up time. This device could be used up until his demise, at which point the game would restart. Knowledge of prior playthoughs would then be used to solve the mystery of the mansion. Although this idea does sound interesting, I fear that it would be to art-heavy and that it doesn't fit the theme closely enough.
Fortunately I had another idea that is something much more up my alley. A puzzle platformer that uses the corpses (bone piles really, let's not get visceral) of the player character in order to solve puzzles. While it's not as original as my first idea I'll be able to quickly get the game into a playable state. That, and I also just like puzzle games and platformers, so it'll also be more fun for me to test the game. One thing I'm slightly worried about though, is that other participants will have had an idea very close to mine. I wouldn't effect the objective quality of my game, but the effect of scarcity and uniqueness is a real thing, so we'll see.
Look like I am going to have to use Box2D though. I want the player to be able to throw the bone piles they left behind in order to solve puzzles and defeat monsters.
With the start of the week of awesome III rapidly approaching I decided to make some changes to my personal game library snowy. Previously I could only render sprites in snowy, and while that is sufficient to make a nice game with I also wanted to be able to use 3D models. So I refactored my SpriteRenderer class to create the vertex buffers in a much more general way. Secondly I extracted a Renderer class that deals with binding the vertex buffers and making the actual draw calls. This way the classes that inherit from Render only have to deal with providing the data to fill the vertex buffers with. It's by no means perfect but simplifies specifying the layout of vertices a lot.
I also wanted to be able to use 3D models created in Blender. Specifically the Wavefront obj format, since that is exported as plain-text and it easy to parse. Writing the parser was pretty straightforward until I discovered that the .obj format uses separate indices for vertex position, texture coordinate and normal. It looks like this:f 25/36/38 26/37/37 257/250/257 Here the 'f' indicates the definition of a face, in this case a triangle, and the numbers are indices to the positions, texture coordinates and normals. Unfortunately glDrawElements expects an index array where the position, texture coordinate and normal all are in the same order, and so being able to use the same indices to render them. So I had to remap and combine the texture coordinates and normals to the same order as the list of positions. It was a bit tricky but it does have the added benefit of smoothing the normals of the mesh.
After I made a quick and dirty potion model in Blender here is the result:
It might not look like much but it does mean that I can use any kind of 3D model created in Blender which I hope will proof to be quite the benefit during the contest.
Lastly I also went over my collision code to look if I could make two dynamic bodies interact reliably. I had written my own collision code after I found out, while making a breakout clone, that Box2D doesn't handle reflective collisions reliably. The moving pellet kept getting stuck to the breakable blocks. Using my own collision code, using ray-casts pretty much exclusively, I got it working perfectly. This code didn't support collision between two or more moving bodies yet, so I went back to take a look. Turns out that making collisions like that is way harder than I though. (Stack of boxes anyone?) So if I'm going to write a game that requires complex 2D physics I'll use Box2D but if simple and precise collisions are necessary I'll use my own collision code.