Jump to content

  • Log In with Google      Sign In   
  • Create Account

Interested in a FREE copy of HTML5 game maker Construct 2?

We'll be giving away three Personal Edition licences in next Tuesday's GDNet Direct email newsletter!

Sign up from the right-hand sidebar on our homepage and read Tuesday's newsletter for details!


We're also offering banner ads on our site from just $5! 1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Like
18Likes
Dislike

RPG Character Design: Technical Blueprints 101

By Ivan Spasov | Published Jul 02 2014 05:49 AM in Game Programming
Peer Reviewed by (Gaiiden, Dave Hunt, jbadams)

technical design blueprints rpg character

In this article, I’m going to try to get over a 101 guide on how to do the technical design for an RPG’s character classes and how you can implement a basic programming model in order to make your development consistent, flexible and generic.

In order for this article to be of any use to you, you should have at least a base knowledge of Object Orientated Programming and concepts like working with Interfaces, Inheritance, Polymorphism etc.

Another thing to note – this article will not be a programming tutorial, rather a technical overview on how things should happen. I’m going to map over the functionalities, however I’m not going to overload this article with code. Most of the developers that are familiar with the above mentioned concepts should have absolutely no problem to implement this technical design in their game.

I also want to mention that this is basic character design. We will not go into the depth of the skill trees, skills usage and character builds. The topic is just far too wide for the scope of the article.

So, how is this going to go?

Well, to start off, for example and simplicity reasons – let’s say we are going to develop the hero character model of an RPG that has three classes: Warrior, Mage and Archer.

In order to develop these classes in a generic, easy to maintain and flexible to extend frame, we are going to develop an interface and class hierarchy that is going to take care of all of our troubles.

The Hero Class Technical Model


As general development, this is not too hard of a task. The problem here is that a lot of times, the end-product is not reusable, it’s not flexible and it’s not generic. Here is a typical problem, when someone is making a design of this nature – more inexperienced developers tend to develop three separate classes – a Warrior class, a Mage class and an Archer class. And that’s it. Just these three classes. Don’t get me wrong, this will work. However, it’s problem prone.

What’s not good about this concept? Here is a list of some of the biggest problems:
  • You have to re-write basic stuff that all of these classes have in common.
  • If you have to change a basic concept of the characters, you have to make the change in all of these classes.
  • If a consistent bug pops up, you are going to have to implement fixes in all of the classes.
  • Many other things that may trip you up.
So how do we avoid this issue?

It’s pretty simple. We are going to build up a character Interface that is going to map out the common traits of all of the characters. Then we are going to have a basic Character class that is going to implement the Interface with some basic programming logic that’s again common to all of the heroes, and last but not least, we are going to create the Warrior, Mage and Archer classes and they are all going to extend the character class that we earlier developed.

Developing the Technical Design


We will start off from the ground. Here is how our hierarchy is going to look.

Attached Image: UML RPG 101.png

Character Interface


First off, we will create the character interface. For this article, let’s simply name it ICharacter.
Now let’s start thinking. What do all of these characters have in common? Well, they can all attack, move, trigger actions and die. Of course, each of them will have its own interpretation of these traits later on.
So, the interface will have these methods:
  • onMove()
  • onAttack()
  • onActionTrigger()
  • onCharacterDeath()

Character Class


Now that we have the Interface up and ready, we should create a basic class that is going to implement it. For this article, we will call the class CharacterBase. So how will it work? When we implement the interface, we will craft out the most basic logic that is going to be initiated for all characters in this. Each method will contain just the very basic amount of logic.
  • onMove() – In this method we are going to handle the character's movement patterns. We will also trigger the movement animation.
  • onAttack() – since each of the character classes has a specific attack type, the only thing we will do here is handle the animation trigger and also make sure (in terms of game design, this step may vary) that we have the needed setup for the attack to commence. Calculate the damage to the target as well.
  • onActionTrigger() – this should basically just trigger an animation whenever we want to interact with something. However, the three character types may have a different way in interacting with objects.
  • onCharacterDeath() – this will trigger the death animation, save statistics or whatever is needed to be saved in order for the game to go further with its logic.

Warrior Class


We have the basics down. So let’s create the Warrior class. We will call it WarriorCharacter. It will extend CharacterBase and basically override all of its methods.

This is how the methods should be customized to fit the WarriorCharacter class:
  • onMove() – Here we will need to add a specific move pattern to the character. Since we have a warrior, he needs to move in a slow yet stable fashion. We will slow down his movement speed. After we've handled that, we will call the basic logic from CharacterBase by using super.onMove(). When the time comes to analyze the movement pattern, we will have already changed it, so now it initiates what we want. It will also trigger the warrior animation for movemet.
  • onAttack() – the method should firstly check the distance from the Warrior’s transform position in regards to its target. If we are in range – that is up close and personal, we will call the CharacterBase onAttack() method logic by using super.onAttack() or whatever technique your programming language supports in order to do so.
  • onActionTrigger() – Our warrior has to be able to interact with breakable objects and well ... break them. This we will do by setting up a trigger in this method that will allow a breaking action for that specific object. How you can actually do that is something that should be designed on the object base, not the character. So, initially we will call the basic logic from CharacterBase and then expand on that by allowing the warrior to break stuff.
  • onCharacterDeath() – To build upon the death animation logic, when a Warrior dies, we would want to implement a specific death effect, like dropping your weapon. After we call the original logic, we can add that as well.
Keep in mind, that in order to execute the basic logic from the CharacterBase class, you need to do something like

super.onAttack()

or the method you actually want to call.

Mage Class


Now to implement the mage logic. We will call this class MageCharacter. It will extend CharacterBase and things will work much like with the WarriorCharacter class. Here, the distance of your attack is going to be vastly different from that of the warrior and gradually, the damage is going to be different as well. We are also going to have a missile effect to the attack. Again, when you put extra logic in your methods, make sure you are calling the original ones from the CharacterBase as well. If you don’t do that, their basic functionality will not be executed and then nothing useful will come out of this. So this is how our basic methods are going to look for the mage character:

  • onMove() – Here the character pattern should be pretty normal. The movement speed as well. In physical terms, the mage is a normal guy so he should move around like the average people. However, we can use magic here. Let's way we use some sort of a skill (again, as said above, we will not go in-depth on the skill thing) that makes our mage fly. In this method we need to check if this skill is on. If it is, we change the movement pattern, the speed and even the animations for the mage.
  • onAttack() – As with the Warrior, after we've found our range, the mage should be able to fire. This range however should be bigger then the warrior's range. At that point we should trigger a missile effect. It can be implemented through additional logic in the mages class that is out of scope for this article.
  • onActionTrigger() – The magge has to be able to interact with objects through magic. That's to say that we should be able to use skills or our attack even on some objects, like spellbooks for example.
  • onCharacterDeath() – Here we should implement a time-span for our mage to be able to ressurect himself if he has such a skill at his disposal. Then we can trigger the standard logic.

Archer Class


And just like with the mage and warrior, we extend CharacterBase with a class called ArcherCharacter. By now you've pretty much got the idea of how this is going to go. For the archer we would need a very fast movement with movement patterns that allow a fast strife from side A to side B of the visible/playable field. We would also need to implement fast and rappid attacks for this class. Maybe even a multiple shots kind of thing, where we initiate two attacks for the time of one. We would also most certainly be able to implement logic that allows us to interact with objects, such as a bush, so we can hide in it. On death, we should be able to implement logic that allows our archer to strike one lasw blow to it's target, before he goes out for good.

Interesting Points


In this article I simply want to make a point on how you can do your most basic character class design. If you are to actually make this into a best practice kind of thing, you should make the hierarchy a lot bigger, including separate classes for melee characters, characters that use magic, range characters. From there do the inheritance for specific character classes.

Also, to be fair, in order for this to actually work good, you would need a bigger array of methods at your disposal. Methods to handle your character’s statistics, usage of skills etc. You would also need to add some variables to handle the health, stamina and a character-specific resource, like mana for example.

However, this is going to get the article too complicated. This article is aimed for developers that have just recently started using concepts like Inheritance, Polymorphism and so on and so forth. If you can get down to write just your basic technical design down, then you should pretty much be able to go to an upper level with no problems.

Conclusion


The technical side of the character class design is not something hard to understand or implement. Just keep in mind, that the concepts of Object Oriented Programming and the reusability factor that stands behind these concepts can save you a lot of time, bugs and make your code really better in all terms.

Article Update Log


4 May 2013: Initial release

7 May 2013: Additional article format

19 May 2013: Remaking the article. Addint additional information and a diagram.



About the Author(s)


My name is Ivan Spasov. I'm currently a game developer on the mobile market. I'm working with a team in a studio, focused on mobile solutions. I've had experience in the indies. I've also been working outside of the gaming world and in the field of Enterprise and corporate business development.

License


GDOL (Gamedev.net Open License)




Comments

Good article. Though to be fair, this doesn't tell much to someone who already knows OOP. However, I think it would be a great idea if you could change the article so it would explain OOP in a game context for people who haven't studied OOP yet.

Good article. Though to be fair, this doesn't tell much to someone who already knows OOP. However, I think it would be a great idea if you could change the article so it would explain OOP in a game context for people who haven't studied OOP yet.

Note taken. I will do some more work on it. I'll also add more code to it in the near future so that it gets more applicable to a real implementation. Thanks for the feedback !

Great article.

One question: isn't it better to write CharacterBase class and have rest of the classes (Warrior, Mage, Archer etc.) inherit it and override what they need instead of using interface (which, from what I understand, just says "there is this method but I don't know what it does") and duplicating code?

Great article.

One question: isn't it better to write CharacterBase class and have rest of the classes (Warrior, Mage, Archer etc.) inherit it and override what they need instead of using interface (which, from what I understand, just says "there is this method but I don't know what it does") and duplicating code?

That was my idea. As you can see, they each extend the CharacterBase class. However, I did decide to have an interface that the CharacterBase implements in order to illustrate how the inheritance process goes and more or so to use the interface later on for an NPC implementation, since NPCs are characters as well.

As far as the blank methods that I've left out a bit, that's more or so for simplicity reasons. I don't want to make this too much of an implementation and pure development kind of thing. Though this is one of the articles' big time downfalls and I'll make sure to correct that and in the near future write in detail the specifics of each character's implementation of the CharacterBase methods. They will still call the base of the CharacterBase method for the core functionality, however they will add certain details to it.

Thank you for reading and thanks for the feedback !

That little picture in the corner looks useful, but it's so tiny! Can you make it accessible in a larger size? For me visualization of OOP was really helpful when I learned it earlier this year. I'm brand new to coding (I learned Python) but the idea of using OOP for character creation seems like a great best practice. Thanks for sharing!

 

-J

That little picture in the corner looks useful, but it's so tiny! Can you make it accessible in a larger size? For me visualization of OOP was really helpful when I learned it earlier this year. I'm brand new to coding (I learned Python) but the idea of using OOP for character creation seems like a great best practice. Thanks for sharing!

 

-J

I would if I could but this is not my diagram. It was set by the moderators and of you take a look, every article has one of these and it's just the same size.

Keeping in mind though that I'm going to refactor the article in the upcoming days, I'll be sure to add a diagram here that's up to par with the example.

Cheers !

It may or may not be worthwhile, and its not clear the language you're using or if you intend to be language agnostic, but in C++ you could collapse the ICharacter interface and CharacterBase class by defining the pure-virtual functions onMove, onAttack, onActionTrigger, and onCharacterDeath with default implementations. In C++, such definitions still qualify as a proper (pure virtual) interface because the default implementation is not wired up by default. That is, rather than defining default functionality in CharacterBase to be inherited by the character-class implementations, the character-class implementations can inherit directly from ICharacter and then delegate those interface-defined methods (by calling explicitly) to the default implementations defined in ICharacter.

 

I am not aware of any downsides this would bring, other than being a somewhat little-known feature of C++, and that I don't believe other languages have equivalent functionality. On the other hand, its benefit is modest, but not game-changing -- basically it would remove a level of inheritance from your character class tree. But, if characters were more compartmentalized (say, instead of just ICharacter, classes were constructed from IMagicUser and IMeleeUser as well) I suspect there would be further benefit to composability and a corresponding reduction in the number of variations you'd have to write (and duplicate code in) the middle layer.


Note: Please offer only positive, constructive comments - we are looking to promote a positive atmosphere where collaboration is valued above all else.




PARTNERS