pete796 Posted January 22, 2017 Share Posted January 22, 2017 Hi everyone, I'm trying to create two types of enemies, the first is a robot that has 2 methods: sleep and patrol. My second enemy is a flyingEnemy. The aim is to inherit the sleep method from the robot but amend the patrol method. Can anyone show me how my flyingEnemy can inherit from robot whilst amending the patrol method? Below is my code. When I create the flyingEnemy, its patrol method overwrites the robot's patrol method and ALL enemies have the same behavior. var SuperSmash = SuperSmash || {}; SuperSmash.flyingEnemy = function(game, x, y, key, velocity, tilemap, player) { "use strict"; SuperSmash.Enemy.call(this, game, x, y, key); this.game = game; this.tilemap = tilemap; this.player = player; this.animations.add("fly", [0]); }; SuperSmash.flyingEnemy.prototype = Object.create(SuperSmash.Enemy.prototype); SuperSmash.flyingEnemy.prototype.constructor = SuperSmash.flyingEnemy; SuperSmash.flyingEnemy.prototype.patrol = function() { "use strict"; SuperSmash.game.physics.arcade.moveToObject(this, this.player, 200); }; Link to comment Share on other sites More sharing options...
pete796 Posted January 22, 2017 Author Share Posted January 22, 2017 ok, so this has been resolved, both enemies now behave as they should. flyingEnemy has its own patrol method Link to comment Share on other sites More sharing options...
samme Posted January 22, 2017 Share Posted January 22, 2017 You can use SuperSmash.flyingEnemy.prototype.patrol = function() { SuperSmash.Enemy.prototype.patrol.call(this, arguments); // + flying stuff… }; Your example has SuperSmash.Enemy.prototype.patrol twice, I think the 2nd is supposed to be flyingEnemy. Also, though it's harmless, the this.game = game; assignments are redundant (the `game` property is already set by Phaser.Sprite). I've seen this somewhere else so I'm worried someone's putting it in tutorials or something. Link to comment Share on other sites More sharing options...
mattstyles Posted January 22, 2017 Share Posted January 22, 2017 Glad you resolved it but I'm still curious as to how you managed to break it in the first place! Did you inadvertently apply a new function to the base prototype rather than the child prototype? I created a couple of fiddles and struggled to break stuff, class Base { constructor (name) { this.name = name } } class Robot extends Base { constructor (name) { super(name || 'Robot') } sleep (time) { console.log(this.name, 'is sleeping...') setTimeout(() => { console.log(this.name, 'is now awake again.') }, time) } patrol () { console.log(this.name, 'is patrolling.') } } class Flyer extends Robot { constructor (name) { super(name || 'Flyer') } patrol () { console.log(this.name, 'is starting an airborne patrol.') } } var robot = new Robot() var flyer = new Flyer() robot.sleep(100) robot.patrol() flyer.sleep(100) flyer.patrol() ES6 ES5 1 hour ago, pete796 said: flyingEnemy has its own patrol method This is the bit I think that confuses me. Given your requirements, which you stated really clearly: 3 hours ago, pete796 said: The aim is to inherit the sleep method from the robot but amend the patrol method. Can anyone show me how my flyingEnemy can inherit from robot whilst amending the patrol method? How else would you code that but to inherit from your base Robot whilst overriding its patrol method? You could directly call the Base.patrol method from the child, but depending on how the functions work that might not be desirable. Part of why I ask is because you're exposing some of the vulnerability and frailty that can become evident in code that relies on inheritance, namely, your FlyingEnemy class has to intricately know the workings of the Base it is inheriting from, not just method names and call parameters, but how that code actually works so you can work out whether it is safe to call a parent (or super) function or not (it gets even trickier when you have to change requirements further down the line and change a class way up your hierarchy, note only do you have to change that class but potentially change all others that inherit from it—because they rely on its implementation—, turning a 10 minute job into an X hr job). With just 2 objects at play it isn't too much of a strain but as you extend your models it becomes intricately difficult to near impossible to accurately hold all that information in your head, which is exact antithesis of the problem inheritance attempts to resolve. Note that this is of particular difficulty to JS because it has no real language level safeguards against these sort of issues, hence why the phrase 'Favour Composition over Inheritance' is sewn into JS's underpants. There is a great quote that sums this up: Quote You wanted a banana but what you got was a gorilla holding the banana and the entire jungle. -- Joe Armstrong The other thing is that (and maybe its just how you phrased it) it doesn't necessarily sound like a FlyingEnemy IS a Robot, more that it just wants some features that a Robot implements. There is a fundamental difference here that is at the heart of inheritance, if you're inheriting then the Child must actually BE its parent, but with some changes or additions. Even if you follow this principle using inheritance too liberally can still be a nightmare but if you don't follow this then your code will quickly become a mess of exceptions and clauses that try to paper over the cracks, and they'll either flat fail or be so time-consuming and bug-introducing that it'll be a near permanent battle. Polymorphism tries to solve this in a sledgehammer-nail kind of way (it has other uses too) but we have none of that in JS, what we can do though is pinch some stuff from more functional languages and use something like a mixin (i.e. composition) to allow our FlyingEnemies to also utilise some methods that Robot's implement. As I say, this might be more in the way that you have phrased it, but if you haven't thought about it too much yet you might want to consider if using composition over inheritance in this instance would be beneficial as your object hierarchy grows. Link to comment Share on other sites More sharing options...
Recommended Posts