-1

I created a Sprite Class and then derived a Dragon class from the sprite class. I am trying to add in an action method only to the Dragon Class, but it is not working. I'm adding the action method to Dragon.prototype in the same way that I added methods to the Sprite class with Sprite.prototype, but if I create an instance of my Dragon class, I'm not able to call the action method I defined in the Dragon prototype.

If I change Dragon.prototype.action to Sprite.prototype.action, the code works perfectly. For this example, it wouldn't matter, but I want to be able to set up methods for specific classes later on. What am I doing wrong? Should I just settle for more method names? If the answer should be obvious I apologize, and thanks for your help.

var Sprite = function(spriteSheet, rows, columns, x, y, width, height){
    this.frameSpeed = 1;
    this.spriteSheet = spriteSheet;
//The starting Location
    this.x = x;
    this.y = y;
//The width and height of the sprite
    this.width = width;
    this.height = height;
//Variables for movement
    this.xSpeed = 0;
    this.ySpeed = 0;
//rows and columns of our spritesheet
    this.rows = rows;
    this.columns = columns;
//our variables needed to animate the sprite.
    this.sourceWidth = this.spriteSheet.width/this.columns;
    this.sourceHeight = this.spriteSheet.height/this.rows;
    this.sourceX = 0;
    this.sourceY = 0;
    this.frameCount = this.rows * this.columns;
    this.currentFrame = 0;
}

Sprite.prototype.update = function(){

    this.y+=this.ySpeed;
    this.x+= this.xSpeed;

    if(this.currentFrame >= this.frameCount){
        this.currentFrame = 0;
    }

    this.row = Math.floor( this.currentFrame / this.columns);
    this.column = Math.floor( this.currentFrame % this.columns);

    this.currentFrame+=this.frameSpeed;
    this.sourceX = this.column * this.sourceWidth;
    this.sourceY = this.row * this.sourceHeight;

}

Sprite.prototype.draw = function(){
     context.drawImage( this.spriteSheet, this.sourceX, this.sourceY, this.sourceWidth, this.sourceHeight, this.x, this.y, this.width, this.height);
}

var mySprite = new Sprite(smiley,4,4,100,50,100,100);

var Dragon = function( x, y, width, height){
    var dragon = new Sprite(dragonSheet,4,3,x,y, width,height);
    dragon.frameSpeed = .5;
    dragon.xSpeed = 4;
    return dragon;
} 

Dragon.prototype.action = function(){
    if(this.x>500){
        this.x = -100;
    }
}

var dragon1 = new Dragon(70,170,80,50);
Myk Willis
  • 9,698
  • 2
  • 32
  • 52

2 Answers2

2

In contrast to your Sprite constructor, the Dragon function does return an object - and is therefore no more a constructor, but a mere factory function. It does create and return a Sprite instace, which will inherit from Sprite.prototype, not from Dragon.prototype. See What is the 'new' keyword in JavaScript? for details.

To fix this, use Dragon as a constructor. this will be the instance, and to initialise it you'd .call() the Sprite function on it before giving it dragon-specific properties. The newly created instances would then inherit from Dragon.prototype.

To set up the prototype chain correctly, you need to make Dragon.prototype inherit from Sprite.prototype - so that all created Dragon instances will have the Sprite methods as well, like here.

function Dragon(x, y, width, height) {
    Sprite.call(this, dragonSheet, 4, 3, x, y, width, height);
    this.frameSpeed = .5;
    this.xSpeed = 4;
}
Dragon.prototype = Object.create(Sprite.prototype);
Dragon.prototype.constructor = Dragon;

Dragon.prototype.action = …;

var dragon1 = new Dragon(70,170,80,50);
Community
  • 1
  • 1
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
0

The reason that Dragon.prototype.action is not called when you do something like:

var d = new Dragon(...);
d.action(); // won't work

is because you are choosing to return a newly-created Sprite object from the Dragon constructor, instead of using this, which will have been set up as a new Dragon instance for you upon having been called with new. Because you are explicitly invoking the Sprint constructor with new, and then returning that object, the object has been set up with Sprite's prototype (and doesn't know anything about Dragon).

There are several ways to do inheritance in JavaScript, but I think in your case you could get away with just changing your Dragon constructor to call Sprite with this specified explicitly, instead having it act on your new Dragon object:

var Dragon = function( x, y, width, height){
    Sprite.call(this, dragonSheet,4,3,x,y, width,height); // act on `this`
    this.frameSpeed = .5;
    this.xSpeed = 4;
    // 'return this' is implied for constructors
} 
Myk Willis
  • 9,698
  • 2
  • 32
  • 52