packetpirate
Senior Newbie 
|
 |
«
Posted
2012-12-05 20:06:25 » |
|
I'm working on a simple game in Java, and I've hit a bit of a roadblock. I don't know anything about scripting, such as using LUA, so I'm trying to think of a way to handle this. I need to add different weapons to my game, but as far as the weapon class goes, I need to make it flexible enough to handle any type of weapon... so what I was thinking of doing is to make a simple class with some general parameters, and then make an interface for it to implement that will have the functions that need to be specific.
From there, I was hoping I could create an enumerator containing anonymous inner classes. This way, I could create a separate file with mappings of IDs like "FLAMETHROWER" to an anonymous inner class where I could hard-code the effects that those weapons would display. Is this possible? If so, how could I do this?
If this isn't possible / a good idea, what would you recommend? I can provide a link to the project on Github if you need to see the code.
|
|
|
|
|
Regenuluz
|
 |
«
Reply #1 - Posted
2012-12-05 20:15:10 » |
|
Why not just go with the interface you suggested yourself, and then make classes for each weapon you want(which of course implement the weapon interface)?
Seems like a simpler approach, than trying to write an enum with anonymous inner classes. ^^
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #2 - Posted
2012-12-05 20:16:54 » |
|
Because I want something elegant that doesn't require writing a different class for each type of weapon. I know the alternative would be easier, but I want something customizable. Eventually, I might add the ability to script your own weapons if I can figure out how.
|
|
|
|
|
Games published by our own members! Check 'em out!
|
|
sproingie
|
 |
«
Reply #3 - Posted
2012-12-05 20:18:49 » |
|
If you're looking for an object model that's expandable at runtime, e.g. through a script, you don't want to restrict the possible instances by assigning them to enums. All the instances of an enum have to be declared up front, and the enum class can't be subclassed or otherwise instantiated.
Enums are more for things that aren't going to change at runtime: if you only ever deal with four compass directions for example, it makes sense to stick them in an enum (NORTH,SOUTH,EAST,WEST), since new directions aren't going to be invented anytime soon. But if you're making a scriptable game, chances are you're not going to anticipate every instance of every weapon, in which case you're probably looking for a Map<String,Weapon> instead.
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #4 - Posted
2012-12-05 20:22:55 » |
|
Scripting is a POSSIBLE feature for the future. Right now, I'm just adding a few different weapons that will be defined at compile time, so an enum is fine... I'm just asking if it's possible to do it the way I described, and if so, how?
If anyone has a link to a tutorial for scripting in the way I described, I'd be glad to read it.
|
|
|
|
|
sproingie
|
 |
«
Reply #5 - Posted
2012-12-05 20:30:01 » |
|
If you're defining all your weapons at compile-time, you could certainly go with making them enums. An Enum is a class like any other, it can have methods and fields -- the latter you'd typically set through the Enum's constructor.
As for scripting, if Lua is your bag, check out JNLua, which has its own scripting interface as well as a JSR223-compliant one. For other languages, check out javax.script and google for "JSR223 languages"
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #6 - Posted
2012-12-05 21:27:13 » |
|
So can you show me an example of how I might attribute an ID to an anonymous inner class in an enumerator?
|
|
|
|
|
sproingie
|
 |
«
Reply #7 - Posted
2012-12-05 22:20:10 » |
|
You can't make anonymous enum instances. Why do you feel you need to use anonymous inner classes here? Can you describe your design in terms of what you're actually trying to do instead of the code you want to use?
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #8 - Posted
2012-12-05 22:27:42 » |
|
Say I have an interface for a weapon, and I want to be able to use that to define any type of weapon, not just a simple one projectile weapon. For example, if I want to define behaviors for how the projectiles act, or even what kinds of projectiles the weapon fires. I want to have an enum of defined weapon types, such as flamethrower or machine gun or shotgun, so that when I select that weapon, the program will use that behavior for the weapon.
The only problem is I don't know how to create an enum that refers to these kinds of things.
Also, there's the problem that I need to be able to define the weapon's behavior very generally so I can just call this function when the weapon "fires" and it will perform the necessary functions to handle the weapon's projectiles and graphical behavior.
|
|
|
|
|
Jimmt
|
 |
«
Reply #9 - Posted
2012-12-06 05:01:43 » |
|
So...still not getting why you have to use an enum. Do you just want a "type" of weapon behavior? If so a class should still be fine.
|
|
|
|
|
Games published by our own members! Check 'em out!
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #10 - Posted
2012-12-06 05:26:27 » |
|
Because the behavior of the functions for each weapon would need to be different, hence, anonymous inner classes, where I can rewrite the functions for the weapon for each weapon.
|
|
|
|
|
Jimmt
|
 |
«
Reply #11 - Posted
2012-12-06 05:32:25 » |
|
That's bad design in my book, having everything in one file. Can you not rewrite functions in a normal class too? Not to mention that it is much more easily reused.
|
|
|
|
|
sproingie
|
 |
«
Reply #12 - Posted
2012-12-06 05:57:52 » |
|
Because the behavior of the functions for each weapon would need to be different, hence, anonymous inner classes, where I can rewrite the functions for the weapon for each weapon.
This conclusion of "hence, anonymous inner classes" does not follow. You can determine different behaviors in a data-driven way, by changing the parameters of the behaviors in fields and keeping the hierarchy flat, or you can subclass and override. I don't see a really compelling use case here for anonymous inner classes or enums. It looks to me like you're fixating on some fairly advanced features of OO design before you have a firm grasp on the basics of polymorphism. For your initial design, just use plain old classes and write lots of subclasses, then see what you can make declarative and data-driven with fields instead of overrides. You need neither enums nor anonymous instances to make this happen. To make this advice less abstract, start with "class Flamethrower extends Weapon", then once you have several weapons under your belt, figure out what aspects are varying across the subclasses and what's invariant, after which you can move to something like "Weapon flamethrower = new Weapon(DamageType.FIRE, RangeType.RANGED, ...etc...)" Start with the simplest thing that actually works, then as you need more flexibility, start abstracting things.
|
|
|
|
|
masteryoom
|
 |
«
Reply #13 - Posted
2012-12-06 07:16:01 » |
|
You could use an .properties file to import the weapons script into the game eg. for flamethrower: Weapon Name: FLAMETHROWER Weapon Type: FIRE Weapon Damage: x Weapon Reload: y Weapon Range: RANGED You could do it like that (in the .properties file  ). P.S. The x and y are your variables for the weapons (Reload might not be applicable  )
|
|
|
|
cylab
|
 |
«
Reply #14 - Posted
2012-12-06 10:00:20 » |
|
You can't assign derived instances to enum constants, just pass parameters to the constructor. If you design your weapon class and it's interaction with the game carefully, this should be all you need. What you are asking for is only achievable using the "old" static constants pattern: 1 2 3 4 5 6 7 8 9 10 11 12 13
| class Weapon { public static Weapon SHOTGUN=new Weapon(){ (...) }; public static Weapon RIFLE=new Weapon(){ (...) }; public static Weapon FLAMETHROWER=new Weapon(){ (...) }; etc. } |
Edit: stand corrected... actually I should have read the language specification before making a fool of myself: http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.2 -> Example 8.9.2-4. Enum Constants with Class Bodies
|
Mathias - I Know What [you] Did Last Summer!
|
|
|
Roquen
|
 |
«
Reply #15 - Posted
2012-12-06 10:09:12 » |
|
As opposed to? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| public enum Weapon { SHOTGUN { (...) }, RIFLE { (...) }, FLAMETHROWER { (...) },
(etc) ; } |
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #16 - Posted
2012-12-06 15:06:08 » |
|
Ok, nobody seems to be following me here, so here's a code example. Since you've told me I can't bind an enum ID to an anonymous inner class the way I wanted, this is just to demonstrate what I meant. 1 2 3 4
| public interface Weapon { public void update(); public void draw(Graphics2D g2d); } |
1 2 3 4 5 6 7 8 9 10 11 12
| public class WeaponObj implements Weapon { @Override public void update() { } @Override public void draw(Graphics2D g2d) { } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| public enum WeaponType { FLAMETHROWER = new WeaponObj() { @Override public void update() { } @Override public void draw(Graphics g2d) { } }; ROCKET_LAUNCHER = new WeaponObj() { @Override public void update() { } @Override public void draw(Graphics g2d) { } }; } |
Now do you see what I mean by "different behavior"? That's not something you can do with simple parameters. Or rather, it would be unnecessarily complicated.
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #17 - Posted
2012-12-06 15:12:33 » |
|
You could use an .properties file to import the weapons script into the game eg. for flamethrower: Weapon Name: FLAMETHROWER Weapon Type: FIRE Weapon Damage: x Weapon Reload: y Weapon Range: RANGED You could do it like that (in the .properties file  ). P.S. The x and y are your variables for the weapons (Reload might not be applicable  ) No I couldn't. I'm not just talking about different parameters. Each weapon would have to have a different update method. What if one weapon just shoots simple projectiles, another is a spray weapon, and another explodes and creates more particles that shoot outward when it reaches its destination? If it helps, I also need to figure out how to create a spell system for a game with magic in the future, if that's any indication as to the level of "customization" I need with each of these weapons.
|
|
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #19 - Posted
2012-12-06 15:48:42 » |
|
But that's not an example of different behaviors... that was an example of the same behavior and the class being designed to do the same thing but with different parameters. What I'm trying to do is create a different method to handle what the weapon actually does for each weapon object. This way, I can make a flamethrower create a spray of particles, whereas a machine gun would just shoot bullets really fast, or a napalm gun would fire a projectile that when it hits its target, small flame particles spread out around the impact site and burn for a short time, doing damage to any that touch it, before extinguishing.
|
|
|
|
|
PaulCunningham
|
 |
«
Reply #20 - Posted
2012-12-06 15:48:49 » |
|
I'm working on a simple game in Java...
So make a simple weapon system. *Disclaimer* I'm no Java guy but I'd do... IWeapon { Some behaviours here like shoot or load, etc } Weapon : IWeapon { Some common functions for all weapons //virtual shoot() : spawn a simple bullet based on some data file (speed, effect, sound, damage) } //Weapons are data driven standardWeapon = new Weapon(DATA FOR THE WEAPON) flamerWeapon = new Weapon(DATA FOR THE WEAPON) //Only need a sub class when BEHAVIOUR is different ShotgunWeapon : Weapon { //Override shoot() to spawn x many bullets in an arc - randomise pellet speed } Something::setWeapon(IWeapon newWeapon) { etc }
|
|
|
|
|
Roquen
|
 |
«
Reply #21 - Posted
2012-12-06 16:09:42 » |
|
But that's not an example of different behaviors... that was an example of the same behavior and the class being designed to do the same thing but with different parameters.
Ah, but it is. Parametrizing a single effect type was simply an example.
|
|
|
|
|
saifix
Senior Newbie  Medals: 1
|
 |
«
Reply #22 - Posted
2012-12-06 16:12:44 » |
|
If I understand correctly, you want to be able to define various types of weapons and new behaviors for them at runtime? If so you could do something like below. 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
| interface Weapon { void fire(...); void reload(...); }
class DefaultWeapon implements Weapon { private final WeaponMetaData meta;
public DefaultWeapon(WeaponMetaData data ) { this.meta = data; }
void fire(...) { } void reload(...) { } }
class FlamethrowerWeaponImpl extends DefaultWeapon { public FlamethrowerWeaponImpl(WeaponMetaData meta) { super(meta); }
@Override void fire(...) { } } |
This way you can create specialized implementations for weapons that don't follow the standard "spawn an accelerated particle" behavior. 1 2 3
| static Weapon PISTOL = new DefaultWeapon(pistolMetaData); static Weapon RIFLE = new DefaultWeapon(rifleMetaData); static Weapon FLAMETHROWER = new FlamethrowerWeaponImpl(flamethrowerMetaData); |
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #23 - Posted
2012-12-06 16:44:38 » |
|
If I understand correctly, you want to be able to define various types of weapons and new behaviors for them at runtime? If so you could do something like below. 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
| interface Weapon { void fire(...); void reload(...); }
class DefaultWeapon implements Weapon { private final WeaponMetaData meta;
public DefaultWeapon(WeaponMetaData data ) { this.meta = data; }
void fire(...) { } void reload(...) { } }
class FlamethrowerWeaponImpl extends DefaultWeapon { public FlamethrowerWeaponImpl(WeaponMetaData meta) { super(meta); }
@Override void fire(...) { } } |
This way you can create specialized implementations for weapons that don't follow the standard "spawn an accelerated particle" behavior. 1 2 3
| static Weapon PISTOL = new DefaultWeapon(pistolMetaData); static Weapon RIFLE = new DefaultWeapon(rifleMetaData); static Weapon FLAMETHROWER = new FlamethrowerWeaponImpl(flamethrowerMetaData); |
Well at least you get it... but the whole point of this was I don't want to have to create 20 different classes for 20 different weapon types. Meanwhile, everyone else still thinks I mean I want different parameters to define damage, speed, etc...
|
|
|
|
|
saifix
Senior Newbie  Medals: 1
|
 |
«
Reply #24 - Posted
2012-12-06 16:51:58 » |
|
If I understand correctly, you want to be able to define various types of weapons and new behaviors for them at runtime? If so you could do something like below. 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
| interface Weapon { void fire(...); void reload(...); }
class DefaultWeapon implements Weapon { private final WeaponMetaData meta;
public DefaultWeapon(WeaponMetaData data ) { this.meta = data; }
void fire(...) { } void reload(...) { } }
class FlamethrowerWeaponImpl extends DefaultWeapon { public FlamethrowerWeaponImpl(WeaponMetaData meta) { super(meta); }
@Override void fire(...) { } } |
This way you can create specialized implementations for weapons that don't follow the standard "spawn an accelerated particle" behavior. 1 2 3
| static Weapon PISTOL = new DefaultWeapon(pistolMetaData); static Weapon RIFLE = new DefaultWeapon(rifleMetaData); static Weapon FLAMETHROWER = new FlamethrowerWeaponImpl(flamethrowerMetaData); |
Well at least you get it... but the whole point of this was I don't want to have to create 20 different classes for 20 different weapon types. Meanwhile, everyone else still thinks I mean I want different parameters to define damage, speed, etc... The only cases which you would need to define a different class is if you need a weapon which implements non-standard behavior (standard defined as whatever is in DefaultWeapon.) What the others were saying is that if you feed the default implementation enough data then you won't need to create specialized implementations. For example, I have a class named DefaultWeapon which fires a single shot and a specialized implementation named SpreadShotWeapon. I can eliminate the need for SpreadShotWeapon type if I introduce three new parameters: angle, particle count and shot type.
|
|
|
|
|
PaulCunningham
|
 |
«
Reply #25 - Posted
2012-12-06 16:52:03 » |
|
Well at least you get it... but the whole point of this was I don't want to have to create 20 different classes for 20 different weapon types. Meanwhile, everyone else still thinks I mean I want different parameters to define damage, speed, etc...
You don't have to create 20 different classes - you only create a NEW CLASS when you need BEHAVIOUR that is different.
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #26 - Posted
2012-12-06 17:12:35 » |
|
Well at least you get it... but the whole point of this was I don't want to have to create 20 different classes for 20 different weapon types. Meanwhile, everyone else still thinks I mean I want different parameters to define damage, speed, etc...
You don't have to create 20 different classes - you only create a NEW CLASS when you need BEHAVIOUR that is different. Right, but the amount of classes I'll need is equivalent to the number of uniquely different weapons, which is a lot, considering the behavior of a machine gun, flamethrower, rocket launcher, and shotgun are all different. Besides... how do you know how many different weapon types I'll have?
|
|
|
|
|
Icecore
|
 |
«
Reply #27 - Posted
2012-12-06 17:15:56 » |
|
Try do components object : (crazy and flexible ^^) 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
| class Bullet_Dmg implements Bulet_Procces { int Dmg; public Bullet_Dmg(int dmg){ Dmg = dmg; } @Override public void update(){ if(bulet hit do damage) } public Bullet_Dmg set_Dmg(int dmg){Dmg = dmg;return this;} } class Bullet_Heal implements Bulet_Procces {} class Bullet_Time_Explode implements Bulet_Procces {} class Weapon_Pistrol_Graphics implements Weapon_Graphics { @Override public void draw(Graphics g2d) { } } class WeaponObj{ Bulet_Procces proc; Weapon_Graphics graph; public WeaponObj(Bulet_Procces Proc, Weapon_Graphics Gra(){ proc = Proc; graph = Gra; } public void draw(Graphics g2d){ graph.draw(g2d); } public void update(){ proc.update(); } public WeaponObj set_New_Proc(Bulet_Procces Proc){proc = Proc; return this;} } Bullet_Dmg pistol_Bullet = new Bullet_Dmg(10); Weapon_Pistrol_Graphics pistol_GR = new Weapon_Pistrol_Graphics(); WeaponObj pistol = new WeaponObj(pistol_Bullet, pistol_GR); Bullet_Heal pistol_Bullet_2 = new Bullet_Heal(30); pistol.set_New_Proc(pistol_Bullet_2);
|
|
|
|
|
|
PaulCunningham
|
 |
«
Reply #28 - Posted
2012-12-06 17:20:06 » |
|
Right, but the amount of classes I'll need is equivalent to the number of uniquely different weapons, which is a lot, considering the behavior of a machine gun, flamethrower, rocket launcher, and shotgun are all different.
Not necessarily. If the standard weapon behaviour is to fire (a) number of (b) projectiles, in an arc from -(c) to +(c) radians with a reload factor of (d) milliseconds then they'd all have the same BEHAVIOUR wouldn't they. But your data would be different - that is the point.
|
|
|
|
|
packetpirate
Senior Newbie 
|
 |
«
Reply #29 - Posted
2012-12-06 17:21:14 » |
|
I already know HOW to make an anonymous inner class to implement the weapons the way I want... the only reason I asked this was to determine if I could somehow put the declarations for these in a separate file and be able to just import them and use an ID to refer to the object without cluttering up my main code.
|
|
|
|
|
|