前言
上一篇文章我实现了第三个BOSS,蜂后,这个boss实际上跟眼珠子没有什么大区别,不过还是有一些需要斟酌写好的,无论是什么,就算他再简单也好,也总是有他的意义。我觉得搞这样的练习最重要还是体会过程,积累一些经验。最后总会有收获的。本来我是想写一些新的东西的,但是最后发现自己技术实在是有限,所以还是继续搞一下基础的,逐层递进。慢慢来。好了,开始本次练习记录。
Boss
一般来说,设计Boss肯定是要多设计几个小怪的,但是这次我直接设计这个boss,不设计太多小怪,这次选择的boss是来自泰拉瑞亚的克脑,这个boss的有趣的点就是他会让玩家陷入一个叫做“混乱”的异常状态。让玩家的方向键相反。这个似乎可以通过unity的刚体速度改变实现。先回顾一下我这个小恐龙的移动逻辑。
private Vector3[] direction = new Vector3[]{
Vector3.right,Vector3.up,Vector3.left,Vector3.down
};
private KeyCode[] keys = new KeyCode[] {
KeyCode.D,KeyCode.W,KeyCode.A,KeyCode.S
};
上面这两段代码是我这个小恐龙移动的最基本的逻辑,通过两个数组,一个存放KeyCode,一个存放记录速度,那么只要设置一个for循环不断检查哪个按键按了,然后利用一个dirHeld变量,使得小恐龙直接获得一个对应的速度变量。
想法一:
在Boss里面的脚本实现这个功能,由于unity里面对于输入流的检测是共通的,因此,我的第一个设想,是直接在Boss的脚本里面,检测输入,然后使其获得相反的速度。那样就可以得到一个混乱的效果。
Input.GetKey(KeyCode.A)------>dinoRig.velocity = Vector3.right;
想要以这样的方法实现,然后通过unity面板里面的脚本顺序设定其执行顺序,可能可以实现这样的效果。
但是最后以失败告终,无论怎么调节都好,都没有任何效果。最后发现这样的核心逻辑是错误的,因为unity对象的脚本并行执行的时候,无论如何都会是的dino的dirheld回到正确的按键,假设是Boss先,那么按键检测到,更改了速度,下一个恐龙脚本执行就会变回原来的速度,要是恐龙的脚本先执行,在后面Boss的脚本又跟改了速度,紧接着还是恐龙的脚本,而且在恐龙的脚本里面,每一次开始我都会把dirHeld重置为-1。
最后这个想法以失败告终
想法二:
现在是第二个想法,在恐龙的脚本里面添加一个isPlz的变量,检测是否处于混乱状态,如果是的话,那就检测dirheld,将对应的编号调转。那么就需要在Boss的脚本里面。将dino脚本实例化,这个耶不困难,因为,基本每一个Boss都保留则恐龙的实例化对象,只需要执行GetComponent这个泛化函数就可以了。
一开始的设想就是用if来执行,但是忽略了,if是顺序执行的,那么判断完前面后面那个依然会再次判断。
if(dirHeld==0){dirHeld=2;}
if(dirHeld==2){dirHeld=0;}
这就出现了无论如何都只会让dirHeld为0,不过可以直接通过goto?但是书上说goto不能乱用。
所以应该使用switch,而且switch的执行是 比较迅速的。代码修改为:
switch(dirHeld)//改用switch
{
case 0:
dirHeld = 2;
break;
case 2:
dirHeld = 0;
break;
default:
break;
}
}
就这样,混乱效果就可以顺利执行了。
然后为了让玩家知道自己混乱了,就随便画了个?的图标,以及Boss释放混乱的信号:
使用的贴图图如下:
新小怪:飞眼
这个小怪本来在游戏里就是Boss的小弟,我也顺理成章地把他加进去,在游戏里,他会一直绕着Boss转,冲向玩家。但是冲向玩家地怪太多了。所以我模仿书里地实例,让他以左右飘动地形式从上往下移动,会配合Boss地混乱攻击。
这玩意实现比较简单直接上代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class flyEyes : MonoBehaviour
{
[Header("Set in Inspector")]
private Rigidbody rig;
public int facing;
public float timePast;
public float timeNow;
// Start is called before the first frame update
void Start()
{
rig = GetComponent<Rigidbody>();
rig.velocity = Vector3.down;
facing = 1;
timeNow = Time.time;
timePast = 1f;
}// Update is called once per frame
void Update()
{
Vector3 Pos = gameObject.transform.position;
if (Pos.y <= 1f)
{
Destroy(gameObject);
}
if(Time.time - timeNow >= timePast)
{
timeNow = Time.time;
rig.velocity = new Vector3(facing * 2f, -1, 0);
if(facing == 1)
{
facing = -1;
}
else
{
facing = 1;
}
}}
}
这是使用的贴图:
Boss实现
这个boss不需要跟往常一样,盯着玩家或者转向。因为他本来就是对称的。
移动逻辑:在四个方向瞬移,并且不断向玩家靠近,靠近玩家到一定程度就会瞬移到别的地方。朝玩家靠近是为了阻挠玩家躲避,不是为了攻击。
攻击三个:分别是召唤五个小弟从天上飘下来
让玩家陷入混乱状态,并召唤三个小弟
跟三个分身夹击玩家。
实现都比较简单,而且这次我直接使用函数了,不像之前那样全部堆在update里面。
下面是代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class KBrain : MonoBehaviour
{
[Header("Set in Inspector")]
public GameObject dino;
public Vector3 dinoPos;//恐龙坐标恐龙位置
public float timeNow;
public float timeSum;
public float timeLive;
public float timePast;
public GameObject brainShadow;//这个是对象
public GameObject what;
public GameObject flyEyes;//飞眼小弟
public GameObject wavePre;//波
public Vector3 standNext;
public int roll;//技能选择
public bool canMove;//是否可以到处移动
public Rigidbody rig;//记录刚体
private Vector2[] sumplace = new Vector2[] {
new Vector3(5,5),new Vector3(5,-5),new Vector3(-5,5),new Vector3(-5,-5)
};//需要使用到这个
private Vector3[] transPlace = new Vector3[]
{
new Vector3(32.5f,8.4f,0),new Vector3(17.2f,8f,0),new Vector3(17.2f,2f,0),new Vector3(32.5f,2f,0)
};//每过一次就瞬移到这个位置
public Vector3 vel;
private bool isRush;
private bool isTrack;
public Rigidbody dinoRig;
public int sumNum;//记录影子的站位对应的数组
public Vector3 sum;
public int tranNum;
public Vector3 flyPos;
public bool isPlz;
public bool hasPlz;
public float plzzTime;
private Vector3 Pos;
public Dino dinoM;
public int test;// Start is called before the first frame update
void Start()
{
dino = GameObject.Find("dino");
dinoPos = dino.transform.position;
sum = new Vector3(32.5f, 8.4f, 0);
gameObject.transform.position = sum;//一开始生成位置
timeNow = Time.time;//获取初始时间
timeSum = Time.time;
timeLive = 60f;
timePast = 3f;
standNext = dinoPos;//这次的逻辑为一直向玩家靠近,到时间再换点
vel = Vector3.zero;
isRush = false;
isTrack = false;
rig = GetComponent<Rigidbody>();
dinoRig = dino.GetComponent<Rigidbody>();
canMove = true;
tranNum = 0;
flyPos = new Vector3(20f,9.5f,0);
isPlz = false;
hasPlz = false;
plzzTime = 0;
Pos = gameObject.transform.position;
dinoM = dino.GetComponent<Dino>();
}// Update is called once per frame
void Update()
{
if(Time.time - timeSum >= timeLive)
{
GameObject wav = GameObject.Find("wave1(Clone)");
if (wav != null)
{
Destroy(wav);
}
GameObject wat = GameObject.Find("what(Clone)");
if (wat != null)
{
Destroy(wat);
}
dinoM.isPlz = false;
Destroy(gameObject);
}
dinoPos = dino.transform.position;
if (canMove == true)
{
Move();
}
if(Time.time - timeNow >= timePast)//这个是表示开始释放技能
{
Skill();
}}
void transNumPlus()
{
if(tranNum == 3)
{
tranNum = 0;
}
else
{
tranNum++;
}
}
void Move()
{
dinoPos = dino.transform.position;
standNext = dinoPos;//获得下一个目标
Pos = gameObject.transform.position;
if ((gameObject.transform.position - standNext).magnitude <= 2f||Pos.x>=33f||Pos.x<=16f)
{//到达了目的地
rig.velocity = Vector3.zero;
gameObject.transform.position = standNext;//停止移动
transNumPlus();
gameObject.transform.position = transPlace[tranNum];}
else
{
vel = standNext - gameObject.transform.position;
vel.Normalize();
rig.velocity = vel * 2f;
}
}
void Skill()
{
canMove = false;
switch(roll)//根据这个变量选择技能
{
case 0:
for(int i = 0; i < 5; i++)
{
GameObject flye = Instantiate(flyEyes);//生成flyeyes
Vector3 tem = flyPos;
tem.x += 2 * i;
tem.y += 0.5f * i;
flye.transform.position = tem;
}
canMove = true;
timeNow = Time.time;//重置时间
roll = Random.Range(0, 3);//一共三个技能
break;
case 1:
if (isTrack == false)
{
dinoPos = dino.transform.position;
standNext = dinoPos;standNext.y += 2f;
vel = standNext - gameObject.transform.position;
vel.Normalize();
rig.velocity = vel*5f;
isTrack = true;
}
if (isTrack == true)
{
if((gameObject.transform.position - standNext).magnitude <= 0.1f)//到达目的位置
{
rig.velocity = Vector3.zero;
gameObject.transform.position = standNext;//固定位置
isPlz = true;
}
if (isPlz == true)
{
if (hasPlz == false)
{
GameObject plzWave = Instantiate(wavePre);//生成
Vector3 plztem = gameObject.transform.position;
for(int i = 0; i < 3; i++)
{
GameObject flp = Instantiate(flyEyes);
Vector3 tem = flyPos;
tem.x += 3 * i;
flp.transform.position = tem;
}
plztem.y += 1.5f;//使得对象显示在上面,目前不是很清楚图层咋用
plzWave.transform.position = plztem;
Instantiate(what);
plzzTime = Time.time;//获取时间
hasPlz= true;
}
GameObject wt = GameObject.Find("what(Clone)");
if (wt != null)//同步混乱符号
{
Vector3 tem2 = dino.transform.position;
tem2.x -= 0.12f;
tem2.y += 0.7f;
wt.transform.position = tem2;
}
dinoM.isPlz = true;//反转的方法修改为此
if(Time.time - plzzTime >= 5f)//时间到了
{//以下为重置改变过的的变量
Destroy(wt);
GameObject wave = GameObject.Find("wave1(Clone)");
if(wave != null)
{
Destroy(wave);
}
hasPlz = false;
isPlz = false;
isTrack = false;
timeNow = Time.time;
canMove = true;
dinoM.isPlz = false;
roll = Random.Range(0, 3);
}
}}
break;
case 2:
if (isTrack == false) {dinoPos = dino.transform.position;//获得恐龙坐标
Vector3 pppos = dinoPos;
pppos.x += sumplace[0].x; pppos.y += sumplace[0].y;
gameObject.transform.position = pppos;
vel = dinoPos - pppos;
vel.Normalize();
rig.velocity = vel * 5f;
isTrack = true;
}
if (isRush == false)
{
for (int i = 1; i < 4; i++)
{
GameObject sdw = Instantiate(brainShadow);
Vector3 sp = dinoPos;
sp.x += sumplace[i].x; sp.y += sumplace[i].y;
sdw.transform.position = sp;
Rigidbody sr = sdw.GetComponent<Rigidbody>();
Vector3 sv = dinoPos - sp;
sv.Normalize();
sr.velocity = sv * 5f;
};
isRush = true;
}
Vector3 POS = gameObject.transform.position;
if (POS.x <= 16f || POS.y <= 1f)
{
isRush = false;
isTrack = false;
timeNow = Time.time;
canMove = true;
roll = Random.Range(0, 3);
}
break;
}
}
}
这是使用的贴图:
下面是效果图,还是不会传视频,是不是一定要把视频传上b站或者优酷才可以放在这里面啊,不是很懂。
test
上面是个视频,还没有加碰撞,所以是无敌的,虽然感觉效果不怎么样,但是作为练习,也让我有所收获了。我还会继续添加东西,但是快过年了,可能会休息一段时间,在这里拜个早年!祝大家新年快乐!万事如意 !谢谢大家的支持!