Implicit Bitmap Particle Physics
implicit 2d particle physics using a bitmap; cant wait to do this in a 3d ray tracer
each particle supports velocity and will inverse it's velocity upon "collision", there is no explicit collision handling, the inverse of particles velocity is a consequence of reaching a 'final' destination, or making it to a pixel that is adjacent with another element. a lot more work id like to do with this but so far this is pretty much the concept. pixelcanvas is super messy, i will probably use an interface for the _updatePixels method in future revisions. trying to keep the canvas modular without one is just a pain in the ass
/**
* Copyright hemingway ( http://wonderfl.net/user/hemingway )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/hmat
*/
package {
import flash.display.Stage;
import flash.display.Sprite;
import flash.geom.ColorTransform;
import flash.events.MouseEvent;
import flash.events.Event;
import net.hires.debug.*;
[SWF(frameRate=60, height=465, width=465)]
public class ContextExample extends Sprite {
public static const FLAG_STATIC:int = 0;
public static const FLAG_DEFAULT:int = 1;
public static const FLAG_SAND:int = 2;
public static const FLAG_WATER:int = 3;
public static const COLOR_STATIC:uint = 0x000001;
public static const COLOR_DEFAULT:uint = 0xDCDCDC;
public static const COLOR_SAND:uint = 0xC2B250;
public static const COLOR_WATER:uint = 0x0000FF;
private var _pixelCanvas:PixelCanvas;
private var _pixelBuffer:Pixel;
private var _sandMap:Vector.<Pixel>;
private var _colorMap4:Vector.<ColorTransform>;
private var _mouseVec2:Vector.<int>;
private var _mouseDown:Boolean;
private var _canvasShift:int;
private var _canvasSize:int;
private var _indexBufferA:int;
private var _indexBufferB:int;
private var _pixelSize:int;
private var _stage:Stage;
private var _size:int;
public function ContextExample() {
this._pixelBuffer = null as Pixel;
this._colorMap4 = new Vector.<ColorTransform>(4);
this._colorMap4[FLAG_STATIC] = new ColorTransform();
this._colorMap4[FLAG_STATIC].color = COLOR_STATIC;
this._colorMap4[FLAG_DEFAULT] = new ColorTransform();
this._colorMap4[FLAG_DEFAULT].color = COLOR_DEFAULT;
this._colorMap4[FLAG_SAND] = new ColorTransform();
this._colorMap4[FLAG_SAND].color = COLOR_SAND;
this._colorMap4[FLAG_WATER] = new ColorTransform();
this._colorMap4[FLAG_WATER].color = COLOR_WATER;
this._pixelCanvas = new PixelCanvas(_colorMap4, 465, 8);
this._canvasShift = this._pixelCanvas.canvasShift;
this._canvasSize = this._pixelCanvas.canvasSize;
this._size = this._pixelCanvas.width;
this._sandMap = new Vector.<Pixel>((_size*_size), true);
this._mouseVec2 = new Vector.<int>(4, true);
this._mouseDown = false;
this._indexBufferA = -1;
this._indexBufferB = -1;
this._pixelSize = 8;
this._stage = stage;
this.addEventListener(Event.ADDED_TO_STAGE, this.__addedToStageHandler);
}
private function __addedToStageHandler($event:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, this.__addedToStageHandler);
this.addChild(this._pixelCanvas);
//this.addChild(new Stats());
this._stage.addEventListener(MouseEvent.MOUSE_DOWN, this._stage__mouseDownHandler);
this._stage.addEventListener(MouseEvent.MOUSE_UP, this._stage__mouseUpHandler);
this._pixelCanvas.addEventListener(Event.ENTER_FRAME, this._pixelCanvas__enterFrameHandler);
}
private function _stage__mouseDownHandler($event:MouseEvent):void {
this._mouseDown = true;
this._mouseVec2[0] = ((this._stage.mouseX / this._pixelSize) << 0) as int;
this._mouseVec2[1] = ((this._stage.mouseY / this._pixelSize) << 0) as int;
this._mouseVec2[2] = this._mouseVec2[3] = 0;
}
private function _stage__mouseUpHandler($event:MouseEvent):void {
this._mouseDown = false;
}
private function _pixelCanvas__enterFrameHandler($event:Event):void {
this._mouseVec2[2] = this._mouseVec2[0];
this._mouseVec2[3] = this._mouseVec2[1];
this._mouseVec2[0] = ((this._stage.mouseX / this._pixelSize) << 0) as int;
this._mouseVec2[1] = ((this._stage.mouseY / this._pixelSize) << 0) as int;
var $deltaX:int = (this._mouseVec2[0] - this._mouseVec2[2]);
var $deltaY:int = (this._mouseVec2[1] - this._mouseVec2[3]);
var $normalX:int;
var $normalY:int;
if ($deltaX > 0) {
$normalX = 1;
} else if ($deltaX == 0) {
$normalX = 0;
} else if ($deltaX < 0) {
$normalX = -1;
}
if ($deltaY > 0) {
$normalY = 1;
} else if ($deltaY == 0) {
$normalY = 0;
} else if ($deltaY < 0) {
$normalY = -1;
}
if (this._mouseDown) {
this._pixelCanvas.setPixels(this._mouseVec2[2], this._mouseVec2[3], this._mouseVec2[0], this._mouseVec2[1], FLAG_SAND);
}
this._pixelCanvas.setGravity($deltaX, $deltaY);
}
}
}
Class {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
class PixelCanvas extends Bitmap {
private var _canvas:BitmapData;
private var _canvasSize:int;
private var _canvasShift:int;
private var _canvasBorder:Boolean;
private var _pixels:Vector.<Pixel>;
private var _pixelSize:int;
private var _pixelBuffer:Pixel;
private var _colorMap:Vector.<ColorTransform>;
private var _inputVelocityX:int;
private var _inputVelocityY:int;
private var _gravity:Vector.<int>;
public function PixelCanvas($colorMap:Vector.<ColorTransform>, $size:int = 465, $pixelSize:int = 3, $border:Boolean = true, $color:uint = 0xDCDCDC) {
this._colorMap = $colorMap;
this._pixelBuffer = null as Pixel;
this._pixelSize = $pixelSize;
this._pixels = new Vector.<Pixel>(($size*$size), true);
this._canvasBorder = $border;
this._canvasSize = $size;//($size / $pixelSize);
this._canvasShift = Math.floor(Math.log(this._canvasSize)/Math.log(2));
this._canvas = new BitmapData($size, $size, false, $color);
this._inputVelocityX = 0;
}
private function __addedToStageHandler($event:Event):void {
this.removeEventListener(Event.ADDED_TO_STAGE, this.__addedToStageHandler);
this.bitmapData = this._canvas;
this._initializePixels();
this.addEventListener(Event.ENTER_FRAME, this.__enterFrameHandler);
}
private function __enterFrameHandler($event:Event):void {
this._updatePixels();
}
private function _initializePixels():void {
var $size:int = (this._canvasSize - 1);
var $borderFlag:int = 0;
var $bodyFlag:int = 1;
for (var $y:int = 0; $y < this._canvasSize; $y++) {
for (var $x:int = 0; $x < this._canvasSize; $x++) {
this._pixels[($y << this._canvasShift) | $x] = new Pixel($x, $y, this._pixelSize, $bodyFlag);
(this._canvasBorder && ($x == 0 || $y == 0 || $x == $size || $y == $size)) ? setPixel($x, $y, $borderFlag) : null;
}
}
}
private function _updatePixels():void {
var $pixel:Pixel;
var $pixelVolume:Rectangle;
this._canvas.lock();
for (var $y:int = 0; $y < this._canvasSize; $y++) {
for (var $x:int = 0; $x < this._canvasSize; $x++) {
$pixel = this._pixels[($y << this._canvasShift) | $x];
if ($pixel.vY == 0) {
if ($pixel.numStaticFrames == 60) {
$pixel.static = true;
$pixel.vX = 0;
$pixel.vY = 0;
$pixel.numStaticFrames = 0;
} else {
$pixel.numStaticFrames++;
}
}
if ($pixel.active) {
$pixel.active = false;
$pixelVolume = new Rectangle($pixel.cX, $pixel.cY, this._pixelSize, this._pixelSize);
this._canvas.colorTransform($pixelVolume, this._colorMap[$pixel.flag]);
} else {
if ($pixel.static) continue;
//hack
if ($pixel.flag == 2) {
var $sign:int = 0;
if ($pixel.vX < 0) {
$sign = -1;
}
else if ($pixel.vX > 0) {
$sign = 1;
}
if ($sign == 1) {($x+$pixel.vX < this._canvasSize) ? ((this._gravity[0]!=0) ? $pixel.vX-=this._gravity[0] : $pixel.vX--) : $pixel.vX=~(($pixel.vX*0.66)-1);}
if ($sign == -1) {($x+$pixel.vX > 0) ? ((this._gravity[0]!=0) ? $pixel.vX+=this._gravity[0] : $pixel.vX++) : $pixel.vX=~(($pixel.vX*0.66)-1);}
if ($sign == 0) {(Math.random()>0.5) ? ((this._gravity[0]!=0) ? $pixel.vX-=this._gravity[0] : $pixel.vX--) : (this._gravity[0]!=0 ? $pixel.vX+=this._gravity[0] : $pixel.vX++);}
($y+$pixel.vY < this._canvasSize) ? (($pixel.vY < 10) ? $pixel.vY+=this._gravity[1] : $pixel.vY++) : $pixel.vY=~(($pixel.vY*0.1)-1);//((this._canvasSize-1)-$y);
($y+$pixel.vY > 0) ? $pixel.vY : $pixel.vY=~(($pixel.vY*0.1)-1);
var $nextPixel:Pixel = this._pixels[(($y+$pixel.vY) << this._canvasShift) | ($x+$pixel.vX)];
if ($nextPixel) {
if ($nextPixel.flag == 1) {
$nextPixel.vY = $pixel.vY;
$nextPixel.vX = $pixel.vX;
$nextPixel.flag = 2;
$pixel.flag = 1;
$pixel.vY = 1;
$pixel.vX = 0;
$pixel.numStaticFrames = 0;
$pixel.active = true;
$nextPixel.active = true;
} else {
$pixel.vY = ~(($pixel.vY*0.1)-1);
$pixel.vX = ~(($pixel.vX*0.1)-1);
$pixel.active = true;
$pixel.vY = ~(($pixel.vY*0.1)-1);
$pixel.vX = ~(($pixel.vX*0.1)-1);
/*} else {
for ($pixel.vY; $pixel.vY>0; $pixel.vY--) {
$nextPixel = this._pixels[(($y+$pixel.vY) << this._canvasShift) | ($x+$pixel.vX)];
if ($nextPixel.flag == 1) {
$nextPixel.flag = 2;
$pixel.flag = 1;
$pixel.vY = 1;
$pixel.vX = 0;
$pixel.active = true;
$nextPixel.active = true;
} else {
if ($sign == 1) {
for ($pixel.vX; $pixel.vX>0; $pixel.vX--) {
$nextPixel = this._pixels[(($y+$pixel.vY) << this._canvasShift) | ($x+$pixel.vX)];
if ($nextPixel.flag == 1) {
$nextPixel.flag = 2;
$pixel.flag = 1;
$pixel.vY = 1;
$pixel.vX = 0;
$pixel.active = true;
$nextPixel.active = true;
} else {
$nextPixel.vX = (((~$pixel.vX+1)+1)*$pixel.vY);
$nextPixel.vY = ((~$pixel.vY+1)*0.50);
$nextPixel.flag = 2;
$pixel.flag = 1;
$pixel.vY = 1;
$pixel.vX = 0;
$pixel.active = true;
$nextPixel.active = true;
}
}
} else if ($sign == -1) {
for ($pixel.vX; $pixel.vX<0; $pixel.vX++) {
$nextPixel = this._pixels[(($y+$pixel.vY) << this._canvasShift) | ($x+$pixel.vX)];
if ($nextPixel.flag == 1) {
//$pixel.vY = ($pixel.vY*0.5);
$nextPixel.flag = 2;
$pixel.flag = 1;
$pixel.vY = 1;
$pixel.vX = 0;
$pixel.active = true;
$nextPixel.active = true;
} else {
$nextPixel.vX = (((~$pixel.vX+1)-1)*$pixel.vY);
$nextPixel.vY = (~$pixel.vY+1);
$nextPixel.flag = 2;
$pixel.flag = 1;
$pixel.vY = 1;
$pixel.vX = 0;
$pixel.active = true;
$nextPixel.active = true;
}
}
}
}
}*/
}
}
}
}
}
}
this._canvas.unlock();
}
public function getPixel($x:int, $y:int):Pixel {
return this._pixels[($y << this._canvasShift) | $x];
}
public function setPixel($x:int, $y:int, $flag:int, $static:Boolean = false):void {
var $index:int = ($y << this._canvasShift) | $x;
this._pixelBuffer = this._pixels[$index];
if (!this._pixelBuffer.static) {
this._pixelBuffer.vX = ($flag == 2) ? this._inputVelocityX : this._pixelBuffer.vX;
this._pixelBuffer.vY = ($flag == 2) ? this._inputVelocityY : this._pixelBuffer.vY;
this._pixelBuffer.flag = $flag;
this._pixelBuffer.static = (this._pixelBuffer.flag) ? false : true;
this._pixelBuffer.active = true;
}
}
public function setPixels($fX:int, $fY:int, $tX:int, $tY:int, $flag:int, $static:Boolean = false):void {
setPixel($fX, $fY, $flag, $static);
var $dY:int = ($tY - $fY);
var $dX:int = ($tX - $fX);
this._inputVelocityX = $dX;
this._inputVelocityY = $dY;
if (($dY ^ ($dY >> 31)) - ($dY >> 31) > ($dX ^ ($dX >> 31)) - ($dX >> 31)) {
$dY ^= $dX;
$dX ^= $dY;
$dY ^= $dX;
var $s:Boolean = true;
} else {
$s = false;
}
var $i:int = ($dX < 0) ? (~1 + 1) : 1;
var $m:Number = ($dX == 0) ? $dY : ($dY / $dX);
if ($s) {
for (var $:int = 0; $ != $dX; $+=$i) {
setPixel(($fX + $ * $m), ($fY + $), $flag, $static);
}
} else {
for ($ = 0; $ != $dX; $+=$i) {
setPixel(($fX + $), ($fY + $ * $m), $flag, $static);
}
}
}
public function setGravity($x:int, $y:int):void{
//($x > 224 && $x < 240) ? this._gravity[0] = 0 : this._gravity[0] = (($x-232)/Math.abs($x-232));
//($y > 224 && $x < 240) ? this._gravity[1] = 0 : this._gravity[1] = (($y-232)/Math.abs($y-232));
}
public function get canvasSize():int {
return this._canvasSize;
}
public function get canvasShift():int {
return this._canvasShift;
}
/* Kept for reference
public function calcIndex($x:int, $y:int):int {
return ($y << this._canvasShift) | $x;
}*/
}
}
Class {
class Pixel {
public var x:int;
public var y:int;
public var vX:int;
public var vY:int;
public var cX:int;
public var cY:int;
public var size:int;
public var flag:int;
public var active:Boolean;
public var static:Boolean;
public var numStaticFrames:int;
public function Pixel($x:int, $y:int, $size:int, $flag:int) {
this.numStaticFrames = 0;
this.static = false;
this.active = true;
this.flag = $flag;
this.size = $size;
this.cY = ($y * $size);
this.cX = ($x * $size);
this.vY = 1;
this.vX = 0;
this.y = $y;
this.x = $x;
}
}
}
Class {
import flash.text.TextField;
class DataField extends TextField {
}
}