【游戏开发创新】上班通勤时间太长,做一个任意门,告别地铁与塞车(Unity | 建模 | ShaderGraph | 摇杆 | 角色控制)
文章目录
- 一、前言
- 二、最终效果
- 三、Blender建模
- 1、Blender下载安装
- 2、传送门建模
- 3、房子建模
- 4、公司大楼建模
- 5、文字模型
- 四、Blender导出FBX
- 五、FBX导入Unity中
- 六、制作材质
- 1、传送门
- 1.1、ShaderGraph准备
- 1.2、创建ShaderGraph
- 1.3、编辑ShaderGraph
- 1.4、材质球使用ShaderGraph
- 1.5、模型引用材质球
- 2、房子材质球
- 3、公司大楼材质球
- 七、地面
- 1、广州地铁图
- 2、地面(Plane)
- 八、主角
- 1、主角资源
- 2、双摇杆制作
- 3、主角移动控制
- 3.1、动画控制
- 3.2、移动控制
- 3.3、主角脚本代码
- 3.4、主角移动测试
- 4、摄像机跟随
- 5、摄像头角度控制
- 九、导航烘焙
- 十、传送门触发器
- 十一、特效
- 十二、最终效果
- 十三、工程源码
- 十四、完毕
一、前言
嗨,大家好,我是新发。
现在每天上班的通勤时间是一个多小时,加上下班的通勤时间,每天在路上就是两个半小时,在广州早高峰坐地铁简直要命,这里我不得不吐槽一下广州21
号线,人流量超多,发车频率还低,导致每趟都堆积特别多人,每次都要等至少两三趟才能挤上,而且都好暴力,太疯狂了,这样真的容易出事,每次出地铁心里都在重复一句话:下次不搭21
号线了!
还好有热心同事经常开车搭我上下班,老麻烦别人也很不好意思,不过,搭了几次车又感觉脸皮厚了-_-
要是有一个任意门可以连接家门口和公司门口就好了,现实中没有,那就在虚拟世界里做一个吧~
二、最终效果
我做的Demo
最终效果如下,
家门口:
从家门口穿过传送门:
从公司经过传送门回家:
下面,我就来讲讲我的制作过程吧~
三、Blender建模
看过我前面两篇文章的同学应该知道,我最近自学了Blender
建模,感兴趣的同学可以看下我之前两篇文章,
【游戏开发创新】当我学了Blender 建模,自制3D电脑桌面,回收站爆发了,把我做的模型都吐了出来(Blender | Unity | FBX),
【游戏开发创新】自学Blender建模,自制孔明灯,在Unity中点亮整个星空,愿新年,胜旧年(Unity | 建模 | 粒子系统 | 预设)
1、Blender下载安装
Blender
官网:https://www.blender.org/
Blender
中国社区:https://www.blendercn.org/
Blender
中文手册:https://docs.blender.org/manual/zh-hans/2.79/about/introduction.html
我使用的Blender
版本是2.93.4
,
注:关于
Blender
的教程网上蛮多的,这里我就不过多讲了,掌握基本操作和快捷键,很快就可以上手建模啦~
2、传送门建模
传送门最终模型如下:
3、房子建模
房子最终模型如下:
4、公司大楼建模
公司大楼最终模型如下:
5、文字模型
再做一些文字模型,
四、Blender导出FBX
在Blender
中点击菜单File / Export / FBX
,将模型导出成FBX
格式,
如下:
五、FBX导入Unity中
将FBX
文件导入到Unity
工程中,
把模型放入场景中,现在都是默认的材质,所以都是灰白色的,不着急,下面我们就来做材质~
六、制作材质
1、传送门
材质球使用的shader
我打算使用ShaderGraph
来制作,我之前写过一篇ShaderGraph的文章:《ShaderGraph使用教程与各种特效案例:Unity2020》,推荐先看下这篇文章。
1.1、ShaderGraph准备
安装Universal RP
插件,
在Project
视图中右键鼠标,点击菜单Create / Rendering / Universal Render Pipeline / Pipeline Asset (Forward Renderer)
,
创建UniversalRenderPipelineAsset
,如下
点击菜单Edit / Project Settings...
,打开Project Settings
窗口,选择Graphics
分页,把UniversalRenderPipelineAsse
t拖到Scriptable Render Pipeline Settings
中,
1.2、创建ShaderGraph
在Project
视图中右键鼠标,点击菜单Create / Shader / Universal Render Pipeline / Lit Shader Graph
,创建一个PBR
的ShaderGraph
,
重命名为PortalCenter
,作为传送门中心的shader
,
1.3、编辑ShaderGraph
双击PortalCenter
打开编辑器,编辑节点如下,核心就是对泰森多边形(Voronio
)进行UV旋涡旋转(Twirl
)。
1.4、材质球使用ShaderGraph
创建一个材质球Material
, 重命名为PortalCenter
,
设置材质球的shader
为刚刚的ShaderGraph
文件,
1.5、模型引用材质球
将材质球赋值给传送门模型,
效果如下,
2、房子材质球
同理,制作房子的材质,
效果如下,
3、公司大楼材质球
制作房子的材质,
效果如下,
七、地面
1、广州地铁图
找一张广州最新的地铁地图,我找到的是下面这张,
2、地面(Plane)
在场景中创建一个Plane
平面,制作材质并引用这张图片,
效果如下:
八、主角
1、主角资源
主角我在AssetStore
上找到了一个心仪的模型,推荐给大家,
AssetStore
地址:https://assetstore.unity.com/packages/3d/characters/humanoids/sci-fi/stylized-astronaut-114298
将模型下载导入Unity
中,
2、双摇杆制作
主角的移动和摄像头的角度旋转我想通过摇杆来控制,我们做一个双摇杆功能。
在Canvas
节点上右键点击菜单UI / Panel
,创建一个Panel
,
把Image
组件禁用掉,因为我们不需要Panel
显示出来,
在Panel下
创建一个Image
,重命名为leftJointedArm
,作为左摇杆的父节点,
设置它的锚点为bottom - left
,即屏幕左下角,调整坐标和宽高,
像这样子,
把它的Color
的alpha
调为0
,因为我们只需要利用它的区域来检测触碰,我们不需要肉眼看见它,
接着在它的子节点下创建两个Image
,分别命名为bg
和center
,
它们的Source Image
都设置为摇杆的图片资源,
分别调整下bg
和center
的大小和颜色透明度,效果如下:
同理再做一个右摇杆,
效果如下:
接下来需要给摇杆加上逻辑,Unity
的UGUI
提供了ScrollRect
组件,非常适合用来制作摇杆,我们继承ScrollRect
然后实现OnDrag
和OnEndDrag
方法,可以很方便地获取到摇杆的遥控数据,另外,为了检测区域点击,我们再实现IPointerDownHandler
接口。
创建摇杆脚本JointedArm.cs
,代码如下:
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using System;/// <summary>
/// 摇杆
/// </summary>
public class JointedArm : ScrollRect, IPointerDownHandler
{public Action<Vector2> onDragCb;public Action onStopCb;protected float radius = 0f;private Transform trans;private RectTransform bgTrans;private Camera uiCam;private Vector3 originalPos;protected override void Awake(){base.Awake();trans = transform;bgTrans = trans.Find("bg") as RectTransform;uiCam = GameObject.Find("UICamera").GetComponent<Camera>();originalPos = trans.localPosition;}void Update(){if (Input.GetMouseButtonUp(0)){//松手时,摇杆复位trans.localPosition = originalPos;this.content.localPosition = Vector3.zero;}}protected override void Start(){base.Start();//计算摇杆块的半径radius = bgTrans.sizeDelta.x * 0.5f;}public override void OnDrag(PointerEventData eventData){base.OnDrag(eventData);var contentPostion = this.content.anchoredPosition;if (contentPostion.magnitude > radius){contentPostion = contentPostion.normalized * radius;SetContentAnchoredPosition(contentPostion);}// Debug.Log("摇杆滑动,方向:" + contentPostion);if(null != onDragCb)onDragCb(contentPostion);}public override void OnEndDrag(PointerEventData eventData){base.OnEndDrag(eventData);// Debug.Log("摇杆拖动结束");if (null != onStopCb)onStopCb();}public void OnPointerDown(PointerEventData eventData){//点击到摇杆的区域,摇杆移动到点击的位置trans.position = uiCam.ScreenToWorldPoint(eventData.position);trans.localPosition = new Vector3(trans.localPosition.x, trans.localPosition.y, 0);}
}
把JointedArm.cs
分别挂到leftJointedArm
和rightJointedArm
上,赋值对应的center
,
运行Unity
,摇杆测试效果如下:
接下来我们要实现左摇杆控制主角移动并播放跑的动画,右摇杆控制摄像机角度旋转。
3、主角移动控制
3.1、动画控制
注:关于Animator组件的详细使用可以参见我之前写的这篇文章:《Unity动画状态机Animator使用》
打开角色的动画控制器文件CharacterController
,
可以看到,两个动作,一个idle
(站立)一个Run
(跑),
到Parameters
(参数)里面有一个AnimationPar
参数,这个参数就是用来控制站立与跑着两个动画的过渡条件的,
从Idle
过渡到Run
的条件是AnimationPar
等于1
,
从Run
过渡到Idle
的条件是AnimationPar
等于0
,
这样,我们就可以在代码中通过这个参数来控制动画的过渡了,例:
// public Animator anim; // 站立 -> 跑
anim.SetInteger("AnimationPar", 1);
// 跑 -> 站立
anim.SetInteger("AnimationPar", 0);
3.2、移动控制
主角的移动控制包括坐标和角度的变化,当摇杆向左滑,主角向左移动,同时主角的朝向也跟着转向左边。
移动我们可以设置transfrom
的position
属性来实现,转向我们可以设置transfrom
的forward
属性来实现,例:
// Vector3 moveDirection; 摇杆向量
// float speed; 移动速度
// float turnSpeed; 转向速度transform.position += moveDirection * speed * Time.deltaTime;
transform.forward = Vector3.Lerp(transform.forward, moveDirection, turnSpeed * Time.deltaTime);
3.3、主角脚本代码
综上,我们封装一个主角脚本Player.cs
,代码如下:
// Player.cs
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.AI;/// <summary>
/// 主角脚本
/// </summary>
public class Player : MonoBehaviour
{// 移动速度public float speed = 1f;// 转向速度public float turnSpeed = 20f;public Animator anim;// 跟节点public Transform rootTrans;// 模型节点public Transform modelTrans;// 导航Agentpublic NavMeshAgent navAgent;// 是否在移动private bool moving = false;// 移动向量private Vector3 moveDirection = Vector3.zero;// 是否可移动private bool canMove = true;private void Awake() {companyPosParticle.Stop();homePosParticle.Stop();}void Update(){if (canMove && moving){anim.SetInteger("AnimationPar", 1);rootTrans.position += moveDirection * speed * Time.deltaTime;modelTrans.forward = Vector3.Lerp(modelTrans.forward, moveDirection, turnSpeed * Time.deltaTime);}else{anim.SetInteger("AnimationPar", 0);}}public void Move(Vector3 direction){moveDirection = direction;moving = true;}public void Stand(){moving = false;}
将Player.cs
脚本挂到主角物体上,在Inspector
面板赋值脚本的成员变量,
我们再创建一个GameMgr.cs
脚本来调度,
// GameMgr.cspublic Player player;
public JointedArm leftJointedArm;
private Transform playerTrans;
private Transform camTrans;// ...// 左摇杆 -------------------------------------------
leftJointedArm.onDragCb = (direction) =>
{var realDirect = camTrans.localToWorldMatrix * new Vector3(direction.x, 0, direction.y);realDirect.y = 0;realDirect = realDirect.normalized;player.Move(realDirect);
};
leftJointedArm.onStopCb = () => { player.Stand(); };
创建一个空物体重命名为GameMgr
,把GameMgr.cs
挂到这个物体上,并在Inspector
面板中赋值脚本的成员变量。
3.4、主角移动测试
运行测试效果如下:
4、摄像机跟随
我们创建一个CameraControler.cs
脚本,实现摄像机跟随主角的逻辑,代码如下:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;/// <summary>
/// 摄像机控制器
/// </summary>
public class CameraControler : MonoBehaviour
{// 限制摄像机角度范围private const float Y_ANGLE_MIN = 10f;private const float Y_ANGLE_MAX = 50.0f;// 摄像机看向的物体public Transform lookAt;// 摄像机Transformpublic Transform camTransform;// 摄像机距离目标物体的距离public float distance = 1.2f;// 原始距离private float originalDistance;// 旋转速度public float rotateSpeed = 0.01f;public float currentX = 0.0f;public float currentY = 20.0f;private void Start(){camTransform = transform;originalDistance = distance;}private void Update(){if (rotating){currentX += rotateDelta.x;currentY += rotateDelta.y;currentY = Mathf.Clamp(currentY, Y_ANGLE_MIN, Y_ANGLE_MAX);}}private void LateUpdate(){Vector3 dir = new Vector3(0, 0, -distance);Quaternion rotation = Quaternion.Euler(currentY, currentX, 0);camTransform.position = lookAt.position + rotation * dir;camTransform.LookAt(lookAt.position);}
}
把CameraControler.cs
脚本挂到主摄像机上,在Inspector
面板赋值脚本的成员变量,运行Unity
,可以看到有跟随效果了,
5、摄像头角度控制
我们在上面的CameraControler.cs
脚本中添加两个方法,如下:
// CameraControler.csprivate bool rotating;
private Vector2 rotateDelta;public void RotateCam(Vector2 delta)
{rotateDelta = delta * rotateSpeed;rotating = true;
}public void StopRotate()
{rotating = false;
}
然后在GameMgr.cs
中添加右摇杆的调度,
// GameMgr.cs// 右摇杆 ------------------------------------------
rightJointedArm.onDragCb = (direction) =>
{camCtrler.RotateCam(direction);
};
rightJointedArm.onStopCb = () => { camCtrler.StopRotate(); };
运行Unity
,可以控制摄像头角度旋转了,
九、导航烘焙
如果我们想要实现点击地图某个位置,让主角走到目标点,可以使用Unity
的寻路导航功能,另外,这个功能也可以限制主角的移动区域,为了防止主角走到地图外面,我们使用Navigation
对场景进行导航烘焙。
首先选中地面,把地面设置为Static
,
然后点击菜单Window / AI / Navigation
,
点击Bake
分页,点击Bake
按钮,
看到地面蒙上了一层蓝色的网,就说明烘焙成功了,
你可以在场景文件所在目录中看到它生成了一个NavMesh
文件,
另外,我们需要给主角添加NavMeshAgent
组件,并根据主角模型大小设置Radius
和Height
,
如下:
运行Unity
,测试一下移动到地面边界的效果,
十、传送门触发器
传送门传送,我使用了触发器,检测主角是否通过了传送门,然后出发传送逻辑。
给传送门的前后添加两个碰撞体,并勾选Is Trigger
,
如下:
分别在两个冲送门位置添加一个标记传送目标位置的空物体,
给主角脚本Player.cs
添加传送的逻辑,
// Player.cspublic Transform homePos;
public Transform companyPos;
private string lastTrigger;private void OnTriggerEnter(Collider other)
{if("trigger1" == other.name || "trigger3" == other.name) {lastTrigger = other.name;}else{if("trigger1" == lastTrigger && "trigger2" == other.name){// 执行传送,从公司到家rootTrans.position = homePos.position;}else if("trigger3" == lastTrigger && "trigger4" == other.name){// 执行传送,从家到公司rootTrans.position = companyPos.position;}}
}
这样,当主角传过传送门的时候就会按顺序触发触发器,最终指向传送逻辑。
十一、特效
传送时加多一个特效吧,使用PhotoShop
画一个菱形,如下:
再画个菱形边框,
使用粒子系统制作特效,效果如下:
主要利用的是粒子系统的color over Lifttime
和Size over Lifetime
来达到上面的效果,
关于粒子系统的相关教程,可以参见我之前写的这几篇文章:
【游戏开发实战】权游红袍女在火中看到了什么,我看到了…(Unity | 粒子系统 | 火焰特效 | ParticleSystem | 手把手制作)
【游戏开发实战】Unity使用ShaderGraph配合粒子系统,制作子弹拖尾特效(Fate/stay night金闪闪的大招效果)
【学Unity的猫】——第十五章:Unity粒子系统ParticleSystem,下雪啦下雪啦
【游戏开发实战】手把手教你使用Unity制作一个飞机喷射火焰尾气的粒子效果
十二、最终效果
家门口:
从家门口穿过传送门:
从公司经过传送门回家:
十三、工程源码
本工程我已上传到CODE CHINA
,感兴趣的同学可自行下载学习。
地址:https://codechina.csdn.net/linxinfa/UnityPortalDemo
注:我使用的Unity
版本为Unity 2021.1.9f1c1 (64-bit)
。
十四、完毕
好了,就到这里吧,最后希望广州地铁21
号线高峰期可以提高发车频率,不然真的很痛苦。
我是林新发:https://blog.csdn.net/linxinfa
原创不易,若转载请注明出处,感谢大家~
喜欢我的可以点赞、关注、收藏,如果有什么技术上的疑问,欢迎留言或私信,我们下期见~
【游戏开发创新】上班通勤时间太长,做一个任意门,告别地铁与塞车(Unity | 建模 | ShaderGraph | 摇杆 | 角色控制)相关推荐
- Systemctl stop XXX 时间太长
一.背景 假如我们自己开发了一个系统,例如web,想要通过systemd来控制.但使用过程中,出现了问题,systemctl stop XXX 的时间太长了. 二.问题原因 先说结论:我们的系统停止的 ...
- spark SQL读取ORC文件从Driver启动到开始执行Task(或stage)间隔时间太长(计算Partition时间太长)且产出orc单个文件中stripe个数太多问题解决方案...
1.背景: 控制上游文件个数每天7000个,每个文件大小小于256M,50亿条+,orc格式.查看每个文件的stripe个数,500个左右,查询命令:hdfs fsck viewfs://hadoop ...
- Android 系统(161)---N/O版本上图库打开一张图片,图片从模糊到清晰的时间太长
N/O版本上图库打开一张图片,图片从模糊到清晰的时间太长 与M版本比较,N版本上进图库打开一张图片,图片从模糊到清晰的时间太长 N上Google默认没有多线程encode而只有单线程encode,导致 ...
- win10 更新计算机时间,win10更新时间太长怎么回事_windows10更新时间太久解决教程...
在使用win10系统的时候,经常会需要电脑进行更新,而我们会发现每次更新都会耗时1-2个小时时间.让人等的不耐烦,遇到win10更新时间太长怎么回事呢?接下来给大家分享一下windows10更新时间太 ...
- 苹果电脑开机长android,苹果笔记本开机白屏时间太长
朋友,我的现在用"优化大师"优化了,开机才用:"13秒"! 1.电脑开机时间太长(建议你关机重启),或一次打开的网页过多,造成电脑"超载运行" ...
- java压缩mp4大小_压缩的mp4视频播放时间太长(exoplayer)
视频(mp4)从Android摄像头录制并发送到后端,这里我使用ffmpeg包装器压缩视频[44mb视频到5.76mb] . 压缩效果很好,但是当我在android(exo播放器)发送视频播放时,开始 ...
- 【幻灯片制作软件】Focusky教程 | 帧的播放时间太长,该如何调整?
(Focusky动画演示大师简称为"FS软件")设置适当的帧的播放时间能有效地展示内容,达到更好的演示效果.但如果帧的播放时间太长,所有演示动作完成后,还需等待一段时间后才能播放下 ...
- 计算机启动时间过长,开机时间太长怎么办【图解】
现在人们生活娱乐.工作.学习都会或多或少的用到电脑,在电脑被使用越发频繁的今天,电脑出现的问题也就相应得多了,最常见的问题之一就是电脑的开机时间太长,导致的原因可能是因为电脑的使用时间太久了,当然,也 ...
- 语言做一个自动售货机软件_软件开发手机app系统软件高端定制做一个app软件要多少钱...
软件开发手机app系统软件高端定制-做一个app软件要多少钱 APP开发分原生APP开发和在线制作,我们来看下这两种都需要多少费用吧. 1.原生APP开发(定制开发) 互联网是个神奇的大网,大数据开发 ...
- vue项目下拉框内容过长做一个滚动条的效果
vue项目下拉框内容过长做一个滚动条的效果 如下图: 关键代码如下:
最新文章
- 网络营销外包——网络营销外包专员如何帮助企业挑选网站建设类型
- python r语言 结合 部署_(转)python中调用R语言通过rpy2 进行交互安装配置详解...
- JS之Boolean的valueOf方法
- 学会了这些技术,你离BAT大厂不远了
- 从历史角度讲现代数学
- 软件设计师--面向对象技术
- 人工智能为什么要从本科生抓起?
- excel导入Mysql之间的转换
- 给Emacs安装一个脚踏板: 用Windows/Menu键作为key modifier
- 《项目经验》静态页面图片找不到
- SPSS做因子分析(非常细致的过程)
- XBOX360游戏发售表(12月1日)
- 谈《西游记》和泛项目
- win10 计算机磁盘加内存,内存不够用?教你给Win10系统增加C盘空间
- 日文配列键盘修改和映射自定义
- 用boot camp助理装win 7时卡在了“正在拷贝windows文件”
- ALTER TABLE 语句添加字段
- 学校学生计算机教室解决方案,学校学生计算机教室解决方案设计.docx
- java其他框架杂记
- STM32MP157驱动开发——Linux自带的LED灯驱动