关于写81款国学游戏的初衷,一是为了传承国学,因为那是我们的根,也是未来人们可以创新和革命的根本。革命就是革新,革命的基础就是有命可以革。二是为了让那些想学习游戏开发的人提供参考,三是为了让自己写的游戏更有价值,我的目标就是写够81款和国学相关的游戏。四是计划写完81款就不再写游戏了。
闲话不说了,开始我们的国学游戏之旅,第一篇,我选择做拼图游戏,游戏算法不是太复杂,适合入门。古诗词也是我们的国粹,这两者结合应该不错,所以就开始诗词拼图创作。
先看游戏截图
游戏说明
将诗句随机打乱然后让玩家拼图,玩家可以点击五角星查看提示,也可以点击绿色喇叭听诗词朗读。拼图成功也可以进入下一首诗,当然也可以直接进入下一首诗词的拼图。当然你也可以配置其他类型的拼图,游戏代码是可拓展的。
游戏代码说明
游戏采用phaser开发,当然你也可以采用egret和layabox开发。换汤不换药,核心算法不变即可。
游戏代码展示
(function(){
var game;
window.onload = function() {
var w=window.innerWidth;
var h=window.innerHeight;
var config=null;
if(w>h){
config = {
"width": 640,
"height": 1136,
"renderer": Phaser.CANVAS,
"parent": '',
"resolution": 4
};
}else{
config = {
"width": w,
"height": h,
"renderer": Phaser.CANVAS,
"parent": '',
"resolution": 4
};
}
game = new Phaser.Game(config);
game.state.add("PlayGame", playGame);
game.state.start("PlayGame");
}
var shiku=[{index:0,name:"登鹳雀楼",cd:"唐代",author:"王之涣",kind:5,sj:"白日依山尽黄河入海流欲穷千里目更上一层楼",audio_key:"dgql_mp3"},
{index:1,name:"池上",cd:"唐代",author:"白居易",kind:5,sj:"小娃撑小艇偷采白莲回不解藏踪迹浮萍一道开",audio_key:"chishang_mp3"},
{index:2,name:"静夜思",cd:"唐代",author:"李白",kind:5,sj:"床前明月光疑是地上霜举头望明月低头思故乡",audio_key:"jys_mp3"},
{index:6,name:"江雪",cd:"唐代",author:"柳宗元",kind:5,sj:"千山鸟飞绝万径人踪灭孤舟蓑笠翁独钓寒江雪",audio_key:"jiangxue_mp3"},
{index:7,name:"夏日绝句",cd:"宋代",author:"李清照",kind:5,sj:"生当作人杰死亦为鬼雄至今思项羽不肯过江东",audio_key:"xrjj_mp3"},
{index:8,name:"春晓",cd:"唐代",author:"孟浩然",kind:5,sj:"春眠不觉晓处处闻啼鸟夜来风雨声花落知多少",audio_key:"chunxiao_mp3"},
{index:3,name:"清明",cd:"唐代",author:"杜牧",kind:7,sj:"清明时节雨纷纷路上行人欲断魂借问酒家何处有牧童遥指杏花村",audio_key:"qingming_mp3"},
{index:4,name:"咏柳",cd:"唐代",author:"贺知章",kind:7,sj:"碧玉妆成一树高万条垂下绿丝绦不知细叶谁裁出二月春风似剪刀",audio_key:"yongliu_mp3"},
{index:5,name:"小池",cd:"宋代",author:"杨万里",kind:7,sj:"泉眼无声惜细流树阴照水爱晴柔小荷才露尖尖角早有蜻蜓立上头",audio_key:"xiaochi_mp3"},
];
var playGame = function(game){};
playGame.prototype = {
preload: function(){
game.load.image("ks", "res/ks.png");
game.load.image("lb", "res/lb.png");
game.load.image("lz", "res/lz.png");
game.load.image("bg", "res/bg2.jpg");
game.load.audio("dgql_mp3", "res/dgql.mp3");
game.load.audio("jys_mp3", "res/jys.mp3");
game.load.audio("yongliu_mp3","res/yongliu.mp3");
game.load.audio("qingming_mp3", "res/qingming.mp3");
game.load.audio("chishang_mp3", "res/chishang.mp3");
game.load.audio("xiaochi_mp3", "res/xiaochi.mp3");
game.load.audio("jiangxue_mp3", "res/jiangxue.mp3");
game.load.audio("xrjj_mp3", "res/xrjj.mp3");
game.load.audio("chunxiao_mp3", "res/chunxiao.mp3");
game.stage.backgroundColor=0xffc773;
game.scale.pageAlignHorizontally = true;
game.scale.pageAlignVertically = true;
game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
},
create: function(){
this.game_init();
var me=this;
var ks=game.add.button(this.w/2,this.h/2,'ks',function(){
ks.destroy();
me.game_start();
});
ks.anchor.set(0.5,0.5);
//ks.rotation=0.5*Math.PI;
},game_start:function(){
var me=this;
this.sk_index=0;
this.si=shiku[this.sk_index];
//创建方块
this.fk_gs=5;
this.create_kk(this.fk_gs);
game.input.onUp.add(function(){
me.fx=me.fx_pd();
me.can_mv(me.fx);
},this);
},create_kk:function(k){
var k_w=this.w*0.9/k;
this.border.clear();
this.border.beginFill(0xfffffb,0.15);
this.border.drawRoundedRect(this.w*0.05,this.h*0.05,this.w*0.9,this.h*0.9,10);
this.border.endFill();
this.fk_group.removeAll();
this.sz=[];
var jsq=0;;
var sjz=this.get_sjz((k*k));
for(var j=0;j<k;j++){
var sza=[];
for(var i=0;i<k;i++){
var kk=game.make.graphics();
kk.beginFill(0x123,0.55);
kk.drawRect(0,0, k_w-2, k_w-2);
kk.endFill();
jsq=sjz[Math.floor(Math.random()*sjz.length)];
if(jsq!=(k*k)){
var fk=this.fk_group.create(game.world.centerX-(k/2)*k_w+i* k_w,j* k_w+this.h*0.1,kk.generateTexture());
fk.name="fk"+i+"n"+j;
var wz=game.make.text( k_w/4, k_w/4,""+jsq,{ font: "bold 10px Arial", fill: "#00ff00"});
wz.anchor.set(0.5,0.5);
fk.addChild(wz);
var wzs=game.make.text( k_w/2, k_w/2,""+this.si.sj.charAt(jsq-1),{ font: "bold 20px Arial", fill: "#fff"});
wzs.anchor.set(0.5,0.5);
fk.addChild(wzs);
fk.i=i;
fk.j=j;
fk.val=jsq;
sza.push(jsq);
}else{
sza.push(0);
}
sjz.splice(sjz.indexOf(jsq),1)
}
this.sz.push(sza);
}
jsq=null;
sjz=null;
var me=this;
this.psp=null;
this.get_szm();//为判断胜负做准备
this.fk_group.setAll('inputEnabled', true);
this.fk_group.callAll('events.onInputDown.add', 'events.onInputDown', function(e){
me.psp=e;
});
var name=game.make.text(this.w/2,this.h*0.05,this.si.name,{ font: "bold 22px Arial", fill: "#fff"});
name.anchor.set(0.5,0.5);
this.fk_group.addChild(name);
var author=game.make.text(this.w/2,k_w*(this.fk_gs+1.8),this.si.cd+":"+this.si.author,{ font: "bold 16px Arial", fill: "#fff"});
author.anchor.set(0.5,0.5);
this.fk_group.addChild(author);
//语音
this.bf_mp3=game.add.audio(this.si.audio_key);
var lb=game.make.button(this.w*0.8,this.h*0.05,'lb',function(){
if(!me.bf_mp3.isPlaying){
me.bf_mp3.play();
lb.tint=0xff0000;
me.bf_mp3.onStop.add(function(){
lb.tint=0x00ff00;
},me);
}
});
lb.tint=0x00ff00
lb.anchor.set(0.5,0.5);
lb.scale.set(3,3);
this.fk_group.addChild(lb);//作者
//文字
var tip=game.make.button(this.w*0.2,this.h*0.05,'lz',function(){
if(me.can_dj){
me.draw_sj();
me.can_dj=false;
}
});
tip.anchor.set(0.5,0.5);
tip.scale.set(3,3);
this.fk_group.addChild(tip);//作者
var pre_t=game.make.text(this.w*0.2,this.h*0.9,"上一首",{font: "bold 18px Arial", fill: "#fff"});
pre_t.anchor.set(0.5,0.5);
pre_t.inputEnabled=true;
pre_t.events.onInputDown.add(function(){
me.pre_lv();
},this);
var next_t=game.make.text(this.w*0.8,this.h*0.9,"下一首",{font: "bold 18px Arial", fill: "#fff"});
next_t.anchor.set(0.5,0.5);
next_t.inputEnabled=true;
next_t.events.onInputDown.add(function(){
me.next_lv();
},this);
this.fk_group.addChild(pre_t);
this.fk_group.addChild(next_t);
},get_sjz:function(a){
var sj=[];
for(var i=1;i<=a;i++){ sj.push(i);}
sj.sort(function(a, b){ return Math.random() > 0.5 ? -1 : 1;});
return sj;
},
pd_win:function(){
if(this.yssj.toString()==this.sz.toString()){
this.next_lv();
return true;
}else{
return false;
}
},get_szm:function(){
this.yssj=[];
var jsq=0;
for(var i=0;i<this.fk_gs;i++){
var sza=[];
for(var j=0;j<this.fk_gs;j++){
jsq++;
if(jsq!=(this.fk_gs*this.fk_gs)){
sza.push(jsq);
}else{
sza.push(0);
}
}
this.yssj.push(sza);
}
jsq=null;
},next_lv:function(){
//下一关
if(this.sk_index<shiku.length){
this.sk_index++;
this.si=shiku[this.sk_index];
this.fk_gs=this.si.kind;
this.create_kk(this.fk_gs);
}else{
this.sk_index=0;
this.si=shiku[this.sk_index];
this.fk_gs=this.si.kind;
this.create_kk(this.fk_gs);
}
},pre_lv:function(){
//上一关
if(this.sk_index>0){
this.sk_index--;
this.si=shiku[this.sk_index];
this.fk_gs=this.si.kind;
this.create_kk(this.fk_gs);
}else{
this.sk_index=shiku.length-1;
this.si=shiku[this.sk_index];
this.fk_gs=this.si.kind;
this.create_kk(this.fk_gs);
}
}
,fg_zfc:function(str,num){
if(str == null || str == undefined) return null;
if(!(/^[0-9]*[1-9][0-9]*$/.test(num))) return null;
var array = new Array();
var len = str.length;
for(var i=0;i<(len/num);i++){
if((i+1)*num > len){
array.push(str.substring(i*num,len));
}else{
array.push(str.substring(i*num,(i+1)*num));
}
}
return array;
}
,draw_sj:function(){
var me=this;
var gra=game.make.graphics();
gra.beginFill(0xffffff,0.95);
gra.drawRoundedRect(0,0,this.w*0.9,this.h*0.8,20);
var namea=game.make.text(0,-this.h*0.3,this.si.name,{ font: "bold 25px Arial", fill: "#000000"})
namea.anchor.set(0.5,0.5);
var nb=game.make.text(0,-this.h*0.3+50,this.si.cd+":"+this.si.author,{ font: "bold 15px Arial", fill: "green"})
nb.anchor.set(0.5,0.5);
var ju=this.fg_zfc(this.si.sj,this.si.kind);
var sjy="";
for(var i=0;i<ju.length;i++){
sjy+=(ju[i]+"\n");
}
var siju=game.make.text(0,-this.h*0.3+150,sjy,{ font: "bold 20px Arial", fill: "orange"});
siju.anchor.set(0.5,0.5);
var bt=game.make.button(this.w/2,this.h/2,gra.generateTexture(),function(){
bt.destroy(true);
me.can_dj=true;
});
bt.anchor.set(0.5,0.5);
bt.addChild(namea);
bt.addChild(nb);
bt.addChild(siju);
this.fk_group.addChild(bt);
},
game_init:function(){
this.w=game.world.width;
this.h=game.world.height;
this.bg=game.add.sprite(this.w/2,this.h/2,'bg');
this.bg.rotation=0.5*Math.PI;
this.bg.anchor.set(0.5,0.5);
this.bg.width=this.h*4;
this.bg.height=this.w*4;
this.border=game.add.graphics();
this.fk_group=game.add.group();
this.fx=null;
this.bf_mp3=null;
this.can_dj=true;
},
fx_pd:function(){
var x =game.input.activePointer.position.x -game.input.activePointer.positionDown.x;
var y =game.input.activePointer.position.y -game.input.activePointer.positionDown.y
this.du=Math.atan2(x,y);
x=null;
y=null;
if(this.du>-Math.PI/4&&this.du<=Math.PI/4){
return "down"
}else if(this.du>Math.PI/4&&this.du<=Math.PI*3/4){
return "right"
}else if(this.du>Math.PI*3/4&&this.du<=Math.PI){
return "up"
}else if(this.du>-Math.PI&&this.du<=-Math.PI*3/4){
return "up"
}else if(this.du>-Math.PI*3/4&&this.du<=-Math.PI/4){
return "left"
}
},can_mv:function(fx){
if(this.psp){
if(fx=="down"){
if(this.have_k(this.psp.j+1,this.psp.i)){
console.log("can down");
var j=this.psp.j;
var i=this.psp.i;
var val=this.psp.val;
this.sz[j][i]=0;
this.sz[j+1][i]=val;
var p=this.fk_group.getByName("fk"+i+"n"+j);
if(p){
p.y+=this.w*0.9/this.fk_gs;
p.j+=1;
p.name="fk"+i+"n"+(j+1);
}
i=null;
j=null;
}
}else if(fx=="up"){
if(this.have_k(this.psp.j-1,this.psp.i)){
console.log("can up");
var j=this.psp.j;
var i=this.psp.i;
var val=this.psp.val;
this.sz[j][i]=0;
this.sz[j-1][i]=val;
var p=this.fk_group.getByName("fk"+i+"n"+j);
if(p){
p.y+=-this.w*0.9/this.fk_gs;
p.j+=-1;
p.name="fk"+i+"n"+(j-1);
}
i=null;
j=null;
}
}else if(fx=="left"){
if(this.have_k(this.psp.j,this.psp.i-1)){
console.log("can left");
var j=this.psp.j;
var i=this.psp.i;
var val=this.psp.val;
this.sz[j][i]=0;
this.sz[j][i-1]=val;
var p=this.fk_group.getByName("fk"+i+"n"+j);
if(p){
p.x+=-this.w*0.9/this.fk_gs;
p.i+=-1;
p.name="fk"+(i-1)+"n"+j;
}
i=null;
j=null;
}
}else if(fx=="right"){
if(this.have_k(this.psp.j,this.psp.i+1)){
console.log("can right");
var j=this.psp.j;
var i=this.psp.i;
var val=this.psp.val;
this.sz[j][i]=0;
this.sz[j][i+1]=val;
var p=this.fk_group.getByName("fk"+i+"n"+j);
if(p){
p.x+=this.w*0.9/this.fk_gs;
p.i+=1;
p.name="fk"+(i+1)+"n"+j;
}
i=null;
j=null;
}
}
this.pd_win();
}
},have_k:function(j,i){
if(i>=0&&i<this.fk_gs&&j>=0&&j<this.fk_gs){
if(this.sz[j][i]==0){
return true
}else{
return false;
}
}else {
return false;
}
}
}
})()
游戏代码量不是太大,代码结构 开始使用的是闭包,(function(){ 代码 })()当然也可以不用,但是如果遇到有数据交互的,为了数据安全必须采用,闭包的使用是因为js没有类似Java的package的概念,如果没有闭包的话,你定义的变量,可以在控制台上访问修改,特别不安全。
游戏结构比较简单 preload依旧是加载资源,create中创建游戏,重点关注fx_pd这个方法,里边主要是手势滑动判断的算法。
还有就是group的callAll的使用。可以让group内所有的sprite都被调用。我们拼图的所有图块都放在group中,图块都有编号。
游戏中将诗句分割的方法重点看一下 fg_zfc。对于学习js很有帮助。欢迎留言或探讨,为国学游戏开发助力。