HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2016
0525
Dice-K(学生につき返信遅)マップの最短ルート検索・移動20解決


Dice-K(学生につき返信遅)

リンク

2016/5/25(Wed) 22:10:36|NO.75588

迷路内で敵キャラ(x1,y1)、自キャラ(x2,y2)とした時に最短で
敵キャラが自キャラに近づいてくるというアルゴリズムを作りたいのですが、思いつきません。
できれば、実際のスクリプトや紹介しているサイトなど教えていただけると、
私でも理解しやすく、非常に助かります。
ご協力お願いします。



この記事に返信する


さか

リンク

2016/5/25(Wed) 23:46:37|NO.75589

一番、簡単なのは自キャラ座標から敵キャラ座標を引いてマイナスなら敵キャラ座標を
マイナス、プラスなら敵キャラ座標をプラスですかね。
こんな感じですか。

x1=100 y1=10 x2=200 y2=200 *@ pos x1,y1:mes "●" pos x2,y2:mes "○" vx=0: vy=0 if x1-x2<0: vx=-3 if x1-x2>0: vx=3 if y1-y2<0: vy=-3 if y1-y2>0: vy=3 x2+=vx: y2+=vy wait 10 goto *@b



Dice-K(学生につき返信遅)

リンク

2016/5/26(Thu) 21:13:45|NO.75598

>さかさん
助言ありがとうございます。
しかし、それでは直線の移動になってしまうのでは?



zakki

リンク

2016/5/26(Thu) 21:38:46|NO.75601

一般的にはA*だったり幅優先だったりですが迷路の表現わからないと何とも言えないのでは



Dice-K(学生につき返信遅)

リンク

2016/5/26(Thu) 21:44:11|NO.75602

>zakkiさん
マップの描画は

map = "111111111111111111111" map += "100000000010000000001" map += "101110111010111011101" map += "101110111010111011101" map += "100000000000000000001" map += "101110101111101011101" map += "100000100010001000001" map += "111110111010111011111" map += "000010100000001010000" map += "111110102202201011111" map += "000000002000200000000" map += "111110102222201011111" map += "000010100000001010000" map += "111110101111101011111" map += "100000000010000000001" map += "101110111010111011101" map += "100010000000000010001" map += "111010101111101010111" map += "100000100010001000001" map += "101111111010111111101" map += "100000000000000000001" map += "111111111111111111111" i = 0 redraw 0 repeat 22 my = cnt repeat 21 maps = peek(map,i) if maps = '0' : dmap = 0 if maps = '1' : dmap = 1 if maps = '2' : dmap = 2 if game = 0{ if dmap = 1{ kabex(k) = i*32 kabey(k) = my*32 if kabex(k) > 640 : kabex(k) -= 672 k += 1 } if dmap = 2{ kabex(k) = i*32 kabey(k) = my*32 if kabex(k) > 640 : kabex(k) -= 672 k += 1 } game = -1 } pos cnt*32,my*32 gmode 2,32,32 gcopy 9,dmap*32,0 i += 1 await 1 loop await 1 loop redraw 1
としています。



さか

リンク

2016/5/26(Thu) 22:02:27|NO.75604

ああ、迷路を見過ごしてました。
でも、パックマンであれば最短ルートでモンスターは移動してませんよ。
例えば、パックマンが右上にいる場合でも、最初の中央の枠から出たとき必ず左に進み、
すぐ上の通路は行けないので左下に進み、遠回りして近づきます。
これは、むしろ最短で進まないために動きが読めなくて面白くなってます。

質問をいくつかしてますが、求めているものが、プログラムの書き方なのかアルゴリズムなのか
パックマンそのものを作りたいのか、似てるものを作りたいのかわからないです。



Dice-K(学生につき返信遅)

リンク

2016/5/26(Thu) 23:00:19|NO.75605

>さかさん
教えていただきたいのはアルゴリズム、作っているのはパックマン風のゲームです。

>>でも、パックマンであれば最短ルートでモンスターは移動してませんよ。
例えば、パックマンが右上にいる場合でも、最初の中央の枠から出たとき必ず左に進み、
すぐ上の通路は行けないので左下に進み、遠回りして近づきます。
これは、むしろ最短で進まないために動きが読めなくて面白くなってます。

おっしゃることは最もです。実際にプレイしたことがなかったため、見落としていました。
では、さかさんのご指摘通りに組むとした時のアルゴリズムに見当などございますか?



GENKI

リンク

2016/5/26(Thu) 23:00:55|NO.75606

> マップの描画は
サンプルスクリプトを載せるときは、コピペするだけで動くようにしておいていただけるといろいろと大変助かります。
そのまま動かないようだと十分に検証されたスクリプトで無いようにも見えてしまうので、なるべく動くようにお願いします。

いろいろと考えやすくなるんじゃないかと思い、ヒント的なスクリプト書いてみたのでどうぞ。
一連の質問とスクリプトを見たところ、マップデータが処理しにくい形式なのが問題のような気がしました。

; map用タイル screen 9 color 255,255,255 boxf 0,0,31,31 color 128,0,0 boxf 32,0,63,31 color 0,128,0 boxf 64,0,95,31 ; mapデータ map = "111111111111111111111" map += "100000000010000000001" map += "101110111010111011101" map += "101110111010111011101" map += "100000000000000000001" map += "101110101111101011101" map += "100000100010001000001" map += "111110111010111011111" map += "000010100000001010000" map += "111110102202201011111" map += "000000002000200000000" map += "111110102222201011111" map += "000010100000001010000" map += "111110101111101011111" map += "100000000010000000001" map += "101110111010111011101" map += "100010000000000010001" map += "111010101111101010111" map += "100000100010001000001" map += "101111111010111111101" map += "100000000000000000001" map += "111111111111111111111" ; mapを数値の配列変数に変換 dim mapdata, 22, 21 r = 0 : i = 0 repeat 22 c = 0 repeat 21 mapdata(r, c) = int(strmid(map, i, 1)) c++ i++ loop r++ loop ; mapから通路情報を作成 ; 0 : 非通路 ; 1 : 通路 ; 2を含む : 上が空いた通路 ; 4を含む : 下が空いた通路 ; 8を含む : 左が空いた通路 ; 16を含む : 右が空いた通路 dim maproad, 22, 21 r = 0 : i = 0 repeat 22 c = 0 repeat 21 maproad(r, c) = 0 ;非通路 if mapdata(r, c) = 0 { maproad(r, c) = 1 ;通路 ; 調査位置の上下左右 ur = r-1 : uc = c dr = r+1 : dc = c lr = r : lc = c-1 rr = r : rc = c+1 if ur>0 : if mapdata(ur, uc) = 0 : maproad(r, c) |= 2 if dr<22 : if mapdata(dr, dc) = 0 : maproad(r, c) |= 4 if lc>0 : if mapdata(lr, lc) = 0 : maproad(r, c) |= 8 if rc<21 : if mapdata(rr, rc) = 0 : maproad(r, c) |= 16 } c++ loop r++ loop ; 描画 screen 0,32*21,32*22 i = 0 redraw 0 repeat 22 my = cnt repeat 21 ; マップデータ dmap = mapdata(my, cnt) ; 謎の処理 if game = 0{ if dmap = 1{ kabex(k) = i*32 kabey(k) = my*32 if kabex(k) > 640 : kabex(k) -= 672 k += 1 } if dmap = 2{ kabex(k) = i*32 kabey(k) = my*32 if kabex(k) > 640 : kabex(k) -= 672 k += 1 } game = -1 } ; 1マス描画 pos cnt*32,my*32 gmode 2,32,32 gcopy 9,dmap*32,0 i += 1 await 1 loop await 1 loop redraw 1 ; 通路情報を可視化 screen 2 r = 0 : i = 0 repeat 22 c = 0 repeat 21 if maproad(r, c) = 0 : pos c*16, r*16 : mes "■" if maproad(r, c) & 2 : pos c*16, r*16 : mes "↑" if maproad(r, c) & 4 : pos c*16, r*16 : mes "↓" if maproad(r, c) & 8 : pos c*16, r*16 : mes "←" if maproad(r, c) & 16: pos c*16, r*16 : mes "→" c++ loop r++ loop

蛇足ですが、プログラミングするときは、コメントを入れる、読み込みと出力を分けるなど整理して見やすくする、などに注意した方がいいと思います。



Dice-K(学生につき返信遅)

リンク

2016/5/26(Thu) 23:08:53|NO.75608

>>サンプルスクリプトを載せるときは、コピペするだけで動くようにしておいていただけるといろいろと大変助かります

今度からは気をつけるようにします。お手数をお掛けしました。

>>いろいろと考えやすくなるんじゃないかと思い、ヒント的なスクリプト書いてみたのでどうぞ。
一連の質問とスクリプトを見たところ、マップデータが処理しにくい形式なのが問題のような気がしました。

マップデータそのものにも問題が…。全く考えていませんでした。書き換えてみようと思います。

>>蛇足ですが、プログラミングするときは、コメントを入れる、読み込みと出力を分けるなど整理して見やすくする、などに注意した方がいいと思います。

そうですね。これも今度から気をつけるようにします。
いつもありがとうございます。



暇人

リンク

2016/5/26(Thu) 23:20:58|NO.75609

>NO.75604
>遠回りして近づきます。
敵は色で縄張りが決まってて
パックマンを基準に動くか縄張りを守るかは時間で切り替わる



Dice-K(学生につき返信遅)

リンク

2016/5/27(Fri) 00:00:11|NO.75610

>暇人さん
それは無条件で敵が自分に向かってくるようなアルゴリズムが完成してから付け加えるオプションだと考えていますので、ここでは考えないことといたします。



Dice-K(学生につき返信遅)

リンク

2016/5/27(Fri) 00:11:43|NO.75611

>GENKIさん
|=

この演算子はどういったものなのでしょうか? 調べてはみたのですが、答えが見つかりませんでした。



Dice-K(学生につき返信遅)

リンク

2016/5/27(Fri) 00:18:21|NO.75612

>GENKIさん
連投すみません。

repeat 22 c = 0 repeat 21 maproad(r, c) = 0 ;非通路 if mapdata(r, c) = 0 { maproad(r, c) = 1 ;通路 ; 調査位置の上下左右 ur = r-1 : uc = c dr = r+1 : dc = c lr = r : lc = c-1 rr = r : rc = c+1 if ur>0 : if mapdata(ur, uc) = 0 : maproad(r, c) |= 2 if dr<22 : if mapdata(dr, dc) = 0 : maproad(r, c) |= 4 if lc>0 : if mapdata(lr, lc) = 0 : maproad(r, c) |= 8 if rc<21 : if mapdata(rr, rc) = 0 : maproad(r, c) |= 16 } c++ loop r++ loop
ここの処理は何をしているのでしょうか?
私では読み解けないのですが…。
簡単にでいいので解説をお願いできますか?
お手数をお掛けします。



Y_repeat(旧y.tack)

リンク

2016/5/27(Fri) 07:48:34|NO.75616

12歳からはじめるHSP3.0わくわくゲームプログラミング教室
大槻 有一郎 著
第六章 マップ型アクションゲームを作ろう
「なんでもイーター」
という章があります

HSP初心者の方にお勧めしている本です
AMAZONの方で購入できるので 購入してみては?



GENKI

リンク

2016/5/27(Fri) 22:07:24|NO.75622

> |=

プログラミング・マニュアルに載ってるだろうと思ってたんですが、ちゃんとは載ってませんね。

a |= b

a = a | b
の別の書き方です。同様に、
a = a + b

a += b
と書くことも出来ます。
「プログラミング・マニュアル」の「3.8.変数」の章に少しだけ説明があるので読んでみてください。

また、「|」は「or」、論理和を示す演算子なのですが、これは分かりますか?
…と聞いてはみたもののきっとまだ分かってない気がする。(´・ω・`)



GENKI

リンク

2016/5/27(Fri) 22:32:25|NO.75623

> ここの処理は何をしているのでしょうか?

後処理しにくいマップデータを後処理しやすいように変換しています。
具体的には「通路情報を可視化」のところで使用例を書いているので、ここの出力結果を見ながら考えていただけるとわかりやすいと思います。
ここで変換されたデータmaproadは、マップのマス目にいる場合にどの方向に進むことが出来るかをデータ化したものです。
サンプルの使用例では、その方向を矢印で示しています。

こういうデータを予め用意しておけば、隣のマスの壁の有無を調べなくても進める方向が簡単に分かりますし、敵が自機を探す処理も書きやすくなると思います。

スクリプトについて少し説明しておきます。
通路の上下左右の壁の有無をチェックして結果をmaproadに入れています。
通路のマスなら1
上に移動できるマスなら2
下に移動できるマスなら4
左に移動できるマスなら8
右に移動できるマスなら16
をmaproadに入れています。通路ではない場所の場合、maproadは0です。
情報を取り出すときは、サンプルにある通りアンドで取り出します。stick命令使う時と同じ要領ですね。



Dice-K(学生につき返信遅)

リンク

2016/5/28(Sat) 17:10:32|NO.75630

>GENKIさん
すみません。返信が遅くなりました。
丁寧な説明ありがとうございます。
a|=b

は「aはaとb2つの性質(要素)を保持している」ということでしょうか。



GENKI

リンク

2016/5/28(Sat) 19:04:45|NO.75631

やっぱりビット演算をまだ知らないようなので、今回はとりあえず使えるようになる程度の説明をしてみます。

「a|=b」つまり「a=a|b」は、
「aの中にbというフラグとして入れている」
というイメージで使用することができます。
aの中にフラグbが入っているかどうかを調べるには

a&b
と書きます。aにbが入っていた場合の式の結果はbになります。入っていなければ結果は0になります。
この辺はstick命令で取得した値の使い方と同じです。同じ仕組なので。

但しこれには約束があって、bに使用できる値が決まっています。
1,2,4,8,16,…,1073741824と後1つです。(後1つは今知ると混乱するので省略。)
この数字にはルールがあって、2の0乗、2の1乗、2の3乗…という感じで30乗までの31個が使用できます。(31乗は今知ると混乱するので省略。)
つまり1個の整数型変数に31個のフラグを入れることが出来るわけです。(32個目は今知ると…以下略)

またaの最初の値、何も入れる前の値、使用前の値は「0」である必要があります。フラグをリセットしたい場合は0を=で代入してやればいいわけです。


と、こういう感じで理解しておけば使うには十分です。私も昔はこのぐらいの理解で使ってました。
もっと厳密な説明の方がいいでしょうか。



Dice-K(学生につき返信遅)

リンク

2016/5/28(Sat) 19:12:02|NO.75632

>GENKIさん
いえ、大丈夫です。ありがとうございます。
もう一つ質問なのですが、フラグの数を調べることは可能ですか?
また、可能であれば、どうすればよいでしょうか?



GENKI

リンク

2016/5/29(Sun) 01:28:03|NO.75633

> もう一つ質問なのですが、フラグの数を調べることは可能ですか?

これは1個ずつ取り出してみて調べるしか方法はないんじゃないでしょうか。
フラグの取り出し方はサンプルでも書きましたし、説明もしたので自分で考えるには十分なヒントが出揃っていると思うのですが…。

ということで効率的な方法なのかなーと思って考えてみました。でも結局ループ回すしか無い気がします。

; 例えば3つフラグが立っている場合 a = 0 a|=1 a|=4 a|=16 ; 例1)わかりやすい例 c = 0 ;フラグの個数カウント b = 1 ;調べるフラグ repeat 32 if a&b : c = c + 1 ;見つかったら+1 b = b * 2 ;次のフラグへ loop mes c ; 例2)理解してる人向けの動作が高速なサンプル c = 0 repeat 32 c += a>>cnt&1 loop mes c



Dice-K(学生につき返信遅)

リンク

2016/5/29(Sun) 10:29:11|NO.75635

>GENKIさん
わかりました。ありがとうございます。

>>皆さん
たくさんの助言等ありがとうございました。方法が浮かんだので、やってみます。
本当にお世話になりました。



ONION software Copyright 1997-2021(c) All rights reserved.