I'm new to this whole thing, so please tell me if I'm doing this wrong of if there's a better spot for my question.
I'm making a game with basic systems for projectiles, npcs and items. This game will have multiple variants of each of these types. For the purposes of this example, there will be a Bullet projectile, a Rocket projectile, and a Pistol which shoots Bullets.
The only experience I have with such a system is inside Terraria's source code, where Items are all defined in a massive if-else tree, e.g.
else if (this.type == 467)
{
this.name = "Fireball";
this.width = 40;
this.height = 40;
this.aiStyle = 1;
this.hostile = true;
this.damage = 10;
}
The problem with this approach is (apart from the terrible mess it makes) that adding new items requires modifications to 4-5 different areas of code - especially if you want to add any extra effects, like giving off light, burning enemies etc.
I'm trying to do this in a much better format. I've come up with a simple system that with nested classes, e.g.
public class ProjectileData
{
public class Bullet : Projectile
{
public float speed;
public Bullet() : base()
{
this.type = ProjectileID.Bullet;
this.damage = 25;
this.origin = new Vector2(9.5f, 2.5f);
speed = 10;
}
public override void AI()
{
this.velocity += new Vector2((float)Math.Cos(rotation), (float)Math.Sin(rotation)) * speed;
}
public override void OnHit()
{
Game.CreateExplosion(this.position);
}
}
public class Rocket : Projectile
{ ... }
}
With this system, to create a bullet, instead of using something like
Projectile.CreateProjectile(int id, ...)
{
Projectile projectile = new Projectile(id);
}
...
Projectile.CreateProjectile(ProjectileID.Bullet, ...);
I have
Projectile.CreateProjectile<T>(...) where T : Projectile, new()
{
T projectile = new T(id);
}
...
Projectile.CreateProjectile<ProjectileData.Bullet>(...);
which looks and works nicely.
However, I've run into a problem: if I want to create an item that shoots a projectile, I can't reference it. For example, with the id-based system I could write something like
item.projectileType = ProjectileID.Bullet
but it isn't possible to assign a Class to a property like that.
I guess this boils down to 2 questions:
- Is this the 'correct' way to pass data to an object or is there a better structure, with or without inheritance??
- Is there a way to reference a class, and use that reference at runtime in a generic method call?
1 Answer 1
Use the factory-pattern. A factory is an object which creates objects.
So when you have a weapon which shoot projectiles, pass a ProjectileFactory
to it and leave the creation of the projectile to that class.
You can then have different classes which extend ProjectileFactory, like BulletProjectileFactory
, ExplosiveProjectileFactory
, GravityAffectedProjectileFactory
, HomingProjectileFactory
etc. which create bullets with different game mechanics.
For example, when you want to create a gun which shoots bullets which fly with a speed 8.0 pixels per tick, do 12 damage and use the sprite "bullet.png" you would write something like this:
Weapon pistol = new Weapon( new BulletProjectileFactory( 8.0f, 12, "bullet.png") );
The fire()
method of your weapon-class would then do something like
projectileFactory.createProjectile();
-
Thankyou! That's a good option. I'm missing something here though: with such a Factory class, how would I change physics/hit effects. There isn't a way to pass a method into such a Factory, is there?FiveThree– FiveThree2016年04月25日 09:49:35 +00:00Commented Apr 25, 2016 at 9:49
-
@FiveThree Since Java 8 you actually can treat methods like variables and pass them around. But that's really just syntactical sugar for something which was already possible before by having classes which implement an interface with just a single method. So you could also add another
HitEffect
class which you pass to the factory which then in turn passes it to all projectiles it generates.Philipp– Philipp2016年04月25日 10:39:30 +00:00Commented Apr 25, 2016 at 10:39 -
1Since you're using C#, you could probably make the Weapon constructor take an
Action<Projectile>
. But there's really nothing wrong with taking a more specific object.Magus– Magus2016年04月26日 15:26:03 +00:00Commented Apr 26, 2016 at 15:26 -
1@FiveThree Sorry, I haven't noticed that this is C#, not Java. In C# you have delegates to pass around methods. As Magus said, the generics Action and Func from the .NET framework cover most use-cases pretty well, so there is rarely a reason to write your own delegate types.Philipp– Philipp2016年04月26日 15:37:45 +00:00Commented Apr 26, 2016 at 15:37
Explore related questions
See similar questions with these tags.
ProjectileData.Bullet
class.item.projectileType = typeof(ProjectileData.Bullet)
andCreateProjectile<item.projectileType>(..)
doesn't work).