# LanW Game Project
目录
(一) 介绍
本文主要是介绍了如何使用用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其位置
主界面如下
在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 此时运行游戏人物可立于地面上
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
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]可将其设为可见不可操作)
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中
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 ++;
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及碰撞体和代码)
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中赋值 运行后将两个点销毁
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动画最后添加关键帧 设置为启用销毁
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.销毁
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 并在组件中拽入音效
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帧显现 停止录制并运行
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的代码
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勾选
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函数 此时运行游戏可点击按钮进入
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 可一起变换音量
19. 打包游戏
Build settings中选择左下角 Player Settings ,设置好自己想要的参数,返回,点击右下角build将游戏打包。
(四)常见问题及解决方法
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. 欢迎一起交流学习,有什么问题可以私信我1228193430@qq.com。