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


HSPTV!掲示板


未解決 解決 停止 削除要請

2016
0304
Sado2Dゲームの描画処理の考え方が分からない (ものすごく幼稚で初歩的な話)27解決


Sado

リンク

2016/3/4(Fri) 15:22:38|NO.74768

HSPに関係があるかどうか怪しい質問なのですが、
自分が他に扱える言語が無かったのでひとまずここで質問することにしました。
質問というよりは意見の募集、のような感じですね。
(ということは雑談スレになるのか?これは。)



■本題
皆さんなら、2Dゲームにおいて、オブジェクトの管理・描画処理はどのように作りますか?
敵・味方・設置物・エフェクト・地形・背景(層有り)・弾丸など
全てのモノが関連して描画順を自由に変えられるようにしたいのですが、
何が何だか全く分からない状態なので、皆さんの意見を参考にさせて頂けませんか?



■※
オブジェクト:
本来の意味(?)ではなく、キャラクターとか何かそれっぽいものをひっくるめて
自分はオブジェクトと呼んでいます。
描画処理+補足:
自分はes_excopyを主軸に使っています。
(gmode+gcopy+gzoom+grotateみたいなヤツ)
知識量:
IT系の知識は皆無、
数学は一応辛うじてギリギリ何とか、高2までの内容を理解でき……ます(たぶん)。



■以下長い
現在自分は、STGゲームを作るのに様々な配列変数を用意しています。

scrl(背景用)
bgobj(背景演出用)
bgobjani~(アニメーション用の諸変数)
bgobjlayer(bgobj内の描画順)
obj(主に当たり判定を持つキャラクターや地形・設置物)
objani~
objlayer
blt(弾丸用)
ptcl(エフェクト用)など

このような感じで管理していたのですが、
背景スクロールとオブジェクトなどが完全に別々で処理・動作・描写していて
描画順を変えることが出来ないのです。
オブジェクト同士の描画順もソートの処理が重そうで怖いので、
事前に振り分けておいた描画順を、
repeat10:if objlayer()=cnt{描画}:loopして描画順を作ってる状況です。

ひょっとしなくても、
全てobj~みたいな配列変数で管理して、描画時にzソートのような何かを利用して
描画するのが一般的なんだろうなぁと思ったのです。

でも、全て一括管理するとなると、
描画処理とその他各処理をどうやって分けたら良いかよく分からなくなってしまって。
それに、
layer(とかz-index)は何を単位に振り分けたらいいのかすら分からない……
レイヤー10枚くらい用意するか。
それとも、z座標を計算に取り込んで、表示倍率と描画順を一括管理しちゃうか。
z座標なら、距離感(表示倍率・描画順)が簡単に把握できて便利そう。
――そしたらソートはどうなるんだ??

いずれにしろ、
今考えている方法で一括管理するとなると
(僕の場合は)敵味方設置物100個位+弾丸64個位+演出用32個位+エフェクト用+32個位の
配列をソートして描画することになる。
バブルソートしかやり方が分からない僕には、絶望的すぎる。
色々分からないor混乱している事だらけで、どう手を付けていいか分からなくなっています。



この記事に返信する


SOU1

リンク

2016/3/5(Sat) 01:28:12|NO.74780

質問している内容が多岐に渡る為どこから手をつければ良いのかが難しい問題ですが……
とりあえず気になった点だけでも羅列しておきますね

・昨今のゲームプログラミング事情的には2Dゲームであっても3D描画を使うのが一般的かと思います
 HSPにおいてもHGIMG3やHGIMG4などを検討してみても悪くないかと思います
 これは処理速度の面においても断然有利ですが、
 画面更新という考え方から「描画オブジェクト」という考え方に変わる事で
 オブジェクトの多いゲームにおいて全体をスッキリさせやすくなったりします

・配列変数含め変数名の命名ルールを適当に持っておいたほうが良さそうです
 例:objBG objBlt flgBGAni など
 このまま突き進むといつかスパゲティ化が激化し自分でも難読になりますので
 「変数の命名ルールを作る」か「変数の説明をコメントに書いておく」
 などの対応は今のうちしておいたほうが楽になりますよ

・ここまで出来ている方なら断然クイックソートを前向きに検討すべきです
 「なんで速いの」を無視すれば実装は結構簡単です だもんでググれば幾つも出ry
 実装時に「配列変数の中身は入れ替えず結果の位置だけ取得出来るようにする」事で
 「ソートのキーにする配列変数に対しクイックソート」->
 「他の配列変数は結果の位置を見ながら参照」とする事でソート回数は1回に出来ますよ
 また「ソートはあくまでZ-Index関連でしか使わない」のであれば
 「Z-Indexに関わる全てのオブジェクトを同一の配列変数に保持し、
 それらの種別などの配列変数を持つ」などといった運用をオススメします

……あ、ここまで書いておいて何ですがZ-Indexの管理運用はクソ面倒だと思うので
やはり何らかの3D描画を利用した上で
「0.001」とか分からないくらいZ軸をズラすという姑息な手段をオススメしておきます……w
HGIMG3だとオブジェクト登録順になったような??これでも楽ですね



科学太郎

リンク

2016/3/6(Sun) 19:49:05|NO.74800

> ひょっとしなくても、
> 全てobj~みたいな配列変数で管理して、描画時にzソートのような何かを利用して
> 描画するのが一般的なんだろうなぁと思ったのです。
モジュール型変数を使えばよいと思います。

//------------------------------------------------------------------------------ // モジュール型変数によるシューティング・ゲーム //============================================================================== // 新規作成日:2013-06-10 (月) 18:28:00 // 最終更新日:2013-06-10 (月) 22:58:00 // 最終更新日:2013-06-11 (火) 03:48:00 // 最終更新日:2013-06-11 (火) 04:36:00 //------------------------------------------------------------------------------ #packopt name __FILE__ //-------------------------------------- // HSP命令/関数の記号定数 //-------------------------------------- #const global STICK_LEFT ($0001) #const global STICK_UP ($0002) #const global STICK_RIGHT ($0004) #const global STICK_DOWN ($0008) #const global STICK_SPACE ($0010) #const global STICK_ENTER ($0020) #const global STICK_CTRL ($0040) #const global STICK_ESC ($0080) #const global STICK_LMOUSE ($0100) #const global STICK_RMOUSE ($0200) #const global STICK_TAB ($0400) #const global STICK_SCAN (STICK_UP|STICK_DOWN|STICK_LEFT|STICK_RIGHT) //-------------------------------------- // ゲーム全体の記号定数 //-------------------------------------- #const global MAX_LEFT (10) ;自機の最大残り数 #const global MAX_BOMB (10) ;自機の最大ボム数 #const global MAX_OPTION (3) ;自機のオプション数 #const global MAX_ITEMTABLE (10) ;敵機のアイテム発生テーブル # #const global MAX_FIGHT (MAX_OPTION+1) #const global MAX_ENEMY (100) #const global MAX_SHOT (50) #const global MAX_BEAM (50) #const global MAX_ITEM (50) #const global MAX_STAR (100) #const global MAX_BLAST (100) #const global MAX_TELOP (5) //-------------------------------------- // モジュールの記号定数 //-------------------------------------- #const global FPS (60) #const global FIGHT_XSIZE (32/2) #const global FIGHT_YSIZE (32/2) #const global FIGHT_SPEED (5) #const global FIGHT_DELAY (12) #const global FIGHT_COURSE (FIGHT_DELAY*MAX_OPTION+1) # #const global ENEMY_XSIZE (32/2) #const global ENEMY_YSIZE (32/2) #const global ENEMY_SPEED (2) #const global ENEMY_BIRTH (FPS/3) #const global ENEMY_SCORE (10) # #const global BLAST_XSIZE (32/2) #const global BLAST_YSIZE (32/2) #const global BLAST_ANIME (12) #const global BLAST_BLINK (4) #const global BLAST_COUNT (FPS/BLAST_ANIME) # #const global SHOT_XSIZE (6/2) #const global SHOT_YSIZE (6/2) #const global SHOT_SPEED (10) # #const global BEAM_XSIZE (4/2) #const global BEAM_YSIZE (32/2) #const global BEAM_SPEED (5) # #const global ITEM_XSIZE (32/2) #const global ITEM_YSIZE (32/2) #const global ITEM_SPEED (1) # #const global STAR_BIRTH (FPS/60) //-------------------------------------- // ゲーム画面の記号定数 //-------------------------------------- #const global DISP_WIDTH (640) #const global DISP_HEIGHT (480) # #const global DEATH_MARGIN (50) #const global DEATH_LEFT (-DEATH_MARGIN) #const global DEATH_TOP (-DEATH_MARGIN) #const global DEATH_RIGHT (DISP_WIDTH+DEATH_MARGIN) #const global DEATH_BOTTOM (DISP_HEIGHT+DEATH_MARGIN) # #const global FIGHT_LEFT (FIGHT_XSIZE) #const global FIGHT_RIGHT (DISP_WIDTH-FIGHT_XSIZE-1) #const global FIGHT_TOP (FIGHT_YSIZE) #const global FIGHT_BOTTOM (DISP_HEIGHT-FIGHT_YSIZE-1) //-------------------------------------- // テロップの記号定数 //-------------------------------------- #const global FONT_SIZE (20) #const global HALF_SIZE (FONT_SIZE/2) # #const global ALIVE_SIZE (HALF_SIZE*12) #const global FLUSH_SIZE (HALF_SIZE*7) #const global SCORE_SIZE (HALF_SIZE*14) #const global HISCORE_SIZE (HALF_SIZE*16) # #const global ALIVE_CX (DISP_WIDTH-ALIVE_SIZE)/2 #const global ALIVE_CY (0) #const global FIGHT_CX (HALF_SIZE*2) #const global FIGHT_CY (DISP_HEIGHT-FONT_SIZE) #const global FLUSH_CX (DISP_WIDTH-HALF_SIZE*3-FLUSH_SIZE) #const global FLUSH_CY (DISP_HEIGHT-FONT_SIZE) #const global SCORE_CX (HALF_SIZE*2) #const global SCORE_CY (0) #const global HISCORE_CX (DISP_WIDTH-HALF_SIZE*3-HISCORE_SIZE) #const global HISCORE_CY (0) //-------------------------------------- // 自機タイプの列挙定数 //-------------------------------------- #enum global FIGHT_NORMAL=0 #enum global FIGHT_OPTION //-------------------------------------- // 爆風タイプの列挙定数 //-------------------------------------- #enum global BLAST_NULL=0 #enum global BLAST_FIGHT #enum global BLAST_ITEM //-------------------------------------- // 流星カラーの列挙定数 //-------------------------------------- #enum global COLOR_BLACK=0 #enum global COLOR_RED #enum global COLOR_GREEN #enum global COLOR_YELLOW #enum global COLOR_BLUE #enum global COLOR_PURPLE #enum global COLOR_CYAN #enum global COLOR_WHITE //-------------------------------------- // アイテムの列挙定数 //-------------------------------------- #enum global ITEMS_NULL=0 #enum global ITEMS_LEFT #enum global ITEMS_BOMB #enum global ITEMS_FLUSH #enum global ITEMS_SCORE #enum global ITEMS_OPTION //-------------------------------------- // テロップの列挙定数 //-------------------------------------- #enum global TELOP_FIGHT=0 #enum global TELOP_FLUSH #enum global TELOP_SCORE #enum global TELOP_HISCORE #enum global TELOP_ALIVE //-------------------------------------- // テロップの更新定数 //-------------------------------------- #const global REDRAW_FIGHT (1<<TELOP_FIGHT) #const global REDRAW_FLUSH (1<<TELOP_FLUSH) #const global REDRAW_SCORE (1<<TELOP_SCORE) #const global REDRAW_HISCORE (1<<TELOP_HISCORE) #const global REDRAW_ALIVE (1<<TELOP_ALIVE) //--[自機クラス]---------------------------------------------------------------- #module FightClass m_cx,m_cy,m_type //-------------------------------------- // 自機の発生 //-------------------------------------- #modinit int _cx_,int _cy_,int _type_ m_cx=_cx_ m_cy=_cy_ m_type=_type_ return //-------------------------------------- // 自機の移動 //-------------------------------------- #modfunc FightMove int _key_ if(_key_ & STICK_LEFT) :m_cx-=FIGHT_SPEED:if(m_cx<FIGHT_LEFT) :m_cx=FIGHT_LEFT if(_key_ & STICK_RIGHT) :m_cx+=FIGHT_SPEED:if(m_cx>FIGHT_RIGHT) :m_cx=FIGHT_RIGHT if(_key_ & STICK_UP) :m_cy-=FIGHT_SPEED:if(m_cy<FIGHT_TOP) :m_cy=FIGHT_TOP if(_key_ & STICK_DOWN) :m_cy+=FIGHT_SPEED:if(m_cy>FIGHT_BOTTOM) :m_cy=FIGHT_BOTTOM return //-------------------------------------- // 自機の描画 //-------------------------------------- #modfunc FightDraw switch m_type case FIGHT_NORMAL color $00,$FF,$00:boxf (m_cx-FIGHT_XSIZE),(m_cy-FIGHT_YSIZE),(m_cx+FIGHT_XSIZE),(m_cy+FIGHT_YSIZE) swbreak case FIGHT_OPTION color $FF,$CC,$00:circle (m_cx-FIGHT_XSIZE),(m_cy-FIGHT_YSIZE),(m_cx+FIGHT_XSIZE),(m_cy+FIGHT_YSIZE),1 color $CC,$99,$00:circle (m_cx-FIGHT_XSIZE),(m_cy-FIGHT_YSIZE),(m_cx+FIGHT_XSIZE),(m_cy+FIGHT_YSIZE),0 swbreak swend return //-------------------------------------- // 自機の現在位置を設定 //-------------------------------------- #modfunc FightSetCurs int _cx_,int _cy_ m_cx=_cx_ m_cy=_cy_ return //-------------------------------------- // 自機の現在位置を取得 //-------------------------------------- #modfunc FightGetCurs var _cx_,var _cy_ _cx_=m_cx _cy_=m_cy return //-------------------------------------- // 自機の矩形領域を取得 //-------------------------------------- #modfunc FightGetRect var _cx_,var _cy_,var _ex_,var _ey_ _cx_=(m_cx-FIGHT_XSIZE) _cy_=(m_cy-FIGHT_YSIZE) _ex_=(m_cx+FIGHT_XSIZE) _ey_=(m_cy+FIGHT_YSIZE) return //-------------------------------------- // 自機の破壊 //-------------------------------------- #modfunc FightCrash var _cx_,var _cy_,var _type_ _cx_=m_cx _cy_=m_cy _type_=m_type delmod thismod return #global //--[敵機クラス]---------------------------------------------------------------- #module EnemyClass m_cx,m_cy,m_beam,m_item //-------------------------------------- // 敵機の発生 //-------------------------------------- #modinit int _cx_,int _cy_,int _item_ m_cx=_cx_ m_cy=_cy_ m_beam=rnd(50)+10 ;ビームの発射間隔 m_item=_item_ return //-------------------------------------- // 敵機の移動 //-------------------------------------- #modfunc EnemyMove m_cy+=ENEMY_SPEED if(m_cy>=DEATH_BOTTOM):delmod thismod return //-------------------------------------- // 敵機の描画 //-------------------------------------- #modfunc EnemyDraw if(m_item):color $FF,$00,$FF:else:color $00,$FF,$FF boxf (m_cx-ENEMY_XSIZE),(m_cy-ENEMY_YSIZE),(m_cx+ENEMY_XSIZE),(m_cy+ENEMY_YSIZE) return //-------------------------------------- // 敵機のビーム発射 //-------------------------------------- #modfunc EnemyShot var _cx_,var _cy_ _cx_=m_cx _cy_=m_cy m_beam-- return (m_beam==0) //-------------------------------------- // 敵機の矩形領域を取得 //-------------------------------------- #modfunc EnemyGetRect var _cx_,var _cy_,var _ex_,var _ey_ _cx_=(m_cx-ENEMY_XSIZE) _cy_=(m_cy-ENEMY_YSIZE) _ex_=(m_cx+ENEMY_XSIZE) _ey_=(m_cy+ENEMY_YSIZE) return //-------------------------------------- // 敵機の当たり判定 //-------------------------------------- #modfunc EnemyCheck int _cx_,int _cy_,int _ex_,int _ey_ n=0 repeat 1 if(_ex_<=(m_cx-ENEMY_XSIZE)):break if(_ey_<=(m_cy-ENEMY_YSIZE)):break if(_cx_>=(m_cx+ENEMY_XSIZE)):break if(_cy_>=(m_cy+ENEMY_YSIZE)):break n=1 loop return n //-------------------------------------- // 敵機の破壊 //-------------------------------------- #modfunc EnemyCrash var _cx_,var _cy_,var _item_ _cx_=m_cx _cy_=m_cy _item_=m_item delmod thismod return ENEMY_SCORE #global //--[自機弾クラス]-------------------------------------------------------------- #module ShotClass m_cx,m_cy //-------------------------------------- // 自機弾の発生 //-------------------------------------- #modinit int _cx_,int _cy_ m_cx=_cx_ m_cy=_cy_ return //-------------------------------------- // 自機弾の移動 //-------------------------------------- #modfunc ShotMove m_cy-=SHOT_SPEED if(m_cy<DEATH_TOP):delmod thismod return //-------------------------------------- // 自機弾の描画 //-------------------------------------- #modfunc ShotDraw color $FF,$FF,$00 circle (m_cx-SHOT_XSIZE),(m_cy-SHOT_YSIZE),(m_cx+SHOT_XSIZE),(m_cy+SHOT_YSIZE) return //-------------------------------------- // 自機弾の当たり判定 //-------------------------------------- #modfunc ShotCheck int _cx_,int _cy_,int _ex_,int _ey_ n=0 repeat 1 if(_ex_<=(m_cx-SHOT_XSIZE)):break if(_ey_<=(m_cy-SHOT_YSIZE)):break if(_cx_>=(m_cx+SHOT_XSIZE)):break if(_cy_>=(m_cy+SHOT_YSIZE)):break delmod thismod n=1 loop return n #global //--[敵機弾クラス]-------------------------------------------------------------- #module BeamClass m_cx,m_cy //-------------------------------------- // 敵機弾の発生 //-------------------------------------- #modinit int _cx_,int _cy_ m_cx=_cx_ m_cy=_cy_ return //-------------------------------------- // 敵機弾の移動 //-------------------------------------- #modfunc BeamMove m_cy+=BEAM_SPEED if(m_cy>=DEATH_BOTTOM):delmod thismod return //-------------------------------------- // 敵機弾の描画 //-------------------------------------- #modfunc BeamDraw color $FF,$FF,$00 boxf (m_cx-BEAM_XSIZE),(m_cy-BEAM_YSIZE),(m_cx+BEAM_XSIZE),(m_cy+BEAM_YSIZE) return //-------------------------------------- // 敵機弾の当たり判定 //-------------------------------------- #modfunc BeamCheck int _cx_,int _cy_,int _ex_,int _ey_ n=0 repeat 1 if(_ex_<=(m_cx-BEAM_XSIZE)):break if(_ey_<=(m_cy-BEAM_YSIZE)):break if(_cx_>=(m_cx+BEAM_XSIZE)):break if(_cy_>=(m_cy+BEAM_YSIZE)):break delmod thismod n=1 loop return n //-------------------------------------- // 敵機弾の破壊 //-------------------------------------- #modfunc BeamCrash var _cx_,var _cy_ _cx_=m_cx _cy_=m_cy delmod thismod return #global //--[アイテム・クラス]---------------------------------------------------------- #module ItemClass m_cx,m_cy,m_item //-------------------------------------- // アイテムの発生 //-------------------------------------- #modinit int _cx_,int _cy_,int _item_ m_cx=_cx_ m_cy=_cy_ m_item=_item_ return //-------------------------------------- // アイテムの移動 //-------------------------------------- #modfunc ItemMove m_cy+=ITEM_SPEED if(m_cy>DEATH_BOTTOM):delmod thismod return //-------------------------------------- // アイテムの描画 //-------------------------------------- #modfunc ItemDraw switch m_item case ITEMS_LEFT: r=$FF:g=$FF:b=$FF:s="UP":swbreak case ITEMS_BOMB: r=$FF:g=$FF:b=$00:s="B":swbreak case ITEMS_FLUSH: r=$FF:g=$FF:b=$00:s="*":swbreak case ITEMS_SCORE: r=$FF:g=$FF:b=$FF:s="S":swbreak case ITEMS_OPTION: r=$FF:g=$CC:b=$00:s="O":swbreak default: r=$00:g=$00:b=$00:s=" ":swbreak swend color r,g,b:boxf (m_cx-ITEM_XSIZE),(m_cy-ITEM_YSIZE),(m_cx+ITEM_XSIZE),(m_cy+ITEM_YSIZE) r=r*60/100 g=g*60/100 b=b*60/100 color r,g,b:pos (m_cx-ITEM_XSIZE),(m_cy-ITEM_YSIZE):mes s return //-------------------------------------- // アイテムの当たり判定 //-------------------------------------- #modfunc ItemCheck int _cx_,int _cy_,int _ex_,int _ey_ n=0 repeat 1 if(_ex_<=(m_cx-ITEM_XSIZE)):break if(_ey_<=(m_cy-ITEM_YSIZE)):break if(_cx_>=(m_cx+ITEM_XSIZE)):break if(_cy_>=(m_cy+ITEM_YSIZE)):break n=1 loop return n //-------------------------------------- // アイテムの消滅 //-------------------------------------- #modfunc ItemCrash var _cx_,var _cy_,var _item_ _cx_=m_cx _cy_=m_cy _item_=m_item delmod thismod return 0 #global //--[流星クラス]---------------------------------------------------------------- #module StarClass m_cx,m_cy,m_color,m_speed //-------------------------------------- // 流星の発生 //-------------------------------------- #modinit m_cx=rnd(DISP_WIDTH) m_cy=0 m_color=rnd(COLOR_WHITE)+1 m_speed=rnd(5)+2 return //-------------------------------------- // 流星の移動 //-------------------------------------- #modfunc StarMove m_cy+=m_speed if(m_cy>=DEATH_BOTTOM):delmod thismod return //-------------------------------------- // 流星の描画 //-------------------------------------- #modfunc StarDraw switch m_color case COLOR_BLACK: color $00,$00,$00:swbreak case COLOR_RED: color $FF,$00,$00:swbreak case COLOR_GREEN: color $00,$FF,$00:swbreak case COLOR_YELLOW: color $FF,$FF,$00:swbreak case COLOR_BLUE: color $00,$00,$FF:swbreak case COLOR_PURPLE: color $FF,$00,$FF:swbreak case COLOR_CYAN: color $00,$FF,$FF:swbreak case COLOR_WHITE: color $FF,$FF,$FF:swbreak swend pset m_cx,m_cy return #global //--[爆風クラス]---------------------------------------------------------------- #module BlastClass m_cx,m_cy,m_count,m_anime,m_type,m_data //-------------------------------------- // 爆風の発生 //-------------------------------------- #modinit int _cx_,int _cy_,int _type_,int _data_ m_cx=_cx_ m_cy=_cy_ m_count=BLAST_COUNT m_anime=BLAST_ANIME m_type=_type_ m_data=_data_ return //-------------------------------------- // 爆風のアニメ //-------------------------------------- #modfunc BlastMove var _cx_,var _cy_,var _data_ m_count-- if(m_count==0){ m_count=BLAST_COUNT m_anime-- } if(m_anime==0){ _cx_=m_cx _cy_=m_cy _data_=m_data n=m_type delmod thismod return n } return 0 //-------------------------------------- // 爆風の描画 //-------------------------------------- #modfunc BlastDraw cx=(m_cx-BLAST_XSIZE) cy=(m_cy-BLAST_YSIZE) ex=(m_cx+BLAST_XSIZE) ey=(m_cy+BLAST_YSIZE) n=(BLAST_ANIME-m_anime)*2 cx+=n cy+=n ex-=n-1 ey-=n-1 r=$FF:g=$66:b=$33 repeat n r=r*90/100 g=g*90/100 b=b*90/100 loop color r,g,b circle cx,cy,ex,ey return #global //--[テロップ・クラス]---------------------------------------------------------- #module TelopClass m_cx,m_cy,m_color,m_msg //-------------------------------------- // テロップの発生 //-------------------------------------- #modinit int _cx_,int _cy_,int _color_,str _msg_ m_cx=_cx_ m_cy=_cy_ m_color=_color_ m_msg=_msg_ return //-------------------------------------- // テロップの描画 //-------------------------------------- #modfunc TelopDraw n=$33 repeat 3 if(m_color & $01):r=n:else:r=$00 if(m_color & $02):g=n:else:g=$00 if(m_color & $04):b=n:else:b=$00 color r,g,b pos (m_cx+2-cnt),(m_cy+2-cnt) mes m_msg n+=$66 loop return //-------------------------------------- // テロップの文字列を設定 //-------------------------------------- #modfunc TelopSetMsg str _msg_ m_msg=_msg_ return #global //--[メイン部]------------------------------------------------------------------ //-------------------------------------- // グローバル変数 //-------------------------------------- #define Score gValue(0) #define HiScore gValue(1) #define FightLeft gValue(2) #define FightBomb gValue(3) #define FightAlive gValue(4) #define FightOption gValue(5) #define TelopRedraw gValue(6) #define StarBirthCycle gValue(7) #define EnemyBirthCycle gValue(8) # #define key gValue(9) #define n gValue(10) #define x gValue(11) #define y gValue(12) #define cx gValue(13) #define cy gValue(14) #define ex gValue(15) #define ey gValue(16) dim gValue,17 //-------------------------------------- // メイン部 //-------------------------------------- *Init ; dim Score ; dim HiScore ; dim FightLeft ; dim FightBomb ; dim FightAlive ; dim FightOption ; dim TelopRedraw ; dim StarBirthCycle ; dim EnemyBirthCycle dim FightCourseX,FIGHT_COURSE dim FightCourseY,FIGHT_COURSE dim EnemyItemTable,MAX_ITEMTABLE *Main randomize title "モジュール型変数によるシューティング・ゲーム" screen 0,DISP_WIDTH,DISP_HEIGHT font MSGOTHIC,FONT_SIZE,1 gosub *ShootingInit repeat redraw 0 stick key,STICK_SCAN gosub *ShootingMove gosub *ShootingDraw redraw 1 await (1000/FPS) loop stop //-------------------------------------- // シューティングの初期化 //-------------------------------------- *ShootingInit dimtype Fight, vartype("struct"),MAX_FIGHT dimtype Enemy, vartype("struct"),MAX_ENEMY dimtype Shot, vartype("struct"),MAX_SHOT dimtype Beam, vartype("struct"),MAX_BEAM dimtype Item, vartype("struct"),MAX_ITEM dimtype Star, vartype("struct"),MAX_STAR dimtype Blast, vartype("struct"),MAX_BLAST dimtype Telop, vartype("struct"),MAX_TELOP gosub *FightInit gosub *EnemyInit gosub *TelopInit return //-------------------------------------- // シューティングの移動 //-------------------------------------- *ShootingMove gosub *FightMoveAll gosub *EnemyMoveAll gosub *ShotMoveAll gosub *BeamMoveAll gosub *ItemMoveAll gosub *StarMoveAll gosub *BlastMoveAll gosub *CrashMainAll return //-------------------------------------- // シューティングの描画 //-------------------------------------- *ShootingDraw color $00,$00,$00:boxf gosub *StarDrawAll gosub *ShotDrawAll gosub *BeamDrawAll gosub *ItemDrawAll gosub *EnemyDrawAll gosub *FightDrawAll gosub *BlastDrawAll gosub *TelopDrawAll return //-------------------------------------- // 全体の当たり判定 //-------------------------------------- *CrashMainAll if(varuse(Fight(0))){ FightGetRect Fight(0),cx,cy,ex,ey // 自機⇒敵機,敵機弾 if(EnemyCheckAll(cx,cy,ex,ey)||BeamCheckAll(cx,cy,ex,ey)){ if(FightAlive==0){ gosub *FightCrashAll } } // 自機⇒アイテム if(ItemCheckAll(cx,cy,ex,ey)){ /* アイテムの衝突音 */ } } // 敵機⇒自機弾 foreach Enemy EnemyGetRect Enemy(cnt),cx,cy,ex,ey if(ShotCheckAll(cx,cy,ex,ey)){ gosub *EnemyDeath } loop return //--[自機管理]------------------------------------------------------------------ //-------------------------------------- // 自機全体の初期化 //-------------------------------------- *FightInit x=(DISP_WIDTH/2) y=(DISP_HEIGHT-FIGHT_YSIZE-16) FightBirth x,y FightLeft=3 FightBomb=5 FightAlive=0 return //-------------------------------------- // 自機全体の移動 //-------------------------------------- *FightMoveAll if(varuse(Fight(0))){ // 無敵モード if(key & STICK_TAB){ FightAlive^=1 TelopRedraw|=REDRAW_ALIVE } // デバッグ・モード if(key & STICK_ESC){ } // 弾丸の発射 if(key & STICK_SPACE){ foreach Fight FightGetCurs Fight(cnt),x,y newmod Shot,ShotClass,x,y loop } // ボムの発射 if(key & STICK_ENTER){ if(FightBomb){ gosub *EnemyFlush gosub *BeamFlush FightBomb-- TelopRedraw|=REDRAW_FLUSH } } // 自機の移動 if(key & STICK_SCAN){ // 軌道シフト repeat FIGHT_COURSE-1 n=(FIGHT_COURSE-1-cnt) FightCourseX(n)=FightCourseX(n-1) FightCourseY(n)=FightCourseY(n-1) loop // 移動 FightMove Fight(0),key FightGetCurs Fight(0),x,y FightCourseX(0)=x FightCourseY(0)=y // 設定 foreach Fight x=FightCourseX(FIGHT_DELAY*cnt) y=FightCourseY(FIGHT_DELAY*cnt) FightSetCurs Fight(cnt),x,y loop } } return //-------------------------------------- // 自機全体の描画 //-------------------------------------- *FightDrawAll foreach Fight FightDraw Fight(cnt) loop return //-------------------------------------- // 自機全体の破壊 //-------------------------------------- *FightCrashAll foreach Fight FightCrash Fight(cnt),x,y,n if(n){ newmod Blast,BlastClass,x,y,BLAST_NULL,0 ;オプションの破壊 } else{ newmod Blast,BlastClass,x,y,BLAST_FIGHT,0 ;自機の破壊 } loop return //-------------------------------------- // 自機全体の誕生 //-------------------------------------- #deffunc FightBirth int _x_,int _y_ // 軌道シフト repeat FIGHT_COURSE FightCourseX(cnt)=_x_ FightCourseY(cnt)=_y_ loop // 誕生 newmod Fight,FightClass,_x_,_y_,FIGHT_NORMAL ; newmod Fight,FightClass,_x_,_y_,FIGHT_OPTION ; newmod Fight,FightClass,_x_,_y_,FIGHT_OPTION ; newmod Fight,FightClass,_x_,_y_,FIGHT_OPTION FightOption=0 return //-------------------------------------- // 自機全体の消滅 //-------------------------------------- #deffunc FightDeath int _cx_,int _cy_ if(FightLeft==0){ dialog "ゲームオーバーです。",1,"確認" end } FightLeft-- FightBirth _cx_,_cy_ TelopRedraw|=REDRAW_FIGHT return //--[敵機管理]------------------------------------------------------------------ //-------------------------------------- // 敵機全体の初期化 //-------------------------------------- *EnemyInit n=-1 n++:EnemyItemTable(n)=ITEMS_LEFT ;20% n++:EnemyItemTable(n)=ITEMS_LEFT n++:EnemyItemTable(n)=ITEMS_BOMB ;20% n++:EnemyItemTable(n)=ITEMS_BOMB n++:EnemyItemTable(n)=ITEMS_FLUSH ;20% n++:EnemyItemTable(n)=ITEMS_FLUSH n++:EnemyItemTable(n)=ITEMS_SCORE ;40% n++:EnemyItemTable(n)=ITEMS_SCORE n++:EnemyItemTable(n)=ITEMS_OPTION ;20% n++:EnemyItemTable(n)=ITEMS_OPTION return //-------------------------------------- // 敵機全体の移動 //-------------------------------------- *EnemyMoveAll // 誕生 EnemyBirthCycle++ if(EnemyBirthCycle>=ENEMY_BIRTH){ x=rnd(DISP_WIDTH-ENEMY_XSIZE*2)+ENEMY_XSIZE y=-ENEMY_YSIZE n=0 if(rnd(100)<10){ n=EnemyItemTable(rnd(MAX_ITEMTABLE)) ;10%確率 } newmod Enemy,EnemyClass,x,y,n EnemyBirthCycle=0 } // 移動 foreach Enemy EnemyShot Enemy(cnt),x,y if(stat):newmod Beam,BeamClass,x,y EnemyMove Enemy(cnt) loop return //-------------------------------------- // 敵機全体の描画 //-------------------------------------- *EnemyDrawAll foreach Enemy EnemyDraw Enemy(cnt) loop return //-------------------------------------- // 敵機全体の当たり判定 //-------------------------------------- #defcfunc EnemyCheckAll int _cx_,int _cy_,int _ex_,int _ey_ n=0 foreach Enemy EnemyCheck Enemy(cnt),_cx_,_cy_,_ex_,_ey_ if(stat){ gosub *EnemyDeath n=1 break } loop return n //-------------------------------------- // 敵機全体の一掃 //-------------------------------------- *EnemyFlush foreach Enemy gosub *EnemyDeath loop return //-------------------------------------- // 敵機一体の破壊 //-------------------------------------- *EnemyDeath EnemyCrash Enemy(cnt),x,y,n TelopScore stat if(n){ newmod Blast,BlastClass,x,y,BLAST_ITEM,n } else{ newmod Blast,BlastClass,x,y,BLAST_NULL,0 } return //--[自機弾管理]---------------------------------------------------------------- //-------------------------------------- // 自機弾全体の移動 //-------------------------------------- *ShotMoveAll foreach Shot ShotMove Shot(cnt) loop return //-------------------------------------- // 自機弾全体の描画 //-------------------------------------- *ShotDrawAll foreach Shot ShotDraw Shot(cnt) loop return //-------------------------------------- // 自機弾全体の当たり判定 //-------------------------------------- #defcfunc ShotCheckAll int _cx_,int _cy_,int _ex_,int _ey_ n=0 foreach Shot ShotCheck Shot(cnt),_cx_,_cy_,_ex_,_ey_ if(stat){ n=1 break } loop return n //--[敵機弾管理]---------------------------------------------------------------- //-------------------------------------- // 敵機弾全体の移動 //-------------------------------------- *BeamMoveAll foreach Beam BeamMove Beam(cnt) loop return //-------------------------------------- // 敵機弾全体の描画 //-------------------------------------- *BeamDrawAll foreach Beam BeamDraw Beam(cnt) loop return //-------------------------------------- // 敵機弾全体の当たり判定 //-------------------------------------- #defcfunc BeamCheckAll int _cx_,int _cy_,int _ex_,int _ey_ n=0 foreach Beam BeamCheck Beam(cnt),_cx_,_cy_,_ex_,_ey_ if(stat){ n=1 break } loop return n //-------------------------------------- // 敵機弾全体の一掃 //-------------------------------------- *BeamFlush foreach Beam BeamCrash Beam(cnt),x,y newmod Blast,BlastClass,x,y,BLAST_NULL,0 loop return //--[アイテム管理]-------------------------------------------------------------- //-------------------------------------- // アイテム全体の移動 //-------------------------------------- *ItemMoveAll foreach Item ItemMove Item(cnt) loop return //-------------------------------------- // アイテム全体の描画 //-------------------------------------- *ItemDrawAll font MSGOTHIC,ITEM_YSIZE*2,1 foreach Item ItemDraw Item(cnt) loop font MSGOTHIC,FONT_SIZE,1 return //-------------------------------------- // アイテム全体の当たり判定 //-------------------------------------- #defcfunc ItemCheckAll int _cx_,int _cy_,int _ex_,int _ey_ n=0 foreach Item ItemCheck Item(cnt),_cx_,_cy_,_ex_,_ey_ if(stat){ gosub *ItemDeath n=1 break } loop return n //-------------------------------------- // アイテム一体の破壊 //-------------------------------------- *ItemDeath ItemCrash Item(cnt),x,y,n TelopScore stat switch n case ITEMS_LEFT if(FightLeft<MAX_LEFT){ FightLeft++ TelopRedraw|=REDRAW_FIGHT } swbreak case ITEMS_BOMB if(FightBomb<MAX_BOMB){ FightBomb++ TelopRedraw|=REDRAW_FLUSH } swbreak case ITEMS_FLUSH gosub *EnemyFlush gosub *BeamFlush swbreak case ITEMS_SCORE TelopScore 1000 swbreak case ITEMS_OPTION if(FightOption<MAX_OPTION){ FightOption++ x=FightCourseX(FIGHT_DELAY*FightOption) y=FightCourseY(FIGHT_DELAY*FightOption) newmod Fight,FightClass,x,y,FIGHT_OPTION } swbreak default:swbreak swend return //--[流星管理]------------------------------------------------------------------ //-------------------------------------- // 流星全体の移動 //-------------------------------------- *StarMoveAll // 誕生 StarBirthCycle++ if(StarBirthCycle>=STAR_BIRTH){ newmod Star,StarClass StarBirthCycle=0 } // 移動 foreach Star StarMove Star(cnt) loop return //-------------------------------------- // 流星全体の描画 //-------------------------------------- *StarDrawAll foreach Star StarDraw Star(cnt) loop return //--[爆風管理]------------------------------------------------------------------ //-------------------------------------- // 爆風全体の移動 //-------------------------------------- *BlastMoveAll foreach Blast BlastMove Blast(cnt),x,y,n switch stat case BLAST_FIGHT: FightDeath x,y :swbreak case BLAST_ITEM: newmod Item,ItemClass,x,y,n :swbreak default: :swbreak swend loop return //-------------------------------------- // 爆風全体の描画 //-------------------------------------- *BlastDrawAll foreach Blast BlastDraw Blast(cnt) loop return //--[テロップ]------------------------------------------------------------------ //-------------------------------------- // テロップ全体の初期化 //-------------------------------------- *TelopInit newmod Telop,TelopClass, FIGHT_CX, FIGHT_CY,COLOR_GREEN,"" newmod Telop,TelopClass, FLUSH_CX, FLUSH_CY,COLOR_GREEN,"" newmod Telop,TelopClass, SCORE_CX, SCORE_CY,COLOR_YELLOW,"" newmod Telop,TelopClass,HISCORE_CX,HISCORE_CY,COLOR_YELLOW,"" TelopRedraw=(REDRAW_FIGHT|REDRAW_FLUSH|REDRAW_SCORE|REDRAW_HISCORE) return //-------------------------------------- // テロップ全体の描画 //-------------------------------------- *TelopDrawAll if(TelopRedraw){ if(TelopRedraw & REDRAW_FIGHT) :TelopSetMsg Telop(TELOP_FIGHT),strf("Left:%02d",FightLeft) if(TelopRedraw & REDRAW_FLUSH) :TelopSetMsg Telop(TELOP_FLUSH),strf("Bomb:%02d",FightBomb) if(TelopRedraw & REDRAW_SCORE) :TelopSetMsg Telop(TELOP_SCORE),strf("Score:%08d",Score) if(TelopRedraw & REDRAW_HISCORE) :TelopSetMsg Telop(TELOP_HISCORE),strf("HiScore:%08d",HiScore) if(TelopRedraw & REDRAW_ALIVE){ if(FightAlive){ newmod Telop,TelopClass,ALIVE_CX,ALIVE_CY,COLOR_WHITE,"[無敵モード]" } else{ delmod Telop(TELOP_ALIVE) } } TelopRedraw=$0000 } foreach Telop TelopDraw Telop(cnt) loop return //-------------------------------------- // テロップ点数の加算 //-------------------------------------- #deffunc TelopScore int _score_ Score+=_score_ if(Score>HiScore){ HiScore=Score } TelopRedraw|=REDRAW_SCORE TelopRedraw|=REDRAW_HISCORE return //------------------------------------------------------------------------------ // End of sample43.hsp //------------------------------------------------------------------------------
上記のサンプルの次の3つを参考にどうぞ。

*ShootingMove *ShootingDraw *CrashMainAll



Sado

リンク

2016/3/9(Wed) 21:38:17|NO.74842

返信が遅れました。
申し訳ありません。

>SOU1さん
Z-indexに関わるものを特に同じ配列で管理→クイックソートですね、
現状、自分にはこれが一番適しているように思えます!
ありがとうございます。
(クイックソートの仕組み、理解できればいいなぁ)
「描画オブジェクト」は、自分には新しくてよく分からない考え方で混乱しています。


>科学太郎さん
とても参考になります!
サンプルの要素が多くてやけに凝っていますね……グラディウス的な何かかと。
モジュール型の利用法を初めて理解できたような気がします!
全く使ったことのないプログラムの形で戸惑いが大きいですが、
とても便利そうで、これはちゃんと利用できるように要練習ですね。

今の僕では、モジュール型の変数とグローバルの変数・配列変数が混同しがちで
すぐには使える自信がありません……(ツライ)



科学太郎

リンク

2016/3/9(Wed) 22:50:34|NO.74844

> サンプルの要素が多くてやけに凝っていますね……グラディウス的な何かかと。
HSPの学習を兼ねて懐かしいシューティング・ゲームをサンプルで作ってみました。

> モジュール型の利用法を初めて理解できたような気がします!
C++のクラスの概念がモジュール型変数なのでC++の書籍を参考にどうぞ。

> 全く使ったことのないプログラムの形で戸惑いが大きいですが、
オブジェクト指向の真似をしてるのが

#modinit #modterm #modfunc #modcfunc newmod delmod thismod
上記の命令、関数ですね。

> 今の僕では、モジュール型の変数とグローバルの変数・配列変数が混同しがちで
> すぐには使える自信がありません……(ツライ)
分かる気がします。
私はC/C++言語の出身でしたので難しく感じませんでした。

#module modStarClass m_x, m_y,m_c1 #deffunc StarInit c1R=$00,$FF,$00,$FF,$00,$FF,$00,$FF c1G=$00,$00,$FF,$FF,$00,$00,$FF,$FF c1B=$00,$00,$00,$00,$FF,$FF,$FF,$FF return #modinit int _x_,int _y_,int _c1_ m_x=_x_ m_y=_y_ m_c1=_c1_ return #modfunc StarMove m_y++ if(m_y>=ginfo_winY):delmod thismod:return 0 return 1 #modfunc StarDraw color c1R(m_c1),c1G(m_c1),c1B(m_c1) circle(m_x-2),(m_y-2),(m_x+3),(m_y+3),1 return #global ;モジュール型変数の作成 randomize repeat 100 newmod 配列,modStarClass,rnd(640),rnd(480),rnd(8) loop ;メイン StarInit repeat redraw 0 color $CC,$CC,$CC:boxf foreach 配列 StarMove 配列(cnt) if(stat):StarDraw 配列(cnt) loop redraw 1 await(1000/60) loop stop
上記のモジュール型変数は次のようなメモリ構造になります。

┌────────modStarClass────────┐ │┌─配列(0) ─┐      ┌─#deffunc─┐│ ││m_x m_y m_c1│←共通参照→│c1R(8)   ││ │└──────┘      │c1G(8)   │←StarInit命令 │┌─配列(1) ─┐      │c1B(8)   ││ ││m_x m_y m_c1│←共通参照→│      ││ │└──────┘      │      ││ │┌─配列(2) ─┐      │      ││ ││m_x m_y m_c1│←共通参照→│      ││ │└──────┘      │      ││ │   :          │      ││ │┌─配列(n) ─┐      │      ││ ││m_x m_y m_c1│←共通参照→│      ││ │└──────┘      └──────┘│ └──────────────────────┘
#deffunc命令、#defcfunc関数は modStarClass 全体で共通な変数・配列となり、
#modfunc命令、#modcfunc関数は 配列要素1つ1つのメンバ変数となります。
分かりますかね?



Sado

リンク

2016/3/10(Thu) 20:49:50|NO.74851

>科学太郎さん
モジュール変数のサンプル、丁寧な解説、ありがとうございます!
とてもわかり易いです。

module内でモジュール変数の内容・処理を定義、
newmod/dimtypeでモジュール変数or配列変数を作成、
不要になればdelmod。
モジュール変数とモジュール型変数の違いにもようやく気がつけました……。




疑問に思ったのですが、
newmodは変数の初期化処理ですが、ループ処理中に初期化を置いても重くはならないのでしょうか?
また、length(配列)を確認したところ、delmod後も要素数は変わらないようですが
delmodで何が行われているのでしょうか?
現状、delmodの意味が理解できず、newmodを使うと配列が増えるばかりなので、
modfunc等で未使用のモジュール変数を検出・初期化(初期値代入)するしか手がないように思えます。



Sado

リンク

2016/3/10(Thu) 21:02:49|NO.74852


#modfunc StarDispCheck if(m_y>=ginfo_winY):return 0 return 1
で不使用となった変数を検出できるのではと思ったのですが、
恐らくdelmodのタイミングでエラー。
要素の削除は行われているようですし、モジュール型はlengthでは正しく取得できないのでしょうか。

また、思い切ってループ中にnewmodを置いてみたところ、
一定数以上(270くらい)には増えないことが分かりました。
コレは一体どういうことなのか、全く見当がつきません……。



科学太郎

リンク

2016/3/11(Fri) 23:05:31|NO.74877

> 疑問に思ったのですが、
> newmodは変数の初期化処理ですが、ループ処理中に初期化を置いても重くはならないのでしょうか?
どこのループですか?
あと newmod は変数の初期化処理ではなく変数の実態を作成します。
この実態の変数を作成するときに初期化が可能ですよ。という感じです。

> また、length(配列)を確認したところ、delmod後も要素数は変わらないようですが
> delmodで何が行われているのでしょうか?
newmod で10個の実態変数を作成すると配列の要素は10個です。
しかし、delmod で3個削除しても実態変数の要素数には変化はありません。
つまり、delmod で削除した部分が未使用領域になるだけです。
なお、この状態で newmod で実態変数を作成すると最初の未使用領域に新しい実態データが作成されます。

> 現状、delmodの意味が理解できず、newmodを使うと配列が増えるばかりなので、
はい。
増え続けると思います。

> modfunc等で未使用のモジュール変数を検出・初期化(初期値代入)するしか手がないように思えます。
newmod で新しく実態の変数を作成すると未使用領域から順番に新しい実態データがセットされますが…。

> で不使用となった変数を検出できるのではと思ったのですが、
> 恐らくdelmodのタイミングでエラー。
全ソースを載せてくれないと良く分かりませんね。

> 要素の削除は行われているようですし、モジュール型はlengthでは正しく取得できないのでしょうか。
そうですね。
newmod を10回実行して delmod を3回実行すると配列データは7個です。
しかし、内部では未使用領域が3個になってるので length では10個が返されます。

max=0 foreach 配列 max++ loop
上記のように配列の実態要素数をカウントすることは可能です。
しかし、このような使い方はモジュール型変数の便利さを損ないます。

> また、思い切ってループ中にnewmodを置いてみたところ、
どこのループかな。

> 一定数以上(270くらい)には増えないことが分かりました。
もしも、メイン・ループならば newmod、delmod を両方実行してるので
配列要素が270個に固定されたことになります。

> コレは一体どういうことなのか、全く見当がつきません……。
これは delmod で削除しても未使用領域にセットされるだけで要素数が減らないからです。
また、delmod で未使用領域があると次の newmod で最初の未使用領域が実態のある要素データになります。
分かるだろうか?



Sado

リンク

2016/3/11(Fri) 23:35:56|NO.74878

なるほど!
newmodは、実態のない変数(未使用領域)がなければ、変数を初期化する
delmodは、実態のない変数へ置き換える("変数"を削除する訳ではない)
lengthは、実態の有無に関わらず要素数をそのまま帰す
foreachやvaruse()は、実態の有無を確認できる
ということだったのですね。

しかも、僕は「delmodが変数を丸ごと消し去るもの」だと勘違いしていたと……



科学太郎

リンク

2016/3/11(Fri) 23:41:07|NO.74879

> newmodは、実態のない変数(未使用領域)がなければ、変数を初期化する
正確には未使用領域が無ければ実態変数(要素数)を1つ追加します。
(追加と共に初期化もするが…)

> delmodは、実態のない変数へ置き換える("変数"を削除する訳ではない)
デバッグ画面で確認できると思います。
未使用領域を意味する表示がされてるはずです。

> lengthは、実態の有無に関わらず要素数をそのまま帰す
はい。

> foreachやvaruse()は、実態の有無を確認できる
> ということだったのですね。
はい。

> しかも、僕は「delmodが変数を丸ごと消し去るもの」だと勘違いしていたと……
名前からするとそうですね。
でも、モジュール型変数は特別な動作をするようです。
特に foreach が要素数ではなく実態のある要素数しか繰り返しませんので。



Sado

リンク

2016/3/12(Sat) 00:23:15|NO.74882

newmodとdelmod、モジュール変数の状態が、やっと、理解できました!
スッキリした……



>> 全く使ったことのないプログラムの形で戸惑いが大きいですが、
>オブジェクト指向の真似をしてるのが...
HSPとプチコンBASICを少し触れる程度の知識しか無いのでよく分からなかったのですが、
ひょっとして、
モジュール変数を定義するもの(module,modinit,modfunc,modcfuncなど)をクラス、
モジュール型変数をオブジェクトと呼ばれるものなのでしょうか?

オブジェクト指向がどうのこうのと言うcもjavaもよく分からない……
そしてhspもオブジェクト指向をぶっこんでくるのか……
ああ、頭痛が激痛で痛くなりそう



科学太郎

リンク

2016/3/13(Sun) 11:23:42|NO.74896

> モジュール変数を定義するもの(module,modinit,modfunc,modcfuncなど)をクラス、
> モジュール型変数をオブジェクトと呼ばれるものなのでしょうか?
はい。
そうですね。
ゲームならば「オブジェクト」=「自機」=「敵機」=「ミサイル」=「アイテム」などになるでしょう。

> オブジェクト指向がどうのこうのと言うcもjavaもよく分からない……
オブジェクトという言葉を部品とか、パーツなどと解釈すると分かりやすいです。
TamaF(100)、TamaX(100)、TamaY(100)などと配列で100個の弾丸パーツを管理する方法から
modTamaClassでTama(0)〜Tama(99)を管理して1つの配列要素内に m_x、m_y を持つ。

つまり、弾丸パーツのすべての変数を1つの配列要素内で一丸管理できるわけです。
C言語の構造体のイメージです。
この構造体に処理する命令、関数を付けたのがC++言語のクラス概念。
そのC++言語の真似が(module,modinit,modfunc,modcfuncなど)ですね。

> そしてhspもオブジェクト指向をぶっこんでくるのか……
上級者向けという位置づけでしょう。

> ああ、頭痛が激痛で痛くなりそう
まぁ。
気軽にサンプルでも作って行けば良いでしょう。



Sado

リンク

2016/3/13(Sun) 13:05:14|NO.74898

構造体とクラスはほとんど同じ意味だったんですね。

スレの本題に「全てのオブジェクトの描画順を自由にできるようにしたい」がありますが、
オブジェクト指向で作っていくとあると、
描画処理以外をBulletMove、BulletHitCheck()のように処理していくとして
描画処理はどのように組んでいけばいいのでしょうか…
z-indexを……でもクラスは別個だし、global変数でz-indexを……でもmoduleとglobalの紐付け……???
思い浮かばない。

ソートに関しては、サンプルソースを漁ってみたところ
hspのrnd()1000個の要素に対してのソートならマージソートが最速だと認識しています。



科学太郎

リンク

2016/3/13(Sun) 16:16:02|NO.74899

> スレの本題に「全てのオブジェクトの描画順を自由にできるようにしたい」がありますが、
ここが良く分からないのです。
一般的な描画は

背景 ↓ 自機弾 ↓ 自機 ↓ 敵弾 ↓ 敵機 ↓ 爆風 ↓ アイテム ↓ テロップ(スコアなど) ↓ 最上位メッセージ(Warrningなど)
上記のように自機弾グループ、自機グループ、爆風グループという感じで一括で描画するはずです。

> 描画処理はどのように組んでいけばいいのでしょうか…
どのような描画を望んでるのでしょうか?
ここが知りたいです。

> 敵・味方・設置物・エフェクト・地形・背景(層有り)・弾丸など
> 全てのモノが関連して描画順を自由に変えられるようにしたいのですが、
> 何が何だか全く分からない状態なので、皆さんの意見を参考にさせて頂けませんか?
関連して描画順を変える必要性が良く分かりませんね。
どんなゲーム・システムですか?

> z-indexを……でもクラスは別個だし、global変数でz-indexを……でもmoduleとglobalの紐付け……???
とりあえず、描画順とオブジェクトを紐づけた独自のスプライト・クラスを用意すれば良いが…。
このモジュール・クラスは敵・味方・設置物・エフェクト・地形・背景(層有り)・弾丸などを
種類IDとして、オブジェクトID(配列の添え字番号)、ZオーダーID(描画順)の3つを管理しており、
Zオーダー順に双方向リストでオブジェクトを鎖のように登録します。

描画時はZオーダー順の複数の双方向リストのチェーン・データを順番に描画します。
つまり、複数のZオーダー順の双方向リスト・チェーンを二分木処理で登録します。
これならばソートするよりも高速にZオーダー順にオブジェクトをチェーン登録可能。

  ┌───────────modSpriteClass───────────┐   │┌─┐ ┌──────┐┌──┐             │   ││オ├→│描画レベル99├┤OBJ1│             │テロップ   ││ブ│ └──────┘└──┘             │   ││ジ│    :                     │   ││ェ│ ┌──────┐┌──┐┌──┐         │ 登録││ク├→│描画レベル03├┤OBJ1├┤OBJ2│         │自機 ┌─→│ト│ └──────┘└──┘└──┘         │ │ ││の│ ┌──────┐┌──┐             │ │ ││二├→│描画レベル02├┤OBJ1│             │自機弾 │ ││分│ └──────┘└──┘             │ │ ││木│ ┌──────┐┌──┐┌──┐┌──┐┌──┐ │ │ ││ ├→│描画レベル01├┤OBJ1├┤OBJ2├┤OBJ3├┤OBJ4│ │背景 │ │└─┘ └──────┘└──┘└──┘└──┘└──┘ │ │ └─────────────────────────────┘ ZオーダーID(描画レベル01〜描画レベル99) 種類ID(敵・味方・設置物・エフェクト・地形・背景(層有り)・弾丸など) オブジェクトID(オブジェクト・クラスの配列添字番号)
・二分木
https://ja.wikipedia.org/wiki/%E4%BA%8C%E5%88%86%E6%9C%A8

・二分探索木
https://ja.wikipedia.org/wiki/%E4%BA%8C%E5%88%86%E6%8E%A2%E7%B4%A2%E6%9C%A8

・ヒープソート
https://ja.wikipedia.org/wiki/%E3%83%92%E3%83%BC%E3%83%97%E3%82%BD%E3%83%BC%E3%83%88

・連結リスト(双方向リスト)
https://ja.wikipedia.org/wiki/%E9%80%A3%E7%B5%90%E3%83%AA%E3%82%B9%E3%83%88



Sado

リンク

2016/3/13(Sun) 22:29:46|NO.74907

なるほど、そのように考えればいいんですね。
ヒープソート・連結リストの考え方が分からないので完全に理解するまで時間がかかりそうで、
すぐには実装できそうにありません。

>どのような描画を望んでるのでしょうか?...
>関連して描画順を変える必要性が良く分かりませんね。
>どんなゲーム・システムですか?
2Dゲーム、特に縦スクロールSTGです。
例えてしまえば、レイフォースのような奥行きのあるギミックが多めの2Dゲームです。

敵や雲、地形、敵弾などが上下(Z軸)に動くことがあり、
明らかに、自機より下に位置するキャラクター・自機よりも上に位置するキャラクターの
描画順が操作できないと不便なのです。
地形(背景スクロール)と一口に言っても、自機よりも下方にある地面や
自機と地面の中間層にある雲。その雲の下から上に登ってくる敵やミサイルなど。



科学太郎

リンク

2016/3/13(Sun) 23:10:05|NO.74908

> 2Dゲーム、特に縦スクロールSTGです。
> 例えてしまえば、レイフォースのような奥行きのあるギミックが多めの2Dゲームです。
このゲームは知らないが…。

> 地形(背景スクロール)と一口に言っても、自機よりも下方にある地面や
> 自機と地面の中間層にある雲。その雲の下から上に登ってくる敵やミサイルなど。
なるほど。
面白そうなシューティングですね。

うーん。
オブジェクト・クラス、その管理、描画スプライト・クラスを
じっくり考えないとモジュール型変数にした段階で破綻しそうですね。

ちょっとゲーム・キャラクタの仕様が欲しいですね。
この掲示板か、自身のホームページあたりに、まとめてみてはどう?
今後、色々と質問するにあたり便利でしょうから。



科学太郎

リンク

2016/3/13(Sun) 23:25:50|NO.74910

・レイフォース解説 1~4面
https://www.youtube.com/watch?v=2VaPL7HSEjU

これですね。



Sado

リンク

2016/3/13(Sun) 23:41:07|NO.74911

>> 例えてしまえば、レイフォースのような奥行きのあるギミックが多めの2Dゲームです。
>このゲームは知らないが…。
レイフォース面白いですよ。音楽もギミックも景観も演出も最高。
自機よりも下方の敵への攻撃手段があって面白いんです。
僕自身詳しくないですが90年台のゲームらしいです。
似たような雰囲気のゲームに同人ゲームの神威ってのもありますよ。

>ちょっとゲーム・キャラクタの仕様が欲しいですね。
オブジェクト指向を知る前に組んだプログラムで全て配列で管理していますが、
そもそも右も左も分からず、高1の時のお馬鹿な自分がテキトーに書きだしたプログラムで、
だいぶスパゲティ化が進んでいますが……
分かりました。
できるだけ細く描写・オブジェクト関係を書き出してみます。

(俺の作業ペースくそ遅いけど、0時半までにはまとめられるかな)



Sado

リンク

2016/3/14(Mon) 00:35:07|NO.74912

主要な変数と描画順をまとめてみました。
不足分は随時更新していきます。
http://d.hatena.ne.jp/st1105/20160313/1457883071



Sado

リンク

2016/3/14(Mon) 19:49:22|NO.74919

どうも上手く理解できませんでした。

>描画時はZオーダー順の複数の双方向リストのチェーン・データを順番に描画します。
双方向リスト?というもの自体初耳でした。
自分なりに解釈しましたが、今回の場合は、
スプライトクラス内で
dim chainlist,スプライト数,{2(次の添字,前の添字) +3(Zオーダー,種類ID,オブジェクトの添字)}
のように定義して、
ん?次の要素前の要素へのリンクはどうやって決めるんだろう
データ(Zオーダー,種類ID,オブジェクトの添字)を先に代入して、
あとから何かしらの手段でリンク(次の添字,前の添字)を貼っていく?
それっぽい
でも"何かしらの手段"が分からない……

>つまり、複数のZオーダー順の双方向リスト・チェーンを二分木処理で登録します。
>これならばソートするよりも高速にZオーダー順にオブジェクトをチェーン登録可能。
「Zオーダー順の双方向リストに二分木処理で登録」が意味するものが全く……
二分木処理とは、ヒープソートのことですか?
ヒープソートも、その前段階の二分ヒープも、
なんとなくのイメージはあるのですが、図のノードの繋がりが変数・プログラムで
どう表わされるのかさえ分かりませんでした。
こうなったら、サンプルソースを流用して「二分木処理?」をどうにかするしか……
>これならばソートするよりも高速にZオーダー順にオブジェクトをチェーン登録可能。
ソートは利用していない
あれ?
二分木処理っていったい???



科学太郎

リンク

2016/3/14(Mon) 21:33:51|NO.74920

> 僕自身詳しくないですが90年台のゲームらしいです。
こちらが高校生をやってた時代ですか。

> 似たような雰囲気のゲームに同人ゲームの神威ってのもありますよ。
こちらは知ってます。
20歳代のゲーム制作にハマってた時期に遊びました。
100円ショップのダイソー・ゲームで宣伝してましたね。

> できるだけ細く描写・オブジェクト関係を書き出してみます。
お待ちしてます。

> (俺の作業ペースくそ遅いけど、0時半までにはまとめられるかな)
1週間以内なら良いのでマイ・ペースでどうぞ。

> どうも上手く理解できませんでした。
サンプルを作成して載せた方が早いかもしれない。
でも、その前にそれぞれの仕様(企画)を知りたいですね。

> 主要な変数と描画順をまとめてみました。
変数の仕様よりもキャラクタなどのオブジェクトの仕様が欲しいですね。

背景レイヤー ギミック・レイヤー(1) 雲レイヤー ギミック・レイヤー(2)…自機 鉄筋レイヤー ギミック・レイヤー(3) エフェクト・レイヤー(爆発や閃光,火花など)
レイヤーの仕様は上記の様ですか?



Sado

リンク

2016/3/14(Mon) 22:27:54|NO.74921

>100円ショップのダイソー・ゲームで宣伝してましたね。
はぇ、ダイソーで。

現状、描画方法(レイヤー構成)は科学太郎さんの言うところの「一般的な描画」と
全く同じです。

背景 ↓ 自機弾 ↓ 自機 ↓ 敵弾 ↓ 敵機 ↓ 爆風 ↓ アイテム ↓ テロップ(スコアなど) ↓ 最上位メッセージ(Warrningなど)

>レイヤーの仕様は上記の様ですか?
ほぼその通りです。

>でも、その前にそれぞれの仕様(企画)を知りたいですね。
仕様というと、理想の描画ルーチンの形・どのような描写を行いたいか でしょうか。



科学太郎

リンク

2016/3/14(Mon) 23:22:23|NO.74922

> 仕様というと、理想の描画ルーチンの形・どのような描写を行いたいか でしょうか。
はい。その通りです。



Sado

リンク

2016/3/15(Tue) 15:13:21|NO.74924

現在は配列で全て管理していますが、ゆっくりとモジュール型変数へ移行していくと思います。

理想の描画ルーチンの形……実はあまり具体的なイメージがありません。
僕のやりたい「全てのオブジェクトの描画順は自由に変えられる」というのを
ものにするために、どのような形であればいいのか分からないからです。
まあ、思いつく限りで書いてみます。

■ルーチン ...諸処理... ↓ 描画処理(どうしていいか分からない) ・アニメーションなど  行動ルーチンに関係のない描画固有の処理とか ・z-index、ソート?紐付け? ・描画 ものすごく普通……?

■どんな描写を行うか ・大分類  キャラクター(自機・敵・障害物・アイテム("無害で有益な敵"みたいな扱い))  地形と背景(多層。自機の上に半透明で描写したり)  エフェクト  +  最前面にUI(テロップやゲージなど)   ・エフェクト  水しぶき・火花・爆炎・アフターバーナ(ノズル噴射など)・  鉄片・雷(部分発光)・煙(巻き上げられた雲やミサイルの尾など)・土埃は  全てまとめてエフェクトとして処理したほうが楽そう。    爆死アニメーションについては、   最小型の敵キャラ以外は死亡時も単爆発ではない演出が入りますので、   死亡時の爆発はキャラクターオブジェクトとは別に、   エフェクトオブジェクトを使って描画したいかも?   というかそれが一般的? ・地形と背景  地形,背景(ループスクロール)の違いです。  「地形なんてどうやって描写していいか分からねぇ!」  「とりあえずループだ!」  「シーン替えは二枚のタイルを利用して上手く繋げよう!」  というものすごいテキトーなノリでループスクロールを作ってみたのですが  残念なことにそこそこ上手いこと良い演出をしてしまって、  ループスクロールを外せません。  かと言って"当たり判定のある複雑な地形"を外してしまうと演出上の問題が。    というわけで   地形と背景…というより地形とループ地形を共存させたいと思います。   あれ、これも一般的な気がする。
一応多関節のキャラクターも視野に入れています。
現在、複数部位の敵を、
パーツごとに一つのキャラクターとして扱い、
objren()に親の配列変数の添字を代入しておいてリンクさせている状況です。
多関節の仕組みや描写方法は、考え中です。(未来永劫思いつかないと思う)



k

リンク

2016/3/17(Thu) 14:32:39|NO.74931

>オブジェクト指向を知る前に組んだプログラムで全て配列で管理していますが、
>そもそも右も左も分からず、高1の時のお馬鹿な自分がテキトーに書きだしたプログラムで、
>だいぶスパゲティ化が進んでいますが……

この気持ちがよくわかります^^;
昔、私も全て配列で管理していました。

その時はオブジェクトをうまく並列に動作させるように
プログラムするのに苦労した記憶があります

私はオブジェクト指向をすべて知った訳ではありませんが
比較的小規模はプログラムなら
配列で管理しても問題ないような気がします。

肝心なのは後から見てもわかるようなプログラムですね。

スパゲティにならないようにするには

ともかくコメントとか解説をたくさん書くことですね

それこそプログラムよりコメントとか解説が多いぐらいに(^^;
キー入力も配列変数に格納して後で見たようが見やすかったです。


役に立つかわかりませんが自己流ですが並列動作のサンプルを書いてみました

;------------------------------------------------- ; ; 並列動作 サンプル ; ;------------------------------------------------- ; このスプリクトはオブジェクト用配列を使って ; 各オブジェクトを並列に動作するようにプログラムしています ; 各オブジェクトはイベント配列の内容に従って動作します ; ; イベント配列は数値をテーブル化して表しています ; 見やすくなるように#defineで定義しています ;------------------------------------------------- ; ; イベント配列 ; ; event_tblという配列テーブルを使う ; event_tbl p1,p2,,,, ; p1 は確定でイベント番号が入る ; p2 は確定で待ちフレームが入る ; p2以降はイベント番号によって変わる ; 今回は 5個 確保していますが  ; 規模が大きくなると増えます ;------------------------------------------------- ;------------------------------------------------- ; ; オブジェクト配列 ; ; obj_tbl p1,p2,p3,p4,p5 ; p1 状態 0以外だと オブジェクトがイベント実行中 ; p2 イベント番号 ; p3 イベントカウント ; p4 X座標 ; p5 Y座標 ; 今回は 5個 確保していますが  ; 規模が大きくなると増えます ;------------------------------------------------- dim event_tbl,5,100 dim obj_tbl,5,100 ;------------------------------------------------- ; ; 各イベント解説 ; ;------------------------------------------------- ; イベント1番 子obj出現 ; ; 解説 ; フレーム待ち後現在のobjとは別にobjを出現させる  ; イベント番号と現在のobjとの座標差分を指定する ; ; EVENT_OBJ p1,p2,p3,p4 ; p1 待ちフレーム ; p2 親objとのx座標差分 ; p3 親objとのy座標差分 ; p4 イベントno ;------------------------------------------------- ;------------------------------------------------- ; イベント2番 objの移動処理  ; ; 解説 ; objのx座標y座標を待ちフレーム後加算する ; ; EVENT_POSMOVE p1,p2,p3 ; p1 待ちフレーム ; p2 x座標差分 ; p3 y座標差分 ;------------------------------------------------- ;------------------------------------------------- ; イベント3番 待ちフレーム  ; ; 解説 ; 待ちフレームのみでなにもしない ; 待ったあと次のイベントに進む ;  ; EVENT_NOP p1 ; p1 待ちフレーム ;------------------------------------------------- ;------------------------------------------------- ; イベント4番 終了  ; 解説 ; 待ちフレーム後オブジェクトを消去する ; ; EVENT_END p1 ; p1 待ちフレーム ;------------------------------------------------- ;------------------------------------------------- ; イベント5番 ループ  ; 解説 ; 待ちフレーム後 指定回数分戻る ; ; EVENT_LOOP p1,p2,p3 ; p1 待ちフレーム ; p2 ループ回数 ; p3 戻る数 ;------------------------------------------------- ; ; 注意 待ちフレームが0の場合は ; 待たずに次のイベントに行く ;------------------------------------------------- ; event_adr++の意味 ; ; イベントを定義したあと1を加算して ; 次のイベントの準備 ;------------------------------------------------- #define EVENT_OBJ(%1=0,%2=0,%3=0,%4=0,%5=0) event_tbl(0,event_adr) = 1,%1,%2,%3,%4 : event_adr++ #define EVENT_POSMOVE(%1=1,%2=0,%3=0) event_tbl(0,event_adr) = 2,%1,%2,%3 : event_adr++ #define EVENT_NOP(%1=0) event_tbl(0,event_adr) = 3,%1 : event_adr++ #define EVENT_END(%1=0) event_tbl(0,event_adr) = 4,%1 : event_adr++ #define EVENT_LOOP(%1=0,%2=0,%3=0) event_tbl(0,event_adr) = 5,%1,%2,%3 : event_adr++ ;------------------------------------------------- ; イベント用の番号セット ; ラベルのような感じで使いますが変数のため数字しか使えません ; EVENT_NO_SET ;------------------------------------------------- #define EVENT_NO_SET(%1=0) event_tbl_no(%1) = event_adr dim event_tbl_no,100 dim loop_tbl,100 ;------------------------------------------------- ; ラベル型変数の定義 ;------------------------------------------------- ldim lavel,20 lavel(1)=*lavel_OBJ lavel(2)=*lavel_POSMOVE lavel(3)=*lavel_NOP lavel(4)=*lavel_END lavel(5)=*lavel_LOOP ;------------------------------------------------------------------------------- ; ; イベントデータ ; ;------------------------------------------------------------------------------- event_adr=0 ; イベントアドレスクリア ;------------------------------------------------------------------------------- ; 親objイベント(マスター) ;------------------------------------------------------------------------------- EVENT_NO_SET 0 ;イベント番号0 EVENT_POSMOVE 1,100,450 ;親obj移動 1フレーム待ち後x座標100,y座標を450足す repeat 10 ;通常のループ 10回あるので 配列を余分に使ってしまう EVENT_OBJ 0,0,0,1 ;子obj出現 イベント番号1をセット EVENT_POSMOVE 1,4,0 ;親obj移動 1フレーム待ち後x座標を4足す EVENT_LOOP 0,10,1 ;ループ処理 待ちフレームなしで10回イベントをひとつ戻す ;増える配列がひとつなので効率がいいが今は2重ループができない loop EVENT_OBJ 0,0,0,1 ;子obj出現 イベント番号1をセット EVENT_END 10000 ;10000フレーム後終了 ;------------------------------------------------------------------------------- ; 子obj用イベント ;------------------------------------------------------------------------------- EVENT_NO_SET 1 ;イベント番号1 EVENT_POSMOVE 1,0,-2 ;子obj移動 1フレーム待ち後y座標を2引く EVENT_LOOP 0,50,1 ;ループ処理 待ちフレームなしで50回イベントをひとつ戻す EVENT_OBJ 0,0,0,2 ;孫obj出現 イベント番号2をセット EVENT_POSMOVE 1,0,-2 ;子obj移動 1フレーム待ち後y座標を2引く EVENT_LOOP 0,150,1 ;ループ処理 待ちフレームなしで150回イベントをひとつ戻す EVENT_END ;待ちフレームなし終了 ;------------------------------------------------------------------------------- ; 孫obj用イベント ;------------------------------------------------------------------------------- EVENT_NO_SET 2 ;イベント番号2 EVENT_POSMOVE 1,1,-5 ;孫obj移動 1フレーム待ち後x座標を1足しy座標を5引く EVENT_LOOP 0,20,1 ;ループ処理 待ちフレームなしで20回イベントをひとつ戻す EVENT_POSMOVE 1,0,-5 ;孫obj移動 1フレーム待ち後y座標を5引く EVENT_LOOP 0,20,1 ;ループ処理 待ちフレームなしで20回イベントをひとつ戻す EVENT_END ;待ちフレームなし終了 ;------------------------------------------------------------------------------- ; ; メインループ ;------------------------------------------------------------------------------- obj_tbl(0,0)=1,0,0,-10,-10 ; 親obj(マスター)をイベント番号0で出現させる ;x座標-10 y座標-10 イベント番号0 repeat 10000 ;------------------------------------------------------------------------------- ; イベント処理 ;------------------------------------------------------------------------------- *event_main repeat 100 obj_num=cnt if (obj_tbl(0,obj_num) >= 1){ ;obj_tbl(0 状態 0(非表示) 1(表示) *event_main_a event_num=obj_tbl(1,obj_num);obj_tbl(1 イベント番号 if (event_tbl(1,event_num) <= obj_tbl(2,obj_num)){ ;obj_tbl(2 イベントカウント ;イベントカウント以下だったらイベントを実行する gosub lavel(event_tbl(0,event_num)) if obj_tbl(0,obj_num)=0 : continue obj_tbl(1,obj_num)++;次のイベント obj_tbl(2,obj_num)=0;イベントカウント初期化 goto *event_main_a } obj_tbl(2,obj_num)++;イベントカウント更新 } loop ;------------------------------------------------------------------------------- ; オブジェクト表示処理 ;------------------------------------------------------------------------------- color 0,0,0 repeat 100 if (obj_tbl(0,cnt) >= 1){ ;実行中を探す x=obj_tbl(3,cnt) y=obj_tbl(4,cnt) boxf x,y,x+10,y+10 } loop await 17 loop end ;------------------------------------------------------------------------------- ; ; 以下イベントプログラム ; ;------------------------------------------------------------------------------- *lavel_OBJ;EVENT_OBJ 1番 x=obj_tbl(3,obj_num) y=obj_tbl(4,obj_num) repeat 100 if obj_tbl(0,cnt)=0{ ;空きを探す obj_tbl(0,cnt)=1 ;状態セット  obj_tbl(1,cnt)=event_tbl_no(event_tbl(4,event_num));イベントセット obj_tbl(2,obj_num)=0 ;イベントカウント初期化 obj_tbl(3,cnt)=x+event_tbl(2,event_num) ;X座標セット obj_tbl(4,cnt)=y+event_tbl(3,event_num) ;Y座標セット break } loop return ;------------------------------------------------------------------------------- *lavel_POSMOVE ;EVENT_POSMOVE 2番 obj_tbl(3,obj_num)+=event_tbl(2,event_num) ;X座標加算 obj_tbl(4,obj_num)+=event_tbl(3,event_num) ;Y座標加算 return ;------------------------------------------------------------------------------- *lavel_NOP ;EVENT_NOP 3番 return ;------------------------------------------------------------------------------- *lavel_END ;EVENT_END 4番 obj_tbl(0,obj_num)=0 ;状態クリア return ;------------------------------------------------------------------------------- *lavel_LOOP ;EVENT_LOOP 5番 loop_tbl(obj_num)++ if event_tbl(2,event_num) < loop_tbl(obj_num) {;通常 loop_tbl(obj_num)=0;ループカウンターリセット }else{ obj_tbl(1,obj_num)-=event_tbl(3,event_num)+1;戻り } return



科学太郎

リンク

2016/3/17(Thu) 18:05:49|NO.74933

> まあ、思いつく限りで書いてみます。
どうやら描画の問題よりもオブジェクトの管理を考えた方が良いかもしれない。
1つのオブジェクト(キャラクタ)に全ての機能を持たせるわけです。
そうすればオブジェクトの描画は「オブジェクトの持つZオーダー順」に描画すれば良いので
いくらでも描画順を変えられることになります。

よって1つのオブジェクトは、 アニメ処理の有無(パラメータ多数) あたり判定の有無(パラメータ多数) 移動カウンタ 移動テーブル
> 一応多関節のキャラクターも視野に入れています。
これに対応するには、1つのオブジェクトに子供のオブジェクトを双方向リストの考えで
鎖のようにチェーンで結ばれてるように管理するわけです。
描画時は末尾の尻尾キャラクタから描画して、先頭の頭部キャラクタを描画。
これで蛇キャラクタからロボットのような多関節キャラクタまで対応が聞くと思います。

> パーツごとに一つのキャラクターとして扱い、
親パーツに手足などの関節キャラを結び付けた方が良いでしょう。

> objren()に親の配列変数の添字を代入しておいてリンクさせている状況です。
親のみか?
1つのオブジェクトに自機・敵機・自機弾・敵機弾・障害物・アイテム・エフェクト効果など
万能キャラクタを用意すれば描画順は任意のタイミングでZオーダーを変えたら
次の描画タイミングで直ぐに反映するようになりますね。

> 多関節の仕組みや描写方法は、考え中です。(未来永劫思いつかないと思う)
これも考慮に入れて1つのオブジェクト管理を設計しないとまずいかもね。
配列方式でも1つのオブジェクトで全てのキャラクタを表現できるようにすれば良いので。
モジュール型変数か、配列方式かは2の次な気がしてきました。

配列タイプでも良いので動く実行ファイルなどを公開して欲しいですね。
その動きからデータ構造を新たに考えた方がよさそうです。
一通り配列タイプで完成させてみるのはどうですか?
その次のバージョン・アップでモジュール型変数に対応するとか。



Sado

リンク

2016/3/17(Thu) 22:10:02|NO.74934

>kさん
すごい、何がすごいのかよく分からないけれど何かすごい。
ラベル変数も使い方がよく分からなかったのですが、
動作パターンをそのように組み立てることができるんですね。
イベント管理・並列処理、とても参考になります。

パッと見ただけでは、見たことがない型だからなのかすぐには理解できそうにありません。
またしても見たことがない作り……勉強不足すぎ。
スタック…じゃない、キュー?の構造になっているのでしょうか……



>科学太郎さん
この記事にツイッターにupされた動画が埋め込まれているので、参考になれば。
もしかすると限定配布なら許してもらえるかも……
http://d.hatena.ne.jp/st1105/20160202/1454428004

>どうやら描画の問題よりもオブジェクトの管理を考えた方が良いかもしれない。
>1つのオブジェクト(キャラクタ)に全ての機能を持たせるわけです。
やはり、グダグダなシステムでボロが出まくっていますし、
そもそも足りていない機能がありまくり。
考えなおしですよね……

>> 一応多関節のキャラクターも視野に入れています。
>これに対応するには、1つのオブジェクトに子供のオブジェクトを双方向リストの考えで
双方向リストは確か、"次"と"前"の配列添え字を保持しておくものでしたっけ。
それでいて次か前にしかアクセス出来なかった気がするので、
親objへダメージを伝えたりするためにするには、既存のobjrenを

objren num,3 0:親へのリンク(0なら単体) 1:前(-1なら最初) 2:次(-1なら最後)
のようにすれば双方向リストとしても成り立ちますよね。

>一通り配列タイプで完成させてみるのはどうですか?
モジュール型に不慣れな現状で、あれができないこれができない、なんて問題が出る度に
ここに質問しに来たり、サンプルを組んでみたりするのでは時間がかかってしょうがありません。
そうですね、配列タイプで完成させます。
モジュール型は次回作でトライします。





多関節で思い出しましたが、
一つのオブジェクトに複数の当たり判定を持たせる場合
どこに当たり判定(矩形)の相対座標(親との座標差分)を代入すればいいのか悩んでいます。
objat(キャラ数,当たり判定64個くらい確保,2(xy相対座標))
なんて初期化した日には、
当たり判定が矩形一個のキャラなら63*2個の変数(確保されたメモリ?)が無駄になると思うのです。

複数の矩形当たり判定をどこに置いておけば良いのか、分かりません。
ただの配列では無いんでしょうけど



k

リンク

2016/3/17(Thu) 23:16:46|NO.74937

>多関節で思い出しましたが、
>一つのオブジェクトに複数の当たり判定を持たせる場合
>どこに当たり判定(矩形)の相対座標(親との座標差分)を代入すればいいのか悩んでいます。

その辺は
グラディウス供.哀薀妊ウス掘‥たり判定などで
動画を検索するといくつか出てきますが
いろいろですね^^;



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