【JavaSE】サイドビューの実験(16/17)

空中にいるとき左右に移動しようとしたら慣性が外れるようにしてみた。いい感じ。
ところでブロックが止まる直前にジャンプしたとき、ブロックが止まると空中にいるキャラクタも止まる。
慣性じゃない。
しかしジャンプアクションゲームとしてただジャンプしただけでは落下しないという仕様はむしろメリットではないかと思う。
- カーソルキーで左右移動
- Zキーでジャンプ
- Xキーで当たり判定を可視化した補助線の描画のオン・オフを切り替え
SideViewExp16.java
import isle.videogame.*; import isle.videogame.image.*; import java.awt.*; @SuppressWarnings("serial") public class SideViewExp16 extends VGStretchCanvas { static final int SCREEN_WIDTH = 240; static final int SCREEN_HEIGHT = 240; int pad_states_last; byte[][] map = { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,2 }, { 1,1,1,1,0,0,1,1,1,1,1,1,1,1,1 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0 }, { 1,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 1,1,2,0,0,0,0,0,0,0,0,0,2,1,1 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, { 2,0,0,0,0,0,0,1,1,0,0,0,0,1,2 }, { 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2 }, }; VGTilemap BG_map; VGTiledImage BG_tile; VGImage[] Girl_imgs; Rectangle Girl_rc = new Rectangle(); int Girl_nImg; int Girl_cWalk; boolean Girl_bLeft; int Girl_ga; int Girl_borderHead; // 当たり判定の頭上の境界 int Girl_borderFoot; // 当たり判定の足元の境界 boolean Girl_bStand; // 立っているか int Girl_idInert; // 慣性を受ける移動ブロックの識別番号 static final int FLOATBLOCK_NUM = 1; int[][][] FloatBlockMovements = { {{ 0, 0, 60 }, { 1, 0, 112 }, { 0, 0, 60 }, { -1, 0, 112 }}, }; int[][] FloatBlockPosTable = {{ 48, 150 }}; int[] FloatBlock_kind = { 1, 2 }; Point[] FloatBlock_pt = new Point[FLOATBLOCK_NUM]; int[] FloatBlock_index = new int[FLOATBLOCK_NUM]; int[] FloatBlock_count = new int[FLOATBLOCK_NUM]; int[] FloatBlockSortedIndex = new int[FLOATBLOCK_NUM]; Rectangle rcBump = new Rectangle(); // 当たり判定対象用 boolean bDrawAux = true; // 補助線などを描画するかどうか public SideViewExp16() { super(SCREEN_WIDTH, SCREEN_HEIGHT, 60); setBackground(Color.DARK_GRAY); Girl_imgs = VGImage.createImages(getResourceImage("buruma.png"), 0, 0, 16, 24, 6); Girl_rc.setSize(32-3*2, 48); // 当たり判定基準 Girl_rc.setLocation(3, 0); BG_tile = new VGTiledImage(getResourceImage("bg.png"), 16, 16, 3); BG_map = new VGTilemap(BG_tile, 15, 15); for (int y=0; y<15; ++y) { for (int x=0; x<15; ++x) { BG_map.setTile(x, y, map[y][x], 0); } } for (int i=0; i<FLOATBLOCK_NUM; ++i) { FloatBlock_pt[i] = new Point(FloatBlockPosTable[i][0], FloatBlockPosTable[i][1]); FloatBlock_index[i] = 0; FloatBlock_count[i] = FloatBlockMovements[i][FloatBlock_index[i]][2]; } } @Override protected void frameUpdate(int skipped) { int pad_states = getPadStates(); int pad_trigger = (pad_states_last ^ pad_states) & pad_states; pad_states_last = pad_states; // 移動前の座標で頭上と足元の当たり判定の境界ラインを設定 Girl_borderHead = Girl_rc.y; Girl_borderFoot = Girl_rc.y + Girl_rc.height; // ユーザー操作によるキャラクタの移動処理 if (Girl_bStand) { Girl_nImg = 4; if ((pad_states & (1<<PAD_LEFT)) != 0) { --Girl_rc.x; ++Girl_cWalk; Girl_cWalk %= 16; Girl_nImg = Girl_cWalk / 4; Girl_bLeft = true; } if ((pad_states & (1<<PAD_RIGHT)) != 0) { ++Girl_rc.x; ++Girl_cWalk; Girl_cWalk %= 16; Girl_nImg = Girl_cWalk / 4; Girl_bLeft = false; } if ((pad_trigger & (1<<PAD_BUTTON1)) != 0) { Girl_ga = -12; } } else { Girl_nImg = 5; if (Girl_ga < 8) ++Girl_ga; Girl_rc.y += Girl_ga; if ((pad_states & (1<<PAD_LEFT)) != 0) { --Girl_rc.x; Girl_idInert = 0; // 空中で操作されたら慣性を受ける移動ブロックなしに設定 } if ((pad_states & (1<<PAD_RIGHT)) != 0) { ++Girl_rc.x; Girl_idInert = 0; // 空中で操作されたら慣性を受ける移動ブロックなしに設定 } } if ((pad_trigger & (1<<PAD_BUTTON2)) != 0) { bDrawAux = !bDrawAux; // 補助線などを描画する・しないを切り替え } // 浮動ブロックの移動 boolean bOnFloatBlock = false; for (int i=0; i<FLOATBLOCK_NUM; ++i) { rcBump.setBounds(FloatBlock_pt[i].x, FloatBlock_pt[i].y-1, 32, 1); if (Girl_bStand && FloatBlock_pt[i].y >= Girl_borderFoot && rcBump.intersects(Girl_rc)) { // 移動ブロックに接地しているとき慣性を受ける移動ブロックとして設定 bOnFloatBlock = true; Girl_idInert = i+1; // とりあえず配列の添字+1を識別番号として使用 } int vx = FloatBlockMovements[i][FloatBlock_index[i]][0]; int vy = FloatBlockMovements[i][FloatBlock_index[i]][1]; // X方向に移動する場合 if (vx != 0) { // キャラクタに慣性を加える if (Girl_idInert == i+1) { Girl_rc.x += vx; } FloatBlock_pt[i].x += vx; } // Y方向に移動する場合 if (vy != 0) { // キャラクタに慣性を加える if (Girl_idInert == i+1) { Girl_rc.y += vy; // 下降時に他の床に引っ掛かるよう足元の境界はそのまま if (vy < 0) Girl_borderFoot += vy; } FloatBlock_pt[i].y += vy; } if (--FloatBlock_count[i] <= 0) { FloatBlock_index[i] = (FloatBlock_index[i] + 1) % FloatBlockMovements[i].length; FloatBlock_count[i] = FloatBlockMovements[i][FloatBlock_index[i]][2]; } } if (Girl_bStand && !bOnFloatBlock) { // 接地しているが移動ブロックではないとき慣性を受ける移動ブロックなしに設定 Girl_idInert = 0; } Girl_bStand = false; // 固定ブロックとの当たり判定 for (int i=0,y=0; i<15; ++i,y+=16) { for (int j=0,x=0; j<15; ++j,x+=16) { doCollideBlock(x, y, map[i][j]); } } // 浮動ブロックの位置で上から下へ順にソートした索引を作る for (int i=0; i<FLOATBLOCK_NUM; ++i) { FloatBlockSortedIndex[i] = i; for (int j=i-1; j>=0; --j) { if (FloatBlock_pt[FloatBlockSortedIndex[i]].y < FloatBlock_pt[FloatBlockSortedIndex[j]].y) { int tmp = FloatBlockSortedIndex[j]; FloatBlockSortedIndex[j] = FloatBlockSortedIndex[i]; FloatBlockSortedIndex[i] = tmp; } } } // 浮動ブロックとの当たり判定 for (int i=0; i<FLOATBLOCK_NUM; ++i) { int ii = FloatBlockSortedIndex[i]; // ソートした順番 doCollideBlock(FloatBlock_pt[ii].x , FloatBlock_pt[ii].y, FloatBlock_kind[ii]); doCollideBlock(FloatBlock_pt[ii].x+16, FloatBlock_pt[ii].y, FloatBlock_kind[ii]); } // 最終座標補正 if (Girl_rc.x < 0) Girl_rc.x = 0; if (Girl_rc.x > SCREEN_WIDTH-Girl_rc.width) Girl_rc.x = SCREEN_WIDTH-Girl_rc.width; } void doCollideBlock(int x, int y, int kind) { // 天井の判定 switch (kind) { case 2: // 横に吹っ飛ばないための除外 if (y + 16 > Girl_borderHead) break; // 天井の当たり判定はブロックの下端だけ rcBump.setBounds(x, y+16-1, 16, 1); if (!Girl_rc.intersects(rcBump)) break; Girl_rc.y = y + 16; Girl_ga = 0; // 当たり判定境界をリセット Girl_borderHead = Girl_rc.y; Girl_borderFoot = Girl_rc.y + Girl_rc.height; } // 床の判定 switch (kind) { case 1: case 2: if (Girl_ga < 0) break; // 引っ張り上げられないための除外 if (y < Girl_borderFoot) break; // 床の当たり判定はブロックの上端だけ // 足元の当たり判定を1ピクセル伸ばすことで // 座標補正後もブロックの上に居る状態を維持 rcBump.setBounds(x, y-1, 16, 2); if (!Girl_rc.intersects(rcBump)) break; Girl_rc.y = y - Girl_rc.height; Girl_ga = 0; // 当たり判定境界をリセット Girl_borderHead = Girl_rc.y; Girl_borderFoot = Girl_rc.y + Girl_rc.height; Girl_bStand = true; } // 壁の判定 switch (kind) { case 2: rcBump.setBounds(x, y, 16, 16); if (!Girl_rc.intersects(rcBump)) break; // 壁にめり込んでいる if (Girl_rc.x < x) { // ブロックより左寄りなら左に座標補正 Girl_rc.x = x - Girl_rc.width; } else { // 右に座標補正 Girl_rc.x = x + 16; } } } @Override protected void frameStretchRender(Graphics g) { // 固定ブロックを描画 BG_map.paint(g, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, 0); // 浮動ブロックを描画 for (int i=0; i<FLOATBLOCK_NUM; ++i) { BG_tile.paint(g, FloatBlock_kind[i], FloatBlock_pt[i].x , FloatBlock_pt[i].y, 0); BG_tile.paint(g, FloatBlock_kind[i], FloatBlock_pt[i].x+16, FloatBlock_pt[i].y, 0); } if (bDrawAux) { g.setColor(Color.YELLOW); g.drawLine(0, Girl_borderHead, SCREEN_WIDTH-1, Girl_borderHead); g.drawLine(0, Girl_borderFoot-1, SCREEN_WIDTH-1, Girl_borderFoot-1); } Girl_imgs[Girl_nImg].paint(g, Girl_rc.x-3, Girl_rc.y, 32, 48, Girl_bLeft ? 0 : VGImage.FLIP_HORIZONTAL); if (bDrawAux) { g.setColor(Color.RED); g.drawRect(Girl_rc.x, Girl_rc.y, Girl_rc.width-1, Girl_rc.height-1); } } // $> java -cp SideViewExp.jar SideViewExp16 public static void main(String[] args) { new VGFrame(new SideViewExp16(), 640, 480, "サイドビュー実験"); } }
| 固定リンク
「JavaSE」カテゴリの記事
- 【JavaSE】フレームワークライブラリを更新 (2011/09/17)(2011.09.17)
- 【JavaSE】フレームワークライブラリを更新 (2011/09/14)(2011.09.14)
- タイルマップ座標のオフセットを求める(2011.06.21)
- 【JavaSE】フレームワークライブラリを更新 (2011/03/01)(2011.03.01)
- 【JavaSE】サイドビューの実験(17/17)(2010.10.12)
コメント