赞
踩
时隔这么久,终于写完了关于兵营的大部分功能,写完的同时,还要感慨一下,从头做一个游戏真的好难啊,到现在也只写完一个一级的兵营,问题也不少,写出来分享一下,目前的代码不是很高深,要是有更好的写法,也请不吝赐教。
上一篇已经介绍了如何建造一座防御塔,选择兵营并建造完成后,关于防御塔还有一些额外操作,比如防御塔升级,兵营的集结点设置,卖出后建造新的防御塔之类,这里只讲一下集结点设置(因为只写完了这个),剩下的后续会补充。
点击集结点的标志后,出现一面跟着鼠标移动的旗帜,移出攻击范围时,旗帜变为一个×号,即无效集结点。关于判断鼠标是否在有效部署范围之内,我用的是碰撞,代码如下
private void OnTriggerEnter2D(Collider2D collision) { if (collision.name == "Flag") { if (FlagStateManager.GetFlagState() != FlagState.Normal) { FlagStateManager.SetFlagState(FlagState.Normal); flag.GetComponent<Image>().sprite = normalFlagSprite; } } } private void OnTriggerExit2D(Collider2D collision) { if (collision.name == "Flag") { if (FlagStateManager.GetFlagState() != FlagState.OutOfRange) { FlagStateManager.SetFlagState(FlagState.OutOfRange); flag.GetComponent<Image>().sprite = outOfRangeSprite; } } }
在这里,旗帜的状态判断不是必须的,不过我为了更清晰的分辨旗帜各个状态下操作加上去了。
void Update() { //设置集结点,士兵向集结点移动 if (flag.activeSelf) { //旗帜跟随鼠标移动 flagRectTransform.anchoredPosition = new Vector3(Input.mousePosition.x - halfFlagSizeDelta.x - flag.transform.parent.GetComponent<RectTransform>().anchoredPosition.x, Input.mousePosition.y + halfFlagSizeDelta.y - flag.transform.parent.GetComponent<RectTransform>().anchoredPosition.y); //集结点在部署范围内 if (FlagStateManager.GetFlagState() == FlagState.Normal) { //鼠标左击确定集结点 if (Input.GetMouseButton(0)) { flag.SetActive(false); flagPosition = new Vector2(flagRectTransform.anchoredPosition.x + halfFlagSizeDelta.x, flagRectTransform.anchoredPosition.y - halfFlagSizeDelta.y); defendRange.GetComponent<RectTransform>().anchoredPosition = flagPosition; if (!defendRange.activeSelf) { defendRange.SetActive(true); } //设置士兵集结点 soliderCommander.GetComponent<SoliderCommander>().SetSoliderRallyPosition(flagPosition); } } } }
上面的代码就是使得旗帜跟随鼠标移动,但是由于旗杆位于图片的两侧
且鼠标始终位于图片右下角,则旗帜的实际位置是鼠标的位置左移1/2的旗帜的宽度,上移1/2的旗帜高度。
关于原作的效果,士兵移动时,保持队形不变,且士兵重生后、巡逻范围没有怪物时也自动移向集结点。我是用向量实现的,士兵小队维持的队形是不变的,那么可以先找出队形的中心,为了简便一些,选取了第一个士兵x轴位置,士兵1和士兵2y轴坐标的中点,那么3个士兵到队形中心的向量就计算出来了,且一直不变,那么设置的旗帜位置,其实就是这个中点的位置,该点加上之前的向量就是设置了新的集结点后的每个士兵的位置。
private void Start() { solider1Controller = soliders[0].GetComponent<SoliderController>(); solider2Controller = soliders[1].GetComponent<SoliderController>(); solider3Controller = soliders[2].GetComponent<SoliderController>(); //设置士兵待机点到旗帜中心的向量 Vector2 solider1IdlePoint = solider1Controller.idlePoint; Vector2 solider2IdlePoint = solider2Controller.idlePoint; Vector2 solider3IdlePoint = solider3Controller.idlePoint; Vector2 soliderTeamCenter = new Vector2(solider1IdlePoint.x, (solider1IdlePoint.y + solider2IdlePoint.y) / 2); flagPosition = soliderTeamCenter; //以下向量加上鼠标设置的旗帜位置就是每个士兵的集结点 solider1PositionToFlag = solider1IdlePoint - flagPosition; solider2PositionToFlag = solider2IdlePoint - flagPosition; solider3PositionToFlag = solider3IdlePoint - flagPosition; }
鼠标点击之后,判断向量的x轴的值来确定士兵移动的方向,根据移动的长度确定士兵移动到指定位置,到达指定位置后,士兵待机。
public void SetRallyPosition(Vector2 position) { timer = 0; moveToFlagVector = new Vector2(0, 0); if (rallyPosition != position) { rallyPosition = position; } //士兵处于待机状态才会受到集结点影响 if (soliderState != SoliderState.Attack) { //士兵与集结点的向量 moveToFlagVector = rallyPosition - soliderRectTransform.anchoredPosition; if (moveToFlagVector.x <= 0) { soliderAnimator.SetInteger("SoliderState", 0); } else { soliderAnimator.SetInteger("SoliderState", 3); transform.GetChild(0).rotation = new Quaternion(0, 0, 0, 1); } soliderState = SoliderState.MoveToFlag; } } void Update() { //当士兵处于待机状态 if (soliderState == SoliderState.Idle) { //每隔一段时间间隔就转换士兵站立姿势 interval += Time.deltaTime; if (interval > 1.5f) { //左右站立姿势随机选择 int randomNum = Random.Range(0, 2); if (randomNum == 0) { if (soliderAnimator.GetInteger("SoliderState") != 1) { soliderAnimator.SetInteger("SoliderState", 1); } } else { if (soliderAnimator.GetInteger("SoliderState") != 2) { soliderAnimator.SetInteger("SoliderState", 2); } } interval = 0; } } //向集结点移动 else if (soliderState == SoliderState.MoveToFlag) { if (timer * moveSpeed < moveToFlagVector.magnitude) { soliderRectTransform.anchoredPosition += moveToFlagVector.normalized * moveSpeed * Time.deltaTime; timer += Time.deltaTime; } else { timer = 0; if (soliderAnimator.GetInteger("SoliderState") == 0) { soliderAnimator.SetInteger("SoliderState", 1); } else if (soliderAnimator.GetInteger("SoliderState") == 3) { soliderAnimator.SetInteger("SoliderState", 2); } soliderState = SoliderState.Idle; } }
关于士兵寻找怪物攻击,我添加了一个关于soliderCommander的脚本,挂载到一个碰撞器上,该脚本下的所有士兵只攻击碰撞器检测到的怪物,而关于分配战斗,我只写了一个最简单的实现,每个士兵随机分配阻击对象。
private void Update() { for (int i = 0; i < soliders.Count; i++) { if (soliders[i] == null) { soliders.Remove(soliders[i]); solidersNumHasChanged = true; } } //当士兵和怪物的数量发生变化,更新战斗队列 if (solidersNumHasChanged || monstersNumHasChanged) { //当没有士兵或者怪物时,无需进行战斗匹配 if (soliders.Count == 0 || monsters.Count == 0) { return; } else { for (int i = 0; i < soliders.Count; i++) { SoliderController soliderController = soliders[i].GetComponent<SoliderController>(); if (soliderController.isReady) { if (soliderController.GetMonsterAttacked() == null) { int monsterID = Random.Range(0, monsters.Count); soliderController.SetMonsterAttacked(monsters[monsterID]); } } } } solidersNumHasChanged = false; monstersNumHasChanged = false; } } public void SetMonsterAttacked(GameObject monster) { if (monster != null) { findMonsterPath = new Vector2(0, 0); monsterAttacked = monster; //当怪兽被选做阻击对象,怪兽停止移动 monsterController = monsterAttacked.GetComponent<MonsterController>(); monsterRectTransform = monsterAttacked.GetComponent<RectTransform>(); monsterController.SetSoliderAttacked(gameObject); //怪兽层级比士兵高,锚点位置要转换到基于怪兽层级的位置 soliderPosition = transform.parent.GetComponent<RectTransform>().anchoredPosition + soliderRectTransform.anchoredPosition; //怪兽从左侧过来 if (monsterRectTransform.anchoredPosition.x <= soliderPosition.x) { //士兵左转动画过渡 soliderAnimator.SetInteger("SoliderState", 0); battlePosition = monsterRectTransform.anchoredPosition + new Vector2(15, 0) - soliderPosition; } else { //士兵右转动画过渡 transform.GetChild(0).rotation = new Quaternion(0, 0, 0, 1); soliderAnimator.SetInteger("SoliderState", 3); battlePosition = monsterRectTransform.anchoredPosition - new Vector2(15, 0) - soliderPosition; } soliderState = SoliderState.FindMonster; } }
寻找怪物的过程用的也是向量,计算当前士兵和分配的怪物进行战斗的位置之间的向量,我的偏移大概是X轴15左右。
else if (soliderState == SoliderState.FindMonster) { if (timer != 0) { timer = 0; } if (monsterAttacked != null) { //士兵向左移动 if (soliderAnimator.GetInteger("SoliderState") == 0) { if (battlePosition.magnitude > findMonsterPath.magnitude) { soliderRectTransform.anchoredPosition += battlePosition.normalized * 2; findMonsterPath += battlePosition.normalized * 2; } else { //达到后攻击 soliderAnimator.SetInteger("SoliderState", 4); soliderState = SoliderState.Attack; } } else if (soliderAnimator.GetInteger("SoliderState") == 3) { if (battlePosition.magnitude > findMonsterPath.magnitude) { soliderRectTransform.anchoredPosition += battlePosition.normalized * 2; findMonsterPath += battlePosition.normalized * 2; } else { soliderAnimator.SetInteger("SoliderState", 5); soliderState = SoliderState.Attack; } } } //攻击目标丢失,返回集结点 else { battlePosition = new Vector2(0, 0); findMonsterPath = new Vector2(0, 0); moveToFlagVector = rallyPosition - soliderRectTransform.anchoredPosition; if (moveToFlagVector.x <= 0) { soliderAnimator.SetInteger("SoliderState", 0); } else { soliderAnimator.SetInteger("SoliderState", 3); transform.GetChild(0).rotation = new Quaternion(0, 0, 0, 1); } soliderState = SoliderState.MoveToFlag; } }
兵营的内容大致就是这些,还有一些代码需要完善,功能也不全,任重而道远啊,还是得继续,期待全部完成之后的效果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。