2009-04-15(Wed)

Papervision3D でブロックを崩してみる

pv3d で基本的なことをやってみる。
とりあえず、以下の要素を入れてブロック崩し(のデモ)を組んでみた。
* 当たり座標は2D
* ブロックはXMLで配置したものを読み込んで配置
* 音を鳴らそう
* オブジェクトの消去(ブロック消す)
* 酔うようなカメラの動きと画角
* ちなみに全部ブロックが消えても何も起こらない

-- 2017/05/08 --
もうFlashはアレなんでswfは削除しました。

以下ムダが多くて長いソース。
今日のの自分は明日の他人。コメントを細かめに書いておこう。
無駄な部分や間違いもあるかもしれないので参考にする人は疑ってかかるように。(^^;
Main.as
package
{
	import adobe.utils.CustomActions;
	import flash.utils.getTimer;
	import flash.display.*;
	import flash.events.*;
	import flash.text.*;
	
	import org.papervision3d.events.InteractiveScene3DEvent;
	import flash.geom.*;
	import caurina.transitions.*;
	import org.papervision3d.cameras.*;
	import org.papervision3d.view.*;
	import org.papervision3d.materials.*;
	import org.papervision3d.objects.*;
	import org.papervision3d.objects.primitives.*;
	import org.papervision3d.materials.utils.BitmapMaterialTools;
	import org.papervision3d.materials.utils.MaterialsList;
	import org.papervision3d.render.*;

	import flash.net.URLLoader;
	import flash.net.URLRequest;
	
	import flash.media.*;

	[SWF(width="400", height="300", backgroundColor="#000000", frameRate="40")]
	
	/**PaperVision3Dでブロック崩しを作ってみるテスト
	 * ...
	 * @author nakami
	 */
	public class Main extends BasicView
	{
		//プロパティ------------------------------------------------

		//3D関係
		private var room:Cube;					//大きな箱を作ってその部屋の中でプレイすることにする
		private var ball:Sphere;				//ボール
		private var paddle:Cube;				//パドル
		private var ball_sx:int = 21;			//ボール速度X方向
		private var ball_sy:int = -33;			//ボール速度Y方向
		private var rootNode:DisplayObject3D;	//ワールド座標
		private const roomWidth:int = 2200;		//部屋のサイズ
		private const roomHeight:int = 3000;
		private const roomDepth:int = 5000;
		private const paddleWidth:int = 250;	//パドルのサイズ
		private const paddleHeight:int = 50;
		private const paddleDepth:int = 80;
		private const ballW:int = 30;			//ボールの幅
		private var blkW:int;					//ブロックの幅(XMLの定義により可変)
		private const blkH:int = 100;
		private const blkTop:int = 300;			//一番上のブロックの配置開始オフセット
		private var blockArr:Array = [];		//ブロック用配列
		private var hitArr:Array = [];			//あたり判定用配列
		private var blockArrX:int;				//ブロック数ヨコ(XMLで可変)
		private var blockArrY:int;				//  〃  タテ
		//サウンド関係
		[Embed( source = 'break.mp3' )] private var BreakSound:Class;	//ブロック破壊音
		[Embed( source = 'bound.mp3' )] private var BoundSound:Class;	//ブロック破壊音
		[Embed( source = 'bound2.mp3' )] private var Bound2Sound:Class;	//ブロック破壊音
		private var brkSnd:Sound;				//サウンド型
		private var bndSnd:Sound;
		private var bnd2Snd:Sound;
		//2D関係
		private var startBtn:Sprite;			//スタートボタン
		
		/**
		 * コンストラクタ
		 */
		public function Main():void 
		{
			//XML読み込み
			var xmlLoader:URLLoader = new URLLoader();				//ローダーのインスタンス作成
			xmlLoader.addEventListener(Event.COMPLETE, makeBlock);	//読み込み完了したら showXML へ飛ぶイベントを定義
			xmlLoader.load(new URLRequest("blocks.xml"));			//読み込み開始
			//サウンドオブジェクトの作成
			brkSnd = new BreakSound();		//ブロック破壊音のインスタンス作成
			bndSnd = new BoundSound();		//バウンド音のインスタンス作成
			bnd2Snd = new Bound2Sound();	//バウンド2音のインスタンス作成
			//BasicView初期化
			super(	stage.stageWidth,	//幅
					stage.stageHeight,	//高さ
					true,				//自動的にステージ中心
					true,				//インタラクティブイベント
					CameraType.TARGET	//カメラ
				);
			//カメラ設定
			camera.focus = 1;		//フォーカス(画角超きつめ)※ちなみにマイナス値にするとひっくり返って面白い
			camera.zoom = 300;		//ズーム
			camera.x = 0;			//配置座標
			camera.y = roomHeight / 2.6;
			camera.z = -3000;
			camera.far = 6000;
			//ワールド作成
			rootNode = scene.addChild( new DisplayObject3D() );
			rootNode.x = 0;
			rootNode.y = 0;
			rootNode.z = 0;
			//部屋作成
			var roomMatList:MaterialsList = new MaterialsList(
			{
				right : new ColorMaterial( 0x888888, 1, false ),
				left  : new ColorMaterial( 0x888888, 1, false ),
				top   : new ColorMaterial( 0x555555, 1, false ),
				bottom: new ColorMaterial( 0xAAAAAA, 1, false )
			} );
			room = new Cube( roomMatList, roomWidth, roomDepth, roomHeight, 1, 1, 1, Cube.ALL, Cube.NONE );	//Cube.ALL で全面反転
			room.x = 0;
			room.y = 0;
			room.z = roomDepth / 2.2;
			//ボール作成
			ball = new Sphere( new ColorMaterial( 0xFFFFFF, 1, false ), ballW, 4, 4 );
			ball.x = 0;
			ball.y = 0;
			ball.z = 0;
			//パドル作成
			var paddleMatList:MaterialsList = new MaterialsList(
			{
				all	: new ColorMaterial( 0x8888FF, 1, false )
			} );
			paddle = new Cube( paddleMatList, paddleWidth, paddleDepth, paddleHeight, 1, 1, 1 );
			paddle.x = 0;
			paddle.y = -1 * roomHeight / 3;
			paddle.z = 0;
			//オブジェクトの配置
			rootNode.addChild( room );
			rootNode.addChild( ball );
			rootNode.addChild( paddle );
			//スタートボタン表示
			startBtn = new Sprite();
			startBtn.graphics.beginFill( 0xFFFFFF );
			startBtn.graphics.drawRect( 0, 0, 100, 20 );
			startBtn.graphics.endFill();
			startBtn.x = stage.stageWidth / 2 - 50;
			startBtn.y = stage.stageHeight / 2 -10;
			addChild( startBtn );
			var mes:TextField = new TextField;
			mes.text = "Click to start.";
			mes.autoSize = TextFieldAutoSize.CENTER;
			startBtn.addChild( mes );
			startBtn.addEventListener( MouseEvent.MOUSE_UP, startBtnClk );
		}
		
		/**
		 * スタートボタンがクリックされた
		 */
		private function startBtnClk( e:Event ):void
		{
			//スタートボタンを消す
			removeChild( startBtn );
			//レンダリング開始
//			renderer = new QuadrantRenderEngine(QuadrantRenderEngine.ALL_FILTERS);	//レンダリングエンジンを切り替えてポリゴン欠けを防ぐ
			startRendering();
			//フレーム毎にイベント発生
			addEventListener( Event.ENTER_FRAME, onEnterFrame );
		}
		
		/**
		 * フレーム毎の処理
		 */
		private function onEnterFrame( e:Event ):void 
		{
			//ボール移動
			ball.x += ball_sx;
			ball.y += ball_sy;
			//パドル移動
			paddle.x = ball.x;
			if ( paddle.x + paddleWidth / 2 > roomWidth / 2 ) {		//パドルの右端が壁に付いたら
				paddle.x = (roomWidth / 2) - (paddleWidth / 2);		//そこで止める
			}
			if ( paddle.x - paddleWidth / 2 < -roomWidth / 2 ) {	//パドルの左端が壁に付いたら
				paddle.x = (-roomWidth / 2) + (paddleWidth / 2);	//そこで止める
			}
			//ボールX方向壁のあたり判定
			if ( ball_sx > 0 ) {				//ボールの進行方向が+の場合
				if ( ball.x > ( roomWidth / 2 ) - ballW ) {			//右の壁にぶつかったら
					ball_sx *= -1;									//向き反転
					bnd2Snd.play(0, 1);								//バウンド2音再生
				}
			} else {							//ボールの進行方向が-の場合
				if ( ball.x < ( -roomWidth / 2 ) + ballW ) {		//左の壁にぶつかったら
					ball_sx *= -1;									//向き反転
					bnd2Snd.play(0, 1);								//バウンド2音再生
				}
			}
			//ボールY方向壁&パドルのあたり判定
			if ( ball_sy > 0 ) {				//ボールの進行方向が+の場合
				if ( ball.y > ( roomHeight / 2 ) - ballW ) {		//上の壁にぶつかったら
					ball_sy *= -1;									//向き反転
					bnd2Snd.play(0, 1);								//バウンド2音再生
				}
			} else {							//ボールの進行方向が-の場合
				if ( ball.y < ( -roomHeight / 3 ) + ballW ) {		//パドルの高さを超えたとき
					if ( (ball.x > paddle.x - paddleWidth / 2) && (ball.x < paddle.x + paddleWidth / 2) ) {	//ボールのX座標がパドルの幅に収まっていたら
						bndSnd.play(0, 1);							//バウンド音再生
						ball_sy *= -1;								//Y向き反転
						if ( int( Math.random() * 2 ) > 0 ) ball_sx *= -1;	//Xランダムで反転
					}
				}
			}
			//ボールとブロックのあたり判定
			for ( var bx:int = 0; bx < blockArrX; bx++ )
			{
				for ( var by:int = 0; by < blockArrY; by++  )
				{
					//ブロック配列から座標範囲を割り出し、その中にボールが入っていたらブロック消滅
					//範囲の左位置&上位置を求める
					var hitX:int = ( -roomWidth / 2 ) + bx * blkW;
					var hitY:int = ( roomHeight / 2 - blkTop ) - ( by * blkH );
					//あたり判定配列で、生き残っているブロックなら
					if ( hitArr[by][bx] == 1 )
					{
						//ボールがブロックと衝突しているか判定
						if ( (ball.x >= hitX) && (ball.x <= (hitX + blkW)) && (ball.y <= hitY) && (ball.y >= (hitY-blkH)) )
						{
							hitArr[by][bx] = 0;				//あたり判定用配列に 0 を代入
							brkSnd.play(0, 1);				//ブロック破壊音再生
							//オブジェクトの消去
							var obj:Cube = blockArr[by][bx];
							if ( obj.material )				//マテリアルが存在するならマテリアルも解放&消去
							{
								if ( obj.material.bitmap )		//ビットマップがあるなら
								{
									obj.material.bitmap.dispose();	//ビットマップを開放
								}
								obj.material.destroy();			//マテリアルを破壊
							}
							rootNode.removeChild( obj );	//シーンから削除
							//ボールの向きを変える(ブロックのどこにあたったかで次の向きが決まる)
							if ( (ball.x - hitX) < (blkW / 2) )	//ブロックの左側にあたった
							{
								//左へ反射(マイナスにする)
								if ( ball_sx > 0 ) ball_sx = -ball_sx;
							} else {							//ブロックの右側にあたった
								//右へ反射(プラスにする)
								if ( ball_sx < 0 ) ball_sx = -ball_sx;
							}
							if ( (ball.y - (hitY - blkH)) < (blkH * .85) )	//ブロックの下側にあたった
							{
								//下へ反射する(マイナスにする)
								if ( ball_sy > 0 ) ball_sy = -ball_sy;
							} else {										//ブロックの上側にあたった
								//上へ反射(プラスにする)
								if ( ball_sy < 0 ) ball_sy = -ball_sy;
							}
						}
					}
				}
			}
			//カメラ移動
			camera.x = -paddle.x / 3;
			camera.y = -ball.y + (roomHeight / 3);
			//カメラのターゲットをボールの位置にする
			camera.target.x = ball.x;
			camera.target.y = ball.y;
		}
		
		/**
		 * ブロックの配列を作成 (XML読み込み後の処理)
		 */
		private function makeBlock( evt:Event ):void
		{
			//ロードしたXMLを取得
			XML.ignoreWhitespace = true;
			var allBlocks:XML = new XML( evt.target.data );
			var by:Number;
			var lineBlocks:String;
			blockArrY = allBlocks.line.length();
			for (by = 0; by < blockArrY; by++) {								//ライン分ループ(
				lineBlocks = String( ( allBlocks.line[by] ).toString() );	//1ラインを文字列に変換
				var lineBlockArr:Array = lineBlocks.split(",");				//カンマ区切りで配列に格納
				//ブロックを配置
				blockArr[by] = [];
				hitArr[by] = [];
				for (var v:String = 0 in lineBlockArr) {
					var bx:int = int(v);
					blockArrX = bx + 1;
					if ( lineBlockArr[bx] == "1" )											//1ならブロック配置
					{
						var mat:MaterialsList = new MaterialsList(							//マテリアル
						{
							all: new ColorMaterial( int(Math.random()*0xFFFFFF), 0.5, false )		//色ランダム
						} ); 
						blkW = roomWidth / lineBlockArr.length;						//ブロック1個の幅を設定
						var blk:Cube = new Cube( mat, blkW, roomDepth/16, blkH, 1, 1);
						blk.x = ( -1 * roomWidth / 2) + (bx * blkW) + (blkW / 2);
						blk.y = (roomHeight / 2) - (by * blkH) -blkTop;
						blockArr[by][bx] = rootNode.addChild( blk );
						hitArr[by][bx] = 1;
					} else {
						hitArr[by][bx] = 0;
					}
				}
			}
			sleep( 2000 );
		}
		
		/**
		 * 指定ミリ秒待つ
		 */
		private function sleep( w:int ):void
		{
			var startTime:Number = getTimer();
			while (true) {
				if ( getTimer() - startTime >= w ) break;
			}
		}
		
	}
	
}
以下ブロック配置用のXML( 0=なし,1=ブロック )
ヨコ個数は全行揃えておけば好きな数に伸縮できる。
タテ行数も好きな数にできる。数を増やすと重くなる。
行数を増やしすぎると最初のボール出現位置とかぶっちゃう。どうなるか判らないけど試してみるのもまた楽しい。
blocks.xml
<?xml version="1.0" encoding="utf-8" ?>
<block>
	<line>1,1,1,1,1,1,1,1,1</line>
	<line>1,1,1,1,1,1,1,1,1</line>
	<line>1,1,1,0,0,0,1,1,1</line>
	<line>1,1,1,0,0,0,1,1,1</line>
	<line>1,1,1,1,1,1,1,1,1</line>
	<line>1,1,1,1,1,1,1,1,1</line>
</block>

テーマ : プログラミング
ジャンル : コンピュータ

コメントの投稿

管理者にだけ表示を許可する

コメント

プロフィール

nakami

Author:nakami
可愛いテンプレートに似合う俺
うそAチームのスミス大佐

NAVI
カテゴリー
最近の記事
リンク
FC2カウンター
ブログ内検索
RSSフィード
sponsored link