文章目录

花了几天零碎时间给极风游的新主页 http://dashgame.com 做了一个小游戏,随便起了个名字叫《UFO Story》。(麻球已去,这里放上3366版本,大家支持下……)

传送门:http://www.3366.com/flash/90949.shtml

游戏是受到一个html5小游戏的启发。移动鼠标来控制自己的UFO,躲开敌人的UFO,吃掉能量方块。小创新是,吃掉能量方块到一定分数,可以激活子弹时间,减缓敌人移动速度5秒。吃掉普通蓝色方块得10分,吃掉带D字的绿色方块得20分。

做这个游戏还是又学习了一些新东西。之前一直没做过像素级碰撞检测,刚开始边学边摸索的自己写了个类,结果超过15个敌人就开始卡了。下载了别人写好的一个高效像素级碰撞检测类,发现用起来效率相当不错,1000HE小本上都是40个敌人才开始卡。内存控制方面还不熟悉,很多实现的思路都没太考虑到实际运行情况。不废话了,分享这个类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package

{
//像素级精确碰撞算法优化
//代码:Aone
//2009-10-30
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.geom.ColorTransform;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;

public class PixHitTestH

{

private var tileSize:int = 20

public function PixHitTestH():void
{

}

public function checkObject(target1:DisplayObject, target2:DisplayObject):Boolean
{
//横向缩小到tileSize尺寸需要的倍数,也就是期望检测的时候缩小到的尺寸。
var scaleX:Number = (target1.width < target2.width ? target1.width : target2.width) / tileSize
//纵向缩小到tileSize尺寸需要的倍
var scaleY:Number = (target1.height < target2.height ? target1.height : target2.height) / tileSize
//
//如果倍数小于1则按原始倍率也就是原始尺寸
scaleX = scaleX < 1 ? 1 : scaleX
scaleY = scaleY < 1 ? 1 : scaleY
//draw用point
var pt:Point = new Point()
//做2次draw时使用的颜色
var ct:ColorTransform = new ColorTransform()
ct.color = 0xFF00000F
//原始尺寸下的重叠矩形
var oldHitRectangle:Rectangle = intersectionRectangle(target1, target2)
//用于存放缩放的重叠矩形
var hitRectangle:Rectangle = new Rectangle()
return complexIntersectionRectangle(target1, target2, scaleX, scaleY, pt, ct, oldHitRectangle, hitRectangle, tileSize, tileSize).width != 0;
}

private function intersectionRectangle(target1:DisplayObject, target2:DisplayObject):Rectangle

{

// If either of the items don't have a reference to stage, then they are not in a display list

// or if a simple hitTestObject is false, they cannot be intersecting.

if (!target1.root || !target2.root || !target1.hitTestObject(target2))
return new Rectangle();

// Get the bounds of each DisplayObject.

var bounds1:Rectangle = target1.getBounds(target1.root);

var bounds2:Rectangle = target2.getBounds(target2.root);

// Determine test area boundaries.

var intersection:Rectangle = new Rectangle();

intersection.x = Math.max(bounds1.x, bounds2.x);

intersection.y = Math.max(bounds1.y, bounds2.y);

intersection.width = Math.min((bounds1.x + bounds1.width) - intersection.x, (bounds2.x + bounds2.width) - intersection.x);

intersection.height = Math.min((bounds1.y + bounds1.height) - intersection.y, (bounds2.y + bounds2.height) - intersection.y);

return intersection;

}

private function complexIntersectionRectangle(target1:DisplayObject, target2:DisplayObject, scaleX:Number, scaleY:Number, pt:Point, ct:ColorTransform, oldhitRectangle:Rectangle, hitRectangle:Rectangle, nowW:int, nowH:int):Rectangle

{
if (!target1.hitTestObject(target2))
return new Rectangle();
//根据纵横的缩小倍数来计算缩小的重叠矩形尺寸
hitRectangle.x = oldhitRectangle.x
hitRectangle.y = oldhitRectangle.y
hitRectangle.width = oldhitRectangle.width / scaleX
hitRectangle.height = oldhitRectangle.height / scaleY
//建立一个用来draw的临时BitmapData对象,尺寸为期望宽nowW,期望高nowH
var bitmapData:BitmapData = new BitmapData(nowW, nowH, true, 0);
//绘制对象1其缩放比例和位移量由getDrawMatrix()函数计算,并且把不透明处绘制为ct的颜色
bitmapData.draw(target1, getDrawMatrix(target1, hitRectangle, scaleX, scaleY), ct);
//当纵横缩小比例不为1的时候把任何有色像素重新替换成ct的颜色0xFF00000F,原因为缩小的对象在进行纯色绘制的时候会有半透明像素产生,如果不加以重新替换会影响后面对象2的滤镜效果。
if (scaleX != 1 && scaleY != 1)
{
bitmapData.threshold(bitmapData, bitmapData.rect, pt, \">\", 0, 0xFF00000F)
}
//绘制对象2其缩放比例和位移量由getDrawMatrix()函数计算,并且把不透明处绘制为ct的颜色,并且模式为叠加。如此一来两个对象重叠的部分颜色值必定大于0xFF00000F。
bitmapData.draw(target2, getDrawMatrix(target2, hitRectangle, scaleX, scaleY), ct, BlendMode.ADD);
//把所有颜色值大于0xFF00000F的部分(也就是重叠部分)重新替换为不透明红色方便后面getColorBoundsRect()方法计算尺寸。这里替换的原因是getColorBoundsRect()不支持范围取色而只支持单色计算。
//对象1缩放后可以重新替换掉透明色,但是对象2则无法使用同一方法,但是对象2由于也是经过缩放绘制也会有半透明像素,那么重叠部分虽然全部大于0xFF00000F,但未必是统一的。
var hits:int = bitmapData.threshold(bitmapData, bitmapData.rect, pt, \">\", 0xFF00000F, 0xFFFF0000)
//判断红色区域尺寸
var intersection:Rectangle = bitmapData.getColorBoundsRect(0xFFFFFFFF, 0xFFFF0000);
//

bitmapData = null
//如果红色区域宽度不为0,即bitmapData中含有红色像素。此时说明对象1和对象2在此次判定中有重叠有碰撞
if (intersection.width != 0)
{
//如果纵横缩放比例有任意一个不是原始尺寸
if (scaleX > 1 || scaleY > 1)
{
//并且红色像素的数量比较少,对象1和对象2的碰撞面积比较小的话
if (hits <= (scaleX + scaleY) * 1.5)
{
//由于bitmapData的宽高坐标都是以整数表示,那么经过缩放后取整的区域势必回又可能在取整的时候把真正可能产生碰撞的区域忽略。
//所以要进行下一次检测时候适当的把检测区域扩大xadd和yadd就是这个扩大的系数
var xadd:int = .5
var yadd:int = .5
//下次检测时候bitmapData的期望大小
var nextW:int = tileSize
var nextH:int = tileSize
//如果此次判定发现碰撞区域和bitmapData尺寸相同,那么在计算下次需要判断区域时候会和此次的区域相同,那么判断结果可能会和此次结果相同。这样则会引起堆栈上溢的情况,为了避免该情况发生,将缩小判断的尺寸扩大一倍进行再次检测。
if (intersection.width != nowW)
{
nextW = tileSize
}
else
{
nextW = nowW * 2
}
if (intersection.height != nowH)
{
nextH = tileSize
}
else
{
nextH = nowH * 2
}
//根据检测出来的缩的碰撞区域来计算未缩小的碰撞区域大小以方便下一次计算的时候缩小检测范围。
oldhitRectangle.x += (intersection.x - xadd) * scaleX
oldhitRectangle.y += (intersection.y - yadd) * scaleY
oldhitRectangle.width = (intersection.width + xadd * 2) * scaleX
oldhitRectangle.height = (intersection.height + yadd * 2) * scaleY
//根据检测期望缩小到的尺寸重新计算缩小倍率
scaleX = (oldhitRectangle.width / nextW)
scaleY = (oldhitRectangle.height / nextH)
//如果倍率小于2则直接按原始尺寸
scaleX = scaleX < 2 ? 1 : scaleX
scaleY = scaleY < 2 ? 1 : scaleY
//进行下一次判定
intersection = complexIntersectionRectangle(target1, target2, scaleX, scaleY, pt, ct, oldhitRectangle, hitRectangle, nextW, nextH)
}
}
}

return intersection;

}

private function getDrawMatrix(target:DisplayObject, hitRectangle:Rectangle, scaleX:Number, scaleY:Number):Matrix
{

var localToGlobal:Point;
var matrix:Matrix;
var rootConcatenatedMatrix:Matrix = target.root.transform.concatenatedMatrix;

localToGlobal = target.localToGlobal(new Point());

matrix = target.transform.concatenatedMatrix;

matrix.tx = (localToGlobal.x - hitRectangle.x) / scaleX;

matrix.ty = (localToGlobal.y - hitRectangle.y) / scaleY;

matrix.a = matrix.a / rootConcatenatedMatrix.a / scaleX;
matrix.d = matrix.d / rootConcatenatedMatrix.d / scaleY;

return matrix;

}

}

}

♦ 本文固定连接:https://www.gsgundam.com/archive/2012-07-04-new-game-ufo-story/

♦ 转载请注明:GSGundam 2012年07月04日发布于 GSGUNDAM砍柴工

♦ 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

♦ 原创不易,如果页面上有适合你的广告,不妨点击一下看看,支持作者。(广告来源:Google Adsense)

♦ 本文总阅读量