本项目是通过unity做成的一款趣味小游戏,通过设计框架,用地板和墙面阻挡水果超出边界并且反弹水果,同时水果之间也存在碰撞效果,相同水果碰撞会合成大一号水果,玩法简单,屏幕上方会出现待命水果,点击鼠标,调整位置,松开鼠标水果就会掉落,同时设置了高度限制,水果超过高度,游戏结束。通过UI设计历史高分与当前分数显示,也设立了水果掉落地板和合成新水果的游戏音效。
其他外加功能:按住空格Space实现自动掉落水果,再次按下取消自动掉落,回到正常游戏模式;通过设置限高线的两个位置,通过两个bool变量实现无尽模式。最后的MenuList文件用于实现游戏的暂停和继续以及切换模式。
在Unity中创建脚本文件名记得与编译器里相同。
Fruit文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public enum FruitType
{
one = 0,
two = 1,
three = 2,
four = 3,
five = 4,
six = 5,
seven = 6,
eight = 7,
nine = 8,
ten = 9,
eleven = 10
}
public enum FruitState
{
Ready = 0,//默认状态
StandBy = 1,//通过鼠标控制移动
Dropping = 2,//水果掉落状态
Collision = 3//水果掉落发生碰撞状态 与地板碰撞 与其他水果碰撞
}
public class Fruit : MonoBehaviour
{
public FruitType fruitType = FruitType.one;//默认是第一个水果
private bool isMove = false;//水果是否在移动中
public FruitState fruitState = FruitState.Ready;//设置水果的默认状态
public float limitX = 0.0f;//设置水果在水平方向上的位移距离
public Vector3 originalScale = Vector3.zero;//水果的默认尺寸大小
public float fruitScore = 0;//给水果设置分数
// Use this for initialization
void Start(){}
// Update is called once per frame
void Update()
{
if (!gamemanner.instance.AutoKeys && gamemanner.instance.gameState == GameState.StandBy && fruitState == FruitState.StandBy)
{
if (Input.GetMouseButtonDown(0))
{
isMove = true;
}
if (Input.GetMouseButtonUp(0) && isMove)
{
isMove = false;
this.GetComponent<Rigidbody2D>().gravityScale = 1.0f;//恢复重力
fruitState = FruitState.Dropping;//
gamemanner.instance.gameState = GameState.InPogress;//设置游戏状态为进行中
gamemanner.instance.InvokeCreateFruit(1.0f);//创建新水果
}
if (isMove)
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
transform.position = new Vector3(mousePos.x, transform.position.y, transform.position.z);
}
}
if (transform.position.x > limitX)
{
transform.position = new Vector3(limitX, transform.position.y, transform.position.z);
}
if (transform.position.x < -limitX)
{
transform.position = new Vector3(-limitX, transform.position.y, transform.position.z);
}
//控制水果尺寸的恢复
if (transform.localScale.x < originalScale.x)
{
transform.localScale += Vector3.one * 0.01f;
}
if (transform.localScale.x > originalScale.x)
{
transform.localScale = originalScale;//设置最终的尺寸大小
}
}
void OnCollisionEnter2D(Collision2D col)
{
//处理水果掉落阶段
if (fruitState == FruitState.Dropping)
{
//碰撞到地板
if (col.gameObject.tag.Contains("flower"))
{
gamemanner.instance.gameState = GameState.StandBy;
fruitState = FruitState.Collision;
gamemanner.instance.isNewFruit = false;
gamemanner.instance.hitSource.Play();//播放到掉落地板的声音
}
//碰撞到其他水果
if (col.gameObject.tag.Contains("fruit"))
{
gamemanner.instance.isNewFruit = false;
gamemanner.instance.gameState = GameState.StandBy;
fruitState = FruitState.Collision;
}
}
//处理合成阶段droping collision
if ((int)fruitState >= (int)FruitState.Dropping)
{
if (col.gameObject.tag.Contains("fruit"))
{
//当前的水果类型和碰撞到水果类型是相同的并且不是最后一个水果时 进行合成
if (fruitType == col.gameObject.GetComponent<Fruit>().fruitType && fruitType != FruitType.eleven)
{
//限制合成只执行一次 通过位置来限制
float thisPosxy = transform.position.x + transform.position.y;
float collisionPosxy = col.transform.position.x + col.transform.position.y;
if (thisPosxy > collisionPosxy)
{
gamemanner.instance.CombineNewFruit(fruitType, transform.position, col.transform.position);
//合成后 进行得分统计
gamemanner.instance.totalScore += fruitScore;
gamemanner.instance.totalScoreText.text = "分数:" + gamemanner.instance.totalScore.ToString();
//合成完成后 需要将原来的两个水果删除
GameObject.Destroy(this.gameObject);
GameObject.Destroy(col.gameObject);
}
}
}
}
}
}
gamemanner文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public enum GameState
{
Ready = 0,
StandBy = 1,
InPogress = 2,
GameOver = 3,
CalculateScore = 4
}
public class gamemanner : MonoBehaviour
{
public Image bg;//背景图
public Button startBtn;//开始游戏按钮
public GameObject bornFruitPosition;//出生水果位置
public GameObject[] fruitList;//存储所有水果
public static gamemanner instance;//单例模式
public GameState gameState = GameState.Ready;//设置水果默认状态
public float totalScore = 0;//统计当前这局的分数
public Text totalScoreText;//显示当前这一局的分数
public Text highestScoreText;//显示历史分数
public AudioSource combineSource;//合成音效
public AudioSource hitSource;//撞击的声音
public AudioSource overSource;
public bool AutoKeys = false;
public float timer = 1.0f;
public GameObject collisionFruit;
public bool isNewFruit = false;
public bool FirstPress = true;
// Use this for initialization
void Start()
{
startBtn.onClick.AddListener(StartGame);
instance = this;
}
//开始游戏
public void StartGame()
{
bg.gameObject.SetActive(false);
startBtn.gameObject.SetActive(false);
CreateFruit();//开始游戏后 创建水果
gameState = GameState.StandBy;//初始化游戏状态
totalScoreText.text = "分数:" + totalScore.ToString();//游戏开始后显示当前分数
float highestScore = PlayerPrefs.GetFloat("highestScore");//本地数据持久化存储获取本地的数据
highestScoreText.text = "历史最高:" + highestScore.ToString();
}
public void InvokeCreateFruit(float invokeTime)
{
Invoke("CreateFruit", invokeTime);
}
//创建水果
public GameObject CreateFruit()
{
int index = Random.Range(0, 5);
if (fruitList.Length >= index && fruitList[index] != null)
{
collisionFruit = GameObject.Instantiate(fruitList[index], bornFruitPosition.transform.position, fruitList[index].transform.rotation);
collisionFruit.GetComponent<Rigidbody2D>().gravityScale = 0.0f;//取消重力
collisionFruit.GetComponent<Fruit>().fruitState = FruitState.StandBy;
//currentFruit.GetComponent<Fruit>().AutoKeys = true;
return collisionFruit;
}
return null;
}
//合成新的水果
public void CombineNewFruit(FruitType currentFruitType, Vector3 currentPos, Vector3 collisionPos)
{
Vector3 centerPos = (currentPos + collisionPos) / 2;
int index = (int)currentFruitType + 1;//通过类型来决定新合成水果的索引
GameObject combineFruitObj = fruitList[index];//获取合成新的水果的预制体
GameObject combineFruit = GameObject.Instantiate(combineFruitObj, centerPos, combineFruitObj.transform.rotation);
combineFruit.GetComponent<Rigidbody2D>().gravityScale = 1.0f;
combineFruit.GetComponent<Fruit>().fruitState = FruitState.Collision;
combineFruit.transform.localScale = Vector3.zero;//给新的水果设置为0
combineSource.Play();//播放合成声音
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
if (FirstPress)
{
AutoKeys = true;
isNewFruit = true;
FirstPress = false;
}
else
{
AutoKeys = false;
isNewFruit = false;
FirstPress = true;
if (collisionFruit)
{
GameObject.DestroyImmediate(collisionFruit);
}
InvokeCreateFruit(1.0f);
}
}
if (AutoKeys)
{
if (isNewFruit)
{
//Debug.Log("11111");
GameObject.DestroyImmediate(collisionFruit);
isNewFruit = false;
}
if (timer > 0)
{
timer -= Time.deltaTime;
if (timer <= 0)
{
GameObject currentFruit = CreateFruit();
currentFruit.GetComponent<Rigidbody2D>().gravityScale = 1.0f;//恢复重力
currentFruit.GetComponent<Fruit>().fruitState = FruitState.Dropping;
gameState = GameState.InPogress;//设置游戏状态为进行中
timer = 1.0f;
}
}
}
}
}
TopLine文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class TopLine : MonoBehaviour {
public bool isMove=false;//限高线是否下落
private float limitY=-5f;//限高线落到地面的位置
//控制限高线下落以及进入得分状态
void OpenMoveAndCalculateScore()
{
isMove=true;
gamemanner.instance.gameState=GameState.CalculateScore;
}
void ReLoadScene()
{
//设置历史最高分
float highestScore=PlayerPrefs.GetFloat("highestScore");
if(highestScore<gamemanner.instance.totalScore)
{
PlayerPrefs.SetFloat("highestScore",gamemanner.instance.totalScore);
}
UnityEngine.SceneManagement.SceneManager.LoadScene(0);
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(isMove)
{
if(transform.position.y>limitY)
{
transform.Translate(Vector3.down*0.05f);
}
else
{
isMove=false;//下落到一定位置不在下落
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
//Invoke("ReLoadScene",1f);//重新开始游戏
}
}
}
//触发检测
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag.Contains("fruit"))
{
//判断游戏是否结束
if((int)gamemanner.instance.gameState<(int)GameState.GameOver)
{
//并且水果是collision状态
if(col.gameObject.GetComponent<Fruit>().fruitState==FruitState.Collision)
{
gamemanner.instance.gameState=GameState.GameOver;
gamemanner.instance.overSource.Play();
Invoke("OpenMoveAndCalculateScore",0.5f);
}
}
//游戏结束后 限高线掉落 并且与掉落过程中所碰到的水果进行得分统计
if(gamemanner.instance.gameState==GameState.CalculateScore)
{
float currentScore=col.GetComponent<Fruit>().fruitScore;
gamemanner.instance.totalScore+=currentScore;
gamemanner.instance.totalScoreText.text="得分:"+gamemanner.instance.totalScore.ToString();
GameObject.Destroy(col.gameObject);//销毁碰到的水果
}
}
}
}
TopLineEnd文件——用于实现无尽模式
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TopLineEnd : MonoBehaviour {
public bool isMove=false;//限高线是否下落
public bool isup = false;//限高线是否上升
public float posy = 2.98f;//限高线原始位置
private float limitY=-0.5f;//限高线落到0.5的位置
//控制限高线下落以及进入得分状态
void OpenMoveAndCalculateScore()
{
isMove=true;
gamemanner.instance.gameState=GameState.CalculateScore;
}
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(isMove)
{
if(transform.position.y>limitY)
{
transform.Translate(Vector3.down*0.05f);
}
else
{
isMove=false;//下落到一定位置不在下落
gamemanner.instance.gameState=GameState.StandBy;//改变游戏模式
isup = true;//限高线上升
}
}
if(isup)
{
transform.Translate(Vector3.up*0.05f);
if(transform.position.y > posy)
{
isup = false;//限高线停止上升
}
}
}
//触发检测
void OnTriggerEnter2D(Collider2D col)
{
if(col.gameObject.tag.Contains("fruit"))
{
//判断游戏是否结束
if((int)gamemanner.instance.gameState<(int)GameState.GameOver)
{
//并且水果是collision状态
if(col.gameObject.GetComponent<Fruit>().fruitState==FruitState.Collision)
{
gamemanner.instance.gameState=GameState.GameOver;
Invoke("OpenMoveAndCalculateScore",0.05f);
}
}
//游戏结束后 限高线掉落 并且与掉落过程中所碰到的水果进行得分统计
if(gamemanner.instance.gameState==GameState.CalculateScore)
{
float currentScore=col.GetComponent<Fruit>().fruitScore;
gamemanner.instance.totalScore+=currentScore;
gamemanner.instance.totalScoreText.text="得分:"+gamemanner.instance.totalScore.ToString();
GameObject.Destroy(col.gameObject);//销毁碰到的水果
}
}
}
}
MenuList文件
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class MenuList : MonoBehaviour {
public GameObject menuList;//菜单列表
[SerializeField] private bool menuKeys=true;//序列化
[SerializeField] private AudioSource combineSource;
[SerializeField] private AudioSource hitSource;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if(menuKeys)
{
if(Input.GetKeyDown(KeyCode.Escape))
{
menuList.SetActive(true);//激活游戏对象 通过此方法让游戏对象显示或者隐藏
menuKeys=false;
Time.timeScale=0;//画面时间暂停
combineSource.Pause();//声音暂停
hitSource.Pause();//声音暂停
}
}
else if(Input.GetKeyDown(KeyCode.Escape))
{
menuList.SetActive(false);
menuKeys=true;
Time.timeScale=1;//画面时间恢复
}
}
public void Return()//返回游戏
{
menuList.SetActive(false);
menuKeys=true;
Time.timeScale=1;//画面时间恢复
//combineSource.Play();//声音播放
//hitSource.Play();//声音播放
}
public void Restart()//重新开始
{
//menuList.SetActive(false);
//menuKeys=true;
SceneManager.LoadScene(0);
Time.timeScale=1;
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);//重新打开当前界面
}
public void Exit()//退出
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex+2);//前进两个界面
}
public void EnterOne()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex+1);//前进一个界面进入经典玩法
}
public void EnterTwo()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex+2);//前进两个界面进入无尽玩法
}
public void BackThree()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex-3);
}
public void ExitGame()//退出游戏
{
Debug.Log("退出");
Application.Quit();
}
}