スクロールの考え方

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
やっくん

スクロールの考え方

#1

投稿記事 by やっくん » 16年前

DXライブラリを用いRPG製作をております。
現在マップのスクロールについて悩んでいます。

ttp://www.play21.jp/board/formz.cgi?action=res&resno=11226&page=&lognum=35&id=dixq&rln=11335

上の過去ログを参考にしようと思ったのですが、

Justyさんの「カメラの概念」とあります。

「カメラの概念」がよくわからないのでこれについて質問させていただきます。

ここで例えなんですが、
当たり判定を考える次の変数を作ります。
(次が1であるとキャラが進めない)
int map01[4][6] = {{1,1,1,1,1,1},
                   {1,0,0,0,0,1},
                   {1,0,0,1,1,1},
                   {1,1,1,1,1,1},
                  }
画面に表示するマップは4×4までとします。

つまり、はじめはこんな状態。(◇がキャラが進める)
■■■■   //→表  ■■
■◇◇◇   //→示  ◇■
■◇◇■   //→な  ■■
■■■■   //→し  ■■

ここでキャラ(画像)自体の座標をずっと右に動かそうとすると画面外に出てしまい、
表示されなくなってしまいます。

したがって「カメラの概念」とは、
キャラ(画像)を動かさず、
画面に表示するマップ自体(&当たり判定)を表示する際に値を増減してずらしていくっていうことでしょうか?


わかり辛い説明ですみません^^;

ねこ

Re:スクロールの考え方

#2

投稿記事 by ねこ » 16年前

キャラを動かす、というのはその都度勝手が変わるんですが
キャラの位置からカメラの位置を計算するという感じですね。

昔のドラクエなんかだとキャラの位置はウィンドウの中心に居るでしょう?
キャラの位置が決まればそこから
キャラのX-2~キャラのX+2
キャラのY-2~キャラのY+2のような範囲のマップ情報を描画すれば画面がどんどんスクロールしていきます。
マップ内でのキャラの位置(X,Y)は変わっても表示するのは真ん中、って感じです。

分かりずらい解説ですいませんorz

Kou

Re:スクロールの考え方

#3

投稿記事 by Kou » 16年前

マップのスクロール自体は、表示するマップを実際の画面サイズより若干大きめに描画し、
画面に表示する位置をずらして行く事で出来るわけですが、キャラが常に中心に居るドラクエタイプと、
画面の一定以上端にキャラが来た場合にスクロールさせる場合があると思いますが、
ドラクエタイプなら、ねこさんが言われたみたいにキャラ位置は中心固定で、移動している方向に対して
マップをスクロール(マップのx、y座標の増減)で済みますが、トピ主さんのはおそらく後者ですよね?
その場合、キャラが画面内で移動できる座標範囲を決めて、その座標で更に移動キーが押されていれば、
キャラ位置はそのままで、マップのみをスクロールさせる事で出来ると思います。
おそらくキャラが消えるのは、移動可能範囲を設定していないためでしょう。

ただしこの方法の場合、移動可能範囲は画面ギリギリにするのではなく、2~3キャラ分内側に設定しないと、
画面に表示されていない移動不可能な場所が表示されず、なぜ移動できないのかプレーヤーが分からない事が
あるので、気を付けてください。

キャラの移動自体出来るのであれば、マップスクロールはそれほど難しい処理ではないので、後は組み合わせるだけです。

長文失礼しました。頑張ってください。

Justy

Re:スクロールの考え方

#4

投稿記事 by Justy » 16年前


>キャラ(画像)を動かさず、
>画面に表示するマップ自体(&当たり判定)を表示する際に値を増減してずらしていくっていうことでしょうか?

 キャラが動かなくて済むかどうかは別として、マップの表示の際に位置をずらすという点においては
結果的にはそういうことになります。


 あのスレで言っているカメラの概念は、現実世界のカメラと同じ考え方です。

 走ってる車の横を同スピードで併走してカメラを向ければ、そのカメラの映像は
背景は流れていても車は止まっています。

 でも実際には背景は動かないけど車は動いているわけで、カメラが車と一緒になって
動くことで動かないはずの背景が動き、動いているはずの車が止まって見えるわけです。

 これと同じことを背景はマップに車はキャラクタに置き換えてコード上で実現したのが
添付したソースだったのですが。
 まぁ、もう消えてますね(必要なら探して再アップしますが)。

 この原理を使えば、表示の時だけ一工夫必要なだけで、あたり判定を含めた内部処理は
通常通りの処理で問題ないですし、イベントなどで画面を揺らしたい場や
主人公以外のところを画面の中心に持ってきたい場合等にも使えます。

 とはいえ、ゲームに内容によってはこんな大層なものは必要なく、
先の方々がおっしゃっているような手法で十分かもしれません。

やっくん

Re:スクロールの考え方

#5

投稿記事 by やっくん » 16年前

自分の説明がわかりにくいものなのに、
皆様回答してくださってありがとうございます><

>ねこさん
とりあえず、自分なりにねこさんの方法で試してみます。

>Kouさん
自分はドラクエタイプの物を作ろうと思ってますね。
説明不足ですみません。
ですが、自分が考えている物にはKouさんがおっしゃるようなタイプのものも必要となりますので参考になります(^^)

>Justyさん
ありがとうございます。なんとなくですが理解できましたが完璧ではありません。
もしよろしければ過去に添付したソースの再アップをお願いしたいです。

-----------------------------

とりあえず試行錯誤して結果をもう一度書かせてもらうことにします。

やっくん

Re:スクロールの考え方

#6

投稿記事 by やっくん » 16年前

とりあえず、ドラクエ風も目標にしているのでねこさんの方法を考えようとしました。

以下の処理の前処理(前提)として、
・キャラをマップの中心に固定させた場合。(スクロール無しverは上手く作れています。)
・map01関数は画面に表示されるより大きめに取った当たり判定の関数です。
・map01[/url]はマップチップのハンドルです
・x,yはキャラ画像の位置情報?です。(初期設定でx=288,y=224)
・マップ一マスを32×32としてます。(よって画面は20×15分割)
・上下左右キーを1回押すとxとyの座標が32増減するようにしています。
・当たり判定は別に行っています。

ごちゃごちゃですみません^^;

見て欲しいのは以下の部分なのですが、
ねこさんの言ったように次の処理でキャラを中心にマップを描こうとしたつもりですが、
うまくいきません。(ちゃんと表示されず、表示の仕方が変)
これ以外にも試行錯誤をずっとやっているのですが中々上手く行かない状況です。

/*壁を描画*/
int i,j;
for(i=0;i<15;i++){
	for(j=0;j<20;j++){
         //↓↓ここでねこさんの言ってることをやったつもりです
		if(map01[y/32-7+i][x/32-9+j]==1){
		          DrawGraph((x/32-9+j)*32,(y/32-7+i)*32, map01[1], TRUE);
		}
		else if(map01[j]==0){
			 DrawGraph((x/32-9+j),(y/32-7+i)*32, map01[0], TRUE);
		}
	}
}

DrawGraph( 288 , 224 , image , TRUE ) ;//自キャラ画像を描画(中心固定)

[pre]

全てソースを載せるとごちゃごちゃになってるため見づらいかと思い、
診断して欲しい部分を載せています。
もしこれだけでは判断できないならば他の部分も載せますので言ってください。

>Justyさんへ
カメラの概念を使うときはキャラ移動(画像の位置x,yの増減)とカメラ移動を同時に行わなければうまくいきませんか?

ねこ

Re:スクロールの考え方

#7

投稿記事 by ねこ » 16年前

DragGraph関数のx,y値が変な気がします。
外枠足りない気がしますが、とりあえずイメージに近い描画をするにはDrawGraphの引数のx/32-9とy/32-7が不要ですね。
DrawGraph( j * 32, i * 32, map01[1], TRUE);

後Preタグの2個目は半角スラッシュが足りません「/Pre」

Justy

Re:スクロールの考え方

#8

投稿記事 by Justy » 16年前

 当時のコードを見つけて、ちょっとだけ改良してアップしました。
 
 実行には
 ttp://dixq.net/g/img/char.png
 こちらのキャラクタデータが必要になります。

 実行したら上下左右でキャラが歩きますが(LSHIFT併用で高速移動)、
標準の状態ではカメラがプレイヤーの位置と同じになるよう設定
されています(自動追尾モード)ので、常に画面中央にキャラクタが
表示されるようになっています。

 Zボタンを押すと自動追尾モードが解除されマニュアルモードになります。
 AWDXの各ボタンでカメラを操作できます。
 この状態で Qを押すと再び自動追尾モードになります。

 一部空白に触れるとマップが切り替わりますが、元からそういう仕様です。

 画面上のデバッグ表示を見るとわかりますが、ch.posの位置と cameraの位置が
一致するとキャラクタは中央に表示されます。


 本格的なカメラになると、回転や拡大縮小にも対応することになりますが、
そこまではこのサンプルではやっていません。

やっくん

Re:スクロールの考え方

#9

投稿記事 by やっくん » 16年前

>ねこさん
ありがとうございます。
何とかキャラ中心とした移動をできるようになりました。
これから「キャラが一定以上端に着たらキャラ中心からキャラ自体を移動させる」などに発展させていこうと思います。

>Justyさん
添付ありがとうございます。
とりあえず形はできたのですが、
カクカク画面が動いていたので比較させていただきました。
カメラの概念が何となくしか理解できていなかったけれど、これで理解できたと思います。
他の人が作ったソースと自分のを比べると「ここまで全然違うのか」って驚きました。
Justyさんのソース綺麗でしたので見やすいですし・・・。
とても参考になりました(^^)

やっくん

Re:スクロールの考え方

#10

投稿記事 by やっくん » 16年前

解決を押しておきながらログを上に上げるのは申し訳ないのですが、
Justyさんの添付ソースを何回も見ています。
今の自分には書けるようなものではありませんでした。
ソースを見て疑問に思ったことがあるのでよければ答えてもらえないでしょうか?

constを使う理由とは何でしょうか。
「変数の中身を変えれないようにしミスを防止する」
ってくらいの知識しかもっておらず、
だけど何でこんなに多く使っているのだろうと疑問に思いました。
多くて1000~2000行のコードしか書いたことなく、
そのときでさえ一回も自分はconst使わなかったので気になります。

ねこ

Re:スクロールの考え方

#11

投稿記事 by ねこ » 16年前

constは「定数」として変更不可の定義を行うとともに
「共通値」として大きな変更を行う際の修正の簡易性を上げる事が出来ます。

例えば今回のやっくんさんのソースで「共通値」を挙げるなら
・1マスの横幅 32
・1マスの高さ 32
・表示する横マス数 20
・表示する縦マス数 15
等があります。

これらをあらかじめ「定数」として使用してコードを記述しておくと
マスのサイズを24x24に変えよう、というような修正をする際この定数の値を24に変えるだけで
直接「32」と書いていた箇所が全て24になるため、修正漏れ等が無くなりますし手間も一瞬です。
またマスの数も「640/1マスの横幅」等で代入していると、関係する項目がある程度連動してくれます。
※勿論変更に伴って必要最低限の修正はあるでしょうが。

このようにあらかじめ同じ値を何度も書いたりする場合、定数としておくと後からの変更が容易になります。

というのが僕の知っている大きな利点です。

他にもswitch文で「0,1,2」とcaseを書くよりは
const int MODE_TITLE = 0;
const int MODE_MENU = 1;
const int MODE_MAIN = 2;
として変数名だけで大体意味が分かるようにしておけば
「1って何だっけ?」というような確認の手間を省けたりしますね。

他にもビットフラグを定義する時・・・ってキリがないのでこんなところでw

Justy

Re:スクロールの考え方

#12

投稿記事 by Justy » 16年前


>constを使う理由とは何でしょうか

 主な理由としては途中で変更されるもの、されないものを明確に区別する、
というのがありますが、どこについている constなのか、で少し意味合いが
変わってきます。


1) 関数の外の const
 変数ではなく定数にしたかった為

2) 関数の外の配列についている const
 変更されたくない・する必要がない、ということと、
データを ROM領域に配置されることを期待して。

3) 関数の引数の const
 データを変更されたくない・する必要がない、ということと、
変数がポインタの場合関数の入出力の方向を明確にする為

 といったところでしょうか。


 2)の ROM領域に関してはこちらを。

Cプログラミング専門課程/第4章メモリ/const修飾子
ttp://www.pro.or.jp/~fuji/mybooks/cpro/cpro.4.6.1.html

 Windosとかだとあまり大きな意味は持たないかもしれませんが、
ROMと RAMが明確に分かれている環境だと大きな違いになることがあります。

やっくん

Re:スクロールの考え方

#13

投稿記事 by やっくん » 16年前

単純に簡易性をあげるための共通値として意味を持たせる場合はconstを付けなくてもかまわなくはないですか??

標準関数ではprintfなどに「変更不可」にしたい部分にconstが使われてたりするようですが、
これは外部から手を加えられないようにってことなのかな。

ねこ

Re:スクロールの考え方

#14

投稿記事 by ねこ » 16年前

<単純に簡易性をあげるための共通値として意味を持たせる場合はconstを付けなくてもかまわなくはないですか??
構いません。ただ直値の置き換えはconstを付けるのが普通ってだけです。
ただわざわざ付けないという事は「差し替えられる危険性を残す」というデメリットしか残らないと考えます。

やっくん

Re:スクロールの考え方

#15

投稿記事 by やっくん » 16年前

なるほど。
納得できました!!
ありがとうございます。

やっくん

Re:スクロールの考え方

#16

投稿記事 by やっくん » 16年前

Justyさん、constについてわざわざ答えてくださっていただいたのにお礼を言わず、すみませんでした。
コメントしていただいてたことに気づいていませんでした;;
ところで、Justyさんの添付したファイルを見ているとまた気になった点がありました。
bool型なのですが、これはCには無い型ですよね?
当たり前のように使われていたので他のCのソースで使おうとしたところ使えなくて、
調べてみたところC++で実装されているものらしいですね。
そこで使い方の質問なのですが、
typedef struct{
  int a,b,c;
  bool tf;
}TF;

TF TF1 = {1,2,3,true};

if(TF1) //処理;
Justyさんの添付ファイルを見てみるとこのような使い方をしている部分がありました。
ifの中身に構造体を渡しているような感じ(?)なのですがこれは「構造体の中のbool値が真なら処理を行う」といったものでしょうか。
それと、C言語はこのように構造体をif文に受け渡すことはできるのでしょうか?

Justy

Re:スクロールの考え方

#17

投稿記事 by Justy » 16年前


>bool型なのですが、これはCには無い型ですよね?

 無いですね。C99には似たような型がありますが、それとは別物ですし。
 一応このコードは C++コンパイラでることを想定して書かれています。



>てみるとこのような使い方をしている部分がありました

 あれ? どこでしょう?
 見直してみましたが、そういうところは見つかりませんでしたが。
 
 ひょっとして、それは構造体のポインタではないですか?



>C言語はこのように構造体をif文に受け渡すことはできるのでしょうか?

 Cでは構造体を直接 ifで評価することはできません。

やっくん

Re:スクロールの考え方

#18

投稿記事 by やっくん » 16年前

>あれ? どこでしょう?
static void CameraUpdate(camera_t *camera, const KeyBufferType key, const ch_t *ch)
{
    if(!camera) return;
    //略
}
この部分です。

この部分のif(!camera)がよくわかりませんでした。
自分の中では勝手に「構造体の中のbool値がfalseならばreturn」と解釈しましたが正しいでしょうか?

Justy

Re:スクロールの考え方

#19

投稿記事 by Justy » 16年前


>この部分です

 この camera変数は camera_t *[/font] であり、camera_t型のポインタです。
 なので、if文はポインタ値に対する評価を行います。

 この場合はポインタが NULLかどうかのチェックであり、メンバの評価はしていません。

やっくん

Re:スクロールの考え方

#20

投稿記事 by やっくん » 16年前

そのような意味だったのですか(^^;
全く勘違いしていたようです。
ありがとうございました。

閉鎖

“C言語何でも質問掲示板” へ戻る