Bootstrap

切水果游戏


一、 介绍

经典切水果游戏

可以设置难度
计时器
计分板
随机水果,随机扭矩
设置不同水果发射的概率
line renderer组件画线

在这里插入图片描述

在这里插入图片描述


文本渐隐效果

逐渐降低透明度
用协程方法,“ready”先消失,“go”后消失

在这里插入图片描述


using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class TextFadeOut : MonoBehaviour {

	//fade速度
	public float speed = 0.5f;
	Color color;

	void Start () {

		color = GetComponent<Text>().color;
	
	}
	
	void Update () {

		if (gameObject.activeSelf)
		{
			color.a -= Time.deltaTime * speed;
			GetComponent<Text>().color = color;
		}
	
	}
}

在这里插入图片描述

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class PrepareLevel : MonoBehaviour {

    // 声明两个游戏对象变量,分别用于显示 GetReady 和 GO。
    public GameObject GetReady;
    public GameObject GO;

    // Awake 方法在对象实例化后,首先被调用。在这里设置计时器的时间。
    void Awake()
    {
        GetComponent<Timer>().timeAvailable = SharedSettings.ConfigTime;
    }

    // Start 方法在 Awake 方法之后被调用,用于初始化。
    void Start () {

        // 获取 LevelName 的 Text 组件,设置文本为关卡名称。
        GameObject.Find("GUI/LevelName/LevelName").GetComponent<Text>().text = SharedSettings.LevelName[SharedSettings.LoadLevel];

        // 启动协程,等待一段时间后执行一些操作。
        StartCoroutine(PrepareRoutine());
    }

    // 定义协程,用于等待一段时间后执行一些操作。
    IEnumerator PrepareRoutine()
    {
        // 等待 1 秒。
        yield return new WaitForSeconds(1.0f);

        // 显示 GetReady。
        GetReady.SetActive(true);

        // 等待 2 秒。
        yield return new WaitForSeconds(2.0f);

        // 隐藏 GetReady,显示 GO。
        GetReady.SetActive(false);
        GO.SetActive(true);

        // 等待 1 秒。
        yield return new WaitForSeconds(1.0f);

        // 隐藏 GO。
        GO.SetActive(false);
    }   
}


倒计时(精确到毫秒)

制作难度文本
制作计时器,精确到毫秒

在这里插入图片描述

在这里插入图片描述

using UnityEngine;
using System.Collections;
using UnityEngine.UI;

public class Timer : MonoBehaviour {

    bool run = false; // 是否开始计时
    bool showTimeLeft = true; // 是否显示剩余时间
    bool timeEnd = false; // 时间是否结束

    float startTime = 0.0f; // 计时器开始时间
    float curTime = 0.0f; // 当前时间差
    string curStrTime = string.Empty; // 当前时间字符串
    bool pause = false; // 是否暂停

    public float timeAvailable = 30f; // 可用时间(秒)
    float showTime = 0; // 显示时间

    public Text guiTimer; // 显示计时器的 Text 组件
	public GameObject finishedUI; // 游戏结束后弹出的 UI 界面

    void Start()
    {
        RunTimer();
    }

    public void RunTimer()
    {
        run = true; // 开始计时
        startTime = Time.time; // 获取开始计时的时间
    }

    public void PauseTimer(bool b)
    {
        pause = b; // 设置暂停状态
    }

    public void EndTimer()
    {
        // 计时器结束时执行的操作
    }
	
    void Update () {

        if (pause) // 如果暂停
        {
            startTime = startTime + Time.deltaTime; // 计时器开始时间加上暂停时间
            return;
        }

        if (run) // 如果开始计时
        {
            curTime = Time.time - startTime; // 计算当前时间差
        }

        if (showTimeLeft) // 如果需要显示剩余时间
        {
            showTime = timeAvailable - curTime; // 计算剩余时间
            if (showTime <= 0) // 如果时间已经结束
            {
                timeEnd = true; // 时间结束标志设为 true
                showTime = 0; // 显示时间设为 0

                //弹出UI界面,告诉用户本轮游戏结束。
                //暂停/停止游戏
				finishedUI.SetActive(true); // 显示游戏结束的 UI 界面
            }
        }

        int minutes = (int) (showTime / 60); // 计算分钟数
        int seconds = (int) (showTime % 60); // 计算秒数
        int fraction = (int) ((showTime * 100) % 100); // 计算毫秒数

        curStrTime = string.Format("{0:00}:{1:00}:{2:00}", minutes, seconds, fraction); // 将时间转换成字符串
        guiTimer.text = "Time: " + curStrTime; // 将时间显示在界面上
	
    }
}


游戏关卡难度配置文件

通过设置不同的时间来改变关卡难度
配置文件
初始化时间为60秒
using UnityEngine;
using System.Collections;

public class SharedSettings : MonoBehaviour {

    //计时时间
    public static int ConfigTime = 60; //seconds

    //游戏难度
    public static int LoadLevel = 2;

    //游戏难度名字
    public static string[] LevelName = new string[] { "Easy", "Medium", "Hard", "Extreme" };
}


制作水果

制作水果模型,苹果、西瓜、梨、炸弹。
贴上不同的材质
发射水果刚体,随即范围速度、随即范围发射点、随机扭矩
给水果随机扭矩
ins.GetComponent<Rigidbody>().AddTorque(Random.onUnitSphere * 0.1f, ForceMode.Impulse);

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数组,随机生成水果、设置生成水果的各种概率
using UnityEngine;
using System.Collections;

public class FruitDispenser : MonoBehaviour {

    public GameObject[] fruits;     // 定义一个水果数组,存放不同的水果
    public GameObject bomb;         // 定义一个炸弹对象
    public float z;                 // 用于存放水果的 z 坐标
    public float powerScale;        // 用于计算水果发射力度的缩放值
    public bool pause = false;      // 是否暂停发射水果和炸弹
    bool started = false;           // 是否已经开始发射水果和炸弹
    public float timer = 1.75f;     // 每个水果发射的计时

    void Start () {
	
    }
	
    void Update () {
        if (pause) return;          // 如果暂停,则直接返回

        timer -= Time.deltaTime;    // 每帧减少计时器的值

        if (timer <= 0 && !started) // 如果计时器已经到达 0,且还没有开始发射水果和炸弹
        {
            timer = 0f;             // 计时器归零
            started = true;         // 开始发射水果和炸弹
        }

        if (started)                // 如果已经开始发射水果和炸弹
        {
            if (SharedSettings.LoadLevel == 0)    // 如果是第一关
            {
                if (timer <= 0)     // 如果计时器已经到达 0
                {
                    FireUp();       // 发射水果和炸弹
                    timer = 2.5f;   // 重置计时器
                }
            }
            else if (SharedSettings.LoadLevel == 1)   // 如果是第二关
            { 
                if (timer <= 0)
                {
                    FireUp();
                    timer = 2.0f;
                }
            }
            else if (SharedSettings.LoadLevel == 2)   // 如果是第三关
            {
                if (timer <= 0)
                {
                    FireUp();
                    timer = 1.75f;
                }
            }
            else if (SharedSettings.LoadLevel == 3)   // 如果是第四关
            {
                if (timer <= 0)
                {
                    FireUp();
                    timer = 1.5f;
                }
            }
        }	
    }

    void FireUp()
    {
        if (pause) return;          // 如果暂停,则直接返回

        // 发射必有的水果
        Spawn(false);

        // 第三关中,有一定概率会发射炸弹
        if (SharedSettings.LoadLevel == 2 && Random.Range(0, 10) < 2)
        {
            Spawn(true);
        }

        // 第四关中,有一定概率会发射炸弹
        if(SharedSettings.LoadLevel == 3 && Random.Range(0, 10) < 4)
        {
            Spawn(true);
        }

        // 第二关中,有一定概率会发射炸弹
        if (SharedSettings.LoadLevel == 1 && Random.Range(0, 100) < 10)
        {
            Spawn(true);
        }

        // 第三关中,有一定概率会发射炸弹
        if (SharedSettings.LoadLevel == 2 && Random.Range(0, 100) < 20)
        {
            Spawn(true);
        }

        // 第四关中,有一定概率会发射炸弹
        if (SharedSettings.LoadLevel == 3 && Random.Range(0 ,100) < 30)
        {
            Spawn(true);
        }
    }

    void Spawn(bool isBomb)
    {
        float x = Random.Range(-3.1f, 3.1f);    // 随机生成水果的 x 坐标

        z = Random.Range(14f, 19.8f);           // 随机生成水果的 z 坐标

        GameObject ins;                        

        // 如果不是炸弹,则生成随机的水果
        if (!isBomb)
            ins = Instantiate(fruits[Random.Range(0, fruits.Length)], transform.position + new Vector3(x, 0, z), Random.rotation) as GameObject;
        // 如果是炸弹,则生成炸弹对象
        else
            ins = Instantiate(bomb, transform.position + new Vector3(x, 0, z), Random.rotation) as GameObject;

        // 根据缩放值计算水果发射力度
        float power = Random.Range(1.5f, 1.8f) * -Physics.gravity.y * 1.5f * powerScale; 
        Vector3 direction = new Vector3(-x * 0.05f * Random.Range(0.3f, 0.8f), 1, 0);  // 随机生成水果发射方向
        direction.z = 0f;

        // 设置水果的发射力和旋转
        ins.GetComponent<Rigidbody>().velocity = direction * power;
        ins.GetComponent<Rigidbody>().AddTorque(Random.onUnitSphere * 0.1f, ForceMode.Impulse);
    }

    // 当水果碰到边缘碰撞器时,销毁水果
    void OnTriggerEnter(Collider other)
    {
        Destroy(other.gameObject);
    }
}


line renderer实现“切”的动作

在这里插入图片描述

主要实现了一个类似水果忍者游戏中画线切水果的效果,具体作用如下:

1. 定义了一些变量,如鼠标屏幕坐标、是否按下鼠标左键、线段渲染器等。

2. 实现了一个BlowObject函数来切水果,生成切开的水果的部分并删除切到的水果,同时根据切到的水果类型生成相应的水果泼溅效果,并更新积分。

3. 实现了一个Control函数来控制画线,包括开始画线、鼠标拖动中、线段alpha值大于0.5时进行射线检测等。

4. 实现了一个AddTrailPosition函数来添加画线的点,以及SendTrailPosition函数来将画线的点拷贝到线段渲染器中。

5. 在Update函数中调用Control函数来控制画线,并根据线段的alpha值设置线段的颜色。

6. 在Update函数中更新鼠标屏幕坐标、是否按下鼠标左键等变量的值。
using UnityEngine;
using System.Collections;

public class MouseControl : MonoBehaviour {

    Vector2 screenInp;  //鼠标屏幕坐标

    bool fire = false;  //是否按下鼠标左键
    bool fire_prev = false;  //上一帧是否按下鼠标左键
    bool fire_down = false;  //是否在这一帧按下鼠标左键
    bool fire_up = false;  //是否在这一帧抬起鼠标左键

    public LineRenderer trail;  //线段渲染器

    Vector2 start, end;  //画线的起点和终点

    Vector3[] trailPositions = new Vector3[10];  //保存画线的点的数组

    int index;  //水果类型索引
    int linePart = 0;  //线段部分
    float lineTimer = 1.0f;  //计时器,控制线段的生成速度

    float trail_alpha = 0f;  //线段的透明度
    int raycastCount = 10;  //射线检测点的数量

    //积分
    public int points;

    bool started = false;  //是否开始画线

    //果汁效果预制品
    public GameObject[] splashPrefab;
    public GameObject[] splashFlatPrefab;

    void Start () {
    }

    void BlowObject(RaycastHit hit)
    {
        if (hit.collider.gameObject.tag != "destroyed")
        {
            //生成切开的水果的部分
            hit.collider.gameObject.GetComponent<ObjectKill>().OnKill();

            //删除切到的水果
            Destroy(hit.collider.gameObject);

            if (hit.collider.tag == "red") index = 0;
            if (hit.collider.tag == "yellow") index = 1;
            if (hit.collider.tag == "green") index = 2;

            //水果泼溅效果
            if (hit.collider.gameObject.tag != "bomb")
            {
                Vector3 splashPoint = hit.point;
                splashPoint.z = 4;
                Instantiate(splashPrefab[index], splashPoint, Quaternion.identity);
                splashPoint.z += 4;
                Instantiate(splashFlatPrefab[index], splashPoint, Quaternion.identity);
            }

            //切到炸弹
            if (hit.collider.gameObject.tag != "bomb") points++; else points -= 5;
            points = points < 0 ? 0 : points;

            hit.collider.gameObject.tag = "destroyed";
        }
    }

    void Update () {

        Vector2 Mouse;

        screenInp.x = Input.mousePosition.x;
        screenInp.y = Input.mousePosition.y;

        fire_down = false;
        fire_up = false;

        fire = Input.GetMouseButton(0);
        if (fire && !fire_prev) fire_down = true;
        if (!fire && fire_prev) fire_up = true;
        fire_prev = fire;

        //控制画线
        Control();

        //设置线段的相应颜色
        Color c1 = new Color(1, 1, 0, trail_alpha);
        Color c2 = new Color(1, 0, 0, trail_alpha);
        trail.SetColors(c1, c2);

        if (trail_alpha > 0) trail_alpha -= Time.deltaTime;
    }

    void Control()
    {
        //线段开始
        if (fire_down)
        {
            trail_alpha = 1.0f;

            start = screenInp;
            end = screenInp;

            started = true;

            linePart = 0;
            lineTimer = 0.25f;
            AddTrailPosition();
        }

        //鼠标拖动中
        if (fire && started)
        {
            start = screenInp;

            var a = Camera.main.ScreenToWorldPoint(new Vector3(start.x, start.y, 10));
            var b = Camera.main.ScreenToWorldPoint(new Vector3(end.x, end.y, 10));

            //判断用户的鼠标(触屏)移动大于0.1后,我们认为这是一个有效的移动,就可以进行一次“采样”(sample)
            if (Vector3.Distance(a, b) > 0.1f)
            {
                linePart++;
                lineTimer = 0.25f;
                AddTrailPosition();
            }

            trail_alpha = 0.75f;

            end = screenInp;
        }

        //线的alpha值大于0.5的时候,可以做射线检测
        if (trail_alpha > 0.5f)
        {
            for (var p = 0; p < 8; p++)
            { 
                for (var i = 0; i < raycastCount; i++)
                {
                    Vector3 s = Camera.main.WorldToScreenPoint(trailPositions[p]);
                    Vector3 e = Camera.main.WorldToScreenPoint(trailPositions[p+1]);
                    Ray ray = Camera.main.ScreenPointToRay(Vector3.Lerp(s, e, i / raycastCount));

                    RaycastHit hit;
                    if (Physics.Raycast(ray, out hit, 100, 1 << LayerMask.NameToLayer("fruit")))
                    {
                        BlowObject(hit);
                    }
                }

            }
        }

        if (trail_alpha <= 0) linePart = 0;

        //根据时间加入一个点
        lineTimer -= Time.deltaTime;
        if (lineTimer <= 0f)
        {
           linePart++;
           AddTrailPosition();
           lineTimer = 0.01f;
        }

        if (fire_up && started) started = false;

        //拷贝线段的数据到linerenderer
        SendTrailPosition();
    }

    void AddTrailPosition()
    {
        if (linePart <= 9)
        {
            for (int i = linePart; i <= 9; i++)
            {
                trailPositions[i] = Camera.main.ScreenToWorldPoint(new Vector3(start.x, start.y, 10));
            }
        }
        else
        {
            for (int ii = 0; ii <= 8; ii++)
            {
                trailPositions[ii] = trailPositions[ii + 1];
            }

            trailPositions[9] = Camera.main.ScreenToWorldPoint(new Vector3(start.x, start.y, 10));
        }
    }

    void SendTrailPosition()
    {
        var index = 0;
        foreach(Vector3 v in trailPositions)
        {
            trail.SetPosition(index, v);
            index++;
        }
    }
}


八、切开水果的特效


八、 游戏管理器


九、 下载工程文件

https://pan.baidu.com/s/15sI2_pMDE1AVHIQ9K_phYg?pwd=fc00

提取码: fc00






;