文章目录
- 一、 介绍
- SpringJoint2D 、line renderer制作发射绳
- 基类bird脚本的基础功能
- 给bird添加飞行拖尾效果
- pig类
- 游戏胜利的小星星烟花界面
- 摄像机跟随移动
- 游戏失败的界面
- 多种小鸟的制作:黄鸟、绿鸟、黑鸟
- 地图选择
- 关卡选择
- 数据保存
- 制作多个关卡
- 场景异步加载
- 游戏全局管理器
- 源文件下载
一、 介绍
SpringJoint2D
line renderer
动画制作
协程
异步资源加载
resource文件夹存储关卡数据
playerprefs存储关卡信息
trail拖尾效果
SpringJoint2D 、line renderer制作发射绳
基类bird脚本的基础功能
bird脚本是红鸟的专属脚本,yellow鸟、green鸟、black鸟可以在此基础上进行拓展。
以下是函数的简要作用:
-
OnMouseDown(): 处理鼠标按下事件,设置isClick为true,并禁用刚体组件。
-
OnMouseUp(): 处理鼠标抬起事件,设置isClick为false,延迟0.1秒后开始飞行,禁用划线组件,设置canMove为false。
-
Update(): 处理小鸟移动和相机跟随的逻辑,以及炫技操作。
-
Fly(): 在飞行状态下播放飞行音效,开启拖尾效果,禁用弹簧关节,5秒后自动切换到下一只小鸟。
-
Line(): 实现划线逻辑。
-
AudioPlay(): 实现音效播放。
-
Next(): 切换到下一只小鸟。
-
Hurt(): 处理小鸟受伤逻辑。
-
ShowSkill(): 处理小鸟炫技效果。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bird : MonoBehaviour {
private bool isClick = false; //是否点击了小鸟
public float maxDis = 3; //弹弓的最大拉伸距离
[HideInInspector]
public SpringJoint2D sp; //SpringJoint2D组件
protected Rigidbody2D rg; //Rigidbody2D组件
public LineRenderer right; //右边的划线组件
public Transform rightPos; //右边的点
public LineRenderer left; //左边的划线组件
public Transform leftPos; //左边的点
public GameObject boom; //小鸟死亡的爆炸效果
protected TestMyTrail myTrail; //拖尾效果
private bool canMove = true; //是否可以移动
public float smooth = 3; //相机跟随的平滑度
public AudioClip select; //选择小鸟的音效
public AudioClip fly; //小鸟飞行的音效
private bool isFly = false; //是否在飞行中
public Sprite hurt; //受伤后的图片
protected SpriteRenderer render; //SpriteRenderer组件
private void Awake()
{
sp = GetComponent<SpringJoint2D>();
rg = GetComponent<Rigidbody2D>();
myTrail = GetComponent<TestMyTrail>();
render = GetComponent<SpriteRenderer>();
}
private void OnMouseDown() //鼠标按下
{
if (canMove)
{
AudioPlay(select); //播放选择小鸟的音效
isClick = true; //设置为点击状态
rg.isKinematic = true; //关闭物理效果
}
}
private void OnMouseUp() //鼠标抬起
{
if (canMove)
{
isClick = false; //设置为非点击状态
rg.isKinematic = false; //开启物理效果
Invoke("Fly", 0.1f); //延迟0.1秒后开始飞行
//禁用划线组件
right.enabled = false;
left.enabled = false;
canMove = false; //不可移动
}
}
private void Update()
{
if (isClick) //鼠标一直按下,进行位置的跟随
{
transform.position = Camera.main.ScreenToWorldPoint(Input.mousePosition);
//transform.position += new Vector3(0, 0, 10);
transform.position += new Vector3(0,0,-Camera.main.transform.position.z);
if (Vector3.Distance(transform.position, rightPos.position) > maxDis) //进行位置限定
{
Vector3 pos = (transform.position - rightPos.position).normalized; //单位化向量
pos *= maxDis; //最大长度的向量
transform.position = pos + rightPos.position;
}
Line(); //绘制划线
}
//相机跟随
float posX = transform.position.x;
Camera.main.transform.position = Vector3.Lerp(Camera.main.transform.position, new Vector3(Mathf.Clamp(posX,0,15),Camera.main.transform.position.y,
Camera.main.transform.position.z),smooth*Time.deltaTime);
if (isFly)
{
if (Input.GetMouseButtonDown(0))
{
ShowSkill(); //炫技操作
}
}
}
void Fly()
{
isFly = true; //设置为飞行状态
AudioPlay(fly); //播放飞行的音效
myTrail.StartTrails(); //开启拖尾效果
sp.enabled = false; //禁用弹簧关节
Invoke("Next", 5); //飞行5秒后自动切换到下一只小鸟
}
/// <summary>
/// 划线
/// </summary>
void Line()
{
right.enabled = true;
left.enabled = true;
right.SetPosition(0, rightPos.position);
right.SetPosition(1, transform.position);
left.SetPosition(0, leftPos.position);
left.SetPosition(1, transform.position);
}
/// <summary>
/// 下一只小鸟的飞出
/// </summary>
///
protected virtual void Next()
{
GameManager._instance.birds.Remove(this); //从GameManager中移除当前小鸟
Destroy(gameObject); //销毁当前小鸟
Instantiate(boom, transform.position, Quaternion.identity); //生成爆炸效果
GameManager._instance.NextBird(); //切换到下一只小鸟
}
private void OnCollisionEnter2D(Collision2D collision)
{
isFly = false; //设置为非飞行状态
myTrail.ClearTrails(); //清除拖尾效果
}
public void AudioPlay(AudioClip clip)
{
AudioSource.PlayClipAtPoint(clip, transform.position); //在指定位置播放音效
}
/// <summary>
/// 炫技操作
/// </summary>
public virtual void ShowSkill()
{
isFly = false; //设置为非飞行状态
}
public void Hurt()
{
render.sprite = hurt; //切换为受伤后的图片
}
}
给bird添加飞行拖尾效果
给bird添加一个子对象,命名为 Trail,为其添加 WeaponTrail.cs脚本、 Mesh Renderer组件,材质为Pocket RPG Trails提供的材质,设置好如下图所示:
修改 TestMyTrail.cs代码为如下:
using UnityEngine;
using System.Collections;
public class TestMyTrail : MonoBehaviour {
public WeaponTrail myTrail;
private Animator animator;
private float t = 0.033f;
private float tempT = 0;
private float animationIncrement = 0.003f;
void Start ()
{
animator = GetComponent<Animator>();
}
void LateUpdate()
{
t = Mathf.Clamp(Time.deltaTime, 0, 0.066f);
if (t > 0)
{
while (tempT < t)
{
tempT += animationIncrement;
if (myTrail.time > 0)
{
myTrail.Itterate(Time.time - t + tempT);
}
else
{
myTrail.ClearTrail();
}
}
tempT -= t;
if (myTrail.time > 0)
{
myTrail.UpdateTrail(Time.time, t);
}
}
}
void OnGUI()
{
if (GUI.Button( new Rect( 0, 0, 50, 50), "攻击"))
{
animator.SetTrigger( "Attack");
}
}
}
将 Trail对象赋给 My Trail属性,如下图所示:
修改 TestMyTrail.cs 代码为如下:
void Start ()
{
animator = GetComponent<Animator>();
// 默认没有拖尾效果
myTrail.SetTime( 0.0f, 0.0f, 1.0f);
}
public void heroAttack()
{
//设置拖尾时长
myTrail.SetTime( 2.0f, 0.0f, 1.0f);
//开始进行拖尾
myTrail.StartTrail( 0.5f, 0.4f);
}
public void heroIdle()
{
//清除拖尾
myTrail.ClearTrail();
}
参考链接:https://blog.csdn.net/akof1314/article/details/37603559
资源链接:https://download.csdn.net/download/akof1314/7610241
pig类
这个脚本可以挂载到pig上,也可以挂在砖头上,受伤后速度值过大直接销毁,速度适中展示“损坏”的效果。
//导入命名空间
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//定义一个猪的类
public class Pig : MonoBehaviour {
//定义最大速度和最小速度
public float maxSpeed = 0.01f;
public float minSpeed = 0.005f;
//定义一个SpriteRenderer
private SpriteRenderer render;
//定义一个hurt的Sprite
public Sprite hurt;
//定义一个炸弹和得分的游戏对象
public GameObject boom;
public GameObject score;
//定义三种音效
public AudioClip hurtClip;
public AudioClip dead;
public AudioClip birdCollision;
//判断是否为猪
public bool isPig = false;
//定义一个Awake方法,在脚本被启用前执行一次
private void Awake()
{
//获取SpriteRenderer组件
render = GetComponent<SpriteRenderer>();
}
//定义一个OnCollisionEnter2D方法,在碰撞发生时执行
private void OnCollisionEnter2D(Collision2D collision)
{
//判断碰撞对象是否为Player
if (collision.gameObject.tag == "Player") {
//播放birdCollision音效
AudioPlay(birdCollision);
//让Bird受伤
collision.transform.GetComponent<Bird>().Hurt();
}
//如果相对速度大于最大速度,直接死亡
if (collision.relativeVelocity.magnitude > maxSpeed)
{
Dead();
}
//如果相对速度在最大速度和最小速度之间,播放hurt音效
else if (collision.relativeVelocity.magnitude > minSpeed && collision.relativeVelocity.magnitude < maxSpeed) {
render.sprite = hurt;
AudioPlay(hurtClip);
}
}
//定义一个Dead方法,处理猪死亡的逻辑
public void Dead() {
//如果是猪,从GameManager中移除猪
if (isPig)
{
GameManager._instance.pig.Remove(this);
}
//销毁猪的游戏对象
Destroy(gameObject);
//在猪的位置生成一个炸弹
Instantiate(boom, transform.position, Quaternion.identity);
//在猪的位置生成得分的游戏对象,并延迟1.5秒后销毁
GameObject go = Instantiate(score, transform.position + new Vector3(0,0.5f,0), Quaternion.identity);
Destroy(go, 1.5f);
//播放死亡音效
AudioPlay(dead);
}
//定义一个AudioPlay方法,用于播放音效
public void AudioPlay(AudioClip clip)
{
//在猪的位置播放指定的音效
AudioSource.PlayClipAtPoint(clip, transform.position);
}
}
游戏胜利的小星星烟花界面
一颗一颗显示星星:
public void ShowStars() {
StartCoroutine("show");
}
IEnumerator show() {
for (; starsNum < birds.Count + 1; starsNum++)
{
if (starsNum >= stars.Length) {
break;
}
yield return new WaitForSeconds(0.2f);
stars[starsNum].SetActive(true);
}
print(starsNum);
}
摄像机跟随移动
//相机跟随
float posX = transform.position.x;
Camera.main.transform.position = Vector3.Lerp(Camera.main.transform.position,new Vector3(Mathf.Clamp(posX,0,15),Camera.main.transform.position.y,
Camera.main.transform.position.z),smooth*Time.deltaTime);
游戏失败的界面
图片嵌套,设置动画,透明度渐变。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PausePanel : MonoBehaviour
{
private Animator anim;
public GameObject button;
private void Awake()
{
anim = GetComponent<Animator>();
}
public void Retry() {
Time.timeScale = 1;
UnityEngine.SceneManagement.SceneManager.LoadScene(2);
}
/// <summary>
/// 点击了pause按钮
/// </summary>
public void Pause()
{
//1、播放pause动画
anim.SetBool("isPause", true);
button.SetActive(false);
}
/// <summary>
/// 点击了继续按钮
/// </summary>
public void Resume() {
//1、播放resume动画
Time.timeScale = 1;
anim.SetBool("isPause", false);
}
public void Home()
{
Time.timeScale = 1;
UnityEngine.SceneManagement.SceneManager.LoadScene(1);
}
/// <summary>
/// pause动画播放完调用
/// </summary>
public void PauseAnimEnd() {
Time.timeScale = 0;
}
/// <summary>
/// resume动画播放完调用
/// </summary>
public void ResumeAnimEnd() {
button.SetActive(true);
}
}
多种小鸟的制作:黄鸟、绿鸟、黑鸟
各种鸟,都继承红鸟bird的基础功能,进而拓展自己的功能。
黄鸟点击屏幕可以加速:
public class YellowBird : Bird {
/// <summary>
/// 重写方法
/// </summary>
public override void ShowSkill()
{
base.ShowSkill();
rg.velocity *= 2;
}
}
绿鸟点击屏幕可以回旋:
public class GreenBird : Bird {
public override void ShowSkill()
{
base.ShowSkill();
Vector3 speed = rg.velocity;
speed.x *= -1;
rg.velocity = speed;
}
}
黑鸟点击屏幕发生爆炸,把一定范围的pig通过处罚监测存到list中,全部销毁
using System.Collections; //导入命名空间System.Collections
using System.Collections.Generic; //导入命名空间System.Collections.Generic
using UnityEngine; //导入命名空间UnityEngine
public class BlackBird : Bird { //定义名为BlackBird的类,继承自Bird类
public List<Pig> blocks = new List<Pig>(); //定义名为blocks的Pig类型的列表
/// <summary>
/// 进入触发区域
/// </summary>
/// <param name="collision"></param>
private void OnTriggerEnter2D(Collider2D collision) //当进入触发区域时
{
if (collision.gameObject.tag == "Enemy") { //如果触碰到的物体标签为“Enemy”
blocks.Add(collision.gameObject.GetComponent<Pig>()); //将触碰到的物体的Pig组件添加到blocks列表中
}
}
/// <summary>
/// 离开触发区域
/// </summary>
/// <param name="collision"></param>
private void OnTriggerExit2D(Collider2D collision) //当离开触发区域时
{
if (collision.gameObject.tag == "Enemy") //如果触碰到的物体标签为“Enemy”
{
blocks.Remove(collision.gameObject.GetComponent<Pig>()); //将触碰到的物体的Pig组件从blocks列表中移除
}
}
public override void ShowSkill() //重写父类的ShowSkill方法
{
base.ShowSkill(); //调用父类的ShowSkill方法
if (blocks.Count > 0 && blocks != null) { //如果blocks列表中有元素
for (int i = 0; i < blocks.Count; i++) { //循环遍历blocks列表中的元素
blocks[i].Dead(); //调用Pig类的Dead方法
}
}
OnClear(); //调用自定义的OnClear方法
}
void OnClear() { //自定义名为OnClear的方法
rg.velocity = Vector3.zero; //将刚体的速度设置为零向量
Instantiate(boom,transform.position,Quaternion.identity); //在对象的位置生成一个boom预制体
render.enabled = false; //关闭SpriteRenderer组件
GetComponent<CircleCollider2D>().enabled = false; //关闭CircleCollider2D组件
myTrail.ClearTrails(); //调用自定义的ClearTrails方法清空拖尾效果
}
protected override void Next() //重写父类的Next方法
{
GameManager._instance.birds.Remove(this); //将当前对象从GameManager类的birds列表中移除
Destroy(gameObject); //销毁对象
GameManager._instance.NextBird(); //调用GameManager类的NextBird方法
}
}
地图选择
关卡选择
数据保存
public void SaveData() {
if (starsNum > PlayerPrefs.GetInt(PlayerPrefs.GetString("nowLevel"))){
PlayerPrefs.SetInt(PlayerPrefs.GetString("nowLevel"), starsNum);
}
//存储所有的星星个数
int sum = 0;
for (int i = 1; i <= totalNum; i++) {
sum += PlayerPrefs.GetInt("level" + i.ToString());
}
PlayerPrefs.SetInt("totalNum",sum);
//print(PlayerPrefs.GetInt("totalNum"));
}
PlayerPrefs类:用于存储游戏数据,包括玩家的设置和游戏状态。
GetInt()方法:从PlayerPrefs中获取一个整数值。
GetString()方法:从PlayerPrefs中获取一个字符串值。
SetInt()方法:将一个整数值存储到PlayerPrefs中。
制作多个关卡
新建文件夹RESOURCE,自己制作不同的关卡,用于方便后续加载
场景异步加载
设置分辨率,加载到选择地图界面。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class LoadLevelAsync : MonoBehaviour {
// Use this for initialization
void Start() {
Screen.SetResolution(960,600,false);
Invoke("Load",2);
}
void Load() {
SceneManager.LoadSceneAsync(1);
}
}
游戏全局管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
public List<Bird> birds; // 小鸟列表
public List<Pig> pig; // 猪列表
public static GameManager _instance; // 游戏管理器实例
private Vector3 originPos; //初始化的位置
public GameObject win; // 胜利界面
public GameObject lose; // 失败界面
public GameObject[] stars; // 星星
private int starsNum = 0; // 星星数量
private int totalNum = 9; // 总星星数量
private void Awake()
{
_instance = this;
if(birds.Count > 0) {
originPos = birds[0].transform.position;
}
}
private void Start()
{
Initialized();
}
/// <summary>
/// 初始化小鸟
/// </summary>
private void Initialized()
{
for(int i = 0; i < birds.Count; i++)
{
if (i == 0) //第一只小鸟
{
birds[i].transform.position = originPos;
birds[i].enabled = true;
birds[i].sp.enabled = true;
}
else
{
birds[i].enabled = false;
birds[i].sp.enabled = false;
}
}
}
/// <summary>
/// 判定游戏逻辑
/// </summary>
public void NextBird()
{
if(pig.Count > 0)
{
if(birds.Count > 0)
{
//下一只飞吧
Initialized();
}
else
{
//输了
lose.SetActive(true);
}
}
else
{
//赢了
win.SetActive(true);
}
}
public void ShowStars() {
StartCoroutine("show");
}
IEnumerator show() {
for (; starsNum < birds.Count + 1; starsNum++)
{
if (starsNum >= stars.Length) {
break;
}
yield return new WaitForSeconds(0.2f);
stars[starsNum].SetActive(true);
}
print(starsNum);
}
public void Replay() {
SaveData();
SceneManager.LoadScene(2);
}
public void Home() {
SaveData();
SceneManager.LoadScene(1);
}
public void SaveData() {
if (starsNum > PlayerPrefs.GetInt(PlayerPrefs.GetString("nowLevel"))){
PlayerPrefs.SetInt(PlayerPrefs.GetString("nowLevel"), starsNum);
}
//存储所有的星星个数
int sum = 0;
for (int i = 1; i <= totalNum; i++) {
sum += PlayerPrefs.GetInt("level" + i.ToString());
}
PlayerPrefs.SetInt("totalNum",sum);
//print(PlayerPrefs.GetInt("totalNum"));
}
}
维护小鸟列表(birds)和猪列表(pig)。
实现了单例模式,通过静态变量 _instance 获取 GameManager 的实例。
存储初始位置(originPos)。
引用胜利界面(win)和失败界面(lose)的游戏对象。
存储星星的数组(stars)。
跟踪星星数量(starsNum)和总星星数量(totalNum)。
在 Awake 方法中设置 GameManager 的实例和初始位置。
在 Start 方法中调用 Initialized 方法进行初始化。
Initialized 方法用于初始化小鸟列表中的小鸟,将第一只小鸟设置在初始位置,其他小鸟禁用。
NextBird 方法根据游戏逻辑判断游戏输赢,并在相应情况下显示胜利或失败界面。
ShowStars 方法使用协程逐个显示星星。
Show 方法用于协程,控制星星的显示过程。
Replay 方法用于重新加载场景。
Home 方法用于返回主菜单。
SaveData 方法用于保存游戏数据,包括更新关卡的星星数量和总星星数量。
源文件下载
https://wwez.lanzoul.com/iBdeT0whs3gh