用Unity开发一款2D横版游戏demo

# LanW Game Project

5d211f15aba14b70ac770a6b275e9b94.jpeg

目录

(一) 介绍

(二) 安装教程

(三) 开发流程

1.  新建工程

2.  设置人物

3.  控制主角的移动

4.   添加切换动作的动画

5.   镜头跟踪

6.   收集物体

7.   创建ui

8.   创建敌人

9.   制作敌人ai

10.   创建青蛙动画

11.   优化代码

12.   设置音效

13.   制作对话框

14.   制作死亡边界

15.   制作场景切换

16.   制作前中后景视觉差 Parallax

17.   创建菜单

18.   制作音轨

19.   打包游戏

(四)常见问题及解决方法

(五) 致谢


(一) 介绍

本文主要是介绍了如何使用用unity开发一款简单的横版平台跳跃类游戏demo,该游戏所展现的素材均来自unity商店,开发流程所展示的仅为部分参考代码,该游戏所有工程文件及代码在https://gitee.com/lan-dashai/lan-w-game-project/tree/master

软件环境
Visual stdio 2019 
Unity Hub;
编辑器版本:Unity 2021.3.7f1c1(LTS);


(二) 安装教程

1.  首先在网页搜索网址:https://unity.cn/unity-ggac-2021
2.  点击下载unity hub
3.  安装编辑器版本

(三) 开发流程

1.  新建工程

*Asset Store商店搜索好包 并下载 在Package manager中下载并导入
*将背景图片的Pixels Per Unit 改为16(每个格中含有16像素)并Apply 将背景图片拖入Level窗口加载并reset其位置

主界面如下

450a5bc22ca64e56aae76c092adc5485.png
 在level中新建2D obj Tilemap
*将背景图片隐藏以便观看 在Window 2D 中选Tile Palette
*在窗口中Create新的 命名为map 在缺省跳到的文件夹中新建文件夹命名maps
*将瓦片素材设置为16 Sprite 自动切割 将Mode改为Mutiple 点击Sprite Editor 点击窗口中的GridByCellSize Pixel设置为16*16 并切割
*切割完点击Apply后将其拖入 Tile Palette  点击画笔绘制地图(关掉edit)(用橡皮可擦掉 记得选择当前的Tile map)
*调整好main camera的属性size设为6
点击背景图片 添加新的Sorting Layer 命名为 Background和Frontground 将背景设置为BG

2.  设置人物

*将人物图片改为20, 在level中新建2D Sprite 将人物拖拽到Sprite Render的编辑面板的Sprite中 并reset
 点击人物的Add Component 添加Rigidbody 2D(刚体 将纸片变成物件)
*继续为人物添加碰撞体 Box Collider 2D 点击三个盒子相连的图标(编辑)将绿色边框拉至合适位置
 为地图添加Tilemap Collider 2D 此时运行游戏人物可立于地面上

51da2068382c4ee1b40fd3a3189b6ada.png

b1708f990fcb4b529124ed32caf7af0c.png

d7488a1b6f7a4655be4854d36e18d39d.png

3.  控制主角的移动

*为人物添加代码 Add New Scrips 命名为PlayerController
打开script
创建刚体 public Rigidbody2D Rd; 将刚体拖入到创建的刚体中
创建初速度 public float Speed; 设置为10
创建移动方式 newfloat用来接收input了的GetAxis(horizontal) if语句当它不为0时(即-1或1)Rd.velocity刚体的移动 = newVector2(HorizontalMove * Speed, Rd.velogy.y);
将人物刚体中的Constrains中的Freeze Rotation Z勾上(冻结z轴)否则会发生移动时刚体旋转
试玩中可调整速度参数 但试玩结束后不会保存 需要手动再设置
写代码 修改人物朝向 在移动方式中创建float用来接受input的GetAxisRaw(horizontal)-1 0 1整数 if语句当它不为0时 物体的transform.scale(在unity中) = new Vector3(FaceDirection,1,1);
*(优化代码)将Update修改为FixedUpdate() 让程序在低于60帧的电脑上流畅运行 在*Speed 后再 *Time.deltaTime 保存后将游戏中的Speed改为400(不推荐使用此条 很麻烦)
写代码 创建跳跃的力 public float JumpForce 在Movement函数中添加if语句如果Input.GetButtonDown("Jump") 则Rigidbody.velocity = (Rigidbody.velocity.x, JumpForce * Time.deltaTime); 并设置unity人物的JumpForce为400 将刚体的Gravity Scale重力称改为2

dc86c0bd98b246edb8c212b73156e5e9.png

cc869d42797a402cb2729b06493c439f.png

e95b9889fdf44c1b920e8b4638b7d57d.png

4.   添加切换动作的动画

*为人物添加Add Animator组件 再新建Animation文件夹以管理 下面新建Player文件夹 里面新建Animation Controller 命名为Player 将其拖入到组件中的Controller位置中
点击Window Animation Animation 创建Animation 点击Create创建 命名为Idle(原地站立)将Asset中idle的图片全部改为16 全部拖入时间轴
*将采样率Samples(三个点打开)设置为10 (或者全选节点拖拽至合适长度)
*创建新的Animation 命名为Run 注意文件存放位置 打开Asset中人物图片的Run 图片改为16全部拖入时间轴 Samples采样率改为10 (缺省勾选了Loop Time循环播放)
*在Animator中右键Run Idle Make Transition将两个互相链接 在Animator组件的Parameters组件的下拉三角形中选择Float 添加Float命名为Running
*选中连接线 将Has Exit Time取消勾选(没有动画缓冲 马上切换)Settings中的Transition Duration改为0(不需要转换时间)在Conditions中点击加号添加条件 数值改为0.1 
两条连接线同理操作 Run到Idle的Conditions的Greater改为Less
*写代码 新建变量public Animator Animator;在Movement函数中新增Animator.SetFloat("Running", Math.Abs(接受的Horizontal的绝对值)) 保存后回到unity的人物编码组件 将Animator组件拖入
*创建Animation Jump和Fall 将图片16拖入 在Animator组件中设置好连线(Run,Idle链接Jump,Jump链接Fall,Fall链接Idle)
*添加Prarmeters Jumping Falling Idle
*设置好连线参数 (Run与Idle 的Jumping是true时到Jump)(Jump的Jumping是false且Falling是true时到Fall)(Fall的Falling是false且Idle是true时到Idle)
*打开PlayController脚本
*编写代码 void SwitchAnimation  if(Animator.GetBool("Jumping")){if刚体的y坐标< 0时 设置Jumping为false,设置Falling为true}
*写代码 public LayerMask Ground;以获取地面 将Tilemap的Layer设置添加新的命名为Ground并选择 将Player中编码组件的Ground 设置为Ground
*写代码 public Collider2D Collider2D;以获取人物的碰撞体 续写SwitchAnimation的elseif(Collider2D.IsTouchingLayers(Ground)){设置Falling为false,Idle为true} *在函数最前定义Bool Animator.SetBool("Idle", false);
(出现闪烁则检查图层或elseif)!
*将Box Collider 缩小 为人物新增 Cricle Collider碰撞体 设置到下半身位置
*写代码 将Rigidbody和Animator改外private 在start中写他们的获取方式 = GetCompenent<Rigidbody 2D>; = GetComponent<Animator>;(<>内名字就是unity组件中的名字)
(在定义的时候前面加[SerializeField]可将其设为可见不可操作)

5a3de6437c9b40ffad58377638bbfae8.png

1cb8e2b89ee44ab0826c2c337cf1674a.png

5.   镜头跟踪

*为Main Camera 添加代码 命名为CameraControl
添加组件Cinemachine 在组件菜单中添加摄像头Create 2D Camera 将player拖拽到Follow中跟随 (Dead Zone调整开始跟随区域 Screen X/Y调整角色固定位置)
ctrl d 复制背景直到填充屏幕 新建Empty命名为BackGround将三个back整理 
在2DCamera中的Add Extension组件中选择CinemachineConfiner
为BackGround添加Polygon Collider2D 并将其设置为is Trigger(打勾)点击编辑将多边形的顶点拉至屏幕边角 不需要的按住ctrl点击可删 将其添加到2D摄像机的Bounding Shape2D中

b63d5c26e812487aa9c2ba880e8147f2.png

6.   收集物体

*为Cherry创建文件夹 将图片素材改为16后拖拽导入 添加组件Animator 在Assets的动画文件夹下创建AnimationController命名为Cherry 将其拖拽导入到Animator中 在组件编辑器中Create新的Cherry动画 将图片拽入
*为Cherry添加Box Collider2D 点击编辑将其调整好 设置为isTrigger(这是一个检测是否碰撞的装置 并不要让它有碰撞效果)
*为Cherry新建Tag标签 叫做Collection
*打开人物的代码 新建函数void OnTriggerEnter2D() 里面写 if语句if(collision.tag == "Collection"){Destory(collision.gameObject);} 如果碰撞物体的标签是Collection的话就销毁该碰撞物体
*创建计数器 public int Cherry 在销毁后面写Cherry ++;

8b49adb86be84d0f9ccba0091eea3b36.png

7.   创建ui

*在level1中新建ui画布UI Canvas  右键Canvas 添加UI Text 命名为Cherry
f找到物件位置 将Text移动到合适位置 修改Text内容 并调整合适大小
*在新增UI Text 命名为Numbers 修改Text内容及其属性
写代码获取ui文本 public Text CherryNumber;并using 保存后将Number拖入
*在OnTriggerEnter中新增代码 CherryNumber.text = Cherry.ToString();
(固定文本位置)
*点选Cherry文本的设置方位图(centermiddle图标)并将位置选为始终在左上角
Number文本同理操作
(为Cherry创建UI Image 并为Gem创建UI及碰撞体和代码)

3ba63f96b1e14d7abe80809f18066350.png

 


8.   创建敌人

*创建Enemy Frog 将青蛙图片拖入 创建其Idle和Jump动画 为其添加Rigidbody 2D 及Box collider 2D并调整好碰撞体位置
*写代码 新函数private void OnCollisionEnter2D() {}
if语句 当collision.gameObject.tag (不是trigger类型的需要加gameObject) == "Enemy"; 时 Destory(collision.gameObject)
调整代码 添加新条件 && 当人物正在执行Falling动作时
*写代码 添加人物受伤后退 new public bool IsHurt;在Update中if(IsHurt == false)时 运行Movement;
当碰撞体碰到敌人时 && 人物x轴小于敌人x轴(从左边碰到敌人)则IsHurt = true 人物刚体.Velocity = New Velocity(-10,y)
右边反之同理
*写代码 在SwitchAnimation中新增else if(IsHurt)时 if(刚体的x速度绝对值<0.1f)时 IsHurt = false;(写在下落代码之上 否则会一直运行下落)
*写代码 在IsHurt中添加动画代码条件 并写SetFloat("Running", 0);以确保受伤动作完毕后回到正常动作

9.   制作敌人ai

*为Frog添加代码 私有变量rb 在Start中获取GetComponent<>
*在heri中为Frog添加子项目作为它的移动区域 为了方便观察可改变他们的颜色
*写代码 创建IsFaceLeft布尔值以观测 左右移动不超过左右两个点的x y坐标 子物体设置分家DetachChildren
*写代码 创建x y在Start中赋值 运行后将两个点销毁
a73d853d9ffa470f96cb227913af5280.png

10.   创建青蛙动画

*为青蛙分别添加Jump fall 动画 连线并设置
*写代码 将y轴移动改为JumpFoece 添加前置if语句 如果rb.IsTouchingLayers(Ground)并开启跳跃动画
自动执行跳跃 为animation组件控制器添加事件关键帧 将其拖到站立动画的最后 设置Function为写好的Movement() 并将代码中update里的Movement注释
*写代码 添加 SwitchAnimation()
if Jumping则改变跳 落 动画 else if 碰撞到地面则关闭下落动画
*添加青蛙死亡的动画 从Any State连线 添加控制器 Trigger开关 命名为Death
*写代码 为青蛙添加public Death函数
在人物动画中的触碰青蛙中的if语句中 添加EnemyFrog实体 EnemyFrog Forg = collision.gameObject.GetComponent<EnemyFrog>(); 并用Frog调用Death
*写代码 为青蛙添加Destroy函数 Destroy(gameObject); 在Death动画最后添加关键帧 设置为启用销毁

c1982938fa9644c488c52d6aa9c67c24.png

 f8a70495bca94c478c2e2fa1b1822b72.png

 

 ed59a4204c874857946daf94013bf243.png

9864feea5b124d7db6824afe6c6e5e6a.png 

0d205011ca914376aa966287713e7307.png

11.   优化代码

*根目录新建C# Enemy 新建变量protected Animator Anim;并获取 并把Start Update函数也改编为protected virtual void Start()(受保护的虚拟函数)
*将EnemyFrog的:父类改为 Enemy 并将青蛙的变量Animator及其Start中的获取 注释
*将青蛙的Start 设为 protected override void Start()(重写父类方法)同时在里面调用 base.Start()
*将Destory和Death函数注释并复制到Enemy中 并全部设为public
*修改人物代码中毁掉青蛙的代码 将new的青蛙注释 改外new Enemy 将底下的青蛙.销毁 改为Enemy.销毁

bfff420a7b5f42a2b60f8e45b14a68d2.png

12.   设置音效

*为player添加组件 Audio Source 右上角点击overrides apply all 将所有新加的组件添加到perfabs预设
*在AudioClip中拖拽添加bgm 将Play on Awake勾选(启动游戏时播放)将loop勾选(循环播放)
*点击青蛙heri中的小箭头进入青蛙组件 为其添加AudioScouce 
*写代码 在enemy 中创建爆炸音效变量 protected AudioSource DeathAudio 并getComponent在Death中启用 DeathAudio.play();
同理 为人物add各种音效 写人物代码 public AudioSource ____ 并.play 并在组件中拽入音效 

549a254c13ae4b71ab83b0571a9295c0.png

13.   制作对话框

*在level1中的Canvas中新建UI Panel面板 命名为EnterDialog
*为其改变颜色 改变位置至固定在下方 width改为600 height125 Y轴改变至100
*为其创建子项目 右键UI Text 设置位置 内容 文字大小
在房子的门上创建Trigger碰撞体 (触碰到门则出现dialog)
*写代码 添加房子的代码 创建变量gameObject Dialog 
*写代码 添加函数 OnTriggerEnter2D 和OnTriggerExit2D if语句如果碰撞体的tag是player的话 则Dialog.SetActive(true/false); (设置开关)
(为text制作浅入浅出动画)
*为heri中的EnterDialog创建动画 命名EnterDialog
*点击红色圆圈录制 第一帧透明 第20帧显现 停止录制并运行

 fdb17c7fb9bc4d4c9e4f3046aa30b3cd.png

 8dbb395b77a64093936abfe1a5776763.png

14.   制作死亡边界

*level1创建新项目DeadLine 并将其放在布局下面 调整好长度 并将其标签添加并改成DeadLine
*写代码 using UnityEngine.SceneManagement;
*在人物TriggerEnter2D中新增if语句 当collision.tag == "DeadLine"; 时
ScenManager.LoadScene(SceneManager.GetActiveScene().name);
*完善代码 新建函数Restart() 将切换场景剪切到里面
*在if中添加 Invoke("Restart",1);延迟1秒运行Restart切换场景
继续添加GetComponent<AudioSource>().enabled = false; 关闭音乐

15.   制作场景切换

*创建代码EnterHouse   using SceneManagement
*在update中写代码 if语句 当按下e时 scenManager.LoadScene(SceneManager.GetActiveScene().buildIndex +1) 当前场景编号+1
*打开File Build Settings 将场景拖入 可观察编号 
*将代码拖拽加入至 enter的dialog中
同理为场景2 写返回场景1的代码

eb3f4f51c50449ed9f952e49cdfe6bf9.png

16.   制作前中后景视觉差 Parallax

*新建Area 拷贝背景的多边形碰撞体至Area中 删除背景的碰撞体 将摄像机重新设置好
新建代码Parallax
*写代码 添加变量float MoveRate(调整幅度)float StartPoint(确定初始位置)transform Camera(调整位置)
*写代码 Start中获取StartPoint = transform.posion.x
*添加y轴变量  
*添加bool变量 lockY
*update添加if 如果lockY 则运行之前的代码 else y轴 = 初始坐标y + 镜头移动*幅度
*将不希望上下移动的物件的lockY勾选

423ef54308874fb3af195f4ccedb4cbd.png

17.   创建菜单

*新建场景Menu
*添加UI Panel 改为黑色 将Source Image(原图像)改为null
*再添加 Panel 控制颜色 改Scource为其添加组件Button Text Mesh... 添加按钮
*调整按钮大小 text文字 颜色
*写代码 Menu 直接创建函数 PlayGame()SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex + 1);
*添加函数QuitGame()Application.Quit();
*将代码添加到按钮的父类中 在按钮里的On Click组件选择父类 选择PlayGame函数 此时运行游戏可点击按钮进入

7c7bc3360f03499bad5c080577c3f9d5.png

 6b1969fb784245ab9c7ef0b37e26ebbd.png

18.   制作音轨

*Assets新建Audio Mixer命名为MainMixer 在Window Audio中找到AudioMixer打开菜单
*为bgm选择Output 选择master 将master的Inspector中的Attenuation的volume 右键改为可编辑的 expose
调整Menu中的音轨 将最小值设置为-80 最大值0
*写代码 在Menu中 新建变量 public AudioMixer AudioMixer 将组件拖入
*写代码 新建函数 public void SetVolume(float值) AudioMixer.SetFloat("刚改的可编辑的代码的名称",float值);
*为音轨条添加代码 用SetVolume函数 选择上面的
*为所有的音效添加master 可一起变换音量

6c8604a710324b659d00e405e528e16a.png

19.   打包游戏

Build settings中选择左下角 Player Settings ,设置好自己想要的参数,返回,点击右下角build将游戏打包。
7516bdf178e14706a41ca11cf06cd1ac.png

(四)常见问题及解决方法

1.提示unable to access unity services. please log in or request membership to this project

解决方法:①点击“Window” —— “General” —— “Service”(或者直接快捷键 ctrl + 0)②点击“new link” —— 选择自己的Project ID —— 点击“create”。

2.Unity报错:The variable ... has not been assigned.

解决方法:给物体添加刚体组件。

3.提示UnassignedReferenceException: The variable target of Moving has not been assigned.You probably need to assign the target variable of the Moving script in theinspector.Moving.Update () (at Assets/_Tutorial/Moving.cs:13)

解决方法:把物体拉到tagger里面进行设置。


(五) 致谢

1.  感谢我的Unity启蒙老师,麦扣老师,@M_STDIO
2.  游戏所使用素材均来自Unity商店
3.  欢迎一起交流学习,有什么问题可以私信我[email protected]

猜你喜欢

转载自blog.csdn.net/weixin_61056520/article/details/126428530