forked from: Billiards (1)
Billiards (1)
ビリヤードもどき (4) [AS2.0]
http://www.project-nya.jp/modules/weblog/details.php?blog_id=839
TODO
1. 不具合(すり抜け)対策 2. 効果音
/**
* Copyright narutohyper ( http://wonderfl.net/user/narutohyper )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/35lz
*/
// forked from ProjectNya's Billiards (1)
////////////////////////////////////////////////////////////////////////////////
// Billiards (1)
//
// ビリヤードもどき (4) [AS2.0]
// http://www.project-nya.jp/modules/weblog/details.php?blog_id=839
//
// TODO
// 1. 不具合(すり抜け)対策 2. 効果音
////////////////////////////////////////////////////////////////////////////////
package {
import flash.display.Sprite;
import flash.display.StageScaleMode;
import flash.display.StageAlign;
import flash.display.StageDisplayState;
import flash.display.Shape;
import flash.geom.Rectangle;
import flash.events.Event;
import flash.events.MouseEvent;
[SWF(backgroundColor="#EEEEEE", width="465", height="465", frameRate="30")]
public class Main extends Sprite {
private var base:Shape;
private var controller:Sprite;
private var fullscreenBtn:Btn;
private var normalBtn:Btn;
private var rect:Rectangle;
private var area:Rectangle;
private var billiards:Billiards;
public function Main() {
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.align = StageAlign.TOP_LEFT;
stage.addEventListener(Event.RESIZE, resize, false, 0, true);
init();
}
private function init():void {
base = new Shape();
base.graphics.beginFill(0x339900);
base.graphics.drawRect(0, 0, 465, 465);
base.graphics.endFill();
base.graphics.beginFill(0x336600);
base.graphics.drawRect(5, 5, 455, 455);
base.graphics.endFill();
controller = new Sprite();
addChild(controller);
controller.x = 232;
controller.y = 445;
fullscreenBtn = new Btn();
controller.addChild(fullscreenBtn);
fullscreenBtn.init({label: "play", width: 80});
fullscreenBtn.addEventListener(MouseEvent.CLICK, click, false, 0, true);
normalBtn = new Btn();
controller.addChild(normalBtn);
normalBtn.init({label: "close", width: 80});
normalBtn.addEventListener(MouseEvent.CLICK, click, false, 0, true);
normalBtn.visible = false;
rect = new Rectangle(0, 0, 1200, 600);
billiards = new Billiards(rect);
resize();
}
private function resize(evt:Event = null):void {
update();
screenMode();
}
private function update():void {
var sw:uint = stage.stageWidth;
var sh:uint = stage.stageHeight;
var cx:uint = uint(sw/2);
var cy:uint = uint(sh/2);
billiards.x = cx - 600;
billiards.y = cy - 300;
controller.x = cx;
if (sh == 465) {
controller.y = cy;
} else {
controller.y = cy + 340;
}
}
private function screenMode():void {
if (stage.displayState == StageDisplayState.NORMAL) {
fullscreenBtn.visible = true;
normalBtn.visible = false;
addChildAt(base, 0);
if (contains(billiards)) {
billiards.stop();
removeChild(billiards);
}
} else {
fullscreenBtn.visible = false;
normalBtn.visible = true;
if (contains(base)) removeChild(base);
addChildAt(billiards, 0);
billiards.start();
}
}
private function click(evt:MouseEvent):void {
if (stage.displayState == StageDisplayState.NORMAL) {
stage.displayState = StageDisplayState.FULL_SCREEN;
} else {
stage.displayState = StageDisplayState.NORMAL;
}
}
}
}
//////////////////////////////////////////////////
// Billiardsクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.display.Shape;
import flash.geom.Rectangle;
import flash.events.Event;
class Billiards extends Sprite {
private var rect:Rectangle;
private static var max:uint = 9;
private static var radius:uint = 25;
private var area:Rectangle;
private static var colors:Array;
private var base:Shape;
private var balls:Array;
private static var limit:uint = radius*2;
private var xMin:uint;
private var xMax:uint;
private var yMin:uint;
private var yMax:uint;
public function Billiards(r:Rectangle) {
rect = r;
init();
}
private function init():void {
draw();
colors = new Array();
colors.push(0xFFFFFF);
colors.push(0xFF9900);
colors.push(0x0066FF);
colors.push(0xFF0066);
colors.push(0x6633CC);
colors.push(0x339900);
colors.push(0xFF6600);
colors.push(0x0033FF);
colors.push(0xFF3366);
colors.push(0x993399);
colors.push(0x006600);
area = new Rectangle(rect.x+radius+5, rect.y+radius+5, rect.width-radius*2-10, rect.height-radius*2-10);
xMin = area.left;
xMax = area.right;
yMin = area.top;
yMax = area.bottom;
setup();
}
private function setup():void {
balls = new Array();
for (var n:uint = 0; n <= max; n++) {
var ball:Ball = new Ball(radius, colors[n]);
addChild(ball);
ball.x = area.x + Math.random()*area.width;
ball.y = area.y + Math.random()*area.height;
ball.setup(n);
balls.push(ball);
}
}
public function start():void {
addEventListener(Event.ENTER_FRAME, update, false, 0, true);
}
public function stop():void {
removeEventListener(Event.ENTER_FRAME, update);
}
private function update(evt:Event):void {
position();
checkHit();
against();
motion();
manageDepths();
}
private function position():void {
for (var n:uint = 0; n < max+1; n++) {
var ball:Ball = balls[n];
ball.position();
}
}
private function checkHit():void {
for (var n:uint = 0; n < max; n++) {
var ball0:Ball = balls[n];
for (var t:uint = n+1; t < max+1; t++) {
var ball1:Ball = balls[t];
repulsion(ball0, ball1);
}
}
}
private function motion():void {
for (var n:uint = 0; n < max+1; n++) {
var ball:Ball = balls[n];
ball.motion();
}
}
private function repulsion(ball0:Ball, ball1:Ball):void {
var x0:Number = ball0.px;
var y0:Number = ball0.py;
var vx0:Number = ball0.vx;
var vy0:Number = ball0.vy;
var x1:Number = ball1.px;
var y1:Number = ball1.py;
var vx1:Number = ball1.vx;
var vy1:Number = ball1.vy;
var d:Number = distance(x0, x1, y0, y1);
if (d <= limit) {
var l:Number = (limit - d)/limit;
var v0:Number = speed(vx0, vy0);
var v1:Number = speed(vx1, vy1);
var r:Number = (v0 + v1)/d*2 + l;
ball0.repulsion((x0 - x1)*r, (y0 - y1)*r);
ball1.repulsion((x1 - x0)*r, (y1 - y0)*r);
}
}
private function distance(x0:Number, x1:Number, y0:Number, y1:Number):Number {
var d:Number = Math.sqrt((x1 - x0)*(x1 - x0) + (y1 - y0)*(y1 - y0));
return d;
}
private function speed(vx:Number, vy:Number):Number {
var r:Number = Math.sqrt(vx*vx + vy*vy);
return r;
}
private function against():void {
for (var n:uint = 0; n < max+1; n++) {
var ball:Ball = balls[n];
var wall:Number;
if (ball.px < (wall = xMin) || ball.px > (wall = xMax)) {
ball.against("x", wall);
} else if (ball.py < (wall = yMin) || ball.py > (wall = yMax)) {
ball.against("y", wall);
}
}
}
private function manageDepths():void {
balls.sortOn(["y", "id"], [Array.CASEINSENSITIVE | Array.NUMERIC, Array.DESCENDING | Array.NUMERIC]);
for (var n:uint = 0; n < max; n++) {
var ball:Ball = balls[n];
addChildAt(ball, n+2);
}
}
private function draw():void {
base = new Shape();
base.graphics.beginFill(0x339900);
base.graphics.drawRect(rect.x, rect.y, rect.width, rect.height);
base.graphics.endFill();
base.graphics.beginFill(0x336600);
base.graphics.drawRect(rect.x+5, rect.y+5, rect.width-10, rect.height-10);
base.graphics.endFill();
addChild(base);
}
}
//////////////////////////////////////////////////
// Ballクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.display.Shape;
import flash.filters.DropShadowFilter;
import flash.filters.GlowFilter;
import flash.geom.Matrix;
import flash.display.GradientType;
import flash.display.SpreadMethod;
import flash.display.InterpolationMethod;
import flash.display.BlendMode;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.AntiAliasType;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.events.MouseEvent;
class Ball extends Sprite {
public var id:uint;
private var radius:uint;
private var color:uint;
private var ball:Sprite;
private var base:Shape;
private var shadow:Shape;
private var light:Shape;
private var reflection:Shape;
private var txt:TextField;
private var shade:Shape;
private static var bColor:uint = 0xFFFFFF;
private static var sColor:uint = 0x000000;
public var px:Number;
public var py:Number;
private var xTarget:Number;
private var yTarget:Number;
public var vx:Number;
public var vy:Number;
private static var deceleration:Number = 0.1;
private static var rebounce:Number = 5;
private static var cueRange:Number = 5:
private var line:Shape;
public function Ball(r:uint, c:uint) {
radius = r;
color = c;
draw();
}
private function draw():void {
shade = new Shape();
addChild(shade);
shade.y = radius;
createShade();
ball = new Sprite();
addChild(ball);
base = new Shape();
ball.addChild(base);
shadow = new Shape();
ball.addChild(shadow);
light = new Shape();
ball.addChild(light);
reflection = new Shape();
ball.addChild(reflection);
createBase();
createShadow();
createLight();
createReflect();
}
public function setup(n:uint):void {
id = n;
if (id > 0) {
txt = new TextField();
ball.addChild(txt);
createTxt();
} else {
setCueBall();
setCueLine();
}
xTarget = px = x;
yTarget = py = y;
}
private function setCueBall():void {
parent.addEventListener(MouseEvent.MOUSE_DOWN, press, false, 0, true);
parent.addEventListener(MouseEvent.MOUSE_MOVE, track, false, 0, true);
parent.addEventListener(MouseEvent.MOUSE_UP, release, false, 0, true);
}
private function press(evt:MouseEvent):void {
xTarget = px + mouseX*cueRange;
yTarget = py + mouseY*cueRange;
}
private function release(evt:MouseEvent):void {
line.graphics.clear();
}
private function setCueLine():void {
line = new Shape();
parent.addChildAt(line, 1);
}
private function track(evt:MouseEvent):void {
line.graphics.clear();
line.graphics.lineStyle(40, bColor, 0.2);
line.graphics.moveTo(px, py);
line.graphics.lineTo(px + mouseX, py + mouseY);
line.graphics.lineStyle(40, bColor, 0.1);
line.graphics.lineTo(px + mouseX*cueRange, py + mouseY*cueRange);
evt.updateAfterEvent();
}
public function repulsion(dx:Number, dy:Number):void {
if (id != 0) {
dx *= rebounce;
dy *= rebounce;
}
xTarget = px + dx;
yTarget = py + dy;
}
public function against(direction:String, wall:Number):void {
var target:Number = this[direction+"Target"];
this[direction+"Target"] = wall*2 - target;
}
public function position():void {
vx = (xTarget - px)*deceleration;
vy = (yTarget - py)*deceleration;
px += vx;
py += vy;
}
public function motion():void {
x = px;
y = py;
}
private function createBase():void {
base.graphics.clear();
base.graphics.beginFill(color, 0.8);
base.graphics.drawCircle(0, 0, radius);
base.graphics.endFill();
}
private function createShadow():void {
var colors:Array = [sColor, sColor, sColor];
var alphas:Array = [0, 0.2, 0.3];
var ratios:Array = [0, 191, 255];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(radius*3.2, radius*3.2, 0, -radius*2, -radius*2);
shadow.graphics.beginGradientFill(GradientType.RADIAL, colors, alphas, ratios, matrix, SpreadMethod.PAD, InterpolationMethod.RGB, 0);
shadow.graphics.drawCircle(0, 0, radius);
shadow.graphics.endFill();
shadow.blendMode = BlendMode.HARDLIGHT;
}
private function createLight():void {
var colors:Array = [bColor, bColor, bColor];
var alphas:Array = [1, 0.2, 0];
var ratios:Array = [0, 191, 255];
var matrix:Matrix = new Matrix();
matrix.createGradientBox(radius*3.2, radius*3.2, 0, -radius*2, -radius*2);
light.graphics.beginGradientFill(GradientType.RADIAL, colors, alphas, ratios, matrix, SpreadMethod.PAD, InterpolationMethod.RGB, 0);
light.graphics.drawCircle(0, 0, radius);
light.graphics.endFill();
light.blendMode = BlendMode.OVERLAY;
}
private function createReflect():void {
var colors:Array = [bColor, bColor];
var alphas:Array = [0.7, 0];
var ratios:Array = [0, 191];
var matrix:Matrix = new Matrix();
var w:Number = radius*1.44;
var h:Number = radius*1.35;
var yOffset:Number = radius*0.95;
matrix.createGradientBox(w, h, 0.5*Math.PI, -w*0.5, -yOffset);
reflection.graphics.beginGradientFill(GradientType.LINEAR, colors, alphas, ratios, matrix, SpreadMethod.PAD, InterpolationMethod.RGB, 0);
reflection.graphics.drawEllipse(-w*0.5, -yOffset, w, h);
reflection.graphics.endFill();
}
private function createTxt():void {
txt.x = -radius*0.5;
txt.y = -radius*0.6;
txt.width = radius;
txt.height = radius;
txt.type = TextFieldType.DYNAMIC;
txt.selectable = false;
//txt.embedFonts = true;
//txt.antiAliasType = AntiAliasType.ADVANCED;
var tf:TextFormat = new TextFormat();
tf.font = "_ゴシック";
tf.size = 20;
tf.align = TextFormatAlign.CENTER;
txt.defaultTextFormat = tf;
txt.text = String(id);
txt.textColor = bColor;
var glow:GlowFilter = new GlowFilter(bColor, 1, 4, 4, 6, 3, false, true);
txt.filters = [glow];
}
private function createShade():void {
shade.graphics.beginFill(sColor, 0.6);
shade.graphics.drawEllipse(-radius*0.75, -radius*0.1775, radius*1.5, radius*0.375);
shade.graphics.endFill();
var shadow:DropShadowFilter = new DropShadowFilter(0, 90, sColor, 0.5, radius*0.15, radius*0.15, 1, 3, false, false, true);
shade.filters = [shadow];
}
}
//////////////////////////////////////////////////
// Btnクラス
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.AntiAliasType;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.filters.GlowFilter;
import flash.events.MouseEvent;
class Btn extends Sprite {
public var id:uint;
private var shade:Shape;
private var bottom:Shape;
private var light:Shape;
private var base:Shape;
private var txt:TextField;
private var label:String = "";
private static var fontType:String = "_ゴシック";
private var _width:uint = 60;
private static var _height:uint = 20;
private static var corner:uint = 5;
private var type:uint = 1;
private static var bColor:uint = 0xFFFFFF;
private static var sColor:uint = 0x000000;
private static var upColor:uint = 0x666666;
private static var overColor:uint = 0x333333;
private static var offColor:uint = 0x999999;
private static var gColor:uint = 0x0099FF;
private var blueGlow:GlowFilter;
private var shadeGlow:GlowFilter;
private var _clicked:Boolean = false;
private var _enabled:Boolean = true;
public function Btn() {
}
public function init(option:Object):void {
if (option.id != undefined) id = option.id;
if (option.label != undefined) label = option.label;
if (option.width != undefined) _width = option.width;
if (option.type != undefined) type = option.type;
draw();
}
private function draw():void {
switch (type) {
case 1 :
bColor = 0xFFFFFF;
sColor = 0x000000;
upColor = 0x666666;
overColor = 0x333333;
offColor = 0x999999;
break;
case 2 :
bColor = 0x000000;
sColor = 0xFFFFFF;
upColor = 0x666666;
overColor = 0x999999;
offColor = 0x333333;
break;
}
blueGlow = new GlowFilter(gColor, 0.6, 5, 5, 2, 3, false, true);
shadeGlow = new GlowFilter(sColor, 0.3, 4, 4, 2, 3, false, true);
shade = new Shape();
bottom = new Shape();
light = new Shape();
base = new Shape();
txt = new TextField();
addChild(shade);
addChild(bottom);
addChild(light);
addChild(base);
addChild(txt);
createBase(shade, _width, _height, corner, sColor);
shade.filters = [shadeGlow];
createBase(bottom, _width, _height, corner, sColor, 0.3);
createBase(light, _width, _height, corner, gColor);
light.filters = [blueGlow];
createBase(base, _width, _height, corner, bColor);
txt.x = -_width*0.5;
txt.y = -_height*0.5;
txt.width = _width;
txt.height = _height - 1;
txt.type = TextFieldType.DYNAMIC;
txt.selectable = false;
//txt.embedFonts = true;
//txt.antiAliasType = AntiAliasType.ADVANCED;
var tf:TextFormat = new TextFormat();
tf.font = fontType;
tf.size = 12;
tf.align = TextFormatAlign.CENTER;
txt.defaultTextFormat = tf;
txt.text = label;
enabled = true;
mouseChildren = false;
}
private function rollOver(evt:MouseEvent):void {
_over();
}
private function rollOut(evt:MouseEvent):void {
_up();
}
private function press(evt:MouseEvent):void {
_down();
}
private function release(evt:MouseEvent):void {
_up();
}
private function click(evt:MouseEvent):void {
}
private function _up():void {
txt.y = -_height*0.5;
txt.textColor = upColor;
base.y = -1;
light.visible = false;
light.y = -1;
}
private function _over():void {
txt.y = -_height*0.5;
txt.textColor = overColor;
base.y = -1;
light.visible = true;
light.y = -1;
}
private function _down():void {
txt.y = -_height*0.5 + 1;
txt.textColor = overColor;
base.y = 0;
light.visible = true;
light.y = 0;
}
private function _off():void {
txt.y = -_height*0.5 + 1;
txt.textColor = offColor;
base.y = 0;
light.visible = false;
light.y = 0;
}
public function get clicked():Boolean {
return _clicked;
}
public function set clicked(param:Boolean):void {
_clicked = param;
enabled = !_clicked;
if (_clicked) {
_down();
} else {
_up();
}
}
public function get enabled():Boolean {
return _enabled;
}
public function set enabled(param:Boolean):void {
_enabled = param;
buttonMode = _enabled;
mouseEnabled = _enabled;
useHandCursor = _enabled;
if (_enabled) {
_up();
addEventListener(MouseEvent.MOUSE_OVER, rollOver, false, 0, true);
addEventListener(MouseEvent.MOUSE_OUT, rollOut, false, 0, true);
addEventListener(MouseEvent.MOUSE_DOWN, press, false, 0, true);
addEventListener(MouseEvent.MOUSE_UP, release, false, 0, true);
addEventListener(MouseEvent.CLICK, click, false, 0, true);
} else {
_off();
removeEventListener(MouseEvent.MOUSE_OVER, rollOver);
removeEventListener(MouseEvent.MOUSE_OUT, rollOut);
removeEventListener(MouseEvent.MOUSE_DOWN, press);
removeEventListener(MouseEvent.MOUSE_UP, release);
removeEventListener(MouseEvent.CLICK, click);
}
}
private function createBase(target:Shape, w:uint, h:uint, c:uint, color:uint, alpha:Number = 1):void {
target.graphics.beginFill(color, alpha);
target.graphics.drawRoundRect(-w*0.5, -h*0.5, w, h, c*2);
target.graphics.endFill();
}
}