Hello and welcome to our community! Is this your first visit?
Register
Enjoy an ad free experience by logging in. Not a member yet? Register.
Results 1 to 5 of 5
  1. #1
    Senior Coder
    Join Date
    Jun 2008
    Location
    New Jersey
    Posts
    2,536
    Thanks
    45
    Thanked 259 Times in 256 Posts

    OOP: Syncing data between classes

    So simple situation:

    I have a class. One of the variables within the class is an array of another class. The second class contains data that it calculates when a function is called; however, one of the values it uses in the calculation comes from the parent class.

    Is there a way I can have it call the value from the class it is within, or sync the data between the parent and the class within it.


    Specifically:

    I have a class spycraft_character. Each character has a set of skills, which I'm defining as an array of classes of type spycraft_skill. Each skill has a total, which uses some values that are stored in the instance of the class, and uses one attribute from the parent. However, the parent attribute can be changed. What can I do to keep the data moving from the parent to the child? I know I can pass it as an parameter in the function that gets the total skill value, but its one of 6 possible values, and I feel like it'd be heavy to check which one it is first then pass it along.

    Thoughts?

  • #2
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    There are a few methods to do this, depending on what is responsible for the calculation.
    First off, the child can access anything that it parent has if it has a scope of protected instead of private.
    Assuming that skill itself has a generic $total on it, there are two easy ways to do this.
    The first is the child is responsible for the calculations. This simply pulls the attribute from the parent. I haven't a clue what these are though, so it does make it difficult for an example. It would likely involve a switch as its logic would be near identical to passing the attribute, but instead you simply select an attribute.

    The next is to do this within the parent. Since the parent can dictate the array for the skillset instead of the child class, you can iterate it within the parent class itself. Again, assuming that there is a constant way to calculate the total, this would eliminate the use of needing to write the same method over and over in the child classes.

    Finally, to control the skill with the attributes, you would add a member property that indicates which attribute governs it (assuming Attribute is a class). Thinking on games like morrowind and oblivion with how they calculate their skills to attribute. This lets you write a quick comparison, the skill would include an public function isGovernedBy(Attribute $a); method.

    So what I see.
    PHP Code:
    interface ISkill
    {
        public function 
    getBaseMagnitude();
        public function 
    getCalculatedMagnitude();
        public function 
    getSkillName();
        public function 
    isGovernedBy(Attribute $a);
        public function 
    setBaseMagnitude($dValue);
        public function 
    setSkillName($sName);
        public function 
    setGovernedBy(Attribute $a);
    }

    abstract class 
    Attribute
    {
        private 
    $sName;
        public function 
    __construct($sName)
        {
            
    $this->sName $sName;
        }

        public function 
    getName()
        {
            return 
    $this->sName;
        }

        public function 
    governsSkill(ISkill $s)
        {
            return 
    $s->isGovernedBy($this);
        }

        public abstract function 
    calculateMagnitude(ISkill $s);
    }

    class 
    Skill implements ISkill
    {
        private 
    $oAttribute;
        private 
    $sName;
        private 
    $dMagnitude;

        public function 
    __construct($sNameAttribute $oAttribute$dMagnitude 0.0)
        {
            
    $this->sName $sName;
            
    $this->oAttribute $oAttribute;
            
    $this->dMagnitude $dMagnitude;
        }

        public function 
    getBaseMagnitude()
        {
            return 
    $this->dMagnitude;
        }

        public function 
    getCalculatedMagnitude()
        {
            return 
    $this->oAttribute->calculateMagnitude($this);
        }

        public function 
    getSkillName()
        {
            return 
    $this->sName;
        }

        public function 
    isGovernedBy(Attribute $a)
        {
            return 
    $a == $this->oAttribute;
        }

        public function 
    setBaseMagnitude($dMagnitude)
        {
            
    $this->dMagnitude $dMagnitude;
        }

        public function 
    setSkillName($sName)
        {
            
    $this->sName $sName;
        }

        public function 
    setGovernedBy(Attribute $a)
        {
            
    $this->oAttribute $a;
        }
    }

    // I'll stick with something like oblivion.  And no I don't know the calcs offhand :P
    class AttributeWillpower extends Attribute
    {
        public function 
    __construct()
        {
            
    parent::__construct('willpower');
        }

        public function 
    calculateMagnitude(ISkill $s)
        {
            
    $dResult $s->getBaseMagnitude();
            if (
    $s->isGovernedBy($this))
            {
                
    $dResult *= 1.15// IE, this skill is now 15% stronger since this attribute governs it
            
    }
            return 
    $dResult;
        }
    }

    class 
    AttributeStrength extends Attribute
    {
        public function 
    __construct()
        {
            
    parent::__construct('strength');
        }

        public function 
    calculateMagnitude(ISkill $s)
        {
            
    $dResult $s->getBaseMagnitude();
            if (
    $s->isGovernedBy($this))
            {
                
    $dResult 1.25;
            }
            return 
    $dResult;
        }
    }

    $aAttributes = array();
    $aAttributes['willpower'] = new AttributeWillpower();
    $aAttributes['strength'] = new AttributeStrength();

    $skill = new Skill('restoration'$aAttributes['willpower'], 1.5); // lets see, I think oblivion used willpower for restoration power.
    foreach ($aAttributes AS $attr)
    {
        
    printf("Skill %s has a calculated magnitude of %f when attribute %s is in use" PHP_EOL$skill->getSkillName(), $attr->calculateMagnitude($skill), $attr->getName());

    Nice.
    Not necessarily the logic you want, but with what I have here a skill is governed by an attribute, and ultimately the attribute calculates the modified skill totals. This can be relatively easy to branch out into trees and families of skills instead of skill by skill if desired.

  • #3
    Senior Coder
    Join Date
    Jun 2008
    Location
    New Jersey
    Posts
    2,536
    Thanks
    45
    Thanked 259 Times in 256 Posts
    That's pretty neat.

    I think though, thanks to my using the wrong terms, I ended up asking the wrong question.

    Unfortunately, I used the terms parent and child, which are used for inheritance. Instead, I meant parent and child in reference to who calls who. Must simplified, I have this:

    PHP Code:
    class character {
        private 
    $name;
        private 
    $stats = array('str' => 0'dex' => 0'con' => 0'int' => 0'wis' => 0'cha' => 0);
        private 
    $skills = array();
    }

    class 
    skill {
        private 
    $name;
        private 
    $stat;
        private 
    $ranks 0;

        function 
    __construct($name$stat$ranks) {
            
    $this->name $name;
            
    $this->stat $stat;
            
    $this->ranks $ranks;
        }

        function 
    calcTotal() {
            
    // $statValue should instead be the value of the stat from the character class that contains this skill instance
            
    echo $this->ranks $statValue
        
    }

    So if I made a character instance 'Keleth', and made added a skill instance 'Sneak', passing the values 'Sneak', 'dex', 0 to it, when I go to calculate, I want to get the stat from the instance 'Keleth' and pass it along.

  • #4
    God Emperor Fou-Lu's Avatar
    Join Date
    Sep 2002
    Location
    Saskatoon, Saskatchewan
    Posts
    16,987
    Thanks
    4
    Thanked 2,660 Times in 2,629 Posts
    The easiest change with what you have here is to modify calcTotal to accept a parameter representing either the character or the skill value required. That would prevent the skill from being replicated as it appears that both the assigned value and definition of the skill has been created in a single class.

    In order to do this, you need to instead call the skill calculations from the character class, and not from the skill class. The skill class is still requiring the same method though, and it accepts a character instead.
    PHP Code:
    class character {
        private 
    $name;
        private 
    $stats = array('str' => 0'dex' => 0'con' => 0'int' => 0'wis' => 0'cha' => 0);
        private 
    $skills = array();

        public function 
    getAttribute($sAttribute)
        {
            return isset(
    $this->stats[$sAttribute]) ? $this->stats[$sAttribute] : 0;
        }

        public function 
    calcTotal(skill $s)
        {
            return 
    $s->calcTotal($this);
        }

        public function 
    setAttribute($sAttribute$value)
        {
            if (isset(
    $this->stats[$sAttribute]))
            {
                
    $this->stats[$sAttribute] = $value;
            }
        }
    }

    class 
    skill {
        private 
    $name;
        private 
    $stat;
        private 
    $ranks 0;

        function 
    __construct($name$stat$ranks) {
            
    $this->name $name;
            
    $this->stat $stat;
            
    $this->ranks $ranks;
        }

        function 
    calcTotal(character $c) {
            
    // $statValue should instead be the value of the stat from the character class that contains this skill instance
            
    echo $this->ranks $c->getAttribute($this->stat);
        }


    $c = new character();
    $c->setAttribute('dex'10);
    $s = new skill('Sneak''dex'0);
    print 
    $c->calcTotal($s); 

  • #5
    Senior Coder
    Join Date
    Jun 2008
    Location
    New Jersey
    Posts
    2,536
    Thanks
    45
    Thanked 259 Times in 256 Posts
    Ah, ok... so I was thinking along those lines, but wasn't sure if it was the right way of doing it. I could even just pass the attributes array along.


  •  

    Posting Permissions

    • You may not post new threads
    • You may not post replies
    • You may not post attachments
    • You may not edit your posts
    •