简体   繁体   English

设置涉及逻辑的函数构造函数属性的最佳方法

[英]Best method to setup properties of function constructor where logic is involved

I have been learning a lot about prototypical and classical inheritance, and I am trying to rewrite some spaghetti code I have written to use one of these approaches. 我已经学习了很多有关原型继承和经典继承的知识,并且我试图重写一些使用这些方法之一编写的意大利面条代码。

The issue I am having is I am not sure the best way to initialize the properties of the constructor function because some of them require some logic to determine the value. 我遇到的问题是,我不确定初始化构造函数的属性的最佳方法,因为其中有些需要确定值的逻辑。

My example below is an enemy constructor function which is used in the spawnEnemy function beneath it. 下面的示例是一个敌人构造函数,该函数在其下面的spawnEnemy函数中使用。 When I rewrite this I think I can make spawnEnemy a function of the prototype and have it inherited by the objects I create. 当我重写它时,我想我可以使spawnEnemy成为原型的函数,并使其由我创建的对象继承。

The first value I need to identify is the spawnDir, because this is used to set the x and y coordinates of the enemy. 我需要确定的第一个值是spawnDir,因为它用于设置敌人的x和y坐标。 Speed is also randomized between a set of values, and the color will be a sprite in a later rewrite which will be an object that is passed in (that is not in the scope of my question). 速度也是在一组值之间随机分配的,颜色在以后的重写中将是精灵,它将是传入的对象(不在我的问题范围内)。

I have provided my existing code below, maybe there isn't a "clean" solution like I am hoping. 我在下面提供了我现有的代码,也许没有像我希望的那样“干净”的解决方案。 I want to learn best practices, and I can't help feel like there is a solution to this using inheritance somewhere and running some additional methods upon instantiating a sub class of some sort. 我想学习最佳实践,我不禁感到有一种解决方案,可以在某个地方使用继承并在实例化某种子类时运行一些其他方法。 I am just having trouble conceptualizing this model. 我只是在概念化此模型时遇到麻烦。

Ideal Solution 理想的解决方案

I am not sure if I am explaining things the best way possible above, so I will try to be concise here with what I am looking for. 我不确定我是否在上面用最好的方式解释了事情,所以在这里我将尽量简化我要寻找的内容。 I am hoping to use the classical model, preferably, to provide a solution using constructors and inheritance for setting up the properties of the objects instantiated from the resulting class. 我希望使用经典模型,最好是提供一种使用构造函数和继承的解决方案,以设置从结果类实例化的对象的属性。

Spaghetti Code (yeah I know, it is very spaghetti) 意大利面代码 (是的,我知道,这是非常意大利面的)

  var Enemy = function(color, spawnDir, speed, w, h) {

  // spawnDir is randomized and passed in as argument
  // objects starting position is set based on what spawn direction was set
  if (spawnDir == 0) {
    this.x = -w;
  } else if (spawnDir) {
    this.x = GAME_WIDTH + w;
  }

  this.y = (GAME_HEIGHT / 2) - (h / 2); // objects y coordinate always set to very middle of screen
  this.color = color;                   // color or sprite image of enemy
  this.spawnDir = spawnDir;             // spawn direction passed as argument
  this.speed = speed;                   // speed passed as argument, randomized
  this.width = w;                       // width passed as argument
  this.height = h;                      // height passed as argument
  this.collision = 0;                   // sets whether object has collided, 0 = default, incremenets with each collision detected
  //this.id = generateRandomId(8);        // randomized id assigned to object as identifier (NOT USED CURRENTLY)

  // called in the draw loop, renders object to canvas
  this.draw = function(ctx) {
    ctx.shadowColor = "black";
    ctx.shadowBlur = 5;
    ctx.shadowOffsetX = 2;
    ctx.shadowOffsetY = 2;

    ctx.fillStyle = this.color;
    ctx.fillRect(this.x, this.y, this.width, this.height);
  };
}; 

// enemy spawn function
var spawnEnemy = function() {
  // if enemies array length is less than enemy reserve limit and spawn counter is set to 0, then success
  if (enemies.length < enemyReserve && spawnCounter == 0) {
    var t;
    var x = Math.floor(Math.random() * 99 + 1); // randomizes spawn direction by generating random number between 0-100
    if (x <= 50) {                              // if the number is less than 50 then spawn is from the left side of the screen
      t = 0;                                    // if the number is greater than 50 then spawn is from the right side of the screen
    } else if (x > 50) {
      t = 1;
    }
    var s = Math.floor(Math.random() * 3 + 1);  // randomizes speed of the enemy
    var enemy = new Enemy("purple", t, s, 40, 20); // instantiates new enemy object with some statis + dynamic arguments

    spawnCounter = spawnRate;                   // spawn counter reset back to default value set in global variables
    enemies.push(enemy);                        // adds the new object to enemies global array
  } else if (spawnCounter != 0) {
    spawnCounter--;                             // if counter is not set to 0 then lowers counter value by 1
  }
};

I prefer to use a pattern where I define the properties within the constructor, any static methods after the constructor, then member methods on the prototype after the static methods. 我更喜欢使用一种模式,在其中定义构造函数内的属性,在构造函数之后定义任何静态方法,然后在静态方法之后定义原型上的成员方法。 It ends up looking something like this: 最终看起来像这样:

function Enemy(color, spawnDir, speed, w, h) {
  //Define instance properties
  this.spawnDir = spawnDir;
  this.speed = speed;
  this.width = w;
  this.height = h;
  //...
}; 

//Static functions
Enemy.spawn = function(){
  var color, spawnDir, speed, w, h;
  //Calculate variables as needed
  return new Enemy(color, spawnDir, speed, w, h);
};


//Member functions
Enemy.prototype.draw = function(){
    //Do instance stuff.
    //Access instance properties with 'this'
};

As far as trying to create subclass (of different enemy types for example) look at the answer to Subclassing a class with required parameters in JavaScript 至于尝试创建子类(例如,具有不同敌人类型的子类),请看在JavaScript中使用必需参数进行子类化的答案

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM