阅读新闻阅读所有新闻

[原创] 在Flash 8 上做基于路径的碰撞检测

作者:精品Flash                                           来源:精品Flash                                    文章类别:本站原创

欢迎转载本站文章,但是转载必须注明出处,并且保留文章中的所有链接,谢谢支持!

本文属于路径判断的基础知识,适合有志于游戏开发的入门者参考(其实本人也只是刚刚接触这方面知识)。文中涉及的知识包括:

基本的ActionScript,初中的一次函数知识,还有一个简单的数学模型。

在游戏里边,据说,2D游戏的碰撞检测是最成熟最稳定的,不过,我还是希望这篇文章能对一些对Flash游戏感兴趣的“闪友”能有点参考价值,如果有幸能对您有点帮助,就上我们网站来捧一捧场:)http://www.exflash.cn

一、数学模型

本人比较孤陋寡闻,不知道这种方法有没有人用过了,更不知道这种做法会不会造成效率较低、复杂度比较高,如有高人,请多加指点。

首先,在这里,我们先假设多边形都是突的,不会有凹多边形的情况。其次,我们把多边形的的边看成是有向边,假设坐标X轴正方向与边重合,定义向右,向上为正,由此可以得出,一个凸多边形里边,各点都是各坐标系的负轴。如下图所示:

这样,我们碰撞的判断可以归结为:点与有向边的距离是否为0?

这样,我们就引出了,如何求点到一直线的距离?哦,这是初中的知识,公式就在下面:

假设直线为:

A * X + B * Y + C = 0

则距离为:

d = (A * X + B * Y + C)/sqrt(A * A + B * B)

d代表距离,我们没有给右边加上绝对值是因为我们假定了距离也是有方向。

根据这个模型,对多边形的每条边做一次计算就可以得到,物体是否落在了该多边形内了。

二、实践演练

首先,我们建立两个多边形,并且根据该原理作出碰撞检测。具体代码如下:

import flash.geom.Point;

stop();

cut = 1;
var BorderArr1:Array = new Array();                         //定义第一个多边形各顶点
BorderArr1[0] = new Point(10, 10);
BorderArr1[1] = new Point(180, 10);
BorderArr1[2] = new Point(180, 180);
BorderArr1[3] = new Point(10, 180);

var BorderArr2:Array = new Array();                         //定义第二个多变形各顶点
BorderArr2[0] = new Point(310, 110);
BorderArr2[1] = new Point(480, 110);
BorderArr2[2] = new Point(480, 280);

var BorderArr3:Array = new Array();                        //定义第三个多边形各顶点,该多边形是该Flash文档的外框。
BorderArr3[0] = new Point(0, 0);
BorderArr3[1] = new Point(550, 0);
BorderArr3[2] = new Point(550, 400);
BorderArr3[3] = new Point(0, 400);

 

//Begin 画出前两个多边形的形状


_root.lineStyle(1, 0xFF0000, 100);
for(i=0;i<BorderArr1.length;++i)
{
 if(i==0)
 {
  _root.moveTo(BorderArr1[i%BorderArr1.length].x, BorderArr1[i%BorderArr1.length].y);
  _root.lineTo(BorderArr1[(i+1)%BorderArr1.length].x, BorderArr1[(i+1)%BorderArr1.length].y);
 }
 else
  _root.lineTo(BorderArr1[(i+1)%BorderArr1.length].x, BorderArr1[(i+1)%BorderArr1.length].y);
}

for(i=0;i<BorderArr2.length;++i)
{
 if(i==0)
 {
  _root.moveTo(BorderArr2[i%BorderArr2.length].x, BorderArr2[i%BorderArr2.length].y);
  _root.lineTo(BorderArr2[(i+1)%BorderArr2.length].x, BorderArr2[(i+1)%BorderArr2.length].y);
 }
 else
  _root.lineTo(BorderArr2[(i+1)%BorderArr2.length].x, BorderArr2[(i+1)%BorderArr2.length].y);
}

//End 画出前两个多边形的形状


r = ball._width/2;

//该函数检测点与直线的距离是否比rd(小球半径)小?

function HitTest(px, py, rd, arr, isin)
{
 for(i=0;i<arr.length;++i)
 {
  A = arr[(i+1)%arr.length].y - arr[i%arr.length].y;
  B = arr[i%arr.length].x - arr[(i+1)%arr.length].x;
  C = arr[(i+1)%arr.length].x * arr[i%arr.length].y -
   arr[i%arr.length].x * arr[(i+1)%arr.length].y;
  d = (A * px + B * py + C)/Math.sqrt(A*A + B*B);
  if((d - rd) > 0)
  {
   return false;
  }
 }
 return true;
}

onEnterFrame = function()
{
 //先算出与各个边的距离
 canmove = true;
 if(Key.isDown(Key.LEFT))
 {
  pX = ball._x - 5;
  pY = ball._y;
  if(!HitTest(pX, pY, r, BorderArr1) &&
     !HitTest(pX, pY, r, BorderArr2) &&
     HitTest(pX, pY, -r, BorderArr3))
  {
   ball._x = pX;
  }
 }

 if(Key.isDown(Key.RIGHT))
 {
  pX = ball._x + 5;
  pY = ball._y;
  if(!HitTest(pX, pY, r, BorderArr1) &&
     !HitTest(pX, pY, r, BorderArr2) &&
     HitTest(pX, pY, -r, BorderArr3))
  {
   ball._x = pX;
  }
 }

 if(Key.isDown(Key.UP))
 {
  pX = ball._x;
  pY = ball._y - 5;
  if(!HitTest(pX, pY, r, BorderArr1) &&
     !HitTest(pX, pY, r, BorderArr2) &&
     HitTest(pX, pY, -r, BorderArr3))
  {
   ball._y = pY;
  }
 }

 if(Key.isDown(Key.DOWN))
 {
  pX = ball._x;
  pY = ball._y + 5;
  if(!HitTest(pX, pY, r, BorderArr1) &&
     !HitTest(pX, pY, r, BorderArr2) &&
     HitTest(pX, pY, -r, BorderArr3))
  {
   ball._y = pY;
  }
 }
}

写好了这些,我们可以预览一下:

注:用方向键移动圆球

 

  可以看到,小球是走不到那两个红线框里边的。其实还有一个框,大小跟影片一样,没有画出来,不过,你试试就知道,小球是走不出可视区外面的。

好的,接下来再看一个例子,看看我们学到的这些能有什么实用价值:

注:用方向健移动船

 

教程原文件下载:

第一个示例

第二个示例

如有任何疑问,可以到我们主站:精品Flash 上面提问。

 

添加时间2007-7-2 11:28:34 共被阅读:6734 次
类别索引