敌人AI的优化
敌人相撞在一起转向
定义一个2D的触发检测的方法
如果标签是 注意引号 让转向时间计时器瞬间等于4
敌人AI的优化
敌人相撞在一起转向
定义一个2D的触发检测的方法
如果标签是 注意引号 让转向时间计时器瞬间等于4
初始化地图的其他游戏物体
坑:只有tank等移动的要加刚体,他们的碰撞体不用钩Is Trigger
实例化地图
for循环 每个产生20个 让墙多一点
初始化玩家(Born)
拿到变量 得到Born组件 将其createPlayer设置为true,
敌人 一开始三个,之后随机在这三个位置产生
bool值默认false,故不用再设
随机产生敌人的方法
用随机数0~2(0,3)
给一个空间坐标变量
再做判断if位置
再在原来位置加上InvokeRepeating(延时调用的方法)参数:(方法名,延时时间,每隔多久)
编写产生随机位置的方法
一个列表 装已经有东西的位置
private List<Vector3> itemPositionList=new List<Vector3>();
所以在CreateItem方法里要加入,每生成一个要把坐标add进list
itemPositionList.Add(createPosition);
产生随机位置的方法 while循环
//外围一圈不产生游戏物体 x=+-8.3的两列,y=+-4.5这两行
用V3类型的变量来接受随机的位置 随机数的方法
-7.3f,8.3f,-3.5f,4.5f
如果这个位置是空的(再在外面写一个方法)
再把这个V3变量return回去
有东西了则继续while循环
方法//判断列表中是否有这个位置
private bool (判断方法 bool类型返回值) HasThePosition(Vector3 createPos)
z再用一个for循环遍历列表 itemPositionList.Count表示列表长度
if =则return ture 不然则return flase
再在上面调用一下这个方法
if(!HasThePosition(createPosition)) z这个就是ture or flase
不是则返回位置(成功通过查重检测)把这个位置拿了出来
易错别把true写错了
//实例化外围空气墙 y=+-5.5f,x从+-9.3
几个for循环 用来限制移动范围包括子弹
for(float i=-9.3f; i<10.3f;i++)
(i,5.5f,0)
for(float i=-9.3f; i<10.3f;i++)(上下两行)
(i,-5.5f,0)
for(float i=-5.5f; i<6.5f;i++)
(-9.3f,i,0)
for(float i=-5.5f; i<6.5f;i++)
(-9.3f,i,0)
地图的实例化
测量四个角与中点的位置 20*16
create empty--MapCreation 新弄一个gameobjevt做地图孵化器 加同名脚本
框架 1.先拿一下预制体
一个数组 public GameObject[] item; 用来装饰初始化地图所需物体的数组
0 heart 1wall 2barrier 3 出生效果 4河流 5 草 6 空气墙 再拖一下预制体
重点 先把脚本(object)的钩消掉再操作
heart 坐标 0,-8 实例化
在awake方法里(因为要先于所有物体)
Instantiate(item[0], new Vector3(0,-8,0), Quaternion.identity(没有旋转角度);
use walls inclose the heart
wall的坐标 上面一排用一个for循环 坐标中x设一个参i(初始=-1),中间记得加分号
ctrl cv
wall中间有缝调大一点 map 都调的3.2
我自己的坐标自己按位置调
每次实例化出来的东西clone就会散落在hierarchy上 让他们产生在mapcreation下
再封装一个方法 private void CreateItem(GameObject createGameObject,Vector3 createPosition,Quaternion,createRotation四元数)
{
用GameObject变量 itemGo来接收它们
再设置成子物体itemGo.transfrom.setParent(gameObject.transform);
}
再把上面的Instantiate全改成CreateItem
易错别把transform写错了
敌人一产生就应有一个转向,所以把计时器初始值=4
敌人AI的编写 重点
1.删掉 isdefended 和effect相关的 没给拖引用会报空
CD 大于等于3,attack删掉空格
move方法 利用v与h的值 随机数,删掉键盘输入
再弄一个计时器 private float timeValChangeDirection;
在外面 private float v;
private float h;
在move方法里写 计时4秒开始 随机变量一到八 大于5时 尽量往下走,概率提高 num==0往回走
0到2区间向左,3到4向右;
重点行动完一次后要对计时归0
计时没到四秒则累加(记得用fixedDeltaTime)
修复一下子弹的脚本 case Enemy
是玩家子弹时 Die 再销毁自身 tank里面也要补一下,再改一下标签
用同样的产生特效产生两种敌人 复制一个敌人
还要拖图片切换 上右下左
再在born脚本中写下敌人的产生方法 写一个数组 因为要产生多个
public GmaeObject[ ] enemyPrefabList;
再写个bool变量用于区分出生特效(因为用的同一个)
public bool createPlayer;
再在之前的实例化玩家的那个出生方法中加上判断
随机产生 int num = Random.Range(0,2);
Instantiate(enemyPrefabList[num], transform.position,Quaternion.identity);
是0的话就是小坦克,1则是大坦克
再往born里拖引用 再copy几份born 就会产生不一样的,再把其中一个勾选为玩家
再往敌人脚本里拖好公共变量
敌人的制作
利用玩家ctrlD一份直接在上面改 断开预制体连接???
改渲染
添加Enemy脚本 把玩家脚本中的内容全部copy过来
记住要把它拖进script再改,不要中途改
先等等,让敌人脚本钩去掉
给Heart做一个爆炸效果
在Heart脚本里
public GameObject explosionPrefab;拿到爆炸效果的引用(不是拿组件)到时候再拖一下yin'yong
在Die方法中加入
Instantiate(explosionPrefab, transform.position, transform.rotation);标准实例化
先做出生特效 添加Born脚本 播放 销毁 产生玩家
在start里做一个延时调用
Invoke("BornTank",1f);
做一个方法
拿下玩家的引用
public GameObject playerPrefab;
private void BornTank()
{
Instantiate(playerPrefab, transform.position,Quaternion.identity);(无旋转)
}
再延时销毁 Destroy(gameObject, 1f);
再删掉已有的player,bullet等 终于好了太棒了
修复几个bug
补上几个case的碰撞销毁子弹
制作敌人的子弹
ctrlD 一份预制体EnemyBullet 把钩消掉
每次在克隆体里面修改时,记得要在override里面applyall一下 将预制体也改了
区别玩家子弹与敌方子弹
难道要写两个脚本? 二合一 用一个bool值来判断一下是谁的子弹
public bool isPlayerBullet;
再在子弹switch标签里case tank 下 补判断
wall下面是销毁子弹自身与销毁自身
加collision就是碰撞对象
空气墙和障碍则都是只销毁子弹 airbarrier也用barrier的标签 并applyall
heart 新添加一个脚本用于破损状态下的渲染
拿到渲染器的引用 private SpriteRenderer sr;
再拿到被破坏时的图片
public Sprite BrokenSprite;公共变量到时候拖进去
在start里
sr=GetComponent<SpriteRenderer>();记得加括号
在外部封装一个又来一个Die方法 同样的名字
public void Die()
{
sr.sprite=BrokenSprite;
}再找下图片拖进去
再在case下加
collision.SendMessage("Die"); 就会调用Die方法了
每个层级的东西只能作用于自己的层级,所以子弹需要与他们同级
玩家无敌方法与死亡方法的编写
在外面封装一个方法 die
第一步是产生爆炸特效 先要拿到特效的预制体(在外面拿到)
public GameObject explosionPrefab; 要不要加大写
里面也是实例化的方法 与子弹很像
Instantiate(explosionPrefab,transform
在爆炸特效上添加消失脚本
start 里 加销毁 Destroy(gameObject,0.167f);可以加时间
再在玩家物件里 把Explosion预制件拖入script组件的公共变量的空格里
第二步 死亡 Destroy(gameObject);
出生无敌保护
又在外面加一个的bool值变量
private bool isDefended=true; bool值默认为false
受到保护时不会被销毁
再在外面加一个计时器
private float defendTimeVal=3;
再在update里 加上判定方法
如果处于保护状态 受保护时间累减
再判定如果时间小于等于0
再将保护变量改为flase
然后需要屏蔽掉死亡方法中的两个小方法
直接在其前面接个判定其是否受保护的方法是的话直接return掉
再去拿到受保护特效的预制体 才发现预制体的名字好像是随意定的,到时候只需拖进去就行了
Public GameObject defendEffectPrefab;
再把护盾套在玩家身上
先把shield拖到player下面 再reset一下(盾的transform的右边)
怎么让他显示与关闭呢,先把预制件拖进去
再无敌判定下面加上一个专门的语法 来控制
defendEffectPrefab.SetActive(true);
这样就可以在外面控制了
关闭 在flase的关闭语句中 把他改为flase
再在bullet的标签switch里 tank的case下
空气墙制作 标签的添加
物件下面的Tag addtag 进入标签window 编辑添加
Collider2D
collision 触发碰到的物体
在触发方法中加入 switch判断物体标签
一列标签,先搭好框架,到时候再往里填
销毁子弹
空气墙碰撞消失法
复制一个barrier(map) ctrlD 删掉渲染器 AirBarrier 就成没有图像的barrier了
1.声音组件播放不了声音: 可能是游戏窗口中的 Mute Audio是开启的,要关闭他才行
2. AudioSocre 里面的 volume是用来调整声音
播放大小的
第二种变向 绕z轴旋转
现在顺时针旋转是负的度数 因为z轴朝着我们
往右转 -90度 h,v正负负责坦克朝向 再加上子弹的朝向
bulletEulerAngles = new Vector3(0,0,90);
上0(无旋转初始图)下180都可以
子弹的移动 update 同样的移动方法 注意是沿y轴
1,前面先加上个速 度 transform.Translate(transform.up*movespeed*Time.deltaTime,Space.World);(还是世界坐标轴,但如果坦克用的是自身坐标系Space.self,则子弹应用世界坐标轴)不填默认world
此时子弹无cd
2,设一个计时器(player) CD
private float timeVal;
定时
在update 里用 if来判断是否attack
发射后归0 在attack方法里加上
触发检测 trriger
将子弹碰撞器上的is Trigger 勾选
在bullet脚本里
private void OnTriggerEnter//(触发器进入)//2D (Collider2D collision)
一定要加2D
第二种变向 绕z轴旋转
现在顺时针旋转是负的度数 因为z轴朝着我们
往右转 -90度 h,v正负负责坦克朝向 再加上子弹的朝向
bulletEulerAngles = new Vector3(0,0,90);
上0(无旋转初始图)下180都可以
子弹的朝向问题
子弹 也有四张图片
但这里用第二种方法 直接改变图片朝向 当前坦克角度+子弹应该旋转的角度 四元数 (transition里的是欧拉角)
将欧拉角转四元数 语句 坦克的
子弹的 欧拉角是Vector3类型的
给子弹的欧拉角定义一个变量
private Vector3 bulletEulerAngles;Quaternion 四元数
小心双括号 复制代码可能是中文符 括号别打成中文符
坦克的攻击方法 子弹
Attack() 检测空格下的按下 实例化*注意方法应用 Instantiate(子弹的变量,坦克位置,旋转角度(无旋转))一个子弹
拿到子弹预制体的引用(预制体的)
移动优先级 两个不同轴的方向键键一起按变成斜着移动
分开两个输入与运动 先执行V(Y) 再执行h(X)加一个判断代码
谁放前面谁优先
先把目前已经写好的控制移动代码们封装为一个(Move)方法 让FixedUpdate里更加整洁,还可以注释一下
2D 渲染层级 图层 特效>玩家 子弹》河流
sorting 大层级 (default) order 小层级 数值越大越在上面 特效 /草/子弹order设为1
添加子弹素材 拖入 Bullet size 331
碰撞检测
1 添加碰撞器,运动的一方最好有刚体(必须有一方有) 经常性不运动时刚体会休眠
2. 2D与3D 碰撞器不一样
3。最好直接在预制体上操作
4 添加刚体 2D给玩家,记得把重力调为0
把所有map预制体都加上碰撞器(草不用) 小技巧 全选后一起加
穿模问题 碰到map时方向乱套(受到旋转力) 将player刚体中的constraints 勾选Z轴
沿墙走时抖动(帧时间不同问题) 在玩家代码中 添加FixedUpdate(固定物理帧) 把所有有关移动的方法移到里面
并将Tima.deltaTime 改为Tima.fixedDeltaTime注意D大写
控制图片的移动与切换
随方向改变图片朝向
法一 更改图片显示 素材里有顺序各方向图片
改渲染器中的sprite 就能改图片
在代码中拿到sprite的引用
在上面 拿到引用(定义一个变量,再用getcomponent)注意拿引用的特殊写法
拿到要切换的图片的引用 (0,8,16,24上右下左 记好顺序)搞一个数组 直接把这几张图拖到inspector 面板里的数组里
tips 在project 上端把素材排列由一行 改为两行可以显示图片
下面用输入监听变量的返回值 判断一下h/v的正负 if else if h< 0是zuo
图片切换就像变量赋值 此时的数组中括号内的值是拿到数组以后的顺序了
法二 根据不需要的z轴来控制旋转