命令・コメント・文字列・プリプロセッサ・ラベルのタグ付けに成功しました。と思ったら命令のタグ付けに不具合があったようです。残念。
関数と変数の区別はデータベースを用いる必要がありそうなので、ここでひと段落です。
今回はHTMLタグを2つのモードで生成するモジュールを垂れ流し。
解析スクリプトはあまりにも長すぎるので、もう少し整理してから垂れ流したいと思います。
配色は一時的にle.Antillaのものをお借りしています。#enum global MODE_XHTML = 1
#enum global MODE_HTML
// パラメータ省略用マクロ
#define ctype aloneTag( %1, %2 = "" ) _aloneTag( %1, %2 )
#define ctype startTag( %1, %2 = "" ) _startTag( %1, %2 )
#module
#defcfunc _aloneTag str tagName, str className
if ( replaceMode@ == MODE_XHTML ) {
if ( className == "" ) {
return "<" + tagName + " />"
} else {
return "<" + tagName + " class=\"" + className + "\" />"
}
} else {
if ( className == "" ) {
return "<" + tagName + ">"
} else {
return "<" + tagName + " class=\"" + className + "\">"
}
}
#defcfunc endTag str tagName
return "</" + tagName + ">"
#defcfunc _startTag str tagName, str className
if ( className == "" ) {
return "<" + tagName + ">"
} else {
return "<" + tagName + " class=\"" + className + "\">"
}
#global
/* モジュールここまで */
*start
repeat 2
if ( cnt == 0 ) {
replaceMode = MODE_HTML
} else {
replaceMode = MODE_XHTML
}
; (X)HTMLの出力
mes startTag( "html" ) + startTag( "head" )
mes "\t" + startTag( "title" ) + "HTML Sample" + endTag( "title" )
mes endTag( "head" )
mes startTag( "body" )
mes "\t" + startTag( "p", "class1" ) + "message test" + aloneTag( "br" ) + "\n\t2nd line" + endTag( "p" )
mes endTag( "body" ) + endTag( "html" ) + "\n"
loop
stop
2007年7月20日金曜日
(X)HTMLコンバータ (2)
2007年7月18日水曜日
(X)HTMLコンバータ (1) 簡単なコンバータ
短期集中連載第1弾(?)、HSPスクリプトをXHTMLへコンバートするスクリプト。
HSP開発WikiのTABからスペース変換を参考にさせていただきました。kz3さんに感謝!
今回は動作イメージをつくるためのβ版です。命令や関数の色づけ、HSPスクリプトエディタ用外部ツール化などを目指します。
特にポイントと言える部分はありませんが、2バイト文字を判定するためにIsDBCSLeadByteEx()を利用していたり変わった方法で文字列を挿入していたり珍しいmemexpandを使っていたりとやや異色です。// HSP to (X)HTML converter 2007.07.18
#uselib "kernel32.dll"
#cfunc global IsDBCSLeadByteEx "IsDBCSLeadByteEx" sptr, sptr
#const CP_ACP 0
#const TAB_SIZE 4
#const EXPAND_SIZE 1024
*start
dialog "hsp;*.as;*.hss;*.hsh", 16
fileName = refstr
on stat goto *notSelected, *openFile
// ファイルが選択されなかった → 終了
*notSelected
end
// ファイルが選択された → ファイルを開く
*openFile
notesel text
noteload fileName
gosub *replaceText
// 前後にタグを挿入(改善の余地あり?)
*addTags
l = strlen( text )
s = ""
memExpand text, l + 26
poke text, l, ""
poke text, strlen(s), text
repeat strlen(s)
poke text, cnt, peek( s, cnt )
loop
*showResult
mesbox text, ginfo_winx, ginfo_winy
title "変換が終了しました。"
stop
// テキストの置換
*replaceText
rTextSize = strlen(text)
sdim rText, rTextSize // ReplacedText
i = 0 : x = 0
repeat
c = peek( text, cnt )
if ( rTextSize <= i + 6 * TAB_SIZE ) {
rTextSize += EXPAND_SIZE
memExpand rText, rTextSize
}
switch c
case 0
break
swbreak
case 13
if ( peek( text, cnt + 1 ) == 10 ) {
// 改行
wpoke rText, i, 2573 : x = 0 : i += 2 // 2573 = ( 10 << 8 ) | 13
continue cnt + 2
}
swbreak
case '\t'
repeat TAB_SIZE - ( x \ TAB_SIZE )
poke rText, i, " " : i += 6 : x++
loop
swbreak
case ' '
poke rText, i, " " : i += 6 : x++
swbreak
case '&'
poke rText, i, "&" : i += 5 : x++
swbreak
case '<'
poke rText, i, "<" : i += 4 : x++
swbreak
case '>'
poke rText, i, ">" : i += 4 : x++
swbreak
default
if IsDBCSLeadByteEx( CP_ACP, c ) {
// 2バイト文字の場合
wpoke rText, i, wpeek( text, cnt ) : i += 2 : x += 2
continue cnt + 2
} else {
poke rText, i, c : i++ : x++
}
swend
; await 1
loop
text = rText
sdim rText, 4
return
2007年7月16日月曜日
波紋のエフェクト(3次元ver.)
d3moduleを利用した波紋のエフェクトの3次元版。波の高さによって明るさが変わるようにもなっています。#include "d3m.hsp"
#define ctype round(%1) double(strf("%%0.0f", %1)) // 四捨五入(hspmathより抜粋)
#const CONST_A 0.1 // 定数その1。波長を決定付ける。
#const CONST_B 7 // 定数その2。屈折の程度を決定付ける。
buffer 1
onclick goto *start
*start
onclick 0
dialog "jpg;*.gif;*.bmp", 16
if stat == 0 : end
gsel 1 : picload refstr
sizeX = ginfo_winx
sizeY = ginfo_winy
centerX = ginfo_winx / 2
centerY = ginfo_winy / 2
screen 0, sizeX, sizeY, SCREEN_NORMAL
gmode GMODE_GDI, sizeX, sizeY
gcopy 1, 0, 0
d3setcam sizeX/2, -300, sizeY/4, sizeX/2, 0, sizeY/2
redraw 0
boxf
gmode GMODE_MEM, 1, 1
repeat sizeY : targetY = cnt
title "変換中…" + str(100 * cnt / sizeY) + "%"
repeat sizeX : targetX = cnt
// 中心から見た座標を算出。
d3getpos vx, vy, targetX, 0, targetY
dx = vx - centerX
dy = centerY -vy
// 中心から見た角度と距離を算出。
theta = atan(dy, dx)
dist = sqrt(dx * dx + dy * dy)
// ここがポイント。sinで屈折する距離を決めています。
// ラスタースクロールのスクリプトのほうが分かりやすいかもしれません。
copyX = centerX + round(cos(theta) * (dist + sin(dist * CONST_A) * CONST_B))
copyY = centerY + round(sin(theta) * (dist + sin(dist * CONST_A) * CONST_B))
pos targetX, targetY
gmode GMODE_ALPHA, 1, 1, absf(sin(dist * CONST_A)) * 64 + 192
gcopy 1, copyX, copyY
loop
await 10
loop
redraw 1
title "変換終了 - クリックで再開"
onclick 1
stop
2007年7月15日日曜日
マウスの方向転換を検知する(失敗作)
マウスジェスチャーを実装する第一歩として、マウスの方向転換を検知するスクリプトを試作。残念ながら正確な検知まで到達できませんでしたが、話のタネに晒しておきます。
基本的な流れは
- マウスの位置を配列に記録しておく(古いものは削除される)
- マウスの進行方向も算出して配列に記録
- 過去数フレームと進行方向を比較し、その差が一定の範囲内に収まっていれば方向を転換したとみなす
#const HISTORY_MAX 3
#const PI 3.1415
#module
#defcfunc dist2d int a, int b
return sqrt(a * a + b * b)
#global
*init
dim historyX, HISTORY_MAX // X座標の履歴
dim historyY, HISTORY_MAX // Y座標の履歴
ddim historyA, HISTORY_MAX // 進行方向の履歴
gosub *resetCounter
*main
gosub *calc
wait 2
goto *main
*resetCounter
counter = HISTORY_MAX // 配列変数history~が一新されるまで判定しない
return
*calc
// クリックでデバッグウィンドウ表示
getkey leftClick, 1 : assert (leftClick == 0)
// 方向転換後ある程度時間が経っており、マウスが動いているときに限り判定
if (counter == 0) {
title ""
if (0.0 < dist2d(mouseY - historyY(0), mouseX - historyX(0))) {
ang = atan(mouseY - historyY(0), mouseX - historyX(0))
repeat HISTORY_MAX
if (dist2d(mouseY - historyY(cnt), mouseX - historyX(cnt)) < 5.0) {
// 距離が短い場合、判定しない
continue
}
// 角度変化をtに代入
t = ang - historyA(cnt)
while (t < -PI) : t += PI * 2 : wend
while (PI < t) : t -= PI * 2 : wend
// 一定の角度内に収まっていれば、方向転換したとみなす
if ((0.5 < absf(t)) & (absf(t) < 2.5)) {
pset mousex, mousey
if (t < 0.0) : title "turn left"
if (0.0 < t) : title "turn right"
gosub *resetCounter
break
}
loop
}
}
if (counter > 0) {
ang = historyA(0)
counter--
}
// 配列変数history~を1ずつシフトさせる
repeat HISTORY_MAX - 1, 1
historyX(HISTORY_MAX - cnt) = historyX(HISTORY_MAX - cnt - 1)
historyY(HISTORY_MAX - cnt) = historyY(HISTORY_MAX - cnt - 1)
historyA(HISTORY_MAX - cnt) = historyA(HISTORY_MAX - cnt - 1)
loop
historyX(0) = mouseX
historyY(0) = mouseY
historyA(0) = ang
return
2007年7月12日木曜日
波紋のエフェクト

「HSPでSTGを作っていくblog」(kt.さん運営)のラスタースクロールに影響を受け、作成。
kt.さんの載せていらっしゃるスクリプトは動作も軽くループに組み込んでも問題ないのですが、こちらはかなり重いです。awaitを外しても変わらないほど。ひとつのネタとしてお楽しみください。
※この記事に限り転載・引用は禁止です。転載・引用可になりました。(2007/7/14)
※細部を修正。(2007/7/14)#define ctype round(%1) double(strf("%%0.0f", %1)) // 四捨五入(hspmathより抜粋)
#const CONST_A 0.2 // 定数その1。波長を決定付ける。
#const CONST_B 7 // 定数その2。屈折の程度を決定付ける。
buffer 1
onclick goto *start
*start
onclick 0
dialog "jpg;*.gif;*.bmp", 16
if stat == 0 : end
gsel 1 : picload refstr
sizeX = ginfo_winx
sizeY = ginfo_winy
centerX = ginfo_winx / 2
centerY = ginfo_winy / 2
screen 0, sizeX, sizeY, SCREEN_NORMAL
gcopy 1, 0, 0, sizeX, sizeY
gmode GMODE_MEM, 1, 1
title "変換中…"
redraw 0
boxf
repeat sizeY : targetY = cnt
repeat sizeX : targetX = cnt
pos targetX, targetY
// 中心から見た座標を算出。
dx = targetX - centerX
dy = targetY - centerY
// 中心から見た角度と距離を算出。
theta = atan(dy, dx)
dist = sqrt(dx * dx + dy * dy)
// ここがポイント。sinで屈折する距離を決めています。
// ラスタースクロールのスクリプトのほうが分かりやすいかもしれません。
copyX = centerX + round(cos(theta) * (dist + sin(dist * CONST_A) * CONST_B))
copyY = centerY + round(sin(theta) * (dist + sin(dist * CONST_A) * CONST_B))
gcopy 1, copyX, copyY
loop
await 10
loop
redraw 1
title "変換終了 - クリックで再開"
onclick 1
stop
2007年7月9日月曜日
格ゲーのようなコマンド解析
フォーチュンサモナーズ(素晴らしいゲームです)に触発されて作成。
文字列検索用の関数instr()を利用しています。
メジャーな実装方法は知りませんが、間違いなくこれはマイナーな実装方法でしょう……。
※キューに要素を追加することを正しくはエンキュー(enqueue)と呼ぶそうです。#const global COMMAND_LENGTH 16
#module
#deffunc shiftAndPush var p1, str p2, local l
poke p1, 0, strmid(p1, 1, COMMAND_LENGTH - 2)
poke p1, COMMAND_LENGTH - 2, p2
poke p1, COMMAND_LENGTH - 1, 0
return
#global
sdim sCommand, COMMAND_LENGTH
gosub *clearCommand
// 方向をあらわす文字(テンキー同様、左が4・上が8・右が6……となっている)
sdim sCom, 4, 17
sCom(1) = "4" // 左
sCom(3) = "7" // 左上
sCom(2) = "8" // 上
sCom(6) = "9" // 右上
sCom(4) = "6" // 右
sCom(12)= "3" // 右下
sCom(8) = "2" // 下
sCom(9) = "1" // 左下
sCom(16)= "A" // スペースキー
*main
gosub *renewCommands
gosub *serch
title sCommand
wait 2
goto *main
// キューが更新されるかどうか判定
*renewCommands
stick keys, 0b01111 : keys &= 0b11111
if ((keys & 0b0101) == 0b0101) {
// 上下同時押しは無効
keys -= 0b0101
}
if ((keys & 0b1010) == 0b1010) {
// 左右同時押しは無効
keys -= 0b1010
}
if (keys != oldKeys) {
if (keys & 0b11111) != (oldKeys & 0b01111) {
// 新しく入力をキューに追加
gosub *insert
}
oldKeys = keys
}
counter++
if counter > 10 {
// 10フレーム入力がないとキューを廃棄
counter = 0
gosub *clearCommand
}
return
// 入力されたボタンに応じてキューに文字列をプッシュ
*insert
counter = 0
if ((keys & 0b01111) != 0) & ((keys & 0b01111) ! (oldKeys & 0b01111)) {
shiftAndPush sCommand, sCom(keys & 0b01111)
}
if (keys & 0b10000) {
shiftAndPush sCommand, sCom(keys & 0b10000)
}
return
// 技の発動条件を検索
*serch
if instr(sCommand, 0, "41236A") > 0 {
// 左 → 左下 → 下 → 右下 → 右 → スペースキー
mes "超必殺拳発動!"
gosub *clearCommand
}
if instr(sCommand, 0, "236A") > 0 {
// 下 → 右下 → 右 → スペースキー
mes "必殺拳発動!"
gosub *clearCommand
}
if instr(sCommand, 0, "2146A") > 0 {
// 下 → 左下 → 左 → 右 → スペースキー
mes "気合脚発動!"
gosub *clearCommand
}
return
// キューを廃棄
*clearCommand
memset sCommand, '_', COMMAND_LENGTH - 1
return
2007年7月1日日曜日
マップのスクロール
本家掲示板に投稿したものに少し手を加えたもの。
説明用なので読みやすくするべく、本来は必要ない変数を多用している。#const WAIT_TIME 3 // ウェイト[10ms]
#const SPEED 5 // 移動スピード
#const CHARACTER_SIZE 5 // キャラクタの描画サイズ
#const BLANK 100 // マップスクロールが始まる位置
screen 0, 480, 240, SCREEN_NORMAL
x = 0 : y = ginfo_winy / 2 // キャラクタの位置
scrollX = 0 : scrollY = 0 // 画面左上のマップ上での位置(=スクロール量)
mapWidth = 750 // マップの幅
// 適当にマップを準備
buffer 1, mapWidth, ginfo_winy, SCREEN_NORMAL
repeat 20
hsvcolor rnd(192), 100, 255
boxf rnd(ginfo_winx), rnd(ginfo_winy), rnd(ginfo_winx), rnd(ginfo_winy)
loop
gsel 0
// ★メインループ★
*main
gosub *moveCharacter // キャラクタを動かす
gosub *setScroll // 描画する位置を決める
gosub *draw // いろんな描画処理
wait WAIT_TIME
goto *main
// キャラクタを動かす
*moveCharacter
stick key, 5 : speedX = SPEED * ((key >> 2 & 1) - (key & 1))
x = limit(x + speedX, 0, mapWidth)
return
// 描画する位置を決める
*setScroll
// (x - scrollX)が画面上でのキャラクタの位置になる
if x - scrollX < BLANK{
// キャラクタがBLANKより左側に移動した場合、カメラを移動させる
scrollX = limit(x - BLANK, 0, mapWidth - ginfo_winx)
}
if ginfo_winx - BLANK < x - scrollX {
// キャラクタが(ginfo_winx - BLANK)より右側に移動した場合、カメラを移動させる
scrollX = limit(x + BLANK - ginfo_winx, 0, mapWidth - ginfo_winx)
}
return
//いろんな描画処理
*draw
redraw 0
gosub *drawMap // マップを描画する
gosub *drawCharacter // キャラクタを描画する
redraw 1
return
// マップを描画する
*drawMap
pos 0, 0 : gcopy 1, scrollX, scrollY, ginfo_winx, ginfo_winy
return
// キャラクタを描画する
*drawCharacter
drawX = x - scrollX : drawY = y
boxf drawX - CHARACTER_SIZE, y - CHARACTER_SIZE, drawX + CHARACTER_SIZE, drawY + CHARACTER_SIZE
return

