上次讲了如何快速显示一张战场地图,有了战场没有军队怎么行,本次来向战场上添加军队。一般战棋游戏中,战场上的军队有三种,我军,敌军和友军。我军是可操纵的,敌军是可攻击的,友军是不可操纵,也不可攻击的。敌军和友军之间会相互攻击。当然,一些更复杂的游戏中,以不同的势力来区分,之间的攻击关系以它们之间的敌对或同盟等关系来决定。
制作开始,军队降临
本脚本中的战棋游戏是以曹操传为参考对象的,军队分我军,敌军和友军,在L#脚本中,添加军队的脚本如下。
//我军添加(我军人员出战序号,面向,坐标x,坐标y,显示或隐藏)
SouSouSCharacter.addOur(0,0,6,6,1);
//敌军添加(人物序号,出场等级,面向,坐标x,坐标y,显示或隐藏,行动AI)
SouSouSCharacter.addEnemy(1,1,0,8,4,1,0);
//友军添加(人物序号,出场等级,面向,坐标x,坐标y,显示或隐藏,行动AI)
SouSouSCharacter.addFriend(2,1,0,6,4,1,0);
上面的脚本分别是,我军添加,敌军添加和友军添加和相关的参数设定。
军队添加的脚本也是下面的脚本之间,且需要再addMap脚本之前。
initialization.start;
initialization.end;
也就是说,军队添加的脚本正确格式如下。
initialization.start;
SouSouSCharacter.addOur(0,0,6,6,1);
SouSouSCharacter.addEnemy(1,1,0,8,4,1,0);
SouSouSCharacter.addFriend(2,1,0,6,4,1,0);
addMap(s01.smap);
initialization.end;
这几个脚本的解析过程如下:
switch(lineValue.substr(0,start)){
case "addMap":
LSouSouObject.sMap.addMap(lineValue.substring(start+1,end).split(","));
break;
case "SouSouSCharacter.addOur":
LSouSouObject.sMap.addOurCharacter(lineValue.substring(start+1,end).split(","));
break;
case "SouSouSCharacter.addEnemy":
LSouSouObject.sMap.addEnemyCharacter(lineValue.substring(start+1,end).split(","));
break;
case "SouSouSCharacter.addFriend":
LSouSouObject.sMap.addFriendCharacter(lineValue.substring(start+1,end).split(","));
break;
default:
LSouSouSMapScript.initialization();
}
为了实现军队的添加,需要预先准备好人物的设定,新建一个chara.json如下
{
"peo1":{
"Index":"1",
"Name":"刘备",
"Face":"0",
"R":"0",
"S":"0",
"Arms":"1",
"Lv":"1",
"Exp":"1",
"Troops":"104",
"Strategy":"30",
"MaxTroops":"104",
"MaxStrategy":"30",
"Force":"78",
"Intelligence":"76",
"Command":"72",
"Agile":"74",
"Luck":"100",
"Skill":"1",
"Introduction":"刘备即蜀汉昭烈帝,字玄德,汉中山靖王刘胜的后代,三国时期蜀汉开国皇帝。"
},
"peo2":{
"Index":"2",
"Name":"关羽",
"Face":"1",
"R":"1",
"S":"1",
"Arms":"4",
"Lv":"1",
"Exp":"1",
"Troops":"107",
"Strategy":"13",
"MaxTroops":"107",
"MaxStrategy":"13",
"Force":"96",
"Intelligence":"90",
"Command":"98",
"Agile":"68",
"Luck":"62",
"Skill":"2",
"Introduction":"关羽本字长生,后改字云长。东汉末年著名将领,自刘备于乡里聚众起兵开始追随刘备,是刘备的结义兄弟,也是刘备最为信任的将领之一。"
},
"peo3":{
"Index":"3",
"Name":"张飞",
"Face":"2",
"R":"2",
"S":"2",
"Arms":"4",
"Lv":"1",
"Exp":"1",
"Troops":"105",
"Strategy":"9",
"MaxTroops":"105",
"MaxStrategy":"9",
"Force":"99",
"Intelligence":"46",
"Command":"74",
"Agile":"72",
"Luck":"76",
"Skill":"3",
"Introduction":"张飞,字翼德,三国时期蜀汉重要将领,自刘备于乡里聚众起兵开始追随刘备,是刘备的结义兄弟,也是刘备最为信任的将领之一。"
}
}
chara.json文件是所有人物数据的设定,本次先暂时添加三个人物,为了方便这些人物数据的管理,先加入一个LSouSouMember类,代码如下
function LSouSouMember(data,flag){
var self = this;
if(data){
self.data = data;
}
}
LSouSouMember.prototype.getIndex = function(){
return this.data.Index;
};
LSouSouMember.prototype.getS = function(){
return this.data.S;
};
当然,上面并不是完整的LSouSouMember类,以后会继续慢慢扩展。曹操传的S战场剧本中,我军加入和敌友军加入有些不同,敌友军出场设定中,第一个参数需要的是人物在chara.json中的序号,而我军出场是由选定出战的我军的人员来决定的,所以第一个参数是我军人员的出场顺序号。我军出场的人员选定,也是由脚本来控制的,不过游戏开发还没到那一步,所以先预先转备好出场人员,以后再进行脚本化。在LSouSouSMap类的构造器中加入我军出场人员,并且添加一个_charaLayer层,来显示战场上的军队,以下是完整的LSouSouSMap构造器。
function LSouSouSMap(){
var self = this;
base(self,LSprite,[]);
LSouSouObject.sMap = self;
self.nodeLength = 48;
self._objectData = null;
self._loadBar = null;
self._mapData = null;
self.mapW = 0;
self.mapH = 0;
self.ourlist = [];
self.enemylist = [];
self.friendlist = [];
self._mapLayer = new LSprite();
self._charaLayer = new LSprite();
self._viewMapLayer = new LSprite();
//暂时添加,后面会脚本化
LSouSouObject.memberList.push(new LSouSouMember(LGlobal.chara["peo1"]));
LSouSouObject.perWarList.push(LGlobal.chara["peo1"].Index);
self.addChild(self._mapLayer);
self.addChild(self._charaLayer);
self.addChild(self._viewMapLayer);
LGlobal.script.scriptLayer.addChild(self);
LSouSouSMapScript.analysis();
}
为了实现军队的添加,给LSouSouSMap类加上下面三个函数,分别用来添加我军,敌军和友军。
LSouSouSMap.prototype.addOurCharacter = function(param){
var self = this;
//判断出战人员是否合法,LSouSouObject.perWarList是我军所选出战人员
if(parseInt(param[0]) >= LSouSouObject.perWarList.length){
LSouSouSMapScript.initialization();
return;
}
var i,mbr,_characterS;
//确定出战人员数据,LSouSouObject.memberList是加入我方的所有人员
for(i=0;i<LSouSouObject.memberList.length;i++){
mbr = LSouSouObject.memberList[i];
if(mbr.getIndex() == LSouSouObject.perWarList[parseInt(param[0])])break;
}
//将出战人员加入到战场中的_charaLayer层
_characterS = new LSouSouCharacterS(mbr,0,parseInt(param[1]),0);
self._charaLayer.addChild(_characterS);
//出战人员位置确定
_characterS.x = parseInt(param[2])*LSouSouObject.sMap.nodeLength;
_characterS.y = parseInt(param[3])*LSouSouObject.sMap.nodeLength;
//出战人员移动目标,人物移动是会用到
_characterS.tagerCoordinate = new LPoint(_characterS.x,_characterS.y);
//出战人员是否隐藏设定
if(parseInt(param[4]) == 0)_characterS.visible = false;
//将出战人员添加到我军人员ourlist数组
LSouSouObject.sMap.ourlist.push(_characterS);
LSouSouSMapScript.initialization();
};
LSouSouSMap.prototype.addEnemyCharacter = function(param){
var self = this;
var i,mbr,_characterS;
//确定出战人员数据
var memberData = LGlobal.chara["peo"+param[0]];
mbr = new LSouSouMember(memberData);
//将出战人员加入到战场中的_charaLayer层
_characterS = new LSouSouCharacterS(mbr,1,parseInt(param[2]),parseInt(param[6]));
self._charaLayer.addChild(_characterS);
//出战人员位置确定
_characterS.x = parseInt(param[3])*LSouSouObject.sMap.nodeLength;
_characterS.y = parseInt(param[4])*LSouSouObject.sMap.nodeLength;
//出战人员移动目标,人物移动是会用到
_characterS.tagerCoordinate = new LPoint(_characterS.x,_characterS.y);
//出战人员是否隐藏设定
if(parseInt(param[5]) == 0)_characterS.visible = false;
//将出战人员添加到敌军人员enemylist数组
LSouSouObject.sMap.enemylist.push(_characterS);
LSouSouSMapScript.initialization();
};
LSouSouSMap.prototype.addFriendCharacter = function(param){
var self = this;
var i,mbr,_characterS;
//确定出战人员数据
var memberData = LGlobal.chara["peo"+param[0]];
mbr = new LSouSouMember(memberData);
//将出战人员加入到战场中的_charaLayer层
_characterS = new LSouSouCharacterS(mbr,1,parseInt(param[2]),parseInt(param[6]));
self._charaLayer.addChild(_characterS);
//出战人员位置确定
_characterS.x = parseInt(param[3])*LSouSouObject.sMap.nodeLength;
_characterS.y = parseInt(param[4])*LSouSouObject.sMap.nodeLength;
//出战人员移动目标,人物移动是会用到
_characterS.tagerCoordinate = new LPoint(_characterS.x,_characterS.y);
//出战人员是否隐藏设定
if(parseInt(param[5]) == 0)_characterS.visible = false;
//将出战人员添加到友军人员friendlist数组
LSouSouObject.sMap.friendlist.push(_characterS);
LSouSouSMapScript.initialization();
};
LSouSouCharacterS类,是战场上的人物类,包含战场上人物的所有行动控制,以及AI属性等,在lufylegend.js引擎中,显示人物动画,一般是用LAnimation类来实现的,但是用LAnimation类来显示动画的时候,使用的图片必须是一张图片,也就是说,人物的所需要播放的动作需要绘制到一张图片上,然后进行切割播放。但是,曹操传中,战场上的人物图片一共分为下面三个
因为要显示的动画,分别分配在三张图片中,所以用LAnimation类来实现的话,就有点麻烦了,所以,这里显示动画,就直接用LBitmap来实现了,只要控制好LBitmap中的LBitmapData对象,同样可以完成动画的显示。看下面的代码
function LSouSouCharacterS(member,belong,direct,command){
var self = this;
base(self,LSouSouCharacter,[]);
self._member = member;
self._belong = belong;
self._direction = direct;
self._command = command;
self.animeList = [];
self.action = 0;
self.actionIndex = 0;
self.image = {};
self.image["atk"] = new LBitmapData(LGlobal.imglist["s-view-atk"]);
self.image["mov"] = new LBitmapData(LGlobal.imglist["s-view-mov"]);
self.image["spc"] = new LBitmapData(LGlobal.imglist["s-view-spc"]);
self.image["mov"].setProperties(0,0,48,48);
self.bitmap = new LBitmap(self.image["mov"]);
self.addChild(self.bitmap);
self.setImage();
}
LSouSouCharacterS.prototype.setImage = function(){
var self = this;
var atklist = LGlobal.divideCoordinate(self.image["atk"].image.width,self.image["atk"].image.height,12,1);
var movlist = LGlobal.divideCoordinate(self.image["mov"].image.width,self.image["mov"].image.height,11,1);
var spclist = LGlobal.divideCoordinate(self.image["spc"].image.width,self.image["spc"].image.height,5,1);
var list;
/*********站立*********/
//下
list = [ "mov", 48, 48, [[movlist[6][0],1]] ];
self.animeList.push(list);
//左
list = [ "mov", 48, 48, [[movlist[8][0],1]] ];
self.animeList.push(list);
//上
list = [ "mov", 48, 48, [[movlist[7][0],1]] ];
self.animeList.push(list);
//右
list = [ "mov", 48, 48, [[movlist[8][0],-1]] ];
self.animeList.push(list);
/*********移動*********/
//下
list = [ "mov", 48, 48, [ [movlist[0][0], 1], [movlist[1][0], 1] ] ];
self.animeList.push(list);
//左
list = [ "mov", 48, 48, [ [movlist[4][0], 1], [movlist[5][0], 1] ] ];
self.animeList.push(list);
//上
list = [ "mov", 48, 48, [ [movlist[2][0], 1], [movlist[3][0], 1] ] ];
self.animeList.push(list);
//右
list = [ "mov", 48, 48, [ [movlist[4][0], -1], [movlist[5][0], -1] ] ];
self.animeList.push(list);
self.action = self._direction+4;
};
在一个战棋游戏中,战场上的军队可以说是多种多样,每个兵种所用的图片都是不同的,而特殊的人物也有其特殊的形象,所用的图片也是不同的。这样一来,所需要的图片就是比较多的,一个游戏中所用的战场形象可能有几十个甚至上百个,要想快速进入战场的话,就需要预先读取所有形象。在本地游戏中,读取这些图片也是不需要多少时间的,可是在页游上就需要注意了。所以我在添加战场人物LSouSouCharacterS时,预先将人物形象设定为准备好的形象图片,运行后的效果如下。
LSouSouCharacterS类的setImage函数,是将三张人物形象的动作进行分解,将【站立】,【移动】,【攻击】,【防御】......等每一个动作都压入到animeList数组中。本次暂时分解【站立】,【移动】两个动作。前面说了,本次显示人物动画,是直接使用LBitmap对象,通过控制LBitmap对象中的LBitmapData对象来实现动画的播放。在setImage函数中被压入animeList数组中的元素依次为[LBitmapData对象名称,形象的宽,形象的高,动画坐标组 ],其中的动画坐标组是由图片区域坐标以及图片是否翻转组成的一组序列,具体为[ [区域坐标,图片是否翻转], [区域坐标,图片是否翻转] ],这里的区域坐标不太好解释,举个例子,比如下面这个图片。
图中红色矩形框为显示区域,由于每个小动作图片的大小为48x48,则区域坐标为(0,48)。这样一来,如果要播放动画,则将animeList中的相应的动作,对应的区域坐标数组中的元素,依次替换当前的人物的LBitmapData对象,就会实现动画,具体实现的话,先要添加LEvent.ENTER_FRAME事件如下。
self.speed = 2;
self.speedIndex = 0;
self.addEventListener(LEvent.ENTER_FRAME,self.onframe);
onframe函数代码如下
LSouSouCharacterS.prototype.onframe = function(self){
if(self.speedIndex++ < self.speed)return;
self.speedIndex = 0;
var anime = self.animeList[self.action]
var list = anime[3];
if(self.actionIndex >= list.length){
self.actionIndex = 0;
}
var obj = list[self.actionIndex++];
var coordinate = obj[0];
self.bitmap.bitmapData = self.image[anime[0]];
self.bitmap.bitmapData.setProperties(coordinate.x,coordinate.y,anime[1],anime[2]);
self.bitmap.scaleX = obj[1];
};
以上代码,虽然实现了动画的播放,但是所用的图片依然是预先设定的黑色动作图片,所有人物都是一样的,如果要实现战场人物的多样化,只需要根据chara.json数据中的设定,读取相应的战场形象图片,待读取完图片之后,替换掉LSouSouCharacterS类中原来所用的图片就可以了,具体实现如下。
LSouSouCharacterS.prototype.loadImage = function(){
var self = this;
atkLoader = new LLoader();
atkLoader.parent = self;
atkLoader.addEventListener(LEvent.COMPLETE,self.loadAtkOver);
atkLoader.load("images/characters/s/" + self._member.getS() +"/atk.png" + (LGlobal.traceDebug?("?"+(new Date()).getTime()):""),"bitmapData");
movLoader = new LLoader();
movLoader.parent = self;
movLoader.addEventListener(LEvent.COMPLETE,self.loadMovOver);
movLoader.load("images/characters/s/" + self._member.getS() +"/mov.png" + (LGlobal.traceDebug?("?"+(new Date()).getTime()):""),"bitmapData");
spcLoader = new LLoader();
spcLoader.parent = self;
spcLoader.addEventListener(LEvent.COMPLETE,self.loadSpcOver);
spcLoader.load("images/characters/s/" + self._member.getS() +"/spc.png" + (LGlobal.traceDebug?("?"+(new Date()).getTime()):""),"bitmapData");
};
LSouSouCharacterS.prototype.loadAtkOver = function(event){
var self = event.target.parent;
self.image["atk"] = new LBitmapData(event.currentTarget);
};
LSouSouCharacterS.prototype.loadMovOver = function(event){
var self = event.target.parent;
self.image["mov"] = new LBitmapData(event.currentTarget);
};
LSouSouCharacterS.prototype.loadSpcOver = function(event){
var self = event.target.parent;
self.image["spc"] = new LBitmapData(event.currentTarget);
};
人物形象读取完之后,将图片替换后的效果如下
测试连接如下
http://lufylegend.com/demo/test/lsharp/09/game/index.html
以上,本章就先讲这么多了,下一章讲一讲战场上的寻路算法,让军队在战场上进行移动。
本章为止的源码如下,不包含lufylegend.js引擎源码,请自己到官网下载
http://lufylegend.com/demo/test/lsharp/09/09.rar
※源码运行说明:需要服务器支持,详细请看本系列文章《序》和《第一章》
《游戏脚本的设计与开发》系列文章目录
http://blog.csdn.net/lufy_legend/article/details/8888787
分享到:
相关推荐
基于unity3d的游戏程序,适合计算机专业哟西方向的学生作为毕业设计和课程设计
基于Unity3D开发的一款3D回合制战棋游戏,内含源码以及资源,在Unity中导入包即可使用。 其实现功能如下: 1,通过qweasd六个按钮以及鼠标来控制场景视野。 2,回合制控制玩家角色移动,攻击,释放技能。 3,游戏...
J2me战棋游戏源码,非Android版,源代码来自国外,注释全是英文的,以前的手机游戏,运行于Java环境的手机系统下,也就是J2me框架内的游戏源码。
简单的安卓战棋游戏,安卓移动开发课程设计/Android期末大作业 - 运行中有什么问题可以私聊博主,本人高级安卓工程师,主页置顶有常见爆红解决的方法,以及更多代码项目 ## 项目备注 1、该资源内项目代码都经过测试...
课程设计基于Python+PyQt5实现的战棋游戏源码.tar课程设计基于Python+PyQt5实现的战棋游戏源码.tar课程设计基于Python+PyQt5实现的战棋游戏源码.tar课程设计基于Python+PyQt5实现的战棋游戏源码.tar课程设计基于...
dev-c++开发的全鼠标操作控制台战棋,完整源代码,使用了最短路径算法,alpha-beta剪枝策略等,其中最后一版的战力相当可以,来尝试一下?
一个用c++开发的3D战棋游戏 3D技术值得大家学习一下
介绍了战棋游戏设计方案、游戏世界的素材设计与实现以及游戏程序的设计流程,在J2ME Wireless Toolkit 2.2的手机模拟器中进行仿真,将游戏打包下载到手机上进行实机测试。实验结果表明,设计的游戏功能完整、运行...
游戏实现了类似英雄无敌3 中战斗场景的回合制玩法: - 增加了六边形地图的实现 - 对战双方每个生物每一轮有一次行动机会,可以行走或攻击对方。 - 每个生物属性有:行走范围,速度,生命,伤害,防御,和攻击。 - 当...
完整的游戏项目,战棋类,coco2d-x开发的,可以提供大家参考。
游戏实现了类似英雄无敌3 中战斗场景的回合制玩法: - 对战双方每个生物每一轮有一次行动机会,可以行走或攻击对方。 - 每个生物属性有:行走范围,速度,生命,伤害,防御,和攻击。 - 当把对方生物都消灭时,即...
基于Python实现的战棋游戏源码.zip基于Python实现的战棋游戏源码.zip基于Python实现的战棋游戏源码.zip基于Python实现的战棋游戏源码.zip基于Python实现的战棋游戏源码.zip基于Python实现的战棋游戏源码.zip基于...
一个战棋游戏源码,制作相当精美,一个下战棋的游戏,希望大家会喜欢
内核Rootkit是运行在操作系统内核空间的恶意程序,对系统安全构成巨大威胁。研究表明,内核Rootkit的共同特征是修改内核的程序控制流程。分析了Linux内核中影响程序控制流程的资源,并通过对这些资源进行保护,来...
基于Java的联机对战棋类游戏.zip基于Java的联机对战棋类游戏.zip 基于Java的联机对战棋类游戏.zip基于Java的联机对战棋类游戏.zip 基于Java的联机对战棋类游戏.zip基于Java的联机对战棋类游戏.zip 基于Java的联机对...
模仿超级机器人大战写一款战棋类游戏,使用cocos2d移植到iphone上
游戏实现了类似英雄无敌3 中战斗场景的回合制玩法: - 对战双方每个生物每一轮有一次行动机会,可以行走或攻击对方。 - 每个生物属性有:行走范围,速度,生命,伤害,防御,攻击 和 是否是远程兵种。 - 当把对方...
这是我在2013年基于Qt开发的一个战棋类RPG游戏,处于未完成状态。 如何建造 安装Qt。我现在用的版本是Qt 5.14。 在QtCreator中单击Run / Debug。第一次会出现错误提示,别紧张,这是正常的。 注意,如果是macOS,...
一款战棋游戏引擎及基于 ncurses 的 UI, 采用 go 语言开发. 支持调整规则, 设计关卡, 和对接不同类型的 UI