MAGI JAVA -Make a game in Java-
JAVA Game作成講座 011回
オブジェを作成→描画する


kouza011 jarファイル



[今回追加したもの]
・ObjectBaseクラスの作成
・ObjectDataSetクラスの作成

壁も物体も人物も全てオブジェクトと呼称している。
置物だとイメージすればいい。
壁は全く動かず、オブジェは条件次第で動く。
壁は触っても何も起きないが、オブジェは触るとイベントが発動する。
オブジェとの接触判定も壁との接触に使ったcollisionクラスを用いる。


当たり判定までやろうと思ったが、謎のバグで絵が出なくなったり、
思った以上に大工事になったので、描画だけで一区切りにした。
一か所いじるといきなりエラーの嵐になる事はよくあるので、
マメにコピーしておくことをお勧めする。

[バックアップは大切]
ファイル全体をバックアップしておき、進行具合などを適当にコメントで付けておく。
何か致命的なエラーが出て原因がさっぱりわからないときは一時中断。
無事に動いていた段階のデータをメインに使った方が速い場合が多い。
エラーまみれのデータから少しずつコピペしていくのだ。
どの段階でエラーが出るのかマメに実行しつつ検証していく。
作ったもの全部が無駄にならないし、一度やった行程なのでスイスイつくれる。


[ObjectBase]
まるまるコピペする意味もないのでかいつまんで説明だけ入れる。
move関数でこの先移動処理を加えていくが、
それ以外の変数はほとんどPlayerPlatformクラスの流用。
いくつか専用の変数を加えてあるが、これも後々使う予定。

[ARPanel→GameDataクラス→ObjectDataSetクラス→ObjectBaseクラス]
この4つが連動しているので抜粋して解説を入れる。
まずARPanelの初期化の時点でマップと一緒にセットする。

[ARPanelクラス]
gData.objKariSet(); //オブジェクト配置テスト

[GameDataクラス]
//仮データを打ち込み、マップ表示テストを行う。適当な座標に一体出してみる。
public void objKariSet() {

//dataSetEasy(int kx,int ky,int shift,int onum,int evnum,int type1,int type2)
ObjectBase obj=new ObjectBase();
obj=odtSet.dataSetEasy(6*32,6*32,0,0,1,0,0);
obj.setMapSize(mapSize[0]*32, mapSize[1]*32);
objs.add(obj);


}

odtSet=ObjDataSetクラスを経由して、objデータを作成する。
座標その他色々データを打ち込む必要があるが、今使わないデータが多い
kx,ky=キャラクターを表示するx,y座標。それならcxだろ。間違えた。
shift=キャラの向き。8246上下左右。処理開始時に向いている向きになる。
onum=オブジェクトのナンバー。0-順に振っていく。
同じナンバーのオブジェは作らない方が良い。
後々、このナンバーを指定して遠隔操作でイベントを動かしたりする予定。
evnum=イベントナンバー。これが一番重要。1=会話イベント、2=戦闘イベントなど
ナンバーによって作動するイベントを変えられる。
Type1,Type2=この二つの組み合わせで何かが起こる…。
evnumと組み合わせて使う。会話のパターン変えたり敵の種類変えたり…。
今はまだ使わないので0でいい。

> obj.setMapSize(mapSize[0]*32, mapSize[1]*32);
オブジェ作成時に定義しておく。これを忘れると狭い範囲しか動かなくなる。

objs.add(obj)
完成したobjをArraylistに放り込む。

では次。odtSet=ObjectDataSetクラスで何が起きているかを説明する。

[ObjectDataSetクラス]
public class ObjectDataSet {
public ObjectDataSet() {
init();
}

public void init() {
//gData=new GameData();
}

public ObjectBase dataSetEasy(int kx,int ky,int shift,int onum,int evnum,int type1,int type2) {

int[] kxy={kx,ky,shift};
int[] smData=null;
int[] smData2= {0,0,0,0,0};
int[] numset= {onum,evnum,0}; //3要素目はグラフィックナンバーが入る。
ObjectBase obj=new ObjectBase();
//ある程度のパターンをtype1の指定で引っ張り出せるようにする。
//evnumが同じでtype1を変える事で外見の違う同じイベントを起こすキャラを作れる。
//敵キャラとか、会話するだけのキャラとか。evnum,type1,2の指定で多様性を持たせる。
if (type1==0) {
int[] sd= {0,0,0,0,0,0};
smData=sd;
numset[2]=2; //基本のキャラ絵。
}
obj.dataSet(kxy,numset,smData,smData2);
return obj;


}
}

obj.dataSet(kxy,numset,smData,smData2);
dataSetEasy関数に入れたデータをさらにまとめて、ObjectBaseに放り込む。
someDataは本来typeによって色々設定する。今回は省略するが。

[ObjectBaseクラス]
public void dataSet(int sxy[],int[] numset,int sdt[],int sdt2[]) {

//System.out.println("oData Set");
x=sxy[0];
y=sxy[1];
init();
live=true; //セットした時点で存在を確定させる。
size=32; //大体サイズは32。
objNumber=numset[0];
eventNumber=numset[1];
graNumber=numset[2];
if (graNumber==2) gra=gSet.mapUnitGraSet(2);
someData=sdt; //イベントによって用途が変わる。場所移動のアドレスになったり、会話のパターン、敵のパターンなど…。
someData2=sdt2; //0=移動タイプ 1=非表示フラグ 2=フラグのスイッチ 3,4=フラグのアドレス1,2


}

重要なのはnumsetで渡したデータ。
eventNumberが最重要。触ったりして発動したイベントの種類がこれで決まる
graNumberはdataset時にtypeから引っ張ってくる。今回はグラ固定。

if (graNumber==2) gra=gSet.mapUnitGraSet(2);
グラナンバーを元に絵をセットする。1にするとプレイヤーと同じグラになってしまう。
someData, someData2 は今回使わないので0でスルー。

[ARPanelで描画]
長くなるが、まるまるコピペする。

public void objPaint(Graphics g) {

int oSize=gData.objs.size();
int[] olist=objSort();
Boolean playerDrawEnd=false;
int poxy[]=gData.pPlatform.getxy();
int pmc=gData.pPlatform.moveCount;
if (oSize>=1) {
for (int i=0; i<= oSize-1; i++) {
ObjectBase cObj=gData.objs.get(olist[i]);
int oxy[]=cObj.getxy();
int omc=cObj.moveCount;
if (playerDrawEnd==false && poxy[1]<=oxy[1]) {
objDraw(g,gData.pPlatform.gra,poxy,pmc);//System.out.println("");
playerDrawEnd=true;
}
objDraw(g,cObj.gra,oxy,omc);
}
}
//オブジェが無い or プレイヤーが一番下のy座標→プレイヤー最後に描画して終了。
if (playerDrawEnd==false) {
objDraw(g,gData.pPlatform.gra,poxy,pmc);
}


}

プレイヤーの描画をオブジェとリンクして行う方法に切り替えている。
なぜそうしたのかというと、重なった時にyが小さい方を奥にしたいから。
32*32でキャラを作っているのではなく、32*48なのが問題になる。
16ドット分の重なりが出来てしまうのだ。

そこで、まずobjをy座標の小さい順にソートする。
順に描画していって、プレイヤーのy座標より大きいオブジェが出てきた時点で
プレイヤーの絵を描く。こうすることでプレイヤーとオブジェが立体的に重なる。

何言ってるのか分からねーよ、という人は、
oSizeの中のfor分にあるプレイヤードロウを無効化して走らせてみて欲しい。
この処理を入れた意味が分かるから。

public void objDraw(Graphics g,BufferedImage gra, int[] oxy,int pmc) {

//カメラによる座標修正を加える
oxy[0]-=gData.cameraPos[0];
oxy[1]-=gData.cameraPos[1];
int sx=0;
int sy=0;
int picSize=oxy[2];
int pShift=oxy[3];
if (pShift==8) sy=148;
if (pShift==2) sy=0;
if (pShift==4) sy=48;
if (pShift==6) sy=96;
//キャラクターを歩いているようにアニメーションさせる
int a=16;

if (pmc>=0 && pmc<=a-1) sx=0; //pmc0-15 左
if (pmc>=a && pmc<=a*2-1) sx=32; //16-31 中
if (pmc>=a*2 && pmc<=a*3-1) sx=64; //32-47 右
if (pmc>=a*3 && pmc<=a*4-1) sx=32; //48-63 中 64カウントで0に戻し、また左パターンへ戻る
g.drawImage(gra,oxy[0],oxy[1]-16,oxy[0]+picSize,oxy[1]+picSize,sx,sy,sx+picSize,sy+picSize+16,this);


}

objDraw処理は、プレイヤーの描画に使っていた物をオブジェにも使いまわせるようした物。
グラフィック、gra, x,y,size,shiftをまとめたものと、移動カウンターを渡す必要がある。
プレイヤーも同じ関数を使って描画している。

//オブジェをy座標の小さい順に並び変える。奥から描画することで重なったときの立体感を出せる。
public int[] objSort() {

int oSize=gData.objs.size()-1;
int[] oblist=new int[10];
if (oSize>=1) {
ArrayList objNum=new ArrayList();
ArrayList objNum2=new ArrayList();
for (int i=0; i<= oSize; i++) {
int oxy[]=gData.objs.get(i).getxy();
objNum.add(oxy[1]);
}
int count=0;

//System.out.println("cMax="+cMax);
while (count<=oSize) {
int yMin=9999;
int keepNum=9999;
//int oMax=objNum.size()-1;
for (int i=0;i<=oSize;i++) {
int yNow=objNum.get(i);
if (yNow<=9000) {
if (yNow<=yMin) {
keepNum=i;
yMin=yNow;
}
}
}
if (yMin<=9000) {
objNum2.add(keepNum);
objNum.set(keepNum,100000); //読み取った要素は巨大な番号と差し替えて無効化する。
}
count++;
}
oblist=new int[objNum2.size()];
for (int i=0;i<=objNum2.size()-1;i++) {
oblist[i]=objNum2.get(i);
}
}
return oblist;


}

そのまんまの処理なので説明は省く。


オブジェの絵がマップに表示されているはずだ。
身動き一つしないが、これだけの処理を経てやっと表示できた。

次回はオブジェとプレイヤーの当たり判定を入れる。
今回ほど複雑な処理はない。追加部分はごくわずかになるはず。
オブジェは壁と同じ扱いなので、上に乗ることは出来ない。
今回のゲームは全て乗れないオブジェで設定する。


・トップページへ戻る
inserted by FC2 system