1.穿透效果
层级(小鸟和弹弓都属于BirdHood层)
前弹弓属于BirdHood层的第3层
后弹弓属于BirdHood层的第1层
小鸟属于BirdHood层的第2层
层级关系小鸟可以在实现穿透效果
- Spring Joint 2D
给弹弓加Rigidbody2D组件
将BodyType改为Kinematic(开启动力学,避免弹弓下落)
将弹弓的RigidBody2D组件给小鸟的Conected Rigid Body
关闭Auto Configure Disstance (游戏运行的时候Distance会自动延长,不会往中心点走,到Distance的距离就不在往前面走)
Distance 小鸟跟弹弓的距离
Frequency 小鸟的抖动(也会影响到小鸟拉伸的力度)
- 给小鸟添加Circle Collider 2D组件
- 添加Bird脚本
添加变量onClicked判断是否在拖拽中
OnMouseDown告诉Update我们在拖拽中
ONMouseUp告诉将OnClicked改为false,表示我们已经拖拽完了改发射了。
- 实现拖拽。
- 首先判断拖拽,只有在拖拽的时候才有效果
if (onClicked)
(2)每次拖拽的位置要跟我们鼠标的位置一致
transform.position =Input.mousePosition;
transform.position相对于父对象的局部坐标,世界坐标
Input.mousePosition屏幕坐标,屏幕坐标
(3)将transform.position =Input.mousePosition;的计算方式改成一样的
Camera.main.ScreenToWorldPoint
其中WorldPoint等于transform.position
但是将Bird的z轴也改成了-30跟摄像头一个平面了,然后就看不到小鸟了
- 改变z轴
用new Vector3 直接将z轴改成0;
- 最大距离限制,
在弹弓组件上添加一个中心点(用了判断小鸟与弹弓的距离的点)
在Bird脚本中添加一中心点的变量
在onClicked中用Vector3.Distance(返回a和b之间的距离)判断,传入小鸟的位置
和中心点的位置,如果大于新建变量maxDistance(最大距离限制),然后就获取中心点跟
鼠标(小鸟的位置)的方向
Vector3 direction = (transform.position - centerPos.position).normalized * maxDistance;
normalized单位化,(1),向量是既有方向又有长度的,单位化之后就只有方向了
*MaxDistance就是我们想要的发射长度
,然后计算以中心点出发到小鸟的具体的位置
transform.position = centerPos.position + direction;
centerPos.position为起始点+direction我们想有发射的长度以及位置=限制之后小鸟发射的位置
- 小鸟的释放
等几秒就释放小鸟,等几秒就关闭Spring Joint2D这个组件小鸟自然会往前面飞。
- 获取SpringJoint2D这个组件
- 设置一个方法IEnumerator()协程(等几秒就释放)
- 设置一个专门的变量控制协程释放的时间
- 关闭SpringJoint2D这个组件。
- 在OnMouseUp中调用Release即可返回
- 获取Rigidbody2D组件,鼠标按下时开启动力学(isKinematic),鼠标松开时关闭
- 猪猪
- .添加CircleCollider2D组件(为了让小鸟检测到猪)
- 添加Rigidbody2D组件(猪也会往下掉)
- 地面:
(1)添加CircleCollider2D组件
(2)添加Rigidbody2D组件
9.控制猪猪
(1)添加脚本pig
(2)添加OnCollisionEnter2D方法检测碰撞检测
(3)判断猪的死亡
if (collision.relativeVelocity.magnitude > maxSpeed)
collision碰撞到的对象
relativeVelocity相对速度(Vector2的一个值并不是float)
magnitude就是把relativeVelocity计算为一个float的值
设置变量maxSpeed最大速度
(4)如果碰撞体的相对速度大于我们设置的最大速度就
Destroy(this.gameObject);//销毁本身(猪)
- Debug.Log(collision.relativeVelocity.magnitude);打印每次碰撞
的相对速度
- 创建木头的预制体
添加pig的脚本
10.弹弓划线
(1).给前后弹弓都添加LineRenderer组件(划线组件)
(2).制作一个材质
(3).改变宽度size
(4).创建两个新的划线的起始位置
(5).在代码(Bird)创建两个变量获取划线组件,再创建两个变量获取两个划线的位置,
(6).创建划线的方法(Line)
《1》LineRenderer.SetPosition设置线段位置。
《2》frontLine.SetPosition(0,frontLine.position)
index(相当于是0画到1,再从1画到2一根一根连接的因为我们就一条线所以就是从0画到1)起始位置0,frontLine.position就是我们设置的中心点的位置
《3》frontLine.SetPosition(1, transform.position);线的终点,到自身的坐标(画了前面的线)
《4》backLine.SetPosition后面的线
《5》在Update中调用
《6》在Release中关闭划线组件
《7》width关闭划线宽度
- 直接添加Partide System
《1》取消Looping的勾选
《2》Shape改为Share(圆形)
《3》radius 0.2
《4》勾选Size over Lifetime
《5》调整曲线Particle System Curves
《6》改变Duration的值
《7》改变Emission的Rate over Time的值,增加特效粒子的数量
《8》添加为预制
《9》在脚本(pig)中销毁的时候生成特效deadEffect
Instantiate(deadEffect, transform.position, transform.rotation);
涉及知识点:1.屏幕坐标与世界坐标的转换
- Spring Joint组件的使用
- 碰撞检测(OnCillisionEnter2D)
- LineRenderer等等
- 实现多只小鸟的飞出
一旦运行小鸟所有小鸟就会捆绑到一起
《1》添加一个GamerManager管理小鸟的飞出
《2》添加GamerManager脚本
《3》声明一个List集合《Bird》类型的管理小鸟的飞出。
《4》声明一个List集合《Pig》类型的管理猪的飞出
《5》声明方法Initialized初始化小鸟
for (int i = 0; i < brids.Count; i++)//遍历小鸟集合
if (i == 0)如果是第一只小鸟
brids[i].enabled = true;开启小鸟的中的一切脚本
brids[i].spj.enabled = true;开启小鸟的SpringJoint2D组件
else(如果不是第一只小鸟)
brids[i].enabled = false;关闭小鸟中的一切脚本
brids[i].spj.enabled = false;关闭SpringJoint2D组件
《6》在场景中赋值
《7》单例模式 public static GameManager _instance;
_instance = this;
- 在脚本(Bird)中的方法(Fly)中让SpringJoint2D失活。
spj.enabled = false;
- 添加方法Next处理下一只小鸟的飞出
《1》GameManager._instance.brids.Remove(this);//移除集合中的小鸟
《2》 Destroy(gameObject);//销毁飞出的小鸟
《3》在方法Fly中调用方法Invoke("Next", 5);//5 秒之后调用Next 方法
飞出5秒之后调用Invoke方法销毁小鸟
- 在脚本(GameManager)中添加方法(NextBird)判断游戏逻辑();
if (pig.Count > 0)如果场景中猪的数量大于零,猪就赢了,就进行小鸟的判定
if (brids.Count > 0)如果小鸟的数量大于0,就进行下一只小鸟的飞出
Initialized();下一只小鸟的飞出
else如果小鸟的数量小于0,小鸟就输了
else如果场景中猪的数量小于零,猪就是输了,小鸟就赢了
《2》在脚本(Bird)方法(Next)中调用方法(NextBird)进行判断游戏逻辑
《3》在Start函数中调用Initialized方法。
- 猪的销毁
在脚本(Pig)中声明变量isPig判断是否是猪
public bool isPig = false;//判断是否是猪
在Dead中判断
if (isPig)判断是否是猪
GameManager._instance.pig.Remove(this);是猪就调用GameManager脚本中的Pig进行Remove移除
在场景中勾选isPig
- 添加音效
《1》在脚本(Bird)中添加方法AudioPlay音乐播放
AudioSource.PlayClipAtPoint(clip, transform.position);
clip音乐片段
transform.position播放位置(自身的位置)
在小鸟脚本鼠标按下的时候调用AudioPlay(bridClip);
小鸟飞行的时候调用AudioPlay(fly);
《2》猪的播放
<1>.在脚本(Bird)中添加方法AudioPlay音乐播放
<2>.猪猪死亡播放AudioPlay(deadclip);
<3>.猪碰撞
if (collision.gameObject.tag == "Player")如果碰撞的物体的标签是Player
{
AudioPlay(birdclip);就播放小鸟碰撞音乐
}
如果用AudioSource这个组件因为物体已经被销毁了,如果使用AudioPlay方法,就不会存在这种问题,因为这个方法没有挂载任何脚本
1.AudioSource.PlayClipAtPoint播放声音,会自动生成一个名为”One shot audio”的物体,并自动添加了AudioSource和相应的audioclip,同时播放多个声音时会生成多个同名的物体,各声音的播放互不影响,但缺点是只能设置音量,位置,不能设置loop(当然也不是不能实现的,只是比较麻烦),还有一些特殊的声音效果也不易实现,只能播放一次,播放完成后,One shot audio自动销毁。
2.SceneManager.LoadSceneAsync() : 异步场景切换,Unity会在后台线程中加载所有资源,并保存之前场景的游戏对象,我们在加载过程中获取到加载的进度,可以播放一个真实的进度条,来看加载进度。
注意
异步加载只能获取90%,剩下10%需要自己设置,所有要进行优化,在最后%10做一个假加载
这个假加载如果读条完了,但是实际场景如果没有加载完,就会出现进度条以满,但是还没进入场景的情况(好像卡住了)
- 当使用SceneManager.LoadScene同步加载:进入的场景先进行资源的加载,待场景中所有的资源加载完成,才能进行场景和切换。并且原场景资源会立刻销毁
4.# if 1
A
#else
B
#endif
当为#if 1时,执行A,不执行B。
当为#if 0时,执行B,不执行A。
#endif 不可省略
- Invoke() 方法是 Unity3D 的一种委托机制,使用 Invoke() 方法需要注意 3点:
1 :它应该在 脚本的生命周期里的(Start、Update、OnGUI、FixedUpdate、LateUpdate)中被调用;
2:Invoke(); 不能接受含有 参数的方法;
3:在 Time.ScaleTime = 0; 时, Invoke() 无效,因为它不会被调用到
Invoke() 也支持重复调用:
OnCollisionEnter2D
OnCollisionEnter2D的形参指的是指碰撞双方的非脚本方
1 碰撞双方必须是碰撞体
2 被动体必须是个刚体
单例模式(让一个类在程序运行期间有且只有一个实例)
1、单例类只能有一个实例。
2、单例类必须自己创建自己的唯一实例。
3、单例类必须给所有其他对象提供这一实例。
gameobject.SetActive()用于激活或禁用gameobject
Rigidbody(刚体)组件可使游戏对象在物理系统的控制下来运动,刚体可接受外力与扭矩力用来保证游戏对象像在真实世界中那样进行运动。任何游戏对象只有添加了刚体组件才能受到重力的影响,通过脚本为游戏对象添加的作用力以及通过NVIDIA物理引擎与其他的游戏对象发生互动的运算都需要游戏对象添加了刚体组件。
个人理解就是刚体是用来模拟物体受到一个力作用时候的表现,这个从刚体中的参数就可以看出
碰撞体是物理组件的一类,它要与刚体一起添加到游戏对象上才能触发碰撞。如果两个刚体相互撞在一起,除非两个对象有碰撞体时物理引擎才会计算碰撞,在物理模拟中,没有碰撞体的刚体会彼此相互穿过。
个人是这样理解的,为什么要判断碰撞,判断碰撞就是需要计算力,无论是阻力也好,动力也好,如果此时物体有刚体组件,那么物体就会在力的作用下运动。如果这个物体没有刚体,那么碰撞产生的力就没有任何意义了,那计算碰撞也就没有任何意义了。
所以,我们可以推断出,如果两个碰撞体都没有刚体组件,那么这两个物体即使相互发生了碰撞,那么也不会有碰撞事件的。
是如果碰撞双方只有一个有刚体,那么那个刚体一定要处于运动的状态下才会有碰撞事件发生。
如果要收到触发事件,必须满足如下三个条件
1、必须都要有碰撞器组件(Collider),其实上面的碰撞事件同样也需要这个前提条件。
2、必须有一个物体带刚体组件,并且处于运动状体中(包括主动运动去撞击别人和在运动过程中被别人撞击)。
- 两个碰撞器中至少有一个开启了IsTrigger。
- start 在项目的第一帧被调用一次(做一些初始化的事情)
- Update每一帧中被调用(循环)
- Start 会在Update之前调用
- Awake函数在start函数之前调用,解决竞争条件。
IEnumerator 是C#的一个迭代器,你可以把它当成指向一个序列的某个节点的指针