Jump to content
  • Advertisement
Sign in to follow this  
menyo

Dynamic objects and copies?

This topic is 911 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I have created a very dynamic and versatile data driven unit and ability system. First I wanted to parse everything when needed but this is unacceptably slow, even for my turn based game. So I have to create templates out of the data driven abilities and whenever I unit requires on I would pass that. Now for my abilities some of the data can be changed so I need a new copy of these fields so they are not shared, for example:

public class Ability {

	//cannot be changed
	private String name;
	private int manaCost;
	//..

	//Obviously every ability needs a different owner unless the owner owns more of it.
	private Creature owner;
	//I use owner in ability to retrieve data from it.
	//For example if a action requires WeaponDamage I can access it's owner.

	//Parameters can be set dynamically but they also get filled in by code in runtime.
	private HashMap<String, Object> parameters = new HashMap<>();
	//Dynamic example: Data not specific to the ability. A ranged ability could hold <"distance", 1>
	//runtime example: When damage is taken it adds the attacker and damage to it so a action can use it.

	/**
	 * Creates a ability from a xml ability node
	 * @param xmlAbility
	 */
	public Ability(XmlNode xmlAbility)
	{
		parseAbility(xmlAbility);
	}
}

Now as far as I understand I need to copy the variable data so they are unique for each owner. Something like this should do:

	public Ability(Ability template, Creature owner)
	{
		//just set unchangeable data
		name = template.name;
		//primitives are copied anyway
		manaCost = template.manaCost;

		//Copy data specific to this instance
		this.owner = owner;
		parameters = new HashMap<>();
		for (Map.Entry<String, Object> parameter : template.parameters.entrySet())
		{
			//Since dynamicly created parameters should not change I can just use references for the entries.
			parameters.put(parameter.getKey(), parameter.getValue());
		}
	}

So am I doing things correctly this way? And since this is just a fraction of the data i'm implementing dynamically and I'm wondering if there are easier or better ways to do this. Are there any other pitfalls I need to be aware off and how would you tackle this problem?

 

Now I have wrote this I feel I do not need a Creature owner since abilities are listening on the creature and it can just pass itself to those listening methods. I could probably abstract the runtime data from parameters too and have a complete generic Ability which I could just reference. Just a quick untested thought, sounds better but I'm not sure how much to change around, the complete system is much larger then what I have shown.

 

Edit

 

I'm experimenting a bit with that last option and I'm wondering if the following code is safe to do. It feels a bit sketchy.

 

Consider the following Ability class:

public class Ability implements CreatureListener {

	private final String name;

	public HashMap<String, Object> parameters = new HashMap<>();

	public Ability(String name)
	{
		this.name = name;
	}

	public void startAbility(Creature owner)
	{
		parameters.put("OWNER", owner);
		//Perform needed actions, if they need the owner they can take it from parameters
	}

	@Override
	public void onAttack(Creature owner, Creature target) {
		parameters.put("OWNER", owner);
		parameters.put("TARGET", target);

		//Perform needed actions, if they need the owner or target they can take it from parameters
	}

	@Override
	public void onTakeDamage(Creature owner, Creature attacker, int damageDealt) {
		parameters.put("OWNER", owner);
		parameters.put("ATTACKER", attacker);
		parameters.put("DAMAGE_DEALT", damageDealt);

		//Perform needed actions, if they need the owner or attacker they can take it from parameters
	}
}

This should be save to do. Let's imagine a creature uses it's aoe attack on two other creatures that have a return damage ability. That return damage ability points to the same object for both creatures.

  1. Attacking creature does AOE action and finds two victims.
  2. Attacking creatures uses a damage action to calculate the damage and apply to victim1.
  3. Victem1 triggers onTakeDamage(..)  it sets itself as it's OWNER, attacking creature as TARGET and the damage it took as DAMAGE_DEALT
  4. Victem1 uses a damage action to apply DAMAGE_DEALT to ATTACKER.
  5. Attacking creature uses a damage action to apply damage to victim2.
  6. Victem2 triggers onTakeDamage(..)  it sets itself as it's OWNER, attacking creature as TARGET and the damage it took as DAMAGE_DEALT
  7. Victem2 uses a damage action to apply DAMAGE_DEALT to ATTACKER.

Seems safe to me but I have deemed unsafe things safe before.

Edited by menyo

Share this post


Link to post
Share on other sites
Advertisement
You haven't really written which language that is (Java and C# sound reasonable but I haven't used either for such a long time I'm not certain if I can exclude one).

Shouldn't this constructor do what you are trying to do by hand?

Share this post


Link to post
Share on other sites

You haven't really written which language that is (Java and C# sound reasonable but I haven't used either for such a long time I'm not certain if I can exclude one).

Shouldn't this constructor do what you are trying to do by hand?

 

Java, but I think the answer to the question would be valid for both.

 

Yeah, since I can just reference it's contents that constructor would work. In the end they do pretty much the same performance wise however,

Edited by menyo

Share this post


Link to post
Share on other sites

[...] and an initial capacity sufficient to hold the mappings in the specified Map.


So for large amounts of data the constructor version is likely to be faster since it avoids unnecessary reallocations and rehashing.

Share this post


Link to post
Share on other sites


So for large amounts of data the constructor version is likely to be faster since it avoids unnecessary reallocations and rehashing.

 

Your right, thanks for pointing it out. Anyway, the question is about something different.

 

I am trying to figure out how to wrap the Ability reference with the creature and additional data but the problem remains that the ability calls the action so it needs the creature to for example apply damage and get the weapon_damage if the action requires that. Another fact is that a single ability can have many actions and the targets can actually change within a single abilty. For example I can create a ability that does damage to a enemy and then heal friendly units. This requires me to first damage the target and OnAttackSuccess fill TARGET with all friendly units to apply healing. A xml file for that would look something like this.

<ability name="DefineSubtraction">
            <range>use_range</range> <!-- corrsponds to parameter -->
            <AI><!-- for AI to decide what to do -->
                <abilityType>
                    <type>SINGLE_DAMAGE</type>
                    <type>MULTIPLE_HEAL</type>
                </abilityType>
            </AI>

            <!-- The behavior of the skill -->
            <behaviors>
                <behavior>CREATURE_TARGET</behavior> <!-- Creature need to select a target on activation -->
                <behavior>MAGIC</behavior> <!-- Cannot target magic imune and does not trigger PhysicalDamageTaken -->
                <!-- More things like NO_TARGET, COORDINATE_TARGET, PASSIVE, SUSTAINED can be added and they act like bits in a bitset -->
            </behaviors>

            <requirements><!-- Requirements to use this ability also creates a bitset from the combinations -->
                <requirement>SPELL_BOOK</requirement> <!-- Need a spell book -->
                <!-- Could have many requirements like AXE + TWO_HANDED would require 2 handed axe and MELEE_WEAPON + SINGLE_HANDED requires single handed melee weapon -->
            </requirements>

            <!-- The parameters, this actually is the thing I'm worried about. As you can see I need this here, especially when modders want to introduce new creatures with different stats and all.
             It will also hold additional information to show information about the ability. I also need this to add additional data at runtime, like when I need current data of the owner. -->
            <parameters>
                <parameter type="int">
                    <name>use_range</name>
                    <value>10</value>
                </parameter>
                <parameter type="int">
                    <name>spell_damage</name>
                    <value>20</value>
                </parameter>
                <parameter type="int">
                    <name>heal_radius</name>
                    <value>200</value>
                </parameter>
            </parameters>

            <!-- Basic stats, not really sure what I exactly need. I probably put all this in parameters eventually -->
            <tickCost>WeaponSpeed</tickCost>
            <cooldown>0</cooldown>
            <manaCost>0</manaCost>
            <energyCost>0</energyCost>
            <lifeCost>0</lifeCost>

            <!-- The actual action blocks for the ability start here.
             For each phase you can add abilities, there are many phases like: 
             OnDamageTaken, OnAbilitySuccess, OnDeath, OnEquip, etc, etc. -->
            <abilityActions>
                <event type="OnAbilityActivated"><!-- Actions that trigger when ability is activated -->
                    <actions>
                        <!-- The actions in order of execution. Actions can force everything to stop until finished or just run in one go by default.
                         Actions are essentially classes that get instantiated for this ability. So these are hardcoded and run by the ability, the actions
                         handle everything what happens in the game world. I could even hook actions up to map objects. Some actions are: Damage, Projectile, 
                          PlaySound, Move, Effect, AOE and many more. But just with those 4 I can make most abilities of any game. I keep them very basic
                          Damage just does damage and might trigger onDamageTaken. AOE just fills a list with participants for the next action in line to use.-->
                        <action>
                            <!-- regular damage action -->
                            <class>Damage</class>
                            <!-- Damage type -->
                            <damageType>MAGICAL</damageType>
                            <!-- The target, since the behavior is CREATURE_TARGET I know it has been filled when ability is activated -->
                            <target>TARGET</target>
                            <!-- amount of damage from parameters -->
                            <damage>Spell_Damage</damage>
                        </action>
                    </actions>
                </event>

                <event type="OnAbilitySuccess"><!-- Actions that trigger when a initial ability was successfully, for example landing a attack although OnAttackLanded is another Phase that can be triggered  -->
                    <actions>
                        <!-- here I queue two actions up, I can essentially create hundreds of actions here that all behave differently. -->
                        <action>
                            <!-- puts all creatures found in the parameters -->
                            <class>AOE</class>
                            <!-- bitset to determine what creatures to add -->
                            <target_type>
                                <type>FRIENDLY</type>
                                <type>NEUTRAL</type>
                                <type>ALLIED</type>
                            </target_type>
                            <!-- point from where to draw circle of influence -->
                            <origin>OWNER_ORIGIN</origin>
                            <!-- radius of circle of influence -->
                            <radius>heal_radius</radius>
                        </action>

                        <action>
                            <!-- action that heals -->
                            <class>Heal</class>
                            <!-- Target, since AOE object always stores crteature in map as "TARGETS", creatureSet I can just put TARGETS here-->
                            <target>TARGETS</target>
                            <!-- Amount to be healed, from parameters -->
                            <damage>HealAmount</damage>
                        </action>
                    </actions>
                </event>
            </abilityActions>
        </ability>
Edited by menyo

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!