新建一个UI脚本,命名为ScoreForm,继承自UGuiForm
编写如下代码
/// <summary>
/// 积分界面脚本
/// </summary>
public class ScoreForm : UGuiForm
{
public Text scoreText;
/// <summary>
/// 积分
/// </summary>
private int m_Score = 0;
/// <summary>
/// 积分计时器
/// </summary>
private float m_ScoreTimer = 0;
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
//订阅事件
GameEntry.Event.Subscribe(BirdDeadEventArgs.EventId, OnBirdDead);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
m_ScoreTimer += elapseSeconds;
if (m_ScoreTimer >= 2f)
{
m_ScoreTimer = 0;
m_Score += 1;
scoreText.text = "总分:" + m_Score;
}
}
protected override void OnClose(object userData)
{
base.OnClose(userData);
//取消订阅
GameEntry.Event.Unsubscribe(BirdDeadEventArgs.EventId, OnBirdDead);
}
protected override void OnPause()
{
base.OnPause();
//清空数据
m_ScoreTimer = 0;
m_Score = 0;
scoreText.text = "总分:" + m_Score;
}
private void OnBirdDead(object sender, GameEventArgs e)
{
//往数据结点里存积分数据
GameEntry.DataNode.GetOrAddNode("Score").SetData<VarInt>(m_Score);
//打开结束界面
GameEntry.UI.OpenUIForm(UIFormId.GameOverForm);
}
}
在小鸟死亡时,ScoreForm会往数据结点系统里存积分数据,这么做的目的在于能让结束界面打开后从数据结点系统里读取到积分数据。
把脚本拖到对应的UI预制体上,指定ScoreText,并应用预制体变更
还没完,我们还需要让子弹击中管道时为玩家增加10个积分,所以需要编写积分增加事件
/// <summary>
/// 加分事件
/// </summary>
public class AddScoreEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(AddScoreEventArgs).GetHashCode();
public override int Id
{
get
{
return EventId;
}
}
/// <summary>
/// 加分数量
/// </summary>
public int AddCount { get; private set; }
/// <summary>
/// 填充事件
/// </summary>
public AddScoreEventArgs Fill(int addCount)
{
AddCount = addCount;
return this;
}
public override void Clear()
{
AddCount = 0;
}
}
打开Bullet脚本,在子弹击中管道时派发事件
private void OnTriggerEnter2D(Collider2D collision)
{
//隐藏管道与自身
GameEntry.Sound.PlaySound(1);
collision.gameObject.SetActive(false);
GameEntry.Entity.HideEntity(this);
//派发加分事件
AddScoreEventArgs e = ReferencePool.Acquire<AddScoreEventArgs>();
GameEntry.Event.Fire(this, e.Fill(10));
}
在ScoreForm脚本中监听并处理
/// <summary>
/// 积分界面脚本
/// </summary>
public class ScoreForm : UGuiForm
{
public Text scoreText;
/// <summary>
/// 积分
/// </summary>
private int m_Score = 0;
/// <summary>
/// 积分计时器
/// </summary>
private float m_ScoreTimer = 0;
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
//订阅事件
GameEntry.Event.Subscribe(AddScoreEventArgs.EventId, OnAddScore);
GameEntry.Event.Subscribe(BirdDeadEventArgs.EventId, OnBirdDead);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
m_ScoreTimer += elapseSeconds;
if (m_ScoreTimer >= 2f)
{
m_ScoreTimer = 0;
m_Score += 1;
scoreText.text = "总分:" + m_Score;
}
}
protected override void OnClose(object userData)
{
base.OnClose(userData);
//取消订阅
GameEntry.Event.Unsubscribe(AddScoreEventArgs.EventId, OnAddScore);
GameEntry.Event.Unsubscribe(BirdDeadEventArgs.EventId, OnBirdDead);
}
protected override void OnPause()
{
base.OnPause();
//清空数据
m_ScoreTimer = 0;
m_Score = 0;
scoreText.text = "总分:" + m_Score;
}
private void OnAddScore(object sender, GameEventArgs e)
{
AddScoreEventArgs ase = (AddScoreEventArgs)e;
m_Score += ase.AddCount;
scoreText.text = "总分:" + m_Score;
}
private void OnBirdDead(object sender, GameEventArgs e)
{
//往数据结点里存积分数据
GameEntry.DataNode.GetOrAddNode("Score").SetData<VarInt>(m_Score);
//打开结束界面
GameEntry.UI.OpenUIForm(UIFormId.GameOverForm);
}
}
这样积分界面的业务逻辑就完成了,我们需要到ProcedureMain中打开积分界面
/// <summary>
/// 主流程
/// </summary>
public class ProcedureMain : ProcedureBase
{
/// <summary>
/// 管道产生时间
/// </summary>
private float m_PipeSpawnTime = 0f;
/// <summary>
/// 管道产生计时器
/// </summary>
private float m_PipeSpawnTimer = 0f;
/// <summary>
/// 结束界面ID
/// </summary>
private int m_ScoreFormId = -1;
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
m_ScoreFormId = GameEntry.UI.OpenUIForm(UIFormId.ScoreForm).Value;
GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), 1, 1f, 0));
GameEntry.Entity.ShowBird(new BirdData(GameEntry.Entity.GenerateSerialId(), 3, 5f));
//设置初始管道产生时间
m_PipeSpawnTime = Random.Range(3f, 5f);
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
m_PipeSpawnTimer += elapseSeconds;
if (m_PipeSpawnTimer >= m_PipeSpawnTime)
{
m_PipeSpawnTimer = 0;
//随机设置管道产生时间
m_PipeSpawnTime = Random.Range(3f, 5f);
//产生管道
GameEntry.Entity.ShowPipe(new PipeData(GameEntry.Entity.GenerateSerialId(), 2, 1f));
}
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
GameEntry.UI.CloseUIForm(m_ScoreFormId);
}
}
点击运行测试,积分会随着时间增加,并且在子弹击中管道时会增加10分
最后我们来处理游戏结束界面的业务逻辑
在游戏结束界面有2个按钮,分别是重新开始与主菜单,因此我们需要定义两个事件
/// <summary>
/// 重新开始游戏事件
/// </summary>
public class RestartEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(RestartEventArgs).GetHashCode();
public override int Id
{
get
{
return EventId;
}
}
public override void Clear()
{
}
}
/// <summary>
/// 返回菜单场景事件
/// </summary>
public class ReturnMenuEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(ReturnMenuEventArgs).GetHashCode();
public override int Id
{
get
{
return EventId;
}
}
public override void Clear()
{
}
}
新建UI脚本,命名为GameOverForm
代码如下
/// <summary>
/// 游戏结束界面
/// </summary>
public class GameOverForm : UGuiForm
{
public Text Score;
protected override void OnOpen(object userData)
{
base.OnOpen(userData);
//获取分数
int score = GameEntry.DataNode.GetNode("Score").GetData<VarInt>();
Score.text = "你的总分:" + score;
}
protected override void OnClose(object userData)
{
base.OnClose(userData);
Score.text = string.Empty;
}
public void OnRestartButtonClick()
{
Close(true);
//派发重新开始游戏事件
GameEntry.Event.Fire(this, ReferencePool.Acquire<RestartEventArgs>());
//显示小鸟
GameEntry.Entity.ShowBird(new BirdData(GameEntry.Entity.GenerateSerialId(), 3, 5f));
}
public void OnReturnButtonClick()
{
Close(true);
//派发返回菜单场景事件
GameEntry.Event.Fire(this,ReferencePool.Acquire<ReturnMenuEventArgs>());
}
}
拖到对应UI预制体上,指定Score
然后删除掉两个按钮的Button组件,挂上CommonBuutton脚本,注册对应的方法,并应用预制体变更
最后需要处理两个新事件的订阅,打开Pipe脚本,监听重新开始游戏事件
/// <summary>
/// 管道实体脚本
/// </summary>
public class Pipe : Entity
{
/// <summary>
/// 管道实体数据
/// </summary>
private PipeData m_PipeData = null;
/// <summary>
/// 上管道
/// </summary>
private Transform m_UpPipe = null;
/// <summary>
/// 下管道
/// </summary>
private Transform m_DownPipe = null;
protected override void OnShow(object userData)
{
base.OnShow(userData);
m_PipeData = (PipeData)userData;
//设置初始位置
CachedTransform.SetLocalPositionX(10f);
if (m_UpPipe == null || m_DownPipe == null)
{
m_UpPipe = transform.Find("UpPipe");
m_DownPipe = transform.Find("DownPipe");
}
//设置上下管道的偏移
m_UpPipe.SetLocalPositionY(m_PipeData.OffsetUp);
m_DownPipe.SetPositionY(m_PipeData.OffsetDown);
//订阅事件
GameEntry.Event.Subscribe(RestartEventArgs.EventId, OnRestart);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
CachedTransform.Translate(Vector3.left * m_PipeData.MoveSpeed * elapseSeconds, Space.World);
if (CachedTransform.position.x <= m_PipeData.HideTarget)
{
//隐藏自身
GameEntry.Entity.HideEntity(this);
}
}
protected override void OnHide(object userData)
{
base.OnHide(userData);
m_UpPipe.gameObject.SetActive(true);
m_DownPipe.gameObject.SetActive(true);
//取消订阅事件
GameEntry.Event.Unsubscribe(RestartEventArgs.EventId, OnRestart);
}
private void OnRestart(object sender, GameEventArgs e)
{
GameEntry.Entity.HideEntity(this);
}
}
打开ProcedureMain,监听返回主菜单事件
/// <summary>
/// 主流程
/// </summary>
public class ProcedureMain : ProcedureBase
{
/// <summary>
/// 管道产生时间
/// </summary>
private float m_PipeSpawnTime = 0f;
/// <summary>
/// 管道产生计时器
/// </summary>
private float m_PipeSpawnTimer = 0f;
/// <summary>
/// 结束界面ID
/// </summary>
private int m_ScoreFormId = -1;
/// <summary>
/// 是否返回主菜单
/// </summary>
private bool m_IsReturnMenu = false;
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
m_ScoreFormId = GameEntry.UI.OpenUIForm(UIFormId.ScoreForm).Value;
GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), 1, 1f, 0));
GameEntry.Entity.ShowBird(new BirdData(GameEntry.Entity.GenerateSerialId(), 3, 5f));
//设置初始管道产生时间
m_PipeSpawnTime = Random.Range(3f, 5f);
//订阅事件
GameEntry.Event.Subscribe(ReturnMenuEventArgs.EventId, OnReturnMenu);
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
m_PipeSpawnTimer += elapseSeconds;
if (m_PipeSpawnTimer >= m_PipeSpawnTime)
{
m_PipeSpawnTimer = 0;
//随机设置管道产生时间
m_PipeSpawnTime = Random.Range(3f, 5f);
//产生管道
GameEntry.Entity.ShowPipe(new PipeData(GameEntry.Entity.GenerateSerialId(), 2, 1f));
}
//切换场景
if (m_IsReturnMenu)
{
m_IsReturnMenu = false;
procedureOwner.SetData<VarInt>(Constant.ProcedureData.NextSceneId, GameEntry.Config.GetInt("Scene.Menu"));
ChangeState<ProcedureChangeScene>(procedureOwner);
}
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
GameEntry.UI.CloseUIForm(m_ScoreFormId);
//取消订阅事件
GameEntry.Event.Unsubscribe(ReturnMenuEventArgs.EventId, OnReturnMenu);
}
private void OnReturnMenu(object sender, GameEventArgs e)
{
m_IsReturnMenu = true;
}
}
点击运行,在小鸟死亡后会弹出结束面板,点击重新开始后小鸟会重新出现,此时积分为0,管道会全部消失并重新产生,点击主菜单则会返回菜单场景