【unity实战】3D水系统,游泳,潜水,钓鱼功能实现

最终效果

在这里插入图片描述

文章目录

  • 最终效果
  • 素材
  • 将项目升级为URP
  • 画一个水潭地形
  • 材质升级为URP
  • 创建水
  • 调节水
  • 第一人称人物移动控制
  • 游泳
  • 水面停留
  • 添加水下后处理
  • 水下呼吸
  • 钓鱼
  • 参考
  • 完结

素材

https://assetstore.unity.com/packages/vfx/shaders/urp-stylized-water-shader-proto-series-187485
在这里插入图片描述

将项目升级为URP

这里可以选择直接创建URP项目,也可以选择把普通项目升级为URP项目,关于如何升级,之前我很多都讲过了,感兴趣可以回去看看:
【实现100个unity特效之1】使用Shader Graph实现动物森友会的世界弯曲效果
【制作100个unity游戏之22】3DRPG游戏开发02——天空盒、URP设置和光照

画一个水潭地形

不知道如何绘制的可以看我之前的文章:【2023Unity游戏开发教程】零基础带你从小白到超神04——地形的绘制和基础使用介绍
在这里插入图片描述

材质升级为URP

在这里插入图片描述
ps:可能你会发现材质转换了还是粉色,虽然看着还是粉色,但是其实已经转换成功了,这是unity的一个bug

创建水

新增空物体,添加Water Volume (Transforms)和Water Volume Helper组件配置参数
在这里插入图片描述
绑定水材质
在这里插入图片描述
添加子物体,并设置尺寸
在这里插入图片描述
调整一下水尺寸就显示出来了
在这里插入图片描述

调节水

将水调整合适大小,放置到刚才我们绘制的水潭地形上
在这里插入图片描述
可以调节水材质参数,达到自己想要的效果
在这里插入图片描述

ps:记得设置水的y轴高度,占满湖底
在这里插入图片描述

第一人称人物移动控制

可以看我这篇文章,直接把代码拿来用即可:
【unity小技巧】unity最完美的CharacterController 3d角色控制器,实现移动、跳跃、下蹲、奔跑、上下坡、物理碰撞效果,复制粘贴即用
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

摄像机视角控制代码MouseLook

public class MouseLook : MonoBehaviour
{// 鼠标灵敏度public float mouseSensitivity = 1000f;// 玩家的身体Transform组件,用于旋转public Transform playerBody;// x轴的旋转角度float xRotation = 0f;void Start(){// 锁定光标到屏幕中心,并隐藏光标Cursor.lockState = CursorLockMode.Locked;}// Update在每一帧调用void Update(){// 执行自由视角查看功能FreeLook();}// 自由视角查看功能的实现void FreeLook(){// 获取鼠标X轴和Y轴的移动量,乘以灵敏度和时间,得到平滑的移动速率float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;//限制旋转角度在-90到90度之间,防止过度翻转xRotation = Mathf.Clamp(xRotation, -90f, 90f);// 累计x轴上的旋转量xRotation -= mouseY;// 应用摄像头的x轴旋转transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);// 应用玩家身体的y轴旋转playerBody.Rotate(Vector3.up * mouseX);}
}

人物移动控制代码PlayerMovement

using UnityEngine;[RequireComponent(typeof(CharacterController))]
public class PlayerMovement: MonoBehaviour
{[Tooltip("角色控制器")] public CharacterController characterController;[Tooltip("重力加速度")] private float Gravity = -19.8f;private float horizontal;private float vertical;[Header("移动")][Tooltip("角色行走的速度")] public float walkSpeed = 6f;[Tooltip("角色奔跑的速度")] public float runSpeed = 9f;[Tooltip("角色移动的方向")] private Vector3 moveDirection;[Tooltip("当前速度")] private float speed;[Tooltip("是否奔跑")] private bool isRun;[Header("地面检测")][Tooltip("是否在地面")] private bool isGround;[Header("跳跃")][Tooltip("角色跳跃的高度")] public float jumpHeight = 2.5f;private float _verticalVelocity;void Start(){speed = walkSpeed;}void Update(){horizontal = Input.GetAxis("Horizontal");vertical = Input.GetAxis("Vertical");//地面检测isGround = characterController.isGrounded;SetSpeed();SetRun();SetMove();SetJump();}//速度设置void SetSpeed(){if (isRun){speed = runSpeed;}else{speed = walkSpeed;}}//控制奔跑void SetRun(){if (Input.GetKey(KeyCode.LeftShift)){isRun = true;}else{isRun = false;}}//控制移动void SetMove(){moveDirection = transform.right * horizontal + transform.forward * vertical; // 计算移动方向//将该向量从局部坐标系转换为世界坐标系,得到最终的移动方向// moveDirection = transform.TransformDirection(new Vector3(h, 0, v));moveDirection = moveDirection.normalized; // 归一化移动方向,避免斜向移动速度过快  }//控制跳跃void SetJump(){bool jump = Input.GetButtonDown("Jump");if (isGround){// 在着地时阻止垂直速度无限下降if (_verticalVelocity < 0.0f){_verticalVelocity = -2f;}if (jump){_verticalVelocity = jumpHeight;}}else{//随时间施加重力_verticalVelocity += Gravity * Time.deltaTime;}characterController.Move(moveDirection * speed * Time.deltaTime + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);}
}

效果
在这里插入图片描述

游泳

实现游泳的逻辑大概就是,修改PlayerMovement人物脚本,控制人物在两个重力直接切换,并修改水里的移动方向为视角方向

[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{[Tooltip("角色控制器")] public CharacterController characterController;[Tooltip("重力加速度")] private float Gravity;//当前重力private float horizontal;private float vertical;[Header("移动")][Tooltip("角色行走的速度")] public float walkSpeed = 6f;[Tooltip("角色奔跑的速度")] public float runSpeed = 9f;[Tooltip("角色移动的方向")] private Vector3 moveDirection;[Tooltip("当前速度")] private float speed;[Tooltip("是否奔跑")] private bool isRun;[Header("地面检测")][Tooltip("是否在地面")] private bool isGround;[Header("跳跃")][Tooltip("角色跳跃的高度")] public float jumpHeight = 5f;private float _verticalVelocity;[Header("水")]public bool isSwimming;//是否在水里//是否在水面public bool isUnderWater;//是否被水淹没public float swimmingGravity = -0.5f; //水里的重力public float groundGravity = -19.8f;//地面的重力public Transform Camera;void Start(){speed = walkSpeed;}void Update(){horizontal = Input.GetAxis("Horizontal");vertical = Input.GetAxis("Vertical");//地面检测isGround = characterController.isGrounded;SetSpeed();SetRun();SetJump();}//速度设置void SetSpeed(){if (isRun){speed = runSpeed;}else{speed = walkSpeed;}}//控制奔跑void SetRun(){if (Input.GetKey(KeyCode.LeftShift)){isRun = true;}else{isRun = false;}}//控制跳跃void SetJump(){bool jump = Input.GetButtonDown("Jump");if (isGround){// 在着地时阻止垂直速度无限下降if (_verticalVelocity < 0.0f){_verticalVelocity = -2f;}if (jump){_verticalVelocity = jumpHeight;}}//水里处理if (isSwimming){Gravity = swimmingGravity;_verticalVelocity = Gravity;moveDirection = transform.right * horizontal + Camera.forward * vertical; //水里往相机的前方移动}else{Gravity = groundGravity;//随时间施加重力_verticalVelocity += Gravity * Time.deltaTime;moveDirection = transform.right * horizontal + transform.forward * vertical;}moveDirection = moveDirection.normalized; // 归一化移动方向,避免斜向移动速度过快characterController.Move(moveDirection * speed * Time.deltaTime + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);}
}

记得配置角色标签
在这里插入图片描述

编辑水的触发器碰撞体积
在这里插入图片描述
效果
在这里插入图片描述

水面停留

我们不希望人物出了水面,还是在上下浮动,可以选择在任务离开水面时把y轴速度设置为0即可,修改PlayerMovement

public bool isUnderWater;//是否被水淹没//。。。void SetJump()
{//控制跳跃bool jump = Input.GetButtonDown("Jump");if (isGround){// 在着地时阻止垂直速度无限下降if (_verticalVelocity < 0.0f){_verticalVelocity = -2f;}if (jump){_verticalVelocity = jumpHeight;}}//水里处理if (isSwimming){if (isUnderWater){Gravity = swimmingGravity;_verticalVelocity = Gravity;}else{_verticalVelocity = 0;}moveDirection = transform.right * horizontal + Camera.forward * vertical; //水里往相机的前方移动}else{Gravity = groundGravity;//随时间施加重力_verticalVelocity += Gravity * Time.deltaTime;moveDirection = transform.right * horizontal + transform.forward * vertical;}moveDirection = moveDirection.normalized; // 归一化移动方向,避免斜向移动速度过快characterController.Move(moveDirection * speed * Time.deltaTime + new Vector3(0.0f, _verticalVelocity, 0.0f) * Time.deltaTime);
}

我们只要检测摄像机是否在水下即可,给我们的摄像机添加触发器和刚体
在这里插入图片描述

修改SwimAra

public class SwimAra : MonoBehaviour
{private void OnTriggerEnter(Collider other) {if(other.CompareTag("Player")){other.GetComponent<PlayerMovement>().isSwimming = true;}if(other.CompareTag("MainCamera")){other.GetComponentInParent<PlayerMovement>().isUnderWater = true;}}private void OnTriggerExit(Collider other) {if(other.CompareTag("Player")){other.GetComponent<PlayerMovement>().isSwimming = false;}if(other.CompareTag("MainCamera")){other.GetComponentInParent<PlayerMovement>().isUnderWater = false;}}
}

效果
在这里插入图片描述

添加水下后处理

在这里插入图片描述
修改模式为局部,碰撞体积设置和水体一样大
在这里插入图片描述

简单配置后处理,添加通道混色器
在这里插入图片描述

你会发现看不到效果,因为我们还需要开启摄像机的后处理效果,记得所有相机都要开启,记得把人物放进水里
在这里插入图片描述
提升伽马增益
在这里插入图片描述

视野模糊效果(Depth OF Field)
在这里插入图片描述

全屏屏幕光圈效果
在这里插入图片描述

胶片颗粒感
在这里插入图片描述
效果
在这里插入图片描述

水下呼吸

新增PlayerHealth,控制人物状态

public class PlayerHealth : MonoBehaviour
{public static PlayerHealth Instance;public float maxHealth = 100;//最大生命值public float currentHealth;//---玩家氧气----/public float currentOxygenPercent; // 当前氧气百分比public float maxOxygenPercent = 100; // 最大氧气百分比public float oxygenDecreasedPerSecond = 1f; // 每次减少的氧气百分比private float oxygenTimer = 0f; // 氧气计时器private float decreaseInterval = 1f; // 减少间隔public GameObject oxygenBar;//氧气条private void Awake() {Instance = this;}void Start(){currentHealth = maxHealth;currentOxygenPercent = maxOxygenPercent;}void Update(){if (GetComponent<PlayerMovement>().isUnderWater){oxygenBar.SetActive(true);oxygenTimer += Time.deltaTime;if (oxygenTimer > decreaseInterval){DecreaseOxygen();oxygenTimer = 0;}}else{oxygenBar.SetActive(false);currentOxygenPercent = maxOxygenPercent;}}private void DecreaseOxygen(){currentOxygenPercent -= oxygenDecreasedPerSecond;// 没有氧气了if (currentOxygenPercent < 0){currentOxygenPercent = 0;//扣血currentHealth -= 1f;}}
}

新增OxygenBar,控制人物氧气条UI

public class OxygenBar : MonoBehaviour
{private Slider slider; // 氧气条的滑动条public TextMeshProUGUI oxygenCounter; // 氧气计数器文本private float currentOxygen, maxOxygen; // 当前氧气值和最大氧气值void Awake(){slider = GetComponent<Slider>(); // 获取滑动条组件}void Update(){currentOxygen = PlayerHealth.Instance.currentOxygenPercent; // 获取当前氧气百分比maxOxygen = PlayerHealth.Instance.maxOxygenPercent; // 获取最大氧气百分比float fillValue = currentOxygen / maxOxygen; // 计算填充值slider.value = fillValue; // 更新滑动条的值oxygenCounter.text = (fillValue * 100).ToString("0") + "%"; // 更新氧气计数器文本显示}
}

配置
在这里插入图片描述
在这里插入图片描述
效果
在这里插入图片描述

钓鱼

待续

参考

https://www.youtube.com/watch?v=vX5AOF4Wdgo&list=PLtLToKUhgzwnk4U2eQYridNnObc2gqWo-&index=44

完结

赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注,以便我第一时间收到反馈,你的每一次支持都是我不断创作的最大动力。当然如果你发现了文章中存在错误或者有更好的解决方法,也欢迎评论私信告诉我哦!

好了,我是向宇,https://xiangyu.blog.csdn.net

一位在小公司默默奋斗的开发者,出于兴趣爱好,最近开始自学unity,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!php是工作,unity是生活!如果你遇到任何问题,也欢迎你评论私信找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~

在这里插入图片描述

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

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

相关文章

239.滑动窗口最大值

一个和 滑动窗口有关的题目 官方给出了三种解法 很值得借鉴 方法一: priority_queue O(nlogn) 使用模板库的优先队列保存pair(i, nums[i]) 在取最大值 .top() 的时候 注意 看一看它的下标在不在范围内(<i-k), 不在的时候需要把它(队首元素)pop出去 每次push或者pop…

Meta正打造一个巨型AI模型,旨在为其“整个视频生态系统”提供动力,一位高管透露

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【Linux】gcc与make、makefile

文章目录 1 gcc/g1.1 预处理1.2 编译1.3 汇编1.4 链接1.4.1 静态链接1.4.2 动态链接 2 make和makefile2.1 依赖关系2.2 依赖方法2.3 伪目标 3 总结 1 gcc/g 当我们创建一个文件&#xff0c;并向里面写入代码&#xff0c;此时&#xff0c;我们该如何使我们的代码能够运行起来呢&…

java中使用rabbitmq

文章目录 前言一、引入和配置1.引入2.配置 二、使用1.队列2.发布/订阅2.1 fanout(广播)2.2 direct(Routing/路由)2.3 Topics(主题)2.4 Headers 总结 前言 mq常用于业务解耦、流量削峰和异步通信,rabbitmq是使用范围较广,比较稳定的一款开源产品,接下来我们使用springboot的sta…

保姆级认识AVL树【C++】(三种insert情况 || 四种旋转方法)

目录 前言 一&#xff0c;AVL概念 二&#xff0c;基础框架 三&#xff0c;insert 1. 插入三种情况 2. 四种旋转方法 法一&#xff1a;左单旋法 法二&#xff1a;右单旋法 法三&#xff1a;先左后右双旋法 法四&#xff1a;先右后左双旋法 测试&#xff08;判断一棵树…

修改简化docker命令

修改|简化docker命令 使用命令打开 .bashrc 文件&#xff1a; vim ~/.bashrc在文件中添加类似以下行来创建别名&#xff1a; # 查看所有容器 alias disdocker images # 查看运行容器 alias dpsdocker ps # 查看所有容器 alias dpsadocker ps -a # 停止容器 alias dsdocker s…

基于智慧灯杆的智慧城市解决方案(2)

功能规划 智慧照明功能 智慧路灯的基本功能仍然是道路照明, 因此对照明功能的智慧化提升是最基本的一项要求。 对道路照明管理进行智慧化提升, 实施智慧照明, 必然将成为智慧城市中道路照明发展的主要方向之一。 智慧照明是集计算机网络技术、 通信技术、 控制技术、 数据…

Data Concerns Modeling Concerns

How was the data you are using collected? What assumptions is your model making by learning from this dataset? Is this dataset representative enough to produce a useful model? How could the results of your work be misused? What is the intended use and …

第15章——西瓜书规则学习

1.序贯覆盖 序贯覆盖是一种在规则学习中常用的策略&#xff0c;它通过逐步构建规则集来覆盖训练数据中的样本。该策略采用迭代的方式&#xff0c;每次从训练数据中选择一部分未被覆盖的样本&#xff0c;学习一条能够覆盖这些样本的规则&#xff0c;然后将这条规则加入到规则集中…

【Python】成功解决ModuleNotFoundError: No module named ‘matplotlib‘

【Python】成功解决ModuleNotFoundError: No module named ‘matplotlib’ &#x1f308; 个人主页&#xff1a;高斯小哥 &#x1f525; 高质量专栏&#xff1a;Matplotlib之旅&#xff1a;零基础精通数据可视化、Python基础【高质量合集】、PyTorch零基础入门教程&#x1f448…

Linux系统安装及简单操作

目录 一、Linux系统安装 二、Linux系统启动 三、Linux系统本地登录 四、Linux系统操作方式 五、Linux的七种运行级别&#xff08;runlevel&#xff09; 六、shell 七、命令 一、Linux系统安装 场景1&#xff1a;直接通过光盘安装到硬件上&#xff08;方法和Windows安装…

基于springboot实现摄影网站系统项目【项目源码】

基于springboot实现摄影网站系统演示 摘要 随着时代的进步&#xff0c;社会生产力高速发展&#xff0c;新技术层出不穷信息量急剧膨胀&#xff0c;整个社会已成为信息化的社会人们对信息和数据的利用和处理已经进入自动化、网络化和社会化的阶段。如在查找情报资料、处理银行账…