Java-Gaming.org Hi !
Featured games (83)
games approved by the League of Dukes
Games in Showcase (513)
Games in Android Showcase (121)
games submitted by our members
Games in WIP (577)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  instanceof or seperate lists?  (Read 2862 times)
0 Members and 1 Guest are viewing this topic.
Offline skinny boy

Junior Duke





« Posted 2009-09-22 12:14:47 »

so i am making a game, and i use Interface Sprite for my basic class for the game entities

the Sprite only has one method, draw.

then i have the Interface Moveable, Objects that can be moved (and also drawn) implement both (or maybe Moveable should extend the Sprite interface ??)

i have a list to hold the Sprites, so when i iterate through the list should i use instanceof to make sure that i move only moveable objects, or should i have two seperate lists, and call the move method only on the Moveable objects???

edited: there is the solution of having an enum, and inside each implementation the object knows its type, and can be asked for it
but it looks kinda ugly, and so does the instanceof operator (to me)
Offline Wildern

Junior Duke





« Reply #1 - Posted 2009-09-22 15:57:00 »

You could have the move and draw methods in the base object and have the derived objects make the distinction between who is movable and who is not by whether or not the move method actually does anything.
Then you have one list and you call move and draw on all objects and the objects control what is actually done.
Offline skinny boy

Junior Duke





« Reply #2 - Posted 2009-09-22 16:16:15 »

your suggestion also occured to me among dozens of others

i am not just trying to make something work, i just want to understand why an approach is better than another

thank you for your answer and time
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #3 - Posted 2009-09-22 16:55:19 »

In games, at least, pretty much everything can be both moved and drawn, and as such you'll typically have a big superclass for anything that can exist in the world, often called Entity. It contains move(), draw(), and other like-methods, and also has fields for X/Y position, size, etc. This is often a better choice as you also get the fields that can be declared protected and therefore used by subclasses.

See my work:
OTC Software
Offline JL235

JGO Coder


Medals: 10



« Reply #4 - Posted 2009-09-22 17:45:48 »

Game objects or sprites may not only want to move, but update their transparency, remove themselves after a certain amount of time or some other action. That's why I'd recommend giving all sprites both an update and draw method, which allows you to put them all into their own list. I take this further with a list of lists to allow me to select which layer the objects will appear on.

Movable objects will move when update is called. Objects that are just there to look pretty (like text) will do nothing when update is called. Other objects will run their own custom code in update.

Offline skinny boy

Junior Duke





« Reply #5 - Posted 2009-09-22 17:51:58 »

ok, big picture, forget about the move and draw

we have a game with lots of entities, too complex for Class hierarchy

Advanced Java Game Programming book example: Zombie extends Undead extends Humanoid extends Thing, or Zombie extends Humanoid extends Undead extends Thing
so either all your Undead are also Humanoids (VampireBats??? ) or all of your Humanoids are Undead....

a solution to this approach is having interfaces

so far so good???

(and also, there is the possibility that someone prefers Interface programming from Class)

so for someone who wants to use Interfaces, and every game entity would be implementing the needed interfaces, what is the best solution?? using instanceof to call the holyWaterDamage() on the Zombie, or the getWet() on the main hero Huh or using seperate lists??

of course, when something is as complex, there must be lots and lots of lists..... though i assume that if the lists store the references and nothing more, the extra memory needed for objects belonging to more than one, isnt that big

thank you for your answers so far and forgive me for not being specific enough from the very beginning
Offline DzzD
« Reply #6 - Posted 2009-09-22 18:05:32 »

you should have a look to Component Oriented Programming and Entity Systems , there is a nice discussion about this somewhere on JGO

Offline i30817

Junior Duke





« Reply #7 - Posted 2009-09-22 18:23:59 »

See this blog post and the discussion bellow.

http://tech.puredanger.com/2007/07/16/visitor/

Disavantages are more upfront work.
Offline skinny boy

Junior Duke





« Reply #8 - Posted 2009-09-22 18:52:41 »

you should have a look to Component Oriented Programming and Entity Systems , there is a nice discussion about this somewhere on JGO

is that a book???
Offline skinny boy

Junior Duke





« Reply #9 - Posted 2009-09-22 18:53:18 »

See this blog post and the discussion bellow.

http://tech.puredanger.com/2007/07/16/visitor/

Disavantages are more upfront work.

thank you for the link (still reading)
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline DzzD
« Reply #10 - Posted 2009-09-22 19:36:17 »

is that a book???

nop, this is  a different approach than OO to build application


http://www.java-gaming.org/topics/game-object-component-system/20589/view.html

Offline JL235

JGO Coder


Medals: 10



« Reply #11 - Posted 2009-09-22 20:53:29 »

A few weeks back I was thinking of building a component oriented system. Reading that discussion on JGO put me off the idea.

so for someone who wants to use Interfaces, and every game entity would be implementing the needed interfaces, what is the best solution?? using instanceof to call the holyWaterDamage() on the Zombie, or the getWet() on the main hero Huh or using seperate lists??

of course, when something is as complex, there must be lots and lots of lists..... though i assume that if the lists store the references and nothing more, the extra memory needed for objects belonging to more than one, isnt that big

thank you for your answers so far and forgive me for not being specific enough from the very beginning
So the main issue is 'how do I find objects of a specific type?' I personally use both systems but with a bit of reflection. I compare the type directly with class.isInstance rather then instance of, this is for when I'm searching for objects inside the world. I also dynamically sort objects into separate lists inside the collision detection handler. By doing it dynamically it still looks like I'm putting them all into one big collection. Both of these contain all game objects (although there is no reason why you couldn't push them together and it'd probably be more efficient, but it's fast enough). The first is for finding objects in a generic fashion, like removing all enemies in the game. The later is used for finding intersections between actors of a specific type.

The code for using them looks a bit like:
1  
2  
3  
Foo foo = getObject( Foo.class );
List<Foo> foos = getObjects( Foo.class );
List<Bar> bars = getIntersectingObjects( Bar.class );


So to solve your Hero/Zombie issue it would be a bit like:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
class HolyWater implements Sprite
{
    public void update()
    {
        Hero hero = getIntersectingObject( Hero.class );
        if (hero != null) {
            hero.getWet();
        } else {
            for (Zombie zombie : getIntersectingObjects( Zombie.class )) {
                zombie.holyWaterDamage();
            }
        }
    }
}


But you could also add a HolyWaterReceiver interface that both Hero and Zombie implement. i.e:
1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
class HolyWaterReceiver implements Sprite
{
    public abstract void receive(HolyWater water);
}

class Hero implements HolyWaterReceiver
{
    public void receive(HolyWater water)
    {
        getWet();
    }
}

class Zombie implements HolyWaterReceiver
{
    public void receive(HolyWater water)
    {
        holyWaterDamage();
    }
}

class HolyWater implements Sprite
{
    public void update()
    {
        for (HolyWaterReveiver receiver : getIntersectingObjects( HolyWaterReceiver.class )) {
            receiver.receive( this );
        }
    }
}

This pushes the responsibility of 'what happens if your hit by holy water' out to the object being hit.

Offline skinny boy

Junior Duke





« Reply #12 - Posted 2009-09-22 21:32:09 »

great stuff to read,,

so the answer to my original question is probably "none"

thank you all for your answers
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #13 - Posted 2009-09-23 00:02:47 »

I think really you're putting too much of your object definition in the hands of your class hierarchy. Instead of all this Poodle extends Dog extends Canine extends Animal extends Entity type ideas you have, you can probably snip off almost all the extra things, like Poodle and Dog for certain, and probably Canine, too.

The functionality that each subclass defines should be pretty major. In my example case, a Poodle is only different from a Dog in how it looks, and maybe how strong it is. That can be translated to fields that are defined differently when you create the object. Just change Poodle's Sprite to reflect his different look and change his size to reflect his new strength. The differences between Dog and Canine will be similarly small - perhaps a Wolf also extends canine, and the difference between a Wolf and a Dog is that Wolves are bigger and meaner. Again, that comes down to a different Sprite, then perhaps the meanness can go into an "aggression" variable.

Then the specific behavior that a Canine exhibits can also be assigned to a bunch of enumerated separate actions, like walkType = TYPE_FOUR_LEGGED, attackType = TYPE_BITE, etc.

Typically the differences in each subclass are very major, like Entity and HostileEntity and FriendlyEntity. In an RPG, the difference between the two is very large (hostile entities need to have stats for combat, what "friends" they can bring with them, what XP they can give you, etc., whereas friendly entities need to know conversations, quests, item rewards, etc.). You should only have subclasses for information that cannot be logically represented by the superclass.

In your Zombie extends Undead extends Humanoid extends Thing example, Zombie is not at all different from Undead, Undead is barely different from Humanoid, and Humanoid probably isn't much different from "Thing." Instead these differences should be defined by different fields, and perhaps you can write a bunch of different behavior scripts they can utilize if you really need to. But typically you'll stick with even just booleans... isUndead, isHumanoid, etc.

Real-world example:
In the game I'm working on right now, we've got:
Entity (comes with position, size, the capability of acting, drawing, doing hit tests, etc.)
Entity > MobileEntity (comes with variables for moving around, like pathfinding, velocity, etc.)
Entity > BackgroundEntity (adds nothing new to the table, but isn't abstract, overrides act to do nothing except animate)
Entity > MobileEntity > Car (has a bunch of logic for dropping off Customers, lining up in the parking lot, etc.)
Entity > MobileEntity > Customer (has a bunch of logic for paying the Player, waiting in a venue to be ready to get their Car, etc.)
Entity > MobileEntity > Particle (has a bunch of logic for falloff, color changing, animation, flipping around, etc.)
Entity > ParticleEmitter (has a bunch of logic for timing of emitting particles)
Entity > MobileEntity > Valet (has a bunch of logic for driving cars, running back to their zone, etc.)

And those are all the entities that exist in the entire game, which is many thousands of lines long. And if I were redesigning it now I would do away with MobileEntity and BackgroundEntity, just because they have become redundant through so many code refactorings.

See my work:
OTC Software
Offline i30817

Junior Duke





« Reply #14 - Posted 2009-09-23 02:55:15 »

Yes don't go overboard with inheritance. Actually i'm not sure how well the visitor technique described in the link i posted works for games. They are actually real time applications, and the guy making the example works in another area.
Offline i30817

Junior Duke





« Reply #15 - Posted 2009-09-23 03:28:43 »

I'd actually read the Game object component system thread too. Might be worth a try.
Offline skinny boy

Junior Duke





« Reply #16 - Posted 2009-09-23 09:39:33 »

so, i should leave the theoritical search of a "best design" and just be practical
a game should be playable (thus completed and tested) after all
thank you all for your great advice
Offline JL235

JGO Coder


Medals: 10



« Reply #17 - Posted 2009-09-23 10:35:57 »

I think really you're putting too much of your object definition in the hands of your class hierarchy. Instead of all this Poodle extends Dog extends Canine extends Animal extends Entity type ideas you have, you can probably snip off almost all the extra things, like Poodle and Dog for certain, and probably Canine, too.

The functionality that each subclass defines should be pretty major. In my example case, a Poodle is only different from a Dog in how it looks, and maybe how strong it is. That can be translated to fields that are defined differently when you create the object. Just change Poodle's Sprite to reflect his different look and change his size to reflect his new strength. The differences between Dog and Canine will be similarly small - perhaps a Wolf also extends canine, and the difference between a Wolf and a Dog is that Wolves are bigger and meaner. Again, that comes down to a different Sprite, then perhaps the meanness can go into an "aggression" variable.
I think works very well and fully agree with this idea; but only if you are never going to be searching for Dog, Poodle or Wolf! Then it doesn't matter if they are stored as a Canine and you can build Factory classes to automate building these (and more) types of Canines.

In your Zombie extends Undead extends Humanoid extends Thing example, Zombie is not at all different from Undead, Undead is barely different from Humanoid, and Humanoid probably isn't much different from "Thing." Instead these differences should be defined by different fields, and perhaps you can write a bunch of different behavior scripts they can utilize if you really need to. But typically you'll stick with even just booleans... isUndead, isHumanoid, etc.
But I do not recommend this part of the design. Your adding methods in order to state the type of the object, which you can already do quite happily with inheritance. If the object is Undead then it should be an instance of Undead (or of a sub-class).

Overall using a common class for objects (i.e. Canine for Dog, Wolf and Poodle) only works well if their differences are very minor (like different image, attack value, hp, etc). Once you start adding differences in behaviour and type you'll begin adding lots of boiler plate code just to get the same effect as using inheritance.

Offline Riven
« League of Dukes »

JGO Overlord


Medals: 818
Projects: 4
Exp: 16 years


Hand over your head.


« Reply #18 - Posted 2009-09-24 10:28:07 »

I tend to agree with Demonpants on this one (surprise!). The aim is to reduce the depth of your inheritance tree. My personal preference is to have it reduced to 0. Inheritance is best avoided - it restricts you into working with some kind of hierarchy, where a hierarchy is often totally not suited to handle your game logic. You end up with moving more and more functionality up the tree, until (in worst case) you end up with a huge 'magic blob' having functionality that you can turn on and off.

Composition over inheritance is here to save the day. You can use it as 'mixins' from other language, so that you can simply add or remove functionality (even at runtime) from an entity. The more complex the game is, the greater the advantages become from using composition. In a tiny game, it's just a royal pain in the behind.

Entity dog = new Entity();
dog.setSprite(myDogSprite);
Movement2D mov = new Movement2D();
BiteWeapon = new BiteWeapon();
dog.addComponent(mov);
dog.addComponent(new DogAI());
dog.addComponent(weapon);

mov.enqueueMoveTo(x1, y1);
mov.enqueueMoveTo(x2, y2);
weapon.enqueueAttack();

while(true)
   dog.tick();

Hi, appreciate more people! Σ ♥ = ¾
Learn how to award medals... and work your way up the social rankings
Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #19 - Posted 2009-09-24 14:47:16 »

I tend to agree with Demonpants on this one (surprise!). The aim is to reduce the depth of your inheritance tree. My personal preference is to have it reduced to 0. Inheritance is best avoided - it restricts you into working with some kind of hierarchy, where a hierarchy is often totally not suited to handle your game logic. You end up with moving more and more functionality up the tree, until (in worst case) you end up with a huge 'magic blob' having functionality that you can turn on and off.

Composition over inheritance is here to save the day. You can use it as 'mixins' from other language, so that you can simply add or remove functionality (even at runtime) from an entity. The more complex the game is, the greater the advantages become from using composition. In a tiny game, it's just a royal pain in the behind.

Entity dog = new Entity();
dog.setSprite(myDogSprite);
Movement2D mov = new Movement2D();
BiteWeapon = new BiteWeapon();
dog.addComponent(mov);
dog.addComponent(new DogAI());
dog.addComponent(weapon);

mov.enqueueMoveTo(x1, y1);
mov.enqueueMoveTo(x2, y2);
weapon.enqueueAttack();

while(true)
   dog.tick();

Wink

Yeah, seems like Riven is getting back towards the component method of doing things - in the end it looks like anything works, but you should find what's best for you. However, using instanceof all over the place is a bit slow, so you should be careful with having a bagillion classes. Otherwise there's not much difference, in the end, between all inheritance, all components, or some shade in between.

One big reason not to use inheritance, however, is for updating purposes. Because Java is JIT you can always just have people download new .class files (like if you added in Vampire after releasing the game) instead of a whole new download, but this won't work if you're planning on distributing in binary, and either can be annoying and is more prone to classpath problems. If you've got a component system then all you need to do is include another constructor with some different parameters to it, which is easier to add on to an existing project.

What really will aid you the best in the end, though, is if you can successfully write down at least most of the stuff you will need for your game. Do some UML-type stuff: this monster does this and this item does that, and these two can share that functionality, etc. Once you've got a steady roadmap to go off of, you'll be in a much better place to decide how you want to implement everything.

See my work:
OTC Software
Offline Orangy Tang

JGO Kernel


Medals: 56
Projects: 11


Monkey for a head


« Reply #20 - Posted 2009-09-24 15:25:38 »

However, using instanceof all over the place is a bit slow
Swing and a miss. instanceof is often just a single comparison and so very fast. We covered this recently as well: http://www.java-gaming.org/topics/implementation-of/18750/view.html

[ TriangularPixels.com - Play Growth Spurt, Rescue Squad and Snowman Village ] [ Rebirth - game resource library ]
Offline kevglass

JGO Kernel


Medals: 188
Projects: 24
Exp: 18 years


Coder, Trainee Pixel Artist, Game Reviewer


« Reply #21 - Posted 2009-09-24 15:48:48 »

Quote
One big reason not to use inheritance, however, is for updating purposes. Because Java is JIT you can always just have people download new .class files (like if you added in Vampire after releasing the game) instead of a whole new download, but this won't work if you're planning on distributing in binary, and either can be annoying and is more prone to classpath problems. If you've got a component system then all you need to do is include another constructor with some different parameters to it, which is easier to add on to an existing project.

Didn't understand this bit. If the Vampire in the example is a sub-class of an existing class you can distribute as much as you add extensions as much as you want. With composition it's the same, if you want to add on new uses of existing stuff thats fine, but as soon as you want to add a new type of component you're back to the same problem. I guess you could end up with a really high level component interface that satifys everything, but most likely that'd be a real PITA to work with.

Kev

Offline Eli Delventhal

JGO Kernel


Medals: 42
Projects: 11
Exp: 10 years


Game Engineer


« Reply #22 - Posted 2009-09-24 17:01:41 »

Swing and a miss. instanceof is often just a single comparison and so very fast. We covered this recently as well: http://www.java-gaming.org/topics/implementation-of/18750/view.html
Yeah, I thought the conclusion from that thread was that it was slower than other options, bot not much so? I guess not... Either way, instead of having in your list always saying if (thing instanceof OtherThing) {doStuff();}, if you're using a component system you can just tell absolutely everything to doStuff(), and if it has no stuff() component it will just ignore it. So you're avoiding a comparison. But scratch that, because really you're just moving the work around... so yeah I guess it's basically going to be the same no matter what.

@Kev: I was more thinking about how Vampire will probably not add any new functionality (because it is so close to Zombie and Undead) and so you'll just be able to make an XML file or whatever for it that has the correct components to use in it. If you had a Vampire class, you need to deal with putting that in the right classpath to avoid problems, whereas the XML can be loaded from wherever, including servers on the net and the like. But I guess if you configure your classpath right that becomes pretty moot anyway. And you're right that if you actually want to add new functionality, rather than a new combination of traits you already have, then either way you're going to need to distribute new code. But really in the end I guess this is just more proof that you should just do what feels best for you and makes the most sense in your project.

See my work:
OTC Software
Offline Roquen
« Reply #23 - Posted 2009-09-24 17:52:35 »


The really depends on if your asking if an object is an instanceof a plain object or an interface.  Here's some pseudo-code:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
24  
25  
26  
27  
28  
29  
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  
43  
44  
45  
46  
47  
48  
49  
50  
51  
52  
53  
54  
// check if class 'S' implements the interface 'T'
boolean
implements(class S, class T)
{
  for (class interface = all interfaces implmented by S) {
    if (interface == T || implements(interface, T))
      return true;
  }
 
  return false;
}

// Is 'S' a superinterface of 'T'?
boolean
isSuperinterface(class S, class T) )
{
  while (S) {
    if (implements(S,T))
        return true;
    S = parent of S;
  }
  return true;
}

boolean instanceof(class S, class T)
{
  // Trivally assignable if the same class
  if (S==T)
    return true;
 
  if (T is a class) {
    if (S is a class) {
      // -> S must be T of a subclass of T
      do {
        S = parent of S;
        if (S==T)
          return true;
      } while(S is not Object);
    }
    else {
      // * T is class type
      // * S is interface
      // -> T must be Object
      return T == java.lang.Object;
    }
  }
  else {
    // * T is interface
    // -> S must implement T
    return isSuperinterface(S, T);
  }

  return false;
}


This can be speed-up in a number a ways.  Example is to track the hierarchy depth with each class and to allow skipping and immediate failure if impossiable.
Offline JL235

JGO Coder


Medals: 10



« Reply #24 - Posted 2009-09-24 19:36:20 »

I don't quite get what your code is for. To check if one class is the super class or interface of another you can just do:
1  
superClass.isAssignableFrom( subClass );

Admittedly I find isAssignableFrom tends to be a very slow function, so I just cache the result.

Offline Roquen
« Reply #25 - Posted 2009-09-25 06:30:14 »

The pseudo-code is "not Java" (TM).  It is what the VM/JIT must insure for 'instanceof' (and likewise assignment compat).  It's intended to point out that 'object instanceof SomeClass" is much less complex than "object instanceof SomeInterface" and that in general both will be more complex than the quoted "single if" cost.

(EDIT: Note I left out dealing with arrays on purpose).
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

theagentd (18 views)
2014-10-25 15:46:29

Longarmx (52 views)
2014-10-17 03:59:02

Norakomi (45 views)
2014-10-16 15:22:06

Norakomi (34 views)
2014-10-16 15:20:20

lcass (39 views)
2014-10-15 16:18:58

TehJavaDev (68 views)
2014-10-14 00:39:48

TehJavaDev (68 views)
2014-10-14 00:35:47

TehJavaDev (60 views)
2014-10-14 00:32:37

BurntPizza (74 views)
2014-10-11 23:24:42

BurntPizza (45 views)
2014-10-11 23:10:45
Understanding relations between setOrigin, setScale and setPosition in libGdx
by mbabuskov
2014-10-09 22:35:00

Definite guide to supporting multiple device resolutions on Android (2014)
by mbabuskov
2014-10-02 22:36:02

List of Learning Resources
by Longor1996
2014-08-16 10:40:00

List of Learning Resources
by SilverTiger
2014-08-05 19:33:27

Resources for WIP games
by CogWheelz
2014-08-01 16:20:17

Resources for WIP games
by CogWheelz
2014-08-01 16:19:50

List of Learning Resources
by SilverTiger
2014-07-31 16:29:50

List of Learning Resources
by SilverTiger
2014-07-31 16:26:06
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!