// forked from nitoyon's PV3D で某ゲームを3D化してみた // [遊び方] // ・クリックでジャンプする // ・それだけ package { import flash.events.Event; import org.papervision3d.view.*; import org.papervision3d.objects.*; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Common.Math.*; [SWF(backgroundColor="#000000", width="475", height="475")] public class Test extends BasicView { // character private var character:Character; // ジャンプ中の状態 private var jump:Boolean; private var prevJump:Boolean; private var world:b2World; public function Test() { super(475, 475, false); { var aabb:b2AABB = new b2AABB(); // 適当 aabb.lowerBound.Set(-512, -512); aabb.upperBound.Set(512, 512); var g:b2Vec2 = new b2Vec2(0., -10.0); world = new b2World(aabb, g, true); } stage.scaleMode = "noScale"; stage.align = "TL"; CharacterGenerator.init(init); } private function init():void { // マップとキャラクタを準備する Map.populateScene(scene, world); scene.addChild(character = new Character(world)); // カメラの初期位置を設定 camera.focus = 700; camera.z = -14000; camera.x = 2000; camera.y = 5000; // 描画開始 startRendering(); // アニメーション stage.addEventListener("keyDown", function(event:Event):void{jump = true;}); stage.addEventListener("click", function(event:Event):void{jump = true;}); } // BasicView の描画処理 protected override function onRenderTick(e:Event = null):void { super.onRenderTick(e); world.Step(1/10., 10); for (var b:b2Body = world.GetBodyList(); b; b = b.GetNext()) { if (b.GetUserData() is DisplayObject3D) { var obj:DisplayObject3D = b.GetUserData(); var pos:b2Vec2 = b.GetPosition(); obj.rotationZ = 180 * b.GetAngle() / Math.PI; var com:b2Vec2 = b.GetLocalCenter(); obj.x = pos.x; obj.y = pos.y; } } // キャラクターの状態を更新する if (prevJump && jump) { jump = false; } prevJump = jump; character.update(jump); } } } import flash.display.*; import flash.events.Event; import flash.geom.*; import flash.utils.ByteArray; import mx.utils.Base64Decoder; import org.papervision3d.core.proto.*; import org.papervision3d.materials.*; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.*; import org.papervision3d.objects.primitives.*; import org.papervision3d.view.*; import Box2D.Dynamics.*; import Box2D.Collision.*; import Box2D.Collision.Shapes.*; class CharacterData { // 画像を BASE64 化したもの public static const data:String = "R0lGODlhEQEQALMLAP/////Mmf+ZM/9mAP8zAMz/AJlmAGaZ/zPM/wCZAAAAAP///wAAAAAAAAAAAAAAACH5BAEAAAsALAAAAAARARAAAAT/8MhJ6xkh66ywHtcgjuRonZOCoupaJXAsx8ps325+KHyr/0BXD0AsGo+Alm+1aDoJ0KhzSqUKroLgIVAaKbjeAXZMvi6FCW3ivLrNeu64tqIo2AvsuZ6F7CNVCkk5VFGFUlWGBAtjWmBdXyQdAgplY5R5FjVpQTCYL3GdPKA4ejx3d557e4F+rUWsqQdUBrQGV7ZVTYmFV41dIpBhYyVksTsxap06o2uizDKlp6eAqtUUrthG1ChTtAK2t1hVteC25L6/Xx3AYlfAPCKWOZowycoucaJwz8hzddKo8FhTxSObwSSCTnQzB+6bOCfeGpajhe7RgB7rsABzdxFLKnr1/zjJSJVPE0h+0aQlkGZsIJ2DMBNaWNjwW61ZDLFIrFjiywZJHCkJ2GhmxclNQGx4KsmPVJB/BWDcWYnKpRZWMbNhqlJJwDhvOskt4BnJ0cV2Zih58cjC6Y8bmJg2nXF1KsBpVq9mxeYJpwECN3M16WqgCVkvZoEOu8iDbSY39t6cmDv3R4+7mAXuKNVDL4AD2BDwdUHzLy3AtCCSM326sOEgZstGQquxozw6ckTCtUC5qQ6ome8C0gwEq0zLREADEH2E+WhuTVYXEru6Fuq/Cyg+XSd7dqXGt1OAiqz0U29m84Kr/9dyh3Ei7SWwOoCgfpH69u/72Tr4FgEBUABYk/hN5BiSnQGNBAAPYj3RxlEZSxxFl25uLHHeMzmop6Ed2xi132bIGYEffsuN2AoT/V2RSCVR/PVfgKj5wkEPsZ1VBlGOHTMKebtJcCF6LAC3YWZ1fNRKIO0NcZ9zJTKpTV8p7vKfV7e4KKV2QDiiQTDeCeWRl5fIhyEFGPFgHigt/LjjCUIOuZ4QSDgZ3w5/7AdfLIRIUUhpUsYI2yOxwdMVhDoCuc9IZh7Ajwpqjsemm256glV+y2njD1aAGGdmooOollp0gRWYCBVaMIYRBmV2kOqqGDXlDJoSVthobo9C+iYfRDh5xJwpcOqer0B4+umBN6VmYC4RAAA7"; public static const CHARACTER_WIDTH:int = 16; public static const SKY:int = 0; // Sky public static const GRD:int = 1; // Ground public static const BLQ:int = 2; // Block question public static const MT0:int = 3; // Mountain left public static const MT1:int = 4; // Mountain top public static const MT2:int = 5; // Mountain right public static const MT3:int = 6; // Mountain with tree public static const MT4:int = 7; // Mountain background public static const BU0:int = 8; // Bush left public static const BU1:int = 9; // Bush mid public static const BU2:int = 10; // Bush right public static const CL0:int = 11; // Cloud left top public static const CL1:int = 12; // Cloud mid top public static const CL2:int = 13; // Cloud right top public static const CL3:int = 14; // Cloud left bottom public static const MR0:int = 15; // MaOio still public static const MR1:int = 16; // MaOio jumping } class CharacterGenerator { private static var bmdChars:Array = null; public static function init(continuation:Function):void { var decoder:Base64Decoder = new Base64Decoder(); decoder.decode(CharacterData.data); var bytes:ByteArray = decoder.toByteArray(); bytes.position = 0; var loader:Loader = new Loader(); loader.loadBytes(bytes); loader.contentLoaderInfo.addEventListener("complete", function(event:Event):void { var bmdBundle:BitmapData = new BitmapData(loader.width, loader.height); bmdBundle.draw(loader); var numChars:int = loader.width / CharacterData.CHARACTER_WIDTH; var _bmdChars:Array = new Array(numChars); for (var i:int = 0; i < numChars; i++) { var bmdChar:BitmapData = new BitmapData(16, 16); bmdChar.copyPixels(bmdBundle, new Rectangle( i * CharacterData.CHARACTER_WIDTH, 0, CharacterData.CHARACTER_WIDTH, CharacterData.CHARACTER_WIDTH), new Point()); _bmdChars[i] = bmdChar; } bmdChars = _bmdChars; continuation(); } ); } // 指定したタイプのマテリアルを取得する。 public static function get(code:int):BitmapData { return bmdChars[code]; } } // キャラクタ クラス class Character extends Plane { // 画像一覧 private var characterImages:Array; // キャラクタ用の Sprite private var character:Sprite; // 表示情報 private var jumping:Boolean; private var vy:int; // 主人公の実装 public function Character(world:b2World) { super(null, 17, 16); // 画像を準備 var bmd1:BitmapData = CharacterGenerator.get(CharacterData.MR0); var bmd2:BitmapData = CharacterGenerator.get(CharacterData.MR1); bmd1.threshold(bmd1, bmd1.rect, new Point(), "==", 0xffffffff, 0, 0xffffffff); // 背景透過 bmd2.threshold(bmd2, bmd2.rect, new Point(), "==", 0xffffffff, 0, 0xffffffff); characterImages = [new Bitmap(bmd1), new Bitmap(bmd2)]; // character に追加 character = new Sprite(); for each (var img:Bitmap in characterImages) { character.addChild(img); img.visible = false; } setImage(0); // Plane の設定 material = new MovieMaterial(character, true, true); x = -64; y = -40; z = -8; } // 状態を更新 public function update(jump:Boolean):void { if (jump && !jumping) { vy = 9; jumping = true; } if (jumping) { y += vy; if (vy < -8) { vy = 0; jumping = false; } vy--; } setImage(jumping ? 1 : 0); } // 表示する画像(静止・ジャンプ中)を更新する private function setImage(num:int):void { for (var i:int = 0; i < characterImages.length; i++) { characterImages[i].visible = (num == i); } } } // マップデータ class Map extends CharacterData { // マップの種類を定義 private static var mapTypeIndex:int = 0; // マップ配置 private static const map:Array = [ [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT0, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT0, MT3, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT1, MT3, MT4, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT2, MT3, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT2, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, GRD, GRD], [SKY, SKY, SKY, CL1, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, GRD, GRD], [SKY, SKY, CL0, CL2, SKY, SKY, SKY, BLQ, SKY, SKY, SKY, SKY, GRD, GRD], [SKY, SKY, SKY, CL3, SKY, SKY, SKY, SKY, BLQ, SKY, SKY, SKY, GRD, GRD], [SKY, SKY, SKY, SKY, CL1, SKY, SKY, SKY, SKY, SKY, SKY, BU0, GRD, GRD], [SKY, BLQ, SKY, CL0, CL2, SKY, SKY, SKY, SKY, SKY, SKY, BU1, GRD, GRD], [SKY, SKY, SKY, CL0, CL2, SKY, SKY, SKY, SKY, SKY, SKY, BU1, GRD, GRD], [SKY, SKY, SKY, SKY, CL3, SKY, SKY, SKY, SKY, SKY, SKY, BU2, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, BLQ, SKY, SKY, MT0, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT1, MT3, GRD, GRD], [SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, SKY, MT2, GRD, GRD] ]; private static var materialCache:Array = []; private static var shapeData:Object = {}; private static function createBoxShape():b2PolygonDef { var boxshape:b2PolygonDef = new b2PolygonDef(); boxshape.SetAsBox(CHARACTER_WIDTH / 2, CHARACTER_WIDTH / 2); return boxshape; } private static function prepareShapeData(): void { var boxshape:b2PolygonDef; boxshape = createBoxShape(); boxshape.friction = .3; boxshape.restitution = .7; boxshape.density = .5; shapeData[BLQ] = boxshape; boxshape = createBoxShape(); boxshape.friction = .4; boxshape.restitution = .3; boxshape.density = 0; shapeData[GRD] = boxshape; } prepareShapeData(); // 指定したタイプのマテリアルを取得する。 public static function getMaterial(mapType:int):MaterialObject3D { if (materialCache[mapType]) return materialCache[mapType]; materialCache[mapType] = new BitmapMaterial( CharacterGenerator.get(mapType)); return materialCache[mapType]; } // scene にマップを追加する public static function populateScene( scene:DisplayObjectContainer3D, world:b2World):void { for (var xx:int = 0; xx < map.length; xx++) { for (var yy:int = 0; yy < map[yy].length; yy++) { var mapType:int = map[xx][yy]; var x:Number = xx * CHARACTER_WIDTH - CHARACTER_WIDTH / 2 - 128; var y:Number = -yy * CHARACTER_WIDTH + CHARACTER_WIDTH / 2 + 128; var obj:DisplayObject3D; if (mapType == GRD || mapType == BLQ) { obj = new Plane(getMaterial(SKY), CHARACTER_WIDTH, CHARACTER_WIDTH); obj.x = x, obj.y = y, obj.z = 0; scene.addChild(obj); obj = new Cube(new MaterialsList({all: getMaterial(mapType)}), CHARACTER_WIDTH, CHARACTER_WIDTH, CHARACTER_WIDTH); obj.x = x, obj.y = y, obj.z = -8; scene.addChild(obj); } else { obj = new Plane(getMaterial(mapType), CHARACTER_WIDTH, CHARACTER_WIDTH); obj.x = x, obj.y = y, obj.z = 0; scene.addChild(obj); } if (shapeData[mapType]) { var boxdef:b2BodyDef = new b2BodyDef(); boxdef.position.Set(obj.x, obj.y); var box:b2Body = world.CreateBody(boxdef); box.CreateShape(shapeData[mapType]); box.SetUserData(obj); box.SetMassFromShapes(); box.GetLocalCenter().x += Math.random() - .5; box.GetLocalCenter().y += Math.random() - .5; } } } } } forked from: PV3D で某ゲームを3D化してみた