赞
踩
要实现的功能
游戏操作
在规定时间内,垃圾通过拖拽进入正确垃圾桶的容器,垃圾在这里消失,飞入第二个屏上对应垃圾桶的位置并实现加分和加时间的效果,垃圾拖拽进入不正确的垃圾桶,垃圾会返回到原来的位置,同时,相应的时间也会减少
胜利和失败的条件:
胜利:垃圾全部分类完毕,并且时间不为零,游戏胜利,
失败:时间为0,垃圾未分类结束,游戏失败
游戏结束后,可以点击屏幕可以重新进入游戏,重新进入游戏时,垃圾的排列会发生变化
游戏代码梳理
需要一个每个垃圾自己的类,涉及垃圾自己的属性,都放在这个类里面,例如:垃圾的拖拽,整个游戏中,只有垃圾需要拖拽的功能,这个是只属于垃圾的功能,就放在这个类里面
每个垃圾桶自己的类,涉及垃圾桶的属性,都放在这里面,例如:垃圾进入和离开垃圾桶的碰撞器
垃圾和垃圾桶之间交互的管理类,例如:垃圾和垃圾桶之间分类正确加分,错误减分,垃圾的布局
游戏胜利和失败等都是在这个类中
双屏显示的类
新建两个canvas,分别命名:MainCanvas和ViceCanvas,新建一个摄像机,名为:ViceCamera
设置MainCamera和MainCanvas属性,如图所示
ViceCamera和ViceCanvas的Target Display设置为DisPlay2,把ViceCamera上面的Audio Listence删掉,一个场景中只需要一个Audio Listence
新建一个C#脚本,名为:SplitScreen,编写代码
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- /// <summary>
- /// 分屏代码
- /// </summary>
- public class SplitScreen : MonoBehaviour
- {
- void Start()
- {
- if (Display.displays.Length > 1)
- Display.displays[1].Activate();
- if (Display.displays.Length > 2)
- Display.displays[2].Activate();
- }
- }
在MainCanvas下面新建一个空物体:GarbagePanel ,铺满全屏,管理类的代码放在这个上面,一直都显示
在GarbagePanel下面新建一个空物体:root,铺满全屏,作为垃圾分类主界面的容器,所有的图片文字视频都放在这里面
在root下
新建图片:bg,铺满全屏,把背景图片拖进去,
新建空物体:garbageItemContent,铺满全屏,用来存放所有垃圾,把所有的垃圾都拖进来,作为他的子物体,每个垃圾都添加BoxCollide2Dr和Rigibody2D,手动调节碰撞盒的大小,(这里设置的是100*100),将Rigibody2D的重力值大小设为0(防止垃圾往下坠落)设置垃圾的标签,不同的垃圾设置不同的标签recycle,dry,wet,hamful
新建C#脚本:GarbageItem,运用鼠标拖拽的三个接口实现垃圾拖拽的操作
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
-
- public class GarbageItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
- {
- Vector2 offest; //鼠标的偏移量
- Vector2 startPos; //垃圾初始位置
- Vector2 oldPos; //鼠标拖拽结束之后的位置
-
- RectTransform rect; //垃圾的RectTransform(当垃圾消失(垃圾的setactive为false)时,垃圾的RectTransform为空)
-
- //组件初始化
- void InitCompoment()
- {
- if (rect==null)
- {
- rect = GetComponent<RectTransform>();
- }
- }
-
- //数据初始化
- void InitData(Vector2 pos)
- {
- //组件初始化
- InitCompoment();
-
- //位置初始化
- startPos = pos;
- RestoreOriginPos();
-
- //TODO:与垃圾桶的关系
-
- }
-
- //位置修改
- void RestoreOriginPos()
- {
- //获取初始位置
- startPos = rect.anchoredPosition;
- }
-
- //鼠标开始拖拽
- public void OnBeginDrag(PointerEventData eventData)
- {
- //拖拽过程中的偏移量
- offest = eventData.position - (Vector2)transform.position;
- }
-
- //鼠标拖拽过程
- public void OnDrag(PointerEventData eventData)
- {
- //垃圾的位置限制,不能拖出屏幕外
- Vector2 pos = eventData.position - offest;
- transform.position = new Vector3(Mathf.Clamp(pos.x, 0, Screen.width), Mathf.Clamp(pos.y, 0, Screen.width), 0);
-
- //拖拽完毕后的位置
- oldPos = eventData.position - offest;
- }
-
- //拖拽结束
- public void OnEndDrag(PointerEventData eventData)
- {
- //TODO:完成加分,加时间等操作,需要与垃圾桶,和管理者交互
- }
- }
但是,我们只是做到了垃圾的拖拽,但是与垃圾桶的交互和游戏的逻辑制作,后面会做这些工作
新建一个空物体:TrashCanRoot,放在屏幕上方,调整大小
在TrashCanRoot的下面新建四个图片,代表四种类型的垃圾桶,每个垃圾筒上都添加BoxCollider2D和Rigidbody2D组件,在BoxCollider2D中勾选IsTrigger,设置Rigidbody2D的重力值为0,并为每个垃圾桶添加标签,如图所示
新建C#脚本:Trash
在GarbageItem中添加垃圾桶的引用,并实现封装
在数据初始化中添加:Trash = null;
在鼠标拖拽结束的代码中,添加
编辑Trash脚本
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
-
- /// <summary>
- /// 垃圾桶
- /// </summary>
- public class Trash : MonoBehaviour
- {
- #region 垃圾进入垃圾桶的碰撞器
- private void OnTriggerEnter2D(Collider2D collision)
- {
- if (collision.transform.GetComponent<GarbageItem>() != null)
- collision.transform.GetComponent<GarbageItem>().Trash = this;
- }
- #endregion
-
- #region 物体离开垃圾桶的碰撞器
- private void OnTriggerExit2D(Collider2D collision)
- {
- //离开后设置垃圾桶为空
- if (collision.transform.GetComponent<GarbageItem>() != null)
- collision.transform.GetComponent<GarbageItem>().Trash = null;
- }
- #endregion
-
- }
副屏上面的界面
新建四个空物体,挂载Audio Source组件,把对应的音效文件拖入Clip中,如图
编写脚本
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine.UI;
- using UnityEngine;
- using UnityEngine.Audio;
- using Interface;
- using DG.Tweening;
-
- /// <summary>
- /// 垃圾分类面板脚本
- /// </summary>
- public class GarbagePanel : MonoBehaviour, BubbleContent
- {
- public bool isGameOver; //游戏是否结束 true结束 false未结束
- int createNumber = 0; //随机次数 为了创建垃圾item的不同位置
-
- int sumScore = 0; //总分数(由垃圾item容器子物体数量决定)
- int timer = 300; //时间
-
- public int score = 0; //分数
-
- GarbageItem currentItem; //当前正在拖拽的垃圾item
-
- Tweener addTimerTweener; //加减时间动画
-
- [Header("游戏最大持续时间")]
- public int maxTimer = 180;
-
- [Header("退出按钮")]
- [SerializeField] Button quitBtn;
-
- [Header("正确、错误、游戏胜利、游戏失败音效")]
- [SerializeField] AudioSource correntAudio;
- [SerializeField] AudioSource errorAudio;
- [SerializeField] AudioSource victoryAudio;
- [SerializeField] AudioSource defeatedAudio;
-
- [Header("游戏胜利/失败Text,2屏时间、分数、加时间Text,点击屏幕刷新游戏按钮")]
- [SerializeField] Text gameOverTxt;
- public Text timeTxt;
- public Text scoreTxt;
- [SerializeField] Button refreshBtn;
-
- [Header("2屏加时间Text,加减分颜色")]
- [SerializeField] Color addColor;
- [SerializeField] Color subtractColor;
- [SerializeField] Text addTimerTxt;
-
- [Header("加分星星动画预设,星星容器")]
- [SerializeField] Transform starPrefab;
- [SerializeField] Transform starContent;
- List<Transform> starPool; //星星对象池
- List<Transform> moveStarList; //正在播放的星星特效
-
- [Header("2屏的垃圾桶位置")]
- public Transform twoSceneTrashPos;
-
- [Header("1屏 所有垃圾item存放容器")]
- public Transform garbageItemContent;
-
- [Header("垃圾分类root,2屏垃圾分类界面")]
- [SerializeField] GameObject root;
- [SerializeField] GameObject twoSceneRoot;
-
- List<GarbageItem> moveGarbageList; //正在dotween移动的垃圾item
- List<Vector2> garbageItemPosRotList; //垃圾item的所有位置
- Dictionary<string, Transform> twoSceneTrashPosDic; //2屏的垃圾桶位置字典
- public Dictionary<string, Transform> TwoSceneTrashPosDic { get => twoSceneTrashPosDic; set => twoSceneTrashPosDic = value; } //封装 GarbageItem调用
- public List<GarbageItem> MoveGarbageList { get => moveGarbageList; }
- public GarbageItem CurrentItem { get => currentItem; set => currentItem = value; }
-
- //单例
- static GarbagePanel instance;
- public static GarbagePanel GetInstance()
- {
- return instance;
- }
- void Awake()
- {
- instance = this;
- }
-
- void Start()
- {
- starPool = new List<Transform>();
- moveStarList = new List<Transform>();
- moveGarbageList = new List<GarbageItem>();
-
- //DoTween动画
- addTimerTweener = addTimerTxt.DOFade(0, 2f);
- addTimerTweener.SetAutoKill(false);
- addTimerTweener.Pause();
-
- //默认颜色透明
- addTimerTxt.color = new Color32(0, 0, 0, 0);
-
- //初始化所有垃圾的位置
- garbageItemPosRotList = new List<Vector2>();
- foreach (Transform item in garbageItemContent)
- {
- garbageItemPosRotList.Add(item.GetComponent<RectTransform>().anchoredPosition);
- }
-
- //2垃圾桶位置字典初始化
- twoSceneTrashPosDic = new Dictionary<string, Transform>();
- foreach (Transform item in twoSceneTrashPos)
- {
- twoSceneTrashPosDic.Add(item.tag, item);
- }
-
- //按钮监听
- quitBtn.onClick.AddListener(ReturnMainPanel);
- refreshBtn.onClick.AddListener(RefreshGame);
- }
-
-
-
- #region 游戏刷新
- IEnumerator timerIE; //时间倒数
- void RefreshGame()
- {
- //游戏未结束
- isGameOver = false;
-
- //不为空 先停止协程,然后在开启,防止冲突
- if (timerIE != null)
- StopCoroutine(timerIE);
-
- //音效停止
- StopAllAudio();
-
- //隐藏刷新,游戏结束提示按钮
- refreshBtn.gameObject.SetActive(false);
- gameOverTxt.gameObject.SetActive(false);
-
- //回收所有加分星星
- RecycleAllStar();
-
- //刷新垃圾item布局
- RefreshGarbage();
-
- //总分数、时间、分数 初始化
- sumScore = garbageItemContent.childCount;
- score = 0;
- timer = maxTimer;
- scoreTxt.text = "分数:" + score.ToString();
- timeTxt.text = "时间:" + timer.ToString();
-
- //开启协程
- timerIE = GameTime();
- StartCoroutine(timerIE);
-
- }
- #endregion
-
- #region 刷新垃圾item布局
- public void RefreshGarbage()
- {
- int count = garbageItemContent.childCount;
-
- //创建次数超过垃圾最大数量时为0
- if (createNumber > count - 1)
- createNumber = 0;
-
- for (int i = 0; i < count; i++)
- {
- int index = i + createNumber;
-
- //当下标超出最后一位时为0
- if (index > count - 1)
- index = Mathf.Abs(count - index);
-
- //位置初始化
- garbageItemContent.GetChild(i).GetComponent<GarbageItem>().InitData(garbageItemPosRotList[index]);
- }
-
- //创建数量加1
- createNumber++;
- }
-
- #endregion
-
- #region 游戏时间
- IEnumerator GameTime()
- {
- while (timer > 0)
- {
- yield return new WaitForSeconds(1f);
-
- //当游戏时间结束前,游戏胜利可以将timer等于-1
- timer--;
- if (timer<=0)
- timer = 0;
-
- timeTxt.text = "时间:" + timer;
-
- }
-
- //停止所有正在移动的垃圾item和星星动画
- StopAllGarbageItemAndStar();
-
- //游戏结束判断
- if (score >= sumScore)
- {
- Debug.Log("时间结束:" + score + " child:" + sumScore);
- GameVictory(); //游戏胜利
- }
- else
- GameDefeated(); //游戏失败
-
- }
-
- /// <summary>
- /// 游戏胜利
- /// </summary>
- void GameVictory()
- {
- //游戏结束
- isGameOver = true;
-
- //停止所有正在移动的垃圾item和星星动画
- StopAllGarbageItemAndStar();
-
- VictoryAudio(); //胜利音效
-
- //刷新按钮,游戏结束Txt显示
- refreshBtn.gameObject.SetActive(true);
- gameOverTxt.gameObject.SetActive(true);
-
- gameOverTxt.text = "游戏胜利";
- }
-
- /// <summary>
- /// 游戏失败
- /// </summary>
- void GameDefeated()
- {
- //游戏结束
- isGameOver = true;
-
- //停止所有正在移动的垃圾item和星星动画
- StopAllGarbageItemAndStar();
-
- DefeatedAudio();//失败音效
-
- //刷新按钮,游戏结束Txt显示
- refreshBtn.gameObject.SetActive(true);
- gameOverTxt.gameObject.SetActive(true);
-
- gameOverTxt.text = "游戏失败";
-
- }
- #endregion
-
- #region 加分(星星效果)
- /// <summary>
- /// 加分
- /// </summary>
- /// <param name="pos">垃圾item消失的位置</param>
- public void AddScore(Vector3 pos)
- {
- //获取星星动画,修改位置
- Transform star = GetStar();
- star.position = pos;
- star.gameObject.SetActive(true);
-
- //星星正在播放 添加到列表
- moveStarList.Add(star);
- }
-
- //获取星星
- Transform GetStar()
- {
- Transform star;
- //判断对象池是否存在item
- if (starPool.Count > 0)
- {
- star = starPool[0];
- starPool.Remove(star);
- }
- else
- star = Instantiate(starPrefab, starContent);
-
- return star;
- }
-
- //星星回收(动画播放完毕后,回收星星到对象池中)由动画关键帧调用
- public void RecycleStar(Transform star)
- {
- /*回收*/
-
- //星星播放结束 从列表移除
- moveStarList.Remove(star);
-
- star.gameObject.SetActive(false);
- starPool.Add(star);
-
- 加分
- //score++;
- //scoreTxt.text = "分数:" + score.ToString();
-
- 加时间
- //ADDTimer();
-
- 播放音效
- //CorrentAudio();
-
- //判断所有垃圾分类完成
- if (score >= sumScore)
- {
- Debug.Log("加分结束胜利:" + score + " child:" + sumScore);
-
- //停止时间协程
- StopCoroutine(timerIE);
-
- GameVictory(); //游戏胜利
- }
- }
-
- /// <summary>
- /// 回收所有加分星星
- /// </summary>
- void RecycleAllStar()
- {
- for (int i = 0; i < starContent.childCount; i++)
- {
- Transform star = starContent.GetChild(i);
- star.gameObject.SetActive(false);
-
- //对象池中不存在此星星时,回收
- if (starPool.IndexOf(star) == -1)
- starPool.Add(star);
- }
- }
- #endregion
-
- #region 加减游戏时间
-
- /// <summary>
- /// 游戏时间+2秒
- /// </summary>
- public void ADDTimer()
- {
- addTimerTxt.text = "时间+2";
- addTimerTxt.color = addColor;
- addTimerTweener.Restart();
-
- timer += 2;
- if (timer >= maxTimer)
- timer = maxTimer;
-
- timeTxt.text = "时间:" + timer.ToString();
- }
- /// <summary>
- /// 游戏时间-2秒
- /// </summary>
- public void SubtractTimer()
- {
- addTimerTxt.text = "时间-2";
- addTimerTxt.color = subtractColor;
- addTimerTweener.Restart();
-
- timer -= 2;
- if (timer <= 0)
- {
- timer = 0;
- //游戏失败
- GameDefeated();
- }
-
- timeTxt.text = "时间:" + timer.ToString();
-
-
- }
- #endregion
-
- #region 隐藏并停止所有动画及效果
-
- /// <summary>
- /// 隐藏并停止所有垃圾动画效果、星星效果、正在拖拽的物体
- /// 防止游戏结束时,
- /// </summary>
- void StopAllGarbageItemAndStar()
- {
- if (currentItem != null)
- {
- currentItem.RestoreOriginPos();
- currentItem = null;
- }
-
- //循环所有在移动的item
- for (int i = 0; i < MoveGarbageList.Count; i++)
- MoveGarbageList[i].StopDoTween(); //停止dotween动画
-
- for (int i = 0; i < moveStarList.Count; i++)
- {
- //隐藏星星
- moveStarList[i].gameObject.SetActive(false);
- //添加到对象池中
- starPool.Add(moveStarList[i]);
- }
- }
- #endregion
-
- #region 音效播放
-
- /// <summary>
- /// 正确
- /// </summary>
- public void CorrentAudio()
- {
- correntAudio.Play();
- }
- /// <summary>
- /// 错误
- /// </summary>
- public void ErrorAudio()
- {
- errorAudio.Play();
- }
-
- /// <summary>
- /// 胜利
- /// </summary>
- public void VictoryAudio()
- {
- victoryAudio.Play();
- }
-
- /// <summary>
- /// 失败
- /// </summary>
- public void DefeatedAudio()
- {
- defeatedAudio.Play();
- }
-
- /// <summary>
- /// 停止所有音效
- /// </summary>
- public void StopAllAudio()
- {
- correntAudio.Stop();
- errorAudio.Stop();
- victoryAudio.Stop();
- defeatedAudio.Stop();
- }
- #endregion
-
- }
GarbageItem中代码的添加和修改
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.EventSystems;
- using UnityEngine.UI;
- using DG.Tweening;
-
- /// <summary>
- /// 垃圾Item
- /// </summary>
- public class GarbageItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
- {
- Vector2 offset; //偏移量
- Vector2 oldPos; //鼠标拖拽结束之后的位置
- Vector2 originPos; //物体原点位置
-
- RectTransform rect;
-
- Trash trash; //垃圾桶
- public Trash Trash { get => trash; set => trash = value; }
-
- #region 组件初始化
- void ThisGetCompontent()
- {
- if (rect == null)
- {
- rect = GetComponent<RectTransform>();
- }
- }
-
- #endregion
-
- #region 数据初始化
- public void InitData(Vector2 pos)
- {
- //组件初始化
- ThisGetCompontent();
-
- //刷新后 垃圾桶为空
- Trash = null;
-
- //位置修改
- originPos = pos;
- RestoreOriginPos();
-
- //显示
- gameObject.SetActive(true);
- }
-
- #endregion
-
- //位置还原
- public void RestoreOriginPos()
- {
- rect.anchoredPosition = originPos;
- }
-
- //开始拖拽
- public void OnBeginDrag(PointerEventData eventData)
- {
- GarbagePanel.GetInstance().CurrentItem = this;
- offset = eventData.position - (Vector2)transform.position;
- }
-
- //拖拽
- public void OnDrag(PointerEventData eventData)
- {
- //游戏结束 不执行操作
- if (GarbagePanel.GetInstance().isGameOver)
- return;
-
- Vector3 pos = eventData.position - offset;
- transform.position = new Vector3(Mathf.Clamp(pos.x, 0, Screen.width), Mathf.Clamp(pos.y, 0, Screen.height), 0);
-
- oldPos = eventData.position - offset;
- }
-
- //拖拽结束
- Tweener tweener;
- public void OnEndDrag(PointerEventData eventData)
- {
- //游戏结束 不执行操作
- if (GarbagePanel.GetInstance().isGameOver)
- return;
-
- //垃圾桶不为空,代表垃圾进入了垃圾桶
- if (trash != null)
- {
- //判断垃圾与垃圾桶的tag是否相同
- if (trash.tag==transform.tag)
- {
- //Debug.Log("正确,执行位移,并加分");
-
- //加分
- GarbagePanel.GetInstance().score++;
- GarbagePanel.GetInstance().scoreTxt.text = "分数:" + GarbagePanel.GetInstance().score.ToString();
-
- //加时间
- GarbagePanel.GetInstance().ADDTimer();
-
- // 播放音效
- GarbagePanel.GetInstance(). CorrentAudio();
-
- //dotween动画正在移动,添加自己
- GarbagePanel.GetInstance().MoveGarbageList.Add(this);
-
- //修改垃圾item在2屏的垃圾桶位置
- rect.anchoredPosition = originPos;
- Debug.Log(rect);
- rect.SetParent(GarbagePanel.GetInstance().twoSceneTrashPos);
- rect.anchoredPosition = GarbagePanel.GetInstance().TwoSceneTrashPosDic[transform.tag].GetComponent<RectTransform>().anchoredPosition;
-
- tweener = rect.DOAnchorPos(new Vector2(rect.anchoredPosition.x, -14), 1f);
- tweener.OnComplete((TweenCallback)delegate
- {
- //Debug.Log("消失");
-
- //dotween移动结束,移除自己
- GarbagePanel.GetInstance().MoveGarbageList.Remove(this);
-
- //加分
- GarbagePanel.GetInstance().AddScore(transform.position);
-
- //修改为1屏的父物体
- gameObject.SetActive(false);
- rect.SetParent((Transform)GarbagePanel.GetInstance().garbageItemContent);
-
- });
- }
- else
- {
- //减时间
- GarbagePanel.GetInstance().SubtractTimer();
-
- //播放错误音效
- GarbagePanel.GetInstance().ErrorAudio();
-
- //垃圾回到原来的位置
- rect.anchoredPosition = originPos;
- //Debug.Log("错误");
- }
-
- }
- else
- {
- //垃圾回到原来的位置
- rect.anchoredPosition = originPos;
- }
-
- //拖拽结束 设置为空
- GarbagePanel.GetInstance().CurrentItem = null;
- //加分结束后,垃圾桶设置为空
- trash = null;
- }
-
-
- /// <summary>
- /// 停止dotween动画
- /// </summary>
- public void StopDoTween()
- {
- //dotween移动结束,移除自己
- GarbagePanel.GetInstance().MoveGarbageList.Remove(this);
-
- //停止并杀死动画,防止有残留
- tweener.Pause();
- tweener.Kill();
-
- //隐藏自己,并修改为1屏的父物体
- gameObject.SetActive(false);
- rect.SetParent(GarbagePanel.GetInstance().garbageItemContent);
- }
-
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。