Reputation: 1487
I am currently working in unity to make a few games. I am using C#. I am usually happy with the code in my game and i know how to make it 'elegant', so to speak. I am very good at coding individual elements (Say, the spaceship in Asteroids). But I am only happy with my code until I get to the point where one object needs to interact with another. It becomes a spaghetti of code after that point and i ALWAYS drop the project.. I have yet to find a graceful way of handling things. I believe I have asked in various places around the internet, but I seem to keep coming back to this.
Is there any common method of handling the interactions between objects? anything that doesn't feel hacky? This problem arose again in my latest project. It is a Unity project, a 2d sidescroller. Detecting whether or not I hit a 'spike' with my character involves checking the collision objects tag and seeing whether or not it is a 'spike'. But then all my 'death' code is contained within the Player, not the spike. The spike isn't really anything other than a mesh collider with a tag. and this feels wrong.
So stackoverflow, how do you all handle this?
Upvotes: 2
Views: 4881
Reputation: 39650
Additionally to the design patterns, which are always good to consider:
Instead of using Tags, i would recommend creating Components for things like that. They are one of the core concepts of Unity3d and are more reusable.
For example, you could create a new component of type DamageVolume
or something like that. That would make it more generic and you could reuse it for other things that damage your player. Also you could configure it with properties like InstantKill
, DamageType
(which would allow the player to decide how he dies or which effects to play) or DamageAmount
. In your player's collision event, you could do something like this then:
var damager = collision.gameobject.GetComponent<DamageVolume>();
if (damager != null) {
if (damager.InstantKill) {
this.Kill(damager.DamageType);
}
else {
this.Damage(damager.DamageAmount, damager.DamageType);
}
}
Upvotes: 3
Reputation:
As Johnn Blade left in a comment on the question, using the Observer Pattern is probably a good approach for communicating state changes between different parts of your application.
As a concrete example, you may be able to break player movement down into several discrete steps (or events) that can be observed by other parts of the application.
For example, if you add the following events to the player:
And other objects in the scene may have events such as:
When you are about to move a player, you would trigger the BeforeMoved event - if nothing responds with canMove = false
(eg a locked door), then the move is permitted. Then you update the player's position, and call Moved.
So, your Spike may listen for player Moved events:
void Moved(Coordinate oldCoordinate, Coordinate newCoordinate)
{
if (newCoordinate.Intersects(this.Location))
{
DamagePlayer(50);
}
}
Correspondingly your player will listen for DamagePlayer events.
void DamagePlayer(int damage)
{
this.Health -= damage;
HealthChanged(this.Health);
}
Something (possibly on the player itself) would listen for HealthChanged events, and when it reaches zero or less, kills the player.
Using this pattern, adding new functionality such as detecting falling is relatively simple. Just create a new observer of the Moved event:
void Moved(Coordinate oldCoordinate, Coordinate newCoordinate)
{
decimal deltaY = oldCoordinate.Y - newCoordinate.Y;
if (deltaY < -100) // If fell 100 units or more, take 10 damage per unit.
{
DamagePlayer(10 * Math.Abs(deltaY));
}
}
Upvotes: 2
Reputation: 21449
That's usually what happens to big projects, they start very nice and end up in big monsters. Here are a couple of useful principles I found interesting when writing Object Oriented applications:
Upvotes: 3