点阵土
2009-10-13 23:11 宝宝合凤凰 阅读(374) 评论(0) 编辑 收藏 举报
根据输入的内容,利用bitmap的象素值判断文字所占用的区域,生成对应的点阵图 http://www.sanag.com.cn/html/teach/flash/2009/0629/1011.html
代码如下: ///bitmap的高和宽
var b = 200; var b2 = 550; //区域大小 var size = 4; // var s:Shape = new Shape(); s.y = b; addChild(s); // cau(null); stage.focus = t; // t.addEventListener(’change’,cau); //计算并绘制 function cau(e) { var bmd:BitmapData = new BitmapData(b2,b); bmd.draw(root); s.graphics.clear(); for (var i=0; i<b2; i+=2*size) { for (var j=0; j<b; j+=2*size) { if (isB(i,j,bmd)) { s.graphics.beginFill(int(Math.random()*0xffff00),1); s.graphics.drawCircle(i,j,size/2); s.graphics.endFill(); } } } } //计算当前区域是否需要画点,条件是在size*size的区域内有5个象素不是空白 function isB(a,b,bmd) { var c = 0; for(var i=0;i<size;i++) for (var j=0; j<size; j++) { if(bmd.getPixel(a+i,b+j)==0)c++; } if(c>5)return true; return false; } /// 源文件(flash cs3格式):
|
第一次在fanflash上看到这个实例,感觉很不可思议
仔细研究一下发现,作者的构思还是很巧妙的,今天拿来与大家分享一下
这个实例可以说结合了BitmapData类的技术与Tween类的动感。
思路:
1.用AS创建一个空文本框,存储欲显示的字;
2.把这个文本框看成一个位图,并存储其位图数据;
3.逐行扫描这个位图数据,把有文字信息的像素点都存储到数组中;
4.最后根据数组复制出"点",并使每个"点"移动到相应的位置。
步骤1:
绘制10*10的圆点,保存为影片剪辑,连接—>导出—>标志符"dot"
步骤2:
加入AS代码:
import flash.display.BitmapData;
import mx.transitions.Tween;
import mx.transitions.easing.*;
//导入BitmapData及Tween类
_root.createTextField("txt", -1, -100, -100, 0, 0);
txt.autoSize = true;
txt.text = "输入要显示的文字";
//创建一个空的文本框,存储输入的文本
var bm:BitmapData = new BitmapData(txt._width,txt._height, false, 0xffffff);
bm.draw(txt);
//把txt看成位图,并把txt位图信息存入mb
var DotArray:Array = new Array();
//申请一个数组用于存储mb位图信息
var w:Number = 4;
var h:Number = 4;
//w,h分别为点间宽度和高度
for (y=0; y<txt._height; y++) {
for (x=0; x<txt._width; x++) {
if (bm.getPixel(x, y) != 0xffffff) {
DotArray.push({x:x*w, y:y*h});
//逐行逐列取像素,把有字的像素位置存入数组并乘上w,h以扩展距离
}
}
}
_root.createEmptyMovieClip("MC", -1);
MC._x = 10;
MC._y = 150;
//============根据数组复制"点"===============
for (var i = 0; i<DotArray.length; i++) {
var p = MC.attachMovie("dot", "dot"+i, i);
p.cacheAsBitmap = true;
//将"点"进行位图缓存
p._x = Math.random()*Stage.width;
p._y = Math.random()*Stage.height;
//给每个"点"一个随机的起点
p.tox = DotArray[i].x;
p.toy = DotArray[i].y;
//tox,toy是每个点要移动到的终点
var speed = Math.random()*4
new Tween(p, "_x", Back.easeOut, p._x, p.tox, speed, true);
new Tween(p, "_y", Back.easeOut, p._y, p.toy, speed, true);
//利用Tween类,让每个"点"移动到他们的终点坐标
}
Flash充电:MovieClip.cacheAsBitmap 属性
1.作用:如果设置为 true,则 Flash Player 将缓存影片剪辑的内部位图表示。这可以提高包含复杂矢量内容的影片剪辑的性能。
2.原理:矢量图体积小,但比较消耗计算资源;位图则比较消耗内存资源,但对计算资源消耗小。
3.简单地说:cacheAsBitmap就是把矢量图转化成位图;节省CPU,但消耗内存,可以提高对于矢量图的运算速度。
4.注意:cacheAsBitmap最适用于包含大量静态内容,并不需要频繁scale和旋转的MC里。
5.默认:当你添加filter(滤镜)到MC上,cacheAsBitmap自动设置为true,这点即使你强行让cacheAsBitmap=false也改变不了。只有当你去掉filter,cacheAsBitmap将返回最新被设置的逻辑值。
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/octverve/archive/2008/02/12/2088991.aspx
=====================================================================
文字点阵和TweenMax的应用以及对象的深度排序
http://www.cnblogs.com/niuniuzhu/archive/2008/08/08/1263343.html
首先说声不好意思,本人太懒,借Roxik大师的头像用一下。
首先从文本输入框获得bitmapData
var bitmapData:BitmapData = new BitmapData(text.textWidth + 3, text.textHeight + 3); //预留3个象素,以避免文字绘制不全
bitmapData.draw(text);
new DataMap(bitmapData, mainCnt.width, mainCnt.height);
这里涉及到一个DataMap类。这个类用来处理放大bitmaoData,并且用一个数组保存所有坐标。
for (var i:int = 0; i < resW; i ++)
{
for (var j:int = 0; j < resH; j ++)
{
if (bitmapDataText.getPixel(i, j) < 0x111111)
dataMap.push({x:i * scale, y:j * scale}); }
}
在完成了以上工作后,开始addChild的操作。
for (var i:int = 0 ; i < dataMap.length; i ++)
{
var mc:MovieClip = loading.mc;
var c:Character = new Character();
c.ID = i;
c.mc = mc;
c.x0 = mc.x;
c.y0 = mc.y;
c.x1 = dataMap[i].x;
c.y1 = dataMap[i].y;
addChild(mc);
addList.push(c);
c.startRender();
}
我们创建dataMap.lenght个MC,并添加到容器。Character是存放每个角色信息的类,包括了ID、开始坐标、结束坐标。注意,最后把这个类放进一个addList的数组,作用下面会说明。最后,我调用了Character类的startRender方法,但这个角色被添加到容器后,就开始移动了。我们看看里面的东西。
public function startRender():void
{
if (pathList)
{
pathList.reverse();
mc.addEventListener(Event.ENTER_FRAME, onRendering);
}
else
{
pathList = [];
trail = {x:x0, y:y0};
var trailList:Array = [{x:x0 + (x1 - x0) * Math.random(), y:-100}];
TweenMax.to(trail, ID * .025 + 2, {x:x1, y:y1, bezier:trailList, onUpdate:onTweenUpdate, ease:Linear.easeIn});
TweenMax.delayedCall(.3, function():void { mc.addEventListener(Event.ENTER_FRAME, onRendering); });
}
}
private function onTweenUpdate():void
{
pathList.push({x:Number(trail.x).toFixed(2), y:Number(trail.y).toFixed(2)});
}
先看else,新建一个trail对象,利用tweenMax,把这个对象从MC的开始坐标,移动到结束坐标。第二个tweenMax作用是延时0.3秒执行MC的移动,延时是为了不让MC“追上"了trail,让MC跟着trail的轨迹走。到这里,可能你会提出一个问题,为什么直接让MC tween呢?因为在这个MC里,定义了13个方向,我们需要知道它现在需要面向的方向,也就是需要知道往后的坐标值。因此必须用一个对象作为"导航"。
再来看看onRendering里面的东西
if (c % 3 == 0)
{
var cc:int = c + 3, l:int = pathList.length - 1;
cc = cc > l ? l : cc;
getDirection(pathList[cc].x, pathList[cc].y);
}
mc.x = pathList[c].x;
mc.y = pathList[c].y;
if (++c == pathList.length)
{
c = 0;
if (mc.scaleX < 0)
mc.scaleX *= -1;
mc.gotoAndStop("yaoshou");
mc.removeEventListener(Event.ENTER_FRAME, onRendering);
mc.dispatchEvent(new Event(MC_END_MOVING));
}
为了减少CPU的负荷,我设了每3步取一次方向,每次以3步后的坐标值来决定现在的方向。然后开始按照trail的轨迹来走。如果走到了最后,向外抛出事件。
在用户输入文本并提交后,在容器里还存在上一次的MC,该如何处理?我们必须让他们按照原来的路径返回到起点,然后removeChild。回来上面提到的addList列表,当用户点击按钮后,我们先把addList里面的东西,复制到removeList列表,然后清空addList列表(说一个题外话,清空Array用array.length = 0是最高效率的 - -!)。然后再调用一次Character类的startRender方法。看到上面startRender的if(pathList),由于上一次移动后,路径并没有被清空,所以当这个列表不为null,表明这个MC需要被移走了。然后把这个列表倒置一下,按照刚才所说的方法移动MC,那么在容器里的MC就按照原路径返回了。
这里做一个小效果,当旧MC在移走的过程中,新的MC就在指定时间后开始创建并移动。我们还是利用TweenLite的delayCall方法,延时指定时间后,开始创建新的MC,并添加到addList(注意,之前addList已经被清空了)。这就开始了新的一轮跑动了。就这样周而复始吧。
最后说一下对象的深度排序问题。其实并不复杂。在这个例子里,为了减少CPU的负荷,我并没有在EnterFrame里面采用排序,我只选择了当MC走到指定位置后,才进行一次排序。先看一下排序的代码。
var dep_arr:Array = [];
for (var i:int = 0; i < addList.length; i ++)
{
dep_arr.push({mc:getChildAt(i), l:MovieClip(getChildAt(i)).y});
}
dep_arr.sortOn("l", Array.NUMERIC);
for (i = 0; i < dep_arr.length; i ++)
{
var mc:MovieClip = dep_arr[i].mc;
setChildIndex(mc, i);
}
这里不作说明了,简单易懂。
如果你有更好的想法、算法和意见,可以和本人联系,或共同讨论。
Preview:http://niuniuzhu.cn/p/ActiveWord/Main.html
Capture:
===============================================================
在这里先介绍一个十分好用的loader类—BulkLoader,这是它的API文档。它能把管理所有需要加载的文件,并支持多种加载类型,加载后可以直接从类中得到各类型的实例,十分方便。这里有官方的一个使用例子。
- import br.com.stimuli.loading.BulkLoader;
- / /instantiate a BulkLoader with a name : a way to reference this instance from another classes without having to set a expolicit reference onon many places
- var bulkLoader : BulkLoader = new BulkLoader("main loading");
- // add items to be loaded
- bulkLoader.add("my_xml_file.xml");
- bulkLoader.add("main.swf");
- // you can also use a URLRequest object
- var backgroundURL : URLRequest = new URLRequest("background.jpg");
- bulkLoader.add(backgroundURL);
- // add event listeners for the loader itself :
- // event fired when all items have been loaded
- bulkLoader.addEventListener(BulkLoader.COMPLETE, onCompleteHandler);
- // event fired when loading progress has been made:
- bulkLoader.addEventListener(BulkLoader.PROGRESS, _onProgressHandler);
- // start loading all items
- bulkLoader.start();
- function _onProgressHandler(evt : ProgressEvent) : void{
- trace("Loaded" , evt.bytesLoaded," of ", evt.bytesTotal);
- }
- function onCompleteHandler(evt : ProgressEvent) : void{
- trace("All items are loaeded and ready to consume");
- // grab the main movie clip:
- var mainMovie : MovieClip = bulkLoader.getMovieClip("main.swf");
- // Get the xml object:
- var mXML : XML = bulkLoader.getXML("my_xml_file.xml");
- // grab the bitmap for the background image by a string:
- var myBitmap : Bitmap = bulkLoader.getBitmap("background.jpg");
- // grab the bitmap for the background image using the url rquest object:
- var myBitmap : Bitmap = bulkLoader.getBitmap(backgroundURL);
- }
- // In any other class you can access those assets without having to pass around references to the bulkLoader instance.
- // In another class you get get a reference to the "main loading" bulkLoader:
- var mainLoader : BulkLoader = BulkLoader.getLoader("main loading");
- // now grab the xml:
- var mXML : XML = mainLoader.getXML("my_xml_file.xml");
- // or shorter:
- var mXML : XML = BulkLoader.getLoader("main loading").getXML("my_xml_file.xml");
回到正题,我们看看如何实现粒子的散落效果。首先我们在3D场景添加一块地板
- var cm:ColorMaterial = new ColorMaterial(0x212121, 1);
- floor = new Plane(cm, 1100, 1100, 1, 1);
- floor.rotationX = 90;
- floor.y = -550;
- scene.addChild(floor);
然后添加粒子阵,damp属性为碰撞后质量损失的值
- pixels = new MotionPixels(bfx, floor);
- pixels.damp = 0.4;
- scene.addChild(pixels);
在这个粒子阵里添加粒子
- var offsetX:int = int(bmd.width * .5 * intervalIn / intervalOut);
- var offsetY:int = int(bmd.height * .5 * intervalIn / intervalOut);
- var m:int = 0, n:int = 0;
- for (var i:int = bmd.height; i > 0; i -= intervalOut)
- {
- for (var j:int = 0; j < bmd.width; j += intervalOut)
- {
- var color:uint = bmd.getPixel32(j, i);
- if (color > 0) pixels.addPixel3D(new MotionPixel(color, n - offsetX, m - offsetY, 0));
- n += intervalIn;
- }
- n = 0;
- m += intervalIn;
- }
我们看看这个MotionPixel类
- public function MotionPixel(color:uint, x:Number=0, y:Number=0, z:Number=0)
- {
- super(color, x, y, z);
- weight = int(Math.random() * 35 + 5);
- radomXYZ();
- sx = x;
- sy = y;
- sz = z;
- }
- public function radomXYZ():void
- {
- vx = int(Math.random() * 60 - 30);
- vy = 0;
- vz = int(Math.random() * 60 - 30);
- }
在构造函数里,每个粒子都拥有初始位置,初始速度和重量。设置X和Z的初始速度目的为了有“分散”的效果,总不能让粒子都落在一条直线上吧。而重量则是决定在粒子Y方向速度的因素。
我们看看最重要的一个类MotionPixels类。里面包括了所有粒子的分散和聚合算法。有深入了解PV3D的朋友都知道所有继承了DisplayObject3D类的子类都可以override project方法。这个方法是pv3d里面重要的渲染方法之一。我们在这里面加上两个函数,让粒子在渲染到屏幕之前进行排列。
- if (isBreaking) startBreakUp(p);
- if (isGrouping) startGroup(p);
我大概说一下算法的原理,由于粒子拥有初速度vx0,vy0,vz0,其中vx0,vz0我们不用改变,它们是粒子能够分散到四周的重要条件。看看vy0,初速度我为0,假设粒子和地板之间的距离为d,有这样一个公式vy -= dy * p.weight * .004,当距离越远,加速度就越大,这个不难理解。当粒子和地板发生碰撞,也就是d=0的时候,vy改变方向:vy *= -1。并且vx,vy,vz都会损失速度vx *= _damp,vy *= _damp;,vz *= _damp;。直到vx=vy=vz=0,粒子停止运动。当所有粒子停止运动后,获得下一张图片的象素位置和颜色,改变现有粒子的初始位置和颜色一致。然后从现在的位置返回到初始位置组成了一个新的图案。
如何你有任何意见和建议,欢迎和本人交流。
Preview:http://niuniuzhu.cn/p/PixelsRank