HTML5 2D平台游戏开发——地图绘制篇之Camera

发布时间:2017-7-1 11:29:39编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"HTML5 2D平台游戏开发——地图绘制篇之Camera ",主要涉及到HTML5 2D平台游戏开发——地图绘制篇之Camera 方面的内容,对于HTML5 2D平台游戏开发——地图绘制篇之Camera 感兴趣的同学可以参考一下。

  在庞大的游戏世界中,玩家不能一览地图全貌,而是只能看到其中一部分,并一步步探索,这时就要用到一种技术来显示局部的地图,游戏术语称为摄像机(Camera)。下面两张图中的白色矩形框表示了Camera的作用,玩家控制的角色总是在该矩形内。

可以想像成一个200X100宽高的相框固定在坐标(0,0)处,然后移动下面的蓝纸,蓝纸的不同位置就会显示在相框中。

同时,也只需绘制出现在相框中的地图即可,这样可以提升一部分程序的性能。为实现Camera功能,需要添加一些辅助方法。

改造一下原来的AABB函数:

class AABB {
    /**
     * 碰撞盒子
     * @param x    {number} 盒子x坐标
     * @param y    {number} 盒子y坐标
     * @param w    {number} 盒子宽度
     * @param h    {number} 盒子高度
     */
    constructor(x,y,w,h) {
        this.pos = new Vector(x,y);
        this.size = new Vector(w,h);
        this.center = new Vector(this.pos.x + w / 2,this.pos.y + h / 2);
        this.halfSize = new Vector(this.size.x / 2,this.size.y / 2);

        this.init();
    }

    set(x, y, /*optional*/w, /*optional*/h) {
        this.pos = new Vector(x, y);
        this.size = new Vector(w || this.width, h || this.height);

        this.init();
    }

    init() {
        this.left = this.pos.x;
        this.top = this.pos.y;
        this.width = this.size.x;
        this.height = this.size.y;
        this.right = this.left + this.width;
        this.bottom = this.top + this.height;
    }

    within(r) {
        return r.left <= this.left &&
            r.right >= this.right &&
            r.top <= this.top &&
            r.bottom >= this.bottom;
    }
}

同时新增Camera构造函数:

let AXIS = {};
Object.defineProperties(AXIS,{
    'NONE':{
        value:"none"
    },
    'HORIZONTAL':{
        value:"horizontal"
    },
    'VERTICAL':{
        value:"vertical"
    },
    'BOTH':{
        value:"both"
    }
});

class Camera {
    /**
     * 摄像机构造函数
     * @param level {map} 地图
     * @param x {Number} camera的x坐标
     * @param y {Number} camera的y坐标
     * @param canvasWidth {Number} camera视口宽度
     * @param canvasHeight {Number} camera视口高度
     * @param maxX {Number} camera的最大x坐标
     * @param maxY {Number} camera的最大y坐标
     */
    constructor(level,x,y,canvasWidth,canvasHeight,maxX,maxY) {
        //摄像机左上角的x,y坐标
        this.x = x;
        this.y = y;
        //摄像机的大小
        this.w = canvasWidth;
        this.h = canvasHeight;

        //摄像机开始移动的临界点
        //跟踪对象到摄像机边界的距离
        this.xDeadZone = 0; //距离水平边界的距离
        this.yDeadZone = 0; //距离垂直边界的距离

        //摄像机能够移动的最大范围
        this.maxX = maxX || level.cols - this.w;
        this.maxY = maxY || level.rows - this.h;
        //摄像机移动的方向
        this.axis = AXIS.BOTH;
        //镜头跟随的对象
        this.followed = null;

        //表示camera视口
        this.viewportRect = new AABB(this.x,this.y,this.w,this.h);

        //表示整个地图范围
        this.worldRect = new AABB(0,0,level.cols,level.rows);
    }

    follow(gameObject,xDeadZone,yDeadZone) {
        this.followed = gameObject;
        this.xDeadZone = xDeadZone;
        this.yDeadZone = yDeadZone;
    }

    update() {
        //仅在有跟随对象时更新摄像机位置
        if(this.followed !== null) {
            if(this.axis === AXIS.HORIZONTAL || this.axis === AXIS.BOTH) {
                //根据跟随对象位置更新摄像机的x坐标
                if(this.followed.pos.x - this.x + this.xDeadZone > this.w) {
                    this.x = this.followed.pos.x - (this.w - this.xDeadZone);
                } else if(this.followed.pos.x - this.xDeadZone < this.x) {
                    this.x = this.followed.pos.x - this.xDeadZone;
                }
            }

            if(this.axis === AXIS.VERTICAL || this.axis === AXIS.BOTH) {
                //根据跟随对象位置更新摄像机的y坐标
                if(this.followed.pos.y - this.y + this.yDeadZone > this.h) {
                    this.y = this.followed.pos.y - (this.h - this.yDeadZone);
                } else if(this.followed.pos.y - this.yDeadZone < this.y) {
                    this.y = this.followed.pos.y - this.yDeadZone;
                }
            }
        }

        //重新设置camera视口的x坐标和y坐标
        this.viewportRect.set(this.x,this.y);


        //保证camera不会超出地图范围
        if(!this.viewportRect.within(this.worldRect)) {
            if(this.viewportRect.left < this.worldRect.left) this.x = this.worldRect.left;
            if(this.viewportRect.top < this.worldRect.top) this.y = this.worldRect.top;
            if(this.viewportRect.right > this.worldRect.right) this.x = this.worldRect.right - this.w;
            if(this.viewportRect.bottom > this.worldRect.bottom) this.y = this.worldRect.bottom - this.h;
        }
    }
}

在游戏开始时初始化Camera:

camera = new Camera(levels,0,0,c.width / MAPCONFIG.TILESIZE,c.height / MAPCONFIG.TILESIZE);
camera.follow(player,c.width / 2 / MAPCONFIG.TILESIZE,c.height / 2 / MAPCONFIG.TILESIZE);

渲染地图时只绘制Camera部分:

_drawLayer(layerIndex) {
        let tileSize = MAPCONFIG.TILESIZE,
            startCol = camera.x >> 0,   //起始列
            endCol = Math.floor(startCol + camera.w) + 1,    //结束列
            startRow = camera.y >> 0,   //开始行
            endRow = Math.floor(startRow + camera.h) + 1,    //结束行
            offsetX = -camera.x + startCol,
            offsetY = -camera.y + startRow;

        for (let r = startRow; r < endRow; r++) {
            for (let c = startCol; c < endCol; c++) {
                let tile = this.getTile(layerIndex, c, r),
                    x = (c - startCol + offsetX) * tileSize,  //瓦片的x坐标
                    y = (r - startRow + offsetY) * tileSize;  //瓦片的y坐标

                if (tile !== -1) {
                    this.ctx.drawImage(
                        this.spriteSheet,
                        tile * tileSize % this.dimensions.w,    //瓦片精灵图上的x坐标
                        Math.floor(tile * tileSize / this.dimensions.w) * tileSize, //瓦片精灵图上的y坐标
                        tileSize,
                        tileSize,
                        Math.round(x),
                        Math.round(y),
                        tileSize,
                        tileSize


上一篇:职责链模式
下一篇:爬虫与反爬虫

相关文章

相关评论

本站评论功能暂时取消,后续此功能例行通知。

一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!

二、互相尊重,对自己的言论和行为负责。

好贷网好贷款