hi as I'm closing in on finishing the game prototype. I would like to
open the champagne to summarise to my-self what I have done so far (So It will be clearer for me what remain to do and what's to improve).
First as I said I'm making a game prototype to test various game idea. On paper ideas look nice but I believe it really need to be experienced by playing to see what concepts are good.
So basically I'm making a battle game 1 vs 1 with card as RPG entities. The Goals is to be the last standing. You can deploy max 30 card (8 max on your side of the board). When player have deployed/used all their 30 cards then it's the first to eliminate all enemies remaining cards on the board who wins.
Card are like RPG entities, with different stat and skills. Or a card it can be just like a spell.
Example:
- warrior entity with life, attack, shield (like an hero).
- heal aura (heal all card on the deck). in this case it has no attack and no life stat and would be destroyed at the first attack it get. That's why I consider It more like a spell.
With that in mind I had to organise my work.
Dev environment:- Eclipse Kleper (love the "rename" refactoring function which I use a lot)
- gcc/g++ compiler (I had some problem to find the right version to work with SFML finally I use TDM-gcc-4.8.1
- SFML (of course)
- CUTE (for unit test) just like its simplicity
- metriculator (some eclipse plugin to count ligne of source code) not essential I just like to see my project advancement
- C++11 I'm new to c++. Long time I know the its syntax , but I never really got to dev in c++. So I jump into c++11. I knew it would be challenging but RAII idioms and smart pointer reassured me
The compromise:I want to dev a prototype to try a game concept. So I have to dev some kind of engine. On one hand I don't want to throw of my work on the engine after I test my concept. On an other hand I don't want to get cut in game engine developing and forgot my first goal. So I try to make something flexible, but not to flexible because it's to much work and I may never use some of the functionalities. I want An engine rapidly release who will allow me to try different concept and somehow with a relatively clean design.
I manage to did it by focusing first on the functionalities that my prototype need and then how to make it more flexible. As I said it's a compromise and I think I lean toward quality dev than to create a lot of functionalities. I get that know that I'm writing this. I have some functionalities yet to implement but I worked quiet a lot on clean coding and test it.
I believe that what I dev would be use as base engine for the game. But also that if my concepts are not good what I have done won't be handy. Or maybe not I will see.
Dev steps & design:1) I started by naively implement a card class, that could be seen as an rpg hero with life, shield, damage, element resistance (damage are of one of the four elements), chance of succeed an attack, and so on.
2) I separate the attack for the card class. Simply because I realise card don't have to got attack. So better to create an AttackSkill class. Therefore I did some other skill classes who play will with card's stats.
3) I create Interaction class for AttackSkill. Wish take an card and its AttackSkill and apply it to an other card. Then I finally get to my head that it's better design to separate stat from the action who manipulate then.
So I got:
- proprieties class (cards stats & skill stats)
- interaction class (which use skill stat to modify taget card's stat)
example
HealSkill class {bonus_stat +10pv}
HealInteraction{healSkill* skill; apply(Card* target)}
Card {life_stat {0}; getLife();, setLife();}
4) I made some unit test ! And caught a lot of bugs
5) The event! All right card1 attack card2 I made it. But what about Card2 heal him-self after receiving damage? So I had to manage event.
What I did:
-
EventHandler class (still empty class it was too hard to do
No I'm just kidding, but it was challenging for me)
-
SkillHolder every card got its skills in it. And there is one for each event:
Holder* trigger_attack, trigger_defense, trigger_dead- player action will call
EventHandler trigger matching function. ex: card1 attack card2 ->
EventHandler.attack(card1, card2) then EventHandler.defense(card2, cart1);- then the event function check
card.trigger_attack for skill to apply
-
EventHandler apply the interaction to the card2 target, using card1 skill
6) What a mess ! So many skill, so many interaction wish are of different class type. I know I deserve it with my "go get it, think one step at the time method". Oh men! template class come to the rescue. One function to apply different interaction class type. C++ is so nice.
7) refactoring: Well all my interaction classes derived from the same base
HealInteraction : Interaction, AttackInteraction : Interaction. It's nice because I need
apply(), canApply(), remove() but apply heal is really different from apply attack. So heritage was a good solutions.
My problems come here: skill are of different type (
HealSkill, AttackSkill, ...) and interaction need access to skill's stat.
First idea (ugly but worked) I made apply() a pure virtual function and add-in member skill pointer to every skill child. But not in the Interaction parent class. As i said ugly but worked.
As you can see I need to improve in c++! Hopefully I found a better solution: parent Interaction as a template class. So now child derive from it. Like this:
healInteraction : Interaction<HealSkill>, attackInteraction : Interaction<AttackSkill>And so I did add-in a template member skill pointeur.
T* skill; And get reed of my ugly design.
8 ) An other problem... In
eventhandler when a event is triggered. I got many type of skill to check if they react and many type of interaction.
So I have to do Something like:
void EventHandler::attack(card, target)
{ if(card.trigger_attack.haveHeal)
applyInteraction<heal>(card, target);
if(card.attack.haveAttack)
applyInteraction<Attack>(card, target);
}
It would have been ok if a had only one event, but I got many of them And really would like to do something like this:
while(card.trigger_attack.hasSkill)
applyInteraction<card.trigger_attack.getTypeSkill)(card, target);
I tried those ideas:
-put my skills into a
vector<Skill> (Skill is the parent class of
HealSkill, AttackSkill...) Okay but I couldn't get access to child member without dynamic_cast wish made me make a giant list of if -> return to case zero
- use a
tuple<HealSkill, AttackSkill> Problem :
tuple.get<X> X is a compil time parameter I would have to write:
tuple.get<1> tuple.get<2> tuple.get<x>, ... Same ****
- I add a class member with the type of the next Skill's derived class to access. It worked well to got my loop. BUT I run into a problem with template type deduction : it's made at compile time add my loop at runtime, so It could call the correct template function matching my current type -> return to case zero
...Meanwhile I received my new book "Modern C++ generic design by Andrei Alexandrescu". Who talks exactly about my problem (didn't know when order it)...
- Out of nowhere I got and idea (
hiding the book it got nothing to do with it) : skills into a tuple and use
boost::fusion::for_each on it who call a template functor for each element of my tuple!
Well that step took time and went back and forward but I learn a lot.
9) refactoring then rewrite from scratch my unit test (to much had evolve and the old one were, hmm... too old)
After all that I can say that I have learn a lot (C++ and software design). I enjoyed developing that prototype more than anything a ever have developed. The C++ book came right on time and I will learn more from it.
About the prototype I still have some skill to add-in (Stun, resurrection and invocation) and work a little bit on the "UI design". Then I will finally be able to test concepts and learn from it to determine how the game will play.