Sign in to follow this  
Nicholas Kong

Restructuring collision code

Recommended Posts

So I decided to restructure my collision code to be general and flexible to something like this:

 

This code restructure single-handily eliminates my original code that had multiple instanceof check inside the for each loop.  biggrin.png

 

Now the only issue I can see is if when I want to add different audio for the monster death upon collision with a projectile. blink.png

 

 

// detect collision detection on all monsters on screen
 
public void checkMonsterCollision(ArrayList<GameComponent> gameObjects) {
 
 
// check for Monsters in the ArrayList
for(GameComponent component: gameObjects)
{
if(component instanceof Monster)
{
/* check the intersection of the laser's rectangle and the OneEye monster
*  rectangle. If both rectangles intersects, it is a collision
*/
if(rectangle.intersects(((Monster) component).getRectangle()))
{
 
// uncomment code to play the 
//playDeathSound();
// remove laser upon monster contact
Game.getInstance().remove(this);
// remove the monster upon contact of the laser
Game.getInstance().remove(component);
 
}
}
 
}
}



import java.awt.Rectangle;
 
 
public abstract class Monster extends Sprite{
 
private Rectangle rectangle;
 
public Rectangle getRectangle()
{
return rectangle;
}
}
Edited by warnexus

Share this post


Link to post
Share on other sites

The sound of the monster getting hit should be handled within the monster class itself. Essentially, when a laser collides with a monster it will tell that monster it got hit. The monster will then proceed to carry out its "getting hit" logic, which would include playing it's own sound effect for getting hit, among other things.

Share this post


Link to post
Share on other sites

The sound of the monster getting hit should be handled within the monster class itself. Essentially, when a laser collides with a monster it will tell that monster it got hit. The monster will then proceed to carry out its "getting hit" logic, which would include playing it's own sound effect for getting hit, among other things.

I forgot to mention the monster class is an abstract class. Is it generally allowed to add logic to an abstract class. The examples I learned for abstract class don't have logic implemented in them. If logic is allowed in the abstract class, then that would be logic per monster. If I add 10 monsters that would be 10 logic in the abstract class.

Share this post


Link to post
Share on other sites

I forgot to mention the monster class is an abstract class. Is it generally allowed to add logic to an abstract class. The examples I learned for abstract class don't have logic implemented in them. If logic is allowed in the abstract class, then that would be logic per monster. If I add 10 monsters that would be 10 logic in the abstract class.

 

Yeah, you probably don't want to do that. As a general rule of thumb, you should inherit interfaces, not implementations. Of course, the logic doesn't have to be actually in the monster class - rather you could have abstract 'OnHit()' functions which can be implemented for each monster separately.

 

That said, you probably don't want to be inheriting each monster from a 'monster' base class either. You'll end up with a whole load of separate monster classes which will likely end up containing a lot of copypaste code with small differences which will be a maintenance nightmare. It will be difficult to add new monsters since they are all hardcoded into the inheritance hierarchy. You also run the risk of creating for yourself a whole bunch of horribly convoluted inheritance trees. Does a Centaur inherit from the Horse monster, or the Human monster? Or both? (erk) And then what happens when you add a Pegasus and an Angel (Winged Human)? And Flying Centaurs? And do they all additionally inherit from the Bird? 

 

It would be better to make your monster class concrete, keep it very generic, and use data & composition to differentiate between the different monster behaviours. 

Share this post


Link to post
Share on other sites

I forgot to mention the monster class is an abstract class. Is it generally allowed to add logic to an abstract class. The examples I learned for abstract class don't have logic implemented in them. If logic is allowed in the abstract class, then that would be logic per monster. If I add 10 monsters that would be 10 logic in the abstract class.

 

Yeah, you probably don't want to do that. As a general rule of thumb, you should inherit interfaces, not implementations. Of course, the logic doesn't have to be actually in the monster class - rather you could have abstract 'OnHit()' functions which can be implemented for each monster separately.

 

That said, you probably don't want to be inheriting each monster from a 'monster' base class either. You'll end up with a whole load of separate monster classes which will likely end up containing a lot of copypaste code with small differences which will be a maintenance nightmare. It will be difficult to add new monsters since they are all hardcoded into the inheritance hierarchy. You also run the risk of creating for yourself a whole bunch of horribly convoluted inheritance trees. Does a Centaur inherit from the Horse monster, or the Human monster? Or both? (erk) And then what happens when you add a Pegasus and an Angel (Winged Human)? And Flying Centaurs? And do they all additionally inherit from the Bird? 

 

It would be better to make your monster class concrete, keep it very generic, and use data & composition to differentiate between the different monster behaviours. 

What do you mean by not inheriting implementations? Give me an example. So you are saying, I think I'm pretty sure this is what you mean. I should create a DeathSound interface that contains a method called "playDeathSound" in which the Monster class inherit from. But override the playDeathSound for each class that extends Monsters. It worked!

Edited by warnexus

Share this post


Link to post
Share on other sites

What do you mean by not inheriting implementations? Give me an example. So you are saying, I think I'm pretty sure this is what you mean. I should create a DeathSound interface that contains a method called "playDeathSound" in which the Monster class inherit from. But override the playDeathSound for each class that extends Monsters.

 

No, just like Sandman was saying - having an abstract OnHit() function and overriding this in each of your monster implementations.

 

But, like Sandman also implied, you might be better of using an entity/compontent based approach, where you have compose your monsters of generic data containers, called components, and have systems to handle the actual behaviour. In your case an entity might have a DeathSound component, containing the name of he sound to play on death.

 

Have a look at how EntityX works (though its C++11, you might want a somewhat similar "interface"), and for a bit older implementation (but further explaining the basics) http://www.gamasutra.com/blogs/MeganFox/20101208/88590/Game_Engines_101_The_EntityComponent_Model.php

Share this post


Link to post
Share on other sites

I forgot to mention the monster class is an abstract class. Is it generally allowed to add logic to an abstract class. The examples I learned for abstract class don't have logic implemented in them. If logic is allowed in the abstract class, then that would be logic per monster. If I add 10 monsters that would be 10 logic in the abstract class.

 

Yeah, you probably don't want to do that. As a general rule of thumb, you should inherit interfaces, not implementations. Of course, the logic doesn't have to be actually in the monster class - rather you could have abstract 'OnHit()' functions which can be implemented for each monster separately.

 

That said, you probably don't want to be inheriting each monster from a 'monster' base class either. You'll end up with a whole load of separate monster classes which will likely end up containing a lot of copypaste code with small differences which will be a maintenance nightmare. It will be difficult to add new monsters since they are all hardcoded into the inheritance hierarchy. You also run the risk of creating for yourself a whole bunch of horribly convoluted inheritance trees. Does a Centaur inherit from the Horse monster, or the Human monster? Or both? (erk) And then what happens when you add a Pegasus and an Angel (Winged Human)? And Flying Centaurs? And do they all additionally inherit from the Bird? 

 

It would be better to make your monster class concrete, keep it very generic, and use data & composition to differentiate between the different monster behaviours. 

 

I never thought of the hierarchy like that. But thanks for the heads-up. This definitely opens new opportunities to add certain weaknesses given a certain projectile. So far there are only 2 monsters in the arcade shooter. Right now, the instances of the Monsters like Ghost and OneEye are mostly copy and paste code with some small differences examples: one has animation frames and one does not, and overriding deathsound methods.

 

Given that one is a ghost which on the top of my head I might label as a Spirit Type and OneEye might be a Flying Type(given OneEye is a one-eyed winged monster.

 

Yes the monster is generic in the sense it is an abstract class. I do not understand what you mean by concrete though. An example would be nice. 

Edited by warnexus

Share this post


Link to post
Share on other sites

Concrete means "non-abstract" i.e. you can create an object of a concrete class type.

 

I wouldn't use the term "generic" for an abstract class since generic usually means it is a parameterised type (like a List<T> is a generic class).

Share this post


Link to post
Share on other sites

I never thought of the hierarchy like that. But thanks for the heads-up. This definitely opens new opportunities to add certain weaknesses given a certain projectile. So far there are only 2 monsters in the arcade shooter. Right now, the instances of the Monsters like Ghost and OneEye are mostly copy and paste code with some small differences examples: one has animation frames and one does not, and overriding deathsound methods.

 

I hope you are well aware that this kind of hierachy you've been "suggested" has really be given as an example of what not to do? Don't like/want to speak for someone else, but I wouldn't want you to go on with the thought "I've been told to make all kind of weird five-parent ten-depth inheritance hierachies to create my entities" and actually belive it to be a good practice. Also sorry if I actually misunderstood an of eighter yours or sandmans saying. It can/will work, but if you care about writing flexible, reusable and halfway decent code, you would never ever want to have things like a "Flying" and "Spirit" class an inherit from both of these. Like you said, they share so much in common, an entity/component system would really fit great here. Given from what I see you might (also) want to have a read at this great article on the topic that good coincidently released today on gamedev:

 

http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013

 

EDIT: Just imagine the "undead flying one-eyed poisiounous evil man-tree of fire" - while not a quite actual example from a game, just thing about how horrible this would work if you had all those "attributes" as single classes, and needed to inherit from all of this - with components you could compose this quite easily, without having one line of boilerplate-code - and you could just as well compose a thousand other similar or completely differnt entities using those components.

Edited by The King2

Share this post


Link to post
Share on other sites

I wouldn't use the term "generic" for an abstract class since generic usually means it is a parameterised type (like a List is a generic class).


Actually I meant generic more in the sense of 'general, non-specific' rather than C# style Generics (in which the data type the class operates on is left generalised).

What do you mean by not inheriting implementations?


'Implementations' are any member functions which are not pure virtual. It can be tempting to put some implementations into a base class, so all derived classes have access to it, saving you from copy-pasting code. However, it's not really a good mechanism for sharing code for two reasons:
1. It needs to make sense for all objects it is called on. Unfortunately, if your inheritance hierarchy is open for extension, you can't guarantee that to be true forever. Anyone adding new derived classes must either make the inherited implementation generic enough to work sensibly, or figure out some horrible kludge to prevent it from being used.
2. You may want to share the code with something that can't sensibly be derived from it. In which case you either have to derive anyway, and thus create a nonsensical relationship, or copy paste the code.

However, if you pull the implementation out of the base class and into a separate component. This component can then be used all over the place, without forcing you into some inheritance hierarchy. This is what I mean by composition. Rather than getting behaviour through inheritance, you can 'build' the correct behaviour by putting together a set of independent components that implement the desired functionality.


So you are saying, I think I'm pretty sure this is what you mean. I should create a DeathSound interface that contains a method called "playDeathSound" in which the Monster class inherit from. But override the playDeathSound for each class that extends Monsters. It worked!


As The King2 correctly suggests, I meant just add an abstract OnHit() function to the Monster class, and playing the appropriate effect in the derived class's implementation. There's nothing to gain by having a separate interface here - and if there were, you wouldn't want anything as narrow in purpose as 'IDeathSound'. For some architectures there might be some value in a 'ISoundEmitter' interface - but it's probably best to keep things simple. Edited by Sandman

Share this post


Link to post
Share on other sites

Concrete means "non-abstract" i.e. you can create an object of a concrete class type.

 

I wouldn't use the term "generic" for an abstract class since generic usually means it is a parameterised type (like a List<T> is a generic class).

Well I am quoting Sandman because he said generic. But yeah I think general class would be a better word. Thanks for the explanation for concrete.

Share this post


Link to post
Share on other sites

I hope you are well aware that this kind of hierachy you've been "suggested" has really be given as an example of what not to do? Don't like/want to speak for someone else, but I wouldn't want you to go on with the thought "I've been told to make all kind of weird five-parent ten-depth inheritance hierachies to create my entities" and actually belive it to be a good practice.

 

In case there was any misunderstanding, this is what I meant. Deep, complicated inheritance trees are generally a bad thing. 

 

An ideal hierarchy for your CMonster class would be just CMonster. No derived classes at all, just one class to represent all of the different monsters in your game. The different attributes and behaviours are added using composition: data and independent helper classes.

 

Given from what I see you might (also) want to have a read at this great article on the topic that good coincidently released today on gamedev:
 
http://www.gamedev.net/page/resources/_/technical/game-programming/understanding-component-entity-systems-r3013

 

This article explains things nicely, although one thing I would say is that you don't necessarily need to go for a full on, general purpose 'Component System' to benefit from a composition approach, and for a smallish project it's probably overkill. Just separating out shareable code into separate and independent objects is a step in the right direction.

 

Another thing I would say is: Don't be too worried about following perfect practice. It's very easy to get caught in the trap of reading about cool new design approaches and then immediately running off and refactoring everything to use it, only to refactor it all again later when some new pattern is discussed. Ultimately, a finished project with a bad architecture is better than a perfectly designed project that is never finished because it's always being refactored. So with all this "best practice advice" - keep it in mind, and remember it for future design decisions, but don't be too eager to throw your old design approach away for the sake of following it, unless your old design has already become so difficult to work with that you need to refactor.

Edited by Sandman
Multiple selective quotes are borked

Share this post


Link to post
Share on other sites

This article explains things nicely, although one thing I would say is that you don't necessarily need to go for a full on, general purpose 'Component System' to benefit from a composition approach, and for a smallish project it's probably overkill. Just separating out shareable code into separate and independent objects is a step in the right direction.

 

You are right, of course it all depends on the magnitude and the needs of the actual developer/project. Such a system, built well and tested out in a current project can be used as a good starting point for writing re-usable code for other projects - it might save a lot of time in comparison to re-building a game-specific composite system when starting a new project. It might also be an excellent case to learn some advanced language features and/or programming pattern - my c++11 entity/component system for example finally gave me the reason and material to properly learn templates/varidic templates, and some design patterns I ignored previously like the factory pattern. But again, it truly all depends on the what one wants to do. If the need for learning is there and possible expansion is wanted, I'd say one can give a "full" component system a try.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this