Beginner's question: implementing items

Started by
4 comments, last by Hajo The Dreamer 16 years, 1 month ago
I'm not new to programming, but this is the first time I'm programming a game. I have come across a hurdle that I hope you guys can help me with. I don't know what's a good way to implement an item system in a game. I am talking in terms of what data structure(s) to use to represent these items. I thought about having just one general item class and then pass the necessary arguments like name, cost, or whatever, but then how do I make each item behave differently? I also thought about having a base item class and then have a bunch of subclasses one for each type of item but it seemed a little overkill. Or should I use a database? I'd like to know what type of solutions are typically used in the video game industry to implement an item system. If you could point me to some example code (preferably in Java or Python) I would really appreciate it. Thanks in advance.
Advertisement
What data structure you use won't really matter at this stage. If you're thinking of an inventory, a basic ArrayList will do. The tricky part is designing an appropriate item hierarchy. Your items will depend on what your game is, as well as what you consider an item to be.

If you provide what items you want in your game and what you want to do with those items you'll likely get more specific responses.

Quote:
I also thought about having a base item class and then have a bunch of subclasses one for each type of item but it seemed a little overkill.


It's not. Depending on how complex you want/need your items to be, you may have a large hierarchy, or you may be able to use the Decorator Pattern to create your items. If your items are complex enough, you might be able to use a component system to create them. This last method is probably too complex to be useful for items, but like I said, it depends on what your items are and what you want to be able to do with them.
@Shakedown

Thanks for the reply.

The area I'm most interested in learning about is how to implement each item's action. The actions I'm thinking of right now are simple ones like increasing the player's hit points, defense, lives or things like that. These are simple since I only have to change a specific numerical attribute. I could have each item have like an "action()" method that would take the attribute name and how to change it as arguments. But I also started thinking, what if I want to expand this later on? Is there a way to make the action() method more general to be able to perform other kinds of changes like perhaps create a helper character, or give the player the ability to fly (just as examples).

I haven't had time to completely read the decorator pattern article you linked to, but it seems to be the kind of thing I'm looking for--something that allows new behavior added to an existing class. I'll also check out the component system you mentioned. Feel free to mention any other related techniques since I'm also trying to become familiar with more programming methodologies.
Quote:
The area I'm most interested in learning about is how to implement each item's action. The actions I'm thinking of right now are simple ones like increasing the player's hit points, defense, lives or things like that. These are simple since I only have to change a specific numerical attribute. I could have each item have like an "action()" method that would take the attribute name and how to change it as arguments. But I also started thinking, what if I want to expand this later on? Is there a way to make the action() method more general to be able to perform other kinds of changes like perhaps create a helper character, or give the player the ability to fly (just as examples).


I started typing up a response and realized that perhaps the Visitor Pattern could be of some interesting use in this situation. By using this method, you would be able to create all sorts of visitors; visitors that alter any entity's HP, visitors that change the state of any entity, visitors that even create a helper character or make the player fly.

The idea of the visitor pattern is that anything (any class) that would like to have the ability to be visited by a visitor simply includes a single method:

void acceptVisitor(Visitor v){ v.visit(this); }

The class should also provide an interface (not Java interface, but setter/getter methods) that the visitor would use to do whatever the visitor wants with the object. This removes coupling between the character and the item (if the item were a visitor), and allows for any new visitors to be added without having to touch the character class (or any class with the acceptVisitor() method).

Now, like I've said, I just thought of this idea, so I'll lay down some example code and I'll probably be able to determine from that whether or not it is a viable option. So, if you don't understand the code I'm about to write, check out the Visitor Pattern and come back, but you should be able to see the idea; it's very simple.

// Perhaps every character (player, enemy, NPC) in your game has a health// and an (x, y) positionpublic class Character { private int health; private int x_pos; private int y_pos; // Constructor public Character(...){...} // Visitor method public void acceptVisitor(Visitor v){  v.visit(this); } // Interface (getter/setter methods) public int getHealth(){ return health; } public int getXPos()  { return x_pos;  } public int getYPos()  { return y_pos;  } public void setHealth(int hp){ health = hp; }}


Now, you have a Character class (while simple, gets the idea across) that can accept any Visitor. You can create all sorts of visitors (although there wouldn't be much they could do since the Character only has a health and (x, y) position) and you can apply them (visit) with any Character without having to touch the Character class again.

Now we need to make a Visitor. One issue with the Visitor pattern is that every implementation of the Visitor interface (Java interface)(or abstract class) must provide definitions for each method, even if they don't care about those methods. We won't run into that problem in this example, but if you use the pattern in the future you'll soon see this.

So, here's the basic Visitor interface
public interface Visitor { public void visit(Character c);}


Remember, our Items will be visitors to Characters, so each Item must implement this Visitor interface and define the method. This is where you can make whatever you want, but to show you the possibilities I'll make a visitor that alters a Characters health and a visitor that creates a helper NPC.

// This could be a HealthPotion, or perhaps an object HealthPotion could contain // a HealthVisitor? Something to considerpublic class HealthVisitor implements Visitor { private int amount;  // Constructor public HealthVisitor(int amount){  this.amount = amount; } public void visit(Character c){  c.setHealth( c.getHealth() + amount ); }}


public class CreateSidekickVisitor implements Visitor { // Constructor public CreateSidekickVisitor(){} public void visit(Character c){  int x = c.getXPos() + 5;  int y = c.getYPos() + 5;  // Some NPC class, for example Sidekick, created right next to the Character   Character sidekick = new Sidekick(x, y); }}


I can see that you would probably want to create an Item class to not only provide the necessary variables for the visitors, but to encapsulate and hide the visitation methods. The Item class would have the abstract method use(), similar to your action() method. Then, the concrete implementations of the Item would invoke their own visitors on whatever Character the item is set to be used on. It could look like this:

public interface Item { public void use(Character c);}


public HealthPotion implements Item { private Visitor healthVisitor; private int     amount; // Constructor public HealthPotion(int amount){  // Create the HealthVisitor and provide it with the necessary information  healthVisitor = new HealthVisitor(amount);  this.amount   = amount; } // Define use() public void use(Character c){  c.acceptVisitor(healthVisitor); }}


Now to use the Item, simply call the use() method

// Somewhere in your gameItem healthPotion = new HealthPotion(10); // a HealthPotion that restore 10 HP// Assuming your have an inventory system, and that healthPotion is in your// Characters inventory, this method call would be made from within your Character classhealthPotion.use(this); // if this method is in your Character class, 'this' would be your Character


After writing all this, it seems to be an interesting idea for Item's. Although this limited example may not show the flexibility in a system like this, it's easy to see what is possible. For example, you could have an Item have multiple visitors, and when you use the item it could boost a characters health (HealthVisitor), give them a sidekick (CreateSidekickVisitor), and enhance their current weapon with fire (EnchantWeaponWithFireVisitor)(using the Decorator pattern on their current weapon)...and all from a single use() invoked on a single Item.



Quote:I also thought about having a base item class and then have a bunch of subclasses one for each type of item but it seemed a little overkill.

As Shakedown says, it isn't overkill, particularly if you're using Java (which is set up to be object oriented even when it isn't the right answer ;)). Without knowing more about what the game is it's hard to be specific, but at the most basic level something along the lines of:
interface Item { bool Use(World world, Actor actor);}

... might work, with World being the overall class that encapsulates the game world (in case the item's action depends on non-local influences, e.g. the number of a certain type of enemy, or has a non-local effect such as spawning an assistant) and Actor being a general character class that is used for any 'sentient' entity such as players, NPCs, or monsters. I added a return value for 'is this successful' because it usually helps and never hurts ;).

A simple health potion for example would simply be
class HealthPotion implements Item { bool Use(World world, Actor actor){  if(actor.Health + 10 > actor.MaxHealth) actor.Health = actor.MaxHealth;  else actor.Health += 10;  return true; }}


This method is less flexible than the Visitor pattern (I had a similar thing which I called 'Observer'), in that you can only act on one character or on the world as a whole, but it is simpler and therefore might help you if you don't want to jump in at the deep end.
Quote:Original post by nafd
I don't know what's a good way to implement an item system in a game. I am talking in terms of what data structure(s) to use to represent these items. I thought about having just one general item class and then pass the necessary arguments like name, cost, or whatever, but then how do I make each item behave differently?


In a former project of mine I used a single class to keep the data of the items. Items didn't have actions there but usages, so each instance of the item class got a list of usages (usage objects), appropriate to the ways this item could be used in the game.

Later I made a usage that encapsulated scripts, so the final architecture was that the basic item data was part of the core, and all actions were externalized as scripts. This worked rather well.

Subclassing on the item class itself I found to be rather rigid, hard to change later on in the course of a project. I, personally, would favor composition about inheritance here. I.e. to split the idea of an item into several, like attributes, usages, display information, and then make items from compositions of these objects.

Subclassing on the more active (functional) parts like usages works well, on the more data centric parts like attributes works less well in my experience. But of course, YMMV.

This topic is closed to new replies.

Advertisement