遊戲碰撞的大致可以分為這幾種類
1.主角與邊界的碰撞,限制主角不能走出手機螢幕外。
2.主角與物理層的碰撞,與地圖中的房子 桌子 椅子等等。
3.主角與遊戲人物之間的碰撞,這裡指NPC等。
4.主角與指令碼框發生的碰撞,例如走進房間出線一段劇情對話等等。
由此可見遊戲中的碰撞主要是 可以分為
1.點與矩形之間的碰撞
2.矩形與矩形之間的碰撞
3.圓形與圓形之間的碰撞
4.圓形與矩形之間的碰撞
今天我主要介紹一下以上中最特殊的一個碰撞方式 主角與物理層之間的碰撞。 :每個小方塊中儲存著地圖塊的資訊,在二位元組中如果為-1表示屬於物理層不可通過,其它均可通過。也就是說-1 這個地圖塊的位置繪製這物理層的東西。主角在行走的時候通過自己的座標原點計算出自己在二位元組中的索引,然後根據索引找到數組中的數值 判斷自己是否可以通過。
繪製地圖
根據地圖編輯器產生出來的數組,一定是先繪製背景層地圖,然後在繪製第物理地圖等等。
物理碰撞層產生的數組 是不用繪製的,只需要每次主角移動座標的時候檢測是否與物理層發生碰撞. 背景底層
物理層
碰撞層
說到這裡可能有些朋友會問為什麼第一層要和第二層分開? 這兩層不能合二為一嗎?
:用兩個圖層主要是為瞭解決物理層圖片不能全部顯示,好比下面這個荷花, 它的繪製地區在矩形中 周圍白色的則是透明的地區,所以我們需要先繪製地圖背景層在繪製物理層這樣就可以遮蓋透明地區。
代碼的實現方式
首先我們需要利用onKeyDown()和onKeyUp()方法確定當前手機那個按鍵被按下,根據按鍵資訊更新人物動畫,檢測是否碰撞。
mIskeyDown = true 表示 按下方向鍵下
mIskeyLeft = true 表示 按下方向鍵左
mIskeyRight = true 表示 按下方向鍵右
mIskeyUp = true 表示 按下方向鍵上
mHeroPosX 表示人物的X座標
mHeroPosY 表示人物的Y座標
mAnimationState 表示播放動畫的ID 因為人物行走有4組方向的動畫 所以 mAnimationState 可以修改播放那組動畫
- /** 根據按鍵更新顯示動畫 **/
- /** 在碰撞數組中尋找看自己是否與地圖物理層發生碰撞 **/
- if (mIskeyDown) {
- mAnimationState = ANIM_DOWN;
- mHeroPosY += HERO_STEP;
- } else if (mIskeyLeft) {
- mAnimationState = ANIM_LEFT;
- mHeroPosX -= HERO_STEP;
- } else if (mIskeyRight) {
- mAnimationState = ANIM_RIGHT;
- mHeroPosX += HERO_STEP;
- } else if (mIskeyUp) {
- mAnimationState = ANIM_UP;
- mHeroPosY -= HERO_STEP;
- }
主角每次移動的時候我們還需要檢測一下他的X Y座標是否超出螢幕
如果超出螢幕則保持他目前的位置不變
- /** 檢測人物是否出屏 **/
- isBorderCollision = false;
- if (mHeroPosX <= 0) {
- mHeroPosX = 0;
- isBorderCollision =true;
- } else if (mHeroPosX >= mScreenWidth) {
- mHeroPosX = mScreenWidth;
- isBorderCollision =true;
- }
- if (mHeroPosY <= 0) {
- mHeroPosY = 0;
- isBorderCollision =true;
- } else if (mHeroPosY >= mScreenHeight) {
- mHeroPosY = mScreenHeight;
- isBorderCollision =true;
- }
主角應該有兩個座標點
: 為什麼主角要有2個座標點的原因是 左上方的00點程式是不能進行邏輯判斷的 比如檢測主角向右移動走超出螢幕,因為座標點在左上方 所以整個圖片都走出螢幕以後程式才能判斷出人物出屏, 所以不能用左上方的點來作為主角的座標原點,須要用下面的點來計算人物的邏輯座標 我的建議是我們只計算下面這個點然後根據這個點在算出來圖片左上方的原點,然後在通知映像繪製。
判斷碰撞檢測
mCollision[][]這個二維數是地圖編輯器產生出來的,用來組儲存碰撞層的所有資訊 -1表示不能通過
mHeroIndexX 、mHeroIndexY 代表當前人物在二位元組中的索引位置,根據索引找到二維數組中的值判斷是否碰撞
mBackHeroPosX、mBackHeroPosY 備份發生碰撞前人物的座標 一旦碰撞以後將使用備份的座標 避免人物碰撞後不能返回。
- if (mCollision[mHeroIndexY][mHeroIndexX] == -1) {
- mHeroPosX = mBackHeroPosX;
- mHeroPosY = mBackHeroPosY;
- isAcotrCollision = true;
- } else {
- mBackHeroPosX = mHeroPosX;
- mBackHeroPosY = mHeroPosY;
- isAcotrCollision = false;
- }
我用我寫的一個碰撞的demo和大家展示一下遊戲碰撞的效果
與實體層發生碰撞
與實體層發生碰撞
與地圖邊界發生碰撞