プログラミングを勉強中の人のあれこれなブログ
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
暑くなってきました。
まだ5月なんですがね……。さておき前置きはこのぐらいにして今回はキー操作のアルゴリズム。
結構いろんなサイトを見てみると、
キー操作をウィンドウプロシージャで制御している方々が多いのですね。
私もそうするのかーと思っていたのですがあるとき先生(教えてもらっている人)に
「そこで管理する必要ないよ」
と言われて、じゃぁどうするの?という話をしていた時に教えてもらったのが以下のソース。
---------------------------------------------------------------
int Param = 0;
void keyControl()
{
if (GetAsyncKeyState(VK_SPACE) & 0x8000)
{
Param ++;
if (Param > 2)
{ Param = 2; }
}
else
{
if (Param == 2)
{ Param ++; }
if (Param == 3)
{ Param = 0; }
}
}
----------------------------------------------------------------
本当は、BOOLで制御するそうですが私にはよくわからないのでこのまま使用しております。
原理としては
1:入力を確認する
2:押されている間にカウントを+して行く。
3:カウントごとにIf分で制御する。
みたいな感じなのかしら。ちなみに使用するときは
if (Param == 1){ True };
みたいな感じです。
Param == 1:押された直後
Param == 2:押している間
Param == 3:離す時
Param == 0:何もしていない状態
というふうに場合分けしているのですね。
大掛かりなものになればなるほどプロシージャで管理するよりも
こちらで管理したほうがよいよいです。参考までにどうぞ。
テトリス制作なうにおいて発生した事件。
落下速度が、早すぎる…!
これ、どういうことかと申しますと。
ようは1フレームに1回移動させていたのが原因らしく、
移動量と相まってめっちゃ落下が早かったのですね。
さんざん悩んで先生(教えてもらっている人)に泣きつきつつ。
(いやほんとご迷惑かけてます、いつもありがとうございます。)
その先生に
「別に1フレームに1回移動させる必要なんてないのですよ」
と言われ、な、なるほど…!と感心せざるを得ない発見に。
ほんと、自分が初心者だと実感した瞬間…とまれ、そんな時にできたソースをご紹介。
-------------------------------------------------
int Count = 0;
void MovePiese()
{
Count ++;
if (Count >= 20)
{
//処理
Count = 0;
}
}
-------------------------------------------------
こんな感じ。
早い話、カウントをチャージしてカウントが一定を超えたら処理させて、カウントを初期化。
こうすることで、好きなタイミングで処理を可能にしました。
多分、いろんなサイトさんでも取り扱ってる方法の一つだと思いますが。
さてさて、次はブロックを次々と落下させる処理だー。
-----------------------------------------------------------------------------------------
BOOL HIT = FALSE; //当たったかどうかのフラグ。初期設定ではFALSE
BlockAYCenter; //矩形Aの中心Y座標
BlockAXCenter; //矩形Aの中心X座標
BlockBYCenter; //矩形Bの中心Y座標
BlockBXCenter; //矩形Bの中心X座標
BlockBYSpeed; //矩形BのY速度
BlockBXSpeed; //矩形BのX速度
BlockAWid; //矩形Aの横幅
BlockAHei; //矩形Aの縦幅
BlockBWid; //矩形Bの横幅
BlockBHei; //矩形Bの縦幅
void Hit()
{
//当たり判定。ここらへんはいろんなところでソースが出ていると思う。
//所謂、二つの座標の絶対値の距離を参照して一定の範囲内だったらTRUEを返すアルゴリズム。
//ただ、今回の判定では未来予測を使用していることに注意。
if (abs(BlockAYCenter - (BlockBYCenter + BlockBYSpeed)) <= (BlockAHei + BlockBHei) / 2)
{
if (abs(BlockAXCenter - (BlockBXCenter + BlockBXSpeed)) <= (BlockAWid + BlockBWid) / 2)
{
HIT = TRUE;
}
}
if (HIT)
{
//角の当たり判定。問題はここ。
//まず、現在位置においてどこにあるのかを判定する。
//このif文は、現状矩形Aが矩形Bの角付近にいる場合を定義している。
if (abs(BlockBXCenter - BlockAXCenter) > ((BlockAWid + BlockBWid) / 2) && abs(BlockBYCenter - BlockAYCenter) > ((BlockAHei + BlockBHei) / 2))
{
//そして判定。
//角に当たって、接触している部分の形が正方形になるのなら、角に当たっているという判定。
//そうでない場合(接触している部分の形が長方形の場合)は、XとYのどちらが長いかを場合分けして左右か上下どちらかにあたっているかを場合分けする。
if (((BlockAWid + BlockBWid) / 2) - abs((BlockBXCenter + BlockBXSpeed) - BlockAXCenter) == ((BlockAHei + BlockBHei) / 2) - abs((BlockBYCenter + BlockBYSpeed) - BlockAYCenter))
{
//ここに角に当たった場合の処理を書く。
}
else if (((BlockAWid + BlockBWid) / 2) - abs((BlockBXCenter + BlockBXSpeed) - BlockAXCenter) > ((BlockAHei + BlockBHei) / 2) - abs((BlockBYCenter + BlockBYSpeed) - BlockAYCenter))
{
//ここに角には当たっているけど左右の辺よりな場合の処理を書く。
}
else if (((BlockAWid + BlockBWid) / 2) - abs((BlockBXCenter + BlockBXSpeed) - BlockAXCenter) < ((BlockAHei + BlockBHei) / 2) - abs((BlockBYCenter + BlockBYSpeed) - BlockAYCenter))
{
//ここに角には当たっているけど上下の辺よりな場合の処理を書く。
}
}
//そして、角以外の当たり判定=各々の辺に当たっているなのでelseで処理を書く。
else
{
//ここでは左右か上下かどちらかの場合分けをしている。
//とりあえず、上下の場合をif文で定義。それ以外は左右なのでelseで分岐。
if (((BlockAWid + BlockBWid) / 2) - abs((BlockBXCenter + BlockBXSpeed) - BlockAXCenter) > ((BlockAHei + BlockBHei) / 2) - abs((BlockBYCenter + BlockBYSpeed) - BlockAYCenter))
{
//ここに上下の辺にあたっている時の処理を書く。
}
else
{
//ここに左右の辺にあたっている時の処理を書く。
}
}
}
}
-----------------------------------------------------------------------------------------
と、こんな感じのソースが出来上がりました。
今回、ブロック崩しを作成している過程でのソースなので、ブロック崩し専用のアルゴリズムになるのかな?
矩形が片方しか動いてなかったり、上下と左右の二つでしか場合分けしてないのがその証拠ですね(ブロック崩しは基本上下と左右は処理が同じ)。
あとこれ、矩形の動き方が斜め45度の時にしか上手く動いてくれないっぽいです。
ただ、角にも判定を作らなきゃいけないという場合には参考になるかと思います。
そしてちょっとだけソースの解説、いやソース内でも記述はしてあるけど。
まず、当たり判定には未来予測を使用しています。
次のフレームで当たる時に、現在のフレームの位置関係を調べてどの方向から当たるのかを調べているわけですね。
そして角付近に居る場合。接触したら角にぶつかったということになるのですが、角といってもちょっきり角に当たった場合と少し上にずれてるとかそういう場合があります。
それを調べるために、「接触している部分の形が正方形ならちょっきり角に当たったよー」という分岐を追加しているのですね、それ以外はずれているのでズレてる場合の処理。
そして角付近にいないということは辺の付近にいるということなのでelseを使用しているわけです。
ということで解説終了。
まぁ、ソースを見てもらって、使えそうならご自由に改変して使ってくださって問題ないです。
矩形同士の当たり判定にしか使えませんので、使う部分は限られてそうですが。