26507人加入学习
(150人评价)
Unity2D 初级案例 - 坦克大战(Unity2017.1)

制作于2017年12月23日

价格 免费

编写产生随机位置的方法

一个列表 装已经有东西的位置

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轴来控制旋转

[展开全文]

控制玩家移动

加载之后再操作

给player 加一个脚本

监听玩家输入的两个float 变量 水平轴 垂直轴

(字符串识别)

tarnsform 用translate 移动 x轴正方向/y轴正方向

h 返回值 1与-1 实现双向移动

定义速度  movespeed 初始值先定个3

(方向*速度*Time.deltaTime(按秒移动而不是按帧移动),Space.World(按世界坐标轴移动));

 

[展开全文]

素材直接拖入

layout 布局

2 by 3

one column lay out

camera 玩家显示体验

   size 8.5     background蓝色  display窗口5:4

素材加工 图集裁剪  

texture type要调成sprite2D and UI  +apply

图片要调成single

图集 multiple

切割   sprite editor  slice  automatic  /grid  by cell/count

小技巧  先用自动模式  拖动方框选定  得出具体数值   再在 grid by cell 中用这个尺寸来切割 关闭 apply

保存场景 建文件夹

主角创建  把图片拖入hierarchy

小技巧  创建cube   把坦克调到与一个tube相似的大小 1平方

sprite renderer精灵渲染器

可以在里面换图片

ctrl+D 复制 换成地图图片 wall

动画

两个文件夹  一个是animator controller, 一个是animator

粗暴法 原地出生四张图片连成动画 点第一张,按shift,在点最后一张,全选了拖到hierarchy 保存

 

 

 

[展开全文]

授课教师

SiKi学院老师

课程特色

图文(2)
视频(31)
下载资料(1)