package { import alternativ5.engine3d.controllers.*; import alternativ5.engine3d.core.*; import alternativ5.engine3d.display.*; import alternativ5.engine3d.events.MouseEvent3D; import alternativ5.types.*; import alternativ5.utils.*; import flash.display.*; import flash.events.*; /** * Faces要素から複数のフェイスを一度に呼ぶことができます * * click属性などが使えないため * その場合のコードジェネレータ作成する予定です * * デモのために矢印を作成しました * 引数は次の画像を参照してください * http://twitpic.com/x7z6b */ [SWF(backgroundColor="#000000", frameRate="120")] public class Main extends Sprite { private var scene:Scene3D; private var view:View; private var camera:Camera3D; private var cameraController:CameraController; public var textures:Array; private var meshes:/*Mesh*/Array; private var map:Map; public function Main() { this.addEventListener(Event.ADDED, init); } public function init(e:Event):void { this.removeEventListener(Event.ADDED, init); stage.scaleMode = StageScaleMode.NO_SCALE; stage.align = StageAlign.TOP_LEFT; scene = new Scene3D(); scene.root = new Object3D(); camera = new Camera3D(); camera.x = camera.y = 500; camera.z = 800; scene.root.addChild(camera); view = new View(); view.interactive = true; view.camera = camera; addChild(view); cameraController = new CameraController(stage); cameraController.camera = camera; cameraController.checkCollisions = false; cameraController.speed = 500; cameraController.controlsEnabled = true; cameraController.setDefaultBindings(); cameraController.lookAt(new Point3D()); FPS.init(stage); stage.addEventListener(Event.RESIZE, onResize); stage.addEventListener(Event.ENTER_FRAME, onEnterFrame); onResize(null); //create create(); } /** * */ private function create():void { var xml:XML = <meshes> <mesh name="Geo"> <surface materialType={EZCreateMesh.FILL} color="0xFF0000" wirethickness="2" wirecolor="0xFFFFFF"> <faces primitive={EZCreateMesh.ARROW} aw="500" ah="500" bw="500" bh="500" tz="0" ch="50" /> </surface> </mesh> </meshes>; // createMeshes meshes = EZCreateMesh.createMeshes(xml, textures, this); // addMehses addMehses(meshes); } /** * addMeshes * @param meshes */ private function addMehses(meshes:Array):void { for (var o:* in meshes) { scene.root.addChild(meshes[o]); } } /** * * @param targetMap * @param targetSet */ private function addSetObjects(targetMap:Map, targetSet:String):void { addObjects(targetMap[EZCreateMesh.KEY_MAP + EZCreateMesh.ID_CONCAT + targetSet]); } /** * addObjects * @param objects */ private function addObjects(objects:Set):void { for (var o:* in objects) { scene.root.addChild(o); } } /** * onResize * @param e */ private function onResize(e:Event):void { view.width = stage.stageWidth; view.height = stage.stageHeight; } /** * * @param e */ private function onEnterFrame(e:Event):void { cameraController.processInput(); scene.calculate(); } } } /** * EZCreateMesh * * 簡単に より早くメッシュを作成する為に * * Alternativa3Dを利用したマップ(Mesh)作成時に ASでは 頂点やフェイス、 * サーフェス全てに id(名前)をつける必要があり、これらの作業は非常に面倒です * * XMLに情報を記述することによって * 値 変更時にコンパイルが不要になり、誰でも簡単にマップ作成が可能です * * @author br */ import alternativ5.engine3d.core.*; import alternativ5.engine3d.materials.*; import alternativ5.types.*; import alternativ5.utils.*; import org.libspark.betweenas3.BetweenAS3; import org.libspark.betweenas3.tweens.ITween; import flash.geom.*; import flash.display.*; import alternativ5.engine3d.core.*; import alternativ5.engine3d.materials.*; import alternativ5.types.*; import alternativ5.utils.*; import flash.geom.*; import flash.display.*; import alternativ5.engine3d.events.*; class EZCreateMesh { /** * static const */ // MATERIAL public static const DEV:String = "DevMaterial"; public static const FILL:String = "FillMaterial"; public static const TEXTURE:String = "TextureMaterial"; public static const WIRE:String = "WireMaterial"; public static const MOVIECLIP:String = "MovieClipMaterial"; // SPEITE 3D public static const SPRITE_TEXTURE:String = "SpriteTextureMaterial"; public static const SPRITE:String = "SpriteMaterial"; public static const ID_CONCAT:String = ":"; public static const ID_SURFACE:String = "s"; public static const ID_FACE:String = "f"; public static const ID_VERTEX:String = "v"; public static const KEY_MAP:String = "m"; private static const _PI:Number = Math.PI; /** * 渡されたXMLに記載されているMeshを全て作成し配列で返します * @param db */ public static function createMeshes(db:XML, textures:Array = null, main:Main = null):/*Mesh*/Array { var _meshes:/*Mesh*/Array = []; for (var a:int = 0; a < db.mesh.length(); a++) { _meshes[db.mesh[a].@name] = new Mesh(); var textureLists:XMLList = db.mesh[a].surface.(@materialType == TEXTURE).@name; _meshes[db.mesh[a].@name] = createMesh(db.mesh[a], textures, main) as Mesh; } return _meshes; } /** * マップを作成 * @param map * @param mapName */ public static function createMap(db:XML, _meshes:/*Mesh*/Array):Map { var map:Map = new Map(); for (var a:int = 0; a < db.set.length(); a++) { var _set:Set; var elements:Array = []; for (var b:int = 0; b < db.set[a].mesh.length(); b++) { var mesh:Mesh = meshPropertiesSetup( _meshes[db.set[a].mesh[b].@name].clone(), db.set[a].mesh[b] ); elements.push(mesh); } _set = Set.createFromArray(elements); map.add(KEY_MAP + ID_CONCAT + db.set[a].@name, _set); } return map; } /** * XMLを元にプロパティを変更したメッシュを返します * @param mesh メッシュ * @param properties プロパティが記載されたXML * @return mesh プロパティが変更されたメッシュを返します * @exampleText XMLの例を示します * <listing version="3.0"> * <mesh z="-100" scaleX="5" scaleY="5" /> * </listing> */ public static function meshPropertiesSetup(mesh:Mesh, properties:XML):Mesh { if (properties.hasOwnProperty("@x")) mesh.x = Number(properties.@x); if (properties.hasOwnProperty("@y")) mesh.y = Number(properties.@y); if (properties.hasOwnProperty("@z")) mesh.z = Number(properties.@z); if (properties.hasOwnProperty("@scaleX")) mesh.scaleX = Number(properties.@scaleX); if (properties.hasOwnProperty("@scaleY")) mesh.scaleY = Number(properties.@scaleY); if (properties.hasOwnProperty("@scaleZ")) mesh.scaleZ = Number(properties.@scaleZ); if (properties.hasOwnProperty("@rotationX")) mesh.rotationX = MathUtils.toRadian(Number(properties.@rotationX)); if (properties.hasOwnProperty("@rotationY")) mesh.rotationY = MathUtils.toRadian(Number(properties.@rotationY)); if (properties.hasOwnProperty("@rotationZ")) mesh.rotationZ = MathUtils.toRadian(Number(properties.@rotationZ)); return mesh; } /** * メッシュ作成 * @param xml メッシュの情報が記載されたXML * @return Mesh */ public static function createMesh(xml:XML, textures:/*BitmapData*/Array = null, main:Main = null):Mesh { var _mesh:Mesh = new Mesh(); var surfaces:Array = []; for (var a:int = 0; a < xml.surface.length(); a++) { if ("faces" in xml.surface[a]) { for ( var f:int = 0; f < xml.surface[a].faces.length(); f++) { xml.surface[a].faces.prependChild(createFacesPrimitive(xml.surface[a].faces[f])); } } // eg - s:s (s:0) var surfaceName:String = xml.surface[a].hasOwnProperty("@id") ? xml.surface[a].@id : String(ID_SURFACE + ID_CONCAT + a); var materialType:String = xml.surface[a].@materialType; var faces:Array = []; for (var b:int = 0; b < xml.surface[a]..face.length(); b++) { if ("vertices" in xml.surface[a]..face[b]) { for (var v:int = 0; v < xml.surface[a]..face[b].vertices.length(); v++) { xml.surface[a]..face[b].vertices[v].prependChild(createVerticesPrimitive(xml.surface[a]..face[b].vertices[v])); } } // eg - f:sf (f:00) var faceName:String = xml.surface[a]..face[b].hasOwnProperty("@id") ? xml.surface[a]..face[b].@id : String(ID_FACE + ID_CONCAT + a + b); var vertices:Array = []; for (var c:int = 0; c < xml.surface[a]..face[b]..vertex.length(); c++) { // eg - v:sfv (v:000) var vertexName:String = xml.surface[a]..face[b]..vertex[c].hasOwnProperty("@id") ? xml.surface[a]..face[b]..vertex[c].@id : String(ID_VERTEX + ID_CONCAT + a + b + c); /** * createVertex */ _mesh.createVertex( xml.surface[a]..face[b]..vertex[c].@x, xml.surface[a]..face[b]..vertex[c].@y, xml.surface[a]..face[b]..vertex[c].@z, vertexName ); vertices.push(vertexName); } /** * createFace */ _mesh.createFace(vertices, faceName); with ( _mesh.getFaceById( faceName ) ) { if ( xml.surface[a]..face[b].hasOwnProperty("@click") ) addEventListener(MouseEvent3D.CLICK , main[xml.surface[a]..face[b].@click]); if ( xml.surface[a]..face[b].hasOwnProperty("@mouseDown") ) addEventListener(MouseEvent3D.MOUSE_DOWN, main[xml.surface[a]..face[b].@mouseDown]); if ( xml.surface[a]..face[b].hasOwnProperty("@mouseMove") ) addEventListener(MouseEvent3D.MOUSE_MOVE , main[xml.surface[a]..face[b].@mouseMove]); if ( xml.surface[a]..face[b].hasOwnProperty("@mouseOut") ) addEventListener(MouseEvent3D.MOUSE_OUT, main[xml.surface[a]..face[b].@mouseOut]); if ( xml.surface[a]..face[b].hasOwnProperty("@mouseOver") ) addEventListener(MouseEvent3D.MOUSE_OVER, main[xml.surface[a]..face[b].@mouseOver]); if ( xml.surface[a]..face[b].hasOwnProperty("@mouseUp") ) addEventListener(MouseEvent3D.MOUSE_UP , main[xml.surface[a]..face[b].@mouseUp]); if ( xml.surface[a]..face[b].hasOwnProperty("@mouseWheel") ) addEventListener(MouseEvent3D.MOUSE_WHEEL, main[xml.surface[a]..face[b].@mouseWheel]); } /** * setUVsToFace */ if ("UVs" in xml.surface[a]..face[b]) { with ( xml.surface[a]..face[b].UVs ) { _mesh.setUVsToFace( new Point(aUV.@x, aUV.@y), new Point(bUV.@x, bUV.@y), new Point(cUV.@x, cUV.@y), faceName ); } } /** * push Faces */ faces.push(faceName); } /** * createSurface */ _mesh.createSurface(faces, surfaceName); with ( _mesh.getSurfaceById(surfaceName) ) { if ( xml.surface[a].hasOwnProperty("@click") ) addEventListener(MouseEvent3D.CLICK , main[xml.surface[a].@click]); if ( xml.surface[a].hasOwnProperty("@mouseDown") ) addEventListener(MouseEvent3D.MOUSE_DOWN, main[xml.surface[a].@mouseDown]); if ( xml.surface[a].hasOwnProperty("@mouseMove") ) addEventListener(MouseEvent3D.MOUSE_MOVE , main[xml.surface[a].@mouseMove]); if ( xml.surface[a].hasOwnProperty("@mouseOut") ) addEventListener(MouseEvent3D.MOUSE_OUT, main[xml.surface[a].@mouseOut]); if ( xml.surface[a].hasOwnProperty("@mouseOver") ) addEventListener(MouseEvent3D.MOUSE_OVER, main[xml.surface[a].@mouseOver]); if ( xml.surface[a].hasOwnProperty("@mouseUp") ) addEventListener(MouseEvent3D.MOUSE_UP , main[xml.surface[a].@mouseUp]); if ( xml.surface[a].hasOwnProperty("@mouseWheel") ) addEventListener(MouseEvent3D.MOUSE_WHEEL, main[xml.surface[a].@mouseWheel]); } /** * push */ surfaces.push(surfaceName); /** * setMaterialToSurface */ _mesh.setMaterialToSurface( createMaterial( xml.surface[a], ( materialType == TEXTURE || materialType == MOVIECLIP ) ? textures[xml.surface[a].@name] : null), surfaceName ); } return _mesh; } /** * マテリアルを作成 * @param material マテリアル情報が記載されたXML * @return SurfaceMaterial * @exampleText XMLの例を示します * <listing version="3.0"> * <surface materialType={EZCreateMesh.FILL} color="0x99ab4e" wirethickness="1" wirecolor="0x7b8d42" /> * <surface materialType="TextureMaterial" repeat="true" smooth="true" src="image" precision="BEST" /> * </listing> */ public static function createMaterial(material:XML, texture:* = null):SurfaceMaterial { with ( material ) { switch ( @materialType.toString() ) { case DEV : return new DevMaterial( hasOwnProperty("@parametertype") ? @parametertype : 0, hasOwnProperty("@color") ? @color: 0xffffff * Math.random(), hasOwnProperty("@maxparametervalue") ? @maxparametervalue : 20, hasOwnProperty("@shownormals") ? @shownormals : false, hasOwnProperty("@normalscolor") ? @normalscolor : 0x00FFFF, hasOwnProperty("@minmobility") ? @minmobility : 0, hasOwnProperty("@maxmobility") ? @maxmobility : 255, hasOwnProperty("@alpha") ? @alpha : 1, hasOwnProperty("@blendmode") ? @blendmode : BlendMode.NORMAL, hasOwnProperty("@wirethickness") ? @wirethickness : -1, hasOwnProperty("@wirecolor") ? @wirecolor : 0 ); break; case FILL : return new FillMaterial( hasOwnProperty("@color") ? @color: 0xffffff * Math.random(), hasOwnProperty("@alpha") ? @alpha : 1, hasOwnProperty("@blendmode") ? @blendmode : BlendMode.NORMAL, hasOwnProperty("@wirethickness") ? @wirethickness : -1, hasOwnProperty("@wirecolor") ? @wirecolor : 0 ); break; case TEXTURE : return new TextureMaterial( new Texture(texture), hasOwnProperty("@alpha") ? @alpha : 1, hasOwnProperty("@repeat") ? (@repeat == "true" ? true : false) : true, hasOwnProperty("@smooth") ? (@smooth == "true" ? true : false) : false, hasOwnProperty("@blendmode") ? @blendmode : BlendMode.NORMAL, hasOwnProperty("@wirethickness") ? @wirethickness : -1, hasOwnProperty("@wirecolor") ? @wirecolor : 0, hasOwnProperty("@precision") ? @precision : 10 ); break; case WIRE : return new WireMaterial( hasOwnProperty("@thickness") ? @thickness : 0, hasOwnProperty("@color") ? @color : 0xffffff * Math.random(), hasOwnProperty("@alpha") ? @alpha : 1, hasOwnProperty("@blendmode") ? @blendmode : BlendMode.NORMAL ); break; case MOVIECLIP : return new MovieClipMaterial( MovieClip( texture ), @textureWidth, @textureHeight, new Rectangle( hasOwnProperty("@clipX") ? @clipX : 0, hasOwnProperty("@clipY") ? @clipY : 0, hasOwnProperty("@clipWidth") ? @clipWidth : 0, hasOwnProperty("@clipHeight") ? @clipHeight : 0 ), new Matrix( hasOwnProperty("@a") ? @a : 1, hasOwnProperty("@b") ? @b : 0, hasOwnProperty("@c") ? @c : 0, hasOwnProperty("@d") ? @d : 1, hasOwnProperty("@tx") ? @tx : 0, hasOwnProperty("@ty") ? @ty : 0 ), hasOwnProperty("@smooth") ? (@smooth == "true" ? true : false) : false, hasOwnProperty("@precision") ? @precision : 10, hasOwnProperty("@fillColor") ? @fillColor : 0xffffff * Math.random(), hasOwnProperty("@refreshRate") ? @refreshRate : 1 ); break; default : return null; break; } } } /** * PRIMITIVE */ /** * * @param primitive * @return */ public static function createFacesPrimitive(primitive:XML):XMLList { var _faces:XML = <faces></faces>; with (primitive) { switch ( @primitive.toString() ) { case CIRCLE : return buildCircleFaces(@tx, @ty, @tz, @r, @rp, @rv, @twoSided); case ARROW : return buildArrowFaces(@aw,@ah, @bw, @bh, @ch, @tz); default : return new XMLList(); } } function buildArrowFaces(aw:Number, ah:Number, bw:Number, bh:Number, ch:Number, tz:Number):XMLList { _faces.appendChild(<face><vertices primitive={ ARROW } rv="false" aw={aw} ah={ah} bw={bw} bh={bh} tz={tz + ch / 2} ch={ch} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax={bw} ay="0" az={tz - ch / 2} bx={bw} by="0" bz={ch / 2} cx="0" cy={bh} cz={ch / 2} dx="0" dy={bh} dz={tz - ch / 2} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax="0" ay={-bh} az={tz - ch / 2} bx="0" by={-bh} bz={ch / 2} cx={bw} cy="0" cz={ch / 2} dx={bw} dy="0" dz={tz - ch / 2} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax="0" ay={bh} az={tz - ch / 2} bx="0" by={bh} bz={ch / 2} cx="0" cy={bh - ah / 2} cz={ch / 2} dx="0" dy={bh - ah / 2} dz={tz - ch / 2} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax="0" ay={-(bh - ah / 2)} az={tz - ch / 2} bx="0" by={-(bh - ah / 2)} bz={ch / 2} cx="0" cy={-bh} cz={ch / 2} dx="0" dy={-bh} dz={tz - ch / 2} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax="0" ay={bh - ah / 2} az={tz - ch / 2} bx="0" by={bh - ah / 2} bz={ch / 2} cx={-aw} cy={bh - ah / 2} cz={ch / 2} dx={-aw} dy={bh - ah / 2} dz={tz - ch / 2} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax={-aw} ay={-(bh - ah / 2)} az={tz - ch / 2} bx={-aw} by={-(bh - ah / 2)} bz={ch / 2} cx="0" cy={-(bh - ah / 2)} cz={ch / 2} dx="0" dy={-(bh - ah / 2)} dz={tz - ch / 2} /></face>); _faces.appendChild(<face><vertices primitive = { PLANE } rv="false" ax={-aw} ay={bh - ah / 2} az={tz - ch / 2} bx={-aw} by={bh - ah / 2} bz={ch / 2} cx={-aw} cy={-(bh - ah / 2)} cz={ch / 2} dx={-aw} dy={-(bh - ah / 2)} dz={tz - ch / 2} /></face >); _faces.appendChild(<face><vertices primitive={ ARROW } rv="true" aw={aw} ah={ah} bw={bw} bh={bh} tz={tz - (ch / 2)} ch={ch} /></face>); return _faces.face; } function buildCircleFaces(tx: Number, ty: Number, tz:Number, r:Number, rp:Number, rv:String, twoSided:String = "false"): XMLList { _faces.appendChild(<face><vertices primitive={CIRCLE} tx={tx} ty={ty} tz={tz} r={r} rp={rp} rv={rv} /></face>); if (twoSided) _faces.appendChild(<face><vertices primitive={CIRCLE} tx={tx} ty={ty} tz={tz} r={r} rp={rp} rv="true" /></face>); return _faces.face; } return new XMLList(); } public static const CIRCLE:String = "Circle"; public static const ARROW:String = "Arrow"; public static const PLANE:String = "Plane"; /** * 頂点の情報を返します UV情報は含まれません。 * @param primitive * @return */ public static function createVerticesPrimitive(primitive:XML):XMLList { var _vertices:XML = <vertices></vertices>; with (primitive) { switch ( @primitive.toString() ) { case CIRCLE : return buildCircleVertices(@tx, @ty, @tz, @r, @rp, @rv); case ARROW : return buildArrowVertices(@aw, @ah, @bw, @bh, @tz, @rv); case PLANE : return buildPlaneVertices(@ax, @ay, @az, @bx, @by, @bz, @cx, @cy, @cz, @dx, @dy, @dz, @rv); case TRIANGLE : return buildTriangleVertices(@ax, @ay, @az, @bx, @by, @bz, @cx, @cy , @cz ,@rv) default : return new XMLList(); } } function buildTriangleVertices(ax:Number, ay:Number, az:Number, bx:Number, by:Number, bz:Number, cx:Number, cy:Number, cz:Number, rv:String = "false"):XMLList { if (rv == "true") { v(ax, ay, az); v(bx, by, bz); v(cx, cy, cz); } else { v(cx, cy, cz); v(bx, by, bz); v(ax, ay, az); } return _vertices.vertex } function buildPlaneVertices(ax:Number, ay:Number, az:Number, bx:Number, by:Number, bz:Number, cx:Number, cy:Number, cz:Number, dx:Number, dy:Number, dz:Number, rv:String = "false"):XMLList { if ( rv == "true" ) { v(ax, ay, az); v(bx, by, bz); v(cx, cy, cz); v(dx, dy, dz); } else { v(dx, dy, dz); v(cx, cy, cz); v(bx, by, bz); v(ax, ay, az); } return _vertices.vertex; } function buildArrowVertices(aw:Number, ah:Number, bw:Number, bh:Number, tz:Number, rv:String = "false"):XMLList { if ( rv == "true" ) { v(0, bh, tz); v(bw, 0, tz); v(0, -bh, tz); v( 0, -(bh - (ah / 2)), tz); v( -aw, -(bh - (ah / 2)), tz); v( -aw, bh - (ah / 2), tz); v( 0, bh - (ah / 2), tz); } else { v( 0, bh - (ah / 2), tz); v( -aw, bh - (ah / 2), tz); v( -aw, -(bh - (ah / 2)), tz); v( 0, -(bh - (ah / 2)), tz); v(0, -bh, tz); v(bw, 0, tz); v(0, bh, tz); } return _vertices.vertex; } function buildCircleVertices(tx: Number, ty: Number, tz:Number, r:Number, rp:Number, rv:String = "false"): XMLList { var rad:int = 0; if ( rv == "true" ) { for (rad = 0; rad < 360; rad += rp) { v(Math.cos(rad * _PI / 180) * r, Math.sin(rad * _PI / 180) * r, tz); } } else { for (rad = 360; rad > 0; rad -= rp) { v(Math.cos(rad * _PI / 180) * r, Math.sin(rad * _PI / 180) * r, tz); } } return _vertices.vertex; } /** * create v * @param _x * @param _y * @param _z */ function v(_x:Number, _y:Number, _z:Number):void { _vertices.appendChild(<vertex x={_x} y={_y} z={_z} />); } } } faces (Arrow) - EZCreateMesh