Skip to main content
gamedev.net
🔒 Locked

[java] Egads! Inheritance!

Started by MMcNeil Apr 25, 2006 at 9:57 AM 12 replies 1.6k views
Original Post
MMcNeil
MMcNeil
Hello gamedev.net Forum buddies! I have a problem with inheritance. Here's the code for my two classes.

public class Player extends Unit{
	private String sName;
	private String sClass;

	public Player(){

	}

	public Player(String pClass){
		if(pClass == "Warrior"){
			Unit("Warrior");
		}
	}

	public String getName(){
		return sName;
	}

	public void setName(String name){
		sName = name;
	}
}

and the parent Unit

public class Unit{
	private int iHealth;
	private int iMana;
	private int iStr;
	private int iSta;
	private int iAgi;
	private int iInt;
	private int iWis;
	private int iMR;
	private int iFR;
	private int iCR;
	private int iDR;
	private int iPR;

	public Unit(){
		iHealth = 0;
		iMana = 0;
		iStr = 5;
		iSta = 5;
		iAgi = 5;
		iInt = 5;
		iWis = 5;
		iMR = 10;
		iFR = 10;
		iCR = 10;
		iDR = 10;
		iPR = 10;
	}

	public Unit(String charClass){
		if(charClass == "Warrior"){
			iHealth = 35;
			iMana = 0;
			iStr = 8;
			iSta = 7;
			iAgi = 5;
			iInt = 3;
			iWis = 5;

			iMR = (iWis * 3) + 2;
			iFR = (iWis * 3) - 1;
			iCR = (iWis * 3) - 1;
			iDR = (iWis * 3) - 2;
			iPR = (iWis * 3) + 1;
		}
		else{
			iHealth = 0;
			iMana = 0;
			iStr = 5;
			iSta = 5;
			iAgi = 5;
			iInt = 5;
			iWis = 5;
			iMR = 10;
			iFR = 10;
			iCR = 10;
			iDR = 10;
			iPR = 10;
		}
	}

	public int getStr(){
		return iStr;
	}

	public int getSta(){
		return iSta;
	}

	public int getAgi(){
		return iAgi;
	}

	public int getInt(){
		return iInt;
	}

	public int getWis(){
		return iWis;
	}

	public int getHP(){
		return iHealth;
	}

	public int getMP(){
		return iMana;
	}

	public int getMR(){
		return iMR;
	}

	public int getFR(){
		return iFR;
	}

	public int getCR(){
		return iCR;
	}

	public int getDR(){
		return iDR;
	}

	public int getPR(){
		return iPR;
	}

}

Hopefully my Source tags worked :) My problem is I have created a class that inherits its parent class that I have also created. How would I initialize the child class to use the constructor from the parent to access its member variables? I get an error saying that the Player class doesn't recognize the Unit("Warrior") line! I don't get it! Heh Thanks a lot guys!
Trouvist
Trouvist
public Player(String pClass) : Unit(pClass)
{
}



That should be your constructor
Son of Cain
Son of Cain
Nope dude, it's Java, not C++ :D

You must use the 'super' keyword in order to call the constructor of the super class. The call to super() must be the very first statement in your subclass constructor when you wish to override it:
public Player() {  super("warrior");}

That would be correct.

Son Of Cain

[edit: beaten by the AP =]
a.k.a javabeats at yahoo.ca
shmoove
shmoove
Like Son of Cain said, the call to super() has to be the very first statement in the constructor so your code:
	public Player(String pClass){		if(pClass == "Warrior"){			Unit("Warrior");		}	}

is actually impossible to reproduce. Looking at your code it seems that:
	public Player(String pClass){		super(pClass);	}

would actually acomplish the exact same thing. But if I assume this is just part of a bigger design and you do have to check something with the if statement in the beginning of the constructor, then you can always move all the initialization out of the contructor into an init() method that you would be free to call whenever you like.

shmoove
Son of Cain
Son of Cain
Since this became a design discussion, I would implement the following:

/** * Super class */public abstract class Unit implements SomethingThatBreathsAndHasAttributes {    public Unit() {}    // Interface methods to set attributes of something that breathes and has attributes :D  // ...  // ...  // ...}/** * Base class */public final class Warrior extends Unit {  public Warrior() {    // call super() if you wish to initialize something as default behavior  }}/** * Responsible for  */public class UnitFactory {    public static final Unit createUnit(Class < ? extends Unit > clazz) {    if ( clazz instanceof Warrior ) {             // requires argument-less constructor to work      Warrior w = clazz.newInstance();            // populate 'w' attributes based of this job's stats      // ...            return w;    }  }}


Why a factory? People may bash me on this, but on a game like this, you have to spawn many units of different types pretty quickly, so using a factory might give you the freedom to retrieve valid instances with default stats (or at least near twisted ones), ready to use. If you have to read a file to initialize these stats, do so on the factory, and you'll be localizing in your code the exact method that handles an important function like that, minimalizing maintenance, etc...

Damn, I gotta go... I can elaborate more on this if you wish, but later :D

Son Of Cain
a.k.a javabeats at yahoo.ca
MMcNeil
MMcNeil
Warrior is going to be a player controlled Class. Like all RPGs, there's a warrior, a mage, a preist, a theif, and various variations thereof.

If that changes how you'd implement a class system, I'm all ears!

And, yes, I am going to be focusing heavily on data files. I just do not want them to be accessible by a user... This game has plans to become Online.. in that case.. would I store all data files on my "server" aka my PC and only allow access as a player needs the info from them?

For example.. Billy has just slain a monster and the loot determined by the program is the Sword of Unforgiving God Slaying (or some such)... Now, his client would send to the server a request to have the data in the appropriately named .txt file send to his/her PC to be able to use it?

Or do I need to learn how to seriously heavy duty encrypt files...? I've had a lot of hacking probelsm in the past, adn hate to have them again!

Thanks again guys!

MMcNeil
5MinuteGaming
5MinuteGaming
For the subject of design I believe that a separate class for each Character class would be benificial both from a standpoint of memory allocation and data transmition across the net. Son of Cain's implementation would be close to my approach.

MMcNeil:
As far as the problem with data hacking, keeping things on the server side would be your best bet though having a single client socket and receiving data request and handling those individually would not be the way I would approach it.

The best way to handle data distribution across a network such that the development time is not hindered would be to use a Proxy Pattern. Java makes this easy with being able to send objects across a network, so that you can have a Proxy class for any type of Player. Lets call it PlayerProxy. The player Proxy class would be a subclass of Player and override all methods that return or change values values and instead send a Message object which would be invoked on the Server side.

The benefits of using a Proxy are:
1. You can use the Proxy in the same way you would if all the data from the Player class was on the Client side.

2. You don't have to worry about a manager to distribute messages or one that has to know about all the classes that need to communicate to each other.

3. You can easily take a PC application and turn it into an Online Application.

A Short Example:
public interface Player {     // all accessor methods or action routines you need          //for example     public void move( Point delta );}public abstract class Proxy implements Runnable {     private ObjectInputStream inComing = null;     private ObjectOutputStream outGoing = null;     public Proxy( Socket com ) {          inComing = new ObjectInputStream(com.getInputStream());          outGoing = new ObjectOutputStream(com.getOutputStream());     }     public void send( Message msg ) {          outGoing.writeObject(msg);     }     public void run() {                    try {               Message msg_in = null;               while( (msg = (Message)inComing.readObject()) != null ) {                    msg_in.invokeCall(this);               }          }catch( /*all the many exceptions */ ) {              //do recovery          }     }}private interface Message {     public invokeCall( Object o );}public class ProxyPlayer extends Proxy implements Player {     public ProxyPlayer( Socket com ) {          super(com);     }     public void move( Point p ) {          send( new Message() {               public void invokeCall( Object o ) {                    Player p = (Player)o;                    p.move(p);               }          });     }}public class ConcretePlayer extends Proxy implements Player {     private Point location = null;     public ConcretePlayer( Socket com, Point start ) {          super(com);          location = start;              }     public void move( Point delta ) {          location.translate( (int)delta.getX(), (int)delta.getY() );     }}

A bit lengthy and a little complicated but hopefully that should help you out with data hacking and reduce the amount of over all maintence required when using a networking manager to handle messages.

For Character classes i.e( warrior, mage, monk, theif, etc.) you would probably use the same Player classes but instead have a private String characterClass = WARRIOR; and have as Son of Cain suggested a Player factor that would initialize all the data members of Player for you and create the ConcretePlayer object but passing back a Player interface. Hope this is clear it's late and I might have missed some important details so let me know.
MMcNeil
MMcNeil
I feel stupid! Not much of the code examples you guys have given me has made much sense. I haven't even begun to look into the networking part of my game.

However, I'm going to be starting soon. My question now is if its all Data Dependant information.. I should be making a bunch of .txt files in a filesystem for all the information? And the info in them is being transferred by the Proxy class to a client?

Grr.. I really shoudl stick to one task - and the most crucial task right now is getting a working class system working :)

Thanks guys,
Michael
5MinuteGaming
5MinuteGaming
Sorry If I overwhelmed you a bit there MMcNeil. Definitely stick to one task at a time. The beauty of using the Proxy class is that you can add it to your code easily once you have a working prototype of even a full game. As long as the game supports multiple players then you will might find it easier to make an online version.

I am thinking of making a tutorial for Java Networking in Games using the proxy pattern. Don't know if that would be useful to anyone though!
MMcNeil
MMcNeil
Hey 5MinuteGaming, I'd definently be up to running through a tutorial on it! Any help would be welcome in trying to get this project up and running. I seem to have hit a road block though.

Should I use a Heirarchy like this?

Unit - Player - Warrior, Mage, Priest, Thief (and others)
- Monster - Different Monster Types (Fire, Earth, Water, etc)

Unit would have general functions. getHealth(), getMana() etc... Player and Monster would use more specific methods for their types. And then the Final types for both sides would have methods specific to their playstyle.

Ex. We have a Mage object. He can use all the methods from Unit and Player, but has the added method in the Mage class that allows him to cast Fire type spells. But now we have another object of the Priest class that has methods to cast Healing and Beneficial spells. Understanding me here or am I talking jibberish? Because this is the most sense Classes has made to me so far!

MMcNeil
5MinuteGaming
5MinuteGaming
It sounds like a good way to go. Pretty standard heirarchy of classes.

Although if you are going to use text files for the data for the players all you would need in the code would be a Unit class, a Player class, and a Monster class. Then you would have a UnitFactory which would load and set all the stats for the unit so in the text file you might have something like:

Player      = defaulttype        = magespelltypes  = Fire,               Commonspells      = Fireball,              Firearrowmana        = 20health      = 90Monster     = Jabberwockhealth      = 1000

Then in your loading code you read in the files into the UnitFactory and whenever you needed a Jabberwock you'd call the UnitFactory.create( String unit_name) for instance and it would return a Unit. And you could subclass UnitFactory to have a PlayerFactory and a MonsterFactory though if you use generics then you'd only need one class and probably call it like so:

UnitFactory factory = new UnitFactory("units.dat");
Player default = factory.create( "default" );

Of course theres more to it than that but I hope you get the idea. But if you don't feel that you know enough to do that then stick with the subclass approach and make the Unit <- Player <- Warrior, Mage, Priest, Theif, etc...
MMcNeil
MMcNeil
Yeah, you lost me at Jabberwock lol!

I'm currently trying to plan out the heirarchy on paper.. Including psuedocode methods for each class... I find that if I don't write puesdocode that when it comes time to code.. I have no idea what I'm doing LOL!

Thanks for the advice.. this is probably not going to be the last time you hear from me!

MMcNeil
Son of Cain
Son of Cain
Hi dude. I've some tips for you:

- Concentrate on defining common behavior first! From this analysis, you'll extract super classes and interfaces. Explaining: Do you have an action that is common to ALL (yes, I said ALL) your game objects? If the answer is yes (and it certainly is), write up an interface to group any of these "actions" as methods, and any class that implements the interface you write is automaticaly eligible to "behave" as one of your standard game objects.

Example:

Suppose this is a 2D game. In your map, you'll like to have power ups, waypoints, traps, things like that. Essentialy, all of these entities have a location in your map, a (x,y) coordinate where they are accessed. Now notice that this behavior is common for Units as well, since they can also "stand" in a coordinate on your map. From this small analysis, you extract the "Localizable" interface:

public class Coordinate2i {  int x;  int y;  public Coordinate2i(int x, int y) {    this.x = x;    this.y = y;  }}public interface Localizable {    // Returns the current coordinate of the Localizable instance  Coordinate2i getCoordinate2i();  // Sets the current coordinate of the Localizable instance  void setCoordinate2i(Coordinate2i coord);}


This behavior is common to a Player class and a WarpPoint class - but the difference is the use each class makes of the data. Player is visible, and its coordinate interferes with the placing of another Player instance in the map, since we consider that two players can't be on the same coordinate at once. This does not apply to a WarpPoint, he can be on the same coordinate of a game object of any type, the only difference is that it responds to collision with certain objects only (such as player).

You'll find out that most of the functionalities you're planning for your classes can be explained through a hierarchy of interfaces. Think of interfaces such as "LivingEntity", where you define methods such as getHP(), getMP, isAlive(), etc: when a class implements this interface, it means that its instances are treated as "living beings" within the game.

If you're going to need this degree of complexity or not, depends on the actions you're planning to execute over a group of objects, so design your system carefully! Not only it can save you mantainance time, but it can also make it a lot of easier to add new features for your game!

Post back with any further doubts... and happy designing ;)

Son Of Cain
a.k.a javabeats at yahoo.ca

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.