
HSPの掲示板に、左右どちらに旋回する方が早いのかの判定について質問がありました。
方法としては色々あるでしょうが、そのひとつとして、ベクトルの外積を使う方法を紹介します。
// 角度の補正が面倒なので、数学に合わせて0ラジアンはx軸方向に並行とします。
// 考え方としては、自分の向きをaベクトル、自分から目標の向きをbベクトルとして、
// 外積から、abベクトルのなす角のsinを求め、どちらに旋回する方が早いか判定します。
; 自分の座標と向き
mx = 320.0
my = 240.0
mr = 0.0
*main
; 目標の座標(マウスカーソル)
tx = 0.0+mousex
ty = 0.0+mousey
; aベクトル(自分の向き)
ax = cos(mr)
ay = sin(mr)
; bベクトル(自分から目標の向き)
bx = tx-mx
by = ty-my
;-----------------------------------------------------------
; ここから重要
;-----------------------------------------------------------
; abベクトルの外積
a×b = ax*by - bx*ay
; abベクトルのなす角をsinθとして
; a×b = |a||b|sinθ
sinθ = (a×b)/sqrt(bx*bx+by*by)
if absf(sinθ)>=0.02 {
; sinθの符号で旋回する方向を判定
if sinθ>=0 {
mr += 0.02
} else {
mr -= 0.02
}
}
;-----------------------------------------------------------
; ここまで
;-----------------------------------------------------------
redraw 0
color 255,255,255 : boxf
color 0,0,0
; 自分
line mx+cos(mr)*100,my+sin(mr)*100, mx,my
; 目標
pos tx-7,ty-9 : mes "◎"
redraw
await 10
goto*main
なぜ外積やsinの符号で判定できるか分からない人は、sinの定義をよく考えてください。
この方法なら、自分が何回転するとしても面倒なことを考えなくて済みます。
説明の為に冗長なソースになっていますが、実際にやってることは簡単です。工夫すれば、かなり短くできるので、HSPコンテストのショート部門に向いているかもしれません。
この手の判定ですが、他の人のゲームのソースを研究すれば、他にも色々な方法があるかもしれません。私はプログラムの技術は人から盗んで学ぶものだと考えているので、そういうのも大切かなと思います。
円と直線の当たり判定です。
円と直線の距離を測って、半径より小さければ、当たってると判断します。
;===========================================================
; 2009/04/18
; 円と直線の判定
; GAM-22
;===========================================================
if 0 {
#defcfunc dis_line_circle double l, double m, double n, int x, int y
;-----------------------------------------------------------
; 点と直線の距離
;-----------------------------------------------------------
;
; p1,p2,p3 : 直線(lx+mx+n=0)の、 l,m,n
; p4,p5 : 点の座標(x,y)
;-----------------------------------------------------------
return absf(l*x +m*y +n) /sqrt(l*l +m*m)
#deffunc circle2 int x, int y, int r
;-----------------------------------------------------------
; 円を描画
;-----------------------------------------------------------
;
; p1,p2,p3 : 中心座標、半径
;-----------------------------------------------------------
circle x-r,y-r, x+r,y+r
return
}
;-----------------------------------------------------------
ly = -1.0
lr = 0.0
repeat
redraw 0
; 背景
color 255,255,255 : boxf
; 円
color ,,255 : circle2 mousex,mousey, 32
; 直線
color 255 : line 0, ln, 640, -(lx*640)/ly +ln
; 判定
pos 0,0 : mes "左右クリックで、回転"
if dis_line_circle(lx,ly,ln, mousex,mousey) <= 32 {
mes "当たってる"
}
redraw
stick key, 256|512
if key&256 : lr -= 0.02
if key&512 : lr += 0.02
lx = tan(lr)
ln = 240.0 -lx*320
await 20
loop
距離は、数IIの教科書に載っていた公式を使って求めています。
作ったのは良いですが、使い道が無さそうです。
HSPでコムソートをやってみました。かなり簡潔なソースになってると思います。
data = 51,62,22,9,2,34,6,21,13,98
h = int(double.length(data) /1.3)
repeat
repeat
if cnt+h >= length(data) : break
if data(cnt+h) < data(cnt) {
v1 = data(cnt)
data(cnt) = data(cnt+h)
data(cnt+h) = v1
}
loop
if h=1 {
break
} else {
h = int(double.h /1.3)
}
loop
foreach data
mes data.cnt
loop
HSPコンテスト2008も終わり、HSPを触ることとも少なくなると思うので、忘れないうちに記事にしようと思います。軽くwinmm.dllを使う方法を紹介したいと思います。
最近コンテストで、HSPTV部門なのに音が出るプログラムを見かけることがあります。私もそれがやりたくて実装してみた作品が「蟲」だったりします。
具体的にはこんな流れになります。
けっこう簡単なのですが、引数を計算する為に構造体を扱うことになります。それだけが厄介です。