patterncsharpMinor
Using the observer pattern with collision detection
Viewed 0 times
thecollisionwithobserverusingdetectionpattern
Problem
My Game class has a property of type Player, which inherits from Entity:
It also has a property of type World, which has a collection of Entities (Robot inherits from Entity):
Finally, it has a Physics object with which I register the Player and World properties:
This is a typical observer pattern. The Register method on the Physics class adds each object to its own collection of Entities.
In my game loop, I update each of the Entities:
When Update is called on the Robot class, it will execute its behavior:
Since there are two Robots in the World (see above), one of them will stand still and one of them will move. Now, when DoIt is called on the MoveBehavior class is where I do some collision detection:
(By the way, this is a simplified example. I'll get to my question really soon.)
Remember, when I registered the Player and World properties they each got assigned to them the Physics object. This is
player = new Player( "knight.png" );It also has a property of type World, which has a collection of Entities (Robot inherits from Entity):
world = new World( new List
{
new Robot( "guy_1.png" ),
new Robot( "guy_2.png", new MoveBehavior( Directions.Up ) )
};Finally, it has a Physics object with which I register the Player and World properties:
physics.Register( player );
physics.Register( world );This is a typical observer pattern. The Register method on the Physics class adds each object to its own collection of Entities.
public void Register( Entity entity )
{
if ( !entity.Collidable )
{
return;
}
entity.Physics = this;
entities.Add( entity );
}
public void Register( World world )
{
foreach ( var entity in world.Entities.Where( e => e.Collidable ) )
{
Register( entity );
}
}In my game loop, I update each of the Entities:
foreach ( var entity in Entities )
{
entity.Update( gameTime );
}When Update is called on the Robot class, it will execute its behavior:
private readonly IBehavior behavior;
public override void Update( GameTime gameTime )
{
if ( behavior != null )
{
behavior.DoIt( gameTime, this );
}
}Since there are two Robots in the World (see above), one of them will stand still and one of them will move. Now, when DoIt is called on the MoveBehavior class is where I do some collision detection:
private readonly Vector2 direction;
public bool DoIt( GameTime gameTime, Entity entity )
{
if ( entity.DetectCollision( direction ) )
{
// Do nothing
return false;
}
entity.Move( direction );
return true;
}(By the way, this is a simplified example. I'll get to my question really soon.)
Remember, when I registered the Player and World properties they each got assigned to them the Physics object. This is
Solution
Your vision about what is an auto-property is correct. Your first question is essentially whether you should use an auto-property or a property instead, which I answer this way:
Is the property implementation likely to change?
Example:
With this you are able to change the age to -1. To prevent that, you would change your code to the following:
You had to: Introduce a field, write get and set code. If you hadn't used an auto-property in the first place, you would have to write less. Although I leave up to you if you would rather use an auto-property or a property. For me there are some cases that I don't use them and they could fit. Properties do not disrespect the principle of encapsulation. In my example (in second code segment) if you exposed the field age you could set it to a negative number, but you couldn't do that if you used the property. Basically you can change the implementation of the property whenever you want, but you wouldn't have to change the code that references that property.
Your re-factored code is actually better and I am glad that you improved it that way! With that code you are able to unit test the method
Finally, if you have to register many objects on your physics object, you may have (at least) two approaches:
-
Implement a fluent method call so you could write
instead of
-
Or write a new class that includes all possible Entities and register it in your physics object. This can be bothersome if you want to add a new type of entity in the future and adds an additional piece that you have to remember (know its purpose). This is also like returning to the same problem because now you would have to register all objects here!
Is the property implementation likely to change?
Example:
public class Person{
public int Age{get; set;}
}With this you are able to change the age to -1. To prevent that, you would change your code to the following:
public class Person{
private int age;
public int Age{
get{return age;}
set{
if(age >= 0)age = value;
else throw new Exception();
}
}
}You had to: Introduce a field, write get and set code. If you hadn't used an auto-property in the first place, you would have to write less. Although I leave up to you if you would rather use an auto-property or a property. For me there are some cases that I don't use them and they could fit. Properties do not disrespect the principle of encapsulation. In my example (in second code segment) if you exposed the field age you could set it to a negative number, but you couldn't do that if you used the property. Basically you can change the implementation of the property whenever you want, but you wouldn't have to change the code that references that property.
Your re-factored code is actually better and I am glad that you improved it that way! With that code you are able to unit test the method
DetectCollision in a better way, and separate the collision logic.Finally, if you have to register many objects on your physics object, you may have (at least) two approaches:
-
Implement a fluent method call so you could write
physics.Register(player).Register(world);instead of
physics.Register(player);
physics.Register(world);-
Or write a new class that includes all possible Entities and register it in your physics object. This can be bothersome if you want to add a new type of entity in the future and adds an additional piece that you have to remember (know its purpose). This is also like returning to the same problem because now you would have to register all objects here!
Code Snippets
public class Person{
public int Age{get; set;}
}public class Person{
private int age;
public int Age{
get{return age;}
set{
if(age >= 0)age = value;
else throw new Exception();
}
}
}physics.Register(player).Register(world);physics.Register(player);
physics.Register(world);Context
StackExchange Code Review Q#37085, answer score: 7
Revisions (0)
No revisions yet.