0

I coded an application that isn't entirely OOP. I was considering converting it to "real" OOP.

Right now, the code is structured by setting subfunctions as attributes to main functions.

Ex: Bullet.move.normal is a subfunction/dependency or Bullet.move.

This is how the code looks right now:

Bullet = function(x,y,angle,type){
    return {x:x,y:y,angle:angle,type:type};
}

Bullet.update = function(b){
    Bullet.move(b);
    Bullet.collision(b);
}

Bullet.move = function(b){
    if(b.type === 'normal') Bullet.move.normal(b);
    else if(b.type === 'sinus') Bullet.move.sinus(b);
}

Bullet.move.normal = function(b){
    b.x +=  Math.cos(b.angle);  b.y +=  Math.sin(b.angle);  //not important
}   
Bullet.move.sinus = function(b){
    b.x +=  Math.cos(b.x);  b.y +=  Math.sin(b.y); //not important
}   

Bullet.collision = function(b){
    Bullet.collision.wall(b);
    Bullet.collision.actor(b);
}

Bullet.collision.wall = function(b){} 
Bullet.collision.actor = function(b){}


---

I've started to write the OOP version of the code above but the structure I had doesn't work perfectly.

this parameter doesn't refer to the object if it's a "multilevel" function. (Check Bullet.prototype.move.normal)

What would be the recommended way to restructured the prototype without having to put all subfunctions in the main function? (Check 2nd Bullet.prototype.move)

Is there a solution other than just naming everything like Bullet.prototype.move_normal? I'd prefer to not have everything on the same "level".

And what would be the advantages of using OOP instead of what I had before? Is it worth converting to OOP?

Bullet = function(x,y,angle,type){
    this.x = x; 
    this.y = y;
    this.angle = angle;
    this.type = type;
}

Bullet.prototype.update = function(){
    this.move();
    this.collision();
}

Bullet.prototype.move = function(){
    if(this.type === 'normal') this.move.normal();
    else if(this.type === 'sinus') this.move.sinus();
}

Bullet.prototype.move.normal = function(){  
    //not working, this === Bullet.prototype.move, not the bullet
    this.x +=  Math.cos(this.angle);    //not important
    this.y +=  Math.sin(this.angle);    
}


Bullet.prototype.move = function(){ //I dont want this. I'd like to keep things separated.
    if(this.type === 'normal'){
        this.x +=  Math.cos(this.angle);
        this.y +=  Math.sin(this.angle);    
    }
    else if(this.type === 'sinus'){
        this.x +=  Math.cos(this.x);
        this.y +=  Math.sin(this.y);    
    }
}
RainingChain
  • 7,397
  • 10
  • 36
  • 68
  • 2
    You can't use multi-level hierarchy for your methods if you want to use the `this` pointer for the reason you discovered. All methods have to be only only one level down from the object or prototype. Simply change `move.normal` to `moveNormal`. – jfriend00 Jun 17 '14 at 03:58
  • Is it the way people normally do things? Put all the functions and attributes on the same level? – RainingChain Jun 17 '14 at 04:08
  • 1
    Yes, that's the way people normally do things in javascript. For properties, there's no issue with going multiple levels. For methods, creating any extra levels creates this issue with the `this` pointer so methods on an object stay at one level. – jfriend00 Jun 17 '14 at 04:52

1 Answers1

1

Replace type code with subclasses would be a good starting point:

function extend(Parent, Child) {
    function Dummy () {}
    Dummy.prototype = Parent.prototype;
    Child.prototype = new Dummy();
    Child.prototype.constructor = Parent;
}

Bullet = function(x, y, angle, type){
    this.x = x;
    this.y = y;
    this.angle = angle;
    this.type = type;
};

Bullet.prototype.update = function(){
    this.move();
    this.collision();
};

Bullet.prototype.collision = function(b){
    this.collisionWall(b);
    this.collisionActor(b);
};

Bullet.prototype.collisionWall = function(b){};
Bullet.prototype.collisionActor = function(b){};

//NormalBullet
NormalBullet = function() {
    //Call parent constructor and pass all the arguments in.
    Bullet.apply(this, arguments);
};

//Set prototype inheritance.
extend(Bullet, NormalBullet);

//Move the bullet move logic into subclass.
NormalBullet.prototype.move = function() {
    this.x +=  Math.cos(this.angle);
    this.y +=  Math.sin(this.angle);
};

//SinusBullet
SinusBullet = function() {
    Bullet.apply(this, arguments);
};

extend(Bullet, SinusBullet);

SinusBullet.prototype.move = function() {
    this.x +=  Math.cos(this.x);
    this.y +=  Math.sin(this.y);
};

var sinusBullet = new SinusBullet(//your arguments);
sinusBullet.move();

var normalBullet = new NormalBullet(//your arguments);
normalBullet.move();

Source

merlin
  • 784
  • 1
  • 15
  • 22
  • I'm not really looking to subdivide the class. I only showed a basic example where subdividing would be easy but it wouldn't work with the actual application. How would you code the collision part with that structure btw? – RainingChain Jun 17 '14 at 04:28
  • [Don't use `new Bullet()` for the prototype](http://stackoverflow.com/q/12592913/1048572)! – Bergi Jun 17 '14 at 05:04
  • @RainingChain just move `Bullet.collision.wall` and `Bullet.collision.actor` one level up. – merlin Jun 17 '14 at 06:25