About my final project, I did a 2d top-down shooter paying respect to my childhood favorite nes game Life Force. Here's a pic for life force 4th level:
As one of the best shooters on NES platform, the most interesting part of it is that you could upgrade your fighter by collecting energy creates in the level. Energy level 1 boost your moving speed. Energy level 2 gives your missile ability and second upgrade on this makes missile faster (which is different in my implementation that second upgrade allows 2 sets of missiles in the screen). Energy level 3 upgrade gives you wave bullet which guarantees wider bullet width and it grows as far as the bullet moves, shown as following:
In my implementation, I haven't implemented scaling vertex in mesh and collider according to distance from the fighter so my wave bullet doesn't change size. Energy level 4 upgrade gives you laser bullet which shows in picture 1. It's a "one shot until recycle" bullet which behaves different then default or wave bullets, after one shot, the fighter or "option" (I'll explain later) will shoot out a serial of bullet which could do multiple damage count until depleted. But the second shot can only be made if all previous shots are out of screen or collided with enemy. This character makes laser a powerful but less flexible weapon. The energy level 5 upgrade is the most amazing invention in the game it's called "option". It's the little shining thing next the the fighter, it has no collision with other object and do the same attack as the main fighter. My way to implement it is adding another child Fighter GameObject to the main Fighter GameObject. Option would enter Fire() logic when main ship controller receives fire input. Also the pattern for option to move is actually always n steps from its parent object. So the controller of the option would move only when parent object set current move from parent movement trace list. There's another interesting mechanics for "option" that if the main fighter is destroyed, options would be come individual object flying to the coming direction, if the new generated fighter could intercept them half way, they get attached again. You can have at most two options. The 6 level upgrade is called force which means a protector over the ship and ship could immune to destroiable enemy/bullet for 3 times. I'm very happy that I implemented most of the fighter game mechanics of the original game except missile crunches wall and wave bullet increase size.
About enemy part, i create them as inert GameObjects and they get enabled and come to screen only when time comes. Before that, physical system (collision and update), rendering system (mesh, texture and sprite animation), controller system would not update with these inert objects. World system is keeping track of wakening up these inert objects. Different enemy have different hit points. Player can also gain energy creates by destroy special enemies.
Memory is carefully managed in my game, take an enemy object as example, they only get awaken when at the right timing and then considered by functioning systems, they get destroyed if bullets killed them or they fly out of the screen area. During destroy object, it's shared_ptr reference is released in every components (renderable, collidable, controller) and also world GameObject list. Then in its dtor, component dtor are called and finally the object itself. Another principle I'm keeping is to minimize calling ctor and dtor during the game, especially ctor. 2 options and the main fighter has bullet and missile pools, after flying out of the screen or collided with matched types in collision mask, it get "hidden" to non-observable locations and reused after next fire. This would keep the game as fluent as it should. Thinking of the original game in 1986, hardware is limited. I see that they would like to keep resources in real time update pool as small as possible and try to do the same.
A game is not a good one without sound effects. I also added sound library based on XAudio2 which works depending on callbacks. It's very nice to see these old sprites work with familiar sounds.
Thanks for JP and Joe's class, I have a pretty reliable game engine to create my beloved game. It's very efficient to work with the engine because I know it's mechanics very well. I also added component based design in its structure that it's a little bit like no-graphic-interface unity. I really like the feeling of gathering assets and make them work perfect with the game. I would like to add scaling next so I could reuse meshes in the game.
During making the game, I started to feel why certain design decisions are made so the game turns out to have its shape. When I was playing the game before on TV during 90s. I sometimes see the force effect not rendered for a while and sometimes the fighter itself doesn't get rendered but the force effect comes back. That's all because limitation of NES console only allowing 8 sprites on the same rendering horizontal line. Although less limited by current PC, I still want to respect the old game makers and their wise decisions.
I like the course a lot because I realized that I should delve into structure design more than ever before, especially considering my current job. I'm getting a better sense of component based system, but this is mostly used in game industry. For my work in medical ultrasound system, I need to study more about pipe, filter and parallel programming design techniques. I'm sure I have my passion in game programming all the time. If currently it's not used in a job, it would come out later in another form. If we could secure what we're going to work on in the midterm, probably people with more passion could have more preparation for their project. That's just a little suggestion i have for our course.
About general good code, during the last 4 months in my job, I was working on QA from time to time. Company purchased Coverity service and I was using that to improve code quality. What comes to my mind first is always memory leak. More RAII is mostly a good approach to improve code quality and maintainability. Conditional/partial initialization is another problem that often happens that I would make sure always initialize everything and free everything in ctor dtor. Also paying attention to McCabe complexity is good for code structure. Singletons are evil creatures and should be mostly avoided. Static analysis tool has its limitation. Run time efficiency would also be important. Cache friendly code and better code structure could help. Unit tests and TDD are important to improve code reliability and reduce future trouble.
About enemy part, i create them as inert GameObjects and they get enabled and come to screen only when time comes. Before that, physical system (collision and update), rendering system (mesh, texture and sprite animation), controller system would not update with these inert objects. World system is keeping track of wakening up these inert objects. Different enemy have different hit points. Player can also gain energy creates by destroy special enemies.
Memory is carefully managed in my game, take an enemy object as example, they only get awaken when at the right timing and then considered by functioning systems, they get destroyed if bullets killed them or they fly out of the screen area. During destroy object, it's shared_ptr reference is released in every components (renderable, collidable, controller) and also world GameObject list. Then in its dtor, component dtor are called and finally the object itself. Another principle I'm keeping is to minimize calling ctor and dtor during the game, especially ctor. 2 options and the main fighter has bullet and missile pools, after flying out of the screen or collided with matched types in collision mask, it get "hidden" to non-observable locations and reused after next fire. This would keep the game as fluent as it should. Thinking of the original game in 1986, hardware is limited. I see that they would like to keep resources in real time update pool as small as possible and try to do the same.
A game is not a good one without sound effects. I also added sound library based on XAudio2 which works depending on callbacks. It's very nice to see these old sprites work with familiar sounds.
Thanks for JP and Joe's class, I have a pretty reliable game engine to create my beloved game. It's very efficient to work with the engine because I know it's mechanics very well. I also added component based design in its structure that it's a little bit like no-graphic-interface unity. I really like the feeling of gathering assets and make them work perfect with the game. I would like to add scaling next so I could reuse meshes in the game.
During making the game, I started to feel why certain design decisions are made so the game turns out to have its shape. When I was playing the game before on TV during 90s. I sometimes see the force effect not rendered for a while and sometimes the fighter itself doesn't get rendered but the force effect comes back. That's all because limitation of NES console only allowing 8 sprites on the same rendering horizontal line. Although less limited by current PC, I still want to respect the old game makers and their wise decisions.
I like the course a lot because I realized that I should delve into structure design more than ever before, especially considering my current job. I'm getting a better sense of component based system, but this is mostly used in game industry. For my work in medical ultrasound system, I need to study more about pipe, filter and parallel programming design techniques. I'm sure I have my passion in game programming all the time. If currently it's not used in a job, it would come out later in another form. If we could secure what we're going to work on in the midterm, probably people with more passion could have more preparation for their project. That's just a little suggestion i have for our course.
About general good code, during the last 4 months in my job, I was working on QA from time to time. Company purchased Coverity service and I was using that to improve code quality. What comes to my mind first is always memory leak. More RAII is mostly a good approach to improve code quality and maintainability. Conditional/partial initialization is another problem that often happens that I would make sure always initialize everything and free everything in ctor dtor. Also paying attention to McCabe complexity is good for code structure. Singletons are evil creatures and should be mostly avoided. Static analysis tool has its limitation. Run time efficiency would also be important. Cache friendly code and better code structure could help. Unit tests and TDD are important to improve code reliability and reduce future trouble.