一、 介绍
经典切水果游戏
可以设置难度
计时器
计分板
随机水果,随机扭矩
设置不同水果发射的概率
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