Click for shoot. Press R button to restore glass mesh:
//Bullet Resistant Glass by Mawhrin Skel http://flickr.com/photos/24789570@N03/2698809741/
[Embed(source='2698809741_76eddd085c.jpg')]
private var MeshMat:Class;
[Embed(source = 'broken.png')]
private var BrokenCenter:Class
//Parquet 2.0 version 6 by Kochubey http://www.filterforge.com/filters/488.html
private const GROUND_TEXTURE:String = "488-v6+.jpg"
private const BULLET_TEXTURE:String = "bullet_back.png"
private static const BOUNDS:Number = 3000; // Limit for bullet
private static const MESH_SIZE:uint = 512
private static const MESH_TESSELATION_X:uint = 8
private static const MESH_TESSELATION_Y:uint = 8
private static const GROUND_Y:int = -300
private static const SHOOT_POWER:Number = 0.15 // 1 is maximum
//Glass Mesh
private var mesh:Plane;
private var meshMaterial:MaterialObject3D
private var meshSprite:Sprite
private var brokenCenterBmp:Bitmap
//Bullet
private var bullets:Array = new Array();
private var collidedBulletIndex:uint;
//Physics
private var isPhysicsOn:Boolean = false
private var meshPartsPhysics:Array = new Array()
private var detainedParts:Array = new Array()
private var detainedPartsCounter:uint = 0
private var ground:Plane
public function Main() {
super(800, 600, false, false, "CAMERA3D");
preparePv3d();
createMaterials();
createObjects();
addListeners();
}
public function preparePv3d():void {
addChild(new StatsView(renderer));
}
public function createMaterials():void {
meshSprite = new Sprite()
meshSprite.addChild(new MeshMat() as Bitmap)
meshSprite.alpha = 0.3
brokenCenterBmp = new BrokenCenter() as Bitmap
brokenCenterBmp.alpha = 0
meshSprite.addChild(brokenCenterBmp);
meshMaterial = new MovieMaterial(meshSprite, true, true, false, new Rectangle(0, 0, MESH_SIZE, MESH_SIZE))
meshMaterial.doubleSided = true;
}
public function createObjects():void {
ground = new Plane(new BitmapFileMaterial(GROUND_TEXTURE), 1024, 1024, 6, 6)
ground.rotationX = -270
ground.y = GROUND_Y
ground.z = 100
scene.addChild(ground)
restoreMesh() // create glass mesh
}
public function breakMesh(mesh:TriangleMesh3D):void {
if (!isPhysicsOn && bullets[collidedBulletIndex] !=null) {
detainedPartsCounter = 0
detainedParts = new Array()
meshPartsPhysics = new Array();
var geom:GeometryObject3D = mesh.geometry;
var oTris:Array = geom.faces;
var nTris:Array = new Array();
var vert:Vertex3D;
var nVert:Vertex3D;
var triangle:Triangle3D;
var nTriangle:Triangle3D;
for (var i:int = 0; i < oTris.length; i++)
{
var currFace:Triangle3D = oTris[i];
var vertCacheA:Dictionary = new Dictionary(true);
var triangleBucketA:Array = new Array();
var vertBucketA:Array = new Array();
var meshX:int
var meshY:int
triangle = currFace
for (var k:int = 0; k < currFace.vertices.length; k++)
{
vert = currFace.vertices[k];
if(!(nVert = vertCacheA[vert])){
nVert = vert.clone();
vertCacheA[vert] = nVert;
}
vertBucketA.push(nVert)
triangle.vertices[k] = nVert;
}
// Save position for new mesh
meshX = triangle.vertices[0].x
meshY = triangle.vertices[0].y
// Calculate shift for vertices
var shiftX:int = MESH_SIZE/MESH_TESSELATION_X
var shiftY:int = MESH_SIZE/MESH_TESSELATION_Y
if (triangle.vertices[0].x > triangle.vertices[1].x)
shiftX = -MESH_SIZE/MESH_TESSELATION_X
if (triangle.vertices[0].y > triangle.vertices[2].y)
shiftY = -MESH_SIZE/MESH_TESSELATION_Y
// Set local position for vertices
triangle.vertices[0].x = 0
triangle.vertices[0].y = 0
triangle.vertices[1].x = shiftX
triangle.vertices[1].y = 0
triangle.vertices[2].x = 0
triangle.vertices[2].y = shiftY
triangle.updateVertices();
//create new mesh add it on scene
var meshA:TriangleMesh3D = new TriangleMesh3D(mesh.material, vertBucketA, [triangle]);
meshA.geometry.ready = true
meshA.x = meshX
meshA.y = meshY
brokenCenterBmp.x = bullets[collidedBulletIndex].x - (mesh.x - MESH_SIZE*0.5) -brokenCenterBmp.width/2
brokenCenterBmp.y = -bullets[collidedBulletIndex].y - (mesh.y - MESH_SIZE*0.5) -brokenCenterBmp.height/2
brokenCenterBmp.alpha = 1
//add physics for new mesh
meshPartsPhysics.push(new PolygonPhysics(TriangleMesh3D(meshA), 10, .5, 1));
scene.addChild(meshPartsPhysics[i].Object3D);
}
for each(var meshPart:PolygonPhysics in meshPartsPhysics)
{
var xdiff : Number = meshPart.Object3D.x-bullets[collidedBulletIndex].x;
var ydiff : Number = meshPart.Object3D.y-bullets[collidedBulletIndex].y;
var distance : Number = Math.sqrt((xdiff * xdiff) + (ydiff * ydiff))
if (distance > MESH_SIZE*SHOOT_POWER*1.5){
meshPart.isDetained = true;
//add impulse for detained parts
meshPart.LinImpulse = new Number3D(Math.random()*10, 10, 10-Math.random()*20)
meshPart.RotImpulse= new Number3D(Math.random()*.2,Math.random()*.2,Math.random()*.2)
}else {
//add impulse for not detained parts
var impX:int
var impY:int
if (bullets[collidedBulletIndex].x < meshPart.Object3D.x)
impX = MESH_SIZE*SHOOT_POWER*.5
else
impX = -MESH_SIZE*SHOOT_POWER*.5
if (bullets[collidedBulletIndex].y < meshPart.Object3D.y)
impY = MESH_SIZE*SHOOT_POWER*.5
else
impY = -MESH_SIZE*SHOOT_POWER*.5
meshPart.LinImpulse = new Number3D(impX, impY, (MESH_SIZE - distance)*SHOOT_POWER)
meshPart.RotImpulse= new Number3D(Math.random()*.6,Math.random()*.6,Math.random()*.6)
}
}
isPhysicsOn = true;
}
scene.removeChild(mesh)
}
public function restoreMesh():void
{
if (meshPartsPhysics.length > 0) {
for (var i:int = 0; i < meshPartsPhysics.length; i++)
{
scene.removeChild(meshPartsPhysics[i].Object3D);
}
}
mesh = new Plane(meshMaterial, MESH_SIZE, MESH_SIZE, MESH_TESSELATION_X, MESH_TESSELATION_Y)
scene.addChild(mesh)
isPhysicsOn = false
brokenCenterBmp.alpha = 0
}
public function enterFrameHandler(event:Event):void {
if(isPhysicsOn){
updatePhysics();
detainedPartsCounter++
}
updateBullet();
rotateCamera();
singleRender();
}
private function updateBullet():void
{
for each(var bullet:DisplayObject3D in bullets) {
bullet.moveForward(100);
if(bullet.hitTestObject(mesh)){
breakMesh(mesh);
collidedBulletIndex = bullets.indexOf(bullet)
}
if (Math.abs(bullet.x) > BOUNDS/2 || Math.abs(bullet.y) > BOUNDS/2 || Math.abs(bullet.z) > BOUNDS/2) {
bullets.splice(bullets.indexOf(bullet), 1 );
scene.removeChild(bullet);
}
}
}
private function updatePhysics():void
{
for (var i:int = 0; i < meshPartsPhysics.length; i++)
{
if(meshPartsPhysics[i].isDetained == false || detainedPartsCounter > meshPartsPhysics.length*SHOOT_POWER){
if (meshPartsPhysics[i].Object3D.y > GROUND_Y) {
meshPartsPhysics[i].AddForce(meshPartsPhysics[i].CGPosition, Number3DPlus.multiply(new Number3D(0, -.2, 0), meshPartsPhysics[i].Mass));
meshPartsPhysics[i].Update(1.7);
}else {
if(meshPartsPhysics[i].isStopped == false){
meshPartsPhysics[i].resetPos();
meshPartsPhysics[i].Object3D.rotationY = Math.random()*180 // dirty fix
meshPartsPhysics[i].ResetImpulse();
meshPartsPhysics[i].ResetForce();
meshPartsPhysics[i].Object3D.y = GROUND_Y
meshPartsPhysics[i].Object3D.rotationX = 90
meshPartsPhysics[i].Object3D.rotationZ = 0
meshPartsPhysics[i].isStopped = true
}
}
}
}
}
public function addListeners():void {
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(KeyboardEvent.KEY_UP, keyUpHandler);
stage.addEventListener(MouseEvent.CLICK, onMouseClick);
}
private function rotateCamera():void
{
camera.rotationX = -(viewport.mouseY - stage.height / 2) / 5;
camera.rotationY = (viewport.mouseX - stage.width / 2) / 5;
}
private function onMouseClick(e:MouseEvent):void {
var bullet:Plane = new Plane(new BitmapFileMaterial(BULLET_TEXTURE), 64, 64, 1, 1)
bullet.copyPosition(camera);
bullet.copyTransform(camera);
bullet.moveForward(400);
scene.addChild(bullet);
bullets.push(bullet);
}
public function keyUpHandler(e:KeyboardEvent):void {
if (isChar(e.charCode, "r")) {
if (meshPartsPhysics.length > 0)
restoreMesh();
else
breakMesh(mesh);
}
}
private function isChar(code:Number, str:String):Boolean{
if(code == str.charCodeAt())
return true;
return false;
}
07.10.2008. 21:10
This article hasn't been commented yet.
Write a comment
* = required field