文章目录
一、前言
还一直在手搓第一三人称角色控制?今天推荐一个unity的免费插件,可以轻松实现一三人称角色控制,在不用书写任何代码的情况下,它已经包括了角色的基本移动奔跑跳跃、相机跟随、角色动画、脚步声、物理系统和移动端支持。如果你的项目对角色控制要求不高,我很推荐你使用它,可以快速开始你的第一三人称项目。
当然后面我会改造它,继续补充一些它不带但是很常用的功能,比如实现一三人称切换、瞄准射击等功能。
二、第三人称
1、下载资产
Start Asset 资源商店:
https://assetstore.unity.com/packages/essentials/starter-assets-third-person-character-controller-196526
2、限制
3、导入
4、使用
打开演示场景,就可以使用了,按住shift就是跑
5、替换模型
换上新模型,调整大小
删除本身模型
换一个骨骼
效果
三、第一人称
1、资产下载
https://assetstore.unity.com/packages/essentials/starterassets-firstperson-updates-in-new-charactercontroller-pac-196525
2、限制
3、使用
打开演示场景,就可以使用了,按住shift就是跑
四、移动端支持
开启虚拟摇杆UI即可
五、瞄准射击
1、新增瞄准相机
复制一个第三人称虚拟相机出来,做我们的瞄准相机,修改参数
2、绑定按钮输入控制
我们新增一个和控制跑一样的按钮
修改StarterAssetsInputs代码,直接参考sprint,做一样的事情就行了
3、相机切换
新增脚本ThirdPersonShooterController,控制第三人称瞄准相机切换
测试
现在相机切换过渡太慢了,可以修改相机转换时间加快
4、灵敏度配置
目前默认状态和瞄准状态视角下的灵敏度一样,这明显不是我们要的,我们希望瞄准状态下视角灵敏度低一些,方便我们射击击中目标
修改ThirdPersonController代码,新增控制相机灵敏度变量
修改ThirdPersonshooterController,实现不同状态下不同灵敏度配置
5、瞄准辅助十字形图标
这个很简单,只要在屏幕中心放置一个图标UI就可以了,这里就不多介绍了
*****准心图片开始
*****准心图片结束
6、射线检测
修改ThirdPersonshooterController,用射线检测像屏幕中心点前发射射线,检测碰撞的物体
制作一个瞄准球体做显示点
效果
记得删除测试球体的碰撞体
7、瞄准远处的问题
比如我们瞄准天空,就是失去目标了
当然这里我们可以选择最简单粗暴的方式就是给天上加入空气墙就可以了
或者可以设置为一个远离视野的点Camera.main.transform.position + Camera.main.transform.forward * 100f
,这样就不需要添加空气墙碰撞器了(记得下面的其他步骤也要记得更改)
// 发射射线并检测碰撞
if (Physics.Raycast(ray, out RaycastHit raycastHit, 999f, aimColliderLayerMask))
{
// 在调试Transform的位置上设置击中点
debugTransform.position = raycastHit.point;
}
else
{
// 或者可以设置为一个远离视野的点,例如:
debugTransform.position = Camera.main.transform.position + Camera.main.transform.forward * 100f;
}
8、瞄准角色朝向
瞄准模式下,角色应该一直面向瞄准方向
修改ThirdPersonshooterController,优化一下代码
但是移动起来,还是出问题,因为移动时角色也试图旋转到对应的方向
修改ThirdPersonController,新增变量禁止脚本上的旋转
修改ThirdPersonshooterController,瞄准状态下禁止脚本上的旋转
效果
9、实体子弹射击
新增子弹预制体
新增子弹脚本BulletProjectile,挂载在前面的子弹预制体上
public class BulletProjectile : MonoBehaviour {
private Rigidbody bulletRigidbody;
private void Awake() {
bulletRigidbody = GetComponent<Rigidbody>();
}
private void Start() {
float speed = 50f;
bulletRigidbody.velocity = transform.forward * speed;
}
private void OnTriggerEnter(Collider other) {
Destroy(gameObject);
}
}
绑定设计按钮,这里主要是鼠标左键点击射击
修改StarterAssetsInputs,监听射击按钮输入
修改ThirdPersonShooterController,定义子弹和子弹生成位置,射击功能
10、添加击中特效效果
击中特效就大家自己去实现和制作吧
public class BulletProjectile : MonoBehaviour {
[SerializeField] private Transform vfxHitGreen;
[SerializeField] private Transform vfxHitRed;
private Rigidbody bulletRigidbody;
private void Awake() {
bulletRigidbody = GetComponent<Rigidbody>();
}
private void Start() {
float speed = 50f;
bulletRigidbody.velocity = transform.forward * speed;
}
private void OnTriggerEnter(Collider other) {
if (other.GetComponent<BulletTarget>() != null) {
// Hit target
Instantiate(vfxHitGreen, transform.position, Quaternion.identity);
} else {
// Hit something else
Instantiate(vfxHitRed, transform.position, Quaternion.identity);
}
Destroy(gameObject);
}
}
11、使用射线投射实现射击
修改ThirdPersonShooterController
效果,开枪会立即击中目标
12、两种射击的问题
隔着墙壁射击,子弹射击会被墙壁挡住,而射线投射不会
这里并没有说使用哪种方式更好,具体选择看自己的需求,见仁见智。
13、瞄准动画
我们新增动画层,通过改变这个层权重实现瞄准效果
修改ThirdPersonShooterController 代码
效果
14、最终代码ThirdPersonShooterController
这里贴出ThirdPersonShooterController 参考代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
using StarterAssets;
using UnityEngine.InputSystem;
public class ThirdPersonShooterController : MonoBehaviour {
[SerializeField] private CinemachineVirtualCamera aimVirtualCamera; // 瞄准虚拟相机
[SerializeField] private float normalSensitivity; // 普通灵敏度
[SerializeField] private float aimSensitivity; // 瞄准灵敏度
[SerializeField] private LayerMask aimColliderLayerMask = new LayerMask(); // 瞄准碰撞层
[SerializeField] private Transform debugTransform; // 调试用的Transform,用于显示射线击中点
[SerializeField] private Transform pfBulletProjectile; // 子弹预制体
[SerializeField] private Transform spawnBulletPosition; // 发射子弹的位置
[SerializeField] private Transform vfxHitGreen; // 击中目标效果(绿色)
[SerializeField] private Transform vfxHitRed; // 击中其他物体效果(红色)
private ThirdPersonController thirdPersonController; // 第三人称控制器组件
private StarterAssetsInputs starterAssetsInputs; // 输入控制组件
private Animator animator; // 动画控制器
private void Awake() {
// 初始化组件
thirdPersonController = GetComponent<ThirdPersonController>();
starterAssetsInputs = GetComponent<StarterAssetsInputs>();
animator = GetComponent<Animator>();
}
private void Update() {
Vector3 mouseWorldPosition = Vector3.zero; // 鼠标在世界中的位置
// 计算屏幕中心点的射线
Vector2 screenCenterPoint = new Vector2(Screen.width / 2f, Screen.height / 2f);
Ray ray = Camera.main.ScreenPointToRay(screenCenterPoint);
Transform hitTransform = null;
// 发射射线并检查是否击中物体
if (Physics.Raycast(ray, out RaycastHit raycastHit, 999f, aimColliderLayerMask)) {
// 射线击中物体
debugTransform.position = raycastHit.point; // 更新调试Transform位置
mouseWorldPosition = raycastHit.point; // 鼠标位置设置为击中点
hitTransform = raycastHit.transform; // 记录击中的物体
} else {
// 射线没有击中任何物体
mouseWorldPosition = Camera.main.transform.position + Camera.main.transform.forward * 100f; // 默认鼠标位置在前方远处
}
if (starterAssetsInputs.aim) {
// 进入瞄准模式
aimVirtualCamera.gameObject.SetActive(true); // 启用瞄准相机
thirdPersonController.SetSensitivity(aimSensitivity); // 设置瞄准灵敏度
thirdPersonController.SetRotateOnMove(false); // 瞄准时禁用移动旋转
animator.SetLayerWeight(1, Mathf.Lerp(animator.GetLayerWeight(1), 1f, Time.deltaTime * 13f)); // 平滑过渡动画层权重
Vector3 worldAimTarget = mouseWorldPosition;
worldAimTarget.y = transform.position.y; // 保持瞄准目标与玩家在同一水平面上
Vector3 aimDirection = (worldAimTarget - transform.position).normalized; // 计算瞄准方向
// 平滑地旋转玩家朝向瞄准方向
transform.forward = Vector3.Lerp(transform.forward, aimDirection, Time.deltaTime * 20f);
} else {
// 退出瞄准模式
aimVirtualCamera.gameObject.SetActive(false); // 禁用瞄准相机
thirdPersonController.SetSensitivity(normalSensitivity); // 恢复普通灵敏度
thirdPersonController.SetRotateOnMove(true); // 恢复移动旋转
animator.SetLayerWeight(1, Mathf.Lerp(animator.GetLayerWeight(1), 0f, Time.deltaTime * 13f)); // 平滑过渡动画层权重
}
if (starterAssetsInputs.shoot) {
/*
//实体子弹射击
if (hitTransform != null) {
// 击中目标
if (hitTransform.GetComponent<BulletTarget>() != null) {
// 击中目标对象
Instantiate(vfxHitGreen, mouseWorldPosition, Quaternion.identity); // 实例化绿色击中效果
} else {
// 击中其他物体
Instantiate(vfxHitRed, mouseWorldPosition, Quaternion.identity); // 实例化红色击中效果
}
}
//*/
//*
// Projectile Shoot(射线投射物射击)
Vector3 aimDir = (mouseWorldPosition - spawnBulletPosition.position).normalized; // 计算投射物方向
Instantiate(pfBulletProjectile, spawnBulletPosition.position, Quaternion.LookRotation(aimDir, Vector3.up)); // 实例化子弹并设置其朝向
//*/
starterAssetsInputs.shoot = false; // 重置射击输入
}
}
}
参考
https://www.youtube.com/watch?v=FbM4CkqtOuA
https://www.bilibili.com/video/BV15R4y12776/
https://space.bilibili.com/43644141
完结
赠人玫瑰,手有余香!如果文章内容对你有所帮助,请不要吝啬你的点赞评论和关注
,你的每一次支持
都是我不断创作的最大动力。当然如果你发现了文章中存在错误
或者有更好的解决方法
,也欢迎评论私信告诉我哦!
好了,我是向宇
,https://xiangyu.blog.csdn.net
一位在小公司默默奋斗的开发者,闲暇之余,边学习边记录分享,站在巨人的肩膀上,通过学习前辈们的经验总是会给我很多帮助和启发!如果你遇到任何问题,也欢迎你评论私信或者加群找我, 虽然有些问题我也不一定会,但是我会查阅各方资料,争取给出最好的建议,希望可以帮助更多想学编程的人,共勉~