随着程序越来越复杂,一下章节不能再贴全部代码了,只贴涉及到的部分,但全部代码会在文末给出


子弹这一部分涉及多个知识点:简单归纳如下
1.给刚体施加力量让其移动
2.利用public一个对象,然后界面绑定的方法传递预制体
3.预制体实例化

十四. 子弹

1.初始化

首先,找到子弹素材,将其做成一个预制体

给他添加刚体 和 碰撞盒

创建一个脚本bullet来控制子弹

2.子弹移动

这里我们用另一种方法来让刚体移动 ==>施加力量

        public void BulletMove(Vector2 moveDirection,float moveForce){bulletRigid.AddForce(moveDirection*moveForce);//给子弹添加一个力,它就会受力移动
    }

3.主角脚本绑定子弹预制体

由于主角是发射子弹的主体,所以,发射代码写在主角的脚本中,在主角脚本中如何获得子弹的预制体呢? 我们利用public一个对象,然后界面绑定的方法来传递预制体

首先我们public一个gameobject对象

        public GameObject bulletPreb;

然后,在界面上将子弹的预制体绑定过去

这种方法简单,高效!接下来就是实例化这个预制体

4.发射子弹

比如:我们按下J键,就发射一个子弹

这里用到了预制体实例化的函数Instantiate(); 实例化后调用子弹移动函数,使其移动

                if (Input.GetKeyDown(KeyCode.J)){GameObject bullet= Instantiate(bulletPreb,rubyBody.position,Quaternion.identity);bullet.GetComponent<bullet>().BulletMove(lookVector,300);}

完成了!!!!

但是,效果和我们想象的完全不一样....

效果不尽人意,原因有好几个,我们一个一个的解决

问题1:角色不应该和子弹有刚体碰撞,这里就要把角色和子弹分好层了(其实所有节点创建之时起就都应该分好层)

然后在项目设置中将player和bullet的层间碰撞取消

此外,后来我将bullet之间的碰撞也取消了,这样就能保证某些极端情况下,子弹互相碰撞.

问题2:

效果终于发生了变化,但是子弹怎么不动呢?

而且控制台还报错

问题出在了,子弹初始化的逻辑上

我们获取子弹刚体,不应该在start里 ,而应该在awake里,

这里说一下start和awake的区别:

1.Awake()是在脚本对象实例化时被调用的,而Start()是在对象的第一帧时被调用的,而且是在Update()之前,先执行Awake方法,再执行Start方法
2.脚本的一些成员,如果想在创建之后的代码中立即使用,则必须写在Awake()里面;
3.当脚本设置为不可用时,Awake方法仍然会执行一次,而Start方法则不会执行!
所以我们可以简单理解为:实例物体创建后就awake,执行脚本开始时start,
awake是实例对象的初始化,start是脚本的初始化

这里我们想实例对象创建后立即执行所以应该将此初始化写在awake里

错误的
            private void Awake() {bulletRigid=GetComponent<Rigidbody2D>();}

终于可以了,接下来我们为子弹添加碰撞和自毁程序,在给角色添加射击动画

5. 子弹碰撞和自毁

子弹不能永远的飞行下去,当他碰到别的物体或这飞行一段时间后,应该自毁

首先我们来做飞行一段时间后自毁:

这个很简单

        Destroy(gameObject,2f);  //写在awake里即可  awake两秒后就会自毁

再写碰撞自毁:

            private void OnCollisionEnter2D(Collision2D other) {Destroy(gameObject);}

6. 给角色添加发射动画

再添加角色的射击动画:

                if (Input.GetKeyDown(KeyCode.J)){GameObject bullet= Instantiate(bulletPreb,rubyBody.position,Quaternion.identity);bullet.GetComponent<bullet>().BulletMove(lookVector,300);anim.SetTrigger("launch");  //触发发射动画
        }

其实这里有问题,就是没有限制角色的发射频率,因为此段代码写在update里,所以很好实现.这个功能以后完善.

7. 子弹击中敌人

子弹击中敌人,应该做以下事情,

1.子弹击中消失;

2. 敌人播放被击中的动画 //这里注意,敌人被击中时不要再继续执行移动等动作.

3.敌人播放完动画后消失

我们在敌人脚本中建立了一个布尔变量记录角色被击中的状态

        private bool fixedState;//角色被击中否,为被击中:false 击中了:true

同时在start里初始化为false

        fixedState=false;

再給敌人增加一个函数,当被击中时触发

            public void BeFixed(){anim.SetTrigger("fixed");    //播放击中动画
        fixedState=true;             //将敌人的状态修改为被击中
        Destroy(gameObject,1f);      //1秒后自爆
    }

接下来我们要做的,就是再子弹击中他时触发事件了~

在子弹脚本中:

            private void OnCollisionEnter2D(Collision2D other) {Destroy(gameObject); if(other.gameObject.tag=="Enemy"){                     //判断一下打中的是不是敌人
            other.gameObject.GetComponent<enemy1>().BeFixed(); //敌人被击中调用BeFixed函数
        }}

十五. 敌人特效

在场景中创建一个特效

我们在其属性框中,将其纹理选项打开

选中精灵模式

将下面的特效图片框增加到2

把我们提前准备好的精灵图片传递进去

将开始帧设为0~2随机,这样久能随机上面的两张特效图片了(点后面的小倒三角)

在render选项卡中,选好图层

然后设置特效细节,好多特效参数都能随机,增加趣味性

把模拟空间设为world,可以使得特效挂载在物体上随物体移动时,有火车拉烟的那种效果

设定特效消失的时间点

在shape选项卡中,可以设计特效的形状样式

在color over lifeTime选项卡中,可以设计特效随进程的颜色及透明度变换

如下图:上面的游标是透明度,下面的游标是颜色(设置起来非常简单)

特效调整完毕后,我们将它制作为预制件,将预制件直接挂在想添加特效的节点下即可

特效挂在节点下后,记得调节好特效在父节点坐标系中的位置

这样一只浓烟滚滚的小机器人就做好了

特效在脚本中的管理

比如我们要做机器人被击中后,停止冒烟(因为角色发射的是齿轮,射击是为了帮它修复....)

这里我们用属性面板绑定的方法传递特效

先public一个特效

        public ParticleSystem effectSmoke;   //机器人冒烟特效

再在属性面板中绑定该特效

然后,我们就可以操作和管理此特效了

            public void BeFixed(){anim.SetTrigger("fixed");fixedState=true;Destroy(gameObject,2f);if(effectSmoke.isPlaying) effectSmoke.Stop();}

十六 吃草莓特效

还是同样的配方,创建特效调参数

添加三张素材

这里我们调节形状时选择了圆形

调节基本特效时,把booping关掉,只播放一次

选择爆发选项卡,添加一种爆发

选择 size over LifeTime 控制动画中的元素大小曲线

最后将调到满意的效果做成预制件

再脚本中,我们public一个特效接口,

        public ParticleSystem strawEffect;

在属性面板中将特效预制件传递给它

最后我们想触发时,直接实例化一个特效就可以了

            private void OnTriggerEnter2D(Collider2D other) {if (other.tag=="Player"){if (other.GetComponent<MyRuby>().getHp()<other.GetComponent<MyRuby>().getMaxHp()){other.GetComponent<MyRuby>().changeHp(1);Instantiate(strawEffect,transform.position,Quaternion.identity);  //角色吃草莓时实例化一个特效预制件
                Destroy(this.gameObject);}}}

最终结果,闪闪惹人爱!~

十七. 血条

新建一个UI image

这时,场景会自动建立下面的节点结构

这时我们先要调整血条UI适应屏幕尺寸 在canvas属性里调节

将准备好的素材图给image,并调整好位置

再建一个image 绑定头像 再建一个image充当血条,整体效果如下.

其中血条因为要变化,所以将其图片类型改为填充型,并将填充方式改为水平

最终结构是这样的

接下来,我们写代码:

我们建立一个脚本专门管理UI 名为uicontroller,将它直接挂在canvas上

首先,我们要获取UI相关的数据类型,需要引用UI相关的命名空间

        using UnityEngine.UI;

其次,为了方便多个脚本里调用UI中的函数,我们直接单例一个UI

        public static UIcontroller instance{get;private set;}
void Start(){instance=this;}

然后我们在脚本里写好血条更新的方法

        using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class UIcontroller : MonoBehaviour
{public Image hpBar;   //注意:hpbar采用的绑定法传递
    public static UIcontroller instance{get;private set;}// Start is called before the first frame update
    void Start(){instance=this;}public void HpShow(int nowHp,int maxHp){Debug.Log(nowHp+"?"+maxHp);hpBar.fillAmount=(float) nowHp / maxHp;}
}

然后再主角的脚本中调用这个方法,主角初始化及血量变化时都需要调用此方法

            public void changeHp(int change){RubyHp=Mathf.Clamp(RubyHp+change,RubyMinHp,RubyMaxHp);UIcontroller.instance.HpShow(RubyHp,RubyMaxHp);}

这样血条就制作完成了!

十八 添加音效

  1. 添加背景音乐

建立一个空物体,添加audio source组件,为其audioclip传递事先准备好的bgm

2.添加吃草莓的音效

创建一个管理音效的脚本,里面写好音乐播放的方法,将此脚本单例,方便各处调用

        using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class audioManager : MonoBehaviour
{public static audioManager instance{get;private set;}// Start is called before the first frame update
    void Start(){instance=this;}public void AudioPlay(AudioClip clip){GetComponent<AudioSource>().PlayOneShot(clip);}
}

实例化之后,就可以给大家使用了,

在草莓脚本中,添加一个传递音频的接口,并把对应的素材传递给它

        public AudioClip eatAudioClip;

在碰撞触发时调用音频播放,并给它传递素材音频对象

         audioManager.instance.AudioPlay(eatAudioClip);

3.给角色添加受伤和射击音效,子弹击中音效,原理同上

4.机器人行走音效

给机器人直接加一个Audio source,并给它素材,同时,为了增加立体声效果,应将混合特效调为3D,同时调节播音范围

我们可以在3D声音设置里调整具体效果.

此外,为了增加沉浸感,给主角加一个audio listener 来收声音,把camera的audio listener禁用掉.

5. 主角行走音效

主角受玩家控制,有移动和静止两个状态,所以要做一下判断.此外这段音频较长(相较于update),所以应该判断一下是否在播放,此外停止移动应该立即停止音效.

其他和敌人移动基本一致

            private AudioSource walkAudioSource;private void Start() {walkAudioSource=GetComponent<AudioSource>();}void Update(){if(moveVector.magnitude!=0){lookVector=moveVector;anim.SetFloat("lookX",lookVector.x);anim.SetFloat("lookY",lookVector.y);if(!walkAudioSource.isPlaying){walkAudioSource.Play();}}else{walkAudioSource.Stop();}}

十九 NPC交互

1.创建NPC

首先我们制作一个NPC,这和制作敌人的方法是一样的

然后为其添加碰撞盒.

2.添加主角射线

我们跟NPC交互的思路是:主角发射一束隐藏的射线,碰到NPC时,触发对话.

这里涉及到给主角添加射线束的知识

我们创建一个射线,

        private RaycastHit2D rubyRay;

再在update里设定射线的属性,一直发射射线,如果碰到NPC就会显示对话,我们先测试一下

        rubyRay=Physics2D.Raycast(rubyBody.position,lookVector,1f,LayerMask.GetMask("NPC"));
if (rubyRay.collider!=null){Debug.Log("NPC");}

3. 添加NPC对话框

给NPC加一个UI canvas,这个canvas出现在场景中,所以我们将它的渲染模式改为world space,并设置好大小

然后我们给canvas加一个背景图片 ui image, 图片采用九宫格模式,再设置一下拉伸模式,按住alt,选择将图片铺满画布(由于热键冲突,下面的截图没有按alt)

在给canvas添加一个显示文本的组件 为了显示效果好,给text组件添加了一个outline组件来描边

最终结构

按照上述方法,建立了两个对话框,提示对话框和触发对话框,平时显示提示对话框,触发后显示触发对话框.

给NPC创建一个脚本,里面写好对话框触发方法

        using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class NPC : MonoBehaviour
{public void ShowDialogue(){transform.Find("showCanvas").gameObject.SetActive(true);transform.Find("hideCanvas").gameObject.SetActive(false);Invoke("hideDialogue",4f);                      //对话框会在4秒后自动消失
    }public void hideDialogue(){transform.Find("showCanvas").gameObject.SetActive(false);transform.Find("hideCanvas").gameObject.SetActive(true);}
}

最后在主角脚本中触发这些方法即可

为了防止主角一直发射线消耗性能,改为了用快捷键触发的方式

                if (Input.GetKeyDown(KeyCode.E)){if (rubyRay.collider!=null){rubyRay.collider.gameObject.GetComponent<NPC>().ShowDialogue();}}

二十 子弹数量及UI

用的都是之前的知识和方法,可以毫无难度的自己做出来,

甚至我是直接复制了草莓的预制件,进行了魔改 公用了collectThings脚本和strawberryEffect

以下是部分代码:

主角脚本:

定义了 当前子弹和总子弹变量

            private int currentBullet=10;private int maxBullet=99;

增加了changeBullet方法

            public void changeBullet(int bullet){currentBullet =Mathf.Clamp(currentBullet+bullet,0,maxBullet);UIcontroller.instance.SetBulletTxt(currentBullet,maxBullet);}

武器攻击时做了判断

                if (Input.GetKeyDown(KeyCode.J)){if(currentBullet>0){GameObject bullet= Instantiate(bulletPreb,rubyBody.position+new Vector2(0,0.5f),Quaternion.identity);bullet.GetComponent<bullet>().BulletMove(lookVector,300);anim.SetTrigger("launch");audioManager.instance.AudioPlay(lunachAudioClip);changeBullet(-1);}else{Debug.Log("Out of Bullet!!!");}}

collectThings脚本:

草莓和子弹公用collectThings,代码简单将草莓和子弹区分开.

        using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class collectThings : MonoBehaviour
{// Start is called before the first frame updatepublic ParticleSystem strawEffect;public AudioClip eatAudioClip;private void OnTriggerEnter2D(Collider2D other) {if (other.tag=="Player"){if (other.GetComponent<MyRuby>().getHp()<other.GetComponent<MyRuby>().getMaxHp()){if(gameObject.name=="CollectibleBullet"){other.GetComponent<MyRuby>().changeBullet(10);}else{other.GetComponent<MyRuby>().changeHp(1);}Instantiate(strawEffect,transform.position,Quaternion.identity);audioManager.instance.AudioPlay(eatAudioClip);Destroy(this.gameObject);}}}
}

UIcontroller脚本增加更新子弹显示的方法

            public void SetBulletTxt(int currentBullet,int maxBullet){if(currentBullet<=maxBullet & currentBullet>=0){bulletTxt.text=currentBullet+" / "+maxBullet;}        }

unity2D备忘志(二)相关推荐

  1. Hyperledger Fabric安装问题备忘(二)

    报错信息: Channel name : mychannel Creating channel... CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/githu ...

  2. DELPHI之备忘(二)

    1. DLL的资源释放问题 EXITPROC //******************* //释放资源 //******************* var   dllExit: Pointer; pr ...

  3. python学习知识点备忘(二)

    1.数字类型         Python 有三种不同的数字类型,分别是: 1.1.整数      整数长度是不受限制的,也就是说它是有无限大的精度.         二进制.八进制 .十进制.十六进 ...

  4. Linux 基础命令备忘(二)

    sed 文本编辑 sed 字符串中匹配某个子串 echo $string | sed 's/^.*--port=\([^ ]*\).*$/\1/' 替换文件中的内容 sed -i "s/ol ...

  5. Android实验之实现一个生日备忘簿

    一.实验内容 实现一个生日备忘簿 二.实验目的 1. 学习 SQLite 数据库的使用; 2. 学习ContentProvider的使用; 3. 复习Android界面编程. 三.实验要求 1. 使用 ...

  6. 前端基础知识备忘——parseInt

    先来看一道经常会看到的前端面试题: [1,2,3,4,5,6,7,8,9].map(parseInt) 输出的结果是什么? 很多第一次看到这道题或者是js基础不太牢靠的前端朋友可能会顺口就来,so e ...

  7. Android Activity的launchMode四种启动模式备忘

    Android Activity的launchMode四种启动模式备忘 Android的Activity的启动模式有四种,在AndroidManifest.xml通过配置Activity的androi ...

  8. 备忘: VC++ 自动适用编译两种模式库文件 (DLL, LIB)

    为什么80%的码农都做不了架构师?>>>    一个好的程序设计规划总会有属于自己的基础代码库.重用这些代码库,DLL或LIB方式最好的选择之一.在写新的项目或程序是,我们不可能每次 ...

  9. 机器学习性能改善备忘单

    原文地址:Machine Learning Performance Improvement Cheat Sheet  原文翻译与校对:@姜范波 && 寒小阳  时间:2016年12月. ...

最新文章

  1. 超硬核的 Python 数据可视化教程!
  2. 让GBDT和GNN结合起来:Criteo AI Lab提出全新架构BGNN
  3. javascript事件模型框架
  4. 网站502与504错误分析
  5. 使用VLC和live555MediaServer搭建RTSP服务器
  6. Codeforces 898E Squares and not squares
  7. IPv4地址分类及特征
  8. 深度剖析“GCC编译器编译过程”
  9. 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第1节 基本概念_01maven概述
  10. 步步为营 .NET三层架构解析 五、DAL与IDAL的设计
  11. 【信号检测】基于matlab双稳随机共振微弱信号检测【含Matlab源码 1701期】
  12. web onblur string
  13. 关于爱情——苏格拉底如是说 (转)
  14. pada mysql
  15. 【Halcon 计算点到直线和点到直线延长线的距离】
  16. 做锤子区块链手机的4种方法(行业观察)
  17. 集成——Mac电脑上app自动化测试(Appium + xcode 8.2 + python)环境搭建
  18. 【遥感】时间分辨率:轨道周期 / 运行周期 / 重复周期 / 轨道重访周期 / 重访周期 概念
  19. 嵌入式安防监控项目——前期知识复习
  20. 【Twinkle】软件工程师的职业路线

热门文章

  1. html图片等比缩放
  2. 【C语言】a++和++a
  3. 优酷视频下载方法(20080506)
  4. Unicode汉字编号范围
  5. 史上最强跨平台、多端加密同步神器,你有用过吗?
  6. JZOJ 4245【五校联考6day2】er
  7. html复习第二课(2_34_0910_html)
  8. 上海计算机研究生学校排名,2018考研:计算机专业全球院校排名公布,上海交通大学竟排第一?...
  9. 网吧电脑怎么录屏?分享3种便捷方法,一键录屏
  10. Python绘制成都地铁全线路图!有路线图也搞不清楚啊!