我应该使用构造函数/原型吗?

Should I be using a constructor / prototype?

本文关键字:原型 构造函数 我应该      更新时间:2023-09-26
function setupMapObjects() {
    lootChest = new PIXI.Sprite(frame("images/chest.png", 0, 0, 50, 50));
    lootChest.x = 200;
    lootChest.y = 200;
    lootChest.anchor.x = 0.5;
    lootChest.anchor.y = 0.7;
    lootChest.closed = true;
    lootChest.opening;
    lootChest.frameCycle = 0;
    lootChest.interactive = true;
    lootChest.hitArea = new PIXI.Circle(lootChest.x, lootChest.y, 10);
    lootChest.on('click', openChest);
    Map.addChild(lootChest);    

    lootChest2 = new PIXI.Sprite(frame("images/chest.png", 0, 0, 50, 50));
    lootChest2.x = 400;
    lootChest2.y = 400;
    lootChest2.anchor.x = 0.5;
    lootChest2.anchor.y = 0.7;
    lootChest2.closed = true;
    lootChest2.opening;
    lootChest2.frameCycle = 0;
    lootChest2.interactive = true;
    lootChest2.hitArea = new PIXI.Circle(lootChest2.x, lootChest2.y, 10);
    lootChest2.on('click', openChest);
    Map.addChild(lootChest2);
};

function openingChest() {
    this.texture.frame = new PIXI.Rectangle(this.frameCycle*50, 0, 50, 50);
    if (this.frameCycle === 3) {
        clearInterval(this.opening); 
    } else {
        this.frameCycle++;    
    };
};

function openChest() {
    if (distance(Player.sprite.x, Player.sprite.y, this.x, this.y) < 50) {
        if (this.closed) {
            this.opening = setInterval(openingChest.bind(this), 100);
            this.frameCycle = 1;
            this.closed = false; 
        };
    };
};

我有 2 个宝箱精灵,点击时打开,玩家靠近。现在我正试图找出一种有效的方法来创建其中的 50 个。继续制作我已经拥有的它们会有多糟糕,还有什么选择?

构造

函数似乎是正确的想法。毕竟,您不想为每个箱子命名(lootChest1..lootChest50 )。更不用说,你要确保你所有的箱子都是平等的。所以这样的东西应该运作良好。

function Chest(x, y) {
  this.x = x;
  this.y = y;
  this.anchor.x = 0.5;
  this.anchor.y = 0.7;
  this.closed = true;
  this.opening;
  this.frameCycle = 0;
  this.interactive = true;
  this.hitArea = new PIXI.Circle(lootChest.x, lootChest.y, 10);
  this.on('click', openChest);
}
// Have them "inherit" from PIXI.Sprite
Chest.prototype = new PIXI.Sprite(frame("images/chest.png", 0, 0, 50, 50));
// How to use it
var lootChest = new Chest(200, 200);

自从我与 PIXI 合作以来已经有一段时间了,所以我不记得这种继承风格是否适用于他们的渲染系统。如果没有,您可以将其设置为工厂函数。工厂函数看起来就像您创建第一个宝箱的方式(除了您希望将其分配给局部变量),然后从函数返回该宝箱。

编辑:工厂方法如下所示:

function createChest(x, y) {
  var chest = new PIXI.Sprite(frame("images/chest.png", 0, 0, 50, 50));
  chest.x = x;
  chest.y = y;
  chest.anchor.x = 0.5;
  chest.anchor.y = 0.7;
  chest.closed = true;
  chest.opening;
  chest.frameCycle = 0;
  chest.interactive = true;
  chest.hitArea = new PIXI.Circle(lootChest.x, lootChest.y, 10);
  chest.on('click', openChest);
  return chest;
}
// How to use it
var lootChest = createChest(200, 200);

我有一个如何从 PIXI 继承的例子。雪碧,但它有点复杂。这样做的方式是允许可配置性,因为它在游戏引擎中,但如果你确切地知道你想要你的对象是什么样子,上述任何一种方法都应该很好。

一定要使用OOP(面向对象编程)。您可以创建一个Chest对象的数组,然后只修改构造函数和原型方法,而不是一丝不苟地遍历每一个箱子。

肖姆兹做对了。

然后,如果你想,比如说,为所有箱子设置动画,只需使用 for 循环遍历Chest数组,并轻松地对所有箱子执行一些操作。

Mike C 举了一个很好的例子,但我想进一步扩展一些与 JavaScript 原型相关的陷阱。

Mozilla在原型继承和构造函数方面有一个很好的例子

但是,在利用原型时,需要记住一些重要的陷阱,我已在此代码笔中演示了这些陷阱。

请注意,对同一对象调用的相同方法在第二次调用时的行为实际上与第一次调用不同。这是因为该对象不存储对 move 函数的给定实现的引用,而是使用调用该对象时当前驻留在其原型上的那个。

可以在

代码运行时修改Shape.prototype.move。这很可能永远不会发生,但如果它发生了(例如,如果团队中的另一位开发人员在运行时重新定义原型上的函数,而不知道已经存在一个同名的函数),它最终可能会导致一个很难追踪的错误。

JavaScript 中的原型可能是有用的工具,但我个人更喜欢使用工厂模式来避免难以捉摸的原型相关错误的可能性。

例:

function CreateShape(newX, newY) {
  return {
    x = newX,
    y = newY,
    move = function(addX, addY){
      this.x += addX;
      this.y += addY;
      console.info('Shape moved.');
    }
  }
}

通过使用此模式,每次都会创建一个新对象,该对象不与任何其他对象共享原型,这意味着无论对其他 Shape 对象或任何原型进行何种修改,它的行为都将始终相同。

只是您考虑的替代方案。我希望这有帮助!