过去几天,我一直在考虑一种方法,以避免需要编写大量代码,并且仍然保持我正在开发的Air桌面游戏的良好性能,作为业余爱好。
游戏是一种垂直射击游戏,由几个移动和检查碰撞的实体组成。有很多不同类型的单位。每一帧我有类似的东西:
entity.execute();
更简单的方法是让所有不同的实体继承Entity类,并手动自定义它们。这是缓慢而繁琐的,并且难以维护。但它快速,性能明智。
另一种方法是只有一个Entity类,只使用某种组合来简单地添加“行为”。因此,例如,我有一个大师类,其中包含类型的移动,攻击等,并且不同的实体使用它们。
这种方法的问题是,调用函数很慢,根据我的测试,它比只需要代码(在execute()内部)慢约3倍。
我处于两难境地,我无法找到重用代码块来装饰通用实体实例的方法,并保持良好的性能。好像我必须使用其中一个。
我尝试使用[内联],但我读过它不是一个稳定的功能,我没有看到任何明显的性能提升,但我没有测试它。
感谢任何见解。
答案 0 :(得分:2)
通过继承进行抽象是一种很好的面向对象模式,我认为维护它并不缓慢或繁琐。关注点的分离会增加继承基本Entity类的类的清晰度;同样,减少复制的代码。接口将进一步抽象具体类型。
ActionScript不支持您可能在C#等语言中找到的强大的面向对象语言功能 - 没有抽象基类,没有部分类,有限的模板/泛型,有限的多态性。组合和装饰器模式可能会强制使用动态类,这也会因类型检查而减慢运行时间。
也许更大的问题是Entity类中的业务逻辑太多。我认为一些世界容器或控制器将负责碰撞检测。
你可以考虑的是像Box 2D这样的物理引擎。
Box2D的端口采用CrossBridge(以前称为Alchemy,FlasCC)构建,它是AVM2的C ++编译器,能够通过精益优化的字节码运行Flash,速度高达10倍,该字节码具有Flash的高性能内存访问操作码(称为域内存。)
这就是Angry Bots或Neverball之类的游戏。
如果使用AS3物理引擎听起来很有趣,请查看Jesse Sternberg的Box2d Flash Alchemy Port + World Construction Kit。
答案 1 :(得分:1)
在游戏开发中有一些加速闪存的常用方法。其中之一是避免使用显示对象,而选择简单的位图。在这种情况下,您将舞台作为位图,并将所有游戏状态保存在轻量级对象中,然后定期将游戏状态快照绘制到该阶段位图数据(带copyPixels
)中(在输入框架上,或者在计时器上)
示意图:说你有一个单位游戏
class PseudoSprite {
public var x:uint;
public var y:uint;
public var currentAnimFrame:uint;
protected var snapshotCreator:AbstractSnapshotCreator;
public function makeSnapshot():BitmapData {
return snapshotCreator.createSnapshot(currentAnimFrame);
}
....
}
class Unit extends PseudoSprite {
public var directionAngle:Number = 0;
public var speed:uint = 0;
function Unit() {
snapshotCreator = UnitSnapshotCreator.instance;
}
public function doStep():void {
x = //count x by speed and direction
y = //count y by speed and direction
animationFrame++;
}
}
class Game {
public var stage:Bitmap;
private var objects:Vector.<PseudoSprite> = new <PseudoSprite>[
new Unit(), new Unit()];
public function step() {
for each (var unit:PseudoSprite in objects) {
unit.doStep();
//draw unit.snapshot() to the stage bitmap data
}
}
}
所以,您可以看到:您可以使用普通OOP构建整个单元(或所有游戏对象)层次结构,并获得一些合适的性能。
答案 2 :(得分:-2)
经过一些测试后,我发现我可以做以下事情:
public var foo:Function;
然后当我创建实体时,我可以:
entity.foo = myCustomFoo;
然后在主循环中我可以:
entity.foo();
这与在Entity实例中调用本机成员函数一样高效。警告,不要创建一个getter来访问你的函数,它变得慢很多。