カニ漁
「大人の科学マガジン vol.27」の付録
Japanino と光残像キット・P.O.V を使った魚釣りゲーム
--------------------------------------------------
カニ漁
--------------------------------------------------
■遊び方
P.O.V のハンドルを回すとリ漁船の網が上がります。
ハンドルを止めると網が下がります。
網を上下にうまくコントロールして、カニを漁船の中に引き上げると、
P.O.V の LEDユニットにカニが表示されます。
※ 画面をクリックでも P.O.V のハンドルを回すかわりになります。
※ ゲームクリアはありません。
mail:usami@i-tach.com
--------------------------------------------------
参考:セットアップ方法の詳細に関しては、以下のページでの説明を
参照してください。
大人の科学マガジンVol.27
http://otonanokagaku.net/magazine/vol27/
wonderfl x japanino
http://wonderfl.net/event/japanino/
注意:光残像キットは、あまり激しく操作すると壊れてしまうことが
ありますので注意してください。
/**
* Copyright usami ( http://wonderfl.net/user/usami )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/wpxN
*/
// 「大人の科学マガジン vol.27」の付録
// Japanino と光残像キット・P.O.V を使った魚釣りゲーム
// --------------------------------------------------
// カニ漁
// --------------------------------------------------
//
// ■遊び方
//
// P.O.V のハンドルを回すとリ漁船の網が上がります。
// ハンドルを止めると網が下がります。
// 網を上下にうまくコントロールして、カニを漁船の中に引き上げると、
// P.O.V の LEDユニットにカニが表示されます。
//
// ※ 画面をクリックでも P.O.V のハンドルを回すかわりになります。
//
// ※ ゲームクリアはありません。
//
// mail:usami@i-tach.com
//
// --------------------------------------------------
//
// 参考:セットアップ方法の詳細に関しては、以下のページでの説明を
// 参照してください。
//
// 大人の科学マガジンVol.27
// http://otonanokagaku.net/magazine/vol27/
//
// wonderfl x japanino
// http://wonderfl.net/event/japanino/
//
// 注意:光残像キットは、あまり激しく操作すると壊れてしまうことが
// ありますので注意してください。
package {
import flash.display.Graphics;
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Loader;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.utils.Timer;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.events.MouseEvent;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import Box2D.Dynamics.*;
import Box2D.Collision.*;
import Box2D.Collision.Shapes.*;
import Box2D.Common.Math.*;
import Box2D.Dynamics.Joints.b2Joint;
import Box2D.Dynamics.Joints.b2MouseJoint;
import Box2D.Dynamics.Joints.b2MouseJointDef;
import funnel.*;
[SWF(frameRate="30")]
public class JapaninoFishingExample extends Sprite {
private var _japanino:Arduino;
private var loader1:Loader;
private var loader2:Loader;
private var loadCnt:int = 0;
public var m_world:b2World;
public var m_iterations:int = 10;
public var m_timeStep:Number = 1.0 / 30.0;
private var body:b2Body;
private var ami:b2Body;
private var bodyDef:b2BodyDef;
private var boxDef:b2PolygonDef;
private var circleDef:b2CircleDef;
private var mouseJointDef:b2MouseJointDef;
private var mouseJoint:b2MouseJoint;
private var xGCnt:int = 0;
private var efCnt:int = 0;
private var amiY:Number = 3;
private var container:Sprite;
private var cntBmpData:BitmapData;
private var cntBmp:Bitmap;
private var amiSp:Sprite
private var amiPt1:Point;
private var amiPt2:Point;
private var line:Sprite;
private var tx:TextField;
private var fm:TextFormat;
//-----------------------------------------------------
//コンストラクタ
public function JapaninoFishingExample() {
//カニ画像
var url:String = "http://assets.wonderfl.net/images/related_images/d/d2/d202/d20265e99e54231799ebc88f7edbcfd7755ec5f4";
loader1 = new Loader();
loader1.load(new URLRequest(url), new LoaderContext(true));
loader1.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler);
//船画像
url = "http://assets.wonderfl.net/images/related_images/3/3d/3d1a/3d1a1353a9c41b0849060661537fb7debab44fa0";
loader2 = new Loader();
loader2.load(new URLRequest(url), new LoaderContext(true));
loader2.contentLoaderInfo.addEventListener(Event.COMPLETE, loadCompleteHandler);
container = new Sprite();
addChild(container);
var config:Configuration = Arduino.FIRMATA;
_japanino = new Arduino(config);
_japanino.addEventListener(FunnelEvent.READY, onJapaninoReady);
}
//-----------------------------------------------------
//画像ロード完了
private function loadCompleteHandler(e:Event):void {
loadCnt++
if (loadCnt == 2) {
set_init();
}
}
//画像ロード完了
private function set_init():void{
// シミュレーションする座標の範囲を指定する
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(-100.0, -100.0);
worldAABB.upperBound.Set(100.0, 100.0);
var gravity:b2Vec2 = new b2Vec2(0.0, 3.0);// 重力を定義する
var doSleep:Boolean = false;//物体が動いていないときに処理削減するか
m_world = new b2World(worldAABB, gravity, doSleep);// 世界のインスタンスを作成する
//海
var umi:Sprite = new Sprite();
umi.graphics.beginFill(0x1F5CEB);
umi.graphics.drawRect(0, 0, 465, 465);
container.addChild(umi);
//空
var sora:Sprite = new Sprite();
sora.graphics.beginFill(0x79D0FF);
sora.graphics.drawRect(0, 0, 465, 115);
container.addChild(sora);
//雲
var kumo1:Sprite = getKumo();
var kumo2:Sprite = getKumo();
var kumo3:Sprite = getKumo();
kumo1.x = 50; kumo1.y = -20;
kumo2.x = -40; kumo2.y = 50;
kumo3.x = 360; kumo3.y = 35;
container.addChild(kumo1);
container.addChild(kumo2);
container.addChild(kumo3);
//壁
setWall(-1.3, 1, 0.3, 3, 0x584130);
setWall(6.6, 1, 0.3, 3, 0x584130);
setWall( 3, 4.5, 4, 0.6, 0x584130);
//船壁
setWall(1.62, 0.75, 0.01, 0.4,0x333333);
setWall(3.02, 0.75, 0.01, 0.4,0x333333);
setWall( 2.32, 0.2, 0.6, 0.01, 0x333333);
//アミ(糸)
line = new Sprite();
container.addChild(line);
//アミ(底)
bodyDef.position.x = 2.32;
bodyDef.position.y = 3.6;
rW = 0.6;
rH = 0.02;
boxDef = new b2PolygonDef();
boxDef.SetAsBox(rW , rH*0.1);
boxDef.density = 3000;//密度
boxDef.friction = 0.05;//摩擦
boxDef.restitution = 0.0001;//跳ね返り
amiSp = new Sprite();
amiSp.graphics.beginFill(0x000000);
amiSp.graphics.drawRect( -5, -5, 10, 10);
amiPt1 = new Point(-5,0);
amiPt2 = new Point(5,0);
bodyDef.userData = amiSp;
bodyDef.userData.width = 100 * 2 * rW;
bodyDef.userData.height = 100 * 2 * rH;
container.addChild(bodyDef.userData);
ami = m_world.CreateBody(bodyDef);//物体を作る
ami.CreateShape(boxDef);//形を物体に追加する
ami.SetMassFromShapes();//重さを計算する
//船
addChild(loader2)
loader2.x = 112;
// カニ
for (var i:int = 1; i < 6; i++){
bodyDef = new b2BodyDef();
bodyDef.position.x = Math.random() * 3+1.2;
bodyDef.position.y = Math.random() * 1.2+1.6;
var rW:Number = 0.5;
var rH:Number = 0.4;
boxDef = new b2PolygonDef();
var sp:Sprite = getKani();
bodyDef.userData = sp;
boxDef.SetAsBox(rW * 0.7, rH * 0.85);
boxDef.density = 0.3;//密度
boxDef.friction = 0.005;//摩擦
boxDef.restitution = 0.0001;//跳ね返り
bodyDef.userData.width = 100 * 2 * rW;
bodyDef.userData.height = 100 * 2 * rH;
body = m_world.CreateBody(bodyDef);//物体を作る
body.CreateShape(boxDef);//形を物体に追加する
body.SetMassFromShapes();//重さを計算する
container.addChild(bodyDef.userData);
}
//テキスト
fm = new TextFormat();
fm.size = 90;
fm.bold = true;
fm.color = 0xff0000;
tx = new TextField();
tx.text = "大漁!!!";
tx.visible = false;
tx.autoSize = TextFieldAutoSize.LEFT;
tx.setTextFormat(fm);
tx.x = 87; tx.y = 10;
addChild(tx);
//ドットフィルタ
var dot:Sprite = new Sprite();
var len:int = 465 / 3;
for (i = 0; i <= len; i++)
{
dot.graphics.beginFill(0x000000,0.2);
dot.graphics.drawRect(i*3, 0, 1, 465);
}
len = 465 / 2;
for (i = 0; i <= len; i++)
{
dot.graphics.beginFill(0x000000,0.2);
dot.graphics.drawRect(0, i*2, 465, 1);
}
addChild(dot);
mouseJointDef = new b2MouseJointDef();// マウスジョイントを定義する
mouseJointDef.body1 = m_world.GetGroundBody();// 片方のbodyにはワールド全体を設定する
mouseJointDef.body2 = ami;// もう片方には移動させたい物体を設定する
mouseJointDef.target = ami.GetWorldCenter();// 車体の中心座標を設定する
mouseJointDef.maxForce = 7000;// マウスで引っ張られるときの力
mouseJointDef.timeStep = 1 / 30;// シミュレーションの間隔
mouseJoint = b2MouseJoint(m_world.CreateJoint(mouseJointDef));//マウスジョイントを作る
stage.addEventListener(MouseEvent.CLICK, clickHandler);
cntBmpData = new BitmapData(465, 465);
cntBmp = new Bitmap(cntBmpData);
addEventListener(Event.ENTER_FRAME, Update, false, 0, true);
}
//画像をチェックして P.O.V に送る
private function set_imgCheck():void {
var pattern:Array = [];
var rowStr:String;
var checkN:int = 0;
for (var i:int = 0; i < 15; i++)
{
rowStr = "";
for (var n:int = 6; n >= 0; n--)
{
var col:uint = cntBmpData.getPixel(i * 9 + 169, n * 10 + 30);
var r:uint = ( col & 0xff0000 ) >> 16;
var b:int = (r > 150)? 1 : 0;
rowStr = rowStr + String(b);
checkN += b;
}
pattern.push(parseInt(rowStr, 2))
}
if (checkN > 1) {//船にカニが入った場合
tx.visible = true;
}else {//船にカニが入ってない場合
tx.visible = false;
}
// パターンをカスタムのメッセージとしてJapaninoに転送する
_japanino.sendSysexMessage(0x10, pattern);
}
//-----------------------------------------------------
/**
* ハンドラ
*/
// EnterFrame
private function Update(e:Event):void{
m_world.Step(m_timeStep, m_iterations);
// Go through body list and update sprite positions/rotations
for (var bb:b2Body = m_world.m_bodyList; bb; bb = bb.m_next) {
if (bb.m_userData is Sprite){
bb.m_userData.x = bb.GetPosition().x * 100;
bb.m_userData.y = bb.GetPosition().y * 100;
bb.m_userData.rotation = bb.GetAngle() * (180 / Math.PI);
}
}
//アミの糸描画
var gPt1:Point = amiSp.localToGlobal(amiPt1);
var gPt2:Point = amiSp.localToGlobal(amiPt2);
var clossY:Number = (gPt1.y + gPt2.y) * 0.5 - 90;
var g:Graphics = line.graphics;
g.clear();
g.lineStyle(2, 0x000000, 0.2);
g.moveTo(gPt1.x, gPt1.y);
g.lineTo(232, clossY);
g.moveTo(gPt2.x, gPt2.y);
g.lineTo(232, clossY);
g.lineTo(232, 30);
if (efCnt % 2 == 0) {
cntBmpData.draw(container);
}
if (Math.random() < 0.5) xGCnt++;
m_world.m_gravity.x = Math.cos(xGCnt*0.1)*2;//重力変更
if (amiY < 3.9) amiY += 0.02;
mouseJoint.SetTarget(new b2Vec2(2.32, amiY)); // マウスジョイントのカーソル位置を更新
efCnt++
}
// JapaninoReady
private function onJapaninoReady(e:Event):void {
// Japaninoからのイベントに対してイベントリスナをセット
_japanino.addEventListener(FunnelEvent.FIRMATA_STRING, onMessage);
// 光残像キットの全面消灯のパターン(7行×19桁)
var pattern:Array = [
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),
parseInt("0000000", 2),];
// パターンをカスタムのメッセージとしてJapaninoに転送して表示をクリアする
_japanino.sendSysexMessage(0x10, pattern);
}
// Japaninoからメッセージを受信
private function onMessage(event:FunnelEvent):void {
// メッセージが"!"であれば(=光残像キットのハンドルが回転した通知であれば)
if (event.message == "!") {
set_imgCheck();
if (amiY > 1.2) amiY -= 0.3;
}
}
// Click
private function clickHandler(e:MouseEvent):void {
set_imgCheck();
if (amiY > 1.2) amiY -= 0.35;
}
//-----------------------------------------------------
//雲を返す
private function getKumo():Sprite {
var _kumo:Sprite = new Sprite();
var xs:Array = [0, 31, 71, 21, 58];
var ys:Array = [10, 0, 4, 31, 26];
for (var i:int = 0; i < 5; i++)
{
_kumo.graphics.beginFill(0xffffff);
_kumo.graphics.drawCircle(xs[i], ys[i], 25);
}
_kumo.scaleY = 0.85;
return _kumo;
}
//壁を配置
private function setWall(_x:Number,_y:Number,_w:Number,_h:Number,col:uint):void {
bodyDef = new b2BodyDef();//物体の定義を作る
bodyDef.position.Set(_x, _y);
boxDef = new b2PolygonDef();
boxDef.SetAsBox(_w, _h);
boxDef.friction = 0.01;//摩擦
boxDef.density = 0;//密度
var sp:Sprite = new Sprite();
sp.graphics.beginFill(col);
sp.graphics.drawRect( -5, -5, 10, 10);
bodyDef.userData = sp;
bodyDef.userData.width = 100 * 2 * _w;
bodyDef.userData.height = 100 * 2 * _h;
container.addChild(bodyDef.userData);
body = m_world.CreateBody(bodyDef);//物体を作る
body.CreateShape(boxDef);//形を物体に追加する
body.SetMassFromShapes();
}
//カニSpriteを返す
private function getKani():Sprite {
var myBitmapData:BitmapData = new BitmapData(loader1.width, loader1.height, true, 0x00000000);
myBitmapData.draw(loader1);
var bmp:Bitmap = new Bitmap(myBitmapData);
var sp:Sprite = new Sprite();
bmp.x = -bmp.width * 0.5;
bmp.y = -bmp.height * 0.5;
sp.addChild(bmp);
return sp;
}
//-----------------------------------------------------
}
}