00 Spring Joint 2D
EnableCollision 支点与悬挂物,而不是悬挂物与悬挂物
AutoConfigureDistance
Distance
DampingRatio
重力设为0,方便比较
Frequency
03 资源导入 场景简单搭建
切图
暂时没体会到“方法”的作用
带很多子图的
(了解)图标大小
(了解)图层顺序
视频多了为小鸟新建Player层
04 SpringJoint组件介绍
弹弓右,静态2D刚体,挂到小鸟弹簧组件上
小鸟,SpringJoint2D(弹簧),2D圆形碰撞器
以“遛狗”为例,“已连接锚点”是“你”,“锚点”是“狗”
(了解) 坐标系
屏幕坐标是左下原点
Unity世界坐标默认是中心原点
(问题)一点小鸟跑到摄像机的位置
一点,z值变得和主相机一样,两种方法:
01 限死z为0
02 减去相机的z
以上操作一点,小鸟(0,0,0)
Vector3 FollowMouse(Vector3 targetPos)//跟随鼠标移动
{
Vector3 screenPos = Camera.main.WorldToScreenPoint(targetPos);//转屏幕
screenPos = Input.mousePosition - Camera.main.transform.position;//屏幕中操作
targetPos = Camera.main.ScreenToWorldPoint(screenPos);//转世界
return targetPos;
}
限制距离
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不要打钩
08 猪的受伤
(问题)切片失败
sprite2D,多个,crunch都试过了,没有用,只切了一块需要用的
ctrl+D几个“蓝绿”框,然后手动框图
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,全没了
动画名== 自己写的那个, 状态机名 = = 物体名 = =第一张图的名字
动画取消循环
(问题)切坏了
删掉多余的,自己切
缺少框就ctrl+D,复制几个(前面说的是复看时加的)
读取精灵图
暂时用这种方法(用过阿里云的,觉得DataHub这个词挺好的)
实际还是读表、json最好。每种敌人对应相应的得分,受伤,死亡特效
(问题)死亡在敌人做,敌人被销毁位置没了
得分Sprite,死亡特效体的位置
setParent错误,敌人会被销毁,连带他们也很快被销毁
transform.position,可以,敌人被销毁,transform.position已经使用了,不会影响(用玩家或敌人的transfrom都可以,两者相撞在同一个位置触发敌人的死亡函数)
11 游戏逻辑的判定,实现多只小鸟的飞出
(了解)公有但隐藏
建议做成片段,不然每次补方括号就很烦
[HideInInspector]
分解
左边的箭头是鼠标按下、抬起的动作
(后面有重构了)
(问题)让鸟柔和上来
设置发射位置
到发射位置
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(){}
放代码太多,看流程就行
Enemy
放代码太多,也是看流程就行
(了解)碰撞,触发的参数命名
最好用other,self,用collision,collider容易混
12 添加小鸟飞出的拖尾效果
1
高度,高
desireTime,宽
(了解) 折叠代码 region
(了解) 代码“连坐”添加组件(添加组件A自动加上组件B,移除也无效)
[RequireComponent(typeof(MeshFilter))]
(TODO:) 菜单添加组件
[AddComponentMenu("PocketRPG/Weapon Trail")]
(问题) 鸟变重
突然会,暂时通过改变刚体的重力
到后面发现是天空背景添加碰撞盒的原因
(问题) 线的位置
运行前有问题,运行后不会。
不理解,虽然可以设置enabled
下面的透视相机,改成正交相机就解决了。毕竟省了几段enabled的代码
相机正交后,游戏面板就正常了
(现象) 相机透视
相机透视,正交、z=0,就正常
(问题) 碰撞盒作用不正常
两个2D碰撞盒都“负距离”了·
(问题)搭好的架子一运行就倒下
因为都是Ctrl+D复制的
天空背景添加了碰撞盒,相当于一直受到碰撞
架子的死亡速度为0,一倒下就销毁
15 添加失败,胜利的游戏UI界面
(了解)
确定16:10
拖出地面(2D/Sprite,不缩放),拉近相机到地面占高度1/5(天空占4/5)。这是UGUI之外的屏幕大小
UGUI挂MainCamera,调整缩放系数,到分数、消息提示框之类的合适
(问题) 切图不准
Bg渐暗
Ctrl给FailUI的Bg做渐暗(透明)动画,取消循环时间(播放一次)
在GameController的失败路径,激活FailUI
(了解) 看图
可以拉上拉下,之前忘了,都是打开“画图”软件
星星
16 修改火花粒子系统
在局部下缩放,初始大小
17 渲染层级关系
相机(深度)
layer
order
相机深度
AB 图(画布)分别有渲染摄像机:
B的相机的深度=-2,-1>-2,显示A
B的相机的深度=0,0>-1,显示B
B的相机的深度=-1,谁在层级的后面显示谁
layer图层
(了解 )相机渲染层与排序图层区别
相机渲染层,相机对谁“睁一只眼闭一只眼”,最高9层
order层内排序
谁大谁上
18 把粒子系统显示在UI之前
z轴与排序图层
节点上,视频是挂在一个root的父节点,我直接取sub子节点,并进行相应的缩放,暂时没什么差别
顺序上,直接修改z轴。视频是拍顺图层,Player>UI(显示优先权);爆炸归于Player层,就是以下2D精灵图的排序图层
(了解) 2D精灵/图像/原始图像
2D精灵图不属于UGUI,3D没有Sprite
//
图像属于UGUI,常用,经常snap(恢复原生大小),实际图片是sprite,有.sprite
原始图像属于UGUI,不常用(个人经验)
(了解) UGUI的排序
2D精灵图独立排序
//
UGUI由Canvas管理排序,可以添加子画布覆盖排序
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
动画器
默认空状态
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中Button的点击方法就丢失
能不能像层级这种,挂上节点后,节点名不管怎么改,挂上的节点也不会丢失
(问题) 层级前后
一开始PauseUI是激活的,带透明的Bg
PauseButton放上面被这透明的Bg挡住,导致按钮不可点击,
01 PauseUI一开始不激活。一激活挡住PauseButton(这时候就体现最上面那个播放按钮的作用了),符合需求(不激活可能也会降低性能消耗?)【先用这个】
02 按钮移到PauseUI的下面。“黑暗之光”教面板的Tween进来又出去,都是激活的。
(问题) 返回界面,新游戏的方法写在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);
}
23 添加镜头跟随
挂在相机上,问题是Player销毁会导致target报空
视频是挂小鸟上;
想挂相机上
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 音乐的添加
(了解) 往上拉有声音
起飞
鸟的起飞是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的重载)
public static void Destroy(Object obj);
public static void Destroy(Object obj, [DefaultValue("0.0F")] float t);
//02
上一条【(问题) 没声音】就是重写
//03 重定义
C#的new关键字的几种用法C++ 重载 覆盖(重写) 重定义(隐藏)的定义的区别
new新建,隐藏旧的
(问题) 不能延时(TODO:)
处理的是鸟的死亡音效(视频是作为受伤音效).
想让音效播放完几秒后在显示ResultUI。目前是音效和ResultUI一起发生
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)
两坨线
//
弹弓的画线方法
leftLine.SetPosition(0, leftPos.position);
leftLine.SetPosition(1, projectile.position);
私有方法可继承不可访问
在YellowBird中update中调用Line,画线可以,但其他方法无效,说明YellowBird对Bird的继承有问题
C#父类的私有成员子类有没有继承?
私有方法可继承不可访问。
但是改成protected,public,也是没作用。然而不是没用,而是还不够
子类不继承父类的Start,Update
测试一个计时函数,父类在跑,子类不跑。
//
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 添加黑色小鸟
需求
爆炸条件,做了一个大点的触发器,时刻记录在圈内的物体(进来又出去,就不会被炸),鼠标点击,圈内的物体受到爆炸会销
//
黑鸟爆炸,图片切换,没有爆炸特效,就用一张图替代下(也是触发器的范围大小)
(问题) 两个问题耦合在一起,分不开
(问题) 已经被销毁
//不清楚==null是否等价于Missing,百度看到一些回答:
try catch异常就是销毁了
移到屏幕看不见的地方
SetActive
C#怎么求两个列表的交集(EnemyController有一个活着的Enemy的enemyList,
//但就想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后索引是不是自动接上来
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不能修改父类的访问符等级
(代码)
重写父类(父类是隔几秒检测位移是不是超过一定的距离)
public override void IsDead()
{
boomFiledSprite.SetParent(transform.parent);
Destroy(boomFiledSprite.gameObject, 1f);
isDead = true;
}
30 制作选择地图UI界面
(了解) UGUI的ScrollView
Content的范围控制着展示元素的范围,比如高度变低点,往下的元素就不会显示,上滑也没用
Content的范围控制着滑动条是否显示,范围内显示,范围外不显示
(了解) 声明赋值与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};
打印结果
在Start中赋值后
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];//评价星星数
}
}
}
//运行后
(代码) level
点击进入正式游戏场景
//
从索引2开始正式游戏场景
//左边是Panel,右边是每个Panel的Level数量
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【仅测试方法是否有效,实际内容的关卡只有一个】)
点击按钮,返回Panel
public void OnBackButtonClick()
{
PanelController._instance.gameObject.SetActive(true);
transform.parent.gameObject.SetActive(false);
}
34 存储关卡星星数据(测试,源数据是在 LevelController统一赋值的)
(需求)
每关的星星,每个Panel的星星总数
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;
}
//已测试多次
LevelController
统计每个Panel下的Level的star总和,装进列表。
原本写在PanelController,发生了错误,
写在LevelController的Start中,也发生有的读取不到的错误;下图正常是放在Update(只能从Panel进入Level时调用一下这个方法)
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中正常,
34 存储关卡星星数据
(重构)
分拆不固定的,做成预制体(视频是这样做的)
1、只需要一个场景,后面做新的关卡就是做新的预制体
2、根据预制体名字(Level01_01,第几个面板的第几关)进行数据读存(PlayerPrefs第几关多少颗星星)
(代码) 玩家通关后关卡星星的存储
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];//评价星星数
}
}
}
(代码) 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;
}
(了解) 调用小鸟时用GetChild还是List
用GetChild的缺点是,比如鸟爆炸,鸟销毁了,爆炸特效还存在一会,那么特效的父节点要移出小鸟。类似的情况都要重复操作(前人不栽树,后人晒太阳);
如果不移出,像这种情况,GetChild子节点就脏了,遍历子节点就走不通(或者说情况复杂)
//
以上(代码也是一样),那个黄色的返回按钮应该放节点内,但会造成Panel和Level的污染
(了解) 节点内能调用的节点内解决
比如UI上有个NewGame的方法,一般GameController中会写,但按钮事件还是写复制相同代码的同节点的UIController。
37 解决星星个数更新问题
39 制作多个关卡
需求
只需要一个场景,后面做新的关卡就是做新的预制体
(重构)
之前是想多个场景做多个关卡,现在改成一个场景,多个预制体做多个关卡
(代码) level
点击哪个,就存储它的名字
public void OnButtonClick()
{
PlayerPrefs.SetString("IsSelected", gameObject.name);//用于实例那一关
SceneManager.LoadScene(2);//游戏主场景
}
(代码) 主场景 LevelSelect
直接挂上去的()
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,捕捉设置
手调第一次得到这个值后,以后复制移动各大概距离,按相应的xyz(水平是x),就自动吸附
平铺
碰撞器大小得相应调整
42-43 异步加载场景
(了解) 分辨率 相机 画布渲染模式
2D相机用正交
写死分辨率
分辨率我做的不好,主要游戏场景由16:10,改回1024:728,那些暂停UI,ResultUI发生过位置缩放问题
void Start()
{
Screen.SetResolution(1024, 768, false);//宽,高,不可修改
Invoke("Load",2f);//延时
}
private void Load()
{
SceneManager.LoadSceneAsync(1);
}