1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > javascript开发HTML5游戏--斗地主(单机模式part1)

javascript开发HTML5游戏--斗地主(单机模式part1)

时间:2024-04-02 14:06:54

相关推荐

javascript开发HTML5游戏--斗地主(单机模式part1)

最近学习使用了一款HTML5游戏引擎(青瓷引擎),并用它尝试做了一个斗地主的游戏,简单实现了单机对战和网络对战,代码可已放到github上,在此谈谈自己如何通过引擎来开发这款游戏的。

客户端代码

服务端代码

(点击图片进入游戏体验)

本篇文章为第一部分,主要包括单机模式的开始布局设计准备。主要内容如下:

斗地主游戏介绍创建工程与主场景单机模式场景布局添加图形资源

一、斗地主游戏介绍

斗地主游戏对于大家应该是算耳熟能详的游戏了,我就简单说明下自己理解的整个游戏的流程。

游戏的主体,如图所示:

二、创建工程与主场景

使用青瓷引擎的编辑器很容易帮我完成整个游戏界面的布局。做这个游戏之前我从事java开发,也做过一段时间的前端开发,对js和前端布局算是比较熟悉。结合官方的手册、demo,我大概花了两三天时间把这些过了遍,尝试修改完善一些demo的内容,接下来我就开始自己尝试做这个游戏了。个人感觉有强大的编辑器,布局可以比较迅速的完成,然后专注地进行逻辑编写。

我的想法是把单机和多人对战分成两个场景,创建项目工程landlord和主场景,其中main是主场景,single是单机版的场景,online是在线对战的场景。

入口与游戏的初始化

在Scripts下创建start.js,并配置为入口脚本,此脚本首先定义了名字空间,将全局的数据都记录在这里。代码如下:

1 // 定义本工程的名字空间 2 qc.landlord = {}; 3 4 // 用来存放所有的全局数据(函数、变量等) 5 window.G = qc.landlord.G = {}; 6 7 // 初始化逻辑 8 qc.initGame = function(game) { 9game.log.trace('Start the game landlord.');10// 将game实例的引用记录下来,方便在其他逻辑脚本模块中访问11G.game = game;12//游戏规则13G.gameRule = new qc.landlord.GameRule();14 15G.online = new qc.landlord.Online();16//AI逻辑17//G.AILogic = new qc.landlord.AILogic();18String.prototype.trim = function() { return this.replace(/(^\s*)|(\s*$)/g,''); };19 };

View Code

点击start.js脚本,在右侧的Inspector面板下点击edit,把start.js拖入并放置到第一的位置就成为入口脚本了。

主场景设计

主场景设计入如图:

在Scripts/ui下创建MainUI.js脚本并挂载在lock节点下挂载(直接拖动脚本防置到节点),主要实现了两个按钮的事件,代码如下:

1 /** 2 * 主场景脚本 3 * @method defineBehaviour 4 */ 5 var MainUI = qc.defineBehaviour('qc.engine.MainUI', qc.Behaviour, function() { 6this.singleBtn = null; 7this.multiBtn = null; 8this.singleScene = null; 9 }, { 10singleBtn : qc.Serializer.NODE, 11multiBtn: qc.Serializer.NODE, 12enterNameBtn : qc.Serializer.NODE, 13backBtn: qc.Serializer.NODE, 14nameField: qc.Serializer.NODE, 15enterNamePanel: qc.Serializer.NODE, 16message: qc.Serializer.NODE, 17singleScene: qc.Serializer.STRING, 18multiScene: qc.Serializer.STRING 19 }); 20 21 // Called when the script instance is being loaded. 22 MainUI.prototype.awake = function() { 23var self = this; 24//单机按钮事件 25self.addListener(self.singleBtn.onClick, function(){ 26 self.game.state.load(self.singleScene, false, function() { 27 //牌组管理 28 G.cardMgr = new qc.landlord.Card(); 29 //玩家本人 30 G.ownPlayer = new qc.landlord.Player('QCPlayer'); 31 G.ownPlayer.isAI = false; 32 var storage = G.game.storage; 33 var ownScore = storage.get('QCPlayer'); 34 G.ownPlayer.score = ownScore ? ownScore : 500; 35 //电脑玩家(左) 36 G.leftPlayer = new qc.landlord.Player('AI_Left'); 37 var leftScore = storage.get('AI_Left'); 38 G.leftPlayer.score = leftScore ? leftScore : 500; 39 //电脑玩家(右) 40 G.rightPlayer = new qc.landlord.Player('AI_Right'); 41 var rightScore = storage.get('AI_Right'); 42 G.rightPlayer.score = rightScore ? rightScore : 500; 43 44 //指定玩家顺序 45 G.ownPlayer.nextPlayer = G.rightPlayer; 46 G.rightPlayer.nextPlayer = G.leftPlayer; 47 G.leftPlayer.nextPlayer = G.ownPlayer; 48 49 //底牌 50 G.hiddenCards = []; 51 //当前手牌 52 G.currentCards = []; 53 }, function() { 54 console.log(self.singleScene + '场景加载完毕。'); 55 }); 56}, self); 57 58//多人对战按钮事件 59self.addListener(self.multiBtn.onClick, function(){ 60 61 var uid = G.game.storage.get('uid'); 62 if(uid){ 63 self.showMessage(self.MSG_WAITING); 64 self.enterGame(uid); 65 } else { 66 var np = self.enterNamePanel.getScript('qc.TweenAlpha'); 67 np.from = 0; 68 np.to = 1; 69 np.resetToBeginning(); 70 self.enterNamePanel.visible = true; 71 np.playForward(); 72 } 73 74}, self); 75 76//确认按钮事件 77self.addListener(self.enterNameBtn.onClick, function(){ 78 var nickname = self.nameField.text.trim(); 79 if(nickname){ 80 self.showMessage(self.MSG_WAITING); 81 var result = G.online.register(nickname); 82 result.then(function(data){ 83 if(data.uid){ 84 G.game.storage.set('uid', data.uid); 85 G.game.storage.save(); 86 self.enterGame(data.uid); 87 } else if(err === G.online.ERR_EXIST_NAME){ 88 self.showMessage(self.MSG_EXIST_NAME); 89 } 90 }).catch(function(err){ 91 if(err === G.online.ERR_EXIST_NAME){ 92 self.showMessage(self.MSG_EXIST_NAME); 93 } 94 }); 95 } 96}, self); 97 98//返回按钮事件 99self.addListener(self.backBtn.onClick, function(){100 var np = self.enterNamePanel.getScript('qc.TweenAlpha');101 np.from = 1;102 np.to = 0;103 np.resetToBeginning();104 //self.enterNamePanel.visible = true;105 np.playForward();106 np.onFinished.addOnce(function (){107 self.enterNamePanel.visible = false;108 }, self);109 window.onbeforeunload = undefined;110}, self);111 };112 113 MainUI.prototype.enterGame = function(uid) {114var self = this;115G.ownPlayer = new qc.landlord.Player(null);116G.ownPlayer.uid = uid;117window.onbeforeunload = function (){118 var warning="确认退出游戏?";119 return warning;120};121G.online.joinGame(G.ownPlayer.uid).then(function(data){122 var player = data.seats ? data.seats[data.ownSeatNo] : data.desk.seats[data.ownSeatNo];123 G.ownPlayer.deskNo = player.deskNo;124 G.ownPlayer.name = player.name;125 G.ownPlayer.seatNo = data.ownSeatNo;126 InitData = data;127 self.game.state.load(self.multiScene, false, function() {128 }, function() {129 console.log(self.multiScene + '场景加载完毕。');130 });131});132 };133 134 MainUI.prototype.showMessage = function(m) {135var self = this;136if(m){137 self.message.text = m;138 self.message.visible = true;139} else {140 self.message.visible = false;141}142 };143 144 MainUI.prototype.MSG_WAITING = '请稍等';145 MainUI.prototype.MSG_EXIST_NAME = '您输入的昵称已被使用,请重试';

View Code

三、单机模式场景布局

游戏主体

斗地主主要的主体就是玩家、纸牌,制作主场景之前,先编写好这两个实体类

玩家类设计:在Scripts/logic创建player.js代码如下:

1 // define a user behaviour 2 var Player = qc.landlord.Player = function (n){ 3var self = this; 4// 玩家名 5self.name = n ? n : 'Player'; 6//是否是地主 7self.isLandlord = false; 8//是否是AI玩家 9self.isAI = true;10//牌组11self.cardList = [];12//下一家13self.nextPlayer = null;14//以下属性用于多人对战15self.uid = null;16self.deskNo = null;17self.seatNo = null;18//是否已经准备19self.isReady = false;20//是否已经离开21self.isLeave = false;22 };23 Object.defineProperties(Player.prototype, {24score: {25 get: function(){26 return this._score;27 },28 set: function(v){29 this._score = v;30 var storage = G.game.storage;31 storage.set(this.name, v);32 storage.save();33 }34}35 });

View Code

牌组类设计:在Scripts/logic/clone创建card.js代码如下:

1 // define a user behaviour 2 var Card = qc.landlord.Card = function (){ 3this.data = [ 4 {icon: 'j1.jpg', type: '0', val: 17}, 5 {icon: 'j2.jpg', type: '0', val: 16}, 6 {icon: 't1.jpg', type: '1', val: 14}, 7 {icon: 't2.jpg', type: '1', val: 15}, 8 {icon: 't3.jpg', type: '1', val: 3}, 9 {icon: 't4.jpg', type: '1', val: 4},10 {icon: 't5.jpg', type: '1', val: 5},11 {icon: 't6.jpg', type: '1', val: 6},12 {icon: 't7.jpg', type: '1', val: 7},13 {icon: 't8.jpg', type: '1', val: 8},14 {icon: 't9.jpg', type: '1', val: 9},15 {icon: 't10.jpg', type: '1', val: 10},16 {icon: 't11.jpg', type: '1', val: 11},17 {icon: 't12.jpg', type: '1', val: 12},18 {icon: 't13.jpg', type: '1', val: 13},19 {icon: 'x1.jpg', type: '2', val: 14},20 {icon: 'x2.jpg', type: '2', val: 15},21 {icon: 'x3.jpg', type: '2', val: 3},22 {icon: 'x4.jpg', type: '2', val: 4},23 {icon: 'x5.jpg', type: '2', val: 5},24 {icon: 'x6.jpg', type: '2', val: 6},25 {icon: 'x7.jpg', type: '2', val: 7},26 {icon: 'x8.jpg', type: '2', val: 8},27 {icon: 'x9.jpg', type: '2', val: 9},28 {icon: 'x10.jpg', type: '2', val: 10},29 {icon: 'x11.jpg', type: '2', val: 11},30 {icon: 'x12.jpg', type: '2', val: 12},31 {icon: 'x13.jpg', type: '2', val: 13},32 {icon: 'h1.jpg', type: '3', val: 14},33 {icon: 'h2.jpg', type: '3', val: 15},34 {icon: 'h3.jpg', type: '3', val: 3},35 {icon: 'h4.jpg', type: '3', val: 4},36 {icon: 'h5.jpg', type: '3', val: 5},37 {icon: 'h6.jpg', type: '3', val: 6},38 {icon: 'h7.jpg', type: '3', val: 7},39 {icon: 'h8.jpg', type: '3', val: 8},40 {icon: 'h9.jpg', type: '3', val: 9},41 {icon: 'h10.jpg', type: '3', val: 10},42 {icon: 'h11.jpg', type: '3', val: 11},43 {icon: 'h12.jpg', type: '3', val: 12},44 {icon: 'h13.jpg', type: '3', val: 13},45 {icon: 'k1.jpg', type: '4', val: 14},46 {icon: 'k2.jpg', type: '4', val: 15},47 {icon: 'k3.jpg', type: '4', val: 3},48 {icon: 'k4.jpg', type: '4', val: 4},49 {icon: 'k5.jpg', type: '4', val: 5},50 {icon: 'k6.jpg', type: '4', val: 6},51 {icon: 'k7.jpg', type: '4', val: 7},52 {icon: 'k8.jpg', type: '4', val: 8},53 {icon: 'k9.jpg', type: '4', val: 9},54 {icon: 'k10.jpg', type: '4', val: 10},55 {icon: 'k11.jpg', type: '4', val: 11},56 {icon: 'k12.jpg', type: '4', val: 12},57 {icon: 'k13.jpg', type: '4', val: 13}58];59 };60 //拷贝牌组,返回一组新的牌组61 Card.prototype.getNewCards = function () {62return this.data.slice(0);63 };

View Code

添加预制

在开始做主场景之前,需要做一些预制(点击我看文档),方便后面调用。主要还是围绕玩家、纸牌进行,引擎在这方面也给我们提供了很强大的支持:

首先是纸牌预制,纸牌比较简单,只是张图片,默认显示的是纸牌的背面图案,我们在图片节点下挂载一个脚本,Scripts/ui下创建CardUI.js并挂载,代码如下:

1 /** 2 * 卡牌规则 3 */ 4 var CardUI = qc.defineBehaviour('qc.engine.CardUI', qc.Behaviour, function() { 5this.isSelected = false; 6this.info = null; 7 }, { 8// fields need to be serialized 9 });10 11 /**12 *显示纸牌,13 *@property info 卡牌信息,14 *@property isSelect 是否选中15 */16 CardUI.prototype.show = function (info, isSelect){17var self = this,18 o =self.gameObject;19if(info){20 o.frame = info.icon;21 o.resetNativeSize();22 o.visible = true;23 self.info = info;24}25 };26 27 /**28 * 选中纸牌,纸牌上移29 */30 CardUI.prototype.onClick = function (){31var self = this;32if(self.isSelected){33 this.gameObject.anchoredY = 0;34} else {35 this.gameObject.anchoredY = -28;36}37self.isSelected = !self.isSelected;38var ui = window.landlordUI ? window.landlordUI : window.olLandlordUI;39if(ui.getReadyCardsKind()){40 ui.playBtn.state = qc.UIState.NORMAL;41} else {42 ui.playBtn.state = qc.UIState.DISABLED;43}44 };

View Code

2、玩家预制:完成之后发现这个并不是很必要,因为是一开始都固定的,游戏中不会添加改动。比如右边玩家,如下图:

每个玩家下都要挂载一个脚本,主要是方便我们后面去查找它的内容,这个比如修改分数,修改手牌数之类的操作,代码如下:

1 // define a user behaviour 2 var PlayerUI = qc.defineBehaviour('qc.engine.PlayerUI', qc.Behaviour, function() { 3// need this behaviour be scheduled in editor 4//this.runInEditor = true; 5this.player = null; 6 }, { 7headPic : qc.Serializer.NODE, 8playerScore : qc.Serializer.NODE, 9cardContainer : qc.Serializer.NODE10 });

View Code

3、信息预制:这个预制只是个文字,做这个预制主要用于叫分出牌的时候,比如给某个玩家显示 2分 、不叫、 不出之类的信息,这样直接加入不需要再去设置字体大小的信息。

布局设计

单机模式场景,我大致划分为以下几个模块,具体可以使用青瓷引擎编辑器打开,这种所见即所得的工具应该很快就能了解整个场景界面的布局设计,如图:

四、添加图形资源

导入图形资源并打包图集(点击我看文档),

将所有的扑克牌图形资源到Assets/atlas/poker@atlas下,身份头像图形资源到Assets/atlas/landlord@atlas,按钮图形资源到Assets/atlas/btn@atlas。

做完这些准备我们就可以进行做发牌的了,我将会在下一篇文章分享这些内容

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。