ニコ割ゲームっぽくしてみた forked from: niconico Tetris
// forked from nitoyon's niconico Tetris
// forked from flashrod's Tetris
// forked from nitoyon's ニコニコテレビちゃんを動かしてみた
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.media.*;
public class Tetris extends Sprite {
private const W:int = 10;
private const H:int = 20;
private const UNIT:int = 22;
private const COLOR:Array =[0x000000, 0x00FFFF, 0xFFFF00, 0x22FF22, 0xFF2222, 0x4444FF, 0xFF8844, 0xFF22FF];
private const PAT:Array =[[[1, 1, 1, 1]],
[[0, 2, 0], [2, 2, 2]],
[[3, 3, 0], [0, 3, 3]],
[[0, 4, 4], [4, 4, 0]],
[[5, 5], [5, 0], [5, 0]],
[[6, 6], [0, 6], [0, 6]],
[[7, 7], [7, 7]]];
private const SPEED:Array = [30, 20, 10, 5];
private const VK_H:int = 72; // h
private const VK_J:int = 74; // j
private const VK_K:int = 75; // k
private const VK_L:int = 76; // l
private const VK_LEFT:int = 37; // left
private const VK_RIGHT:int = 39; // right
private const VK_UP:int = 38; // up
private const VK_DOWN:int = 40; // down
private const VK_SPC:int = 32; // space
private var field:Array = [];
private var piece:Array;
private var next:Array;
private var text:TextField = new TextField();
private var keytable:Array = [];
private var count:int = 0;
private var step:int = 0;
private var px:int;
private var py:int;
public static var param:int = 0;
public function Tetris() {
text.x = W*UNIT;
text.text="Next:";
addChild(text);
var t:TextField = new TextField();
t.x = W * UNIT;
t.y = 8 * UNIT;
t.text = "usage:\n h(or left),j(or up),k,\n l(or right),SPACE(or down)";
t.autoSize = "left";
addChild(t);
field = new Array(H).map(function():*{
return new Array(W).map(function():*{
return 0;
})
});
keytable[VK_H] = keytable[VK_LEFT] = function():void {px -= space(px-1, py, piece)};
keytable[VK_J] = keytable[VK_UP] = function():void {rotate(true)};
keytable[VK_K] = function():void {rotate(false)};
keytable[VK_L] = keytable[VK_RIGHT] = function():void {px += space(px+1, py, piece)};
keytable[VK_SPC] = keytable[VK_DOWN] = function():void {drop(); pick();};
stage.addEventListener(KeyboardEvent.KEY_DOWN, function(e:KeyboardEvent):void {
if (keytable[e.keyCode]) {
keytable[e.keyCode]();
repaint();
}
});
pick();
pick();
addEventListener(Event.ENTER_FRAME, function(e:Event):void {
param = (param + 9) % 360;
for (var j:int = 0; j < numChildren; j++) {
if(getChildAt(j) is Body) Body(getChildAt(j)).update();
}
if (--step < 0) {
step=SPEED[int(count/10)];
if (space(px, py+1, piece)) {
++py;
repaint();
} else {
drop();
pick();
}
}
});
_initializeSound();
}
private function rotate(clock:Boolean):void {
var r:Array = new Array(piece[0].length).map(function():*{return [];});
for (var j:int = 0; j<piece.length; ++j)
for (var i:int = 0; i < r.length; ++i)
if (clock)
r[i][piece.length-1-j] = piece[j][i];
else
r[r.length-1-i][j] = piece[j][i];
if (space(px, py, r))
piece = r;
}
private function repaint():void {
for (var j:int = numChildren - 1; j >= 0; j--) {
if (getChildAt(j) is Body) removeChildAt(j);
}
graphics.clear();
graphics.lineStyle(0);
graphics.drawRect(0, 0, W*UNIT, H*UNIT);
graphics.endFill();
for (j = 0; j < H; ++j)
for (var i:int = 0; i < W; ++i) {
var g:int = 0;
if (py <= j && j < (py+piece.length) && px <= i && i < (px+piece[0].length))
g = piece[j-py][i-px];
if (g == 0)
g = field[j][i];
if(g == 0) continue;
var body:Body = new Body(COLOR[g]);
addChild(body);
body.x = (i+.5)*UNIT;
body.y = (j-.5)*UNIT;
}
for (j = 0; j < next.length; ++j)
for (i = 0; i < next[j].length; ++i) {
if(next[j][i] == 0) continue;
var body:Body = new Body(COLOR[next[j][i]]);
addChild(body);
body.x = (i+W+1)*UNIT;
body.y = (j+2)*UNIT;
}
}
private function space(x:int, y:int, p:Array):int {
for (var j:int = 0; j < p.length; ++j) {
if (0 > (y+j) || (y+j) >= H)
return 0;
for (var i:int = 0; i < p[j].length; ++i) {
if (0 > (x+i) || (x+i) >= W)
return 0;
if (p[j][i] && field[y+j][x+i])
return 0;
}
}
return 1;
}
private function drop():void {
for (; space(px, py+1, piece); py++)
;
for (var j:int = 0; j < piece.length; ++j)
for (var i:int = 0; i < piece[j].length; ++i)
if (piece[j][i])
field[py+j][px+i] = piece[j][i];
for (j=0; j<H; ++j)
if (field[j].indexOf(0) < 0) {
field.splice(j, 1);
field.unshift([]);
for (i=0; i<W; ++i)
field[0][i] = 0;
}
count++;
if (count/10 >= SPEED.length)
count = 0;
}
private function pick():void {
piece = next;
if (piece != null) {
px = (W-piece[0].length)/2;
py = 0;
if (!space(px, py, piece))
text.text="GAME OVER";
}
next = PAT[int(Math.random()*PAT.length)];
}
// Sound
//------------------------------------------------------------
private var _sound:Sound;
private var _module:TinySiOPM;
private var _sequencer:Sequencer;
private function _initializeSound() : void {
/*
t180;
$v9@q8s40w24o6l8[d+ef+2ed+c+d+>b2|f+2l4g+b<eg+f+2.]l4bg+@q18f+ed+c+@q24>b<d+>br
@q8a+b<cc+l8de-ef@qf+2@q8>[f+<c+d+c+>bb-b<f+eba+g+f+2ef+ef+d+f+d+f+|c+d+c+d+c+f+ec+]d+c+d+c+>b4;
$v5%1@6@q8s40w24o5l8[b<c+d+2c+>ba+|bf+2d+2l4eg+b<ed+2.]>f+8e2l4<e>b<@q18c+c+>a+a+@q24f+bf+r
@q8c+d+ee+l32@q[16f+g+]@q24l4r8>[a+a+b|bbbbb]@ql16br<c+>[5a+b]<cc+ed+c+
ec+>a+f+ef+a+<c+>ba+b<d+f+d+>b<f+eg+beg+>be<g+f+>f+<d+b<d+>bd+f+c+>f+a+<c+ec+>a+f+b<b>b<<d+>f+d+>b<b[a+>a+<f+>a+]b8.r;
$v8@q8s40w24o3l8r4[4b<f+>f+<f+>][b<g+>e<g+>][4b<f+>f+<f+>]b<e>[e<e>]f<f>[f+<f+>]g+<g+>a+<a+>[b<b>]@qbl4r.@q8f+g+aa+@qb2a+f+
l8@q8f+<f+>f+<f+>[b<f+>b<f+>b<g+>b<g+>b<f+>b<f+>a+<f+>a+<f+>b<f+>b<f+>|f+<f+>f+<f+>f+<f+>f+<f+>a+<f+>a+<f+>]f+<e>f+<ed+4;
*/
var A:String = "$v9@11s2o6l2[d+rerf+14rerd+rc+rd+r>b14r|f+14rg+6rb6r<e6rg+6rf+22r]<b6rg+6rf+3r5e3r5d+3r5c+3r5>br6<d+r6>b4r12a+6rb6r<c6rc+6rdrd+rerfrf+16>[f+r<c+rd+rc+r>bra+rbr<f+rerbra+rg+rf+14rerf+rerf+rd+rf+rd+rf+r|c+rd+rc+rd+rc+rf+rerc+r>]d+rc+rd+rc+r>b6r";
var B:String = "$v6@9s3o5l2[br<c+rd+14rc+r>bra+r|brf+14rd+14re6rg+6rb6r<e6rd+22r>]f+re14r<e6r>b6r<c+3r5c+3r5>a+3r5a+3r5f+r6br6f+4r12c+6rd+6re6re+6rl1v5[16f+g+]v7l2>[r4a+r6a+r6br6br|r4br6br6br6br]<v4c+>[5a+b]<cc+ed+c+ec+>a+f+ef+a+<c+>ba+b<d+f+d+>b<f+eg+beg+>be<g+f+>f+<d+b<d+>bd+f+c+>f+a+<c+ec+>a+f+b<b>b<<d+>f+d+>b<b[a+>a+<f+>a+|<]b6r";
var C:String = "$v8@11s2o3l2r8[4br<f+r>f+r<f+r>][br<g+r>er<g+r>][4br<f+r>f+r<f+r>]br<er>[er<er>]fr<fr>[f+r<f+r>]g+r<g+r>a+r<a+r>[br<br>]b4r12f+6rg+6ra6ra+6rb16a+8f+8f+r<f+r>f+r<f+r>[br<f+r>br<f+r>br<g+r>br<g+r>br<f+r>br<f+r>a+r<f+r>a+r<f+r>br<f+r>br<f+r>|f+r<f+r>f+r<f+r>f+r<f+r>f+r<f+r>a+r<f+r>a+r<f+r>]f+r<er>f+r<erd+6r";
_module = new TinySiOPM(2048, 1024, _onSoundFrame);
_sequencer = new Sequencer(2, [A,B,C]);
_sound = new Sound();
_sound.addEventListener("sampleData", _onStream);
_sound.play();
}
private function _onSoundFrame() : void {
if (_sequencer.onSoundFrame()) {
}
}
private function _onStream(e:SampleDataEvent) : void {
var moduleOut:Vector.<Number> = _module.render();
for (var i:int = 0; i<4096; i++) {
e.data.writeFloat(moduleOut[i]);
}
}
}
}
import flash.display.*;
import flash.events.*;
import flash.filters.*;
import flash.media.*;
class Body extends Sprite{
private var eye1:Sprite;
private var eye2:Sprite;
private var antena:Sprite;
public function Body(color:uint){
scaleX = scaleY = .19;
var l1:Leg = new Leg(color);
l1.x = -30; l1.y = 150
addChild(l1);
var l2:Leg = new Leg(color);
l2.x = 30; l2.y = 150
addChild(l2);
// アンテナを描く
antena = new Sprite();
antena.graphics.lineStyle(4, 0x000000);
antena.graphics.moveTo(-30, 40);
antena.graphics.lineTo( 0, 60);
antena.graphics.lineTo( 30, 40);
addChild(antena);
// 外側四角を描く
var s2:Sprite = new Sprite();
s2.graphics.lineStyle(6, 0x000000);
s2.graphics.beginFill(color);
s2.graphics.drawRect(-60, 0, 120, 90);
s2.graphics.endFill();
s2.y = 60;
addChild(s2);
// 内側四角を描く
var s3:Sprite = new Sprite();
s3.graphics.lineStyle(4, 0x000000);
s3.graphics.beginFill(0xffffff, 0.8);
s3.graphics.drawRect(-50, 0, 100, 70);
s3.graphics.endFill();
s3.y = 70;
addChild(s3);
// 左目を描く
eye1 = new Sprite();
eye1.graphics.beginFill(0x000000);
eye1.graphics.drawCircle(0, 0, 5);
eye1.x = -30;
eye1.y = 100;
addChild(eye1);
// 右目を描く
eye2 = new Sprite();
eye2.graphics.beginFill(0x000000);
eye2.graphics.drawCircle(0, 0, 5);
eye2.x = 30;
eye2.y = 90;
addChild(eye2);
// 口を描く
var s8:Sprite = new Sprite();
s8.graphics.lineStyle(1, 0x000000);
s8.graphics.beginFill(0x000000);
s8.graphics.moveTo( 0, 120);
s8.graphics.lineTo(-10, 130);
s8.graphics.lineTo( 15, 130);
s8.graphics.endFill();
addChild(s8);
update();
}
public function update():void{
var s:Number = Math.cos(Tetris.param / 180 * Math.PI);
eye1.y = 95 + 5 * s;
eye2.y = 95 - 5 * s;
antena.scaleX = s;
}
}
class Leg extends Sprite{
public function Leg(color:uint){
graphics.lineStyle(4, 0x000000);
graphics.beginFill(color);
graphics.moveTo( 20, -12);
graphics.lineTo( 0, 12);
graphics.lineTo(-20, -12);
graphics.endFill();
}
}
// MML Sequencer
// http://wonderfl.kayac.com/user/keim_at_Si
//--------------------------------------------------
class Sequencer {
private var _tracks:Array, _count:int=Track.speed+1;
function Sequencer(speed:int, mmls:Array) { Track.speed=speed; mml=mmls; }
public function onSoundFrame() : Boolean {
if (++_count == Track.speed) {
for each (var tr:Track in _tracks) tr.execute();
_count = 0;
return true;
}
return false;
}
public function set mml(list:Array) : void {
_tracks = [];
for each (var seq:String in list) _tracks.push(new Track(seq));
_count = 0;
}
}
class Track {
static public var codeA:int="a".charCodeAt(), nt:Array=[9,11,0,2,4,5,7], speed:int=3;
public var oct:int, len:int, tl:int, dt:int, cnt:int, seq:String, sgn:int, stac:Array, osc:Osc;
private var _rex:RegExp=/(@i|@o|[a-gkloprsvw<>[|\]$@])([#+])?(-?\d+)?/g;
function Track(seq:String) {
osc = (new Osc()).reset().activate(false);
reset(seq);
}
public function reset(seq_:String) : void {
seq=seq_; oct=5; len=4; tl=256; dt=0; cnt=0; sgn=0; _rex.lastIndex=0; stac=[];
}
public function execute() : void {
if (--cnt <= 0) {
for (var i:int=0; i<100; i++) {
var res:* = _rex.exec(seq);
if (!res) {
if (sgn) { _rex.lastIndex = sgn; continue; }
else { cnt = int.MAX_VALUE; break; }
}
var cmd:int = res[1].charCodeAt();
if (cmd>=codeA && cmd<=codeA+6) {
cnt = (res[3]) ? int(res[3]) : len;
osc.len = cnt * speed;
osc.pt = ((nt[cmd-codeA]+oct*12+((res[2])?1:0))<<4) + dt;
osc.tl = tl;
break;
} else if (res[1] == 'r') {
cnt = (res[3]) ? int(res[3]) : len;
break;
} else {
switch(res[1]){
case 'k': dt = int(res[3]); break;
case 'l': len = int(res[3]); break;
case 'o': oct = int(res[3]); break;
case 'v': tl = TinySiOPM.log(int(res[3])*0.0625); break;
case '<': oct++; break;
case '>': oct--; break;
case '@': osc.ws = int(res[3]); break;
case 's': osc.dr = int(res[3])<<2; break;
case 'w': osc.sw = -int(res[3]); break;
case 'p': osc.pan = (int(res[3])<<4)-64; break;
case '@i': osc.mod = int(res[3]); break;
case '@o': osc.out = int(res[3]); break;
case '$': sgn = _rex.lastIndex; break;
case '[': stac.unshift({p:_rex.lastIndex,c:((res[3])?int(res[3]):2),j:0}); break;
case '|': if (stac[0].c == 1) { _rex.lastIndex = stac[0].j; stac.shift(); } break;
case ']':
stac[0].j = _rex.lastIndex;
if (--stac[0].c == 0) stac.shift();
else _rex.lastIndex = stac[0].p;
break;
}
}
}
}
}
}
class TinySiOPM {
private var _output:Vector.<Number>, _zero:Vector.<int>, _pipe:Vector.<int>;
private var _pitchTable:Vector.<int> = new Vector.<int>(2048, true);
private var _logTable:Vector.<int> = new Vector.<int>(6144, true);
private var _panTable:Vector.<Number> = new Vector.<Number>(129, true);
private var _bufferSize:int, _callbackFrams:int, _onSoundFrame:Function;
// Pass the buffer size and the function calls in each frame.
function TinySiOPM(bufferSize:int=2048, callbackFrams:int=1024, onSoundFrame:Function=null) {
var i:int, j:int, p:Number, v:Number, t:Vector.<int>, ft:Array=[0,1,2,3,4,5,6,7,7,6,5,4,3,2,1,0];
for (i=0, p=0; i<192; i++, p+=0.00520833333) // create pitchTable[128*16]
for(v=Math.pow(2, p)*12441.464342886, j=i; j<2048; v*=2, j+=192) _pitchTable[j] = int(v);
for (i=0; i<32; i++) _pitchTable[i] = (i+1)<<6; // [0:31] for white noize
for (i=0, p=0.0078125; i<256; i+=2, p+=0.0078125) // create logTable[12*256*2]
for(v=Math.pow(2, 13-p), j=i; j<3328; v*=0.5, j+=256) _logTable[j+1] = -(_logTable[j]=int(v));
for (i=3328; i<6144; i++) _logTable[i] = 0; // [3328:6144] is 0-fill area
for (i=0, p=0; i<129; i++, p+=0.01217671571) _panTable[i]=Math.sin(p)*0.5; // pan table;
for (t=Osc.createTable(10), i=0, p=0; i<1024; i++, p+=0.00613592315) t[i] = log(Math.sin(p)); // sin=0
for (t=Osc.createTable(10), i=0, p=0.75; i<1024; i++, p-=0.00146484375) t[i] = log(p); // saw=1
for (t=Osc.createTable(5), i=0; i<16; i++) t[i+16] = (t[i] = log(ft[i]*0.0625)) + 1; // famtri=2
for (t=Osc.createTable(15), i=0; i<32768; i++) t[i] = log(Math.random()-0.5); // wnoize=3
for (i=0; i<8; i++) for (t=Osc.createTable(4), j=0; j<16; j++) t[j] = (j<=i) ? 192 : 193; // pulse=4-11
_zero = new Vector.<int>(bufferSize, true); // allocate zero buffer
_pipe = new Vector.<int>(bufferSize, true); // allocate fm pipe buffer
_output = new Vector.<Number>(bufferSize*2, true); // allocate stereo out
_bufferSize = bufferSize;
_callbackFrams = callbackFrams;
_onSoundFrame = onSoundFrame; // set parameters
for (i=0; i<bufferSize; i++) { _pipe[i]=_zero[i]=0; } // clear buffers
}
// calculate index of logTable
static public function log(n:Number) : int {
return (n<0) ? ((n<-0.00390625) ? (((int(Math.log(-n) * -184.66496523 + 0.5) + 1) << 1) + 1) : 2047)
: ((n> 0.00390625) ? (( int(Math.log( n) * -184.66496523 + 0.5) + 1) << 1) : 2046);
}
// Returns stereo output as Vector.<Number>(bufferSize*2).
public function render() : Vector.<Number> {
var i:int, j:int, ph:int, dph:int, mod:int, sh:int, tl:int, lout:int, v:int, imax:int,
osc:Osc, tm:Osc, l:Number, r:Number, wv:Vector.<int>, fm:Vector.<int>, base:Vector.<int>,
out:Vector.<int>=_pipe, lt:Vector.<int>=_logTable, stereoOut:Vector.<Number> = _output;
imax = _bufferSize<<1;
for (i=0; i<imax; i++) stereoOut[i] = 0;
for (imax=_callbackFrams; imax<=_bufferSize; imax+=_callbackFrams) {
if (_onSoundFrame!=null) _onSoundFrame();
tm = Osc._tm;
for (osc=tm.n; osc!=tm; osc=osc.update()) {
dph=_pitchTable[osc.pt]; ph=osc.ph; mod=osc.mod+10; sh=osc.sh; tl=osc.tl; wv=osc.wv;
fm=(osc.mod==0)?_zero:_pipe; base=(osc.out!=2)?_zero:_pipe;
for (i = imax-_callbackFrams; i < imax; i++) {
v = ((ph + (fm[i] << mod))& 0x3ffffff) >> sh;
lout = wv[v] + tl;
out[i] = lt[lout] + base[i];
ph = (ph + dph) & 0x3ffffff;
}
osc.ph = ph;
if (osc.out==0) {
l = _panTable[64-osc.pan] * 0.0001220703125;
r = _panTable[64+osc.pan] * 0.0001220703125;
for (i=imax-_callbackFrams, j=i*2; i<imax; i++) {
stereoOut[j] += out[i]*l; j++;
stereoOut[j] += out[i]*r; j++;
}
}
}
}
return stereoOut;
}
// note on
public function noteOn(pitch:int, length:int=0, vol:Number=0.5, wave:int=0, decay:int=6, sweep:int=0, pan:int=0) : Osc {
var osc:Osc = Osc.alloc().reset();
osc.pt = pitch;
osc.len = length;
osc.tl = log(vol);
osc.ws = wave;
osc.dr = decay<<2;
osc.sw = sweep;
osc.pan = pan;
return osc.activate(true);
}
}
class Osc {
// create new wave table and you can refer the table by '@' command.
static public function createTable(b:int) : Vector.<int> {
_w.push(new Vector.<int>(1<<b,true)); _s.push(26-b);
return _w[_w.length-1];
}
static public var _w:Array=[], _s:Array=[], _fl:Osc=new Osc(), _tm:Osc=new Osc();
static public function alloc():Osc{ if(_fl.p==_fl)return new Osc();var r:Osc=_fl.p;_fl.p=r.p;r.p.n=_fl;return r; }
public function into(x:Osc):Osc{ p=x.p;n=x;p.n=this;n.p=this;return this; }
public var p:Osc, n:Osc, fl:Osc, pt:int, len:int, ph:int;
public var tl:int, sw:int, dr:int, wv:Vector.<int>, sh:int, mod:int, out:int, pan:int;
public function set ws(t:int) : void { wv=_w[t]; sh=_s[t]; }
public function Osc() { p = n = this; }
public function update() : Osc { tl+=dr; pt+=sw; pt&=2047; return (--len==0||tl>3328) ? (inactivate().n) : n; }
public function reset() : Osc { ph=0; pt=0; len=0; tl=3328; sw=0; dr=24; pan=0; ws=0; mod=0; out=0; return this; }
public function activate(autoFree:Boolean=false) : Osc { into(_tm); fl=(autoFree)?_fl:null; return this; }
public function inactivate() : Osc { tl=3328; if(!fl)return this; var r:Osc=p; p.n=n; n.p=p; into(fl); return r; }
public function isActive() : Boolean { return (tl<3328); }
}