A Flash Developer Resource Site

Results 1 to 7 of 7

Thread: Calling a function from an extended class inside a top level class

Hybrid View

  1. #1
    Member
    Join Date
    Sep 2009
    Posts
    88

    resolved [RESOLVED] Calling a function from an extended class inside a top level class

    package{
    public class Character{
    protected var _hp:uint = 50; //Character Health Points
    protected var _power:uint = 5; //Damage dealt
    public fonction attack(defender:Character){
    defender._hp -= this._power;
    if (defender._hp <= 0)
    this.win();
    }
    }
    }

    package{
    public class Player extends Character{
    public function win():void{
    trace("Opponent defeated");
    }
    }
    }

    I`m instancing a Character and a Player in the Main Timeline, all in frame 1.
    When I use: ""player.attack(character)"" it works fine by itself.

    So I added the if (defender._hp <= 0) this.win() which gives me the following error:

    1061: Call to a possibly undefined method win through a reference with static type Character.

    "defender" is a Character instance, "this" is a Player instance and "win()" is a Player method. I try to call the Player method inside a Character method using the Player instance adding the "." and his method name

    Do I really need to define the win() function in the Character class?
    Is there a bypass to use a subclass method in a parent class method if it`s called from an instance of the subclass?

    I`m really sorry if it is hard to understand and not clear enough. I didn`t know how to explain this better.
    Last edited by ArenaFlash; 09-23-2009 at 08:52 PM.

  2. #2
    newb of many sorts Ralgoth's Avatar
    Join Date
    Apr 2002
    Posts
    466
    I don't know that this is really kosher, but you could just create a class for global assets.

    PHP Code:
    package
    {
        public class 
    Globals
        
    {
            public static var 
    assets:Object = new Object();
        }

    so you would make sure to import this class into any other class that might need it. Then when you define your win function, include a line like Globals.assets.win = win; That way, from your character file, instead of saying this.win() you would say Globals.assets.win();

    caution! use sparingly. It's usually bad practice to declare dynamic globals... but it's certainly a quick work around when you need to define a new function within multiple classes.
    Search first, asked questions later.

  3. #3
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    I don't think the globals stuff really addresses the question.

    This is a job for inheritance. The problem is that you are assuming that the instance is a Player within the Character class. win is not defined in Character, so it throws the error. The main ways to solve this are:
    1. Implement win in Character and override it appropriately in any subclasses that need to change its behavior.
    2. Override the attack method in Player to do player specific stuff.
    3. Test that the instance is of the appropriate type and cast before using a specific method.

    3 is bad. It would mean that Character needs to know about all things that extend it and check for each of the special cases.

    Here's a way to do 1:

    Code:
    package{
      public class Character{
        protected var _hp:uint = 50; //Character Health Points
        protected var _power:uint = 5; //Damage dealt
        public function attack(defender:Character){ 
          defender._hp -= this._power;
          if (defender._hp <= 0){
            this.win();
          }
        }
    
        public function win():void{
           //do nothing.  This method exists just to have something to call and not throw errors
        }
      }
    }
    
    package{
      public class Player extends Character{
        public override function win():void{
          trace("Opponent defeated");
        }
      }
    }
    Now, that's not so bad, if all things that extend Character need a win method that might change how it's implemented in particular. This style emulates "abstract" classes in other languages.

    Here's the second style:
    Code:
    package{
      public class Character{
        protected var _hp:uint = 50; //Character Health Points
        protected var _power:uint = 5; //Damage dealt
        public function attack(defender:Character){
          defender._hp -= this._power;
        }
      }
    }
    
    package{
      public class Player extends Character{
    
        public override function attack(defender:Character):void{
           super.attack(defender);
           if (defender._hp <= 0){
            this.win();
           }
        }
    
        public function win():void{
          trace("Opponent defeated");
        }
      }
    }
    This way puts all the player specific logic within player. This way would be better if only players can win.

  4. #4
    Member
    Join Date
    Sep 2009
    Posts
    88
    Wow 5tons, I wasen`t expecting to get such a great answer and so quickly. I appreciate the input as well Ralgot.

    If you don`t mind futher questions on the subject 5tons...

    I believe I will go for the option 1. So by using that "dummy" function declaration in the Character class, will the real one from the Player class be used for sure even though it is called from inside a Character method(by the Player instance)?

    I`m still quite new on AS3 and OOP, if I understand well...
    1- from the timeline a Character method is called (from his extended class instance)
    2- from the method called inside the Character class I can use the Player class (extends Character) attributes and play with them (as they are protected) and can be accessed without a problem but not the Player class functions?
    3- Character class doesn`t bother trying to see if that Player method is defined when I try to call it?
    4- but if I implement the "dummy" method in Character class, and call it from the Player instance, NOW it will check if it is defined in the Player class in case of overriding?
    5- it will apply the overrided method from Player class even though we are inside a Character class method, because it was overriden and is called from a Player instance?

  5. #5
    Will moderate for beer
    Join Date
    Apr 2007
    Location
    Austin, TX
    Posts
    6,801
    1. Okay. The instance on Stage is a Player, right?
    2. No. Character will not compile if it references things (properties OR methods. From anywhere, not just Player) that are undefined in Character.
    3. The error occurs at compile-time, not run-time. There is no Player instance to check at compile-time. The methods defined in Character must be valid for all Characters.
    4. By implementing the dummy method, the Character class can now be compiled. At run-time, the win method will be resolved according to the particular instance running the code.
    5. yes, I believe so. Of course, now you've got me a bit paranoid about it.

  6. #6
    Senior Member joshstrike's Avatar
    Join Date
    Jan 2001
    Location
    Alhama de Granada, España
    Posts
    1,136
    I'd usually go w/ Flax's #1 option, but there's a 4th way, an alternative to Flax's #3, which is rather than testing to see if the Character is one of possibly many types that have a public win() function, you could just check
    Code:
    if (myCharacter.hasOwnProperty("win")) {
      myCharacter.win();
    }
    In general, this is a hackish approach. But it's superior to testing which class you're dealing with and keeping a hard-coded list of which ones have win() as a function. And in some cases, like if you're extending functionality from a class in an existing project that may have dozens of subclasses, and only one of them has this win() function, and it's only being checked infrequently by some unrelated asset, this can be more efficient than including an unnecessary extendable function in the interface or base class for all of them.

  7. #7
    Member
    Join Date
    Sep 2009
    Posts
    88
    Thanks for the help again, I marked the topic as resolved although it doesn`t seem to show up same way as other resolved threads.

    I wasen`t sure about creating an account on this forum, but now I see that there is many ressourceful people around

Posting Permissions

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




Click Here to Expand Forum to Full Width

HTML5 Development Center