テトロミノゲーム
ゲームで極める シェルスクリプトスーパーテクニック
http://gihyo.jp/book/2007/978-4-7741-3202-0/shellscript_games/
の移植です。操作は方向キーのみで、上を押すと回転します。
未完成ですが、ひとまず形にはなってきました。
ピースを記憶するクラスとグラフィックスを担うクラスが別になっているので
外観は改造しやすいと思います。
/**
* Copyright lla ( http://wonderfl.net/user/lla )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/rEPLD
*/
package {
import flash.text.TextField;
import flash.display.Sprite;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.events.KeyboardEvent;
public class FlashTest extends Sprite {
public static var tf: TextField;
public function FlashTest() {
//stage.frameRate = 5;
tf = new TextField();
//tf.border = true;
//tf.width = 200;
addChild(tf);
var tetUI = new UI();
tetUI.y = 50;
addChild(tetUI);
//var counter = 0;
addEventListener(Event.ENTER_FRAME, function(e){
//counter += 1;
//if(counter % stage.frameRate == 0) {
tetUI.draw();
//}
});
//tetUI.draw();
var timer = new Timer(500, 0);
timer.addEventListener(TimerEvent.TIMER, tetUI.onTimeout);
timer.start();
stage.addEventListener(KeyboardEvent.KEY_DOWN, tetUI.onKeyDown);
//tf.text = "hoge";
/*
FlashTest.tf.appendText("\n");
for(var i = 0; i < 13; i++){
FlashTest.tf.appendText(String(tetUI.tet.map[i][10]));
}*/
}
}
}
import flash.display.Sprite;
import flash.ui.Keyboard;
class UI extends Sprite{
public static function randInt(min, max): int {
return Math.floor(Math.random() * (max - min)) + min;
}
public var posX;
public var posY;
public var oldPosX;
public var oldPosY;
public var pieceNo: uint;
public var nextPieceNo: uint;
public var drawable: Boolean;
public var tet: Tetromino;
public var pieces: Array;
public var direction;
public var oldDirection ;
public var tetShape: TetShape;
public var score: uint;
public function UI(){
super();
oldPosX = posX = 5;
oldPosY = posY = 0;
pieceNo = randInt(0,7);
nextPieceNo = randInt(0,7);
//pieceNo = nextPieceNo = 0;
drawable = true;
direction = 0;
oldDirection = 0;
tet = new Tetromino();
pieces = Piece.init(PieceData.allPieces);
tetShape = new TetShape(25,25,5);
tetShape.drawMap(10,10);
addChild(tetShape);
}
public function redrawMap(){
for(var j = 0; j < tet.mapHeight; j++) {
for(var i = tet.mapL; i < tet.mapL + tet.mapWidth; i++) {
var num = tet.map[i][j];
if(0 <= num) {
tetShape.drawPoint(i,j, 0x000000);
} else if(num == tet.blankNo) {
tetShape.drawPoint(i,j, 0xFFFFFF);
}
}
}
}
public function draw(){
if(!drawable){ return; }
drawable = false;
tetShape.drawPiece(oldPosX, oldPosY, pieces[pieceNo][oldDirection], 0xFFFFFF);
tetShape.drawPiece(posX, posY, pieces[pieceNo][direction], 0x000000);
oldPosX = posX;
oldPosY = posY;
oldDirection = direction;
}
//タイムアウトなので左右の動きはない。
public function onTimeout(e) {
var puttable = tet.checkPiecePuttable(posX, posY+1, pieces[pieceNo][direction]);
//FlashTest.tf.text = String(puttable);
if(puttable){
posY += 1
drawable = true;
return ;
}
tet.putPieceMap(posX, posY, pieces[pieceNo][direction], pieceNo);
var lineScore = tet.check4Lines(posY);
if(lineScore != 0) {
score += lineScore;
redrawMap();
FlashTest.tf.text = String(score);
}
//置き終わる
/*
FlashTest.tf.appendText("\n");
for(var i = 1; i < 11; i++){
FlashTest.tf.appendText(String(tet.map[i][10]));
}
* */
//次のピース
posX = 5;
posY = 0;
oldPosX = posX;
oldPosY = posY;
oldDirection = direction;
pieceNo = nextPieceNo;
nextPieceNo = randInt(0,7);
//nextPieceNo = 0;
//nextピースの描画
//tetShape.drawPiece(nextpiece)
var puttable2 = tet.checkPiecePuttable(posX, posY, pieces[pieceNo][direction]);
if(puttable2){
//FlashTest.tf.text = "game over"
tetShape.drawPiece(posX, posY, pieces[pieceNo][direction], 0x000000);
}
}
public function onKeyDown(event) {
switch(event.keyCode)
{
case Keyboard.LEFT:
var diff = tet.checkPieceLR(posX-1, posY, pieces[pieceNo][direction]);
var puttable = tet.checkPiecePuttable(posX-1, posY, pieces[pieceNo][direction]);
if(diff == 0 && puttable){
posX -= 1;
drawable = true;
}
break;
case Keyboard.RIGHT:
var diff = tet.checkPieceLR(posX+1, posY, pieces[pieceNo][direction]);
var puttable = tet.checkPiecePuttable(posX+1, posY, pieces[pieceNo][direction]);
if(diff == 0 && puttable){
posX += 1;
drawable = true;
}
break;
case Keyboard.DOWN:
var piece = pieces[pieceNo][direction];
tetShape.removePiece(oldPosX, oldPosY, piece);
for(posY; tet.checkPiecePuttable(posX, posY+1, piece); posY++) {}
//posY--;
tetShape.putPiece(posX, posY, piece);
score += (posY - oldPosY);
oldPosX = posX;
oldPosY = posY;
break;
case Keyboard.UP:
direction = (direction + 1) % 4;
var piece = pieces[pieceNo][direction];
var modX = tet.checkPieceLR(posX, posY, piece);
var puttable = tet.checkPiecePuttable(posX, posY, piece);
if(modX == 0 && !puttable) {
direction = oldDirection;
} else if(modX == 0) {
drawable = true;
} else {
posX += modX;
}
break;
}
event.updateAfterEvent();
}
}
//座標記録
//異なる配列に行が含まれるやりかた。
//[[w], [0], [0], [0], [w], [w]]
class Tetromino {
public var map: Array;
public var mapWidth: uint;
public var mapHeight: uint;
public var mapL: uint;
public var mapR: uint
public var blankNo: int;
public var wallNo: int;
public function Tetromino(){
blankNo = -1;
wallNo = -2;
mapWidth = 10;
mapHeight = 10;
mapL = 1;
mapR = mapL+mapWidth;
map = [];
makeMap();
}
public function makeMap(){
var w = mapWidth;
var h = mapHeight;
for(var i: uint = 0; i < w+3; i++) {
map.push([]);
}
for(var j: uint = 0; j < h; j++) {
map[0][j] = wallNo;
for(var i: uint = mapL; i < w+mapL; i++) {
map[i][j] = blankNo;
}
map[w+1][j] = wallNo;
map[w+2][j] = wallNo;
}
//床
for(var i: uint = 0; i < w+3; i++) {
map[i][h] = wallNo;
}
}
//置けるか
public function checkPieceLR(x,y, piece): int{
//var piece = pieces[pieceNo][dir];
if(x + piece.minX < mapL){
return 1;
}
if(mapWidth < x + piece.maxX) {
return -1;
}
return 0;
}
//下が空白か確認する
public function checkPiecePuttable(x,y, piece): Boolean {
if(map[x][y] != blankNo) {
return false;
}
for(var i = 0; i < piece.points.length; i++) {
var px = x + piece.points[i][0];
var py = y + piece.points[i][1];
if(map[px][py] != blankNo) {
return false;
}
}
return true;
}
public function putPieceMap(x, y, piece, pieceNo) {
//var piece = pieces[pieceNo][dir]
map[x][y] = pieceNo;
for(var i = 0; i < piece.points.length; i++) {
var px = x + piece.points[i][0];
var py = y + piece.points[i][1];
map[px][py] = pieceNo;
}
}
public function clearLine(y): void{
for(var i = mapL; i < mapWidth+mapL; i++) {
map[i].splice(y, 1);
map[i].unshift(blankNo);
}
}
//床も一行そろっているので注意
public function checkOneLine(y): Boolean {
for(var px = mapL; px < mapWidth+mapL; px++) {
if(map[px][y] == blankNo) {
return false;
}
}
return true;
}
public function check4Lines(y): Number {
var ymin = (y-1 < 0) ? 0 : y-1;
var ymax = (mapHeight < y+2) ? mapHeight : y+2;
var lineScore = 0;
for(var py = ymin; py < ymax; py++) {
if(checkOneLine(py)) {
lineScore = lineScore * 2 + 100;
clearLine(py);
}
}
return lineScore;
}
}
import flash.display.Shape;
class TetShape extends Shape{
public var pieceWidth;
public var pieceHeight;
public var pieceMargin;
public function calX(n: Number): Number {
return pieceMargin + (pieceWidth + pieceMargin) * n;
}
public function calY(n: Number): Number {
return pieceMargin + (pieceHeight + pieceMargin) * n;
}
public function TetShape(w,h,margin) {
pieceWidth = w;
pieceHeight = h;
pieceMargin = margin;
}
public function drawPiece(x,y, piece, color) : void{
graphics.lineStyle(0, color);
graphics.beginFill(color);
graphics.drawRect(calX(x), calY(y), pieceWidth, pieceHeight);
for(var j = 0; j < 3; j++) {
var point = piece.points[j];
graphics.drawRect(calX(x+point[0]), calY(y+point[1]), pieceWidth, pieceHeight);
}
graphics.endFill();
}
public function putPiece(x,y, piece) : void{
drawPiece(x,y, piece, 0x000000);
}
public function removePiece(x,y, piece) : void{
drawPiece(x,y, piece, 0xFFFFFF);
}
public function drawMap(width,height){
graphics.lineStyle(0);
var centerX = pieceWidth/2.0;
var centerY = pieceHeight/2.0;
var w = calX(width+1);
var h = calY(height+1);
graphics.drawRect(centerX, centerY-calY(1), w,h);
}
public function drawPoint(x,y,color) {
graphics.lineStyle(0, color);
graphics.beginFill(color);
graphics.drawRect(calX(x), calY(y), pieceWidth, pieceHeight);
graphics.endFill();
}
}
//allPieces[PieceNo][dir].maxX, minX, points
//allPieces[PieceNo][dir][points][xy]
//var pieces = Piece.init(PieceData.allPieces);
class Piece {
public var maxX: int;
public var minX: int;
public var points: Array; //[[x,y] [x, y] [x, y]]
public function Piece(piece: Array){
this.points = piece;
minX = maxX = 0;
findMinMaxX(piece);
}
public function findMinMaxX(piece): void {
for(var j = 0; j < piece.length; j++) {
var x = piece[j][0];
maxX = Math.max(x, maxX);
minX = Math.min(x, minX);
}
}
public static function init(pieceList): Array {
var pieces =
pieceList.map(function(piece, i1, a1) {
return piece.map(function(piece_shapes, i2, a2) {
return new Piece(piece_shapes);
});
});
return pieces;
}
}
/*
class PieceData {
// OOO
// O
public static var l1 = [
[[-1, 0], [1, 0], [1, 1]],
[[0, 1], [0, -1], [1, -1]],
[[1, 0], [-1, 0], [-1, -1]],
[[0, -1], [0, 1], [-1, 1]]
];
public static var allPieces = [l1];
}
*/
class PieceData {
// OOO
// O
public static var l1 = [
[[-1, 0], [1, 0], [1, 1]],
[[0, 1], [0, -1], [1, -1]],
[[1, 0], [-1, 0], [-1, -1]],
[[0, -1], [0, 1], [-1, 1]]
];
// OOO
// O
public static var l2 = [
[[-1, 0], [1, 0], [-1, 1]],
[[0, 1], [0, -1], [1, 1]],
[[1, 0], [-1, 0], [1, -1]],
[[0, -1], [0, 1], [-1, -1]]
];
// OO
// OO
public static var s1 = [
[[-1, 1], [1, 0], [0, 1]],
[[1, 1], [0, -1], [1, 0]],
[[-1, 1], [1, 0], [0, 1]],
[[1, 1], [0, -1], [1, 0]]
];
// OO
// OO
public static var s2 = [
[[-1, 0], [1, 1], [0, 1]],
[[0, 1], [1, -1], [1, 0]],
[[-1, 0], [1, 1], [0, 1]],
[[0, 1], [1, -1], [1, 0]]
];
// OOO
// O
public static var t = [
[[-1, 0], [1, 0], [0, 1]],
[[0, 1], [0, -1], [1, 0]],
[[1, 0], [-1, 0], [0, -1]],
[[0, -1], [0, 1], [-1, 0]]
];
// OOOO
//
public static var i = [
[[-1, 0], [1, 0], [2, 0]],
[[0, -1], [0, 1], [0, 2]],
[[-1, 0], [1, 0], [2, 0]],
[[0, -1], [0, 1], [0, 2]]
];
// OO
// OO
public static var o = [
[[1, 0], [1, 1], [0, 1]],
[[1, 0], [1, 1], [0, 1]],
[[1, 0], [1, 1], [0, 1]],
[[1, 0], [1, 1], [0, 1]]
];
public static var allPieces = [l1, l2, s1, s2, t, i, o];
}