5k boxes
learning to post some cool!!
flash on 2013-4-21
new version(更新):
http://wonderfl.net/c/dVTF
/**
* Copyright shen_0_ ( http://wonderfl.net/user/shen_0_ )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/iLtG
*/
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Shape;
import flash.display.Sprite;
import flash.display.Stage3D;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DRenderMode;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.VertexBuffer3D;
import flash.display3D.textures.Texture;
import flash.events.Event;
import flash.geom.Matrix3D;
import net.hires.debug.Stats;
[SWF(frameRate=60, width="465", height="465")]
public class Boxes extends Sprite {
public static const NUM_PARTICLE:int=7000;
public static const SIZE:int=5;
public static const W:int=460;
public static const H:int=460;
public static const COLS:int=W / SIZE;
public static const ROWS:int=H / SIZE;
public static const REST:int=3;
public static const SPEED:Number=SIZE / REST; //moving speed
public static const SPEED_No_SQRT:Number=SPEED * SPEED * 0.5;
private var nets:Array=[];
private var boxList:Array=[];
///////////////////stage3D
public static const COLOR_ORANGE:uint=0x9B8553;
public static const COLOR_GRAY:uint=0xaaaaaa;
private var context:Context3D;
private var program:ShaderProgram;
private var iBuffer:IndexBuffer3D;
private var vBuffer:VertexBuffer3D;
private var uvBuffer:VertexBuffer3D;
private var rotBmp:BitmapData;
private var texture:Texture;
private var ortho:Matrix3D=new Matrix3D();
private var r_rot_steps:Vector.<Number>=Vector.<Number>([0, 0, 0, 0]);
private var vb:Vector.<Number>=new Vector.<Number>();
private var uvb:Vector.<Number>=new Vector.<Number>();
private var ib:Vector.<uint>=new Vector.<uint>();
private const vunit:int=4;
private const uvunit:int=2;
public function Boxes() {
Wonderfl.disable_capture();
stage.align=StageAlign.TOP_LEFT;
stage.scaleMode=StageScaleMode.NO_SCALE;
rotBmp=new BitmapData(16, 4, true, 0);
const ox:Number=0.5;
var sp:Shape=new Shape();
sp.graphics.lineStyle(0, COLOR_GRAY * 0.7);
sp.graphics.beginFill(COLOR_GRAY);
sp.graphics.drawRect(ox, ox, 3, 3);
sp.graphics.endFill();
sp.graphics.lineStyle(0, COLOR_ORANGE);
sp.graphics.beginFill(COLOR_ORANGE);
sp.graphics.drawRect(ox + 4, ox, 3, 3);
sp.graphics.endFill();
sp.graphics.lineStyle(0, COLOR_ORANGE, 0.5);
sp.graphics.beginFill(COLOR_ORANGE);
sp.graphics.drawRect(ox + 8, ox, 3, 3);
sp.graphics.endFill();
rotBmp.draw(sp);
var rotBM:Bitmap=new Bitmap(rotBmp);
rotBM.x=100;
var i:int, j:int;
for (j=0; j < ROWS; j++) {
nets[j]=[];
for (i=0; i < COLS; i++) {
nets[j][i]=null;
}
}
//obstacle
for (i=0; i < 20; i++) {
createObstacle(Math.random() * 90, 10 + Math.random() * 50, 20 * Math.random());
}
stage.stage3Ds[0].addEventListener(Event.CONTEXT3D_CREATE, createContext3D);
stage.stage3Ds[0].requestContext3D(Context3DRenderMode.AUTO);
addChild(new Stats());
addChild(rotBM);
}
private function createContext3D(e:Event):void {
context=(e.target as Stage3D).context3D;
context.removeEventListener(Event.CONTEXT3D_CREATE, createContext3D);
context.configureBackBuffer(W, H, 0, false);
context.setRenderToBackBuffer();
context.enableErrorChecking=true;
//program
program=new ShaderProgram(context, new VertexShader(), new FragmentShader());
ortho=MatrixUtil.ortho(W, H, false);
//index, vertex, uv
const part:Number=0.25;
const count:int=ROWS * COLS;
for (var i:int=0; i < count; i++) {
vb.push(0, 0, 0, 0);
vb.push(0, 0, 0, 0);
vb.push(0, 0, 0, 0);
vb.push(0, 0, 0, 0);
uvb.push(0, 0);
uvb.push(part, 0);
uvb.push(part, 1);
uvb.push(0, 1);
ib.push(i * 4 + 0, i * 4 + 1, i * 4 + 2, i * 4 + 0, i * 4 + 2, i * 4 + 3);
}
vBuffer=context.createVertexBuffer(vb.length / vunit, vunit);
vBuffer.uploadFromVector(vb, 0, vb.length / vunit);
uvBuffer=context.createVertexBuffer(uvb.length / uvunit, uvunit);
uvBuffer.uploadFromVector(uvb, 0, uvb.length / uvunit);
iBuffer=context.createIndexBuffer(ib.length);
iBuffer.uploadFromVector(ib, 0, ib.length);
r_rot_steps[0]=part;
//texture
texture=context.createTexture(16, 4, Context3DTextureFormat.BGRA, false);
texture.uploadFromBitmapData(rotBmp);
context.setTextureAt(0, texture);
//setting
context.setProgram(program.program);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 0, ortho, true);
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 4, r_rot_steps);
//enter frame
stage.addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(Event.RESIZE, resize);
}
private function resize(e:Event):void {
context.configureBackBuffer(stage.stageWidth, stage.stageHeight, 0, false);
}
private function loop(e:Event):void {
context.clear(0.1, 0.1, 0.1);
boxsLoop();
const len:int=boxList.length;
var index:int=0;
var id:int=0;
for each (var box:Box in boxList) {
var oldX:Number=box.x;
var oldY:Number=box.y;
id=box.getFixed() ? 0 : 2;
vb[index++]=oldX;
vb[index++]=oldY;
vb[index++]=id;
index++;
vb[index++]=oldX + SIZE;
vb[index++]=oldY;
vb[index++]=id;
index++;
vb[index++]=oldX + SIZE;
vb[index++]=oldY + SIZE;
vb[index++]=id;
index++;
vb[index++]=oldX;
vb[index++]=oldY + SIZE;
vb[index++]=id;
index++;
}
vBuffer.uploadFromVector(vb, 0, len * vunit);
context.setVertexBufferAt(0, vBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context.setVertexBufferAt(1, vBuffer, 2, Context3DVertexBufferFormat.FLOAT_2);
context.setVertexBufferAt(2, uvBuffer, 0, Context3DVertexBufferFormat.FLOAT_2);
context.drawTriangles(iBuffer, 0, 2 * len);
if (false && captureTime-- == 0) {
var cc:BitmapData=new BitmapData(465, 465, false, 0);
context.drawToBitmapData(cc);
cc.draw(stage);
addChild(new Bitmap(cc));
}
context.present();
}
private var captureTime:int=5 * 60;
//loop
private var nums:int=NUM_PARTICLE;
private function boxsLoop():void {
var box:Box, tx:int, ty:int, bool:Boolean;
var len:int=boxList.length;
for (var i:int=0; i < len; i++) {
box=boxList[i];
if (box.getFixed()) {
continue;
}
if (box.getSleep()) {
if (box.rest < 1) {
continue;
} else {
box.rest--;
}
}
if (!box.needMoving) {
tx=box.cx;
ty=box.cy;
bool=true;
if (ty < ROWS - 1) {
if (isEmpty(tx, ty + 1)) {
box.setGoto(tx, ty + 1);
bool=false;
} else {
if (tx > 0 && isEmpty(tx - 1, ty) && isEmpty(tx - 1, ty + 1)) {
box.setGoto(tx - 1, ty);
bool=false;
} else if (tx < COLS - 1 && isEmpty(tx + 1, ty) && isEmpty(tx + 1, ty + 1)) {
box.setGoto(tx + 1, ty);
bool=false;
}
}
}
if (bool) {
box.setSleep(true);
}
}
if (box.needMoving) {
box.move();
}
}
trace("debug:", debug);
debug=0;
if (nums > 0) {
for (i=5; i > 0; i--) {
var randX:int=Math.random() * COLS
if (!getBox(randX, 0)) {
nums--;
createBox(randX, 0);
}
}
}
}
private var debug:Number=0;
//public
public function setCheckBox(x:int, y:int, box:Box):void {
nets[y][x]=box;
}
public function wakeOther(x:int, y:int):void {
//wake.wake.wake
//wake.move.wake
var box:Box=getBox(x - 1, y); //x-1,y
if (box)
box.setSleep(false);
box=getBox(x + 1, y); //x+1,y
if (box)
box.setSleep(false);
box=getBox(x, y - 1); //x,y-1
if (box)
box.setSleep(false);
box=getBox(x - 1, y - 1); //x-1,y-1
if (box)
box.setSleep(false);
box=getBox(x + 1, y - 1); //x+1,y-1
if (box)
box.setSleep(false);
}
//check this position box;
private function getBox(x:int, y:int):Box {
if (x > -1 && y > -1 && x < COLS && y < ROWS) {
return nets[y][x];
}
return null;
}
private function isEmpty(x:int, y:int):Boolean {
if (x > -1 && y > -1 && x < COLS && y < ROWS) {
return !(nets[y][x]);
}
return false;
}
//create
private function createObstacle(x:int, y:int, len:int):void {
for (var i:int=0; i < len; i++) {
createBox(x + i, y, true);
}
}
private function createBox(x:int, y:int, isFixed:Boolean=false):Box {
if (!isEmpty(x, y)) {
return null;
}
var box:Box=new Box(this, x, y);
box.setFixed(isFixed);
boxList.push(box);
setCheckBox(x, y, box);
return box;
}
}
}
import flash.geom.Point;
class Box {
public var x:Number=0;
public var y:Number=0;
public var cx:int=0;
public var cy:int=0;
public var toX:int=0;
public var toY:int=0;
public var needMoving:Boolean=false;
public var rest:int=0;
private var _sleep:Boolean=false;
private var _fixed:Boolean=false;
private var _v:Point=new Point();
private var world:Boxes=null;
public function Box(world:Boxes, x:int, y:int) {
this.world=world;
setPos(x, y);
}
//set/get fixed
public function getFixed():Boolean {
return _fixed;
}
public function setFixed(bool:Boolean):void {
if (bool != _fixed) {
_fixed=bool;
}
}
//sleep
public function getSleep():Boolean {
return _sleep;
}
public function setSleep(bool:Boolean):void {
if (_sleep != bool) {
_sleep=bool;
if (bool) {
rest=Boxes.REST;
}
}
}
public function setPos(xa:int, ya:int):void {
cx=xa;
cy=ya;
x=xa * Boxes.SIZE;
y=ya * Boxes.SIZE;
}
public function setGoto(xa:int, ya:int):void {
world.setCheckBox(xa, ya, this);
toX=xa;
toY=ya;
needMoving=false;
_v.x=0;
_v.y=0;
//set the moving speed
if (toX != cx || toY != cy) {
needMoving=true;
var v:int=toX - cx;
if (v != 0) {
_v.x=Boxes.SPEED * v / Math.abs(v);
}
v=toY - cy;
if (v != 0) {
_v.y=Boxes.SPEED * v / Math.abs(v);
}
}
}
public function move():void {
var tx:Number=this.x - toX * Boxes.SIZE;
var ty:Number=this.y - toY * Boxes.SIZE;
if ((tx * tx + ty * ty) < Boxes.SPEED_No_SQRT) {
world.setCheckBox(cx, cy, null);
setPos(toX, toY);
needMoving=false;
_v.x=0;
_v.y=0;
} else {
this.x+=_v.x;
this.y+=_v.y;
}
world.wakeOther(cx, cy);
}
}
//Stage3D
import com.adobe.utils.AGALMiniAssembler;
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Program3D;
import flash.geom.Matrix3D;
class ShaderProgram {
public var program:Program3D=null;
public function ShaderProgram(context:Context3D, vsh:AGALMiniAssembler, fsh:AGALMiniAssembler) {
program=context.createProgram();
program.upload(vsh.agalcode, fsh.agalcode);
}
}
class VertexShader extends AGALMiniAssembler {
private var src:String=
"m44 op, va0, vc0 \n" +
"mov v0, va2 \n" +
"mul vt0.x, va1.x, vc4.x \n" + //offset = base frame% x step
"add v0.x, va2.x, vt0.x \n" + //new u = u + offset
"";
public function VertexShader() {
assemble(Context3DProgramType.VERTEX, src);
}
}
class FragmentShader extends AGALMiniAssembler {
private var src:String=
"mov ft0, v0\n" +
"tex ft1, ft0.xy, fs0 <2d,repeat,nearest>\n" +
"mov oc, ft1\n";
public function FragmentShader() {
assemble(Context3DProgramType.FRAGMENT, src);
}
}
class MatrixUtil {
public static function ortho(w:int, h:int, rev:Boolean):Matrix3D {
var m:Matrix3D=new Matrix3D();
m.appendTranslation(-w * 0.5, -h * 0.5, 0);
m.appendScale(2 / w, rev ? 2 / h : -2 / h, 1);
return m;
}
}