UGF游戏框架实例开发教程—FlappyBird(七)子弹发射与小鸟飞行功能的实现
程序员文章站
2024-03-18 19:42:10
...
与之前的操作类似,新建一个子弹的实体数据类,命名为BulletData
/// <summary>
/// 子弹实体数据
/// </summary>
public class BulletData : EntityData
{
/// <summary>
/// 发射位置
/// </summary>
public Vector2 ShootPostion { get; private set; }
/// <summary>
/// 飞行速度
/// </summary>
public float FlySpeed { get; private set; }
public BulletData(int entityId, int typeId,Vector2 shootPositoin,float flySpeed) : base(entityId, typeId)
{
ShootPostion = shootPositoin;
FlySpeed = flySpeed;
}
}
编写对应的实体逻辑脚本
/// <summary>
/// 子弹实体脚本
/// </summary>
public class Bullet : Entity
{
/// <summary>
/// 子弹实体数据
/// </summary>
private BulletData m_BulletData = null;
protected override void OnShow(object userData)
{
base.OnShow(userData);
m_BulletData = (BulletData)userData;
CachedTransform.SetLocalScaleX(1.8f);
CachedTransform.position = m_BulletData.ShootPostion;
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
CachedTransform.Translate(Vector2.right * m_BulletData.FlySpeed * elapseSeconds, Space.World);
//已达到最大飞行距离
if (CachedTransform.position.x >= 9.1f)
{
GameEntry.Entity.HideEntity(this);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
//隐藏管道与自身
GameEntry.Sound.PlaySound(1);
collision.gameObject.SetActive(false);
GameEntry.Entity.HideEntity(this);
}
}
子弹在撞击到管道时会将自身与管道一同隐藏
到EntityExtension里封装一个显示子弹的方法
/// <summary>
/// 显示子弹实体
/// </summary>
public static void ShowBullet(this EntityComponent entityComponent, BulletData data)
{
entityComponent.ShowEntity(typeof(Bullet), "Bird", data);
}
接下来新建小鸟的实体数据类,命名为BirdData
/// <summary>
/// 小鸟实体数据
/// </summary>
public class BirdData : EntityData
{
/// <summary>
/// 飞行力度
/// </summary>
public float FlyForce { get; private set; }
public BirdData(int entityId, int typeId,float flyForce) : base(entityId, typeId)
{
FlyForce = flyForce;
}
}
编写对应的实体逻辑脚本
/// <summary>
/// 小鸟实体脚本
/// </summary>
public class Bird : Entity
{
/// <summary>
/// 小鸟实体数据
/// </summary>
private BirdData m_BirdData = null;
/// <summary>
/// 射击时间
/// </summary>
private float m_ShootTime = 10f;
/// <summary>
/// 射击计时器
/// </summary>
private float m_ShootTimer = 0f;
private Rigidbody2D m_Rigidbody = null;
protected override void OnShow(object userData)
{
base.OnShow(userData);
m_BirdData = (BirdData)userData;
//修改缩放
CachedTransform.localScale = Vector2.one * 2;
if (m_Rigidbody == null)
{
m_Rigidbody = GetComponent<Rigidbody2D>();
}
//重置射击冷却
m_ShootTimer = 10f;
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
//上升控制
if (Input.GetKeyDown(KeyCode.Space))
{
GameEntry.Sound.PlaySound(2);
m_Rigidbody.velocity = new Vector2(0, m_BirdData.FlyForce);
}
//射击控制
m_ShootTimer += elapseSeconds;
if (m_ShootTimer >= m_ShootTime && Input.GetKeyDown(KeyCode.J))
{
m_ShootTimer = 0;
GameEntry.Sound.PlaySound(3);
GameEntry.Entity.ShowBullet(new BulletData(GameEntry.Entity.GenerateSerialId(), 4,CachedTransform.position + CachedTransform.right, 6));
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
GameEntry.Sound.PlaySound(1);
GameEntry.Entity.HideEntity(this);
}
}
同样需要到EntityExtension里封装一个显示小鸟的方法
/// <summary>
/// 显示小鸟实体
/// </summary>
public static void ShowBird(this EntityComponent entityComponent, BirdData data)
{
entityComponent.ShowEntity(typeof(Bird), "Bird", data);
}
在ProcedureMain类的OnEnter方法中,调用显示小鸟的方法
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
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);
}
现在可以运行测试一下
子弹碰到管道后会导致管道消失,小鸟碰到管道后自己也会消失
这时候会发现一个问题,在射击后如果小鸟很快就死亡,那么子弹还会继续发射,我们需要让子弹在小鸟消失的时候也跟着一起消息,这时候就需要使用自定义事件了
在Event文件夹下新建一个BirdDeadEventArgs,继承GameEventArgs
/// <summary>
/// 小鸟死亡事件
/// </summary>
public class BirdDeadEventArgs : GameEventArgs
{
public static readonly int EventId = typeof(BirdDeadEventArgs).GetHashCode();
public override int Id
{
get
{
return EventId;
}
}
public override void Clear()
{
}
}
打开Bird脚本,在小鸟死亡的时候派发这个事件
private void OnTriggerEnter2D(Collider2D collision)
{
GameEntry.Sound.PlaySound(1);
GameEntry.Entity.HideEntity(this);
//派发小鸟死亡事件
GameEntry.Event.Fire(this, ReferencePool.Acquire<BirdDeadEventArgs>());
}
然后打开Bullet脚本,监听小鸟死亡事件并处理
/// <summary>
/// 子弹实体脚本
/// </summary>
public class Bullet : Entity
{
/// <summary>
/// 子弹实体数据
/// </summary>
private BulletData m_BulletData = null;
protected override void OnShow(object userData)
{
base.OnShow(userData);
m_BulletData = (BulletData)userData;
CachedTransform.SetLocalScaleX(1.8f);
CachedTransform.position = m_BulletData.ShootPostion;
//监听小鸟死亡事件
GameEntry.Event.Subscribe(BirdDeadEventArgs.EventId, OnBirdDead);
}
protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
{
base.OnUpdate(elapseSeconds, realElapseSeconds);
CachedTransform.Translate(Vector2.right * m_BulletData.FlySpeed * elapseSeconds, Space.World);
//已达到最大飞行距离
if (CachedTransform.position.x >= 9.1f)
{
GameEntry.Entity.HideEntity(this);
}
}
protected override void OnHide(object userData)
{
base.OnHide(userData);
//取消监听小鸟死亡事件
GameEntry.Event.Unsubscribe(BirdDeadEventArgs.EventId, OnBirdDead);
}
private void OnBirdDead(object sender, GameEventArgs e)
{
//小鸟死亡后立即隐藏自身
GameEntry.Entity.HideEntity(this);
}
private void OnTriggerEnter2D(Collider2D collision)
{
//隐藏管道与自身
GameEntry.Sound.PlaySound(1);
collision.gameObject.SetActive(false);
GameEntry.Entity.HideEntity(this);
}
}
这样我们在小鸟死亡的时候如果子弹还在飞行的话就会发现子弹也和小鸟一起消失了
上一篇: PHP的伪随机数与真随机数详解
下一篇: python读书笔记-基本数据类型