Home > Archives > 2008-10-21

2008-10-21

グニャグニャするネットを作る

以前作ったのの続き。
前回のは位置が固定されていて動かせなかったけど、どうにかして動かせるようにしました。
まだ未完ですが、勢いでUPします。


別windowでサンプルを開きます
1.png 2.png

今回はパラメーターを弄れるようにスライダーを付けていて、左からfriction(摩擦 : 0.1~0.98)、spring(バネの係数 : 0.1~1)、_POWER_COEFFICIENT(各点にかかる力を求めるための定数。自分でやっといて良く理解していない : 5~300)です。
スライダーのソース、使い方は書籍『ActionScriptアニメーション』のものを使わせて貰いました。色だけ変えてあります。

Ballクラスにtensionってパラメーターを追加し、マウスとの距離によって変え、バネ運動の際にその値を反映させています。

以下は問題点。

  • 未だにネット部分だけにあたり判定を付けるのが出来てない。
  • なのでスライダーを弄ってもネットが動く。
  • 前回も書いたけど、多分この方法は間違ってる気がする。ちゃんと点どうしが連結されていない。
  • 各値をかなり低くすると、動作がおかしい点がある。

要改善。次は回転させようと思います。

んで、僕は何がやりたいのかと言うと、
The Magic Carpet  —  Manuel’s Coding Blogとか、THE ECO ZOO | ECODA!DOBUTSUENの引っ張れる旗みたいなのを作りたいのです。
といっても3Dにしたい訳ではなく、どういう風に座標を管理しているのか、等の仕組みが知りたい。
同じように、確かFlash8が出たあたり、fladdictさんがグネグネするコーラの缶のデモを作られていた。そこのURLはもう無い(ドメインが違う)し、はっきりとは覚えていないんだけど、テクスチャも貼られていた。そういったのを作りたいのです。

今回のソース一式 net2.zip

メインとなるソースだけ載せてみます。

package
{
	import flash.display.Sprite;
	import flash.display.StageScaleMode;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import org.miniapp.customFigure.Ball;

	[SWF(backgroundColor="0x000000", width="800", height="800", frameRate="60")]
	public class Net extends Sprite
	{
		private static const _SPRING:Number = 0.5;
		private static const _FRICTION:Number = 0.5;
		private static const _COLUM:uint = 20
		private static const _ROW:uint = 20;
		private static const _NUM_BALLS:uint = _COLUM * _ROW;
		private static const _DIFF_X:uint = 20;
		private static const _DIFF_Y:uint = 20;
		private static const _START_X:uint = 200;
		private static const _START_Y:uint = 200;
		private static const _BALL_RADIUS:uint = 4;

		//TODO 名前も数値も適当。ちゃんとしたい。
		private static const _POWER_COEFFICIENT:uint = 50;

		/**
		 * コンストラクタ
		 */
		public function Net()
		{
			if (stage)
				init();
			else
				addEventListener(Event.ADDED_TO_STAGE, init);
		}

		private var _mousePressX:Number;
		private var _mousePressY:Number;
		private var _isDragging:Boolean = false;
		private var _lastMouseX:Number;
		private var _lastMouseY:Number;
		private var _balls:Array/* of Ball */
		private var _horizontalBallArray:Array/* of Array */
		private var _verticalBallsArray:Array/* of Array */
		private var _frictionSlider:SimpleSlider;
		private var _springSlider:SimpleSlider;
		private var _powerCoefficientSlider:SimpleSlider;

		private function init():void
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			stage.scaleMode = StageScaleMode.NO_SCALE;

			_frictionSlider = new SimpleSlider(0.1, 0.98, _FRICTION);
			_frictionSlider.x = 10;
			_frictionSlider.y = 10;
			addChild(_frictionSlider);

			_springSlider = new SimpleSlider(0.1, 1, _SPRING);
			_springSlider.x = 30;
			_springSlider.y = 10;
			addChild(_springSlider);

			_powerCoefficientSlider = new SimpleSlider(5, 300, _POWER_COEFFICIENT);
			_powerCoefficientSlider.x = 50;
			_powerCoefficientSlider.y = 10;
			addChild(_powerCoefficientSlider);

			_balls = [];

			//ボールを繋ぐ線を描くため、縦、横に分けて配列に入れて纏める。
			//縦に並ぶボールを入れた配列をまとめる配列
			_horizontalBallArray = [];
			//横に並ぶボールを入れた配列をまとめる配列
			_verticalBallsArray = [];

			for (var i:uint = 0; i < _COLUM; i++)
			{
				//縦に並ぶボールを管理する配列を作る
				var horizontalBalls:Array/* of Ball */ = [];
				_horizontalBallArray.push(horizontalBalls);
			}

			//ボール生成、配置
			for (i = 0; i < _ROW; i++)
			{
				//横に並ぶボールを管理する配列を作る
				var verticalBalls:Array/* of Ball */ = [];
				for (var j:uint = 0; j < _COLUM; j++)
				{
					var ball:Ball = new Ball(_BALL_RADIUS, 0xFFFFFF);
					ball.x = ball.defaultX = _START_X + _DIFF_X * j;
					ball.y = ball.defaultY = _START_Y + _DIFF_Y * i;
					_balls.push(ball);

					//縦に並ぶボールを入れる
					(_horizontalBallArray[j] as Array).push(ball);
					//横に並ぶボールを入れる
					verticalBalls.push(ball);
					//ball.cacheAsBitmap = true;
					//addChild(ball);
				}
				_verticalBallsArray.push(verticalBalls);
			}

			drawLine();
			stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
			stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
		}

		/**
		 * ボール同士を線で繋ぐ
		 */
		private function drawLine():void
		{
			graphics.clear();
			graphics.lineStyle(1, 0xFFFFFF);

			//縦のラインを引く
			for (var i:uint = 0; i < _COLUM; i++)
			{
				var horizontalBalls:Array = _horizontalBallArray[i] as Array;
				var firstBall:Ball = Ball(horizontalBalls[0]);
				graphics.moveTo(firstBall.x, firstBall.y);
				for (var j:uint = 1; j < _COLUM; j++)
				{
					var ball:Ball = Ball(horizontalBalls[j]);
					graphics.lineTo(ball.x, ball.y);
				}
			}

			//横のラインを引く
			for (i = 0; i < _ROW; i++)
			{
				var verticalBalls:Array = _verticalBallsArray[i] as Array;
				firstBall = Ball(verticalBalls[0]);
				graphics.moveTo(firstBall.x, firstBall.y);
				for (j = 1; j < _ROW; j++)
				{
					ball = Ball(verticalBalls[j]);
					graphics.lineTo(ball.x, ball.y);
				}
			}
		}

		/**
		 * バネ運動させる
		 * @param	ball バネ運動させるボール
		 * @param	targetPoint 目標位置
		 */
		private function springTo(ball:Ball, targetX:Number, targetY:Number):void
		{
			ball.vx += (targetX - ball.x) * _springSlider.value * ball.tension;
			ball.vy += (targetY - ball.y) * _springSlider.value * ball.tension;

			ball.vx *= _frictionSlider.value;
			ball.vy *= _frictionSlider.value;

			ball.x  += ball.vx;
			ball.y  += ball.vy;
		}

		private function enterFrameHandler(e:Event):void
		{
			if (_isDragging)
			{
				//マウスが移動した距離を調べる
				var dxMouse:Number = mouseX - _lastMouseX;
				var dyMouse:Number = mouseY - _lastMouseY;
			}

			for (var i:uint = 0; i < _NUM_BALLS; i++)
			{
				var ball:Ball = Ball(_balls[i]);
				if (_isDragging)
				{
					//マウスが押された地点とボールの距離を調べる
					var dx:Number = mouseX - ball.x;
					var dy:Number = mouseY - ball.y;
					var distance:Number = Math.sqrt(dx * dx + dy * dy);

					//マウスとボールの位置からボールにかかる力を算出
					//マウスから近いボールほど引っ張られる力が大きくなる
					var tension:Number = _powerCoefficientSlider.value / ( _powerCoefficientSlider.value + distance);
					ball.tension = tension;

					//目的地を算出
					var toX:Number = ball.defaultX + dxMouse;
					var toY:Number = ball.defaultY + dyMouse;
				}
				else
				{
					toX = ball.defaultX;
					toY = ball.defaultY;
				}

				springTo(ball, toX, toY);
				ball.defaultX = toX;
				ball.defaultY = toY;
			}

			drawLine();

			//マウス位置を記憶
			_lastMouseX = mouseX;
			_lastMouseY = mouseY;
		}

		private function mouseDownHandler(e:MouseEvent):void
		{
			_isDragging = true;
			_mousePressX = mouseX;
			_mousePressY = mouseY;
		}

		private function mouseUpHandler(e:MouseEvent):void
		{
			_isDragging = false;
		}
	}
}

Home > Archives > 2008-10-21

Return to page top