前言
欢迎来到【制作100个Unity游戏】系列!本系列将引导您一步步学习如何使用Unity开发各种类型的游戏。在这第29篇中,我们将探索如何用unity复刻经典游戏《愤怒的小鸟》,我会附带项目源码,以便你更好理解它。
素材下载
链接:https://pan.baidu.com/s/1hBbnRkGuf44jsQQBZSn96g?pwd=h73r
提取码:h73r
简单搭建环境
修改图片配置并切图,修改最大尺寸是为了让图片放大不那么模糊
背景图片和地面草地可能不够长,可以修改绘制模式改成平铺,修改宽度
控制小鸟
新增Bird,控制小鸟跟随鼠标移动
public enum BirdState { Waiting,//等待 BeforeShoot,//发射前 AfterShoot//发射后 } public class Bird : MonoBehaviour { public BirdState state = BirdState.BeforeShoot; private bool isMouseDown = false; //是否按下 void Update() { switch (state) { case BirdState.Waiting: break; case BirdState.BeforeShoot: MoveControl(); break; case BirdState.AfterShoot: break; default: break; } } //按下触发事件 private void OnMouseDown() { if (state == BirdState.BeforeShoot) { isMouseDown = true; } } //抬起触发事件 private void OnMouseUp() { if (state == BirdState.BeforeShoot) { isMouseDown = false; } } //跟随鼠标 private void MoveControl() { if (isMouseDown) transform.position = GetMousePosition(); } //屏幕坐标转世界坐标 private Vector3 GetMousePosition() { Vector3 position = Camera.main.ScreenToWorldPoint(Input.mousePosition); return new Vector2(position.x, position.y); } }
配置,记得给小鸟加上碰撞体
效果
生成弹簧
新增Slingshot代码,控制弹簧得生成
public class Slingshot : MonoBehaviour { public static Slingshot Instance; public LineRenderer leftLineRenderer; public LineRenderer rightLineRenderer; public Transform leftPoint; public Transform rightPoint; // private Transform centerPoint; private bool isDrawing = false;//是否画线 private Transform birdTransform;//鸟 private void Awake() { Instance = this; } private void Update() { if (isDrawing) { Draw(); } } public void StartDraw(Transform birdTransform) { isDrawing = true; this.birdTransform = birdTransform; } public void EndDraw() { isDrawing = false; } public void Draw() { leftLineRenderer.SetPosition(0, birdTransform.position); leftLineRenderer.SetPosition(1, leftPoint.position); rightLineRenderer.SetPosition(0, birdTransform.position); rightLineRenderer.SetPosition(1, rightPoint.position); } }
配置
效果
可以看到现在线得终点是在鸟的中位置,我们希望在鸟的后面位置生成
修改代码,按碰撞器的半径进行偏移
public void Draw() { Vector2 birdPosition = birdTransform.position + birdTransform.GetComponent<CircleCollider2D>().radius * (birdTransform.position-transform.position).normalized; leftLineRenderer.SetPosition(0, birdPosition); leftLineRenderer.SetPosition(1, leftPoint.position); rightLineRenderer.SetPosition(0, birdPosition); rightLineRenderer.SetPosition(1, rightPoint.position); }
效果
限制小鸟的控制范围
修改Bird
public float maxDistance = 1.5f;//限制拉动距离 //屏幕坐标转世界坐标 private Vector3 GetMousePosition() { Vector3 position = Camera.main.ScreenToWorldPoint(Input.mousePosition); position.z = 0; // 获取弹弓的中心位置 Vector3 centerPosition = Slingshot.Instance.gameObject.transform.position; //计算鼠标指向的方向 Vector3 mouseDir = position - centerPosition; //计算鼠标指向的距离 float distance = mouseDir.magnitude; // 如果距离超过最大距离,则限制在最大距离范围内 if(distance > maxDistance){ position = mouseDir.normalized * maxDistance + centerPosition; } return position; }
效果
弹簧线的显示隐藏
修改Slingshot
private void Awake() { Instance = this; HideLine(); } public void StartDraw(Transform birdTransform) { isDrawing = true; this.birdTransform = birdTransform; ShowLine(); } public void EndDraw() { isDrawing = false; HideLine(); } void HideLine() { leftLineRenderer.enabled = false; rightLineRenderer.enabled = false; } void ShowLine() { leftLineRenderer.enabled = true; rightLineRenderer.enabled = true; }
效果
飞行
给鸟添加刚体,默认为静态
修改Slingshot,配置射击点
public Transform shootPoint;
配置
修改Bird
public float flySpeed;//飞行速度 public float force = 10f;//力大小 private Vector2 m_pushSpeed;//力向量 //抬起触发事件 private void OnMouseUp() { if (state == BirdState.BeforeShoot) { isMouseDown = false; Slingshot.Instance.EndDraw(); Fly(); } } private void MoveControl() { if (isMouseDown) { transform.position = GetMousePosition();//跟随鼠标 Vector3 mouseDir = Slingshot.Instance.shootPoint.position - transform.position; m_pushSpeed = mouseDir.normalized * mouseDir.magnitude * force;//力向量 } } void Fly(){ rb.bodyType = RigidbodyType2D.Dynamic; rb.AddForce(m_pushSpeed, ForceMode2D.Impulse); state = BirdState.AfterShoot; }
配置
效果
新增木头
添加刚体和碰撞体
木头销毁
新增Destructiable,控制木头销毁
public class Destructiable : MonoBehaviour { public int maxHP = 100;// 最大生命值 private int currentHP;// 当前生命值 private void Start() { currentHP = maxHP; } private void OnCollisionEnter2D(Collision2D collision) { // 获取当前碰撞的相对速度 Vector2 relativeVelocity = collision.relativeVelocity; // 计算相对速度的大小(标量值) float impactForce = relativeVelocity.magnitude; if(impactForce <= 1) return;//过滤小伤害 // 根据相对速度大小计算伤害值,并减少当前生命值 currentHP -= (int)(impactForce * 5); if (currentHP <= 0)Destroy(gameObject); } }
效果
不同血量的木头状态
修改Destructiable,控制不同血量显示不同阶段的图片
public List<Sprite> spriteList;//不同阶段的图片 private SpriteRenderer spriteRenderer; spriteRenderer = GetComponent<SpriteRenderer>(); private void OnCollisionEnter2D(Collision2D collision) { // 获取当前碰撞的相对速度 Vector2 relativeVelocity = collision.relativeVelocity; // 计算相对速度的大小(标量值) float impactForce = relativeVelocity.magnitude; if(impactForce <= 1) return;//过滤小伤害 // 根据相对速度大小计算伤害值,并减少当前生命值 currentHP -= (int)(impactForce * 5); if (currentHP <= 0) { Destroy(gameObject); } else { //计算剩余生命值的比例 float healthRatio = (float)currentHP / maxHP; //计算阶段索引 int index = (int)((1 - healthRatio) * spriteList.Count) - 1; if (index != -1) spriteRenderer.sprite = spriteList[index]; } }
配置
效果
配置更多物品
通过跳转血量,实现易碎的冰块和坚固的砖块
爆炸效果
配置
修改Destructiable,物体销毁时调用
//爆炸特效 GameObject prefabs = Resources.Load("Prefabs/VFX/爆炸烟雾特效") as GameObject; GameObject go = Instantiate(prefabs, transform.position, Quaternion.identity); Destroy(go, 1f);
效果
创建敌人的小猪
新增脚本pig,继承Destructiable
public class Pig : Destructiable {}
配置
效果
创建多个小鸟循环
修改Bird,
public enum BirdState { Waiting,//等待 BeforeShoot,//发射前 AfterShoot,//发射后 WaitToDie//死亡 } void Update() { switch (state) { case BirdState.Waiting: break; case BirdState.BeforeShoot: MoveControl(); break; case BirdState.AfterShoot: StopControl(); break; case BirdState.WaitToDie: break; default: break; } } void StopControl(){ if(rb.velocity.magnitude < 0.1f){ state = BirdState.WaitToDie; Invoke("LoadNextBird", 1f); } } //加载下一只鸟 protected void LoadNextBird(){ Destroy(gameObject); //爆炸特效 GameObject prefabs = Resources.Load("Prefabs/VFX/爆炸烟雾特效") as GameObject; GameObject go = Instantiate(prefabs, transform.position, Quaternion.identity); Destroy(go, 1f); GameManager.Instance.LoadNextBird(); } //设置开始小鸟 public void SetStart(Vector3 position){ state = BirdState.BeforeShoot; transform.position = position; }
新增GameManager,
public class GameManager : MonoBehaviour { public static GameManager Instance { get; private set; } public Bird[] birdList; private int index = -1; private void Awake() { Instance = this; } private void Start() { //在当前场景中查找所有带Bird脚本的对象,不进行排序 birdList = FindObjectsByType<Bird>(FindObjectsSortMode.None); LoadNextBird(); } public void LoadNextBird() { index++; GameEnd(); } public void OnPigDead() { pigTotalCount--; if (pigTotalCount <= 0) { GameEnd(); } } void GameEnd() { print("游戏结束"); } }
效果
游戏结束
修改GameManager,实现猪全部死亡或者鸟全部用完结束游戏
private int pigTotalCount;//剩余猪的数量 private void Start() { //在当前场景中查找所有带Bird脚本的对象,不进行排序 birdList = FindObjectsByType<Bird>(FindObjectsSortMode.None); pigTotalCount = FindObjectsByType<Pig>(FindObjectsSortMode.None).Length; LoadNextBird(); } public void LoadNextBird() { index++; if (index >= birdList.Length) { GameEnd(); } else { birdList[index].SetStart(Slingshot.Instance.shootPoint.transform.position); } } public void OnPigDead() { pigTotalCount--; if (pigTotalCount <= 0) { GameEnd(); } } void GameEnd() { print("游戏结束"); }
修改Destructiable
public virtual void Dead(){ Destroy(gameObject); //爆炸特效 GameObject prefabs = Resources.Load("Prefabs/VFX/爆炸烟雾特效") as GameObject; GameObject go = Instantiate(prefabs, transform.position, Quaternion.identity); Destroy(go, 1f); } • 1 • 2 • 3 • 4 • 5 • 6 • 7
修改Pig
public class Pig : Destructiable { public override void Dead() { base.Dead(); GameManager.Instance.OnPigDead(); } }
效果