• Advertisement

Gameplay Creating a Weapon System Allowing Easy Implementation of Unique Effects

Recommended Posts

Hey,

So I'm currently working on a rogue-like top-down game that features melee combat. Getting basic weapon stats like power, weight, and range is not a problem. I am, however, having a problem with coming up with a flexible and dynamic system to allow me to quickly create unique effects for the weapons. I want to essentially create a sort of API that is called when appropriate and gives whatever information is necessary (For example, I could opt to use methods called OnPlayerHit() or IfPlayerBleeding() to implement behavior for each weapon). The issue is, I've never actually made a system as flexible as this.

My current idea is to make a base abstract weapon class, and then have calls to all the methods when appropriate in there (OnPlayerHit() would be called whenever the player's health is subtracted from, for example). This would involve creating a sub-class for every weapon type and overriding each method to make sure the behavior works appropriately. This does not feel very efficient or clean at all. I was thinking of using interfaces to allow for the implementation of whatever "event" is needed (such as having an interface for OnPlayerAttack(), which would force the creation of a method that is called whenever the player attacks something).

 

Here's a couple unique weapon ideas I have:

Explosion sword: Create explosion in attack direction.

Cold sword: Chance to freeze enemies when they are hit.

Electric sword: On attack, electricity chains damage to nearby enemies.

 

I'm basically trying to create a sort of API that'll allow me to easily inherit from a base weapon class and add additional behaviors somehow. One thing to know is that I'm on Unity, and swapping the weapon object's weapon component whenever the weapon changes is not at all a good idea. I need some way to contain all this varying data in one Unity component that can contain a Weapon field to hold all this data. Any ideas?

 

I'm currently considering having a WeaponController class that can contain a Weapon class, which calls all the methods I use to create unique effects in the weapon (Such as OnPlayerAttack()) when appropriate.

Edited by Ovicior
Grammar.

Share this post


Link to post
Share on other sites
Advertisement

One might consider breaking the problem down a bit further. What defines an attack? Going only by your description, it appears to be comprised of target selection (i.e. chains to nearby enemies, directional), a visual/audio representation (i.e. explosion, lightning), and a status effect (i.e. bleeding, on fire, electrified) to those targets.

So I'd probably design this as non-inherited Weapon class, which is configured with instances of 3 separate class hierarchies: a TargetSelector, an AudioVisualAttackRepresentation, and a TargetStatusApplier (not optimal class naming, but you get the idea).

You could implement this as a single class hierarchy (as you suggest), but I'd imagine that quite a few weapons will want to share similar implementations of the functionality I've broken out... Composition will make that easier than a single class hierarchy.

Share this post


Link to post
Share on other sites
3 hours ago, swiftcoder said:

One might consider breaking the problem down a bit further. What defines an attack? Going only by your description, it appears to be comprised of target selection (i.e. chains to nearby enemies, directional), a visual/audio representation (i.e. explosion, lightning), and a status effect (i.e. bleeding, on fire, electrified) to those targets.

So I'd probably design this as non-inherited Weapon class, which is configured with instances of 3 separate class hierarchies: a TargetSelector, an AudioVisualAttackRepresentation, and a TargetStatusApplier (not optimal class naming, but you get the idea).

You could implement this as a single class hierarchy (as you suggest), but I'd imagine that quite a few weapons will want to share similar implementations of the functionality I've broken out... Composition will make that easier than a single class hierarchy.

An attack is just really whenever the player left clicks, at which point a prefab with a collider that checks for enemies inside itself is instantiated at whatever angle the player is facing. The visual representation is a slash effect. I'd like to think that I'd instantiate a prefab for something like an explosion and have some sort of lightning prefab that can take gameobjects as parameters to chain between. 

 

My apologies, but I still don't quite understand how I'd use composition in this way. Wouldn't it be easier to have a normal Weapon component that handles most calculations, with unique Components for each weapon that use the Weapon component to do their behavior?

 

I'm not too familiar with writing quality code, I've mostly been trying to learn how to make stuff work over the past four years.

Share this post


Link to post
Share on other sites
1 hour ago, Ovicior said:

Wouldn't it be easier to have a normal Weapon component that handles most calculations, with unique Components for each weapon that use the Weapon component to do their behavior?

Its really a question of what quantity of weapons you plan on having in the game. If you only plan to have 3 weapon types, and they all basically work the same way, then by all means, code them in one place.

If on the other hand you plan to have a hundred different types of weapon, and many of them function differently to one another, then you'll probably want to factor out the commonalities in some way that reduces the amount of code you have to write.

Share this post


Link to post
Share on other sites

You are probably overdesigning. (As often happen with oop).

Just assign a "effect type" to your weapon, and switch on that type to handle the sword effect.

 

switch( weapon->type)

{

    case Weapon_FireDamage:

  { ... } break;

   case Weapon_SpecialEffectFoo:

   { ...} break;

}

 

Probably you won't ever have the need of something more complicated than this. (And you can always do fancy stuff like compressing common parts, parametrize them, ecc)

 

Leonardo

Share this post


Link to post
Share on other sites
5 hours ago, swiftcoder said:

Its really a question of what quantity of weapons you plan on having in the game. If you only plan to have 3 weapon types, and they all basically work the same way, then by all means, code them in one place.

If on the other hand you plan to have a hundred different types of weapon, and many of them function differently to one another, then you'll probably want to factor out the commonalities in some way that reduces the amount of code you have to write.

I plan on having close to 100 weapons. Many will feature some sort of unique effect. I don't quite completely understand how "TargetSelector, an AudioVisualAttackRepresentation, and a TargetStatusApplier" would all work together. A target selector doesn't seem too necessary considering only the lightning sword will chain as of now. Having something to create the proper "streak" or "smear" animation is good, and having something apply the effect for each weapon seems pretty good as well. Would the 'TargetStatusApplier' also be used for something immediate, like stealing an enemy's health? Or would it only be for longer-term statuses like burning/frozen.

Share this post


Link to post
Share on other sites
8 hours ago, Ovicior said:

I don't quite completely understand how "TargetSelector, an AudioVisualAttackRepresentation, and a TargetStatusApplier" would all work together. A target selector doesn't seem too necessary considering only the lightning sword will chain as of now.

That's just an example breakdown I extrapolated from the example you described. It sounds like your targeting isn't as complex as I had assumed from the chain lightning example - it's not uncommon for games to have a lot of complex behaviour in this area, such as weapons that deal damage in a cone vs line vs arc, piercing through to enemies behind vs not, chaining vs not, and so on...

8 hours ago, Ovicior said:

Would the 'TargetStatusApplier' also be used for something immediate, like stealing an enemy's health? Or would it only be for longer-term statuses like burning/frozen.

Both, most likely. In the simplest form, it's just an interface with a single method, applyStatusTo(Target), and implementors can choose to apply long term status effects, or just apply damage directly.

Share this post


Link to post
Share on other sites

My implementation would be like what was done in Final Fantasy VII: Divide effects into a few broad groups (as you did with cold, electric, and explosion swords) and then define more detailed properties inside each group that weapons can have.

I would use inheritance to implement the broad groups, as you can’t say how much they would have in common in terms of functionality or properties, and then use a data-driven model for the details inside each group.

You can imagine all the attacks and effects in Final Fantasy VII.  Whether simple sparks fly or a huge monster with a camera and scene animation comes could be handled by inheritance as broad groups that categorize the types of effects you want to implement.

Then which sparks are shown or which monster is shown can be driven via data.

You get a compromise between a data-driven approach and inheritance that should make even large numbers of attacks manageable.


L. Spiro

Share this post


Link to post
Share on other sites

Check out Brian Bucklew's use of an ECS in Caves Of Qud, he solved exactly the probem you're describing with his approach and has done a couple of presentations about it.

 

Share this post


Link to post
Share on other sites
4 hours ago, DerekB said:

Check out Brian Bucklew's use of an ECS in Caves Of Qud, he solved exactly the probem you're describing with his approach and has done a couple of presentations about it.

 

Thanks! This presentation is useful. I'll definitely keep it in mind when designing my system.

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


  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By owenjr
      Hi there.
      I'm pretty new to this and I don't know if it has been asked before, but here I go.
      I'm developing a game using SFML and C++.
      I would like to use the "Tiled" tool to load maps into my game but I don't actually find any tutorial or guide on how to exaclty use it (I know that I have to read an XML file and stuff). I just step into diverse projects that make all a mess. 
      Anyone knows where can I find good information to make my map loader by myself?
      Thanks in advantage!!
    • By GhostarWhite7
      Today again I painted the next drawing. I look at him and I understand that something is wrong in him. Can problems with the prospect or with black and white or with the composition or is everything terrible? help me figure it out, help.. My english is not very well, i'm from russia and i want to draw for game

    • By MHG OstryTM
      Hello guys,
      I've released my game for the first time. I'm very excited about it and I hope you'll enjoy the game - Beer Ranger. It's a retro-like puzzle-platfromer which makes you think a lot or die trying. You have a squad of skilled dwarfs with special powers and your goal is tasty beer. There is a lot of traps as well as many solutions how to endure them - it is up to your choice how to complete the level! 
      Link to the project: Project site
      Link to the Steam site with video: Beer Ranger
      Have fun and please write feedback if you feel up to.
      Some screens: 




    • By Manuel Berger
      Hello fellow devs!
      Once again I started working on an 2D adventure game and right now I'm doing the character-movement/animation. I'm not a big math guy and I was happy about my solution, but soon I realized that it's flawed.
      My player has 5 walking-animations, mirrored for the left side: up, upright, right, downright, down. With the atan2 function I get the angle between player and destination. To get an index from 0 to 4, I divide PI by 5 and see how many times it goes into the player-destination angle.

      In Pseudo-Code:
      angle = atan2(destination.x - player.x, destination.y - player.y) //swapped y and x to get mirrored angle around the y axis
      index = (int) (angle / (PI / 5));
      PlayAnimation(index); //0 = up, 1 = up_right, 2 = right, 3 = down_right, 4 = down

      Besides the fact that when angle is equal to PI it produces an index of 5, this works like a charm. Or at least I thought so at first. When I tested it, I realized that the up and down animation is playing more often than the others, which is pretty logical, since they have double the angle.

      What I'm trying to achieve is something like this, but with equal angles, so that up and down has the same range as all other directions.

      I can't get my head around it. Any suggestions? Is the whole approach doomed?

      Thank you in advance for any input!
       
  • Advertisement