Unity学习制作Flappy Bird小游戏(超详细全教程,可发布到PC、Web、Android平台)

您所在的位置:网站首页 重力小球游戏玩法视频教程 Unity学习制作Flappy Bird小游戏(超详细全教程,可发布到PC、Web、Android平台)

Unity学习制作Flappy Bird小游戏(超详细全教程,可发布到PC、Web、Android平台)

2024-07-15 02:56| 来源: 网络整理| 查看: 265

本文中Flappy Bird基于Unity2019.4.7f1完成,源工程已部分代码改为适配安卓

在这里插入图片描述

flappy bird:一夜爆红的胖鸟

这是一款简单又困难的手机游戏,游戏中玩家必须控制一只胖乎乎的小鸟,跨越由各种不同长度水管所组成的障碍。上手容易,但是想通关可不简单。Flappy bird 于2013年5月在苹果App Store上线,2014年2月份在100多个国家/地区的榜单一跃登顶,尽管没有精细的动画效果,没有有趣的游戏规则,没有众多的关卡,却突然大火了一把,下载量突破5000万次。

一、工程创建和素材导入

在Assets中创建不同的文件夹,存储声音、图片、脚本、材质素材。

二、添加背景

创建Quad,创建Material,bg,back,pipe,bird,整个场景设置图1所示。其中材质的创建得选择 在这里插入图片描述 图 1 场景制作 Unlit Shader(无光照着色器):它是一个不包含光照(但包含雾效)的基本顶点/片元着色器

三、脚本使小鸟飞起来

关键技术: 小鸟飞行动画由三幅图组成,连续播放三幅图可以看出小鸟的翅膀在动。需要修改offset参数实现。 图 2 小鸟 0为第一个图,0.333为第二个图,0.666为第三个图。因此,每隔0.1s播放一个图片。 比如:0.1s播放offset为0,0.2s播放offset为0.333,0.3s播放offset为0.666 所以调用SetTextureOffset函数 this.GetComponent().velocity 意思是给小鸟一个初始速度,方向为x方向。所以前提是给小鸟一个rigidbody组件。

public float timer=0; public int frameNumber=10; public int frameCount=0;//统计第几帧 void Start() { this.GetComponent().velocity=new Vector3(1,0,0) } void Update(){ timer+=Time.deltaTime; if(timer>=1.0f/frameNumber){ frameCount++; timer-=Time.deltaTime; //修改材质的偏移值 int frameIndex=frameCount%3; this.GetComponent().material.SetTextureOffset("_MainTex",Vector2(0.333f*frameIndex,0)); } }

"_MainTex"是主要的漫反射纹理; "_BumpMap"是法线贴图 "_Cube"是反射cubemap.(立方体贴图)

四、随机生成管道的位置

修改管道的y值 随机值范围 Random.Range(a,b);//也就是说保持x和z不变,y是一个上下变化的值

public class pipe : MonoBehaviour{ void Start(){ RandomGeneratePosition(); } public void RandomGeneratePosition(){ float pos_y=Random.Range(-0.2f,0.2f); this.transform.localPosition=new Vector3(this.transform.localPosition.x,pos_y,this.tranform.localPosition.z); } } 五、添加小鸟、管道碰撞器

小鸟的碰撞器 图 3 小鸟的碰撞器 图 4 碰撞器的限制 锁定x,y方向的旋转,z方向的移动 图 5 小鸟的球型碰撞器 管道的碰撞器 图 6 管道的碰撞器

地面碰撞器 图 7 地面碰撞器 图 8 地面的碰撞器设置

3个背景循环展示

当小鸟走到bg1时,修改bg的位置,放置在bg2前面,依次循环。创建bg为一个预制体,根据这个预制体创建bg1,bg2.修改坐标。创建游戏管理器存放共享的变量、分值、ui等信息。新建一个脚本GameManage,挂在摄像头上。在这个脚本中,定义了一个共享的第一个bg位置,也就是最前面的bg的位置,同时,创建了一个共享单例。 在这里插入图片描述 创建一个MoveTrigger触发器。 图 9 MoveTrigger触发器的设置 图 10 MoveTrigger触发器的设置 图 11 其中,MoveTrigger属于bg下属子物体,当小鸟走到差不多第2个背景时候,触发MoveTrigger,讲左侧的这个bg移动到右侧的bg2的右侧。设置的触发器的z值,保证小鸟可以触发到。 这里要存储2个背景的位置。也就是说。当小鸟触发到了触发器,将第一个背景移动到右侧的第三个背景的右侧。他们的坐标值在x方向上相差20.

public class MoveTrigger : MonoBehaviour{ public Transform currentBG; public pipe p1; public pipe p2; void OnTriggerEnter(Collider other){ Transform firstBG = GameManage._instance.FirstBG; currentBG.position=new Vector3(firstBG.position.x+10,currentBG.position.y,curremtBG.position.z); p1.RamdomGeneratePosition(); p2.RamdomGeneratePosition(); } } 代码的意思是: currentBG为左侧的第一个bg的值。如果碰撞到是小鸟,firstBG为右侧的bg2的值,用bg2的x+10(当前的案例中应该是x+20),y和z不变。而后,currentBG赋值为FirstBG的值。 六、小鸟的跳跃

在小鸟的脚本中,鼠标左键按下后,有一个向上的速度。小鸟的重力必须加上。 在这里插入图片描述

七、相机的跟随 先试一下,将相机放在bird的子物体下。试一下看看,发现一个结果:bird飞后,相机会跟着,但是如果bird被撞飞后,相机会旋转。 解决如下: 创建一个相机跟随脚本。 手动给出 camera和bird的一个位置坐标差。

在这里插入图片描述

八、计分功能: 在每根管道中间添加一个触发器,选择一个pipe1,添加box collider

图 12 图 13 图 14图 15 到pipe2上粘贴collider。 图 16 在GameManage中,定义一个变量存储分数的。 在这里插入图片描述 在pipe脚本中,添加以下代码: 在这里插入图片描述

九、游戏状态控制

在游戏开始时,小鸟没有速度,没有重力。是停止的,在鼠标右键点击后,给小鸟添加上速度和重力,在飞行过程中,若小鸟撞到管子,就掉落,鼠标左键按下去应该没有作用,游戏结束。所以,需要给游戏设定几种游戏状态。 在这里插入图片描述 初始情况下,取消小鸟的速度和重力。并在小鸟的飞行和鼠标左键按下的左右是在playing状态下

if(GameManage._instance.GameState==GameMabage.GAMESTATE_PLAYING){ timer+=Time.deltaTime; if(timer>=1.0f/frameNumber){ frameCount++; timer-=Time.deltaTime; //修改材质的偏移值 int frameIndex=frameCount%3; this.GetComponent().material.SetTextureOffser("_MainTex",new Vector2(0.333f*frameIndex,0)); } if(Input.GetMouseButton(0)){ Vector3 vel=this.GetComponent().velocity; this.GetComponent().velocity=new Vector3(vel.x,2,vel.z); } }

设定函数,让其满足设置小鸟的速度和重力。 在这里插入图片描述 在GameMange中,从menu状态转变成Playing状态。在playing状态下,调用上述函数,使用方法是SendMessage。在一个脚本中向另一个脚本发送方法。 在这里插入图片描述 此时小鸟可以飞行了,可是,小鸟掉落后,再通过鼠标点击时,还可以点击后飞起。游戏状态没有改变。 于是,我们需要在小鸟撞击掉落后,修改游戏状态,同时,不让小鸟再次飞起。 注意: 不能在pipe中再写OnCollionEnter有关的函数,因为本代码又有触发器,两者是冲突的,要么触发器要么碰撞器。所以,我们在pipeup和pipedown中使用碰撞器。 在这里插入图片描述

十、添加声音

在Main Camera上,添加audio sourse 组件,添加声音文件sfx_swooshing,取消Loop 在这里插入图片描述 每次飞行都有翅膀煽动的声音,所以在bird上添加audiosourse,添加声音文件sfx_wing。取消play on awake。在bird的脚本中,播放声音。

if(input.GetMouseButton(0)){ audio.Play(); }

得分的声音。在MoveTrigger的时候,才会有声音。于是在Pipe1和pipe2上添加audio sourse声音文件sfx_point.同样在脚本中添加

audio.Play();

撞到柱子的时候,会有声音,于是在pipe_up,pipe_down都添加audio sourse,添加sfx_hit声音。取消play on awake。在pipeupordown脚本中,trigger过程中,audio.Play() 死亡的声音 在这里插入图片描述

public class PipeUpOrDown:MonoBehaviour{ public AudioSource hitMusic; public AudioSource dieMusic; void OnCollisionEnter(Collision other){ if(other.gameObject.tag=="Player"){ hitMusic.Play(); dieMusic.Play(); GameManager._instance.GameState=GameManager.GAMESTATE_END; } } } 十一、失败后的界面

在GameManage脚本,对菜单显示及更新分数 在这里插入图片描述

更新最高分值

在这里插入图片描述 同时加上HighScoreText.text = preHighScore + " "; finalScoreText.text = Score + " "; //加上空串可以将int转换成字符串 在结束状态 在这里插入图片描述

游戏的退出

在这里插入图片描述 不过Application.Quit();的代码在Unity3D运行中是不好使的,此代码是在打包之后运行才能好使!

游戏的重新开始

在这里插入图片描述

额外的知识 1.PlayerPrefs PlayerPrefs简单来说就是unity提供的一种本地存储数据的方式。 目前提供存储,int/float/string三种类型的数据。 存储结构类似于字典,一个key值对应一个value。

分别使用

PlayerPrefs.GetInt(key); PlayerPrefs.GetFloat(key); PlayerPrefs.GetString(key); 获取键值对应的数值。 PlayerPrefs.SetInt(key,value); PlayerPrefs.SetFloat(key,value); PlayerPrefs.SetString(key,value); 设置键值对应的数值。 PlayerPrefs.DeleteKey(key); 删除键值。 PlayerPrefs.HasKey(key); 判断键值是否存在。 值得注意的是,键值对应的数据的默认值为数据类型的默认值。 比如当我们尝试获取一个未曾使用的Key,其返回值可能是:0,0F 或者 "",而不是null。 但是unity却允许存入默认数值,所以在读取数值的时候,返回默认数值的情况有两种,一种是因为不存在该Key值,另一种是因为你存入了默认值。 PlayerPrefs的储存位置

在Mac OS X上PlayerPrefs存储在~/Library/PlayerPrefs文件夹,名为unity.[company name].[product name].plist,这里company和product名是在Project Setting中设置的,相同的plist用于在编辑器中运行的工程和独立模式 (打开Find,按住Option键,点击“前往 →“资源库”,就可以找到Preferences文件夹。). 在Windows独立模式下,PlayerPrefs被存储在注册表的 HKCU\Software[company name][product name]键下(打开“运行”输入regedit打开注册表),这里company和product名是在Project Setting中设置的. 是持久本地化存储

using UnityEngine; using System.Colliections; public class PlayerPerfsExample:MonoBehaviour { void Example() { //设置键值和值 PlayerPerfs.SetInt(“keyInt”,10); PlayerPerfs.SetFloat(“keyFloat”,10.2f); PlayerPerfs.SetString(“keyString”,”lmzqm”); //获取键值如果不存在该键值就返回默认值0 PlayerPerfs.GetInt("keyInt",0); PlayerPerfs.GetFloat("keyFloat",0); PlayerPerfs.GetString("keyString","0"); PlayerPerfs.DeleteAll();//删除所有键值 PlayerPerfs.DeleteKey("keyInt");//删除某个键值 bool exist = PlayerPerfs.HasKey("keyInt");//判断是否存在键值 } 3.发布到安卓时需要修改的地方

将脚本中的:

if(Input.GetMouseButton(0))

改为:

if(Input.touchCount==1)//表示手指单点触摸屏幕

在这里插入图片描述

源工程

下载链接:flappybird



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3