坦克游戏_经典坦90克大战游戏快来看
工程难度:⭐⭐
关注我们可以获取最新游戏开发资讯解闷。
工程难度:⭐⭐作为红白机时代的经典游戏,90坦克绝对算是年代表作品之一,今天我想用读取配置表的方式复刻一下这儿时的经典1.场景建设首先将准备好的场景素材导入工程,将其中的砖墙的Tag设置为Wall,草地Tag设置为Wall1,水墙设置为Wall2,铁墙Wall3,并在每个物体身上添加Box Collider2D组件,设置三个空节点,用来挂载敌人和玩家和子弹。
上图中白色图片为敌人生成点2.数据配置表作为可拓展、可配置的坦克大战当然离不开配置表的设置,你可以在配置表里面添加一切你想拥有的角色属性或道具属性等等玩家表分析设计:1.需要一个唯一ID来区别表中的数据,方便索引;。
2.需要等级来绑定显示和子弹类型;3.需要图片名称,用来加载图片用;4.需要子弹类型,用来显示不同的子弹效果,及能打穿铁墙和不能;敌人表分析设计:1.需要一个唯一ID来区别表中的数据,方便索引;2.需要等级来绑定显示和子弹类型;
3.需要图片名称,用来加载图片;4.需要子弹类型,用来显示不同的子弹效果,及能打穿铁墙和不能;道具分析:1.添加ID来,方便索引;2.添加图片名称,用来显示道具外形;(勤劳的我,会告诉你就做了一个道具么?)
我的配置表如下:1.玩家配置表
ID为1的玩家,等级为1,外观图片是Character1,子弹种类为12.敌人配置表
ID为1的敌人,等级为1,外观图片是Monster1,子弹种类为1
ID为1的道具,外观图片是Star做好表格之后需要将表格放入Unity中读取,这中间我用了一个小工具将.xlsx格式的文件转化为TXT文本,并放在了Assets根目下,然后用Json插件读取表格信息并写入字典,当游戏中需要对应数据时new一个新的物体出来附上对应的值,从而获取动态数据。
代码方式如下://构造静态数据类,他们的组成与表格对应publicclassStaticMonsterData{publicreadonlystring id;publicreadonlystring level;
publicreadonlystring pictrue;publicreadonlystring buttle;publicfloatValue(string m){float intA;float
.TryParse(m, out intA);return intA; }}publicclassStaticPropData{publicreadonlystring ID;publicreadonly
string Pictrue;}publicclassStaticCharacterData{publicreadonlystring id;publicreadonlystring level;public
readonlystring pictrue;publicreadonlystring buttle;publicfloatValue(string m){float intA;float .TryParse(m,
out intA);return intA; }}publicclassStaticData : MonoBehaviour {publicstatic StaticData Instance;public
Dictionary monsterDictionary;public Dictionary characterDictionary;
public Dictionary propdictionary;voidAwake(){ Instance = this; Init();
LoadSence(); }// 初始化,将表格数据写如字典voidInit(){ monsterDictionary = Load
, StaticMonsterData>>("Monster"); characterDictionary = Load(
"Character"); propdictionary = Load("Prop"); }// 载入场景,并挂载GameMode脚本
voidLoadSence(){var temp = Resources.Load("Sence").gameObject;var sence = Instantiate(temp);
sence.name = temp.name; sence.AddComponent(); }//获取TXT文本并赋值给对应的类,并返回T的类型值;
publicstatic T Load(string name) {string rName = name;string readFilePath= "Assets/" + rName +
".txt";string str; T data = default(T);if (File.Exists(readFilePath)) { StreamReader textData = File.OpenText(readFilePath);
str = textData.ReadLine(); textData.Close(); textData.Dispose(); data = JsonMapper.ToObject(str);
}return data; }}动态数据的获取://建立角色类publicclassRoleData{publicstring id;publicfloat level;public
string picture;publicfloat speed;publicfloat bullet;}//玩家类继承角色类publicclassCharacterData : RoleData{
///建立构造函数,获取静态数据publicstatic CharacterData GetCharacterData(StaticCharacterData data){ CharacterData characterData =
new CharacterData(); characterData.id = data.id; characterData.level = data.Value(data.level);
characterData.picture = data.pictrue; characterData.bullet = data.Value(data.buttle);return
characterData; }}publicclassMonsterData : RoleData{publicstatic MonsterData GetMonsterData(StaticMonsterData data
){ MonsterData monsterData =new MonsterData(); monsterData.id = data.id; monsterData.level = data.Value(data.level);
monsterData.picture = data.pictrue; monsterData.bullet = data.Value(data.buttle);return
monsterData; }}publicclassPropData{publicstring id;publicstring pictrue;publicstatic PropData GetPubicPropData
(StaticPropData data){ PropData propData = new PropData(); propData.id = data.ID; propData.pictrue = data.Pictrue;
return propData; }}3.GameMode当数据获取完毕,场景载入开始时,需要加载玩家角色,敌人角色,道具信息等,并将他们对应的表信息转换成能随时调用的动态信息赋值给他们代码如下:。
voidStart(){ home = gameObject.transform.Find("CharacterHome").gameObject; home1 = gameObject.transform.Find(
"MonsterHome/Home1").gameObject; home2 =gameObject .transform .Find("MonsterHome/Home2").gameObject;
home3 = gameObject.transform.Find("MonsterHome/Home3").gameObject; home4 = gameObject.transform.Find(
"MonsterHome/Home4").gameObject; animator1 = home1.GetComponent(); animator2 = home2.GetComponent();
animator3 = home3.GetComponent(); animator4 = home4.GetComponent();
Init(); }voidCreatMonster(string ID, GameObject Object){var Data = StaticData.Instance.monsterDictionary[ID];
//获取字典中相应key值的静态数据var monsterData = MonsterData.GetMonsterData(Data);//将静态数据转换成动态数据var temp = Resources.Load(
"Monster");var monster = Instantiate(temp, Object.transform); monster.AddComponent().data = monsterData;
//将动态数据赋值给角色 }//获取KEY值为1的静态数据,转化赋值给生成的玩家voidCreatCharacter(){var Data = StaticData.Instance.characterDictionary[。
"1"];var characterData = CharacterData.GetCharacterData(Data);var temp = Resources.Load("Character"
);var character = Instantiate(temp, home.transform); character.AddComponent().data = characterData;
}//随机地点生成道具并赋值voidCreatProp(){var data = StaticData.Instance.propdictionary["1"];var propData = PropData.GetPubicPropData(data);。
var temp = Resources.Load("Prop");var prop = Instantiate(temp,gameObject.transform); prop.transform.position +=
new Vector3(Random.Range(-480, 200),Random.Range(350,-350)); prop.AddComponent().data = propData;
}voidInit(){ animator1.Play("Start", 0); animator2.Play("Start", 0); animator3.Play(
"Start", 0); animator4.Play("Start", 0);//2s后创建敌人 StartCoroutine(OnDelay(2.0f, () => {
CreatMonster("1", home1); CreatMonster("2", home2); CreatMonster(
"3", home3); CreatMonster("4", home4); })); CreatCharacter(); }int times =
0;voidUpdate (){if (isGameover == false) { times++; CreatProp();if (times ==
3) { isGameover = true; } } }IEnumerator OnDelay(float
time, UnityEngine.Events.UnityAction rFunc){yield return new WaitForSeconds(time); rFunc();yield
returnnull; }}效果显示:
4.玩家简单的搭建好玩家模型,设计玩家行为:玩家可以上、下、左、右四个方向移动;每次移动距离为场景中一个墙体的1/2宽度距离;玩家无法穿越障碍;玩家可以发射子弹;玩家可以获得道具;玩家获取道具升级之后可以改变外形和字典效果;
玩家可以死亡;代码如下:voidStart(){//获取玩家模型组件 muzzle = gameObject.transform.Find("MuzzlePiont").gameObject;
rayPiont1 = gameObject.transform.Find("RayPiont1").gameObject; rayPiont2 = gameObject.transform.Find(
"RayPiont2").gameObject; bulletPiont = GameObject.Find("BulletPiont"); animator = gameObject.GetComponent();
bron = gameObject.transform.Find("Image").GetComponent();//调用函数 Init(data); OnPlayAnimation();
}// 播放出生光圈,并在3S后隐藏该组件privatevoidOnPlayAnimation(){ animator.Play("Bron", 0); StartCoroutine(OnDelay(
3, () => { bron.gameObject.SetActive(false); })); }//初始化玩家,画出当前数据下玩家的外形void
Init(CharacterData data){ draw = gameObject.transform.Find("Draw").GetComponent();var image_Show = Resources.Load(
"Image/" + data.picture); draw.sprite = image_Show; }voidUpdate(){//判断当前是正在移动if (OnMove ==
false) {if (Input.GetKey(KeyCode.D)) { OnMove = true; MoveVector =
new Vector3(1, 0, 0); endPosition = transform.position + MoveVector * 25;// 设定每次移动25为1/2墙宽
}if (Input.GetKey(KeyCode.S)) { OnMove = true; MoveVector =
new Vector3(0, -1, 0); endPosition = transform.position + MoveVector * 25; }
if (Input.GetKey(KeyCode.A)) { OnMove = true; MoveVector = new
Vector3(-1, 0, 0); endPosition = transform.position + MoveVector * 25; }if
(Input.GetKey(KeyCode.W)) { OnMove = true; MoveVector = new
Vector3(0, 1, 0); endPosition = transform.position + MoveVector * 25; } }
if (OnMove) { Move(); } Fire(); }voidMove(){//当初始位置和结束位置相等时,可以接受重新输入移动方向。
if ((endPosition - transform.position).magnitude ==0) { OnMove = false;return; }
//转向 Trun(MoveVector);//向移动方向打出两条射线 RaycastHit2D hit1 = Physics2D.Raycast(rayPiont1.transform.position, MoveVector,
0.1f); RaycastHit2D hit2 = Physics2D.Raycast(rayPiont2.transform.position, MoveVector, 0.1f);// 射线 碰撞判定
if (hit1.collider != null || hit2.collider != null) {if (hit1.collider == null) {if
(hit2.collider.tag == "Prop") {if (data.id == "1") {var Data = StaticData.Instance.characterDictionary[
"2"];var characterData = CharacterData.GetCharacterData(Data); data = characterData;
Init(data); }elseif (data.id == "2") {var
Data = StaticData.Instance.characterDictionary["3"];var characterData = CharacterData.GetCharacterData(Data);
data = characterData; Init(data); }
elseif (data.id == "3") {var Data = StaticData.Instance.characterDictionary["4"];var
characterData = CharacterData.GetCharacterData(Data); data = characterData; Init(data);
}else {return; } }if (hit2.collider.tag ==
"Wall1") { transform.position += MoveVector; }else {
OnMove = false; } }elseif (hit2.collider == null) {
if (hit1.collider.tag == "Prop") { Destroy(hit1.collider.gameObject);
if (data.id == "1") {var Data = StaticData.Instance.characterDictionary["2"];var characterData = CharacterData.GetCharacterData(Data);
data = characterData; Init(data); }
elseif (data.id == "2") {var Data = StaticData.Instance.characterDictionary["3"];var
characterData = CharacterData.GetCharacterData(Data); data = characterData; Init(data);
}elseif (data.id == "3") {var Data = StaticData.Instance.characterDictionary[
"4"];var characterData = CharacterData.GetCharacterData(Data); data = characterData;
Init(data); } }if (hit1.collider.tag == "Wall1"
) { transform.position += MoveVector; }else {
OnMove = false; } }else {if (hit1.collider.tag ==
"Prop") {if (data.id == "1") {var Data = StaticData.Instance.characterDictionary[
"2"];var characterData = CharacterData.GetCharacterData(Data); data = characterData;
Init(data); }elseif (data.id == "2") {var
Data = StaticData.Instance.characterDictionary["3"];var characterData = CharacterData.GetCharacterData(Data);
data = characterData; Init(data); }
elseif (data.id == "3") {var Data = StaticData.Instance.characterDictionary["4"];var
characterData = CharacterData.GetCharacterData(Data); data = characterData; Init(data);
} }elseif (hit2.collider.tag == "Prop") {if (data.id ==
"1") {var Data = StaticData.Instance.characterDictionary["2"];var characterData = CharacterData.GetCharacterData(Data);
data = characterData; Init(data); }
elseif (data.id == "2") {var Data = StaticData.Instance.characterDictionary["3"];var
characterData = CharacterData.GetCharacterData(Data); data = characterData; Init(data);
}elseif (data.id == "3") {var Data = StaticData.Instance.characterDictionary[
"4"];var characterData = CharacterData.GetCharacterData(Data); data = characterData;
Init(data); }else {return; }
}if (hit1.collider.tag == "Wall1" && hit2.collider.tag == "Wall1") { transform.position += MoveVector;
}else { OnMove = false; } }
}else { transform.position += MoveVector; } }voidTrun(Vector3 moveVector
){var angel = Vector3.Angle(transform.right, moveVector);//计算当前方向和下一个方向的角度var normal = Vector3.Cross(transform.right, moveVector);
//计算当前向量和下一个移动方向的叉乘得出它们所在平面的垂直向量 angel *= Mathf.Sign(Vector3.Dot(transform.forward, normal));//技算当前向量和下个移动方向向量的点积,并返回正负号赋值给角度
var vector = transform.right.normalized - moveVector.normalized;//计算从下一个方向向量指向当前向量的向量if (vector.magnitude >
0.1f) { transform.Rotate(transform.forward, angel); } }voidFire(){if (Input.GetKeyDown(KeyCode.Space))
{var bulletDemo = Resources.Load("Bullet");var bullet = Instantiate(bulletDemo, muzzle.transform);
bullet.transform.SetParent(bulletPiont.transform); bullet.transform.localScale = Vector3.one;
//如果玩家数据的等级为4则改变自己的子弹效果,并将发射子弹的母体赋值给子弹if (data.level == 4) { bullet.AddComponent().motherObject = gameObject;
}else { bullet.AddComponent().motherObject = gameObject;
} } }// 死亡时将显示晚间外形组件隐藏,播放死亡动画0.3S后摧毁玩家组件publicvoidDie(){ draw.gameObject.SetActive(
false); animator.Play("Die", 0); StartCoroutine(OnDelay(0.3f, () => { Destroy(gameObject);
})); }IEnumerator OnDelay(float time, UnityEngine.Events.UnityAction rFunc){yield return new
WaitForSeconds(time); rFunc();yieldreturnnull; }}效果查看:
5.敌人搭建好敌人模型,设置敌人Ai:敌人可以上、下、左、右四个方向移动;每次移动距离为场景中墙的1/2宽;敌人无法穿越障碍;若没有遇见障碍则随机选择是否继续延当前方向前进,若遇见障碍则随机重新选择移动方向;
敌人可以发射子弹,频率为1.5s一次;敌人可以死亡;代码如下:因为敌人和玩家基本雷同只是把玩家的输入换成了随机数,所以不贴代码了。查看效果:
6.道具搭建好道具模型,设置其功能道具随机生成在地图上;玩家获取道具后,道具消失;因为只有一个道具,模块小没有单独划分模块出来随机生成的体现在GamaMode脚本中体现,玩家获取道具后消失在玩家功能中体现了。
嗯,90坦克的主要玩法差不多也就时这些了,而且所用的数据完全来至配置表,有兴趣的朋友可以自己研拓展,可以增加一些道具啊,或者玩家属性什么的,当然也可以加别的那就看你的脑洞了相关工程和插件已经上传github 。
链接:https://github.com/dingchao12/Deom- THE END -
皮皮关游戏工作室不只是游戏开发教育官网:http://www.levelpp.com/地址:成都市天府三街69号新希望国际B座2117室商务咨询(QQ):109131279报名咨询(QQ):742318116
报名咨询(电话):18080998425报名咨询(微信):aoee1010游戏开发交流群:610475807B站新手教程地址:http://space.bilibili.com/38043731#!/---------
---------课程信息Unity工程师2017年10月班---满员授课中Unity工程师2018年1月班、3月班---预约报名中~点击阅读原文查看更多专栏~
- 标签:
- 编辑:慧乔
- 相关文章
-
坦克游戏_经典坦90克大战游戏这都可以
如果在那个物资匮乏的年代,能有一台红白机,那一定是一件令人艳羡的事情。流行至今的很多经典游戏都脱胎于红白机,像是《超级玛丽》、…
-
权利的游戏第一季_权力的游戏第一季龙妈和马王海边不要告诉别人
编者按:不管《权力的游戏》的结局走向会是如何,也无法妨碍其成为一部值得反复观看的神剧众所周知,因复杂的原因导致国内观众从…
- 权利的游戏第一季_权力的游戏第一季龙妈和马王海边越早知道越好
- 权利的游戏第一季_权力的游戏第一季龙妈和马王海边越早知道越好
- 新开网络游戏排行榜_新开网络游戏一览表原创
- 新开网络游戏排行榜_新开网络游戏一览表一看就会
- 换装游戏_换装游戏女生版墙裂推荐