Home > Archives > 2008-08-08
2008-08-08
球が通り抜ける布みたいなのを作る
- 2008-08-08 (金)
- flash
前回(バネ運動するネットみたいなのを作る)からの続き。
ドラッグすると球が大きくなります。
別windowでサンプルを開きます

前回(バネ運動するネットみたいなのを作る)は引っ張るネットを作りましたが、やっぱりProcreoFlashDesign Laboratory ボールと布や、52sec.orgさんのデモのようなのを作りたいので、挑戦しました。
まずは一個のボールをマウスに反応させるところから。
マウスとボールの位置を計算して、その距離に応じてボールが反応するようなのを作ってみた。
次は数を増やしていきます。
今回は線を連結しているボールは表示せず、ただ位置のプロパティを持っているだけのPlotPointってクラスを作って、マス目だけを引く事にしました。
球の座標の求め方が最初は分からなくて試行錯誤してしまったのですが、
ググったらすぐ出てきました。
<参考URL>
座標変換公式
1から始める数学 ベクトル解析 座標系 (ここの球座標系のところ。)
最初から調べればよかった…。
球の座標を求めた後、更に透視投影で座標変換してみたですが、変換しなかった際と比べ、あまり差がなかったので、結局、透視投影での変換はしてません。なのでZ値は無視しています。
一応今回のメインコード。
前回と変わったのはenterFrameHandler内ぐらいで、あとは大体やってる事は一緒です。
package
{
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.events.MouseEvent;
import org.miniapp.point.PlotPoint;
[SWF(backgroundColor="0xFFFFFF", width="700", height="700", frameRate="60")]
public class SphereNet extends Sprite
{
private static const _THETA_LIMIT:Number = Math.PI / 2; //90度
private static const _MAX_RADIUS:uint = 200;
private static const _MIN_RADIUS:uint = 100;
private static const _SPRING:Number = 0.2;
private static const _FRICTION:Number = 0.9;
private static const _COLUM:uint = 20;
private static const _ROW:uint = 20;
private static const _NUM_POINTS:uint = _COLUM * _ROW;
private static const _DIFF_X:uint = 20;
private static const _DIFF_Y:uint = 20;
private static const _START_X:uint = 160;
private static const _START_Y:uint = 160;
/**
* コンストラクタ
*/
public function SphereNet()
{
init();
}
private var _sphereRadius:uint = SphereNet._MIN_RADIUS;
private var _points:Array/* of PlotPoint */
private var _horizontalPointsArray:Array/* of Array */
private var _verticalPointsArray:Array/* of Array */
public function init():void
{
stage.scaleMode = StageScaleMode.NO_SCALE;
_points = [];
//ポイントを繋ぐ線を描くため、縦、横に分けて配列に入れて纏める。
//縦に並ぶポイントを入れた配列をまとめる配列
_horizontalPointsArray = [];
//横に並ぶポイントを入れた配列をまとめる配列
_verticalPointsArray = [];
for (var i:uint = 0; i < SphereNet._COLUM; i++)
{
//縦に並ぶボールを管理する配列を作る
var horizontalPoints:Array/* of PlotPoint */ = [];
_horizontalPointsArray.push(horizontalPoints);
}
//ポイント生成
for (i = 0; i < SphereNet._ROW; i++)
{
//横に並ぶボールを管理する配列を作る
var verticalPoints:Array/* of PlotPoint */ = [];
for (var j:uint = 0; j < SphereNet._COLUM; j++)
{
var point:PlotPoint = new PlotPoint();
point.x = point.defaultX = _START_X + _DIFF_X * j;
point.y = point.defaultY = _START_Y + _DIFF_Y * i;
_points.push(point);
//縦に並ぶポイントを入れる
(_horizontalPointsArray[j] as Array).push(point);
//横に並ぶポイントを入れる
verticalPoints.push(point);
}
_verticalPointsArray.push(verticalPoints);
}
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
}
/**
* ボールを元の大きさにする
* @param e
*/
private function mouseUpHandler(e:MouseEvent):void
{
_sphereRadius = SphereNet._MIN_RADIUS;
}
/**
* ボールを大きくする
* @param e
*/
private function mouseDownHandler(e:MouseEvent):void
{
_sphereRadius = SphereNet._MAX_RADIUS;
}
private function enterFrameHandler(e:Event):void
{
for (var i:uint = 0; i < SphereNet._NUM_POINTS; i++)
{
var point:PlotPoint = PlotPoint(_points[i]);
var dx:Number = point.defaultX - mouseX;
var dy:Number = point.defaultY - mouseY;
var distance:Number = Math.sqrt(dx * dx + dy * dy);
//球の半径内にいる点に対して球の上に乗った時の座標計算
//参考 http://kenpei-web.hp.infoseek.co.jp/math/coordinates/index.html
if (distance <= _sphereRadius)
{
//距離と球の半径の関係から力がかかる倍率を決める
var powerRate:Number = distance / _sphereRadius;
//Z軸からXY平面への角度
var theta:Number = SphereNet._THETA_LIMIT * powerRate;
//真上から見た角度
var angle:Number = Math.atan2(dy, dx);
var sin:Number = Math.sin(theta);
var toX:Number = mouseX + _sphereRadius * sin * Math.cos(angle);
var toY:Number = mouseY + _sphereRadius * sin * Math.sin(angle);
springTo(point, toX, toY);
}
else
springTo(point, point.defaultX, point.defaultY);
}
drawLine();
}
/**
* ポイントをバネ運動させる
* @param point
* @param targetX
* @param targetY
*/
private function springTo(point:PlotPoint, targetX:Number, targetY:Number):void
{
point.vx += (targetX - point.x) * SphereNet._SPRING;
point.vy += (targetY - point.y) * SphereNet._SPRING;
point.vx *= SphereNet._FRICTION;
point.vy *= SphereNet._FRICTION;
point.x += point.vx;
point.y += point.vy;
}
/**
* ポイント同士を線で繋ぐ
*/
private function drawLine():void
{
graphics.clear();
graphics.lineStyle(1, 0x000000);
//縦のラインを引く
for (var i:uint = 0; i < SphereNet._COLUM; i++)
{
var horizontalPoints:Array = _horizontalPointsArray[i] as Array;
var firstPoint:PlotPoint = PlotPoint(horizontalPoints[0]);
graphics.moveTo(firstPoint.x, firstPoint.y);
for (var j:uint = 1; j < SphereNet._COLUM; j++)
{
var point:PlotPoint = PlotPoint(horizontalPoints[j]);
graphics.lineTo(point.x, point.y);
}
}
//横のラインを引く
for (i = 0; i < SphereNet._ROW; i++)
{
var verticalPoints:Array = _verticalPointsArray[i] as Array;
firstPoint = PlotPoint(verticalPoints[0]);
graphics.moveTo(firstPoint.x, firstPoint.y);
for (j = 1; j < SphereNet._ROW; j++)
{
point = PlotPoint(verticalPoints[j]);
graphics.lineTo(point.x, point.y);
}
}
}
}
}
- Comments: 0
- Trackbacks (Close): 0
Home > Archives > 2008-08-08
