-
[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.
-
newb of many sorts
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.
-
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.
-
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?
-
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.
-
Senior Member
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.
-
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|