切水果小游戏

这几天跟着视频学做了一个切水果的游戏(用UGUI做的),有点粗糙记录一下。~在导入一些素材包的时候发现一些prefab丢失了,变成了白纸 ( 可能是我的unity版本有点低了╮(╯▽╰)╭)
1.png
2.png
没办法只能自己动手做几个预设了(apple lemon watermelon以及一些特效)ps:特效没接触过看了下网上的介绍自己尝试着做几个出来 - -

OK,Let's do it!

一、开始页面搭建
1、调整画布以及基本的界面布置
3.png

这里我将SoundButton和SoundSlider都放在一个空物体里面,方便管理以及锚点设置。


4.png
2、添加一个脚本用来注册点击事件、音量控制、声音播放。

ps:值得一提的是,平时我们注册点击事件都是写一个方法,然后将其拖拽到Button组件的OnClick里实现,这里可以通过监听的方式简化我们的操作。

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

public class UIStart : MonoBehaviour {
    /// <summary>
    /// 开始按钮
    /// </summary>
    private Button PlayButton;

    /// <summary>
    /// 声音按钮
    /// </summary>
    public Button SoundButton;

    /// <summary>
    /// 添加背景音乐
    /// </summary>
    public  AudioSource Audio_Bg;

    /// <summary>
    ///声音的图片 
    /// </summary>
    public Sprite[] soundSprites;

    private Image soundImg;

    /// <summary>
    /// 控制音量滑块
    /// </summary>
    public  Slider soundSlider;

    void Start () {
        getComponents();
        PlayButton.onClick.AddListener(PlayClick);//注册点击事件的第三种方法。监听
        SoundButton.onClick.AddListener(SoundClick);
    }

    void Destory()
    {
        PlayButton.onClick.RemoveListener(PlayClick);
        SoundButton.onClick.RemoveListener(SoundClick);
    }
    /// <summary>
    /// 寻找组件
    /// </summary>
    private void getComponents()
    {
        PlayButton = transform.Find("StartButton").GetComponent<Button>();
       
    }
    /// <summary>
    /// 开始按钮点击调用
    /// </summary>
    void PlayClick()
    {
        SceneManager.LoadScene("play");
    }
    /// <summary>
    /// 声音按钮点击调用
    /// </summary>
    void SoundClick()
    {
        if (Audio_Bg.isPlaying)
        {
            Audio_Bg.Pause();
            soundImg.sprite = soundSprites[1];
        }
        else
        {
            Audio_Bg.Play();
            soundImg.sprite = soundSprites[0];
        }
    }
    /// <summary>
    /// 滑动条控制音量大小
    /// </summary>
    void SoundController()
    {
        if (soundSlider.value == 0)
        {
            Audio_Bg.volume = 0;
        }
        else if (soundSlider.value != 0)
        {
            Audio_Bg.volume = soundSlider.value;
        }
    }

    void Update () {
        SoundController();
    }
}

public Sprite[] soundSprites;
private Image soundImg;
这两个字段用于展现静音和开启音乐的效果(2张图片)。

二、游戏界面内容
5.png
1、设置背景图片--Background
2、实现发射水果

创建一个空物体Spawner,将其摆放在Bg的中下位置也就是水果发射的初始地点,为其添加一个Box Collider组件用于销毁游戏物体节省内存。
创建一个脚本实现水果、炸弹发射。

using UnityEngine;
using System.Collections;
using UnityEngine;
//本脚本功能为产生水果、炸弹以及销毁超出屏幕的预制体
//产生水果时间、水果发射(速度、方向、反重力)、产生多个水果、

/// <summary>
/// 产生水果、炸弹
/// </summary>
public class Spawn : MonoBehaviour {

    [Header("水果的预设")]
    public GameObject[] Fruits;
    [Header("炸弹的预设")]
    public GameObject Bomb;

    public AudioSource audioSource;
    //产生水果的时间
    float spawnTime = 3f;
    //计时
    float currentTime = 0f;

    bool isPlaying = true;

    void Update () {
        if (!isPlaying)
        {
            return;
        }
        
        currentTime += Time.deltaTime;
        if (currentTime >= spawnTime)
        {
            //产生多个水果
            int fruitCount = Random.Range(1, 5);
            for (int i = 0; i < fruitCount; i++)
            {
                //到时间产生水果
                onSpawn(true);
            }

            //生成炸弹
            int bombNum = Random.Range(0, 100);
            if (bombNum > 70)
            {
                onSpawn(false);
            }
            currentTime = 0f;
        }

    }

    private int tmpZ = 0; //临时存储生成体的Z坐标,前提要保证生成体的Z坐标不会超出摄像机。

    /// <summary>
    /// 产生水果
    /// </summary>
    private void onSpawn(bool isFruit)
    {
        //播放音乐
        this.audioSource.Play();
        //x范围在(-8.4,8.4)之间[生成物UI可显示的范围]
        //y : transform.pos.y
        float x = Random.Range(-8.4f, 8.4f);
        float y = transform.position.y;
        float z = tmpZ;

        //保证生成体的Z坐标不会超出摄像机。(摄像机的Z轴坐标为-12.)
        tmpZ -= 2;
        if (tmpZ <= -10)
        {
            tmpZ = 0;
        }
        //定义一个随机数(水果号码)
        int fruitIndex = Random.Range(0, Fruits.Length);

        GameObject go;
        if (isFruit)
        {
            go = Instantiate(Fruits[fruitIndex], new Vector3(x, y, z), Random.rotation) as GameObject;
        }
        else 
        {
            go = Instantiate(Bomb, new Vector3(x, y, z), Random.rotation) as GameObject;
        }
            //给与一个反重力初始速度,飞行方向相反的
            Vector3 velocity = new Vector3(-x * Random.Range(0.2f, 0.8f), -Physics.gravity.y * Random.Range(1.2f, 1.5f));

            Rigidbody rigidbody = go.GetComponent<Rigidbody>();
            rigidbody.velocity = velocity;
        
    }
    /// <summary>
    /// 销毁产生的物体
    /// </summary>
    /// <param name="other"></param>
    private void OnCollisionEnter(Collision other)
    {
        Destroy(other.gameObject);
    }
}

3、生成刀痕

刀痕的生成用Line Renderer

6.png

LineRenderer里的Positions 是记录鼠标在滑动的时候记录下来的实时坐标。通过坐标来连成线。
代码中的head和last,分别是每一帧鼠标所在的位置,和上一帧鼠标所在的位置,这个的确有点绕需要自己多理解一下。(鼠标移动的时候每一帧都有变化。)

7.png
using UnityEngine;
using System.Collections;

//产生刀痕
//产生射线
public class MouseControl : MonoBehaviour {
    
    /// <summary>
    /// 直线渲染器
    /// </summary>
    [SerializeField]
    private LineRenderer lineRenderer;

    /// <summary>
    /// 播放声音
    /// </summary>
    [SerializeField]
    private AudioSource audioSource;

    /// <summary>
    /// 首次按下鼠标
    /// </summary>
    private bool firstMouseDown = false;

    /// <summary>
    /// 一直按住鼠标
    /// </summary>
    private bool onMouseDown = false;

    /// <summary>
    /// 用于存放渲染器位置坐标
    /// </summary>
    private Vector3[] positions = new Vector3[10];

    /// <summary>
    /// 对渲染直线坐标个数的统计
    /// </summary>
    private int posCount = 0;

    /// <summary>
    /// 存储鼠标按下的第一帧位置
    /// </summary>
    private Vector3 head;

    /// <summary>
    /// 存储上一帧鼠标所在的位置
    /// </summary>
    private Vector3 last;

    void Update () {

        if(Input.GetMouseButtonDown(0))
        {
            firstMouseDown = true;
            onMouseDown = true;
            audioSource.Play();
        }
        if(Input.GetMouseButtonUp(0))
        {
            onMouseDown = false;
        }
        OnDrawLine();
        firstMouseDown = false;
    }

    /// <summary>
    /// 画线
    /// </summary>
    private void OnDrawLine()
    {
        if (firstMouseDown)
        {
            posCount = 0;
            head = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            last = head;
        }
        if (onMouseDown)
        {
            head = Camera.main.ScreenToWorldPoint(Input.mousePosition);
            //根据首次按下时与上一次鼠标的位置的距离来判断是否画线。
            if (Vector3.Distance(head, last) > 0.01f)
            {
                setPositions(head);
                posCount++;
                //发射一条射线
                OnDrawRay(head);
            }
            last = head;
        }
        else
        {
            //放鼠标松开时,清空坐标
            positions = new Vector3[10];
        }
        changePosition(positions);
    }

    /// <summary>
    /// 用来存储坐标
    /// </summary>
    private void setPositions(Vector3 pos)
    {
        
        pos.z = 0;
        if (posCount <= 9)
        {
            for (int i = posCount; i < 10; i++)
            {
                positions[i] = pos;
            }
        }
        else
        {
            //坐标个数大于10,将坐标往上挤,将最新的赋值给第十个坐标[下标为9]
            for (int i = 0; i < 9; i++)
            {
                positions[i] = positions[i + 1];
                positions[9] = pos;
            }
        }
    }

    /// <summary>
    /// 发射射线
    /// </summary>
    private void OnDrawRay(Vector3 worldPos)
    {
        Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
        Ray ray = Camera.main.ScreenPointToRay(screenPos);
        
        ////如果射线检测单一物体时用以下方法
        //RaycastHit hit ;
        //if(Physics.Raycast(ray,out hit))
        //{
        //    //执行内容
        //}

        //由于检测到的物体不止一个所以用hits[] 来检测
        RaycastHit[] hits = Physics.RaycastAll(ray);
        for (int i = 0; i < hits.Length; i++)
        {
            //Destroy(hits[i].collider.gameObject);
            hits[i].collider.gameObject.SendMessage("Oncut",SendMessageOptions.DontRequireReceiver);
        }
    }

    /// <summary>
    /// 改变坐标
    /// </summary>
    /// <param name="positions"></param>
    private void changePosition(Vector3[] positions)
    {
        lineRenderer.SetPositions(positions);
    }
}

效果图:
8.png
4、实现水果切半以及特效。
9.png

在每一个完成的水果上添加一个脚本叫ObjectControl

using UnityEngine;
using System.Collections;

/// <summary>
/// 物体控制脚本
/// </summary>
public class ObjectControl : MonoBehaviour {
    /// <summary>
    /// 生成一半水果
    /// </summary>
    public  GameObject halfFruit;

    public GameObject Splash;

    public GameObject SplashFlat;

    public GameObject BombSplash;

    public AudioClip Clip;

    private bool dead = false;

    public void Oncut()
    {
        //保证只切割一次
        if (dead) 
        {
            return;
        }
        if (gameObject.name.Contains("Bomb"))
        {
            GameObject bSplash = Instantiate(BombSplash, transform.position, Quaternion.identity)as GameObject;
            ScoreEditor.Instance_.ReduceScore(20);
            Destroy(bSplash,3.0f);
        }
        else
        {
            //实例化2个切半的水果
            for (int i = 0; i < 2; i++)
            {
                GameObject go = Instantiate(halfFruit, transform.position, Random.rotation) as GameObject;
                go.GetComponent<Rigidbody>().AddForce(Random.onUnitSphere * 5f, ForceMode.Impulse);
                Destroy(go, 2.0f);
            }
            //生成特效

            GameObject Splash1 = Instantiate(Splash, transform.position, Quaternion.identity)as GameObject;
            GameObject Splash2 = Instantiate(SplashFlat, transform.position, Quaternion.identity) as GameObject;
            Destroy(Splash1, 3.0f);
            Destroy(Splash2, 3.0f);
            ScoreEditor.Instance_.AddScore(10);
        }

        AudioSource.PlayClipAtPoint(Clip, transform.position);
        Destroy(gameObject);
        dead = true;
    }
}

5、得分UI以及倒计时
加分与减分:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class ScoreEditor : MonoBehaviour {

    public static ScoreEditor Instance_ = null;

    void Awake()
    {
        Instance_ = this;
    }

    [SerializeField]
    public Text txtScore;

    private int score = 0;

    // Update is called once per frame
    void Update () {
    
    }

    public  void AddScore(int Score)
    {
        score += Score;
        txtScore.text = score.ToString();
    }

    public void ReduceScore(int Score)
    {
        score -= Score;
        if (score <= 0)
        {
            SceneManager.LoadScene("Gameover");
        }
        txtScore.text = score.ToString();

        
    }
}
倒计时:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
/// <summary>
/// 倒计时脚本
/// </summary>
public class showTime : MonoBehaviour
{

    public float time_All = 300;//计时的总时间(单位秒)  
    public float time_Left;//剩余时间  
    public bool isPauseTime = false;
    public Text time;
    // Use this for initialization  
    void Start()
    {
        time_Left = time_All;
    }

    // Update is called once per frame  
    void Update()
    {
        if (!isPauseTime)
        {
            if (time_Left > 0)
                StartTimer();
            else
            {
                SceneManager.LoadScene("Gameover");
            }
        }

    }
    
    /// <summary>  
    /// 获取总的时间字符串  
    /// </summary>  
    string GetTime(float time)
    {
        return GetMinute(time) + GetSecond(time);

    }

    /// <summary>  
    /// 获取小时  
    /// </summary>  
    string GetHour(float time)
    {
        int timer = (int)(time / 3600);
        string timerStr;
        if (timer < 10)
            timerStr = "0" + timer.ToString() + ":";
        else
            timerStr = timer.ToString() + ":";
        return timerStr;
    }
    /// <summary>  
    ///获取分钟   
    /// </summary>  
    string GetMinute(float time)
    {
        int timer = (int)((time % 3600) / 60);
        string timerStr;
        if (timer < 10)
            timerStr = "0" + timer.ToString() + ":";
        else
            timerStr = timer.ToString() + ":";
        return timerStr;
    }
    /// <summary>  
    /// 获取秒  
    /// </summary>  
    string GetSecond(float time)
    {
        int timer = (int)((time % 3600) % 60);
        string timerStr;
        if (timer < 10)
            timerStr = "0" + timer.ToString();
        else
            timerStr = timer.ToString();

        return timerStr;
    }
}
三、结束界面与数据保存
10.png

代码:

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

public class Gameover : MonoBehaviour {

    public Text text;
    public Text nowScore;
    public Text bestScore;

    void Start()
    {
        getScore();
    }

    void Update()
    {
    }

    private void getScore()
    {
       
        text.text = ScoreEditor.Instance_.txtScore.text;
        bestScore.text = text.text;
        bstScore(int.Parse(text.text));
        
    }
    private void bstScore(int NowScore)
    {
        
        int bstScore = PlayerPrefs.GetInt("sr", 0);
        Debug.Log(bstScore);

        if (NowScore > bstScore)
        {
            bstScore = NowScore;
        }
        PlayerPrefs.SetInt("sr", bstScore);
        bestScore.text = bstScore.ToString();
    }
    public void OnClick()
    {
        SceneManager.LoadScene("play");

    }

}

NowScore对应上图中“你的分数”里面的text
BestScore对应上图中“你的最高分数”里面的text


11.png

结束,写的很乱,只是以后自己方便看-。- 哈哈哈。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • This article is a record of my journey to learn Game Deve...
    蔡子聪阅读 3,750评论 0 9
  • Unity3D塔防开发流程 配置环境及场景搭建 编程语言:C#,略懂些许设计模式,如果不了解设计模式,BUG Mo...
    Grape_葡萄阅读 2,923评论 1 3
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,016评论 4 62
  • 华灯初上夜朦胧 霓虹摇曳影婆娑 酒毕随兴漫步走 且聊且笑且高歌 何愁平日苦难多 莫笑他人争不得 醉卧闲谈千古事 有...
    深夜爱瞎想阅读 413评论 0 0
  • 2017年10月8号 蕙兰的咖啡冥想 感恩: 今天是我们洛阳爱心种子读书会,金刚商学院DCI1,2阶学员三个月实践...
    蕙兰坊阅读 257评论 0 2