Hit&Blowゲーム
なんか落ちゲーの基本の動きを作ろうと思ってたらいつの間にかHit&Blowに…
エフェクトとかリトライとか点数とかそのうち付けたい…
================================
Hit&Blowのルール
・あらかじめcomが決めた色の組み合わせを当てるゲーム。
・一度の回答に付き、Hit数とBlow数を教えてくれる。
(Hit = 色も位置もあっている)
(Blow = 色はあってるが場所が違う)
・同じ色は2回以上使われません。
================================
/**
* Copyright ug24k8 ( http://wonderfl.net/user/ug24k8 )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/531n
*/
package {
/*
なんか落ちゲーの基本の動きを作ろうと思ってたらいつの間にかHit&Blowに…
================================
Hit&Blowのルール
・あらかじめcomが決めた色の組み合わせを当てるゲーム。
・一度の回答に付き、Hit数とBlow数を教えてくれる。
(Hit = 色も位置もあっている)
(Blow = 色はあってるが場所が違う)
・同じ色は2回以上使われません。
================================
*/
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.ui.Mouse;
[SWF(backgroundColor="0x000000", width="465", height="465", frameRate="30")]
// ゲーム本体
public class HitAndBlow extends Sprite {
public static const STAGE_DATA:Array = [
[4, 3], [5, 3], [5, 4], [6, 3], [6, 4], [6, 5],
];
private var mPlayer:Player;
private var mField:GameField;
private var mRecord:RecordList;
private var mCheckSwitch:CheckSwitch;
private var mStateChecked:Boolean = false;
private var mMessage:Message;
private var mStage:uint;
private var mAnswer:Array;
// コンストラクタ
public function HitAndBlow() {
// フィールド登録
mField = addChild(new GameField()) as GameField;
mField.x = 150;
mField.y = 15;
// プレイヤー登録
mPlayer = addChild(new Player()) as Player;
mPlayer.y = stage.stageHeight * 0.9;
// 履歴登録
mRecord = addChild(new RecordList()) as RecordList;
mRecord.x = 310;
mRecord.y = 20;
mCheckSwitch = addChild(new CheckSwitch()) as CheckSwitch;
mCheckSwitch.x = 30;
mCheckSwitch.y = mPlayer.y;
// ステージ設定
mAnswer = new Array();
mStage = 0;
createAnswer();
mField.set_gamelevel(STAGE_DATA[mStage][0], STAGE_DATA[mStage][1]);
// メッセージ追加
mMessage = addChild(new Message()) as Message;
mMessage.x = stage.stageWidth * 0.5;
mMessage.y = stage.stageHeight * 0.5;
// マウス非表示
Mouse.hide();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
stage.addEventListener(MouseEvent.CLICK, onMouseClick);
mMessage.pop("Start!", 5000);
}
// 答え作成
private function createAnswer():void {
var i:int;
var color_val:int = STAGE_DATA[mStage][0];
mAnswer.splice(0); // 全削除
for (i = 0; i < color_val; ++i) mAnswer.push(i);
shuffleList(mAnswer);
trace(mAnswer);
}
// 毎フレーム処理
private function onEnterFrame(evt:Event):void {
if (mField.is_game_over) {
mMessage.pop("Game Over!");
removeEventListener(Event.ENTER_FRAME, arguments.callee);
}
// マウス位置をプレイヤーに反映
mPlayer.target_x = stage.mouseX;
if (mPlayer.hitTestObject(mCheckSwitch)) {
if (mStateChecked == false) {
var i:int, j:int;
var correct:Boolean = false;
var block_set:DropBlockSet = mField.popCurrentBlock();
if (block_set) {
var hit_count:int = 0;
var blow_count:int = 0;
for (i = 0; i < block_set.block_size; ++i) {
var color:int = block_set.block_color(i);
for (j = 0; j < block_set.block_size; ++j) {
if (mAnswer[j] == color) {
if (i == j) ++hit_count;
else ++blow_count;
break;
}
}
}
if (hit_count == block_set.block_size) {
// 正解~
correct = true;
mStage = Math.min(mStage + 1, STAGE_DATA.length - 1);
createAnswer();
mField.set_gamelevel(STAGE_DATA[mStage][0], STAGE_DATA[mStage][1]);
mField.addBonus(block_set.block_size);
mMessage.pop("All Hit", 1000);
}
else {
// ミスー
mField.addPenalty(1.0 - hit_count / block_set.block_size);
mMessage.pop(hit_count + " Hit " + blow_count + " Blow", 1000);
}
mRecord.push_record(new Record(block_set, hit_count, blow_count, correct));
}
mStateChecked = true;
}
}
else {
mStateChecked = false;
}
}
// マウスクリック
private function onMouseClick(evt:MouseEvent):void {
// 弾はフィールドに付けようそうしよう
mField.addBullet(mPlayer.x, mPlayer.y);
}
private function shuffleList(list:Array):void {
var n:Number = list.length;
while (n--) {
var i:Number = Math.floor(Math.random()*(n+1));
var t:Number = list[n];
list[n] = list[i];
list[i] = t;
}
}
}
}
import com.bit101.components.Text;
import flash.display.DisplayObject;
import flash.display.Shape;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.text.TextFormat;
import flash.text.TextFormatAlign;
import flash.utils.Timer;
// Block-base
class BlockBase extends Shape {
public static const COLOR_DATA:Array = [
0xFF4444, 0x44444FF, 0x44FF44,
0xFFFF44, 0xFF44FF, 0x44FFFF,
];
public var mSize:int;
// コンストラクタ
public function BlockBase(size:int = 10) {
mSize = size;
}
public function drawColorBox(color:uint):void {
var block_size:uint = mSize - 1;
graphics.clear();
graphics.beginFill(COLOR_DATA[color]);
graphics.lineStyle();
graphics.drawRoundRect(
-block_size * 0.5, -block_size * 0.5,
block_size, block_size, block_size*0.6, block_size*0.6);
graphics.endFill();
}
}
// field
class GameField extends Sprite {
public static const GRID_SIZE:uint = 30;
public static const GRID_WIDTH:uint = 5;
public static const GRID_HEIGHT:uint = 14;
public static const BULLET_MAX_COUNT:uint = 3;
public static const DROP_WAIT_TIME:uint = 1000;
private var mCurrent:DropBlockSet;
private var mBulletList:Sprite; // 弾リスト代わり
private var mDropTimer:Timer;
private var mColor_val:int;
private var mBlock_cout:int;
private var mGameOver:Boolean;
private var mDeadLine:Shape;
private var mDeadPoint:Number;
// コンストラクタ
public function GameField() {
var i:int;
mGameOver = false;
mDeadPoint = 0;
// デッドライン描画
mDeadLine = addChild(new Shape()) as Shape;
mDeadLine.x = 0;
mDeadLine.y = GRID_HEIGHT * GRID_SIZE;
update_deadline();
// 床描画
graphics.lineStyle(1, 0x8080F0, 0.8);
for (i = 0; i < GRID_WIDTH+1; ++i) {
graphics.moveTo(i * GRID_SIZE, 0);
graphics.lineTo(i * GRID_SIZE, GRID_SIZE * GRID_HEIGHT);
}
for (i = 0; i < GRID_HEIGHT+1; ++i) {
graphics.moveTo(0, i * GRID_SIZE);
graphics.lineTo(GRID_SIZE * GRID_WIDTH, i * GRID_SIZE);
}
mBulletList = new Sprite();
addChild(mBulletList);
// ドロップbox タイマー
if (! mDropTimer) mDropTimer = new Timer(DROP_WAIT_TIME, 1);
mDropTimer.addEventListener(TimerEvent.TIMER, requestDropBlock);
mDropTimer.start();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function get is_game_over():Boolean { return mGameOver; }
public function set_gamelevel(color_val:int, block_cout:int):void {
mColor_val = color_val;
mBlock_cout = block_cout;
}
public function popCurrentBlock():DropBlockSet {
var block_set:DropBlockSet = null;
if (mCurrent) {
DropBlockSet.recordLastBlock(mCurrent);
block_set = mCurrent;
removeChild(mCurrent);
mCurrent = null;
mDropTimer.reset();
mDropTimer.start();
}
return block_set;
}
// ドロップボックスの投下
private function requestDropBlock(evt:TimerEvent):void {
if (mGameOver) return;
if (mCurrent == null) {
mCurrent = new DropBlockSet(mBlock_cout, mColor_val);
mCurrent.x = ((GRID_WIDTH - mBlock_cout) * 0.5) * GRID_SIZE;
addChild(mCurrent);
}
}
public function addBullet(x:int, y:int):void {
if (mGameOver) return;
// 弾数制限つけようかしら?
if (mBulletList.numChildren >= BULLET_MAX_COUNT) return;
var pos:Point = mBulletList.globalToLocal(new Point(x, y));
if (pos.x > 0 && pos.x < GRID_WIDTH * GRID_SIZE) {
mBulletList.addChild(new Bullet(pos.x, pos.y));
}
}
// ペナルティ追加ー
public function addPenalty(pt:Number):void {
mDeadPoint += pt;
update_deadline();
}
// ボーナスによりペナルティ削除
public function addBonus(pt:Number):void {
mDeadPoint = Math.max(0, mDeadPoint - pt * 2);
update_deadline();
}
// デッドライン更新
private function update_deadline():void {
mDeadLine.graphics.clear();
mDeadLine.graphics.beginFill(0x00FFFF, 0.25);
mDeadLine.graphics.drawRect(
0, 0,
GRID_SIZE * GRID_WIDTH,
-(mDeadPoint * 0.4 + 1.2) * GRID_SIZE
);
mDeadLine.graphics.endFill();
}
// 毎フレーム処理
private function onEnterFrame(evt:Event):void {
var i:int;
if (mCurrent) {
// 弾チェック
for (i = mBulletList.numChildren - 1; i >= 0; --i) {
// 削除すると後ろがずれるので、後ろからやるわー
var bullet:Bullet = mBulletList.getChildAt(i) as Bullet;
if (! bullet) continue; // 一応弾じゃない場合は無視る
if ((bullet.y < 0) || // 画面端なら消しとこう
(mCurrent.isHitBlock(bullet))) { // ブロックにあたっても消しとこう
mBulletList.removeChild(bullet);
}
}
// ゲームオーバーチェック
if (mDeadLine.hitTestObject(mCurrent)) {
removeChild(mCurrent);
mCurrent = null;
mGameOver = true;
}
}
}
}
// MessageBoard
class Message extends Sprite {
private var mText:TextField;
private var mTimer:Timer;
public function Message() {
mText = addChild(new TextField()) as TextField;
var text_format:TextFormat = new TextFormat()
text_format.size = 20;
text_format.color = 0xFFFFFF;
text_format.align = TextFormatAlign.CENTER;
mText.autoSize = TextFieldAutoSize.CENTER;
mText.defaultTextFormat = text_format;
mTimer = new Timer(1, 1);
mTimer.addEventListener(TimerEvent.TIMER, function(evt:TimerEvent):void {
visible = false;
});
mTimer.stop();
visible = false;
}
public function pop(text:String, time:int = 0):void {
mText.text = text;
mText.x = -mText.width * 0.5;
visible = true;
if (time > 0) {
mTimer.delay = time;
mTimer.start();
}
}
}
// player
class Player extends Sprite {
public var target_x:Number = 0;
// コンストラクタ
public function Player() {
graphics.beginFill(0x800000);
graphics.lineStyle(1, 0xFFFFFF, 0.5);
graphics.moveTo(0, -10);
graphics.lineTo(10, 10);
graphics.lineTo(0, 5);
graphics.lineTo(-10, 10);
graphics.endFill();
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
// 毎フレーム処理
private function onEnterFrame(evt:Event):void {
x = (target_x - x) * 0.8 + x;
}
}
class Bullet extends Shape {
public const SPEED:int = -18;
// コンストラクタ
public function Bullet(x:int, y:int) {
graphics.beginFill(0xFFFFFF);
graphics.drawRoundRect(0, 0, 5, 10, 1, 2);
graphics.endFill();
this.x = x;
this.y = y;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
// 毎フレーム処理
private function onEnterFrame(evt:Event):void {
y += SPEED;
}
}
// Drop Block
class DropBlock extends BlockBase {
public var color:uint;
public var color_var:uint;
// コンストラクタ
public function DropBlock(color_var:uint) {
super(GameField.GRID_SIZE);
this.color_var = Math.min(color_var, COLOR_DATA.length);
color = Math.floor(Math.random() * this.color_var);
drawColorBox(color);
}
// うたれた!?
public function shot():void {
color = (color + 1) % this.color_var;
drawColorBox(color);
}
}
// Drop Block の塊
class DropBlockSet extends Sprite {
private static var sLastBlockList:Vector.<DropBlock>;
private var mBlockList:Vector.<DropBlock>;
private var mSpeed:Number;
public function DropBlockSet(width:uint, color_var:uint, speed:Number = 0.4) {
var i:int;
if (sLastBlockList != null
&& sLastBlockList.length == width
&& sLastBlockList[0].color_var == color_var) {
mBlockList = sLastBlockList.concat(); // 複製
}else {
mBlockList = new Vector.<DropBlock>();
for (i = 0; i < width; ++i) {
mBlockList.push(new DropBlock(color_var));
}
sLastBlockList = null;
}
mBlockList.forEach(
function(item:DropBlock, index:int, vector:Vector.<DropBlock>):void {
addChild(item);
item.x = (index + 0.5)* GameField.GRID_SIZE;
item.y = 0.5* GameField.GRID_SIZE;
});
mSpeed = speed;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
public function isHitBlock(obj:DisplayObject):Boolean {
var i:int;
for (i = 0; i < mBlockList.length; ++i) {
if ( mBlockList[i].hitTestObject(obj) ) {
mBlockList[i].shot();
return true;
}
}
return false;
}
public function get block_size():int {
return mBlockList.length;
}
public function block_color(index:int):uint {
return mBlockList[index].color;
}
public static function recordLastBlock(blockset:DropBlockSet):void {
sLastBlockList = blockset.mBlockList.concat();
}
// 毎フレーム処理
private function onEnterFrame(evt:Event):void {
y += mSpeed;
}
}
// 記録
class Record extends Sprite {
public const BLOCK_SIZE:uint = 12;
public function Record(record:DropBlockSet, hit:int, blow:int, correct:Boolean = false) {
var i:int;
if (correct) {
graphics.lineStyle(1, 0xFFa0a0, 0.6);
graphics.drawRoundRect(0, 2, 100, 13, 10, 10);
}
for (i = 0; i < record.block_size; ++i) {
var block:BlockBase = new BlockBase(BLOCK_SIZE - 1);
block.drawColorBox(record.block_color(i));
block.x = i * BLOCK_SIZE + 25;
block.y = 9;
addChild(block);
}
var hit_text:TextField = new TextField();
hit_text.textColor = 0xFFFFFF;
hit_text.text = hit.toString();
hit_text.x = 5;
hit_text.y = 0;
addChild(hit_text);
var blow_text:TextField = new TextField();
blow_text.textColor = 0xFFFFFF;
blow_text.text = blow.toString();
blow_text.x = 84;
blow_text.y = 0;
addChild(blow_text);
}
}
// 記録一覧
class RecordList extends Sprite {
public const RECORD_MAX_SIZE:uint = 20;
private var mRecordList:Vector.<Record> = new Vector.<Record>();
public function RecordList() {
var hit_text:TextField = addChild(new TextField()) as TextField;
hit_text.text = "hit";
hit_text.textColor = 0xFFFFFF;
hit_text.x = 8;
hit_text.y = 0;
var blow_text:TextField = addChild(new TextField()) as TextField;
blow_text.text = "blow";
blow_text.textColor = 0xFFFFFF;
blow_text.x = 90;
blow_text.y = 0;
}
public function push_record(record:Record):void {
var i:int;
if (mRecordList.length >= RECORD_MAX_SIZE) {
var old_record:Record = mRecordList.shift();
removeChild(old_record);
}
mRecordList.push(record);
record.x = 10;
addChild(record);
for (i = 0; i < mRecordList.length; ++i) {
mRecordList[i].y = (mRecordList.length - i - 1) * 15 + 20;
}
}
}
// チェックスイッチ
class CheckSwitch extends Sprite {
public function CheckSwitch() {
graphics.lineStyle(2, 0x00FF00, 0.2);
graphics.drawCircle(0, 0, 18);
graphics.lineStyle(5, 0x00FF00, 0.4);
graphics.drawCircle(0, 0, 8);
}
}