我正在尝试检查父母是否有孩子。例如,我在我的子弹类enterframe中有这个代码。子弹需要检查父级(哪个级别)内部是否有僵尸。
if (MovieClip(parent).zombie != null)
{
MovieClip(parent).zombie.checkCollisionWithEnemies(this);
}
但是,并非所有级别都有僵尸,所以如果将此子弹添加到父级,我会收到错误。
这是添加项目符号时启动的功能。这段代码在僵尸类中。
public function checkCollisionWithEnemies(bullet: MovieClip)
{
if (this.hitTestObject(bullet))
{
if (this.meter != null)
{
if (this.meter.scaleX > 0)
{
this.meter.scaleX -= 0.5;
}
if (this.meter.scaleX <= 0.01)
{
this.gotoAndStop(2);
}
}
this.parent.removeChild(bullet);
}
}
因此,由于僵尸仅处于某个级别,如果我处于没有僵尸的级别,它将引发此错误:
TypeError:错误#1009:无法访问空对象引用的属性或方法。 在Bullet / update()[Bullet.as:47]
该错误来自这一行:
if (MovieClip(parent).zombie != null)
我正在尝试检查父母内部是否有僵尸,如果确实如此,则运行僵尸的功能。
我在下面尝试过这些代码,但仍然遇到了同样的错误。
if (MovieClip(parent).contains(zombie))
if (MovieClip(parent).getChildByName("zombie"))
答案 0 :(得分:2)
你真正的问题是:
我的子弹类enterframe中有这个代码
此代码不应位于Bullet
类中!为了测试碰撞,您需要两个要相互测试的对象。因此,如果您想在Bullet
类中执行此操作,则bullet对象必须获取对另一个对象的引用(这是您遇到问题的位置)。
要求对另一个对象的引用不必要地使问题复杂化,因为bullet
所做的一切都将自己传递给zombie
的某个函数。它不应该在Bullet
类中进行该方法调用,而应该在已知zombie
和Bullet
的情况下进行:level
。
该级别引用了bullet
和zombie
对象,这使得在那里执行碰撞检测变得容易:
var zombie:Zombie = new Zombie();
addChild(zombie);
var bullet:Bullet = new Bullet();
addChild(bullet);
addEventListener(Event.ENTER_FRAME, gameLoop);
function gameLoop(e:Event):void
{
zombie.checkCollisionWithEnemies(bullet);
}
这很常见,建议使用一个ENTER_FRAME
函数来调用游戏中所有对象的其他功能。它比每个对象都具有ENTER_FRAME
功能更清晰(并且它对性能也有害)
您可以通过覆盖hitTestObject
来改进代码,而不是引入一个基本上做同样事情的新方法名checkCollisionWithEnemies
。
override public function hitTestObject(obj:DisplayObject):Boolean
{
var result:Boolean = super.hitTestObject(obj);
if(result)
{
if (this.meter != null)
{
if (this.meter.scaleX > 0)
{
this.meter.scaleX -= 0.5;
}
if (this.meter.scaleX <= 0.01)
{
this.gotoAndStop(2);
}
}
this.parent.removeChild(bullet);
}
return result;
}
这样您就不必记住任何新的方法名称,而您的课程只是为现有的hitTestObject
功能添加了一些功能。
现在,如果您想拥有仅适用于项目符号的专用功能,那么您应该更加具体了解您的类型,仅接受Bullet
:
public function checkCollisionWithEnemies(bullet: Bullet)
{
if (this.hitTestObject(bullet))
{
if (this.meter != null)
{
if (this.meter.scaleX > 0)
{
this.meter.scaleX -= 0.5;
}
if (this.meter.scaleX <= 0.01)
{
this.gotoAndStop(2);
}
}
this.parent.removeChild(bullet);
}
}
如果你正在调用只有Bullet
类的方法,那么这就是你要走的路。但是你没有这样做,这就是为什么你应该只是override hitTestObject
。
您之前称为hitTestObject
的{{1}}方法仍有问题。这就是这条线:
checkCollisionWithEnemies
与你的this.parent.removeChild(bullet);
类似的问题,恰恰相反。现在,您的Bullet
正在使用zombie
。它适用于这种情况,因为bullet
作为参数传递,但这个想法仍然存在缺陷,因为它依赖于显示列表的结构来工作。
如果您以后决定将一些项目符号移动到一个容器中,或者要让一群僵尸想要与容器一起分组,则此代码将失败。 它假定bullet
和zombie
都有相同的父级。
解决方案与我的答案的第一部分相同:将与其他对象有关的代码部分移到bullet
:
level
现在级别代码看起来像这样:
override public function hitTestObject(obj:DisplayObject):Boolean
{
var result:Boolean = super.hitTestObject(obj);
if(result)
{
if (this.meter != null)
{
if (this.meter.scaleX > 0)
{
this.meter.scaleX -= 0.5;
}
if (this.meter.scaleX <= 0.01)
{
this.gotoAndStop(2);
}
}
// line removed
}
return result;
}
<强> TL;博士强>
尝试创建彼此之间没有太多联系的对象。 在你的情况下,在var zombie:Zombie = new Zombie();
addChild(zombie);
var bullet:Bullet = new Bullet();
addChild(bullet);
addEventListener(Event.ENTER_FRAME, gameLoop);
function gameLoop(e:Event):void
{
if(zombie.hitTestObject(bullet))
{
removeChild(bullet);
//or
bulletContainer.removeChild(bullet);
//or whatever
}
}
类中使用特定于僵尸的代码和在Bullet
类中使用特定于子弹的代码会在两者之间产生不必要的耦合。这种耦合也称为依赖,因为每个类不能再独立使用了。
我在这个答案中指出的解决方案是以Zombie
的形式保留现有的API,并将应用程序特定的逻辑移到另一个地方。 Thsi方式每个类都可以独立工作,在hitTestObject
的情况下处理一些与被击中时相关的逻辑。
这会使Zombie
遍布整个地方更加清洁,正如您所发现的那样,这不是一个好的解决方案。
不可否认,这就是为什么你不应该像你在问题中那样编写代码的原因,但实际上并没有解决问题。我不能强调(现在再次这样做)你遇到的问题主要是因为代码设计有缺陷,这将导致更多的问题。
好的,足够了,现在问题是:
你已经尝试了这3行,你得到了#1009
!=null
这是一个快速的经验法则,告诉你某些代码是否可怕:它包含if (MovieClip(parent).zombie != null)
if (MovieClip(parent).contains(zombie))
if (MovieClip(parent).getChildByName("zombie"))
的强制转换,如下所示:MovieClip
。在某些情况下,进行这样的演员是有道理的,但在大多数情况下,人们滥用它来获得一些非常可怕的代码。
这是因为MovieClip(...)
是一个MovieClip
类,如果你转换为这样的类,编译器会抛出更少的错误。这听起来不错,但问题是它并没有真正解决导致错误的任何问题。它只是将它们隐藏在一个&#34;让我们希望这是有效的&#34;时尚。就像你说的那样:
我已尝试过以下代码
请尝试理解代码,而不是仅仅提出更多解决方案&#34;在它试图解决&#34;问题。
如果某些内容为dynamic
,那么您应首先找出null
。在您的情况下,null
的结果为MovieClip(parent)
,这意味着投射失败。换句话说: null
不是parent
。
原因很可能是你将子弹添加到舞台上,如下所示:
MovieClip
这是另一种常见的不良做法。问题是stage.addChild(bullet);
不是stage
,你甚至不应该MovieClip
任何东西。为什么这种情况不在这个已经很久的答案的范围内。简短的回答是,您永远不应该向addChild
添加任何标记,只需添加我在上面的代码中添加的内容,而不是stage
。这会将其添加到时间轴。 (不,stage.
不是主时间线)