こんにちは。きんくまです。
なんだかんだで8月ですね。蝉もたくさん鳴いてます。
今回は内積による表裏の位置判定をしたあとに、もし裏だったら表に位置補正するというものです。
言葉だとよくわからないと思うので、作りました。
■遊び方
・各玉をドラッグできる
・補正ありをチェックすると表の位置だけになるように補正開始
3点の玉を互いにばねとして干渉させあった場合に、赤い玉は表側、裏側の2点で収束する位置ができます。
これに表裏の判定をつけてあげることで、表側にだけ居続けることができます。位置によっては補正が弱い場合もあるけど…。
内積の位置判定は以下のサイトからそのままもってきています。ありがとうございます。
>> 点が線を境にどちら側にあるか判定を取る(HAKUHIN’s home page)
それで、これをどう利用するかといいますと、形状記憶みたいなことができます。クラゲ時計では、ほっておくともとの形状に戻る力が働きます。
>> クラゲ時計を見る
以下ソースです。
Main
package { import flash.display.Graphics; import flash.display.MovieClip; import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Rectangle; public class Main extends Sprite { public var frontBack:MovieClip; public var correctSwitch:MovieClip; public var currentDragMC:MovieClip; public var canvas:Sprite; public var isCorrectSpring:Boolean = true; public var ball:Ball; public var basePoint1:Ball; public var basePoint2:Ball; public var balls:Array; public var arrow:MovieClip; public var startBtn:MovieClip; public function Main() { init(); } private function init():void { balls = [basePoint1, basePoint2, ball]; canvas = new Sprite(); addChildAt(canvas, 0); registerEvent(); initLook(); startBtn.addEventListener(MouseEvent.CLICK, startBtnClickHD); } private function startBtnClickHD(e:MouseEvent):void { startBtn.removeEventListener(MouseEvent.CLICK, startBtnClickHD); startBtn.visible = false; stage.addEventListener(Event.ENTER_FRAME, enterframeHD); } private function enterframeHD(e:Event):void { update(); draw(); } private function draw():void { var g:Graphics = canvas.graphics; g.clear(); g.lineStyle(1, 0x999999, 1); g.moveTo(basePoint1.x, basePoint1.y); g.lineTo(basePoint2.x, basePoint2.y); } private function update():void { var i:int, j:int; var myball:Ball; var target:Ball; for (i = 0; i < 3; i++) { if (i == 0 || i == 1) { //continue; } myball = balls[i]; myball.initDvector(); for (j = 0; j < 3; j++) { if (i == j) { continue; } target = balls[j]; myball.updateDVector(target); myball.updateDVector(target); } if (i < 2) { myball.updateVector(); } } correctVector(); ball.updateVector(); updateArrow(); } private function updateArrow():void { var dx:Number = basePoint2.x - basePoint1.x; var dy:Number = basePoint2.y - basePoint1.y; var rad:Number = Math.atan2(dy, dx) + Math.PI; arrow.rotation = 180 * rad / Math.PI; arrow.x = dx / 2 + basePoint1.x; arrow.y = dy / 2 + basePoint1.y; } //裏と表によって元の位置に戻すように補正 private function correctVector():void { var dx1:Number = basePoint2.x - basePoint1.x; var dy1:Number = basePoint2.y - basePoint1.y; var tmp:Number = dx1; dx1 = -dy1; dy1 = tmp; var dx2:Number = ball.x - basePoint1.x; var dy2:Number = ball.y - basePoint1.y; //内積 var productSpace:Number = dx1 * dx2 + dy1 * dy2; //裏側だったら if (productSpace < 0) { frontBack.gotoAndStop("back"); if (!ball.isDragging && isCorrectSpring) { var dx3:Number = (basePoint2.x + basePoint1.x) / 2 + dx1; var dy3:Number = (basePoint2.y + basePoint1.y) / 2 + dy1; ball.dvx += dx3 - ball.x; ball.dvy += dy3 - ball.y; } }else { frontBack.gotoAndStop("front"); } } private function initLook():void { frontBack.gotoAndStop("front"); correctSwitch.gotoAndStop("on"); } private function registerEvent():void { correctSwitch.addEventListener(MouseEvent.CLICK, correctSwitchClickHD); correctSwitch.buttonMode = true; } private function correctSwitchClickHD(e:MouseEvent):void { isCorrectSpring = !isCorrectSpring; if (isCorrectSpring) { correctSwitch.gotoAndStop("on"); }else { correctSwitch.gotoAndStop("off"); } } } }
Ball
package { import flash.display.MovieClip; import flash.events.MouseEvent; import flash.geom.Rectangle; public class Ball extends MovieClip { public var dvx:Number = 0; public var dvy:Number = 0; public var vx:Number = 0; public var vy:Number = 0; public var spring:Number = 0.07; public var friction:Number = 0.8; public var isDragging:Boolean = false; public var springLen:Number = 100; public function Ball() { this.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHD); this.buttonMode = true; } private function mouseDownHD(e:MouseEvent):void { isDragging = true; this.startDrag(false, new Rectangle(0,0,stage.stageWidth, stage.stageHeight)); stage.addEventListener(MouseEvent.MOUSE_UP, stageMouseUpHD); } private function stageMouseUpHD(e:MouseEvent):void { isDragging = false; this.stopDrag(); stage.removeEventListener(MouseEvent.MOUSE_UP, stageMouseUpHD); } public function initDvector():void { dvx = 0; dvy = 0; } public function updateDVector(target:MovieClip):void { if (isDragging) { return; } var rad:Number = Math.atan2(this.y - target.y, this.x - target.x); var targetX:Number = target.x + Math.cos(rad) * springLen; var targetY:Number = target.y + Math.sin(rad) * springLen; dvx += targetX - this.x; dvy += targetY - this.y; } public function updateVector():void { vx += dvx * spring; vy += dvy * spring; vx *= friction; vy *= friction; this.x += vx; this.y += vy; if (x < 0) { x = 0; }else if (x > stage.stageWidth) { x = stage.stageWidth; } if (y < 0) { y = 0; }else if (y > stage.stageHeight) { y = stage.stageHeight; } } } }
■ 自作iPhoneアプリ 好評発売中!
・フォルメモ - シンプルなフォルダつきメモ帳
・ジッピー電卓 - 消費税や割引もサクサク計算!
■ LINEスタンプ作りました!
毎日使える。とぼけたウサギ