cocos creator主程入門教程(九)—— 瓦片地圖

 

五邑隱俠,本名關健昌,10年遊戲生涯,現隱居五邑。本系列文章以TypeScript爲介紹語言。

 

這一篇介紹瓦片地圖,在開發模擬經營類遊戲、SLG類遊戲、RPG遊戲,都會使用到瓦片地圖。瓦片地圖地面是通過一個個地磚拼起來的,又分爲45度角和90度角兩種。45度角俗稱2.5D,每個格子都是菱形,而90度角每個格子都是正方形。

瓦片地圖一般包括以下圖層(不一定同時存在,例如一般RPG遊戲沒有背景和自由裝飾層):

1.背景層(大圖拼接的背景)

2.地形層(瓦片格子拼接的地形)

3.建築層(按瓦片格子擺放的建築、地面物品、角色)

4.自由裝飾層(雲朵、煙霧)

除此以外,還需要提供隱藏的層用於編輯數據,控制遊戲邏輯,例如阻擋、擺放區域等,稱爲數據層。其中需要瓦片佈局的有3種圖層:地形層、建築層、數據層。

 

先來說說背景層BgLayer,背景層在美術設計裏是張完整的大圖,爲了避免連續內存太大導致加載失敗,把大圖打碎成等大小的小圖拼接。一般出於性能考慮,小圖長寬選擇爲1024、512、256、128。

設置背景需要提供背景的小圖數組,列數,每張小圖的寬高

public setPieces(fileArr: Array<string>, colCount: number, pieceW: number, pieceH: number, loadAtOnce: boolean = true): void {}

  

如果是在H5平臺,要考慮資源的逐步加載。所以在H5平臺該方法最好只是做佔位,提供方法進行資源加載

public loadPiece(file: string) {}

  

除了加載外,由於玩家在移動地圖時只看到背景的一部分,不在視窗內的應該裁剪掉,所以還要提供方法對背景進行裁剪

public setViewPort(x: number, y: number, w: number, h: number): void {}

  

完全不在視窗的小圖,通過removeFromParent從渲染列表移除。

 

接下來說說基於瓦片佈局的圖層。基於瓦片的圖片我們會擺放一些物品,例如地形層的地形塊、建築層的建築、地面物品、角色。所以在介紹瓦片佈局的圖層前,先介紹下地圖裏的物品。一般包括:

1.地形塊

2.建築、地面物品

3.角色

4.編輯數據

 

先設計一個基類MapItem,定義物品的基本屬性:格子位置、寬高佔格子數、是否可穿越、可否編輯

export class MapItem extends cc.Component {
    protected mGridX: number = 0;
    protected mGridY: number = 0;
    protected mRow: number = 1;
    protected mCol: number = 1;
    protected mCanPass: boolean = true;
    private mEditable: boolean = true;
    private mIsLock: boolean = false;
}

  

地形塊主要是顯示一張一格大小的圖片,一般會先把這些地形圖片合成一張大圖,按照格子大小等分。設計一個TileSet類定義這張合圖的結構

export class TileSet {
    private mId: number = -1;
    private resPath: string = null;
    private tex: cc.Texture2D = null;

    private gridW: number = 0;
    private gridH: number = 0;
    private row: number = 0;
    private col: number = 0;
}

  

每個地形塊Tile引用TileSet裏的資源

export class Tile extends MapItem {
    private mSpr: cc.Sprite = null;
    private mId: number = 0;
    private mTileSetId: number = 0;
    private mIdx: number = 0;
}

  

當然,如果希望地面有幀動畫,也可以讓Tile保存一個幀系列,按順序切換mSpr的spriteFrame屬性。

 

建築要考慮建築、地面物品的方向和操作

export class MapBuilding extends MapItem {
    protected mId: number = 0;
    protected mType: number = 0;
    protected mResType: number = 0; // 0 image, 1 spine
    protected mResPath: string = null;
    protected mDir: number = 0;
    protected mReverse: boolean = false;
}

  

爲了區分擺放和旋轉點,我會給MapBuilding添加兩個子節點,因爲在45角地圖擺放建築時,一般以右下角格子做擺放參考點,但是旋轉是以左上角格子爲參考。

需要注意,在H5平臺,建築的圖片資源應該是動態加載的,在地圖移動時逐漸加載顯示。所以要提供接口對資源進行加載。

public loadRes(): void {}

  

還有點擊範圍,圖片是矩形的,點擊的時候可能是點到了圖片的空白區域,這時後玩家看到的是點擊了後面的建築,如果沒有處理透明區域剔除,實際判斷卻是點擊了前面的建築。對於圖片資源的建築在H5平臺,可以通過使用該圖片相同位置,截取點擊區的一個像素,模擬畫在屏幕該地方,如果getImageData獲取的data[3]不是0,說明點擊到了該建築,否則是點擊了空白區。

 

角色都是spine動畫,是可以運動的物體,需要路徑、速度相關的屬性

export class MapActor extends cc.Component {
    protected mActorId: number = 0;
    protected mResPath: string = null;

    protected mRoadGrids: Array<cc.Vec2> = []; // 路徑
    protected mCurRoadIdx: number = 0;

    protected mSpeed: number = 0; // 設置的行走速度, 跟x方向速度絕對值一樣
    protected mSpeedX: number = 0; // 實時行走X速度
    protected mSpeedY: number = 0; // 實時行走Y速度

    protected mTestActor: boolean = false;
    protected mIsKeepRoad: boolean = false;
    protected mIsPauseWalk: boolean = false;
}

  

編輯數據是不可見的,只有基本的位置信息和相應數據

export class MapDataItem extends MapItem {
    private data: any = null;
}

  

瓦片佈局的圖層有一個基類,負責物品MapItem的添加、刪除、查詢等操作

/**
 * 基於地磚的圖層基類
 * 定義基於地磚圖層基本數據和接口
 */
export abstract class TileBaseLayer extends cc.Component implements GestureListener {
    protected mRow: number = 0;
    protected mCol: number = 0;
    protected mGridW: number = 0;
    protected mGridH: number = 0;
    protected mMapItems: Array<MapItem> = [];

    protected mOriX: number = 0;
    protected mOriY: number = 0;
}

  

對於90度角的地圖,沒有太多複雜的地方需要處理。點擊點到格子的映射是簡單除以寬、高。遮擋是從左往右,從上到下設定zorder。

對於45度角的地圖,點擊點到格子的映射需要用到解析幾何

 

每個點擊點,按照格子寬高比的斜率經過該點作直線,到經過點(oriX,oriY)平行於x軸的直線都有交點,而且交點的距離等於格子的寬度。所以,交點相對於點(oriX,oriY)的距離(x - oriX)可以判斷該點屬於哪行或哪列。對於行,交點可以通過(oriY - touchY)* (gridW / gridH) - (touchX - oriX)。對於列,交點可以通過(touchX -  oriX) + (oriY - touchY)* (gridW / gridH)。(平行、三角形中同樣大小的角的對邊比鄰邊比例一樣)

角色起始在格子中心點,行走的時候,按照格子的寬高比,把速度分解爲x、y兩個方向,這樣角色就能沿着格子走下去。每次走到格子中心時才做站立、繼續行走的處理。

 

遮擋方面,45度角依然是從上到下遮擋

 

要注意的是,建築佔多格,而設置遮擋時只能設置zorder,所以採用的是中心位置方式,把建築中心格子作爲zorder的參照。角色在地圖中行走的時候,按上圖的規則修改角色的zorder,建築的zorder一直不變。

自由裝飾層沒有擺放限制,可以放置雲朵、霧等動畫,增加層次感。

 

瓦片地圖先說到這裏,下一篇我們將介紹A*尋路算法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章