Javascript:无法处理多个实例的事件

时间:2016-08-07 00:53:44

标签: javascript prototype

我已经为游戏创作制作了一个有趣的API。在代码中,我为Mover创建了一个原型,然后使用几个特定的​​原型(Gold,Monster和Hero)扩展它。每个都基于具有给定ID的img标签。我在构造函数中使用特定于类型的信息,并为每种类型使用单个模板方法。 Mover中的大多数功能代码都依赖于特定于类型的详细信息。为简单起见,我列举了一个例子。

我在单独的脚本中使用方法调用来创建和销毁Mover子类型的实例。当我一次创建并销毁一个实例时,一切都按预期工作。图像更新,声音播放,并在正确的延迟后删除。但是,如果我创建两个或更多,则只有最后一个按预期工作。所以,如果我做金,培养,英雄。只有英雄会正确删除。其他两个将播放音频,但似乎没有更新。

当我尝试将函数附加到多个实例的onclick事件时,我遇到了同样的问题。只有最后一个工作,其他人什么也没做。显然我对java处理方法赋值的方式缺一些了解。您可以提供任何解释都会有所帮助。 谢谢, BSD

function Mover()
{
}

Mover.prototype.InitTag = function()
{
   this.HTMLtag.src=this.imageURL;
   this.HTMLtag.style.position="absolute";
   this.HTMLtag.style.width=characterSize;
   this.HTMLtag.style.height=characterSize;
   this.Position(Math.floor(Math.random()*(MaxW-characterSize)+(characterSize/2)),Math.floor(Math.random()*(MaxH-characterSize)+(characterSize/2)));
}

Mover.prototype.Destroy = function()
{
   var disp = this.HTMLtag.display;
   this.HTMLtag.src=this.destroyURL
   this.HTMLtag.display = disp;
   this.destroyAudio.play();

   this.RemoveTag();
}

function Monster(id)
{
   this.MonsterID = id;
   this.HTMLtag = document.getElementById("monster"+id);
   this.imageURL = "monster1.jpg";
   this.destroyURL = "monster2.jpg";
   this.destroyAudio = monsterAudio;
}

Monster.prototype = new Mover();

Monster.prototype.RemoveTag = function()
{
   var mID = this.MonsterID;
   setTimeout(function() {field.DeleteMonster(mID)}, 1000);
}

function Hero()
{
   this.HTMLtag = document.getElementById("hero");
   this.imageURL = "hero1.jpg";
   this.destroyURL = "hero2.jpg";
   this.destroyAudio = heroAudio;
}

Hero.prototype = new Mover();

Hero.prototype.RemoveTag = function()
{
   setTimeout(function() {field.DeleteHero()}, 5000);
}

function Gold(id)
{
   this.GoldID = id;
   this.HTMLtag = document.getElementById("gold"+id);
   this.imageURL = "gold1.jpg";
   this.destroyURL = "gold2.jpg";
   this.destroyAudio = goldAudio;
}

Gold.prototype = new Mover();

Gold.prototype.RemoveTag = function()
{
   var mID = this.GoldID;
   setTimeout(function() {field.DeleteGold(mID)}, 1000);
}

---------更新更新更新----------- 我至少部分解决了这个问题。我已经让它工作了,但我仍然不知道为什么它没有按预期运行。我注意到,虽然我的浏览器(Chrome)开发人员工具可以在视觉上识别出最近添加的Mover,但是它在任何其他推动者时都无法实现。

Tag of most recently added Mover can be identified in Chrome developer tools. 这表明Mover.HTMLtag实际上与document.getElementById('mover1')不同。我能够通过查看GoldField.DeleteMover中的变量来确认这一点。在指示的行mover.src没有改变,但是movers [id] .HTMLtag.src已经正确更新。在最近添加的案例中,它们都是相同的。

GoldField.prototype.DeleteMover = function(id)
{
  var isHero = false;
  if(this.Hero!=null && id==this.Hero.myID)
  {
    this.Hero = null;
    isHero = true;

  }
  else if(this.Tower!=null && id==this.Tower.myID)
  {
    this.Tower = null;
  }

  var mover = document.getElementById("mover"+id);
  if(!isHero)
  {
    this.tag.removeChild(mover);//<<< HERE HERE HERE HERE
    delete this.movers[id];
  }
}

所以,我在Mover.Destroy中更改了一行。通过ID查找标记并设置src。我能够做到可靠的行为。在添加第二个Mover之后,Mover.HTMLtag似乎不可靠。有什么解释吗?

Mover.prototype.Destroy = function()
{
   document.getElementById(this.HTMLtag.id).src=this.destroyURL;
   this.HTMLtag.src=this.destroyURL;//old method
   this.destroyAudio.play();

   this.RemoveTag();
}

由于怀疑这可能延伸到this.HTMLtag的其他更新,我设置了Hero的一些基本动作。它工作得很好,但是如果你添加一个额外的Mover,它就不再移动了。这大大缩小了这个问题。为什么构建第二个Mover导致原型成员改变?

2 个答案:

答案 0 :(得分:1)

所以我调试你的代码,我找到了问题的原因。问题是当你创建一个新的怪物实例时,你在怪物var上存储了对它的引用。当您删除它时,您不会删除/更新对它的引用。所以你的删除函数myField.DeleteMover(id)尝试删除已删除的怪物。如何解决这个问题。

// create an array to keep ref to our instances
var monsters= [];
// var monster = null;
function addMonster()
{
  // monster = goldField.AddMonster();⏎
  // push every monster in array
  monsters.push(goldField.AddMonster());
}

function killMonster()
{
  // if array.length is true
  if (monsters.length) {
    // call the destroy function on the last ref
    monsters[monsters.length - 1].Destroy();
    // remove the last ref from array using pop
    monsters.pop();
  }
//monster.Destroy();
}

这是有效的,但我认为所有这些都应该在对象本身中完成。你不应该在乎它。

另一个建议是尝试使用更多array methods。避免在数组索引上使用delete因为它混乱了索引和计数而是使用splice(index,1)相同的数组使用push而不是任意索引添加项目。

无论如何有趣的游戏!祝你好运。

编辑,在你回答之后我回去测试。 为了使它工作,我这样做。

// First go inGoldField.prototype.DeleteMover and replace the ugly delete index by
this.movers.splice(id, 1);
// Then in the Mover.prototype.Destroy
// This part is a a little blurred for me.
// the current HTMLtag looks good but when I console.log like this
console.log('before', this.HTMLtag);
this.HTMLtag = document.querySelector("#mover" + this.myID);
console.log('after', this.HTMLtag);
// They are not equal look like the first is outdated

您应该将所有删除和添加转换为拼接和推送方法 这只是一个快速的调试,我不知道为什么选择器已经过时了。

答案 1 :(得分:0)

所以我再次检查代码并使其工作而不刷新选择器。问题是由使用innerHTML创建dom元素引起的。

首先重置

this.HTMLtag.src=this.destroyURL

然后代替

//Mover.prototype.Destroy
this.tag.innerHTML+="<img id='mover"+this.moverCount+"'>";

我创建了一个img dom el。

var img = document.createElement("img");
img.setAttribute('id', 'mover' + this.moverCount);
this.tag.appendChild(img);

现在所有怪物都被删除了 我没有检查英雄,但首先你应该更新你的innerHTML并回答是否还有问题。我不认为某些原型有任何问题。