Unity制作卡牌游戏

我的第一个unity项目是卡牌游戏,是看着慕课网以及用同学分享的项目资源跟着老师做的。慕课网课程的链接,希望老师允许我把课程的链接放在这里,宁静方致远 分享的项目,内含素材,希望他们可以同意把他们的链接放在这里。
游戏功能是判断两张翻转的卡牌是否相同,如果相同就消掉两张卡牌,不相同就把卡牌翻转到背面,游戏共有三个关卡,分别有23、24,2*5张卡牌。下面是游戏的界面
1.panel_start界面
panel_start界面
2.panel_card界面
在这里插入图片描述
3.panel_over界面
在这里插入图片描述
项目的构建过程
1.先建一个unity的3D项目,然后在File——>Build Setting中建一个叫game的Scenes,后期build生成apk的时候用。
2.建目录,在Project window下的Assets(资源)下建各种文件夹用于组织各种资源。我建了四个目录,第一个是Resources,用于保存项目需要的静态资源(图片);Scenes目录,用于用于放置unity场景文件,方便大包时引用;Script目录用于保存文件脚本(C#文件);Testure用于也是用于保存游戏需要的图片。然后把需要的资源导入相应的目录,把Txeture Type(纹理类型)设置为Sprite(2D and UI)

3.在game场景下建一个画布Canvas,在Canvas下建一个个panel,设置其layer为UI,在把Testure下的游戏背景图拖进Source Image,点击set native size,这样一个有图片的panel就弄好了。因为都是同一个背景,所以可以通过Ctrl+d复制panel两次,分别取名Panelstart(游戏开始的主界面),PanelCard(卡牌界面),PanelOver(结束界面)。

4.在PanelStart 下面建一个Button,设置layer为UI,在把Testure下的level1拖进Source Image,点击set native size,在自己调整合适的Button大小。Ctrl复制两次,分别取名ButtonLevel1(关卡一的按钮)、ButtonLevel2(关卡二的按钮)ButtonLevel3(关卡三的按钮),然后在更改ButtonLevel2,ButtonLevel3的Source Image为Level2,Level3图片。通过同样的步骤建立如下的机构,Image_Back是卡牌的背面,Image_front是卡牌的正面,Button_to_start是一个关卡通过后从新回到PanelStart的按钮,Button_to_end关闭游戏。
在这里插入图片描述
4.Script下建立两个脚本,分别是叫gameMain,CardFlipAnimtionCtrl。
gameMain的代码:

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;public class gameMain : MonoBehaviour//只有继承于monobehavior 类的游戏对象才可以直接在unity 中运行
{public Button btnLevel1;public Button btnLevel2;public Button btnLevel3;public Button Button_to_start;public Button Button_to_end;public Transform panelStart;public Transform panelCard;public Transform panelOver;// Start is called before the first frame updatevoid Start()// 从MonoBehaviour继承的方法,start在MonoBehaviour的生命周期中只会被执行一次{//跳转到关卡一btnLevel1.onClick.AddListener(() =>{panelStart.gameObject.SetActive(false);//设置panelStart为不可用,不显示panelStartpanelCard.gameObject.SetActive(true);//设置panelCard为可用LoadLevelCard(3,2);});btnLevel2.onClick.AddListener(() =>{panelStart.gameObject.SetActive(false);panelCard.gameObject.SetActive(true);LoadLevelCard(4,2);});btnLevel3.onClick.AddListener(() =>{panelStart.gameObject.SetActive(false);panelCard.gameObject.SetActive(true);LoadLevelCard(5,2);});//跳转到游戏开始的页面,关闭游戏卡牌界面和游戏结束见面Button_to_start.onClick.AddListener(() => {panelStart.gameObject.SetActive(true);panelCard.gameObject.SetActive(false);panelOver.gameObject.SetActive(false);});//关闭游戏Button_to_end.onClick.AddListener(() => {Application.Quit();});}//跳转到游戏开始界面,即观其选择的那个界面private void ToGameStartPage(){panelStart.gameObject.SetActive(true);panelCard.gameObject.SetActive(false);panelOver.gameObject.SetActive(false);}//为levelCrad界面加载卡牌void LoadLevelCard(int width,int height)//width:卡牌的一行的数量;heigth:卡牌一列的数量{//1.加载卡牌图片Sprite[] sps = Resources.LoadAll<Sprite>("");//加载根目录下的资源,加载Assets下Resources目录下的资源,这个目录名字必须是Resources,卡牌的格式都被设置为Sprite(2D and UI),所以泛型的参数是Sprite/**  for(int i=0;i<sps.Length;i++){Debug.LogError(sps[i].name);//在Unity控制台打印数据的名称}*///2.计算需要加载卡牌的数量,因为每一种牌有两张,所以实际上只需要一半不同的卡牌int totalCount = width * height / 2;//3.计算随机加载卡牌的索引List<Sprite> spsList = new List<Sprite>();//把数组里的数据存到列表里,列表可以调用RemoveAt()删除已经加载的卡牌索引,这样就不会加载同样的图片for (int i = 0; i < sps.Length; i++){spsList.Add(sps[i]);}List<Sprite> needShowCardList = new List<Sprite>();while(totalCount>0){int randomIndex = UnityEngine.Random.Range(0, spsList.Count);needShowCardList.Add(spsList[randomIndex]);//需要加载两个needShowCardList.Add(spsList[randomIndex]);spsList.RemoveAt(randomIndex);//删除已经加载的图片totalCount--;}//高等级通关后在玩低等级要销毁对象,且解除关联Transform contentRoot = panelCard.Find("Panel");//获取panelCard下的Panel节点的对象for (int i = 1; i < contentRoot.childCount; ++i){GameObject itemTemp = contentRoot.GetChild(i).gameObject;Sprite ss = itemTemp.transform.Find("Image_front").GetComponent<Image>().sprite;//获取Image_front的对象Debug.Log(i + "," + ss.name);//打印Image_front对象的名字itemTemp.transform.SetParent(null);//把itemTemp的父节点设置为nullDestroy(itemTemp);//删除itemTemp}//4.显示卡牌到UI上int maxCount = Mathf.Max(contentRoot.childCount, needShowCardList.Count);//比较panel这个节点的子节点的数量和需要展示的卡牌数量的大小GameObject itemPrefab = contentRoot.GetChild(0).gameObject;//获取容器的第一个节点for(int i=0;i<maxCount; i++){int index = Random.Range(0, needShowCardList.Count);GameObject itemObject = null;if(i<contentRoot.childCount){itemObject = contentRoot.GetChild(i).gameObject;//用容器原有的子节点对象给空的对象引用赋值}else{itemObject = GameObject.Instantiate<GameObject>(itemPrefab);//克隆对象itemObject.transform.SetParent(contentRoot, false);//将itemObject的父节点设置为contentRoot,也就是把itemObject添加到panel下}itemObject.transform.Find("Image_front").GetComponent<Image>().sprite = needShowCardList[index];//给图片资源对象赋给sprite属性needShowCardList.RemoveAt(index);//从需要展示的列表里删除已经赋给sprite的图片资源CardFlipAnimtionCtrl cardAniCtrl = itemObject.GetComponent<CardFlipAnimtionCtrl>();cardAniCtrl.SetDefaultState();//设置卡牌默认初始状态}GridLayoutGroup glg = contentRoot.GetComponent<GridLayoutGroup>();//获取contentRoot(panel的对象)的网格布局组的组件/*自动计算panel节点的宽高*宽=元素的个数*元素的宽+元素距离左边的距离+元素距离右边的距离+(元素个数-1 )*元素的间距x**/float panelWidth = width * glg.cellSize.x + glg.padding.left +glg.padding.right + (width - 1) * glg.spacing.x;float panelHeight = height * glg.cellSize.y + glg.padding.top +glg.padding.bottom + (height - 1) * glg.spacing.y;contentRoot.GetComponent<RectTransform>().sizeDelta =new Vector2(panelWidth, panelHeight);//给contenRoot的大小赋值}
//判断玩家是否通关public void CheckIsGameOver(){CardFlipAnimtionCtrl[] allCards= GameObject.FindObjectsOfType<CardFlipAnimtionCtrl>();//首相获取所有对象,找的方法是通过全局检查,找的类型是卡牌动画脚本。if(allCards!=null&&allCards.Length>0){List<CardFlipAnimtionCtrl> cardInFront = new List<CardFlipAnimtionCtrl>(); //这个list是用来存储遍历过程中翻到正面的卡牌,快捷键:选中一个变量,按f12,快速跳到这变量所在个的位置for(int i=0;i<allCards.Length;i++){CardFlipAnimtionCtrl cardTem = allCards[i];if(cardTem.isInFront && !cardTem.isOver){cardInFront.Add(cardTem);}if(cardInFront.Count>=2)//当翻转的两张牌了两张牌以上{string cardImageName1 = cardInFront[0].getCradImageName();string cardImageName2 = cardInFront[1].getCradImageName();if(cardImageName1==cardImageName2){cardInFront[0].MatchSuccess();//需要做的事情为,把这两张牌标记为匹配结束状态cardInFront[1].MatchSuccess();}else{cardInFront[0].MatchFail();//把卡牌翻转到反面cardInFront[1].MatchFail();}bool isAllOver =true;for (int j=0;j<allCards.Length;j++){isAllOver &= allCards[j].isOver;//当数组中的CardFlipAnimtionCtrl的isOver为ture时isAllover才为ture}if(isAllOver){ToGameOverPage();}break;}}}}private void ToGameOverPage(){panelStart.gameObject.SetActive(false);panelCard.gameObject.SetActive(false);panelOver.gameObject.SetActive(true);}//ctrl+—号快速返回原来的位置
}

在脚本里声明的的button变量只有和button按钮关联才会有作用,关联的方法:第一种方法点击Main Camera,在将对应的button按钮拖到对应的变量上面
在这里插入图片描述
后者点击变量旁边的小圆圈,在Select Button选择对应的Button
在这里插入图片描述
为panel添加Grid Layout Group组件:点击add Component,在弹出的搜索框中搜索Grid Layout Group
Grid Layout Group是为了组织卡牌元素。
在这里插入图片描述
CardFlipAnimationCtrl(卡牌翻转动画控制)代码

using System;
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;//封装卡牌的属性和操作
public class CardFlipAnimtionCtrl : MonoBehaviour,IPointerClickHandler
{Transform cardFront;//卡牌的正面Transform cardBack;//卡牌的反面float flipDuaration=0.2f;public bool isInFront = false;//卡牌是否正面朝上public bool isOver=false;//正面朝上的卡牌是否匹配成功public void OnPointerClick(PointerEventData eventData)//当鼠标点击触发的事件{if (isOver) return;//如果已经配对成功就不需要任何操作了if (!isInFront){StartCoroutine(FlipCardToFront());//将翻转到正面}else{StartCoroutine(FlipCardToBack());}}//把卡牌翻转到正面IEnumerator FlipCardToFront(){//1.翻转反面到90度cardFront.gameObject.SetActive(false);cardBack.gameObject.SetActive(true);cardFront.rotation = Quaternion.identity;//卡牌初始角度,Quaternion.identity相当于Quaternion.Euler(0,0,0)while (cardBack.rotation.eulerAngles.y < 90)//欧拉角小于90°的时候,一直执行{cardBack.rotation *= Quaternion.Euler(0, Time.deltaTime*90f*(1f/flipDuaration), 0);//0.2秒内翻转90°if(cardBack.rotation.eulerAngles.y>90)//当欧拉角大90°时设置为90°{cardBack.rotation = Quaternion.Euler(0, 90, 0);break;}yield return new WaitForFixedUpdate();}//翻转卡牌到正面cardFront.gameObject.SetActive(true);cardBack.gameObject.SetActive(false);cardFront.rotation = Quaternion.Euler(0, 90, 0);//设置卡牌初始状态的欧拉角为90度while(cardFront.rotation.eulerAngles.y>0){cardFront.rotation *= Quaternion.Euler(0, -Time.deltaTime * 90f * (1f / flipDuaration),0);if(cardFront.rotation.eulerAngles.y>90){cardFront.rotation = Quaternion.Euler(0, 0, 0);break;}yield return new WaitForFixedUpdate();}isInFront = true;Camera.main.GetComponent<gameMain>().CheckIsGameOver();//每次将牌翻转到正面都要调用gameMain类中的CheckIsGameOver()的方法判断是不是所有的开牌都匹配成功//应为这个脚本是放在主相机,通过主相机的对象可以获取这个脚本的对象,然后获取其方法。}//把卡牌翻转到反面IEnumerator FlipCardToBack(){//翻转正面到90°,翻转反面到0°cardFront.gameObject.SetActive(true);cardBack.gameObject.SetActive(false);cardBack.rotation = Quaternion.identity;while(cardFront.rotation.eulerAngles.y<90){cardFront.rotation *= Quaternion.Euler(0, Time.deltaTime * 90f * (1f / flipDuaration), 0);if(cardFront.rotation.eulerAngles.y>90){cardFront.rotation = Quaternion.Euler(0, 90, 0);break;}yield return new WaitForFixedUpdate();}cardFront.gameObject.SetActive(false);cardBack.gameObject.SetActive(true);while(cardBack.rotation.eulerAngles.y>0){cardBack.rotation *= Quaternion.Euler(0, -Time.deltaTime * 90f * (1f / flipDuaration), 0);if(cardBack.rotation.eulerAngles.y>90){cardBack.rotation = Quaternion.Euler(0, 0, 0);break;}yield return new WaitForFixedUpdate();}isInFront = false;}// Start is called before the first frame update//初始化cardFront,cardBackvoid Start(){cardFront = transform.Find("Image_front");cardBack = transform.Find("Image_back");}// Update is called once per framevoid Update(){}//得到卡牌的名字internal string getCradImageName(){return cardFront.GetComponent<Image>().sprite.name;}//两只卡牌匹配成功internal void MatchSuccess(){isOver = true;//卡牌匹配成功cardFront.gameObject.SetActive(false);cardBack.gameObject.SetActive(false);}//两张卡牌匹配失败internal void MatchFail(){StartCoroutine(FlipCardToBack());//将卡牌翻转为反面朝上}//设置卡牌的默认状态即初始状态internal void SetDefaultState(){isInFront = false;isOver = false;if (cardFront != null){cardFront.gameObject.SetActive(false);cardFront.rotation = Quaternion.identity;}if (cardBack != null){cardBack.gameObject.SetActive(true);cardBack.rotation = Quaternion.identity;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/58481.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

百度搜索框搜索时显示或者隐藏历史搜索记录

1.首先进入百度首页 2.找到设置下的搜索设置&#xff0c;如下图所示 3.点击“搜索设置”会出现如下图的弹框&#xff0c;有搜索历史记录的设置&#xff0c;“显示”或者“不显示”。

在谷歌搜索框内不显示搜索记录

在谷歌搜索框内不显示搜索记录 在不删除谷歌历史浏览记录的前提下&#xff0c;不主动显示浏览记录。 操作步骤如上图所示&#xff0c;在数据与个性化中找到网络与应用活动记录&#xff0c;点进去&#xff0c;然后关闭 推荐用edge&#xff0c;可以轻松切换用户&#xff0c;管理…

google 输入栏不显示历史搜索记录方法

网上看了很多回答&#xff0c;试了都不起作用。这里记录一下我的方法&#xff0c;供大家参考。 第一步&#xff1a;在google输入栏输入&#xff1a;chrome://version 查看浏览器信息。其中有个个人资料路径 第二步&#xff1a;在文件夹中找到该路径&#xff0c;路径下有个His…

企业数据分析分四步走:描述、诊断、预测、指导

谈到数据,大家都喜欢拿大数据说事儿,精准营销、客户管理、企业洞察,但事实上,对于大部分中小型企业来说,把创立至今多少年来各个渠道积攒下来的数据统合到一起,也仅仅只是小数据而已。 这些数据,选用合适的工具,可以非常轻松的管好。不过,在选工具之前可以先问自己这…

什么是RLHF

什么是RLHF&#xff1f; **字面翻译&#xff1a;**RLHF (Reinforcement Learning from Human Feedback) &#xff0c;即以强化学习方式依据人类反馈优化语言模型。 强化学习从人类反馈&#xff08;RLHF&#xff09;是一种先进的AI系统训练方法&#xff0c;它将强化学习与人类…

ChatGPT,我跟不动了,你呢?

周末扒出来一个 10 多年前的老系统&#xff0c;搁现在绝对得老破旧一个&#xff0c;如果要升级改造&#xff0c;绝对不如重写速度快。打开编辑器&#xff0c;从 JSP 翻到 XML 配置文件&#xff0c;基本还算看得懂&#xff0c;不过还是太久远了&#xff0c;把玩起来难度比较大。…

chatgpt赋能python:用Python开发软件的步骤

用 Python 开发软件的步骤 Python 是一种广泛使用的编程语言&#xff0c;因其灵活性、易读性以及可扩展性而备受推崇。Python 也有许多应用场景。在本文中&#xff0c;我们将重点介绍使用 Python 开发软件的基本步骤&#xff0c;帮助初学者入门。 第一步&#xff1a;确定需求…

关于在手机端可以看到加入的百度网盘群,在pc段找不到的原因

1.应该有人和我遇到过一样的问题&#xff0c;在手机上加入的百度网盘群&#xff0c;一直都存在&#xff0c;而在电脑端的时候&#xff0c;有时候登陆会显示出群&#xff0c;有时候却找不到&#xff0c;遇到群友分享的学习资料下载下来却找不到路&#xff0c;你说气不气。为了让…

盖茨笔记:人工智能时代已经开始

来源&#xff1a;比尔盖茨 In my lifetime, I’ve seen two demonstrations of technology that struck me as revolutionary. 我平生见识过两次令我印象深刻、革命性的技术演示。 The first time was in 1980, when I was introduced to a graphical user interface—the fore…

人工智能时代已经开始

In my lifetime, I’ve seen two demonstrations of technology that struck me as revolutionary. 我平生见识过两次令我印象深刻、革命性的技术演示。 The first time was in 1980, when I was introduced to a graphical user interface—the forerunner of every modern op…

警惕GPT对个人电脑中文件的读取!!!

最近在使用chatgpt帮忙写代码时&#xff0c;出现了不可思议的一幕&#xff0c;有可能是是我的见识太浅薄。 由于和gpt对话时&#xff0c;用的多了以后&#xff0c;我的提问方式变得比较简洁&#xff0c;想不到GPT并没有给我代码&#xff0c;而是让我告诉他数据的路径和对应的列…

【工具】1744- Claude2:GPT4 强劲竞争对手来了,完全免费!

关注 “AI 工具派” 探索最新 AI 工具&#xff0c;发现 AI 带来的无限可能性&#xff01; 「近期热门」 AI Colors&#xff1a;轻松定制你的网页配色方案Albus&#xff1a;探索你的无限创意PMAI&#xff1a;优秀的产品经理 AI 帮手Forefront Chat&#xff1a;免费的 GPT-4 聊天…

照片生成漫画头像的软件,试试这个方法很好用

相信很多朋友都喜欢看动漫或者漫画吧&#xff0c;有时候遇到喜欢的人物有没有过把自己代入漫画里呢&#xff1f;我倒是有过&#xff0c;想象自己在漫画里是什么样子&#xff0c;但是如果想把照片变成漫画效果&#xff0c;找画师的话既费时又费钱。其实只要使用把照片生成漫画的…

分享一个把照片变成漫画的方法

不知道小伙伴们平时喜欢看卡通动漫吗&#xff1f;在一些二次元圈子里的小伙伴肯定都会有一些自己非常喜欢的画风和角色&#xff0c;我也有将喜欢的动漫人物的卡通图片用作头像&#xff0c;这样的话不会像真人头像那样会暴露隐私说不定还会发现一些同样爱好的小伙伴。但是还有一…

不知道图片变漫画怎么弄?来跟我学这几个简单的方法

我想问经常换头像的朋友一个问题&#xff0c;你们有用过自己的漫画脸当头像吗&#xff1f;如果我们把自己的头像做成漫画脸不仅不容易和别人撞头像而且更加能贴合我们自身的形象。那你们知道漫画脸怎么拍吗&#xff1f;今天我来给大家分享几个漫画脸制作都的方法。有兴趣的朋友…

照片变漫画怎么做?分享这几个照片变漫画的技巧给你

大家在网上是否有看到过一些绘画博主给别人画漫画图呢&#xff1f;这些图片中的人物形象与现实中的非常相像&#xff0c;而且看起来真的很像漫画中的人物一般&#xff0c;画出来对于一些没有绘画功底的人来说是比较困难的。那么我们又该如何得到我们在漫画中的图片呢&#xff1…

瞧瞧我们对漫画图片都做了什么!?

动手点关注 干货不迷路 概述 漫画是一种以图片为主体的内容形式&#xff0c;我们在实现漫画业务需求时&#xff0c;不可避免地会和图片打交道。本文总结了番茄小说业务场景中两个和图片相关的技术需求&#xff0c;在此抛出遇到的问题与团队的解决思路&#xff0c;望能抛砖引玉。…

数据结构---绪论

个人复习&#xff0c;欢迎指正&#xff01; 参考教材《数据结构教程》&#xff08;第五版&#xff09; 李春葆主编 清华大学出版社 1.1.1数据结构的定义 数据&#xff1a;描述客观事物的数和字符的集合&#xff1b; 数据元素&#xff1a;数据的基本单位&#xff1b…

获取英文期刊的封面及目录

通过期刊编辑部获取。直接给编辑部的 Journal Manager 发邮件&#xff0c;索取封面和目录。 以 Elsevier 旗下期刊为例&#xff1a;使用“通讯作者”邮箱发邮件到support_chineseelsevier.com - 主题&#xff1a;通讯作者需要自己已发表论文当期期刊的纸本样式封面和目录页 PDF…

写论文检索文献总结

毕业季写论文如何快速找资料呢 国外文献检索网站 1.IEEE(电气与电子工程师协会),&#xff0c;IEEE在电气及电子工程、计算机、通信等领域发表的技术文献数量占全球同类文献的30% https://ieeexplore.ieee.org/Xplore/home.jsp 2.Elsevier世界上公认的高品位学术期刊 https:/…