今次发1个用于实现各种碰撞的组件,和扩展和使用这个组件的代码。
恩- -以前发过1个低版本的,今次更新1下最新的~~。。
首先看个演示吧:
点击浏览该文件
例子中是4种不同的碰撞模型:hitArea检测,ball,plane,point
文件包
点击浏览该文件
包内物品简介- -:
例子文件包括example.fla example.swf组件文件reflector.swc
类声明包为目录xp
4个组件应用代码和付赠1块logo
reflector组件中包装了用于实现碰撞的基类xp.gameLib.reflect.Reflector(和其他很多个class- -)
xp.gameLib.reflect.Reflector实现了追踪检测的目标,纪录数据等功能,而碰撞检测的具体功能由用户编写自己的代码实现。这次的dd里包含了4个已经实现好的比较常用的碰撞:
点对hitArea的碰撞检测;
点对球形物体的碰撞;
点对平板的碰撞;
点对点的碰撞;
分别对应4个as文件:
HitAreaReflector.as
ArcReflector.as
PlaneReflector.as
PointReflector.as
碰撞模型简介
和上次发的东西类似,碰撞的使用不需要用户进行更多的操作,只需要处理由reflector发出的事件即可。
点对hitArea的碰撞适用于很少的环境,因为reflector设计的目标是精确的碰撞计算,使用hitArea就失去了意义。这里只是给个例子。。= =
点对球的碰撞中,ArcReflector创建了1个圆形的区域,并计算运动的点与这个园的碰撞,并根据结果发出相应的事件。
点对平面的碰撞中,PlaneReflector创建1个条线来检查穿过这条线的运动的点。
点对点的碰撞中,PointReflector创建1个有1定有效范围的点,来检测运动的点与它的碰撞
数学计算虽然增加了精确度,但也使程序变慢。这几个模型适用于碰撞较少的场合,支持超高速运动而不会发生穿过的情况。
使用组件的代码范例
包内的as文件是组件的实用示例。这个组件没有提供什么实际功能,只是包装几个class的功能。虽然放在场景中也会显示出参数面板。。。- -。表被迷惑。。
组件包装的主要的1个类是xp.gameLib.reflect.Reflector,也就是我们需要继承的类。其他还有很多零碎。
每个as文件都是1个类,他们都继承于xp.gameLib.reflect.Reflector,每个类需要实现2个主要的函数来实现碰撞功能:
collisionCalculate
被系统调用,用于计算碰撞,参数给出了待检测的点的信息,用户实现这个函数计算碰撞,并需要返回1个boolean值表示是否发生了碰撞。update
更新数据用。当系统需要更新数据时,调用这个函数。
可以翻看包内的几个as文件,具体用法后面说。。
使用方法:
由于实现这个组件的代码比较分散,所以用组件的形式包装了所有需要用到的类,10分类似于jar文件呢~~
- 将reflector.swc拷贝到C:\Documents and Settings\xp\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Components
目录下,并在component面板上reload组件,可以看到reflectorBaseClass这个组件,说明可以正常使用。 - 新建1个fla文档,将reflectorBaseClass组件拖入场景中,并删除。这时它会保存在库中,并在发布时存在于swf中,组件中的类就都可以在这个swf中使用了~。
- 然后新建1个as类文件,来实现具体的碰撞功能。可以参考包中给出的4个例子。都是经过测试的~。
- 然后回到fla文档,新建1个元件名为ref,并连接到刚刚建立的类,例如连接到HitAreaReflector.as。
现在ref元件就具有碰撞检测的功能了。
接着加些其他东西,写几个代码。完成测试文件制作。。都是很简单的东西。。看源文件吧。。木多说了
关于调试
在编辑as类的时候,语法检查需要用到Reflector这个基类,以及其他1些类的声明,但是这些类只有在编译发布fla文件时才可见,编辑.as文件时还无法找到swc组件中的类来用。
所以在单独编辑譬如ArcReflector文件时会提示找不到Reflector文件(Reflector在swc中,这里看木到- -)。
为了能够进行语法检查,必须在类的目录下声明这些类的形式,类似于C:\Documents and Settings\xp\Local Settings\Application Data\Macromedia\Flash MX 2004\en\Configuration\Classes中的intrinsic类的声明。
这里偶也用了intrinsic类来声明已经存在于swc中的类。它们保存在xp文件夹内。用户在使用的时候可以把xp文件夹拷贝到系统class目录中,或当前项目目录。
当系统可以找到这些intrinsic的类时,就会根据这些类的声明进行语法检查,而当发布swf时,系统会忽略掉所有intrinsic的类的声明,结果就是转而使用swc中的类咯~
评测
优点:
- -。。使用简单。。不知道别人是不是也认同自己呢-"-。。
数学运算,不会出现速度过快会穿过的bug。。恩。也因此会变慢。。
事件模型,方便耐用。- -。。
缺点:
可能会有些慢,因为用了不少运算和函数调用。一直本着'自己解决技术问题,期待cpu升级来解决效率问题'的原则作的- -。。效率和便捷总是不能两全阿。。- -
每个Reflector实例保存所有需要检测碰撞的mc的数据。只适合像玛利那种板子多,目标少的环境了。。
显示和计算的不同步:虽然计算都是准确的,但却经常显示出本应在物体外的点被拉到物体内(但实际位置还是在外面的),例子中可以看到。这是因为计算碰撞的onEnterFrame调用出现在处理点运动的onEnterFrame之前。可以通过只使用1个onEnterFrame来解决。具体见后。
[插嘴]
貌似组件总是不太受欢迎,恩- -。偶本人也不是很喜欢用别人写的组件,除非已经对那个组件的结构10分了解了。。不知道那个人的coding习惯,不知道他使用了哪些变量名所以我不能再用,万一遇到bug想调试更是让人受不了。。
所以这个组件也就不大肆宣传了。。卡卡,把代码拿出来当作1次研究咯~。。- -。。恩,所有代码是前后老长时间内写的,没咋设计过。可能乱了点。。哈哈。
函数接口
function collisionCalculate (v1, v2,ins,result):Boolean
这个是用户继承Refelctor类首先要实现的1个函数,在这个函数里要实现碰撞的运算,参数有4个:
v1:{x:0,y:0};v2:{x:0,y:0};
ins:MovieClip;
result:{x0:0,y0:0,vvx:0,vvy:0}
v1和v2是两个坐标参数,表示被检测物体的上1帧位置和当前帧位置。
ins是被检测mc的实例引用。
result用于保存计算的结果,(x0,y0)是碰撞发生的位置。(vvx,vvy)是碰后的速度矢量。
所有坐标都是用this内的坐标系。
最后要返回1个boolean表示是否发生了碰撞。
function update ()
用于刷新数据,在构造函数中被调用1次。
Reflector代码
//
//on(collide) or onCollide
//on(passed) or onPassed
//on(hit) or onHit
[Event("collide")]
[Event("passed")]
[Event("hit")]
class xp.gameLib.reflect.Reflector extends MovieClip implements Reflector_itf{
//
static var __xp__init__EventDispatcher = xp.events.SimpleEventDispatcher.initialize (Reflector.prototype);
function dispatchEvent(eventObj:Object):Void{}
function addEventListener(event:String, handler):Void{}
function removeEventListener(event:String, handler):Void{}
//
//broadcaster for test collision/refresh.
private static var __testCollisionBroadcaster:xp.gameLib.reflect.ReflectorBroadcaster=undefined ;
//
//
//event list:
private var __f_hit:Function;
private var __f_collide:Function;
private var __f_passed:Function;
//
var onHit:Function;
var onCollide:Function;
var onPassed:Function;
//
//list of mc which will be test
private var testList:Array;
//
//
//
//component parameters for config this plane,& also could be set in runtime.
//
//
//visual effect clip’s linkage id.
[Inspectable(defaultValue="",type="String")]
var clipName:String = "ef";
//
var clipIns:MovieClip;
//
//if it is a double side plane.
[Inspectable(defaultValue=false,type="Boolean")]
var doubleSide:Boolean = false;
//
//
//friction:
//
//f>0;
//0:+oo friction
//1:no friction;
[Inspectable(defaultValue=0,type="Number")]
var f:Number = 0;
//
//
//elasticity:
//
//0:no elasticity,object will be sticked after collision.
//>0:reflect after collision;
//>1:speed up & reflect.
//<0:get through,but slow down.
//<-1:get through,and speed up.
[Inspectable(defaultValue=0,type="Number")]
var e:Number = 0;
//
//u could add a force to a mc while it touch it.
[Inspectable(defaultValue=0,type="Number")]
var xForce = 0;
//
[Inspectable(defaultValue=0,type="Number")]
var yForce = 0;
//
//
//
var _enabled:Boolean = true;
//
function set enabled (e:Boolean) {
_enabled = e;
//
//update old position record:
if (e) {
for (var i = 0; i < testList.length; i++) {
var o = testList[i];
//remove dead links.
if (o.ins == undefined) {
testList.splice (i, 1);
i--;
continue;
}
//new position
o.v1.x = o.ins._x;
o.v1.y = o.ins._y;
//
o.ins._parent.localToGlobal (o.v1);
this.globalToLocal (o.v1);
}
}
}
function get enabled(){
return _enabled;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function Reflector () {
super ();
//
testList = new Array ();
//
//create visual effect clip
if (clipName==undefined || clipName=="") clipName="ef";
clipIns= this.attachMovie (clipName, "1", 1);
//
if (!__testCollisionBroadcaster)
{
__testCollisionBroadcaster = new xp.gameLib.reflect.ReflectorBroadcaster()
}
__testCollisionBroadcaster.addChildListener (this);
//
this.addEventListener ("onHit", this);
this.addEventListener ("onCollide", this);
this.addEventListener ("onPassed", this);
//
update ();
}
//
function addTarget (o:MovieClip) {
testList.push ({ins:o, v1:{x:0, y:0}, v2:{x:0, y:0}});
this.addEventListener ("onHit", o);
this.addEventListener ("onCollide", o);
this.addEventListener ("onPassed", o);
}
//
function removeTarget (o:MovieClip) {
for (var i = 0; i < testList.length; i++) {
if (testList[i].ins == o) {
testList.splice (i, 1);
}
}
}
//
function resetPosition(p:MovieClip)
{
for (var i = 0; i < testList.length; i++) {
if (testList[i].ins == p) {
var o=testList[i];
//new position
o.v2.x = o.ins._x;
o.v2.y = o.ins._y;
//
o.ins._parent.localToGlobal (o.v2);
this.globalToLocal (o.v2);
return;
}
}
}
//
function testCollision () {
if (!_enabled) {
return;
}
//
for (var i = 0; i < testList.length; i++) {
var o = testList[i];
//remove dead links.
if (o.ins == undefined) {
testList.splice (i, 1);
i--;
continue;
}
var re:Object;
//new position
o.v2.x = o.ins._x;
o.v2.y = o.ins._y;
//
o.ins._parent.localToGlobal (o.v2);
this.globalToLocal (o.v2);
//
re=new Object();
var flag:Boolean=collisionCalculate (o.v1, o.v2,o.ins,re);
//
this.localToGlobal (o.v2);
o.ins._parent.globalToLocal (o.v2);
if (flag)
{
//calculate result position, in MC’s own coordinates
var rp={x:re.x0+re.vvx,y:re.y0+re.vvy};
this.localToGlobal(rp);
o.ins._parent.globalToLocal(rp);
//calculate collision position,in MC’s own coordinates.
var rp0={x:re.x0,y:re.y0};
this.localToGlobal(rp0);
o.ins._parent.globalToLocal(rp0);
//get velocity.
rp.x-=rp0.x;
rp.y-=rp0.y;
//event dispatching:
//clip event & onXXX event.
//
this.__f_hit ();
this.dispatchEvent ({type:"onHit", position:{x:o.v2.x,y:o.v2.y},hitPosition:{x:re.x0,y:re.y0},velocity:{x:re.vvx,y:re.vvy},rv:{x:rp.x,y:rp.y}});
//
if (e >= 0) {
this.__f_collide ();
this.dispatchEvent ({type:"onCollide", position:{x:o.v2.x,y:o.v2.y},hitPosition:{x:re.x0,y:re.y0},velocity:{x:re.vvx,y:re.vvy},rv:{x:rp.x,y:rp.y}});
}
else {
this.__f_passed ();
this.dispatchEvent ({type:"onPassed", position:{x:o.v2.x,y:o.v2.y},hitPosition:{x:re.x0,y:re.y0},velocity:{x:re.vvx,y:re.vvy},rv:{x:rp.x,y:rp.y}});
}
}
//record old position for next test.
o.v1.x = o.ins._x;
o.v1.y = o.ins._y;
o.ins._parent.localToGlobal (o.v1);
this.globalToLocal (o.v1);
}
// updateAfterEvent();
}
//
//
//v1 / v2 are objects with properties ’x’ & ’y’,in this coordinates
function collisionCalculate (v1, v2,ins,result):Boolean {
//Vx
result.vvx=0;
//Vy
result.vvy=0;
//X
result.x0=0;
//Y
result.y0=0;
return false;
}
//re-calculate reflector data.
function update()
{}
}
