forked from: 3D VOCALOID RUNS!
forked from 3D VOCALOID RUNS! (diff: 454)
ActionScript3 source code
/**
* Copyright tepe ( http://wonderfl.net/user/tepe )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/oUf0
*/
// forked from daniwell's 3D VOCALOID RUNS!
package
{
import alternativa.engine3d.core.Camera3D;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.core.Resource;
import alternativa.engine3d.core.View;
import alternativa.engine3d.lights.AmbientLight;
import alternativa.engine3d.lights.DirectionalLight;
import alternativa.engine3d.lights.OmniLight;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.primitives.Plane;
import alternativa.engine3d.resources.BitmapTextureResource;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.types.Texture;
import flash.display.*;
import flash.display3D.Context3DRenderMode;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.geom.Point;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.system.LoaderContext;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.ui.Keyboard;
import flash.text.*;
import flash.geom.*;
public class ModelRun extends Sprite
{
// MMD でモーション付けて、Blender のプラグインで読み込んで COLLADA 書き出しするだけ
// 但しモーションに IK は使えない
private const PATH_DAEIDLE :Array = ["http://aidn.jp/_wonderfl/vr/miku_idle.dae", "http://aidn.jp/_wonderfl/vr/rin_idle.dae", "http://aidn.jp/_wonderfl/vr/len_idle.dae"];
private const PATH_DAERUN :Array = ["http://aidn.jp/_wonderfl/vr/miku_run.dae", "http://aidn.jp/_wonderfl/vr/rin_run.dae", "http://aidn.jp/_wonderfl/vr/len_run.dae"];
private const PATH_TEXTURE :Array = ["http://aidn.jp/_wonderfl/vr/miku_texture.png", "http://aidn.jp/_wonderfl/vr/rin_texture.png", "http://aidn.jp/_wonderfl/vr/len_texture.png"];
private const CAMERA_DISTANCE :Number = 600;
private const BOX_NUMS :int = 30;
private var _texture :BitmapData;
private var _daeIdle :XML;
private var _daeRun :XML;
private var _n :int = int(Math.random() * 3);
private var _stage3D :Stage3D;
private var _camera :Camera3D;
private var _scene :Object3D;
private var _model :ColladaModel;
private var _shadow :Plane;
private var _boxes :/*CustomBox*/Array = [];
private var _keyFlags :/*Boolean*/Array = [];
private var _t :Number = 0;
private var _rot :Number = 0;
private var _rotTmp :Number = -90;
private var _cameraZ :Number = 50;
private var _tfLoading :TextField;
private var cmap:CraftMap;// = new CraftMap();
private var tf:TextField;
public function ModelRun () {
stage.scaleMode = "noScale";
stage.align = "TL";
// Now Loading
_tfLoading = addChild(new TextField()) as TextField;
_tfLoading.defaultTextFormat = new TextFormat("_sans", 42, 0x999999, true);
_tfLoading.autoSize = "left"; _tfLoading.text = "NOW LOADING...";
stage.addEventListener(Event.ENTER_FRAME, _enterFrame);//メインループ
// Stage3D
_stage3D = stage.stage3Ds[0];
_stage3D.addEventListener(Event.CONTEXT3D_CREATE, _contextCreate);// #01
_stage3D.requestContext3D(Context3DRenderMode.AUTO);
tf = new TextField();
addChild(tf);
tf.background = true;
tf.text = "test\n";
}
// #01
private function _contextCreate ( evt :Event ) :void {
tf.appendText("1\n");
_stage3D.removeEventListener(Event.CONTEXT3D_CREATE, _contextCreate);// #01
// IDLE 時データ読み込み #02
var ul :URLLoader = new URLLoader(); ul.addEventListener(Event.COMPLETE, _loadCompleteIdle); ul.load(new URLRequest(PATH_DAEIDLE[_n]));
}
// #02
private function _loadCompleteIdle ( evt :Event ) :void {
tf.appendText("2\n");
_daeIdle = XML(URLLoader(evt.target).data);
// RUN 時データ読み込み #03
var ul :URLLoader = new URLLoader(); ul.addEventListener(Event.COMPLETE, _loadCompleteRun); ul.load(new URLRequest(PATH_DAERUN[_n]));
}
// #03
private function _loadCompleteRun ( evt :Event ) :void {
tf.appendText("3\n");
_daeRun = XML(URLLoader(evt.target).data);
var l :Loader = new Loader();
l.contentLoaderInfo.addEventListener(Event.COMPLETE, _loadCompleteTexture);// #04
l.load(new URLRequest(PATH_TEXTURE[_n]), new LoaderContext(true));
}
// #04
private function _loadCompleteTexture ( evt :Event ) :void {
tf.appendText("4\n");
_tfLoading.visible = false;
_texture = Bitmap(evt.target.content).bitmapData;//テクスチャ画像
_scene = new Object3D();
_camera = new Camera3D(1, 10000);
_camera.view = new View(stage.stageWidth, stage.stageHeight);
_camera.view.hideLogo();//ロゴ非表示
addChild(_camera.view);
//addChild(_camera.diagram);//パフォーマンス表示
_camera.rotationX = MathUtil.toRad(-90);
_camera.x = 0; _camera.y = 0; _camera.z = 250;
_camera.fov = 1.8;
_scene.addChild(_camera);
//cmap.initMap(100,100,100);
cmap = new CraftMap();
cmap.initMap(100,100,100);
tf.appendText("\n");
//var n:int = cmap.sx;
//tf.appendText(n.toString()+"\n");
//tf.appendText(cmap.sx.toString()+"\n");
// Box
/* for (var i :int = 0; i < BOX_NUMS; i ++){
//for (var i :int = 0; i < cmap.sx; i ++){
//if(100<i)break;
//_boxes.push(new CustomBox(_scene));
var b:Block = new Block(_scene);
b.setColor(0xff0000);
var k:int = Math.random()*10;
b.setPos(i*200,k*100,-250);
_boxes.push(b);
}
*/
var bmp3:BitmapData = tex();
var ar:Array = new Array();
var texAr:Array = new Array();
for(i=0;i<16;i++){
for(j=0;j<3;j++){
var bm4:BitmapData = func2(bmp3,i*16,j*16,16,16);
texAr.push(new Texture(bm4));
//ar.push(new TextureMaterial(texAr[i*16+j],1,true,true));
}
}
///*
for(var i:int=0;i<cmap.sx;i++){
//if(5<i)b
for(var j:int=0;j<cmap.sy;j++){
for(var k:int=0;k<cmap.sz;k++){
if(cmap.getBlock(i,j,k)==0)continue;
var b:Block = new Block(_scene);
var n:int = cmap.getBlock(i,j,k);
if(n!=0){
//b.setMaterialToSurface(ar[n*3],"top");
}
if(cmap.getBlock(i,j,k)==9)b.setColor(0x0000ff);
else b.setColor(0xff0000);
b.setPos(i*100,j*100,k*100);
_boxes.push(b);
}
}
}
//*/
// Model
_model = new ColladaModel(_stage3D, _scene);
_model.init(_daeIdle, _texture, 0, 0, -300, 100);
_model.addAnimation(_daeIdle, 0);
_model.addAnimation(_daeRun, 1);
// Shadow
var bmd :BitmapData = new BitmapData(128, 128, false, 0x0);
var sp :Shape = new Shape(); sp.graphics.beginFill(0xffffff); sp.graphics.drawCircle(64, 64, 64); sp.graphics.endFill();
bmd.draw(sp);
var material :TextureMaterial = new TextureMaterial(new BitmapTextureResource(new BitmapData(128, 128, false, 0x333333)), new BitmapTextureResource(bmd));
material.alphaThreshold = 1;
_shadow = new Plane(100, 100);
_shadow.setMaterialToAllSurfaces(material);
_shadow.z = _model.z;
_shadow.y = _model.y;
_scene.addChild(_shadow);
// Light
var aLight :AmbientLight = new AmbientLight(0xffffff);
aLight.intensity = 0.5;
_scene.addChild(aLight);
var oLight :OmniLight = new OmniLight(0xffffff, 1000, 10000);
oLight.x = 100; oLight.y = 200; oLight.z = 200;
_scene.addChild(oLight);
var dLight :DirectionalLight = new DirectionalLight(0xffffff);
dLight.x = 0; dLight.y = - 100; dLight.z = 100; dLight.intensity = 0.5;
_scene.addChild(dLight);
// Resource
for each (var resource :Resource in _scene.getResources(true)) resource.upload(_stage3D.context3D);
// Event
stage.addEventListener(KeyboardEvent.KEY_DOWN, _keyDown);
stage.addEventListener(KeyboardEvent.KEY_UP, _keyUp);
stage.addEventListener(Event.RESIZE, _resize);
_resize();
}
/* RESIZE */
private function _resize ( evt :Event = null ) :void {
_camera.view.width = stage.stageWidth;
_camera.view.height = stage.stageHeight;
}
/* KEY DOWN & KEY UP */
private function _keyDown ( evt :KeyboardEvent ) :void { _keyFlags[evt.keyCode] = true; if (evt.keyCode == Keyboard.UP) _model.changeAnimation(1, 1.8); }
private function _keyUp ( evt :KeyboardEvent ) :void { _keyFlags[evt.keyCode] = false; if (evt.keyCode == Keyboard.UP) _model.changeAnimation(0, 1.4); }
//メインループ
private function _enterFrame ( evt :Event ) :void {
// loading
if (! _scene) {
_tfLoading.visible = ! _tfLoading.visible;
return;
}
if (_keyFlags[Keyboard.LEFT]) _model.rotationZ += MathUtil.toRad(5);//左旋回
if (_keyFlags[Keyboard.RIGHT]) _model.rotationZ -= MathUtil.toRad(5);//右旋回
if (_keyFlags[Keyboard.UP]) {//キャラ前進
_model.moveFront(16);
var p :Point, n :int = 0;
var l :int = _boxes.length;
/*
for (var i :int = 0; i < l; i ++) {//衝突判定
p = _boxes[i].hitTest(_model.x, _model.y, _model.prePosition.x, _model.prePosition.y);//当たり判定
if (p) {
_model.x = p.x;
_model.y = p.y;
i = -1; n ++; if (10 < n) break;
}
}*/
_shadow.x = _model.x;
_shadow.y = _model.y;
}
_model.updataAnimation();//キャラのモーション
// カメラの回転
if (_keyFlags[Keyboard.A]) _rotTmp += 8;
else if (_keyFlags[Keyboard.D]) _rotTmp -= 8;
else if (_keyFlags[Keyboard.W]) _cameraZ += 20;
else if (_keyFlags[Keyboard.S]) _cameraZ -= 20;
else if(_keyFlags[Keyboard.Q]) aa();
_updateCameraPosition();//カメラ位置更新
_camera.render(_stage3D);//描画
}
private function aa():void{
_rotTmp = _model.rotationZ-_rot;
}
//カメラ位置更新
private function _updateCameraPosition ( ) :void {
_rot += (_rotTmp - _rot) / 6;
var px :Number = _model.x + CAMERA_DISTANCE * Math.cos(MathUtil.toRad(_rot));
var py :Number = _model.y + CAMERA_DISTANCE * Math.sin(MathUtil.toRad(_rot));
_camera.x += (px - _camera.x) / 6;
_camera.y += (py - _camera.y) / 6;
_camera.z += (_cameraZ - _camera.z) / 6;
_camera.x += Math.sin(_t / 210) * 11;
_camera.y += Math.sin(_t / 300) * 9;
_t += 11;
var p :Point, n :int = 0;
var l :int = _boxes.length;
_camera.lookAt(_model.x, _model.y, _model.z);//対象方向に向ける
}
//ビットマップ切り出し
private function func2(res:BitmapData,x:int,y:int,w:int,h:int):BitmapData{
var dat:BitmapData = new BitmapData(w,h);
var rect:Rectangle = new Rectangle(x,y,w,h);
var ar:Vector.<uint> = res.getVector(rect);
for(var i:int=0;i<w;i++){
for(var j:int=0;j<h;j++){
var col:int = ar[i+j*w];
dat.setPixel32(i,j,col);
}
}
return dat;
}
private function tex():BitmapData{
initTexMap();
var dat:BitmapData = new BitmapData(16*16,16*3,false,0xffffff);
dat.lock();
for ( var i:int = 1; i < 16; i++) {//ブロックの種類
//var br:int = 255 - ((Math.random() * 96) | 0);
for ( var y:int = 0; y < 16 * 3; y++) {
for ( var x:int = 0; x < 16; x++) {
var col:int = texmap[x + y * 16 + i * 256 * 3];
dat.setPixel32(x+(16*i),y,col);
}
}
}
dat.unlock();
return dat;
}
//テクスチャデータ
private var texmap: Vector.<int> = new Vector.<int>(16 * 16 * 3 * 16, true);
//テクスチャ生成
private function initTexMap():void {
for ( var i:int = 1; i < 16; i++) {//ブロックの種類
var br:int = 255 - ((Math.random() * 96) | 0);
for ( var y:int = 0; y < 16 * 3; y++) {
for ( var x:int = 0; x < 16; x++) {
var color:int = 0x966C4A;
if (i == 4)color = 0x7F7F7F;
if (i != 4 || ((Math.random() * 3) | 0) == 0) {
br = 255 - ((Math.random() * 96) | 0);
}
if ((i == 1 && y < (((x * x * 3 + x * 81) >> 2) & 3) + 18)) {
color = 0x6AAA40;
}
else if ((i == 1 && y < (((x * x * 3 + x * 81) >> 2) & 3) + 19)) {
br = br * 2 / 3;
}
if (i == 7) {//木
color = 0x675231;
if (x > 0 && x < 15
&& ((y > 0 && y < 15) || (y > 32 && y < 47))) {
color = 0xBC9862;
var xd:int = (x - 7);
var yd:int = ((y & 15) - 7);
if (xd < 0)
xd = 1 - xd;
if (yd < 0)
yd = 1 - yd;
if (yd > xd)
xd = yd;
br = 196 - ((Math.random() * 32) | 0) + xd % 3 * 32;
} else if (((Math.random() * 2) | 0) == 0) {
br = br * (150 - (x & 1) * 100) / 100;
}
}
if (i == 5) {//レンガ
color = 0xB53A15;
if ((x + (y >> 2) * 4) % 8 == 0 || y % 4 == 0) {
color = 0xBCAFA5;
}
}
if(i == 10){
color = 0xeecc99;
}
if (i == 9) {//水
color = 0x4040ff;
}
var brr:int = br;
if (y >= 32)
brr /= 2;
if (i == 8) {//葉っぱ
color = 0x50D937;
if (((Math.random() * 2) | 0) == 0) {
color = 0;
brr = 255;
}
}
var col:int = (((color >> 16) & 0xff) * brr / 255) << 16
| (((color >> 8) & 0xff) * brr / 255) << 8
| (((color) & 0xff) * brr / 255);
texmap[x + y * 16 + i * 256 * 3] = col;//ドットカラー
}//for
}//for
}//for
}//function
}
}
class CraftMap{
//マップサイズ
private var _sx:int=14;
private var _sy:int=14;
private var _sz:int=2;
private var _waterlevel:int;
//マップデータ
public var map:Vector.<int>;
public function CraftMap(){
map = new Vector.<int>(128 * 64 * 64, true);
//initMap();
}
public function getBlock(x:int,y:int,z:int):int{
var x2:int = x%_sx;
var y2:int = y%_sy;
var z2:int = z%_sz;
var i:int = z2*_sz + y2*_sy + x2;
return map[i];
}
public function setBlock(x:int,y:int,z:int,t:int=0):void{
var x2:int = x%_sx;
var y2:int = y%_sy;
var z2:int = z%_sz;
var i:int = z2*_sz + y2*_sy + x2;
map[i]=t;
}
public function get sx():int{
return _sx;
}
public function get sy():int{
return _sy;
}
public function get sz():int{
return _sz;
}
public function initMap(s: int = 0, w: int = 0, f: int = 0): void {
//var noise: BitmapData = new BitmapData(_sx, _sy, false);
//noise.lock();
var p1: Point = new Point(), p2: Point = new Point();
var offset: Array = [p1, p2];
var seed: int = s || Math.random() * 0xFFFFFF;
//水位
var waterlevel: int = w || 19 + Math.random() * 10;
_waterlevel = waterlevel;
var flora: int = f || Math.random() * 10000;
for ( var z: int = 0; z < _sz; z++){
// 擬似PerlinNoise3D
p1.x = z, p2.x = -z;
//noise.perlinNoise(_sx/2, _sy/2, 2, seed, false, true, 7, true, offset);//ノイズ生成
for ( var x: int = 0; x < _sx; x++){
for ( var y: int = 0; y < _sy; y++){
var i:int = z*_sy*_sx + y*_sx + x;
map[i] = 4; //(Math.random() * 16) | 0;
if (Math.random() > 0.8){
map[i] = 0;//ブロックなし
}
}
}
}
/*
//noise.dispose();
for( z = 0; z < _sz; z++){
for( x = 0; x < _sx; x++){
for( y = 0; y < _sy; y++){
i = z*_sy*_sx + y*_sx + x;//z << 12 | y << 6 | x;
if (map[i] == 0 && y>64-waterlevel){ //ブロックがなくて海抜より低い位置は水ブロックを設置
map[i] = 9;//水ブロック
}
else
if(map[i] != 0){
var j:int = z*_sy*_sx + (y-1)*_sx + x;
if(map[j] == 0)//ブロックの上に空間があれば
map[i] = 1;//草ブロック
else{//上にブロックがある場合
j = z*_sz + (y-2)*_sy + x;
if(map[j] == 0)//深さ2ブロックまでは土ブロックとする
map[i] = 2;//土ブロック
else map[i] = Math.random()*3+2;//深さ2ブロック以降
}
}
}
}
}
///*
for ( var b: int = 0; b < flora; b++ ){
x = Math.random()*_sx;
y = Math.random()*_sy;
z = Math.random()*_sz;
i = z*_sy*_sx + (y+1)*_sx + x;
var c:int = map[i];
i = z*_sy*_sx + y*_sx + x;
var c2:int = map[i];
if (c2 != 0){
y--;
i = z << 12 | y << 6 | x;
c2 = map[i];
while (c2 != 0 && y>1){
y--;
i = z << 12 | y << 6 | x;
c=c2;
c2 = map[i];
//c2 = 0;
}
}
if (c2==0 && c!=9 && c!=0) map[i] = 8;
}
*/
}
}
import alternativa.engine3d.animation.AnimationClip;
import alternativa.engine3d.animation.AnimationController;
import alternativa.engine3d.core.Object3D;
import alternativa.engine3d.loaders.ParserCollada;
import alternativa.engine3d.materials.TextureMaterial;
import alternativa.engine3d.materials.VertexLightTextureMaterial;
import alternativa.engine3d.objects.Mesh;
import alternativa.engine3d.primitives.Box;
import alternativa.engine3d.resources.BitmapTextureResource;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Stage3D;
import flash.geom.*;
import mx.core.BitmapAsset;
/* -----------------------------------------------------------------
* ColladaModel
*/
class ColladaModel extends Object3D
{
private var _stage3D :Stage3D;
private var _material :TextureMaterial;
private var _animationController :AnimationController;
private var _animationClips :/*AnimationClip*/Array = [];
private var _textureResources :/*BitmapTextureResource*/Array = [];
private var _pre :Point;
public function ColladaModel ( stage3D :Stage3D, parent :Object3D = null ) {
_stage3D = stage3D;
if (parent) parent.addChild(this);
}
public function init ( dae :*, texture :*, x :Number = 0, y :Number = 0, z :Number = 0, scale :Number = 1 ) :void {
if (! (dae is XML)) dae = new XML(dae);
if (texture is Bitmap || texture is BitmapAsset) texture = texture.bitmapData;
this.x = x; this.y = y; this.z = z;
scaleX = scaleY = scaleZ = scale;
_pre = new Point(x, y);
// Parser
var parser :ParserCollada = new ParserCollada();
parser.parse(dae);
// Texture
var texResource :BitmapTextureResource = new BitmapTextureResource(texture);
texResource.upload(_stage3D.context3D);
var txtRes :BitmapTextureResource = texResource;
_material = new TextureMaterial(txtRes);
// Mesh
for each (var obj :Object3D in parser.objects) {
var mesh :Mesh = obj as Mesh;
if (mesh) { mesh.setMaterialToAllSurfaces(_material); addChild(obj); }
}
}
/* 前進 */
public function moveFront ( d :Number ) :void {
_pre.x = this.x;
_pre.y = this.y;
var radZ :Number = this.rotationZ;
this.x += d * Math.sin(radZ);
this.y -= d * Math.cos(radZ);
}
/* アニメーションのアップデート */
public function updataAnimation ( ) :void { _animationController.update(); }
/* アニメーションを追加 */
public function addAnimation ( dae :*, id :int ) :void {
if (! (dae is XML)) dae = new XML(dae);
// Animation Clip
var animationClip :AnimationClip = ParserCollada.parseAnimation(dae);
animationClip.attach(this, true);
_animationClips[id] = animationClip;
// Animation Controller
if (! _animationController) {
_animationController = new AnimationController();
_animationController.root = animationClip;
}
}
/* アニメーションの切り替え */
public function changeAnimation ( id :int, speed :Number = 1.0, loop :Boolean = true ) :void {
_animationClips[id].speed = speed;
_animationClips[id].loop = loop;
_animationController.root = _animationClips[id];
}
public function get prePosition ( ) :Point { return _pre; }
}
/* -----------------------------------------------------------------
* Box
*/
class CustomBox extends Box
{
private var _p :/*Point*/Array = [];
public function CustomBox ( parent :Object3D = null ) {
var w :int = MathUtil.rand(100, 500);
var l :int = MathUtil.rand(100, 500);//奥行き
var h :int = MathUtil.rand(100, 2500);//高さ
super(w, l, h);
const RANGE :int = 3000;
if (Math.random() < 0.5) {
x = MathUtil.rand(-RANGE, RANGE);
y = (Math.random() < 0.5) ? MathUtil.rand(-RANGE, -l/2) : MathUtil.rand(l/2, RANGE);
} else {
x = (Math.random() < 0.5) ? MathUtil.rand(-RANGE, -w/2) : MathUtil.rand(w/2, RANGE);
y = MathUtil.rand(-RANGE, RANGE);
}
z = - 300 + h /2;
setMaterialToAllSurfaces(new VertexLightTextureMaterial(new BitmapTextureResource(new BitmapData(8, 8, false, 0xffffff))));
if (parent) parent.addChild(this);
var rad :Number = rotationZ = MathUtil.toRad(MathUtil.rand(0, 45));
var cw :Number = (w + 90) / 2;
var cl :Number = (l + 90) / 2;
_p[0] = new Point(x + (-cw * Math.cos(rad) + cl * Math.sin(rad)), y + (-cw * Math.sin(rad) - cl * Math.cos(rad)));
_p[1] = new Point(x + (-cw * Math.cos(rad) - cl * Math.sin(rad)), y + (-cw * Math.sin(rad) + cl * Math.cos(rad)));
_p[2] = new Point(x + ( cw * Math.cos(rad) - cl * Math.sin(rad)), y + ( cw * Math.sin(rad) + cl * Math.cos(rad)));
_p[3] = new Point(x + ( cw * Math.cos(rad) + cl * Math.sin(rad)), y + ( cw * Math.sin(rad) - cl * Math.cos(rad)));
/*
// Show HitArea
var zz :Number = z - h / 2;
var vec :Vector.<Vector3D> = new <Vector3D>[
new Vector3D(_p[0].x, _p[0].y, zz),
new Vector3D(_p[1].x, _p[1].y, zz),
new Vector3D(_p[2].x, _p[2].y, zz),
new Vector3D(_p[3].x, _p[3].y, zz),
new Vector3D(_p[0].x, _p[0].y, zz)
];
var wire :WireFrame = WireFrame.createLineStrip(vec, 0x999999, 1, 2);
parent.addChild(wire);
//*/
}
//当たり判定
public function hitTest (nx :Number, ny :Number, px :Number, py :Number) :Point {
var f :Boolean = MathUtil.boxContainsPos(_p[0].x, _p[0].y, _p[1].x, _p[1].y, _p[2].x, _p[2].y, _p[3].x, _p[3].y, nx, ny);
if (! f) return null;
for (var i :int = 0; i < 4; i ++) {
var p1x :Number = _p[i].x;
var p1y :Number = _p[i].y;
var p2x :Number = _p[(i+1)%4].x;
var p2y :Number = _p[(i+1)%4].y;
f = MathUtil.intersectLineSegment(px, py, nx, ny, p1x, p1y, p2x, p2y);
if (f) {
var pt :Point = MathUtil.getCrossPoint(p1x, p1y, p2x, p2y, nx, ny);
return new Point(pt.x + (pt.x - nx) * 0.2, pt.y + (pt.y - ny) * 0.2);
}
}
return null;
}
}
class Block extends Box{
private var _p :/*Point*/Array = [];
public function setPos(px:Number=0,py:Number=0,pz:Number=0):void{
x = px;
y = py;
z = pz;
updateHitPos();
}
private function updateHitPos():void{
var w:int = 100;
var rad :Number = rotationZ = 0;//MathUtil.toRad(MathUtil.rand(0, 45));
var cw :Number = (w + 90) / 2;
var cl :Number = (w + 90) / 2;
_p[0] = new Point(x + (-cw * Math.cos(rad) + cl * Math.sin(rad)), y + (-cw * Math.sin(rad) - cl * Math.cos(rad)));
_p[1] = new Point(x + (-cw * Math.cos(rad) - cl * Math.sin(rad)), y + (-cw * Math.sin(rad) + cl * Math.cos(rad)));
_p[2] = new Point(x + ( cw * Math.cos(rad) - cl * Math.sin(rad)), y + ( cw * Math.sin(rad) + cl * Math.cos(rad)));
_p[3] = new Point(x + ( cw * Math.cos(rad) + cl * Math.sin(rad)), y + ( cw * Math.sin(rad) - cl * Math.cos(rad)));
}
public function setColor(c:uint):void{
setMaterialToAllSurfaces(new VertexLightTextureMaterial(new BitmapTextureResource(new BitmapData(8, 8, false, c))));
}
public function set X(n:Number):void{
x += n;
updateHitPos();
}
public function set Y(n:Number):void{
y += n;
updateHitPos();
}
public function set Z(n:Number):void{
z += n;
updateHitPos();
}
public function Block( parent :Object3D = null ) {
var w :int = 100;
super(w,w,w);
x = 0;
y = 0;
z = 0;
var col:uint = Math.random()*0xffffff;
setMaterialToAllSurfaces(new VertexLightTextureMaterial(new BitmapTextureResource(new BitmapData(8, 8, false, col))));
if (parent) parent.addChild(this);
var rad :Number = rotationZ = 0;//MathUtil.toRad(MathUtil.rand(0, 45));
var cw :Number = (w + 90) / 2;
var cl :Number = (w + 90) / 2;
_p[0] = new Point(x + (-cw * Math.cos(rad) + cl * Math.sin(rad)), y + (-cw * Math.sin(rad) - cl * Math.cos(rad)));
_p[1] = new Point(x + (-cw * Math.cos(rad) - cl * Math.sin(rad)), y + (-cw * Math.sin(rad) + cl * Math.cos(rad)));
_p[2] = new Point(x + ( cw * Math.cos(rad) - cl * Math.sin(rad)), y + ( cw * Math.sin(rad) + cl * Math.cos(rad)));
_p[3] = new Point(x + ( cw * Math.cos(rad) + cl * Math.sin(rad)), y + ( cw * Math.sin(rad) - cl * Math.cos(rad)));
}
//当たり判定
public function hitTest (nx :Number, ny :Number, px :Number, py :Number) :Point {
var f :Boolean = MathUtil.boxContainsPos(_p[0].x, _p[0].y, _p[1].x, _p[1].y, _p[2].x, _p[2].y, _p[3].x, _p[3].y, nx, ny);
if (! f) return null;
for (var i :int = 0; i < 4; i ++) {
var p1x :Number = _p[i].x;
var p1y :Number = _p[i].y;
var p2x :Number = _p[(i+1)%4].x;
var p2y :Number = _p[(i+1)%4].y;
f = MathUtil.intersectLineSegment(px, py, nx, ny, p1x, p1y, p2x, p2y);
if (f) {
var pt :Point = MathUtil.getCrossPoint(p1x, p1y, p2x, p2y, nx, ny);
return new Point(pt.x + (pt.x - nx) * 0.2, pt.y + (pt.y - ny) * 0.2);
}
}
return null;
}
}
/* -----------------------------------------------------------------
* MathUtil
*/
class MathUtil
{
/* min ~ max の範囲で乱数生成 */
public static function rand ( min :Number, max :Number ) :Number { return Math.random() * ( max - min ) + min; }
/* 角度からラジアンに変換 */
public static function toRad ( deg :Number ) :Number { return deg * Math.PI / 180; }
/* 外積 */
public static function intersect ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number ) :Number {
var n :Number = ((p1x - p2x) * (p3y - p1y) + (p1y - p2y) * (p1x - p3x)) * ((p1x - p2x) * (p4y - p1y) + (p1y - p2y) * (p1x - p4x));
return n;
}
/* 任意の三角形の中に任意の点が内包されているかどうか */
public static function triContainsPos ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, psx :Number, psy :Number ) :Boolean {
if ((p1x - p3x) * (p1y - p2y) == (p1x - p2x) * (p1y - p3y)) return false;
if (intersect(p1x, p1y, p2x, p2y, psx, psy, p3x, p3y) < 0) return false;
if (intersect(p1x, p1y, p3x, p3y, psx, psy, p2x, p2y) < 0) return false;
if (intersect(p2x, p2y, p3x, p3y, psx, psy, p1x, p1y) < 0) return false;
return true;
}
/* 任意の四角形の中に任意の点が内包されているかどうか(凸のみ) */
public static function boxContainsPos ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number, psx :Number, psy :Number ) :Boolean {
if (triContainsPos(p1x, p1y, p2x, p2y, p3x, p3y, psx, psy)) return true;
if (triContainsPos(p1x, p1y, p3x, p3y, p4x, p4y, psx, psy)) return true;
return false;
}
/* 線分の交差判定 */
public static function intersectLineSegment ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, p3x :Number, p3y :Number, p4x :Number, p4y :Number) :Boolean {
if (intersect(p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y) < 0)
if (intersect(p3x, p3y, p4x, p4y, p1x, p1y, p2x, p2y) < 0) return true;
return false;
}
/* 点から直線におろした垂線の交点の座標 */
public static function getCrossPoint ( p1x :Number, p1y :Number, p2x :Number, p2y :Number, psx :Number, psy :Number ) :Point {
var a :Number = p2y - p1y;
var b :Number = p1x - p2x;
var c :Number = (p1y - p2y) * p1x + (p2x - p1x) * p1y;
var d :Number = (a * psx + b * psy + c) / (a * a + b * b);
var x :Number = psx - d * a;
var y :Number = psy - d * b;
return new Point(x, y);
}
}