GoFのCommandパターンにヒントを得て作成。
描画した履歴を文字列型配列変数に記録しておき、必要に応じて取り出します。
今回は単純な文字列型配列変数ではなく、スタックのモジュールを用意してみました。
bregexp.dll(bregonig.dll)および月影ともさんのbregexp.hspが必要です。// 文字列用スタック
#module string_stack stack, max
#modinit
max = 0
sdim stack, 32, 10
return
#deffunc new_sstack array v
newmod v, string_stack@
return
#modfunc push str s
stack(max) = s
max++
return
#defcfunc pop modvar string_stack@
if max == 0 {
logmes "引数の値が異常です。"
return ""
}
max--
return stack(max)
#defcfunc get_length modvar string_stack@
return max
#defcfunc get_last modvar string_stack@
return stack(max-1)
#defcfunc get_at modvar string_stack@, int index
if index < 0 || max <= index {
logmes "引数の値が異常です。"
return ""
}
return stack(index)
#modfunc clear_stack
max = 0
return
#global
// 矩形の塗りつぶし
// http://rpen.blogspot.com/2007/11/blog-post.html
#include "gdi32.as"
#module
#const FLOODFILLSURFACE 1
#deffunc fill int x, int y
current_color = ginfo_r, ginfo_g, ginfo_b
CreateSolidBrush (ginfo_b << 16) | (ginfo_g << 8) | ginfo_r
if stat {
hBrush = stat
} else {
dialog "ブラシの生成に失敗しました。プログラムを終了します。", 1
end
}
SelectObject hDC, hBrush
pget x, y
ExtFloodFill hdc, x, y, (ginfo_b << 16) | (ginfo_g << 8) | ginfo_r, FLOODFILLSURFACE
DeleteObject hBrush
color current_color(0), current_color(1), current_color(2)
return
#global
// 命令を解析して描画するモジュール
#include "bregexp.hsp"
#module drawer
#define ctype result(%1) int(_result(%1))
#deffunc draw str _cmd
cmd = _cmd
BSplit _result, cmd, "m/[ ,]+/"
switch _result(0)
case "moveTo" : pos result(1), result(2) : swbreak
case "lineTo" : line result(1), result(2) : swbreak
case "color" : color result(1), result(2), result(3) : swbreak
case "fill" : fill result(1), result(2) : redraw 1 : swbreak
default : logmes "未知の命令です" : swbreak
swend
return
#deffunc draw_all array cmds, int wait_time
redraw 0
color 255, 255, 255 : boxf
color
repeat get_length(cmds)
draw get_at(cmds, cnt)
if wait_time {
redraw 1
wait wait_time
redraw 0
}
loop
redraw 1
return
#global
#define push_and_do(%1,%2) push %1, %2 : draw %2
#define WM_MOUSEMOVE $00000200
#define WM_LBUTTONDOWN $00000201
#define WM_LBUTTONUP $00000202
#define WM_RBUTTONDOWN $00000204
*init
title "左ドラッグで線を描画 / 右クリックで塗りつぶし"
oncmd gosub *onLButtonDown, WM_LBUTTONDOWN
oncmd gosub *onRButtonDown, WM_RBUTTONDOWN
oncmd gosub *onLButtonUp, WM_LBUTTONUP
oncmd gosub *onMouseMove, WM_MOUSEMOVE
objsize 80
button gosub "color change", *color_change
button gosub "redraw slowly", *all_draw_slowly
button gosub "clear", *clear
button gosub "undo", *undo
new_sstack cmds
stop
// 色の変更
*color_change
hsvcolor rnd(192), 255, 255
push_and_do cmds, "color " + ginfo_r + "," + ginfo_g + "," + ginfo_b
return
// 全消去
*clear
clear_stack cmds
draw_all cmds, 0
return
// アンドゥ
*undo
tmp = pop(cmds)
draw_all cmds, 0
return
// すべて描画
*all_draw
draw_all cmds, 0
return
// ゆっくりとすべて描画
*all_draw_slowly
oncmd 0
gosub *invalidate_buttons
draw_all cmds, 4
gosub *validate_buttons
oncmd 1
return
// 左ドラッグ開始
*onLButtonDown
dragging = 1
push_and_do cmds, "moveTo " + mousex + "," + mousey
return
// 左ドラッグ終了
*onLButtonUp
dragging = 0
return
// 左ドラッグ中
*onMouseMove
if dragging {
push_and_do cmds, "lineTo " + mousex + "," + mousey
}
return
// 右クリック
*onRButtonDown
if dragging == 0 {
push_and_do cmds, "fill " + mousex + "," + mousey
}
return
#include "obj.as"
*invalidate_buttons
repeat 4
objgray cnt, 0
loop
return
*validate_buttons
repeat 4
objgray cnt, 1
loop
return
2008年2月12日火曜日
アンドゥや再生ができるペイントツール
2008年1月28日月曜日
サイトのサムネイルを表示する
サイトのサムネイルを作成・表示するAPI「ThumbnailAPI」を利用します。
ネットの接続などはスクリプトから明示的には行っていません。imgload命令の内部で使用しているCOMが自動で行ってくれているようです。#include "mod_img.as"
imgload "http://img.simpleapi.net/small/http://www.forest.impress.co.jp/"
stop
2008年1月2日水曜日
RPG風メッセージウィンドウの描画
ツクールなどでよくありそうなデザインのウィンドウを描画します。三角関数とhsvcolorを組み合わせることで、きれいなグラデーションが表現できます。
白と黒の線で囲むことで、どんな背景でもある程度の見易さを確保するよう努めています。#module
#include "hspmath.as"
#deffunc line_box int x, int y, int _w, int _h, local w, local h
w = _w - 1 : h = _h - 1
line x+w, y, x, y : line x+w, y+h
line x, y+h : line x, y
return
#deffunc draw_win int x, int y, int _w, int _h, local w, local h
w = _w - 1 : h = _h - 1
repeat 10
angle = M_PI * cnt/20, M_PI * (1+cnt)/20
hsvcolor 130, 255, 255-2*cnt*cnt
boxf x+sin(angle)*w, y, x+sin(angle(1))*w, y+h
loop
color : line_box x, y, _w, _h
color 255, 255, 255 : line_box x+1, y+1, _w-2, _h-2
return
#global
redraw 0
draw_win 0, 0, 240, 200
redraw 1
stop
2007年12月20日木曜日
3D画像ビューア サンプル
Flashなどでありそうな3Dの画像ビューア。のサンプル。
マウスのホイールに連動して回転します。#include "d3m.hsp"
#include "hspmath.as"
#const TILE_NUM 16
#const SHIFT_TURN 5
#const BUFFER_WIDTH 200
#const BUFFER_HEIGHT 200
// タイルを表示するための配列変数
tile_x = 100, 300, 300, 100
tile_y = 0, 0, 0, 0
tile_z = 200, 200, 0, 0
// タイル用のバッファを作成
repeat TILE_NUM, 1
buffer cnt, BUFFER_WIDTH, BUFFER_HEIGHT
color , 255 : boxf
color 255, 255, 255
font msgothic, 32, font_bold
mes cnt
loop
// メイン画面の初期化・カメラ設定
screen 0, 240, 200, screen_normal
title "ホイールで回転"
d3setcam -250,-300,100, 250,0,100
// 各種初期化作業
gmode GMODE_ALPHA, , , 128
theta_shift = 0.0 // タイルの回転量
theta_add = 0.0 // タイルの角速度
moving = 0 // 回転中フラグ
need_to_draw = 1 // 描画フラグ
// ★メインループ
*main
gosub *move
gosub *draw
wait 5
goto *main
// 移動計算
*move
mw = mousew
if moving > 0 {
// 移動中
moving--
theta_shift += theta_add
} else : if mw != 0 {
// 静止中かつホイールが動いたとき
moving = SHIFT_TURN // SHIFT_TURN回動く
need_to_draw = 1 // 描画フラグON
// 角速度を決定
theta_add = M_PI * 2.0 * sgn(mw) / SHIFT_TURN / TILE_NUM
}
return
// 描画処理
*draw
if need_to_draw == 0 : return
if moving == 0 : need_to_draw = 0
redraw 0
color : boxf
vect_x = cos(theta_shift)
vect_y = sin(theta_shift)
// 2.0 * M_PI / TILE_NUMだけ角度(位置)を変えながら、タイルをTILE_NUM個描画
repeat TILE_NUM
d3rotate vect_x, vect_y, vect_x, vect_y, 2.0 * M_PI / TILE_NUM
d3setlocal 0,0,0, vect_x,vect_y,0, -vect_y,vect_x,0, 0,0,1
d3texture tile_x, tile_y, tile_z, cnt + 1, 0, 0, BUFFER_WIDTH, BUFFER_HEIGHT, 1
loop
redraw 1
return
2007年11月11日日曜日
閉塞領域の塗りつぶし
ペイントツールお約束の機能も、APIを使えば簡単に実装できます。
昔はSRPGの経路探索を応用したりしてモジュールを組んでたのですが……今思えば結構無茶してますね。
なおHSP2.61用のスクリプトはCrimson Forestさんにあるようです。// 参考
// http://msdn.microsoft.com/library/ja/default.asp?url=/library/ja/jpgdi/html/_win32_extfloodfill.asp
#include "gdi32.as"
#module
#const FLOODFILLSURFACE 1
// カレントカラーで(x, y)を含む同色領域を塗りつぶす
// 実際の画面に反映させるには redraw 1 を実行すること
#deffunc fill int x, int y
// カレントカラーを記憶
current_color = ginfo_r, ginfo_g, ginfo_b
// カレントカラーからブラシを生成
CreateSolidBrush (ginfo_b << 16) | (ginfo_g << 8) | ginfo_r
if stat {
hBrush = stat
} else {
dialog "ブラシの生成に失敗しました。プログラムを終了します。", 1
end
}
SelectObject hDC, hBrush
// 塗りつぶす色を取得
pget x, y
// 塗りつぶし実行
ExtFloodFill hdc, x, y, (ginfo_b << 16) | (ginfo_g << 8) | ginfo_r, FLOODFILLSURFACE
// 後始末
DeleteObject hBrush
color current_color(0), current_color(1), current_color(2)
return
#global
repeat 5
hsvcolor 191 * cnt / 5, 255, 255
boxf rnd(640), rnd(480), rnd(640), rnd(480)
loop
onclick gosub *do_fill
stop
*do_fill
hsvcolor rnd(192), 255, 255
fill mousex, mousey
redraw 1
return
2007年10月28日日曜日
角丸四角形を描画
標準命令で角丸四角形を描くモジュール。
半径が大きすぎた場合は自動で調節するおまけつき。// 角丸四角形を描画する
#module
#define ctype max( %1, %2 ) ( %1 )*( %1 > %2 ) + ( %2 )*( %1 <= %2 )
#define ctype min( %1, %2 ) ( %1 )*( %1 < %2 ) + ( %2 )*( %1 >= %2 )
#const DEFAULT_R 20
/*
rboxf (左上X座標), (左上Y座標), (右下X座標), (右下Y座標), (角の半径)
*/
#deffunc rboxf int _x1, int _y1, int _x2, int _y2, int _r
x1 = min(_x1, _x2) : x2 = max(_x1, _x2)
y1 = min(_y1, _y2) : y2 = max(_y1, _y2)
box_width = x2 - x1 : box_height = y2 - y1
if ( _r <= 0 ) {
r = DEFAULT_R
} else {
r = _r
}
r = min( r, min( box_width / 2, box_height / 2 ) )
boxf x1, y1+r, x2, y2-r
boxf x1+r, y1, x2-r, y2
repeat 4
x = x1 + ( cnt \ 2 ) * ( box_width - r * 2 + 1)
y = y1 + ( cnt / 2 ) * ( box_height - r * 2 + 1 )
circle x, y, x + r * 2, y + r * 2
loop
return
#global
// サンプル
rboxf 50, 50, 300, 300, 50
rboxf 600, 400, 400, 300, 100 // 右下→左上の順で指定してもOK
// 半径が大きすぎる場合は自動で調節する
2007年8月16日木曜日
障害物のあるマップで視野を求める
フリーソフト超激辛ゲームレビュー様でHSPで作られたと思われる素晴らしいゲームが紹介されていました。Elonaというローグライクゲームです。詳しくは製作者様のサイトをご覧ください。
ローグ系はやったことも作ったこともあまり無いので処理内容の大半はよく分からないのですが、視野の計算がちょっと気になった&イメージが湧いたのでサンプルスクリプトを作成してみました。
左右非対称だったりと不完全ではありますが、充分実用に耐えうるのではないかと思われます。#const CHIP_SIZE 16 // マップチップの大きさ
#const WINX 320 // ウィンドウの大きさ
#const WINY 320
#const AREA_W WINX / CHIP_SIZE // マップの大きさ
#const AREA_H WINY / CHIP_SIZE
#const OBSTACLE_W 3 // 障害物の大きさ
#const OBSTACLE_H 2
//
// 数学関数
#define ctype max( %1, %2 ) ( %1 * ( %1 > %2 ) + %2 * ( %1 <= %2 ) )
#define ctype round( %1 ) double(strf("%%0.0f", %1))
//
// マップ描画用マクロ
#define draw_chip( %1, %2 ) boxf CHIP_SIZE * %1, CHIP_SIZE * %2, CHIP_SIZE * ( %1 + 1 ) - 2, CHIP_SIZE * ( %2 + 1 ) - 2
screen 0, WINX, WINY
randomize
sdim map, AREA_W * AREA_H
sdim shadow, AREA_W * AREA_H // 影を記録する変数。0なら明るい地点、それ以外は影。
gosub *make_blocks
onclick gosub *make_blocks
//
// メインループ
*main
if ( light_x != mousex / CHIP_SIZE ) | ( light_y != mousey / CHIP_SIZE ) {
renew = 1
}
if renew {
renew = 0
light_x = mousex / CHIP_SIZE
light_y = mousey / CHIP_SIZE
gosub *calc
gosub *draw
}
wait 2
goto *main
//
// 視野の計算
*calc
memset shadow, 2, AREA_W * AREA_H // 2...未検査
repeat AREA_H
y = cnt
dy = abs( y - light_y )
repeat AREA_W
if peek( shadow, y * AREA_W + cnt ) != 2 : continue
x = cnt
dx = abs( x - light_x )
// コメントアウトを解除すると、距離も考慮に入れるようになる
; if ( dx*dx+dy*dy > 48 ) {
; poke shadow, y * AREA_W + x, 1 // 1...検査済み(影)
; continue
; }
m = max( dx, dy )
repeat m
// 内分点の公式を使い、調査地点と光源の間にあるマス全てを調べる
_x = int(round(double( light_x * cnt + x * ( m - cnt ) ) / m))
_y = int(round(double( light_y * cnt + y * ( m - cnt ) ) / m))
if peek( map, _y * AREA_W + _x ) {
// 障害物を見つけた場合、今まで調べた地点はすべて影とする
repeat cnt + 1
_x = int(round(double( light_x * cnt + x * ( m - cnt ) ) / m))
_y = int(round(double( light_y * cnt + y * ( m - cnt ) ) / m))
poke shadow, _y * AREA_W + _x, 1 // 1...検査済み(影)
loop
break
}
poke shadow, _y * AREA_W + _x, 0 // 0...検査済み(明るい地点)
loop
loop
loop
return
//
// 各種描画処理
*draw
redraw 0
gosub *draw_map
gosub *draw_light
redraw 1
return
//
// マップを描画
*draw_map
color : boxf
repeat AREA_H
y = cnt
repeat AREA_W
if peek( map, y * AREA_W + cnt ) == 0 {
if peek( shadow, y * AREA_W + cnt ) {
color 192, 192, 192
} else {
color 255, 255, 255
}
draw_chip cnt, y
}
loop
loop
return
//
// 光源を描く
*draw_light
color 255, 128, 0
draw_chip light_x, light_y
return
//
// ブロックをランダムに配置
*make_blocks
memset map, 0, AREA_W * AREA_H
// 10個障害物を作成
repeat 10
poke map, rnd( AREA_W * AREA_H ), 1
loop
// 1個大きな障害物(OBSTACLE_WxOBSTACLE_H)を作成
x = rnd( AREA_W + 1 - OBSTACLE_W )
y = rnd( AREA_H + 1 - OBSTACLE_H )
repeat OBSTACLE_H
memset map, 1, OBSTACLE_W, ( y + cnt ) * AREA_W + x
loop
renew = 1
return
2007年8月12日日曜日
ちっちゃなテトリス
結局遊べるところまで完成させてしまいました。短期集中連載第2弾とでも呼びましょうか。
これと全く同じものをHSPコンテスト2007へ投稿しました。ので、いつも通り利用・改造・転載など自由ですが、これの改造をHSPコンテスト2007へ投稿することはご遠慮ください。
関連:stick命令をgetkey命令で実装する
fujidigさんによるバグの指摘#include "hsptv.as"
// 独自stick定義モジュール
#undef stick
#module modStick
// getkeyキーコード
#const GETKEY_LEFT 37
#const GETKEY_UP 38
#const GETKEY_RIGHT 39
#const GETKEY_DOWN 40
#const GETKEY_Z 'Z'
#const GETKEY_X 'X'
#deffunc _initStick
dim KEY_CODE, 6
KEY_CODE(0) = GETKEY_X, GETKEY_Z, GETKEY_DOWN, GETKEY_RIGHT, GETKEY_UP, GETKEY_LEFT
return
#deffunc _stick var vTarget, int NO_TRIGGER, int CHECK_MODE, local tmp
vTarget = 0
repeat 6; = length(KEY_CODE) // start.ax軽量化のために定数化
getkey tmp, KEY_CODE(cnt)
vTarget = vTarget << 1 | tmp
loop
if (CHECK_MODE == WIN_ACTIVE_CHECK_ON) & (ginfo_act == -1){
// HSPウィンドウがアクティブでない
prev = vTarget
vTarget = 0
} else {
tmp = vTarget
vTarget &= (-1 ^ prev) | NO_TRIGGER
prev = tmp
}
return
#define global stick(%1, %2=0, %3=1) _stick %1, %2, %3
#global
_initStick // 配列の初期化
// 独自stick定義モジュールここまで
#const global BLOCK_SIZE 32
#const global BLOCK_HSIZE BLOCK_SIZE / 2
#const global BLOCK_COLOR_MAX 8
#const global AREA_WIDTH 10
#const global AREA_HEIGHT 15
#const global AREA_WIDTH2 AREA_WIDTH * BLOCK_SIZE
#const global AREA_HEIGHT2 BLOCK_SIZE * AREA_HEIGHT
#const global AREA_X ( 640 - AREA_WIDTH2 ) / 2
#const global AREA_Y ( 480 - AREA_HEIGHT2 ) / 2
#const HIGHSCORE_MAX 6
#enum STATE_NORMAL = 1
#enum STATE_BLINK
#enum STATE_GAMEOVER
#module
//
// 指定した色でブロックを描く
#deffunc draw_block int x, int y, int c, int mode
hsvcolor 191 * c / BLOCK_COLOR_MAX, 255, 255 - 155 * ( mode != 0 )
boxf AREA_X + BLOCK_SIZE * x, AREA_Y + BLOCK_SIZE * y, AREA_X + BLOCK_SIZE * ( x + 1 ) - 2, AREA_Y + BLOCK_SIZE * ( y + 1 ) - 2
return
//
// エリアを再描画
#deffunc draw_area var map
color
boxf AREA_X, AREA_Y, AREA_X + AREA_WIDTH2 - 1, AREA_Y + AREA_HEIGHT2 - 1
repeat AREA_HEIGHT
y = cnt
repeat AREA_WIDTH
p = peek( map, y * AREA_WIDTH + cnt )
if p : draw_block cnt, y, p
loop
loop
return
//
// チェックされた行を塗りつぶす
#deffunc blink_sellines var check
repeat AREA_HEIGHT
if peek( check, cnt ) {
boxf AREA_X, AREA_Y + BLOCK_SIZE * cnt, AREA_X + AREA_WIDTH2 - 1, AREA_Y + BLOCK_SIZE * ( cnt + 1 ) - 1
}
loop
return
//
// テトリミノを描く
#deffunc draw_tetrimino int block_type, int block_color, int _x, int _y, int mode
repeat 4
y = _y + cnt
if ( AREA_HEIGHT <= y )|( y < 0 ) : continue
_cnt = cnt
repeat 4
x = _x + cnt
if ( AREA_WIDTH <= x ) : break
if block_type >> ( _cnt * 4 + cnt ) & 1 {
draw_block x, y, block_color + 1, mode
}
loop
loop
return
//
// マップにブロックを固定
#deffunc fix_to_map var map, int block_type, int block_color, int _x, int _y
repeat 4
y = _y + cnt
_cnt = cnt
repeat 4
x = _x + cnt
if block_type >> ( _cnt * 4 + cnt ) & 1 {
if (x < 0)|(AREA_WIDTH <= x) : continue
if (y < 0)|(AREA_HEIGHT <= y) : continue
poke map, y * AREA_WIDTH + x, block_color + 1
}
loop
loop
return
//
// 消せる行をチェックし、変数へ結果を返す
#deffunc check_del_lines var map, var check
ret = 0
repeat AREA_HEIGHT
i = 1
_cnt = cnt
repeat AREA_WIDTH
if peek( map, _cnt * AREA_WIDTH + cnt ) == 0 {
i = 0
break
}
loop
poke check, cnt, i
ret += i
loop
return ret
//
// nLine行目を消し、上にあるラインを下へ落とす
#deffunc del_line var map, int nLine
; if ( nLine < 0 ) | ( AREA_HEIGHT <= nLine ) : return -1
if nLine > 0 {
memcpy map, map, nLine * AREA_WIDTH, AREA_WIDTH, 0
}
memset map, 0, AREA_WIDTH, 0
return; 0
//
// 指定した行をすべて削除
#deffunc del_sellines var map, var check
i = AREA_HEIGHT - 1
repeat AREA_HEIGHT, 1
if peek( check, AREA_HEIGHT - cnt ) {
del_line map, i
} else {
i--
}
loop
return; 0
//
// テトリミノが壁やブロックと衝突するか検出
#defcfunc hit_check var map, int block_type, int _x, int _y
ret = 0
repeat 4
y = _y + cnt
_cnt = cnt
repeat 4
x = _x + cnt
if block_type >> ( _cnt * 4 + cnt ) & 1 {
if ( x < 0 ) | ( AREA_WIDTH <= x ) | ( AREA_HEIGHT <= y ) {
ret = 1
break
}
if y >= 0 : if peek( map, y * AREA_WIDTH + x ) {
ret = 1
break
}
}
loop
if ret : break
loop
return ret
#global
cls 1
randomize
hsptv_up -1, ""
dim block_type, 4, 7 // Zが時計回り
block_type( 0, 0 ) = $0660, $0660, $0660, $0660 // ■
block_type( 0, 1 ) = $2222, $00F0, $4444, $0F00 // |
block_type( 0, 2 ) = $0270, $0232, $0072, $0262 // ┤
block_type( 0, 3 ) = $0360, $0462, $06C0, $4620 // s
block_type( 0, 4 ) = $0630, $0264, $0C60, $2640 // z
block_type( 0, 5 ) = $2260, $0470, $0644, $0E20 // 「
block_type( 0, 6 ) = $4460, $0740, $0622, $02E0 // └
dim high_score, HIGHSCORE_MAX
sdim ranker_name, 50, HIGHSCORE_MAX
sdim map, AREA_WIDTH * AREA_HEIGHT
sdim line_check, AREA_HEIGHT
sqarea_x = AREA_X, AREA_X + AREA_WIDTH2, AREA_X + AREA_WIDTH2, AREA_X
sqarea_y = AREA_Y, AREA_Y, AREA_Y + AREA_HEIGHT2, AREA_Y + AREA_HEIGHT2
;pos ginfo_winx : mes "Gameover"
;gameover_width = ginfo_mesx : gameover_height = ginfo_mesy
#const gameover_width 64
#const gameover_height 18
#const fall_limit 17
gmode GMODE_ALPHA, , , 192
*restart
gosub *reload_highscore
memset map, 0, AREA_WIDTH * AREA_HEIGHT
next_type = rnd(7)
state = STATE_NORMAL
score = 0
gosub *create_new_tetrimino
*main
stick keys, 8
if state == STATE_BLINK {
state_limit--
if state_limit == 0 {
state = STATE_NORMAL
del_sellines map, line_check
gosub *create_new_tetrimino
}
}
if state == STATE_GAMEOVER {
if state_limit : state_limit--
if state_limit == 1 : hsptv_up score, ""
if ( state_limit == 0 ) & ( keys >> 4 & 1 ) : goto *restart
}
if state == STATE_NORMAL {
gosub *move_tetrimino
}
gosub *draw
wait 2
goto *main
*draw
redraw 0
draw_area map
gosub *draw_score
gosub *draw_next
if state == STATE_NORMAL {
gosub *draw_ghost
draw_tetrimino block_type( moving_rot, moving_type ), moving_type, moving_x, moving_y, 0
}
if state == STATE_BLINK {
c = 255 * ( state_limit / 3 \ 2 )
color c, c, c
blink_sellines line_check
}
if state == STATE_GAMEOVER {
color
gsquare -1, sqarea_x, sqarea_y
x = AREA_X + ( AREA_WIDTH2 - gameover_width ) / 2
y = AREA_Y + ( AREA_HEIGHT2 - gameover_height ) / 2
color 100, 100, 100
pos x+2, y+2
mes "Gameover"
color 255, 255, 255
pos x, y
mes "Gameover"
if ( state_limit == 0 ) {
pos x-50, y+40 : mes "push Z key to restart"
}
}
redraw 1
return
*draw_next
color
boxf BLOCK_HSIZE, BLOCK_HSIZE, BLOCK_HSIZE * 9 - 1, BLOCK_HSIZE * 11 - 1
pos BLOCK_HSIZE, BLOCK_HSIZE
draw_tetrimino block_type( 0, next_type ), next_type, -4, 1, 0
return
*draw_score
color
boxf BLOCK_HSIZE, BLOCK_SIZE * 6, BLOCK_HSIZE * 9 - 1, BLOCK_HSIZE * 29 - 1
color 255, 255, 255
pos BLOCK_HSIZE + 6, BLOCK_SIZE * 6 + 9
mes strf( "score:%08d", score )
mes "--------------"
repeat HIGHSCORE_MAX
mes "" + ( cnt + 1 ) + ":" + ranker_name( cnt )
mes strf( " %08d", highscore(cnt) )
loop
return
*move_tetrimino
if state != STATE_NORMAL : return
// 横方向の移動
next_moving_x = moving_x + ( keys >> 2 & 1 ) - ( keys & 1 )
if hit_check( map, block_type( moving_rot, moving_type ), next_moving_x, moving_y ) == 0 {
moving_x = next_moving_x
}
// 縦方向の移動
fall_count += 1 + 3 * ( keys >> 3 & 1 )
if fall_count >= fall_limit {
fall_count = 0
if hit_check( map, block_type( moving_rot, moving_type ), moving_x, moving_y + 1 ) == 0 {
moving_y++
} else {
// これ以上落下できないので、今の位置に固定
fix_to_map map, block_type( moving_rot, moving_type ), moving_type, moving_x, moving_y
gosub *check_delete
}
}
if keys & 2 {
moving_y = ghost_y
fall_count = fall_limit
}
// 回転処理
if keys & %110000 {
next_rot = moving_rot + (keys >> 4 & 1) - (keys >> 5 & 1) & 3
if hit_check( map, block_type( next_rot, moving_type ), moving_x, moving_y ) == 0 {
moving_rot = next_rot
// fall_count--
}
}
return
*check_delete
check_del_lines map, line_check
if stat {
score += stat * stat * 10
state = STATE_BLINK
state_limit = 12
} else {
gosub *create_new_tetrimino
}
return
*draw_ghost
repeat
if hit_check( map, block_type( moving_rot, moving_type ), moving_x, moving_y + cnt ) {
ghost_y = moving_y + cnt - 1
break
}
loop
if ghost_y > moving_y {
draw_tetrimino block_type( moving_rot, moving_type ), moving_type, moving_x, ghost_y, 1
}
return
*create_new_tetrimino
moving_x = AREA_WIDTH / 2 - 2// 動かしているテトリミノの位置(左上)
moving_y = -2
moving_rot = 0 // 動かしているテトリミノの回転
moving_type = next_type // 動かしているテトリミノの種類(兼色の種類)
next_type = rnd(7)
if hit_check( map, block_type( moving_rot, moving_type ), moving_x, moving_y ) {
// ゲームオーバー
state = STATE_GAMEOVER
state_limit = 20
gosub *reload_highscore
}
return
*reload_highscore
repeat HIGHSCORE_MAX
hsptv_getrank highscore(cnt), ranker_name(cnt), s, cnt
loop
return