Java-Gaming.org    
Featured games (79)
games approved by the League of Dukes
Games in Showcase (477)
Games in Android Showcase (109)
games submitted by our members
Games in WIP (536)
games currently in development
News: Read the Java Gaming Resources, or peek at the official Java tutorials
 
    Home     Help   Search   Login   Register   
Pages: [1]
  ignore  |  Print  
  RPG Style Weapons + Upgrades + Player Stat Upgrades  (Read 4729 times)
0 Members and 1 Guest are viewing this topic.
Offline MunchGamer

Senior Newbie


Medals: 1



« Posted 2012-02-06 05:36:42 »

Hey all,

Developing a big RPG style inventory system.  Currently it's organized with class hierarchy:

Inventory (contains items, hotbar for quickselect, etc)

Item
->Weapon
   ->MeleeWeapon
   ->RangedWeapon
      ->Pistol
      ->Shotgun


etc...

So here's what's on my mind-grapes:

If a weapon can be upgraded (ex. purchase silencer for Beretta 9mm) through purchase of upgrades, and also 'upgraded' through player skill trees (ex. '+10% accuracy with pistols'), I was thinking that it might be best, on creation of the item, to poll the player for their skills and adjust the attributes accordingly and then to have an instance reference of a 'WeaponUpgrade' class which holds the internal (and importantly, specific to that instance of that weapon) upgrades, also adjusting the attributes.

Thoughts on this design implementation?
Offline GabrielBailey74
« Reply #1 - Posted 2012-02-06 05:49:34 »

You could create one class in example the RangedWeapons package/folder that has a sub class that handles each weapon/upgrades/bonuses.

Or you could in that RangedWeapons package create multiple classes 1 for each weapon.
Explain a bit more on what you're trying to do please?

Offline MunchGamer

Senior Newbie


Medals: 1



« Reply #2 - Posted 2012-02-06 06:00:45 »

The individual weapons are implemented already ie Beretta9mm extends Pistol, which extends RangedWeapon, so on and so forth back up to Item.  The reason for this architecture is to allow a player to have any sort of item, be it a Pistol or a Potion, in their hot bar, and use it by clicking.

The question, or rather more of a implementation proposal since everyone does things their own way, is that I'm suggesting within the class Weapon:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
public abstract class Weapon extends Item {
   protected double damage;
   protected double knockback;
   protected double speed;   //time (in seconds) for a full attack.
  protected double atkTime;
   
   protected double accuracy; //lower is more accurate
  protected double accuracyModifier;
        // etc.. with other attributes, plus:
       protected WeaponUpgrade upgrade;


And when the player stops in at the upgrade shop / other gameplay contrivance, the WeaponUpgrade is retrieved from the weapon, an attribute of it is modified, ex:

1  
2  
3  
public void setAccuracyBonus(double d){
        this.accuracyBonus += d;
}


and off the player goes, now with a more accurate, reliable weapon. 

When the accuracy (or damage, or knockback, or other attribute) of the weapon then needs to be retrieved, it can be grabbed as some calculation performed on:
1. the weapon's base attribute
2. modifiers provided by specific upgrades to that instance of the weapon
3. the player's global benefits for weapons of that class (ie pistols)

If anything, I guess I'm asking if this seems like a reasonable way to go about doing things, or if there's some glaring oversight I'm making.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline GabrielBailey74
« Reply #3 - Posted 2012-02-06 06:07:22 »

That's what i'd do, declare all the various upgrade/statistics variables of the UpgradeClass, than when a upgrade is clicked in the shop, set all the variables accordingly to the current level, and set the bonuses++ accordingly to the current upgrade bieng purchased.

Offline loom_weaver

JGO Coder


Medals: 17



« Reply #4 - Posted 2012-02-06 06:28:23 »

Look for postings by Ray aka Bear in this thread:
http://groups.google.com/group/rec.games.roguelike.development/browse_thread/thread/68850017f706a5db

His post itemizes many things that you might want to consider for your item framework.

The general consensus is that class hierarchies are too restrictive when designing RPG entities.  For example if you have a gun with a bayonet on it how will it fit into your hierarchy?  I would recommend some kind of very flat framework or component-based system aka composition to give you the needed flexibility.
Offline theagentd
« Reply #5 - Posted 2012-02-06 13:01:57 »

I think it would be "cleaner" to keep weapons and player skill upgrades clearly separated. I'd not have any player skill related variables in my Weapon class, and instead pass the PlayerSkills/UpgradeClass (whatever you call it xd) to the Weapon each fire()/update().

Myomyomyo.
Offline MunchGamer

Senior Newbie


Medals: 1



« Reply #6 - Posted 2012-02-06 17:44:11 »

I think it would be "cleaner" to keep weapons and player skill upgrades clearly separated. I'd not have any player skill related variables in my Weapon class, and instead pass the PlayerSkills/UpgradeClass (whatever you call it xd) to the Weapon each fire()/update().

Right.  The idea is that the Player Skills and Upgrades are 2 separate ideas.  IE:

1  
2  
3  
4  
5  
6  
7  
8  
public void dealDamage(Sprite theOneGettingOwned){
    int dmg = 0;
    dmg += this.damage; //base weapon damage
   dmg *= this.upgrade.getDamageBonus(); //damage bonus from weapon upgrades
   dmg *= this.getOwner().getDamageBonus(this); //retrieve damage bonus from player for this weapon class

    theOneGettingOwned.receiveDamage(dmg);
}
Offline sproingie

JGO Kernel


Medals: 202



« Reply #7 - Posted 2012-02-06 20:27:06 »

What everyone else has been saying: the less mutation of state you do the better.  Wielding a weapon shouldn't modify a "damage" variable on the player, it should simply be included in a "calculateDamage()" method.  RPGs can involve dozens of variables for calculating stats, but it's something even the weakest computer nowadays will do in microseconds.  

If you want to be fancy, then even an old standby like "hit points" is something you might want to calculate by keeping a list of individual wounds with their respective HP penalty, rather than just decrementing a variable.  Then when a player applies the "first aid" skill, you can limit it to removing only wounds that his skill is sufficient to treat.  Of course, if your game models a player's health by way of a life bar, then by no means indulge in design overkill like that.  Your code design should reflect the game you want
Offline Roquen
« Reply #8 - Posted 2012-02-06 21:09:02 »

I just said something like this in a previous thread.  What's the difference between two ranged weapon?  Some data...so you could skip on subclassing RangedWeapon.  What's the difference between a MeleeWeapon and a RangedWepon?  Some data...so you could skip on subclass Weapon.  The point to stop with this kind of thinking is (roughly) when a parent and child require different state data.
Offline MunchGamer

Senior Newbie


Medals: 1



« Reply #9 - Posted 2012-02-06 22:11:06 »

I just said something like this in a previous thread.  What's the difference between two ranged weapon?  Some data...so you could skip on subclassing RangedWeapon.  What's the difference between a MeleeWeapon and a RangedWepon?  Some data...so you could skip on subclass Weapon.  The point to stop with this kind of thinking is (roughly) when a parent and child require different state data.

In my implementation MeleeWeapons and RangedWeapons hold different sorts of data and override methods in different ways, so the subclassing is relevant.
Games published by our own members! Check 'em out!
Legends of Yore - The Casual Retro Roguelike
Offline sproingie

JGO Kernel


Medals: 202



« Reply #10 - Posted 2012-02-07 00:10:35 »

I think he meant that subclasses of RangedWeapon, like LongBow, CrossBow, Sling, etc aren't useful subclasses.  The behaviors of ranged and melee are different enough that they might deserve to be subclasses of Weapon, but individual cases of them aren't really sufficient.

That brings us back to the "gun with a bayonet" problem though, and the answer is pretty simple: it's two weapons.  The identity of a single object shouldn't be confused with the possibly multiple instances that may constitute its behavior.   Similarly a robe with pouches could be armor and a bag.  Rather than trying to fake multiple inheritance, you just accept that one item may actually be a composite of several objects.  

This has implications for where you put unrelated properties like "sale value" and "durability" for example.  The answer there may be you either create a CompositeItem for such chimeras, or you treat Weapon, Armor, and Bag as behaviors attached to Items, not subclasses of Item.  I prefer the behavior angle, but there's probably no single right answer there, it's mostly a matter of what you're most comfortable with and what tradeoffs you're willing to make.

  
Offline Roquen
« Reply #11 - Posted 2012-02-07 14:26:00 »

I think he meant that subclasses of RangedWeapon, like LongBow, CrossBow, Sling, etc aren't useful subclasses.
Yes.  Exactly this.  These things only vary by data.  And remember that "code" can be considered data.  Take a game like the original doom.  All weapons could be used in exactly one way (bound to some input).  The original Unreal?  Each could be exactly used in two ways (by default bound to L&R mouse button).  In the "classic" RPG "Dungeon Master" any item could be placed in the "weapon" hand and by clicking the GUI button the player could choose up to three different attacks depending on the item in question.  In none of these examples does the "type" of weapon or what the kind of attack does effect how it's triggered.  Each just has more or less ways a given item can be used to perform an attack action.

Here's a rough sketch of a possible design direction:

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  
// concrete sub-classes of this deal with what a given attack "does" and the data (not specific to the given item)
// may be stored.
public abstract class OnAttack extends PerhapsSomeBaseActionClass
{
   // there could be some "bookkeeping" method here which deals with higher order logic
  // common to all attacks here, which in turn calls 'exec' or not depending on the
  // overall design.

   public abstract ... exec(Enitity attacker, Item item, ....);
}

public class WeaponArchtypeForSomeGameWhichHasUpToTwoTypesOfAttackPerItem extends Whatever
{
  public OnAttack OnAttack1;
  public OnAttack OnAttack2;
}

public class OnProjectileAttack extends OnAttack
{
   // whatever fields are require to describe some set of projectile attacks

   public ... exec(Enitity attacker, Item item, ....)
   {
       // whatever stuff.
  }
}
Offline MunchGamer

Senior Newbie


Medals: 1



« Reply #12 - Posted 2012-02-07 19:17:14 »

I think he meant that subclasses of RangedWeapon, like LongBow, CrossBow, Sling, etc aren't useful subclasses.  The behaviors of ranged and melee are different enough that they might deserve to be subclasses of Weapon, but individual cases of them aren't really sufficient.

That brings us back to the "gun with a bayonet" problem though, and the answer is pretty simple: it's two weapons.  The identity of a single object shouldn't be confused with the possibly multiple instances that may constitute its behavior.   Similarly a robe with pouches could be armor and a bag.  Rather than trying to fake multiple inheritance, you just accept that one item may actually be a composite of several objects.  

This has implications for where you put unrelated properties like "sale value" and "durability" for example.  The answer there may be you either create a CompositeItem for such chimeras, or you treat Weapon, Armor, and Bag as behaviors attached to Items, not subclasses of Item.  I prefer the behavior angle, but there's probably no single right answer there, it's mostly a matter of what you're most comfortable with and what tradeoffs you're willing to make.

  


So I think what you might be getting at with the data part of things (though I am rather ignoring your confusing Robe example), is that instead of :

1  
2  
3  
4  
5  
6  
7  
8  
public class M16 extends AutomaticRangedWeapon{
    public M16(Sprite owner){
        super(owner);
        this.damage = 3;
        this.accuracy = 10;
        // etc...
   }
}


Something like this might be more appropriate:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
public class AutomaticRangedWeapon{
    public static enum AutoWpnType{
        M16, P90
    }

    public AutomaticRangedWeapon(Sprite owner, AutoWpnType type){
        super(owner);
        switch(AutoWpnType)
            case M16:
                this.damage = 3;
                this.accuracy = 10;
                //etc...
               break;
            case P90:
                this.damage = 2;
                this.accuracy = 15;
                //etc...
               break;
    }
}


[EDIT] to clarify, the reason that the Automatic part is specified is that upon use, it may have different attack behavior than a pistol (automatic fire, etc...) or a shotgun (shotgun may generate 8 attacks for spray).
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #13 - Posted 2012-02-08 04:02:45 »

If you approach this from the opposite direction you start with raw data stored in a common type e.g.:

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
14  
15  
16  
17  
18  
19  
20  
21  
22  
23  
HashMap<String, Object> m16 =
{
  "type" -> gun
  "automatic" -> true
  "damage" -> 16
  "accuracy" -> 10
}

HashMap<String, Object> p90 =
{
  "type" -> gun
  "automatic" -> true
  "damage" -> 2
  "accuracy" -> 15
}

HashMap<String, Object> knife =
{
  "type" -> blade
  "range" -> 1
  "damage" -> 3
  "accuracy" -> 15
}


Then toss these into a List.

Sometimes that's all you'll need and this form has the most amount of flexibility.  If you have odd items you could change "type" -> Set(...).

From there introduce a class hierarchy where it makes sense.  You could design your classes so that they just contain static methods that operate on the raw HashMaps thus decoupling your logic from the data.

Anyways, you avoid introducing classes too early which will only end up restricting you.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #14 - Posted 2012-02-08 04:24:39 »

And here is an upgrade class (pseudocode):

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
class DamageUpgrade {
    static HashMap<String, Object> pimpMyWeapon(HashMap<String, Object> weapon) {
      HashMap<String, Object> modified = new HashMap<String, Object>(weapon);  // some kind of copy constructor
     modified("damage") += 10;
      return modified;  
    }
}

...
beefy_m16 = DamageUpgrade.pimpMyWeapon(m16);


Notice if you construct your class hierarchy properly then you could have a big list of "active upgrades" and then you just daisy chain the calculations to determine the final actual result to use in combat.  You still have access to your original unmodified weapon too (m16).
Offline theagentd
« Reply #15 - Posted 2012-02-08 04:32:13 »

How much you need to complicate things mostly depend on what kind of upgrades that you have. If you want to be able to add and remove "buffs" and modifiers then you'll need to keep track of the base value of the weapon and either compute the value every update or when a weapon's stat modifiers change. This is to avoid rounding errors, obviously assuming you're using floating point variables for stats. I'd strongly recommend doing so though, since a 10% bonus to a 5 damage weapon is still 5 otherwise...

Myomyomyo.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #16 - Posted 2012-02-08 04:48:01 »

How much you need to complicate things mostly depend on what kind of upgrades that you have. If you want to be able to add and remove "buffs" and modifiers then you'll need to keep track of the base value of the weapon and either compute the value every update or when a weapon's stat modifiers change.

Exactly!  With all entities represented as a simple data structure i.e. a HashMap, this becomes really easy.  A damage buff/debuff is stored as a tuple of <String, Integer> e.g. "damage", 10.  Negative numbers are debuffs.

Store a list of them and calculate the final value only when you need it.  Adding a buff to a weapon/item/mobile/anything is easy: just instantiate another tuple and add it to the list.  Expiring buffs are a snap as well: just remove them from the list.
Offline sproingie

JGO Kernel


Medals: 202



« Reply #17 - Posted 2012-02-08 04:57:57 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public class AutomaticRangedWeapon{
    public static enum AutoWpnType{
        M16, P90
    }

    public AutomaticRangedWeapon(Sprite owner, AutoWpnType type){
        super(owner);
        switch(AutoWpnType)
            case M16:
                this.damage = 3;
                this.accuracy = 10;
                //etc...
...


First of all, enums can have fields and constructors, so if you used them to store the stats, you can store them on the enum itself.  However, you probably want to avoid this approach, because all instances of enums are staticly defined (which is largely the point of enums), so you would have to recompile your app to add a new weapon.  What you're going to want eventually is to read in some kind of config, like xml or json or .ini format, that builds a map of weapon definitions.
Offline MunchGamer

Senior Newbie


Medals: 1



« Reply #18 - Posted 2012-02-08 05:01:15 »

1  
2  
3  
4  
5  
6  
7  
8  
9  
10  
11  
12  
13  
public class AutomaticRangedWeapon{
    public static enum AutoWpnType{
        M16, P90
    }

    public AutomaticRangedWeapon(Sprite owner, AutoWpnType type){
        super(owner);
        switch(AutoWpnType)
            case M16:
                this.damage = 3;
                this.accuracy = 10;
                //etc...
...


First of all, enums can have fields and constructors, so if you used them to store the stats, you can store them on the enum itself.  However, you probably want to avoid this approach, because all instances of enums are staticly defined (which is largely the point of enums), so you would have to recompile your app to add a new weapon.  What you're going to want eventually is to read in some kind of config, like xml or json or .ini format, that builds a map of weapon definitions.


Personally I'd prefer keeping it out of config files to prevent users from adding their own weapon definitions, especially for a 'campaign mode' style single player.
Offline sproingie

JGO Kernel


Medals: 202



« Reply #19 - Posted 2012-02-08 05:05:41 »

You can always make java source code the config format, which will effectively freeze the config for whatever mode you're using, but I still wouldn't go as far as hardwiring them into an enum.  Even a shooter will want to support mods.
Offline MunchGamer

Senior Newbie


Medals: 1



« Reply #20 - Posted 2012-02-08 05:21:26 »

I don't think changing a config file to add a new weapon really counts as "modding" IMO Tongue But I do see your point.  Things like NPC (written) dialogue, texture filepaths and other sorts might also belong outside of the code.
Offline theagentd
« Reply #21 - Posted 2012-02-08 10:03:02 »

How much you need to complicate things mostly depend on what kind of upgrades that you have. If you want to be able to add and remove "buffs" and modifiers then you'll need to keep track of the base value of the weapon and either compute the value every update or when a weapon's stat modifiers change.

Exactly!  With all entities represented as a simple data structure i.e. a HashMap, this becomes really easy.  A damage buff/debuff is stored as a tuple of <String, Integer> e.g. "damage", 10.  Negative numbers are debuffs.

Store a list of them and calculate the final value only when you need it.  Adding a buff to a weapon/item/mobile/anything is easy: just instantiate another tuple and add it to the list.  Expiring buffs are a snap as well: just remove them from the list.
Okay, so now you're storing weapons, their modifiers and items in HashMap<String, Object>s. Are you going to store player properties in a HashMap too? Game objects? I'd say you're completely missing the point of object orientation. HashMaps also do not preserve the ordering of objects. This kills determinism for online games, and it might also be good to be able to control in which order for example modifiers are applied, because you'd want a +20% damage bonus to be applied before a +5 flat damage bonus so the % bonus is applied to the flat bonus too. What you're doing is emulating objects with Strings in HashMaps. HashMaps themselves are in my opinion just a glorified emulation of references anyway, so you're emulating objects and keeping them in emulated references. I'd stay far away from that kind of code if I were you... ._.

Myomyomyo.
Offline loom_weaver

JGO Coder


Medals: 17



« Reply #22 - Posted 2012-02-08 19:51:16 »

Okay, so now you're storing weapons, their modifiers and items in HashMap<String, Object>s. Are you going to store player properties in a HashMap too? Game objects? I'd say you're completely missing the point of object orientation. HashMaps also do not preserve the ordering of objects. This kills determinism for online games, and it might also be good to be able to control in which order for example modifiers are applied, because you'd want a +20% damage bonus to be applied before a +5 flat damage bonus so the % bonus is applied to the flat bonus too. What you're doing is emulating objects with Strings in HashMaps. HashMaps themselves are in my opinion just a glorified emulation of references anyway, so you're emulating objects and keeping them in emulated references. I'd stay far away from that kind of code if I were you... ._.

Nah, the statistics are in the HashMap but the modifiers are stored separately e.g. in a List.
Pages: [1]
  ignore  |  Print  
 
 
You cannot reply to this message, because it is very, very old.

 

Add your game by posting it in the WIP section,
or publish it in Showcase.

The first screenshot will be displayed as a thumbnail.

CogWheelz (18 views)
2014-07-30 21:08:39

Riven (26 views)
2014-07-29 18:09:19

Riven (15 views)
2014-07-29 18:08:52

Dwinin (13 views)
2014-07-29 10:59:34

E.R. Fleming (34 views)
2014-07-29 03:07:13

E.R. Fleming (12 views)
2014-07-29 03:06:25

pw (43 views)
2014-07-24 01:59:36

Riven (44 views)
2014-07-23 21:16:32

Riven (30 views)
2014-07-23 21:07:15

Riven (31 views)
2014-07-23 20:56:16
List of Learning Resources
by SilverTiger
2014-07-31 18:29:50

List of Learning Resources
by SilverTiger
2014-07-31 18:26:06

List of Learning Resources
by SilverTiger
2014-07-31 13:54:12

HotSpot Options
by dleskov
2014-07-08 03:59:08

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:58:24

Java and Game Development Tutorials
by SwordsMiner
2014-06-14 00:47:22

How do I start Java Game Development?
by ra4king
2014-05-17 11:13:37

HotSpot Options
by Roquen
2014-05-15 09:59:54
java-gaming.org is not responsible for the content posted by its members, including references to external websites, and other references that may or may not have a relation with our primarily gaming and game production oriented community. inquiries and complaints can be sent via email to the info‑account of the company managing the website of java‑gaming.org
Powered by MySQL Powered by PHP Powered by SMF 1.1.18 | SMF © 2013, Simple Machines | Managed by Enhanced Four Valid XHTML 1.0! Valid CSS!