画面の大きさを調整する

 後でフルスクリーンモードを使うことを考えて画面の大きさを640×480にしていますが、これって幅が広すぎると思いませんか? 普通縦スクロールシューティングの画面は縦長ですね。それと、敵が上端にパッと現れて、下端に達するとパッと消えますが、キャラクタの下部から徐々に現れ、消える時も徐々に消えた方がいいですね。そこで、画面の大きさは640×480のまま、真ん中の320×448の領域をゲーム画面にしたいと思います。
 指定した座標がゲーム画面の外側で、キャラクタの一部分だけ画面内にある場合は、画面に現れている部分だけ描画するようにします。

  敵の一部分

 1.画面の大きさを指定する
 2.描画位置が完全に画面の外側である場合、描かない
 3.一部分だけ画面内にある場合、コピー元の指定領域を調節する
 4.描画する

 1.画面の大きさを指定する

「プログラム起動時の初期設定」で、ゲーム画面の幅、高さを変数xsize,ysizeに代入します。
    xsize=320
    ysize=448
 以降のプログラムではxsize、ysizeを参照します。あちこちに、320、448と書くと、後で変えたくなった時に面倒くさいですね。こうしておけば、この部分を書き換えるだけで済みます。

 2.描画位置が完全に画面の外側である場合、描かない

 指定位置に指定した絵を描く処理をサブルーチンにします。呼び出し側(メインルーチン)で、座標を変数gdx,gdyに代入します。ファイル中の、コピー元の座標をgdox,gdoyに代入します。キャラクタの幅をgdw、高さをgdhに代入します。(gdはgraphic draw、oはoriginal、wはwidth、hはheightの略です。)そしてこのサブルーチンを呼ぶと、絵が描かれるようにします。
 座標は、ゲーム画面に対するものです。つまり、320×448の矩形領域の、左上端が(0,0)、右下の端が(319,447)です。
 描画位置が完全に画面の外側である場合、何もしないという処理はこうなります。
    if (gdx+gdw<=0)|(gdx>=xsize)|(gdy+gdh<=0)|(gdy>=ysize) { return }
  画面の外
 図中の"="は代入の意味ではありません。
 図とif文が結びつかない人は、"gdx+gdw-1<0"と"gdx+gdw<=0"は同じである点に注意して下さい。

 3.一部分だけ画面内にある場合、コピー元の指定領域を調節する

 キャラクタが左側にはみ出している場合、例えば、指定したx座標が−5の時、左側の幅5ドットの部分を除いた領域をコピーして、x座標が0の位置に貼り付けます。つまり、コピー元の画像のx座標はgdox+(-gdx)です。幅はgdw-(-gdx)です。
 右側にはみ出している場合、描画する座標はそのままです。コピー元の画像の幅はxsize-gdxとなります。キャラクタの右端のx座標はgdx+gdw-1、画面の右端のx座標はxsize-1ですから右側にはみ出している条件は"gdx+gdw-1>xsize-1"、つまり"gdx+gdw>xsize"です。   コピー領域

    if gdx<0 {
        gdox=gdox-gdx
        gdw=gdw+gdx
        gdx=0
    }
    else {
        if gdx+gdw>xsize { gdw=xsize-gdx }
    }
 "else"は、「もし条件が成り立っていなかったら」です。
  if 条件式 {
    処理1
  }
  else {
    処理2
  }
 で、「もし条件が成り立っていたら処理1を、成り立っていなければ処理2を実行せよ」という意味です。
 y座標についても同じ考え方です。
 上の場合、完全に画面内におさまっていたら、何もいじりません。

 4.描画する

 ddposで指定する位置は、(gdx,gdy)ではありません。ゲーム画面の左余白、上余白を考慮しなければなりません。
  余白

    ddpos (640-xsize)/2+gdx,(480-ysize)/2+gdy
    ddsetrect gdox,gdoy,gdw,gdh
    ddgcopy 1


 以上をふまえて、サブルーチンは以下のようになります。

	; 指定した絵を描画
*Graphic_Draw
	; 描画するキャラクタが端の方にあり、一部分だけ描画する場合も
	; 表示できるようにするサブルーチン
	;
	; gdx,gdy	: 描画する座標
	; gdox,gdoy	: グラフィックのコピー元座標
	; gdw		: 幅
	; gdh		: 高さ

	if (gdx+gdw<=0)|(gdx>=xsize)|(gdy+gdh<=0)|(gdy>=ysize) { return }
	if gdx<0 {
		gdox=gdox-gdx
		gdw=gdw+gdx
		gdx=0
	}
	else {
		if gdx+gdw>xsize { gdw=xsize-gdx }
	}

	if gdy<0 {
		gdoy=gdoy-gdy
		gdh=gdh+gdy
		gdy=0
	}
	else {
		if gdy+gdh>ysize { gdh=ysize-gdy }
	}

	ddpos (640-xsize)/2+gdx,(480-ysize)/2+gdy
	ddsetrect gdox,gdoy,gdw,gdh
	ddgcopy 1
	return

 例えば、自機を描画する、メインルーチン側の記述はこうなります。
    gdx=playerx:gdy=playery
    gdox=0:gdoy=0
    gdw=32:gdh=32
    if (rkey=1)&(lkey=0) { gdox=32 }
    if (lkey=1)&(rkey=0) { gdox=64 }
    gosub *Graphic_Draw
 敵が徐々に現れるようにするためには、出現時のy座標を0から−32に変更するだけでよいのです。またy座標が448に達したら消すようにしていたのも、ysizeに達したら、に変えます。

[プログラム全体と絵をダウンロード]
※今回の改造が影響する箇所はすべて修正してあります。

ひとくちメモ:
・saveについて
 プログラムのsave(保存)は、実行する前に行った方がいいと思います。HSPの場合大抵は大丈夫だと思いますが、実行して、万が一強制終了(Ctrl+Alt+Del)によっても止められず、リセットするしかないようなバグが起こってしまった場合、saveしていなかったら悲惨ですね。昔、プログラミングはアセンブリ言語で行うのが一般的だった時代、saveもせずに実行するのは無謀以外の何物でもなかったみたいです。
 
・実行する前に読み直すべきか?
 プログラムを書いたら、即実行したいと思うのが人情です。しかし、実行する前に読み直すようにすると、バグが残る可能性がぐんと減ります。もちろん、実行させてみればすぐ見つかるようなバグの方が多いです。書いて即実行すると、バグが起こって、原因がありそうな部分だけ読み直し、修正してまた実行させてみる、というスタイルになるかと思います。この場合、ある特定の条件でしか起こらない、めったに起こらないバグが残る可能性があります。
 

[目次へ][前へ][次へ] inserted by FC2 system