どう書く?orgベータ版というサイトをCodeZineさま経由で見つけました。
プログラミングのお題が沢山あって、お題を探している方や新しい言語に挑戦される方にはちょうど良いサービスだと思います。
お題の流用を禁止してはいないようなので、私がどう書く?orgに投稿した記事の一部をこちらのブログにも残していきたいと思います。
2007年10月31日水曜日
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年10月23日火曜日
特定の文字列を説明文に含む命令・関数を抽出する
空色鉛筆の方に載せるサンプルスクリとして書いたものの、ちょっとややこしすぎたのでこちらへ。
HDLがインストールされていないと動作しませんので注意してください。
HDLがインストールされていないと動作しませんので注意してください。
// 動作条件・SQLele1.10以降
// およびHSP Document Library BETA 0.01 以降が
// インストール済みであること
#include "sqlele.hsp"
#define DB_NAME "hdlbase.xdb"
chdir dir_exe
exist DB_NAME
if ( strsize < 0 ) {
dialog "データベースファイルが見つかりません。プログラムを終了します。", 1
end
}
key_word = "%ボタン%" // 検索キーワード
// %は0文字以上の文字列にマッチ
// _は任意の1文字にマッチ
sql_open DB_NAME
// キーワードが説明文にマッチする命令・関数名を検索する(昇順ソート)
sql_q "SELECT Name FROM Help WHERE Inst LIKE " + prm_text( key_word ) + " ORDER BY Name"
count = stat
mes "文字列'" + key_word + "'がマッチした項目一覧:"
repeat count
mes " - " + sql_v( "Name" )
sql_next
loop
mes "以上" + count + "件"
sql_close
stop
2007年10月9日火曜日
論理和とビットシフトで掛け算する
ビットシフトを使った掛け算。CASL2などを学んだ方なら動作原理はご存知かと思います。
前回の加算モジュールを利用しています。
関連:http://blog.livedoor.jp/dankogai/archives/50638838.html
前回の加算モジュールを利用しています。
関連:http://blog.livedoor.jp/dankogai/archives/50638838.html
#module
#defcfunc add int left_op, int right_op, local left, local right, local tmp
left = left_op : right = right_op
while ( left & right )
tmp = ( left & right ) << 1
left ^= right
right = tmp
wend
return ( left | right )
#defcfunc multi int left_op, int right_op, local left, local right, local tmp
left = left_op : right = right_op
while ( right )
if ( right & 1 ) : tmp = add( tmp, left )
left <<= 1
right >>= 1
wend
return tmp
#global
randomize
repeat 10
l = rnd( 9 ) + 1
r = rnd( 9 ) + 1
mes strf( "%1d", l ) + " * " + strf( "%1d", r ) + " = " + strf( "%2d", multi( l, r ) )
loop
stop
2007年10月8日月曜日
論理積と論理和と排他的論理和で足し算する
ビット演算で足し算を行うスクリプト。
単純で短いスクリプトですが、再帰が必要だったり排他的論理和(XOR)演算を行う必要があったりと少々高度です。やっていることは小学校で習う「筆算」と同じなのですが。
CPU内部の演算は、もしかしたらこうして行われているのかもしれませんね。ちょっと調べてみます。
再帰ではなくループを使う方法はこちら。
単純で短いスクリプトですが、再帰が必要だったり排他的論理和(XOR)演算を行う必要があったりと少々高度です。やっていることは小学校で習う「筆算」と同じなのですが。
CPU内部の演算は、もしかしたらこうして行われているのかもしれませんね。ちょっと調べてみます。
#module
#defcfunc add int left_op, int right_op
kuri = ( left_op & right_op ) << 1 // 繰り上がり
if ( kuri == 0 ) {
// 繰り上がりがなければ論理和を返す
return ( left_op | right_op )
} else {
// 繰り上がりがある場合は、
// 繰り上がりと排他的論理和の結果を加算する
return add( left_op ^ right_op, kuri )
}
#global
randomize
repeat 10
l = rnd( 99 ) + 1
r = rnd( 99 ) + 1
mes strf( "%2d", l ) + " + " + strf( "%2d", r ) + " = " + strf( "%3d", add( l, r ) )
loop
stop
再帰ではなくループを使う方法はこちら。
#module
#defcfunc add int left_op, int right_op
left = left_op : right = right_op
while ( left & right )
tmp = ( left & right ) << 1
left ^= right
right = tmp
wend
return ( left | right )
#global
randomize
repeat 10
l = rnd( 99 ) + 1
r = rnd( 99 ) + 1
mes strf( "%2d", l ) + " + " + strf( "%2d", r ) + " = " + strf( "%3d", add( l, r ) )
loop
stop
2007年10月2日火曜日
俯瞰型RPGマップの描画 2
前回のスクリプトにカメラの移動とキャラクタの移動・ジャンプを追加しました。マップチップの明るさは距離に応じた変化に限定しています。
ここまでくるとRPGというよりはアクションに近いものがありますね。
カメラの位置に合わせてカーソルキーで移動する方向を変化させる処理や、ビルボードのようにキャラクタを常に手前を向ける処理など、三角関数を多用しているので、今回のスクリプトはさすがに読みづらいと思います。d3setlocal命令によって多少は読みやすくなっていますが……。興味のある方はぜひ式を解いてみてください。
ここまでくるとRPGというよりはアクションに近いものがありますね。
カメラの位置に合わせてカーソルキーで移動する方向を変化させる処理や、ビルボードのようにキャラクタを常に手前を向ける処理など、三角関数を多用しているので、今回のスクリプトはさすがに読みづらいと思います。d3setlocal命令によって多少は読みやすくなっていますが……。興味のある方はぜひ式を解いてみてください。
// カーソルキーでキャラクタの移動
// Ctrl同時押しでカメラの移動(回転)
// Spaceでジャンプ
#include "d3m.hsp"
#include "hspmath.as"
#const CELL_SIZE 100 // d3m上のマップチップサイズ
#const IMG_SIZE 64 // bmpのマップチップサイズ
#const CAM_DIST 500
#const CHAR_SPEED 15
#const MAP_WIDTH 18
#const MAP_HEIGHT 15
// マップチップのロード
buffer 1 : picload dir_exe + "/sample/game/testchr.bmp"
// 影用の画像を用意する
color : boxf IMG_SIZE * 3, 0, IMG_SIZE * 4, IMG_SIZE
color 255,255,255 : circle IMG_SIZE * 3, 0, IMG_SIZE * 4, IMG_SIZE, 1
gsel 0
// 変数の初期化
cam_theta = M_PI * 2 / 5 // カメラの角度
cam_phi = -M_PI / 2
char_x = 0.0 // キャラクタの位置
char_y = 0.0
char_z = 0.0
char_vz = 0.0 // キャラクタの速度
// マップ作成
dim map, MAP_WIDTH, MAP_HEIGHT
repeat length2( map )
y = cnt
repeat length( map )
map( cnt, y ) = rnd( 3 )
loop
loop
gosub *draw
*main
stick keys, 15 + 64
gosub *move
if ( is_jumping ) | ( ( keys & 15 ) > 0 ) : gosub *draw
wait 3
goto *main
*move
if ( keys >> 4 & 1 ) & ( is_jumping == 0 ) {
char_vz = 20.0 // ジャンプ開始
is_jumping = 1 // ジャンプ中フラグをON
}
char_vz -= 2.0 // 重力による加速
char_z += char_vz // Z方向の移動
if char_z < 0.0 {
// 着地時の演算
char_z = 0.0
char_vz = 0.0
is_jumping = 0
}
if keys & 64 {
// ctrl同時押し…カメラの移動
cam_theta = limitf( cam_theta + 0.05 * ((keys >> 3 & 1) - (keys >> 1 & 1)), 0.01, M_PI / 2 - 0.01 )
cam_phi += 0.05 * ((keys >> 2 & 1) - (keys & 1))
} else {
// ctrlを押さない…キャラクタの移動
keys_x = (keys >> 2 & 1) - (keys & 1)
keys_y = (keys >> 3 & 1) - (keys >> 1 & 1)
char_x = limitf( char_x - ( sin( cam_phi ) * keys_x - cos( cam_phi ) * keys_y ) * CHAR_SPEED, -MAP_WIDTH/2*CELL_SIZE, (MAP_WIDTH-1)/2*CELL_SIZE)
char_y = limitf( char_y + ( cos( cam_phi ) * keys_x + sin( cam_phi ) * keys_y ) * CHAR_SPEED, -MAP_HEIGHT/2*CELL_SIZE, (MAP_HEIGHT-1)/2*CELL_SIZE)
}
return
*draw
// カメラの設定
d3setcam cos(cam_phi)*sin(cam_theta)*CAM_DIST + char_x, sin(cam_phi)*sin(cam_theta)*CAM_DIST + char_y, cos(cam_theta)*CAM_DIST, char_x, char_y, 0
redraw 0
color : boxf
gz = 0, 0, 0, 0 // d3texture用の配列
repeat MAP_WIDTH, -MAP_WIDTH/2 : x = cnt
repeat MAP_HEIGHT, -MAP_HEIGHT/2 : y = cnt
dx = ( x * CELL_SIZE - char_x ) / CELL_SIZE
dy = ( y * CELL_SIZE - char_y ) / CELL_SIZE
gmode GMODE_ALPHA, , , 255.0 / pow( dx * dx + dy * dy + 1, 0.25 )
// d3texture用の配列を準備
gx( 0 ) = x * CELL_SIZE - CELL_SIZE / 2, x * CELL_SIZE + CELL_SIZE / 2
gx( 2 ) = gx( 1 ), gx( 0 )
gy( 0 ) = y * CELL_SIZE + CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
gy( 2 ) = y * CELL_SIZE - CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
d3texture gx, gy, gz, 1, IMG_SIZE * map( x + MAP_WIDTH/2, y + MAP_HEIGHT/2 ), 0, IMG_SIZE, IMG_SIZE
loop
loop
d3setlocal char_x, char_y, 0, sin(cam_phi),cos(cam_phi),0,-cos(cam_phi),sin(cam_phi),0,0,0,1
// 影を描画
gmode GMODE_SUB,,,32
gx( 0 ) = -CELL_SIZE / 2, CELL_SIZE / 2
gx( 2 ) = gx( 1 ), gx( 0 )
gy( 0 ) = CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
gy( 2 ) = -CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
gz( 0 ) = 0, 0, 0, 0
d3texture gx, gy, gz, 1, IMG_SIZE * 3, 0, IMG_SIZE, IMG_SIZE
// キャラクターを描画
gmode GMODE_RGB0
gy( 0 ) = 0, 0, 0, 0
gz( 0 ) = CELL_SIZE + char_z : gz( 1 ) = gz( 0 )
gz( 2 ) = int( char_z ) : gz( 3 ) = gz( 2 )
d3texture gx, gy, gz, 1, IMG_SIZE * 1, IMG_SIZE, IMG_SIZE, IMG_SIZE
redraw 1
return
俯瞰型RPGマップの描画
RPG関連のスクリプトを書こうと思い立ち、作成。普通のマップじゃつまらないので3Dにしてみました。
drawmodeが1の時の明るさの計算は、CodeZine: 3Dモデルを表示するJavaアプレットの作成を参考としています。
障害物のあるマップで視野を求めるで使った視野計算を合わせれば、よりそれっぽくなりそうです。
少々単純すぎるうえに用途が限られるので、開発wikiには投げずにここへ置いときます。
drawmodeが1の時の明るさの計算は、CodeZine: 3Dモデルを表示するJavaアプレットの作成を参考としています。
障害物のあるマップで視野を求めるで使った視野計算を合わせれば、よりそれっぽくなりそうです。
少々単純すぎるうえに用途が限られるので、開発wikiには投げずにここへ置いときます。
#include "d3m.hsp"
#const CELL_SIZE 100 // d3m上のマップチップサイズ
#const IMG_SIZE 64 // bmpのマップチップサイズ
#const CAM_X 0 // カメラ位置(45°手前から俯瞰)
#const CAM_Y -400
#const CAM_Z 400
#define ctype pow(%1,%2) expf(logf(%1)*(%2)) // x^y
// マップチップのロード
buffer 1 : picload dir_exe + "/sample/game/testchr.bmp"
// カメラの設定
gsel 0
d3setcam CAM_X, CAM_Y, CAM_Z, 0, 0, 0
// 変数の初期化
gz = 0, 0, 0, 0 // d3texture用の配列
ch = CAM_Z // CH = カメラの高さ
// マップ作成
dim map, 20, 20
repeat length2( map )
y = cnt
repeat length( map )
map( cnt, y ) = rnd( 3 )
loop
loop
title "クリックで描画モード変更"
onclick gosub *change_drawmode
gosub *draw
stop
*draw
redraw 0
color : boxf
for x, -10, 10
for y, -10, 10
// マップチップの明るさを計算
switch drawmode
case 0 // 均等描画(どのマップチップも同じ明るさで描画)
c = 255
swbreak
case 1 // 光の反射を考慮(45°手前から俯瞰するとして最適化済み)
// カメラの位置を点C、カメラの位置からXY平面におろした垂線の足を点H、
// マップチップの中心を点B、マップチップの中心からY軸におろした垂線の足を点A、
// XY平面上の原点を点Oとする。
// このとき、マップの中心が最も明るいという条件(すなわち光が45°奥から入射するという条件)を課すと、
// マップの明るさは cos( ∠COH - ∠CAH ) * cos( ∠BCA ) で決定される。
ah = y * CELL_SIZE - CAM_Y // AH
ab = x * CELL_SIZE // AB
cb = sqrt( ab * ab + ah * ah + ch * ch ) // CB
c = int( double( ah + ch ) / ( sqrt( 2.0 ) * cb ) * 255 ) // = cos( ∠COH - ∠CAH ) * cos( ∠BCA ) * 255
swbreak
case 2 // 距離に応じて変化(遠ければ遠いほど暗くなる)
c = int( 255.0 / pow( x * x + y * y + 1, 0.2 ) ) // 距離に反比例させると暗すぎたので0.2乗で調整
swbreak
swend
gmode GMODE_ALPHA, , , c
// d3texture用の配列を準備
gx( 0 ) = x * CELL_SIZE - CELL_SIZE / 2, x * CELL_SIZE + CELL_SIZE / 2
gx( 2 ) = gx( 1 ), gx( 0 )
gy( 0 ) = y * CELL_SIZE + CELL_SIZE / 2 : gy( 1 ) = gy( 0 )
gy( 2 ) = y * CELL_SIZE - CELL_SIZE / 2 : gy( 3 ) = gy( 2 )
d3texture gx, gy, gz, 1, IMG_SIZE * map( x + 10, y + 10 ), 0, IMG_SIZE, IMG_SIZE
next
next
redraw 1
return
*change_drawmode
drawmode = ( drawmode + 1 ) \ 3
switch drawmode
case 0 : title "均等描画" : swbreak
case 1 : title "光の反射を考慮" : swbreak
case 2 : title "距離に応じて変化" : swbreak
swend
gosub *draw
return