欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

HTML5游戏实战之拼图游戏(包含关卡)

程序员文章站 2023-11-06 23:50:16
拼图游戏是每个人小时候都玩过的经典休闲游戏,依托hola studio强大的图片功能和事件回调体系,实现一个游戏性十足的拼图游戏并不难。本文就介绍整个游戏的制作过程,本游戏包含完整的游戏元素,包括广...

拼图游戏是每个人小时候都玩过的经典休闲游戏,依托hola studio强大的图片功能和事件回调体系,实现一个游戏性十足的拼图游戏并不难。本文就介绍整个游戏的制作过程,本游戏包含完整的游戏元素,包括广告、关卡、分享等元素,你可以自行添加其他游戏元素,也可以将素材替换成你需要的元素。

游戏截图
HTML5游戏实战之拼图游戏(包含关卡)

扫描二维码
HTML5游戏实战之拼图游戏(包含关卡)

游戏链接

导入为你的项目

游戏界面的编辑

游戏主要有四个界面
HTML5游戏实战之拼图游戏(包含关卡)
我们只介绍游戏界面的编辑,其他界面的编辑在之前的博客中已经都介绍过,可以说,用hola studio编辑界面简直是再容易不过的事,甚至可以交给策划来做。

游戏界面

游戏界面的控件树形图如图所示:
HTML5游戏实战之拼图游戏(包含关卡)

而界面效果图:
HTML5游戏实战之拼图游戏(包含关卡)vcg9upy8ysbocmvmpq=="http://studio.holaverse.cn/cantk/docs/zh/index.html">uigridviewx控件,作为拼图游戏小图块的起始和目的。

图片的操作

拼图游戏免不了跟图片的打交道,关于图片更多的便捷操作和技巧,可以参考链接关于jim写的番外。

图片的存储

在我们的拼图游戏中,是分为多关卡的,每个关卡一张图片,这些关卡的图片都可以存在图片控件的备用图片中。如下图所示:
HTML5游戏实战之拼图游戏(包含关卡)

图片的切割

我们的游戏中,每个图片都被切割成4x4个小图片,然后拼成一张大的,我们不可能又傻又天真,真用ps之类工具去切割成图片。借助hola studio强大的图片操作,我们可以采用如下方式切割图片:

        var selection = "#r"+rows+"c"+cols+"i"+index;
        image.setimagesrc(imagesrc + selection);

其中rows是你向切割的总行数,cols是总列数,index是次序,imagesrc是图片的链接,image就是图片控件了,是不是非常简单。另一种切割图片的方法是:

        var selection = "#x"+x+"y"+y+"w"+w+"h"+h;
        image.setimagesrc(imagesrc + selection);

其中x,y就是起始点相对于原始图片原点的位置,w,h就是切割的宽高了。

图片的切换

每个关卡完成以后,要切换到下一张图片,可以采用如下方法

image.setvalue(imageindex);

这里的imageindex就是备用图片的序号了。参考uiimage

图片的拖动

如果你熟悉hola studio就知道hola studio有强大的事件代码入口,比如onclick,onbeforeopen等等,你只需要将代码写道事件里即可。但是对于资深的游戏开发者来说,这种方式显得有点不够“高大上“,今天就着重介绍另一种熟知编辑事件回调的方法——addeventlistener

在我们的游戏中,这些个小图片封装成了一个类pimage

function pimage(element) {
    this.element = element; //element就是图片控件
    //处理拖动事件
    element.addeventlistener("pointerdown", this.ondragstart.bind(this));
    element.addeventlistener("pointermove", this.ondragmove.bind(this));
    element.addeventlistener("pointerup", this.ondragend.bind(this));

    element.pimage = this;
}

//跟另外一个pimage交换图片资源
pimage.prototype.exchangeimage = function(pimage) {
    var src = this.element.getimagesrc();
    this.element.setimagesrc(pimage.element.getimagesrc());
    pimage.element.setimagesrc(src)
}

pimage.prototype.canhandleevent = function(event) {
    if(event.beforechild || !this.element.getimagesrc()) {
        return false;
    }
    var container = this.element.getparent();
    var controll = container.seats.getcontroll();
    return !controll.startinfo || controll.startinfo.element == this.element;
}

pimage.prototype.ondragstart = function(event) {
    if(!this.canhandleevent(event)) {
        return;
    }
    this.startp = {x:event.point.x, y:event.point.y};
    var container = this.element.getparent();
    var point = this.converteventpoint(event.point);
    container.seats.getcontroll().onpick(this, point);

    this.element.setopacity(0);
    this.ondragmove(event);
};

pimage.prototype.ondragmove = function(event) {
    if(!this.canhandleevent(event)) {
        return;
    }

    var point = this.converteventpoint(event.point);
    point.x -= this.startp.x;
    point.y -= this.startp.y;
    var container = this.element.getparent();
    container.seats.getcontroll().onmove(this, point);
};

//转换坐标,因为拖动控件是相对当前小图片,要转换为相对于场景坐标
pimage.prototype.converteventpoint = function(point) {
    var p = this.element.getpositioninwindow();
    var parent = this.element.getparent();
    var x = p.x + point.x - parent.getxoffset();
    var y = p.y + point.y + parent.getyoffset() ;
    p = {x:x, y: y};

    return p;
};

pimage.prototype.ondragend = function(event) {
    console.log(this.element.name, "pointup");
    if(!this.canhandleevent(event)) {
        return;
    }
    var point = this.converteventpoint(event.point);

    var container = this.element.getparent();

    container.seats.getcontroll().onput(this, point);
};

图片的容器封装

拼图游戏中的起始容器和目的容器分别是一个uigridviewx控件,需要做一些封装。

//这是公共类
function seats(container) {
    this.container = container;
    if(container) {
        container.seats = this;
    }
    return this;
}

seats.prototype.initcontainer = function() {
    return this;    
}

seats.prototype.onput = function(pimage, point) {
}

seats.prototype.getcontroll = function() {
    return this.controll;
}

seats.prototype.setcontroll = function(controll) {
    this.controll = controll;
}

seats.prototype.onpick = function(pimage, point) {
}

seats.prototype.onmove = function(pimage, point) {
}

seats.prototype.oncancel = function(pimage, point) {
}

seats.prototype.onremove = function(element) {
}
//这是起始容器
function sourceseats(container) {
    seats.call(this, container);
    this.pimages = [];
    return this;
}

sourceseats.prototype = new seats();
sourceseats.prototype.constructor = sourceseats;

sourceseats.prototype.init = function(baseimage, rows, cols) {
    console.log("sourceseats.prototype.init");
    var container = this.container;
    var pimages = this.pimages;
    var indexs = [];
    var num = rows * cols;
    for(var i = 0; i  0.5 ? 1 : -1;
    });
    var imagesrc = baseimage.getimagesrc();
    baseimage.setvisible(true).setenable(true);
    indexs.foreach(function(index) {
        var child = baseimage.clone();
        container.addchild(child);
        child.setimagescale(0, 0);
        var selection = "#r"+rows+"c"+cols+"i"+index;
        child.setimagesrc(imagesrc + selection);
        pimages.push(new pimage(child));
    });
    container.relayoutchildren();
}

sourceseats.prototype.onremove = function(element) {
    if(element.getparent() != this.container) {
        return;
    }
    var index = this.pimages.indexof(element.pimage);
    this.pimages.slice(index, 1);
    element.remove(true);
    settimeout(function() {
        this.container.relayoutchildren();
    }.bind(this), 0);
}

sourceseats.prototype.onput = function(startinfo, point) {
    var element = startinfo.element;
    var index = startinfo.index;
    var elementatpoint = element.getwindow().findchildbypoint(point, true);

    if(startinfo.seats != this)  {
        //从dest拖到source,创建一个pimage
        var c = element.clone();
        element.setimagesrc(null);
        c.setopacity(100);
        this.container.addchild(c, elementatpoint ? elementatpoint.getzindex() - 1 : this.container.getchildren().length + 1);
        this.pimages.push(new pimage(c));
        settimeout(function() {
            this.container.relayoutchildren();
        }.bind(this), 0);
        this.getcontroll().onputteddone(element, null);
    } else {
        element.setimagesrc(startinfo.imagesrc);
        this.getcontroll().onputteddone(element, elementatpoint);
    }
}
//这是目标容器
function destseats(container) {
    seats.call(this, container);
    this.pimages = [];
    return this;
}

destseats.prototype = new seats();
destseats.prototype.constructor = destseats;

destseats.prototype.init = function(baseimage, rows, cols) {
    var container = this.container;
    var pimages = this.pimages;
    var num = rows * cols;
    container.setcols(cols);
    container.setrows(rows);
    baseimage.setenable(true).setvisible(true);
    for(var i = 0; i 
//游戏控制类,处理游戏逻辑的
gamecontroll = function(win) {
    this.win = win;
    this.gametime = 0;
    win.find("计时器控件").stop();
    win.find("计时器").setvalue("00:00s");
}

gamecontroll.prototype.initgame = function(rows, cols) {
    var win = this.win;

    this.sourceseats = new sourceseats(win.find("选图框").getchild(0));
    this.destseats = new destseats(win.find("底图框架").getchild(0));

    this.cols = cols;
    this.rows = rows;
    this.sourceseats.setcontroll(this);
    this.destseats.setcontroll(this);
    var level = this.readgamelevel();
    var baseimage = win.find("selecting-image");
    var max_level = 11;
    if(level >= max_level) {
        level = 0;
    }
    baseimage.setvalue(level);
    //初始化两个容器
    this.sourceseats.init(baseimage, rows,  cols);
    this.destseats.init(baseimage, rows, cols);
    baseimage.setvisible(false).setenable(false);
    this.baseimage = baseimage;
    this.gamelevel = level;
    win.find("迷宫答案").setimagesrc(baseimage.getimagesrc());
};

gamecontroll.prototype.readgamelevel = function() {
    var value = webstorage.get("game-level");
    value = parseint(value);
    return isnan(value) ? 0 : value; 
}

gamecontroll.prototype.writegamelevel = function(level) {
    //存储游戏进度
    webstorage.set("game-level", level);
}

gamecontroll.prototype.showgametime = function() {
    this.gametime++;
    var win = this.win;
    var min = 0;
    var sec = 0;
    min = math.floor(this.gametime/60);
    sec = this.gametime%60;

    if (min = rect.x && point.x = rect.y && point.y