00 Spring Joint 2D

EnableCollision 支点与悬挂物,而不是悬挂物与悬挂物

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线

AutoConfigureDistance

unity 愤怒的小鸟 轨迹线_游戏引擎_02

Distance

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_03

DampingRatio

重力设为0,方便比较

unity 愤怒的小鸟 轨迹线_图层_04

Frequency

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_05

03 资源导入 场景简单搭建

切图

unity 愤怒的小鸟 轨迹线_UI_06


暂时没体会到“方法”的作用

unity 愤怒的小鸟 轨迹线_unity_07


unity 愤怒的小鸟 轨迹线_unity_08


带很多子图的

unity 愤怒的小鸟 轨迹线_UI_09

(了解)图标大小

unity 愤怒的小鸟 轨迹线_图层_10

(了解)图层顺序

视频多了为小鸟新建Player层

unity 愤怒的小鸟 轨迹线_unity_11

04 SpringJoint组件介绍

弹弓右,静态2D刚体,挂到小鸟弹簧组件上
小鸟,SpringJoint2D(弹簧),2D圆形碰撞器

以“遛狗”为例,“已连接锚点”是“你”,“锚点”是“狗”

unity 愤怒的小鸟 轨迹线_UI_12

(了解) 坐标系

屏幕坐标是左下原点
Unity世界坐标默认是中心原点

(问题)一点小鸟跑到摄像机的位置

一点,z值变得和主相机一样,两种方法:
01 限死z为0
02 减去相机的z

以上操作一点,小鸟(0,0,0)

Unity踩坑记录 从屏幕坐标系转换到世界坐标系

Vector3 FollowMouse(Vector3 targetPos)//跟随鼠标移动
    {
        Vector3 screenPos = Camera.main.WorldToScreenPoint(targetPos);//转屏幕
        screenPos = Input.mousePosition - Camera.main.transform.position;//屏幕中操作
        targetPos = Camera.main.ScreenToWorldPoint(screenPos);//转世界

        return targetPos;
    }

unity 愤怒的小鸟 轨迹线_unity_13


unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_14

限制距离

Vector3 LimitDistance(Vector3 movePoint, Vector3 basePoint, float maxDistance)//让movePoint始终在距离内
    {
        if (Vector3.Distance(movePoint, basePoint) > maxDistance)
        {
        
            pos = (movePoint - basePoint).normalized;//归一
            movePoint = basePoint + maxDistance * pos;
        }

        return movePoint;
    }
        }

(问题)弹射出去、弹力大小

问题是弹射后往下掉:auto configure distance不要打钩

unity 愤怒的小鸟 轨迹线_unity_15

08 猪的受伤

(问题)切片失败

sprite2D,多个,crunch都试过了,没有用,只切了一块需要用的

ctrl+D几个“蓝绿”框,然后手动框图

unity 愤怒的小鸟 轨迹线_UI_16

Enemy

速度太大就死掉,不然受伤

private void OnCollisionEnter2D(Collision2D self)
    {
        float speed = self.relativeVelocity.magnitude;
        if (speed > maxSpeed)
        {
            Destroy(gameObject);
        }
        else if (speed < maxSpeed && speed > minSpeed)
        {
            GetComponent<SpriteRenderer>().sprite = hurt;
        }
    }

09 弹弓的线LineRedender

在玩家isClick中调用

public Transform leftPos;
    public Transform rightPos;

    public LineRenderer leftLine;
    public LineRenderer rightLine;


    public static Slingshot _instance;

	void Awake()
    {
        _instance = this;
    }
        
 Start()
    {
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    public void Line()
    {
        leftLine.SetPosition(0, leftPos.position);
        leftLine.SetPosition(1, Player._instance.transform.position);

        rightLine.SetPosition(0, rightPos.position);
        rightLine.SetPosition(1, Player._instance.transform.position);
    }

10 敌人死亡动画,得分

查看所需的图片

这13个

171

160

136

128

116

107

96

88

36

自动切坏,自己切的3个

16 31 34

这个Ctrl点得很不人性化,一不小心点空白处,或者没按着ctrl,全没了

动画名== 自己写的那个, 状态机名 = = 物体名 = =第一张图的名字

动画取消循环

unity 愤怒的小鸟 轨迹线_unity_17

(问题)切坏了

删掉多余的,自己切

缺少框就ctrl+D,复制几个(前面说的是复看时加的)

unity 愤怒的小鸟 轨迹线_UI_18

读取精灵图

暂时用这种方法(用过阿里云的,觉得DataHub这个词挺好的)

实际还是读表、json最好。每种敌人对应相应的得分,受伤,死亡特效

unity 愤怒的小鸟 轨迹线_图层_19

(问题)死亡在敌人做,敌人被销毁位置没了

得分Sprite,死亡特效体的位置

setParent错误,敌人会被销毁,连带他们也很快被销毁
transform.position,可以,敌人被销毁,transform.position已经使用了,不会影响(用玩家或敌人的transfrom都可以,两者相撞在同一个位置触发敌人的死亡函数)

11 游戏逻辑的判定,实现多只小鸟的飞出

(了解)公有但隐藏

建议做成片段,不然每次补方括号就很烦

[HideInInspector]

分解

左边的箭头是鼠标按下、抬起的动作

(后面有重构了)

unity 愤怒的小鸟 轨迹线_图层_20

(问题)让鸟柔和上来

设置发射位置
到发射位置
Slingshot弹弓的意思

transform.position = Slingshot._instance.startPos.position;//一开始设置,柔和些

重构

从分数那里入手

敌人碰撞检测,检测速度
敌人速度大于死亡速度,死亡
销毁自身,在列表移除自己,;提供分数(玩家)

玩家接收提供的分数,+=,通知UI更新显示
玩家销毁,在列表中移除自己,GameController中进行StepAfterShoot()

UI更新显示分数

Bird

press = = drag
release = = up
为了追求和系统函数命名一样,把开始的press、release,改成drag,up

private void OnMouseDrag(){}
    private void OnMouseUp(){}

unity 愤怒的小鸟 轨迹线_UI_21


放代码太多,看流程就行

unity 愤怒的小鸟 轨迹线_图层_22

Enemy

放代码太多,也是看流程就行

unity 愤怒的小鸟 轨迹线_unity_23

(了解)碰撞,触发的参数命名

最好用other,self,用collision,collider容易混

12 添加小鸟飞出的拖尾效果

1

Unity 武器拖尾效果

高度,高

desireTime,宽

unity 愤怒的小鸟 轨迹线_UI_24


unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_25

(了解) 折叠代码 region

unity 愤怒的小鸟 轨迹线_UI_26

(了解) 代码“连坐”添加组件(添加组件A自动加上组件B,移除也无效)

[RequireComponent(typeof(MeshFilter))]

unity 愤怒的小鸟 轨迹线_图层_27

(TODO:) 菜单添加组件

[AddComponentMenu("PocketRPG/Weapon Trail")]

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_28

(问题) 鸟变重

突然会,暂时通过改变刚体的重力

到后面发现是天空背景添加碰撞盒的原因

(问题) 线的位置

运行前有问题,运行后不会。
不理解,虽然可以设置enabled

下面的透视相机,改成正交相机就解决了。毕竟省了几段enabled的代码

unity 愤怒的小鸟 轨迹线_图层_29


相机正交后,游戏面板就正常了

unity 愤怒的小鸟 轨迹线_游戏引擎_30

(现象) 相机透视

相机透视,正交、z=0,就正常

unity 愤怒的小鸟 轨迹线_unity_31

(问题) 碰撞盒作用不正常

两个2D碰撞盒都“负距离”了·

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_32

(问题)搭好的架子一运行就倒下

因为都是Ctrl+D复制的
天空背景添加了碰撞盒,相当于一直受到碰撞
架子的死亡速度为0,一倒下就销毁

15 添加失败,胜利的游戏UI界面

(了解)

确定16:10
拖出地面(2D/Sprite,不缩放),拉近相机到地面占高度1/5(天空占4/5)。这是UGUI之外的屏幕大小
UGUI挂MainCamera,调整缩放系数,到分数、消息提示框之类的合适

(问题) 切图不准

unity 愤怒的小鸟 轨迹线_图层_33

Bg渐暗

Ctrl给FailUI的Bg做渐暗(透明)动画,取消循环时间(播放一次)
在GameController的失败路径,激活FailUI

(了解) 看图

可以拉上拉下,之前忘了,都是打开“画图”软件

unity 愤怒的小鸟 轨迹线_UI_34

星星

16 修改火花粒子系统

在局部下缩放,初始大小

unity 愤怒的小鸟 轨迹线_UI_35

17 渲染层级关系

相机(深度)
layer
order

相机深度

AB 图(画布)分别有渲染摄像机:

B的相机的深度=-2,-1>-2,显示A

B的相机的深度=0,0>-1,显示B

B的相机的深度=-1,谁在层级的后面显示谁

unity 愤怒的小鸟 轨迹线_unity_36

layer图层

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_37

(了解 )相机渲染层与排序图层区别

相机渲染层,相机对谁“睁一只眼闭一只眼”,最高9层

unity 愤怒的小鸟 轨迹线_unity_38


unity 愤怒的小鸟 轨迹线_游戏引擎_39

order层内排序

谁大谁上

unity 愤怒的小鸟 轨迹线_unity_40

18 把粒子系统显示在UI之前

z轴与排序图层

节点上,视频是挂在一个root的父节点,我直接取sub子节点,并进行相应的缩放,暂时没什么差别
顺序上,直接修改z轴。视频是拍顺图层,Player>UI(显示优先权);爆炸归于Player层,就是以下2D精灵图的排序图层

(了解) 2D精灵/图像/原始图像

2D精灵图不属于UGUI,3D没有Sprite

//

图像属于UGUI,常用,经常snap(恢复原生大小),实际图片是sprite,有.sprite

原始图像属于UGUI,不常用(个人经验)

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_41

(了解) UGUI的排序

2D精灵图独立排序

//

UGUI由Canvas管理排序,可以添加子画布覆盖排序

unity 愤怒的小鸟 轨迹线_unity_42

19 让星星一颗一颗的显示

(代码)剩多少敌人扣多少星星

冗余了,后面改了

public void  StepAfterShoot()
    {
        if (enemyList.Count <= 0)
        {
            UIController._instance.ShowMessage("游戏通关");
            UIController._instance.ShowStar(3);
            
        }
        else 
        {
            if (birdList.Count <= 0)
            {
                UIController._instance.ShowMessage("游戏失败");
                UIController._instance.failUI.SetActive(true);

                if(enemyList.Count ==2 )
                    UIController._instance.ShowStar(3-2);
                else if (enemyList.Count == 1)
                    UIController._instance.ShowStar(3-1);

            }
            else 
            {
                NextBird();//下一只鸟
            }
        }
    }

(了解) List只声明的赋值

长度未确定,不能用[i]方式,报超出范围错误

public List<Enemy> enemyList;

    void Start()
    {
        childCount = transform.childCount;

        for (int i = 0; i < transform.childCount; i++)
        {
            enemyList.Add( transform.GetChild(i).GetComponent<Enemy>() );
        }
    }

20 添加暂停动画

动画

为PauseUI,做两个动画,要素是面板的一进一出,Bg的透明度

//

动画是Panel从左边移动到靠边

动画需在“录制”下才生效

//

NGUI有原生的Tween组件,自带了Reverse功能。UGUI有没有暂时不知道,所以只能做两个Clip

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_43

动画器

默认空状态

unity 愤怒的小鸟 轨迹线_UI_44

GameController

取反

void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Pause();
        }
    }
    public void Pause()
    {
        isPause = !isPause;

        UIController._instance.Pause(isPause);
    }

Bird上

限制按键

private void OnMouseDrag()
    {
        if (!GameController._instance.isPause)
        {
            isDrag = true;
        }
    }
    private void OnMouseUp()
    {
        if (!GameController._instance.isPause)
        {
            isDrag = false;
            isUp = true;
        }
    }

UI上

public void Pause(bool isPause)
    {
        pauseUI.SetActive(isPause);
        if (isPause)
            pauseUI.GetComponent<Animator>().SetBool("isPause",isPause);
    }

22 添加鼠标注册事件

(需求) unity 点击物体能自动展开选项卡

想法都是暂时没遇到方案

双击按钮,折叠的还不展开

unity 愤怒的小鸟 轨迹线_游戏引擎_45

(需求) 点击方法名一改,Unity中Button的点击方法就丢失

能不能像层级这种,挂上节点后,节点名不管怎么改,挂上的节点也不会丢失

(问题) 层级前后

一开始PauseUI是激活的,带透明的Bg

PauseButton放上面被这透明的Bg挡住,导致按钮不可点击,

01 PauseUI一开始不激活。一激活挡住PauseButton(这时候就体现最上面那个播放按钮的作用了),符合需求(不激活可能也会降低性能消耗?)【先用这个】

02 按钮移到PauseUI的下面。“黑暗之光”教面板的Tween进来又出去,都是激活的。

unity 愤怒的小鸟 轨迹线_UI_46

(问题) 返回界面,新游戏的方法写在UIController,还是GameController(先它)

(代码) Home、NewHome按钮

GameController

public void Pause()
    {
        isPause = !isPause;
        UIController._instance.Pause();
    }
    public void Home()
    {
       SceneManager.LoadScene(0);
    }
    public void NewGame()
    {
        SceneManager.LoadScene(1);
    }

//
UIController

public void Pause()//鼠标事件不能传参?(没学过)
    {
        bool isPause = GameController._instance.isPause;
        pauseUI.SetActive(isPause);
        pauseUI.GetComponent<Animator>().SetBool("isPause",isPause);
    }

unity 愤怒的小鸟 轨迹线_游戏引擎_47

23 添加镜头跟随

挂在相机上,问题是Player销毁会导致target报空

视频是挂小鸟上;

想挂相机上

unity 愤怒的小鸟 轨迹线_图层_48

public Transform target;
    // clamp
    public float startX = 0f;
    public float endX = 15f;
    public float smooth = 3f;
    //

    // Update is called once per frame
    void Update()
    {
        if (target != null)
        {
            CameraFollowTargetFunc();
        } 
    }

    public void CameraFollowTargetFunc()
    {
        float posX = Mathf.Clamp(target.position.x, startX, endX);
        float posY = transform.position.y;
        float posZ = transform.position.z;

        transform.position = Vector3.Lerp(transform.position, new Vector3(posX, posY, posZ), smooth);
    }

做成片段

一个是方便,一个是提炼(练习命名,重新认识流程)
//
钳制

<Code Language="csharp"><![CDATA[Mathf.Clamp(current, start, end);]]>

线性插值

<Code Language="csharp"><![CDATA[Vector3.Lerp(start, end, smooth)]]></Code>

24 音乐的添加

(了解) 往上拉有声音

unity 愤怒的小鸟 轨迹线_图层_49

起飞

鸟的起飞是update的,需要加标志位让其只执行一次

if (hasPlayed == false)
        {
            AudioSource.PlayClipAtPoint(DataHub._instance.birdFlyClip, transform.position);
            hasPlayed = true;
        }

(问题) 没声音

Wood,Pig都继承于Enemy,除了音效不同,其他差不多
失败:然后Wood,Pig的音效方法都用new(不了解),没用的,调用的是Enemy的(输出打印过),所以没声音
成功:重写虚函数可以(下一条是小结重载、重写、重定义)
//
父类Enemy

//音效,木头,猪音效不一样
    virtual public void PlayCollisionAudioClip() { }
    virtual public void PlayDestroyedAudioClip() { }

    public void PlayAudioClip(AudioClip clip)//仅仅为了少写点
    {
        AudioSource.PlayClipAtPoint(clip, transform.position);
    }

//
子类Pig:Enemy(Wood的类似)

override public void PlayCollisionAudioClip()
    {
        PlayAudioClip(DataHub._instance.pigCollisionClip);
    }
    override public  void PlayDestroyedAudioClip()
    {
        PlayAudioClip(DataHub._instance.pigDestroyedClip);
    }

(了解) 重载、重写、重定义

多态和虚函数重写 //01

重载(以下是Destroy的重载)

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_50

public static void Destroy(Object obj);
        public static void Destroy(Object obj, [DefaultValue("0.0F")] float t);

//02
上一条【(问题) 没声音】就是重写

//03 重定义

C#的new关键字的几种用法C++ 重载 覆盖(重写) 重定义(隐藏)的定义的区别

new新建,隐藏旧的

unity 愤怒的小鸟 轨迹线_游戏引擎_51

(问题) 不能延时(TODO:)

处理的是鸟的死亡音效(视频是作为受伤音效).

想让音效播放完几秒后在显示ResultUI。目前是音效和ResultUI一起发生

unity 愤怒的小鸟 轨迹线_游戏引擎_52

void Dead()//死亡
    {
        StartCoroutine(A());

        Destroy(gameObject);
        GameController._instance.birdList.RemoveAt(0);
        GameController._instance.StepAfterShoot();
        //TODO:鸟死亡,没特效
    }

    IEnumerator A()
    {
        AudioSource.PlayClipAtPoint(DataHub._instance.birdCollisionClip, transform.position);
        yield return new WaitForSeconds(5f);     
    }

(了解) virtual public 和public virtual

public virtual流行点
virtual(C# 参考)

25 添加黄色小鸟

(了解) protected

子类可以调用,编辑器面板看不到

(现象) unity不能重命名

重启

(问题) 第二只鸟无法点击操作

对比是YellowBird(空格键加2倍速的子类:Bird)

两坨线

unity 愤怒的小鸟 轨迹线_UI_53


//

弹弓的画线方法

leftLine.SetPosition(0, leftPos.position);
        leftLine.SetPosition(1, projectile.position);

unity 愤怒的小鸟 轨迹线_图层_54

私有方法可继承不可访问

在YellowBird中update中调用Line,画线可以,但其他方法无效,说明YellowBird对Bird的继承有问题
C#父类的私有成员子类有没有继承?

私有方法可继承不可访问。

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_55


但是改成protected,public,也是没作用。然而不是没用,而是还不够

子类不继承父类的Start,Update

测试一个计时函数,父类在跑,子类不跑。

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_56


//

Start,Update补上去就可以

void Start()
    {
        PreDragMouseButton();
    }

    // Update is called once per frame
    void Update()
    {
        //
        if (isDrag)//按下,预备发射
        {
            DragMouseButton();
        }

        if (!isUp)//比isDrag跟线时间更长
        {
            PreUpMouseButton();
        }
        else if (isUp)//松开
        {

            UpMouseButton();
        }
        //
    }

私有系统函数可继承访问

但是以下这种系统函数,子类可以继承执行到

private void OnMouseDrag()
    {
        if (!GameController._instance.isPause)
        {
            isDrag = true;
        }
        UIController._instance.ShowMessage("按下");
    }

(代码) 加速

......
        if (isUp && Input.GetKeyDown(KeyCode.LeftShift) && useSkill== false)
        {
            useSkill = true;         
        }
        if (useSkill)
        {
            ShowSkill();
            //
            coolTimer += Time.deltaTime;
            if (coolTimer > coolTime)
            {
                coolTimer = 0f;
                useSkill = false;
            }
        }
    }

    public override void ShowSkill()
    {
        if ( skillCount > 0)
        {
            skillCount--;
            //GetComponent<Rigidbody2D>().AddForce(-Vector2.left*Time.deltaTime * skillPower);//加力数值太大
            GetComponent<Rigidbody2D>().velocity *= skillPower;
            UIController._instance.ShowMessage("加速");//显示看看
        }
    }

26 添加绿色的小鸟

(代码)

同上黄色小鸟改作用的部分
改变方向,效果像回旋镖;
if这段代码会在update,update中执行的会封装成一个方法,让子类调用,这样子类的代码就少了点

if (isUp && Input.GetKeyDown(KeyCode.LeftShift) && useSkill== false)
        {
            useSkill = true;         
        }
        if (useSkill)
        {
            ShowSkill();
            //
            coolTimer += Time.deltaTime;
            if (coolTimer > coolTime)
            {
                coolTimer = 0f;
                useSkill = false;
            }
        }
    }

    public override void ShowSkill()
    {
        if ( skillCount > 0)
        {
            skillCount--;
            //GetComponent<Rigidbody2D>().AddForce(-Vector2.left*Time.deltaTime * skillPower);//加力数值太大
            GetComponent<Rigidbody2D>().velocity *= skillPower;
            GetComponent<SpriteRenderer>().sprite = skillSprite;
            UIController._instance.ShowMessage("加速");//显示看看
        }
    }

27 添加黑色小鸟

需求

爆炸条件,做了一个大点的触发器,时刻记录在圈内的物体(进来又出去,就不会被炸),鼠标点击,圈内的物体受到爆炸会销

//

黑鸟爆炸,图片切换,没有爆炸特效,就用一张图替代下(也是触发器的范围大小)

unity 愤怒的小鸟 轨迹线_UI_57


unity 愤怒的小鸟 轨迹线_图层_58

(问题) 两个问题耦合在一起,分不开

(问题) 已经被销毁

//不清楚==null是否等价于Missing,百度看到一些回答:

try catch异常就是销毁了
移到屏幕看不见的地方
SetActive
C#怎么求两个列表的交集(EnemyController有一个活着的Enemy的enemyList,

unity 愤怒的小鸟 轨迹线_unity_59


//但就想Destroy

TrimDead();的作用是"Trim"掉"Missing…”的元素。

试着不加这一句,运行停了(Missing时不能通过相应的Enemy组件找到相应的gameObject)

(问题) List在for循环中Remove导致的越界

if (enemyList[i] != null)后,Missing解决,但发生越界,所以有(了解)的测试
//
具体的原因因为已经修改覆盖了,无法对比。总结就是,在for循环中删除 列表 ,会有以下两种情况:
1、.Count会变小
2、后面接上来,i不减减,就会跳过接上来的那个元素

(代码)

public void TrimDead() //剔除一撞就死了,导致挂的Enemy也没了的物体
    {
        for (int i = 0; i < enemyList.Count; i++)
        {
            if (enemyList[i] == null)
            {
                enemyList.Remove(enemyList[i]);
                i--;
            }
        }
    }
    public override void ShowSkill()//鼠标左键触发
    {
        if ( skillCount > 0)
        {
            skillCount--;
            GetComponent<SpriteRenderer>().sprite = skillSprite;
            UIController._instance.ShowMessage("加速");//显示看看
            //
            AudioSource.PlayClipAtPoint(DataHub._instance.woodDestroyedClip, transform.position);//爆炸音效          
            boomFiledSprite.gameObject.SetActive(true);//显示爆炸范围
            
            //
            TrimDead();
            //杀敌
            while(enemyList.Count > 0)
            { 
                Destroy(enemyList[0].gameObject);               
            }
        }
    }

(了解) 列表Remove后索引是不是自动接上来

unity 愤怒的小鸟 轨迹线_unity_60

public List<int> list = new List<int> { 0, 1, 2, 3, 4 };

    // Start is called before the first frame update
    void Start()
    {
        list.Remove(list[2]);

        print(list.IndexOf(3));
    }

(重构) base.xxx()

1、if(skillCount > 0) { skillCount–;提到父类UpdateFunc()
2、ShowSkill()相同的部分提到父类

父类

public void UpdateFunc()//为子类少写点,因为Upadate子类不能继承
    {
		......
        //
        if ( Input.GetKeyDown(KeyCode.LeftShift) && useSkill == false)
        {
            useSkill = true;//标志计时状态
        }
        if (useSkill && skillCount > 0)
        {
            skillCount--;
            ShowSkill();
            //
            coolTimer += Time.deltaTime;
            if (coolTimer > coolTime)
            {
                coolTimer = 0f;
                useSkill = false;
            }
        }
    }
    ......
    public  virtual void ShowSkill()
    {
        GetComponent<SpriteRenderer>().sprite = skillSprite;//发动技能图片变化
        UIController._instance.ShowMessage("加速");//显示看看
    }

子类

比如BlackBird

void Update()
    {
        UpdateFunc();
    }

    public override void ShowSkill()//鼠标左键触发
    {
		base.ShowSkill();//继承家产
		//
        AudioSource.PlayClipAtPoint(DataHub._instance.woodDestroyedClip, transform.position);//爆炸音效,没有专属的,挑个接近的          
        boomFiledSprite.gameObject.SetActive(true);//显示爆炸范围
            
        //
        TrimDead();
        //杀敌
        while(enemyList.Count > 0)
        { 
            Destroy(enemyList[0].gameObject);               
        }     
    }
    public void TrimDead() //剔除一撞就死了,导致挂的Enemy也没了的物体
    {
        for (int i = 0; i < enemyList.Count; i++)
        {
            if (enemyList[i] == null)
            {
                enemyList.Remove(enemyList[i]);
                i--;
            }
        }
    }

28 处理黑色小鸟的爆炸问题

需求

鸟(拖尾)没了,爆炸特效还存在一会

(了解) override不能修改父类的访问符等级

unity 愤怒的小鸟 轨迹线_游戏引擎_61

(代码)

重写父类(父类是隔几秒检测位移是不是超过一定的距离)

public override void IsDead()
    {
        boomFiledSprite.SetParent(transform.parent);
        Destroy(boomFiledSprite.gameObject, 1f);

        isDead = true;
    }

30 制作选择地图UI界面

(了解) UGUI的ScrollView

Content的范围控制着展示元素的范围,比如高度变低点,往下的元素就不会显示,上滑也没用

Content的范围控制着滑动条是否显示,范围内显示,范围外不显示

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_62

(了解) 声明赋值与Start

第一次声明赋值,组件里的值随之变化,但是再次修改,修改无效
只能在组件里(Unity编辑器),或者Start里修改

[Tooltip("每个关卡获得的星星总数")] public List<int> collectedStarNumList = new List<int>() { 0,0,0,0,0, 0,0,};
    [Tooltip("每个关卡解锁需要的的星星")] public List<int> unlockNeedStarNumList = new List<int>() { 0,10,13,10,16, 10,19};//一开始是new List<int>() { 0,10,10,10,10,   10,10};

打印结果

unity 愤怒的小鸟 轨迹线_图层_63


在Start中赋值后

unity 愤怒的小鸟 轨迹线_游戏引擎_64

32 制作关卡选择界面

(现象) 有时Unity点不开,VS没发生这情况

(代码) LevelController

为Penel下的level赋值

void Start()
    {
        Init();
    }
    void Init()
    {
        //每个面板
        for (int i = 0; i < transform.childCount; i++)
        {
            panelList.Add(transform.GetChild(i));
        }
        //
        for (int i = 0; i < panelList.Count; i++)
        {
            //面板下的关卡
            for (int j = 0; j < panelList[i].childCount; j++)
            {
                //为可读
                Transform level = panelList[i].GetChild(j);
                Transform lockTrans = level.GetChild(1);
                Transform unlockTrans = level.GetChild(0);
                //
                lockTrans.gameObject.SetActive(false);
                unlockTrans.gameObject.SetActive(true);
                //0关卡,1星星
                unlockTrans.GetChild(0).GetComponent<Text>().text = (j + 1).ToString();//关卡数
                unlockTrans.GetChild(1).GetComponent<Image>().sprite = rankList[2];//评价星星数
            }
        }
    }

//运行后

unity 愤怒的小鸟 轨迹线_游戏引擎_65

(代码) level

点击进入正式游戏场景

//

从索引2开始正式游戏场景

unity 愤怒的小鸟 轨迹线_图层_66


//左边是Panel,右边是每个Panel的Level数量

unity 愤怒的小鸟 轨迹线_unity_67

public void OnButtonClick()
    {
        int panel=LevelController._instance.panelList.IndexOf(transform.parent);//第几个面板
        int level = int.Parse(transform.GetChild(0).GetChild(0).GetComponent<Text>().text ) ;//解锁节点的关卡数Text
        //
        int index = 2-1;//2是开始,关卡选择
        if (panel == 0)//当前Panel
        {
            index += level;
        }
        else if (panel > 0)
        {
            for (int i = 0; i < panel; i++)//前面的Panel的关卡
            {
                index += LevelController._instance.panelList[i].childCount;
            }
        }
        //
        SceneManager.LoadScene(index);
    }

33 添加地图选择和关卡选择界面的交互

点击Panel,激活相应的节点

public void OnButtonClick()
    {
        if (isLocked == true)//未解锁无法进入
            return;
        if(isLocked == false)//还未用到
            isSelected = true;

        int index = PanelController._instance.panelList.IndexOf(this);//获得自己在父节点的子节点列表的索引
       
        //更换sky,grounp
        EnvController._instance.ChangeBg(index);
        //进入相应的Panel
        LevelController._instance.panelList[index].gameObject.SetActive(true);
        //隐藏Panel页面
        PanelController._instance.gameObject.SetActive(false);
    }

//这是第三个Panel的sky,ground,和关卡信息(共7Panel,分别1234567level【仅测试方法是否有效,实际内容的关卡只有一个】)

unity 愤怒的小鸟 轨迹线_游戏引擎_68

点击按钮,返回Panel

public void OnBackButtonClick()
    {
        PanelController._instance.gameObject.SetActive(true);
        transform.parent.gameObject.SetActive(false);
    }

unity 愤怒的小鸟 轨迹线_游戏引擎_69

34 存储关卡星星数据(测试,源数据是在 LevelController统一赋值的)

(需求)

每关的星星,每个Panel的星星总数

unity 愤怒的小鸟 轨迹线_UI_70

level

public int StarNum()//根据星星评价图得到星星数量
    {
        Sprite starSprite = transform.GetChild(0).GetChild(1).GetComponent<Image>().sprite;//得到那张星星评价的图
        int starIndex = LevelController._instance.rankList.IndexOf(starSprite);//到levelController找在rankList中的索引

        return starIndex;
    }

//已测试多次

unity 愤怒的小鸟 轨迹线_图层_71

LevelController

统计每个Panel下的Level的star总和,装进列表。

原本写在PanelController,发生了错误,

写在LevelController的Start中,也发生有的读取不到的错误;下图正常是放在Update(只能从Panel进入Level时调用一下这个方法)

unity 愤怒的小鸟 轨迹线_游戏引擎_72

public List<int> StarNum()//计算每个Panel下的星星总数
    {
        for (int i = 0; i < panelList.Count; i++)
        {
            int star = 0;
            for (int j = 0; j < panelList[i].childCount; j++)
            {
                Transform level = panelList[i].GetChild(j);
                star += level.GetComponent<Level>().star;
            }
            starNumList[i]=star;
        }

        return starNumList;
    }

PanelController统一赋值】

这里也发生在Start中有问题,在Update中正常,

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_73

34 存储关卡星星数据

(重构)

分拆不固定的,做成预制体(视频是这样做的)

1、只需要一个场景,后面做新的关卡就是做新的预制体

2、根据预制体名字(Level01_01,第几个面板的第几关)进行数据读存(PlayerPrefs第几关多少颗星星)

unity 愤怒的小鸟 轨迹线_UI_74

(代码) 玩家通关后关卡星星的存储

unity 愤怒的小鸟 轨迹线_unity_75

public void Save(string level, int star)
    {
        if (PlayerPrefs.HasKey(level))//有且大于
        {
            if (star < PlayerPrefs.GetInt(level))
            {
                return;
            }
        }

        //其他情况,有且大于;没有
        PlayerPrefs.SetInt(level, star);
    }

(代码) LevelController分发Level的名字

主要看名字的那段代码,有了名,就可以到PlayerPrefs取值

void Init()
    {
        //每个面板
        for (int i = 0; i < transform.childCount; i++)
        {
            panelList.Add(transform.GetChild(i));
        }
        //
        for (int i = 0; i < panelList.Count; i++)
        {
            Transform panel = panelList[i];
            //面板下的关卡
            for (int j = 0; j < panel.childCount; j++)
            {
                //为可读
                Transform level = panel.GetChild(j);
                //
                string levelName;
                levelName = "Level";
                levelName += "0" + (i+1);
                levelName += "_";
                levelName += "0" + (j + 1);
                level.gameObject.name = levelName;
                //
                Transform lockTrans = level.GetChild(1);
                Transform unlockTrans = level.GetChild(0);
                lockTrans.gameObject.SetActive(false);
                unlockTrans.gameObject.SetActive(true);
                //0关卡,1星星
                unlockTrans.GetChild(0).GetComponent<Text>().text = (j + 1).ToString();//关卡数
                //
                int star = PlayerPrefs.GetInt(level.gameObject.name);
                unlockTrans.GetChild(1).GetComponent<Image>().sprite = rankList[star];//评价星星数
            }
        }
    }

unity 愤怒的小鸟 轨迹线_游戏引擎_76

(代码) LevelController统计每个Panel的星星

void Update()
    {
        starNumList = StarNum();
    }
    public List<int> StarNum()//计算每个Panel下的星星总数
    {
        for (int i = 0; i < panelList.Count; i++)
        {
            int star = 0;
            for (int j = 0; j < panelList[i].childCount; j++)
            {
                Transform level = panelList[i].GetChild(j);
                star += level.GetComponent<Level>().star;
            }
            starNumList[i]=star;
        }

        return starNumList;
    }

unity 愤怒的小鸟 轨迹线_unity_77

(了解) 调用小鸟时用GetChild还是List

用GetChild的缺点是,比如鸟爆炸,鸟销毁了,爆炸特效还存在一会,那么特效的父节点要移出小鸟。类似的情况都要重复操作(前人不栽树,后人晒太阳);
如果不移出,像这种情况,GetChild子节点就脏了,遍历子节点就走不通(或者说情况复杂)
//
以上(代码也是一样),那个黄色的返回按钮应该放节点内,但会造成Panel和Level的污染

(了解) 节点内能调用的节点内解决

比如UI上有个NewGame的方法,一般GameController中会写,但按钮事件还是写复制相同代码的同节点的UIController。

37 解决星星个数更新问题

39 制作多个关卡

需求

只需要一个场景,后面做新的关卡就是做新的预制体

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_78

(重构)

之前是想多个场景做多个关卡,现在改成一个场景,多个预制体做多个关卡

(代码) level

点击哪个,就存储它的名字

unity 愤怒的小鸟 轨迹线_图层_79

public void OnButtonClick()
    {
        PlayerPrefs.SetString("IsSelected", gameObject.name);//用于实例那一关

        SceneManager.LoadScene(2);//游戏主场景
    }

(代码) 主场景 LevelSelect

直接挂上去的()

unity 愤怒的小鸟 轨迹线_图层_80

void Start()
    {
        string levelName;
        if (!PlayerPrefs.HasKey("IsSelected"))
            levelName = "Level01_01";
        else
            levelName = PlayerPrefs.GetString("IsSelected");

        for (int i = 0; i < levelList.Count; i++)
        {
            if(levelList[i].gameObject.name == levelName)
                Instantiate( levelList[i] );
        }
        
    }

//
或者Resources

void Start()
    {
        string levelName;
        if (!PlayerPrefs.HasKey("IsSelected"))
            levelName = "Level01_01";
        else
            levelName = PlayerPrefs.GetString("IsSelected");

        GameObject go = Resources.Load<GameObject>(levelName);
        Instantiate(go);     
    }

40 snap settings使用介绍

snap settings,捕捉设置

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_81

手调第一次得到这个值后,以后复制移动各大概距离,按相应的xyz(水平是x),就自动吸附

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_82

平铺

碰撞器大小得相应调整

unity 愤怒的小鸟 轨迹线_图层_83

42-43 异步加载场景

(了解) 分辨率 相机 画布渲染模式

2D相机用正交

unity 愤怒的小鸟 轨迹线_unity 愤怒的小鸟 轨迹线_84

写死分辨率

分辨率我做的不好,主要游戏场景由16:10,改回1024:728,那些暂停UI,ResultUI发生过位置缩放问题

void Start()
    {
    	Screen.SetResolution(1024, 768, false);//宽,高,不可修改
        Invoke("Load",2f);//延时
    }
    private void Load()
    {
        SceneManager.LoadSceneAsync(1);
    }

unity 愤怒的小鸟 轨迹线_unity_85