从本篇开始我们要编写实体相关的业务逻辑代码
先去EntityComponent中添加EntityGroup
为背景实体创建实体数据类,命名为BgData,继承自EntityData
定义出需要用到的数据的字段,并提供构造方法
/// <summary>
/// 背景实体数据
/// </summary>
public class BgData : EntityData
{
/// <summary>
/// 移动速度
/// </summary>
public float MoveSpeed { get; private set; }
/// <summary>
/// 到达此目标时产生新的背景实体
/// </summary>
public float SpawnTarget { get; private set; }
/// <summary>
/// 到达此目标时隐藏自身
/// </summary>
public float HideTarget { get; private set; }
/// <summary>
/// 移动起始点
/// </summary>
public float StartPostion { get; private set; }
public BgData(int entityId, int typeId, float moveSpeed, float startPostion) : base(entityId, typeId)
{
MoveSpeed = moveSpeed;
SpawnTarget = -8.66f;
HideTarget = -26.4f;
StartPostion = startPostion;
}
}
然后创建对应的背景实体逻辑脚本,命名为Bg,继承自Entity
在为其编写业务逻辑代码之前,我们先去EntityExtension里找到TODO的地方,仿照它来封装一个专门用来显示背景实体的方法
/// <summary>
/// 显示背景实体
/// </summary>
public static void ShowBg(this EntityComponent entityComponent, BgData data)
{
entityComponent.ShowEntity(typeof(Bg), "Bg", data);
}
然后回到Bg类中,开始编写循环滚动的代码
/// <summary>
/// 背景实体脚本
/// </summary>
public class Bg : Entity
{
/// <summary>
/// 背景实体数据
/// </summary>
private BgData m_BgData = null;
private bool m_IsSpawn = false;
protected override void OnShow(object userData)
{
base.OnShow(userData);
m_BgData = (BgData)userData;
//修改开始位置
CachedTransform.SetLocalPositionX(m_BgData.StartPostion);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
//控制背景实体移动
CachedTransform.Translate(Vector3.left * m_BgData.MoveSpeed * elapseSeconds, Space.World);
if (CachedTransform.position.x <= m_BgData.SpawnTarget && m_IsSpawn == false)
{
//显示背景实体
GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), m_BgData.TypeId, m_BgData.MoveSpeed, 17.92f));
m_IsSpawn = true;
}
if (CachedTransform.position.x <= m_BgData.HideTarget)
{
//隐藏实体
GameEntry.Entity.HideEntity(this);
}
}
protected override void OnHide(object userData)
{
base.OnHide(userData);
m_IsSpawn = false;
}
}
接着打开ProcedureMain,重写OnEnter方法,在其中显示背景实体
/// <summary>
/// 主流程
/// </summary>
public class ProcedureMain : ProcedureBase
{
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), 1, 1f, 0));
}
}
现在点击运行,然后点击菜单上的开始,可以看到实现了背景图的无缝循环滚动功能(如果没实现,可以自己手动测试后修改ProcedureMain显示背景实体时传给BgData的startPosition参数与BgData构造方法里的SpawnTarget等数值)
接下来为管道实体创建实体数据类
/// <summary>
/// 管道实体数据
/// </summary>
public class PipeData : EntityData
{
/// <summary>
/// 移动速度
/// </summary>
public float MoveSpeed { get; private set; }
/// <summary>
/// 上管道偏移
/// </summary>
public float OffsetUp { get; private set; }
/// <summary>
/// 下管道偏移
/// </summary>
public float OffsetDown { get; private set; }
/// <summary>
/// 到达此目标时隐藏自身
/// </summary>
public float HideTarget { get; private set; }
public PipeData(int entityId, int typeId,float moveSpeed) : base(entityId, typeId)
{
MoveSpeed = moveSpeed;
OffsetUp = Random.Range(4.1f, 7f);
OffsetDown = Random.Range(-3f, -4.5f);
HideTarget = -9.4f;
}
}
创建实体逻辑脚本
/// <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);
}
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);
}
}
到EntityExtension里封装一个显示管道的方法
/// <summary>
/// 显示管道实体
/// </summary>
public static void ShowPipe(this EntityComponent entityComponent, PipeData data)
{
entityComponent.ShowEntity(typeof(Pipe), "Pipe", data);
}
回到ProcedureMain中,编写定时产生管道的业务逻辑代码
/// <summary>
/// 主流程
/// </summary>
public class ProcedureMain : ProcedureBase
{
/// <summary>
/// 管道产生时间
/// </summary>
private float m_PipeSpawnTime = 0f;
/// <summary>
/// 管道产生计时器
/// </summary>
private float m_PipeSpawnTimer = 0f;
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), 1, 1f, 0));
//设置初始管道产生时间
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));
}
}
点击运行,可以看到会在随机一段时间的间隔后产生出管道,并且两个管道之间的上下距离也是随机