20240115-【UNITY 学习】第一人称移动增加斜坡移动、冲刺和蹲伏功能

直接修改或者替换PlayerMovement_01.cs

在这里插入图片描述

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovement_02 : MonoBehaviour
{
    private float moveSpeed; // 玩家移动速度
    public float walkSpeed = 7; // 行走速度
    public float sprintSpeed = 10; // 冲刺速度


    public float groundDrag = 5; // 地面时的阻力

    public float playerHeight = 2; // 玩家身高
    public LayerMask whatIsGround; // 地面的LayerMask
    private bool grounded; // 是否在地面上

    public float jumpForce = 6; // 跳跃力度
    public float jumpCooldown = 0.25f; // 跳跃冷却时间
    public float airMultiplier = 0.4f; // 空中移动速度衰减
    private bool readyToJump = true; // 是否可以跳跃

    public float crouchSpeed = 3.5f; // 蹲伏时的移动速度
    public float crouchYScale = 0.5f; // 蹲伏时的Y轴缩放比例
    private float startYScale; // 初始Y轴缩放比例

    public float maxSlopAngle = 40; // 最大坡度角度
    private RaycastHit slopeHit; // 坡度检测的射线信息
    private bool exitingSlope = true; // 是否正在离开坡度

    public KeyCode jumpKey = KeyCode.Space; // 跳跃键
    public KeyCode sprintKey = KeyCode.LeftShift; // 冲刺键
    public KeyCode crouchKey = KeyCode.LeftControl; // 下蹲键

    public Transform orientation; // 玩家朝向的Transform

    private float h; // 水平输入
    private float v; // 垂直输入

    private Vector3 moveDirection; // 移动方向

    private Rigidbody rb; // 玩家刚体

    public MovementState state; // 当前玩家的移动状态
    public enum MovementState
    {
        walking,    // 行走
        sprinting,  // 冲刺
        crouching,  // 蹲伏
        air         // 空中
    }

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.freezeRotation = true; // 防止刚体旋转

        startYScale = transform.localScale.y;  // 记录初始的Y轴缩放
    }

    private void Update()
    {
        grounded = Physics.Raycast(transform.position, Vector3.down, playerHeight * 0.5f + 0.2f, whatIsGround);

        MyInput();

        SpeedControl();

        StateHandler();

        if (grounded)
            rb.drag = groundDrag;
        else
            rb.drag = 0;
    }

    private void FixedUpdate()
    {
        MovePlayer();
    }

    private void MyInput()
    {
        // 获取水平和垂直输入
        h = Input.GetAxisRaw("Horizontal");
        v = Input.GetAxisRaw("Vertical");

        // 如果按下跳跃键且准备好跳,并且在地面上
        if (Input.GetKey(jumpKey) && readyToJump && grounded)
        {
            readyToJump = false;

            Jump();

            Invoke(nameof(ResetJump), jumpCooldown);
        }

        if (Input.GetKeyDown(crouchKey))
        {
            // 调整玩家缩放以模拟蹲下效果
            transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);

            rb.AddForce(Vector3.down * 5f, ForceMode.Impulse);
        }

        // 如果释放下蹲键
        if (Input.GetKeyUp(crouchKey))
        {
            // 恢复到原始Y轴缩放
            transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
        }
    }

    private void MovePlayer()
    {
        // 根据朝向计算移动方向
        moveDirection = orientation.forward * v + orientation.right * h;

        // 如果在斜坡上并且不是即将离开斜坡
        if (OnSlope() && !exitingSlope)
        {
            // 在斜坡上施加力,以便更好地移动
            rb.AddForce(GetSlopeMoveDirection() * moveSpeed * 20f, ForceMode.Force);

            // 如果垂直速度为正(上升),则额外施加向下的力,以克服斜坡引起的垂直速度变慢
            if (rb.velocity.y > 0)
            {
                rb.AddForce(Vector3.down * 80f, ForceMode.Force);
            }
        }
        else if (grounded) // 如果在地面上
        {
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f, ForceMode.Force); // 在地面上施加移动力
        }
        else if (!grounded) // 如果在空中
        {
            // 在空中施加移动力,乘以空中移动速度衰减系数
            rb.AddForce(moveDirection.normalized * moveSpeed * 10f * airMultiplier, ForceMode.Force);
        }

        // 根据是否在斜坡上决定是否启用重力
        rb.useGravity = !OnSlope();
    }

    private void SpeedControl()
    {
        // 如果在斜坡上并且不是即将离开斜坡
        if (OnSlope() && !exitingSlope)
        {
            // 如果速度的大小超过了设定的移动速度
            if (rb.velocity.magnitude > moveSpeed)
            {
                // 将速度归一化,并乘以设定的移动速度,以限制速度在设定范围内
                rb.velocity = rb.velocity.normalized * moveSpeed;
            }
        }
        // 如果不在斜坡上
        else
        {
            // 获取水平方向的速度
            Vector3 flatVel = new Vector3(rb.velocity.x, 0f, rb.velocity.z);

            // 如果水平速度的大小超过了设定的移动速度
            if (flatVel.magnitude > moveSpeed)
            {
                // 限制水平速度在设定范围内
                Vector3 limitedVel = flatVel.normalized * moveSpeed;

                // 更新刚体的速度,保持垂直速度不变
                rb.velocity = new Vector3(limitedVel.x, rb.velocity.y, limitedVel.z);
            }
        }
    }

    private void Jump()
    {
        exitingSlope = true;

        //rb.velocity = new Vector3(rb.velocity.x, 0f, rb.velocity.z);
        rb.velocity = Vector3.zero;

        // 添加向上的力以实现跳跃
        rb.AddForce(transform.up * jumpForce, ForceMode.Impulse);
    }

    private void ResetJump()
    {
        readyToJump = true;

        exitingSlope = false;
    }

    private void StateHandler()
    {
        // 如果在地面上并且按住冲刺键
        if (grounded && Input.GetKey(sprintKey))
        {
            // 设置当前状态为冲刺状态
            state = MovementState.sprinting;
            // 设置移动速度为冲刺速度
            moveSpeed = sprintSpeed;
        }
        // 如果在地面上但没有按住冲刺键
        else if (grounded)
        {
            // 设置当前状态为行走状态
            state = MovementState.walking;
            // 设置移动速度为行走速度
            moveSpeed = walkSpeed;
        }
        // 如果不在地面上
        else
        {
            // 设置当前状态为空中状态
            state = MovementState.air;
        }

        // 如果按住蹲伏键
        if (Input.GetKey(crouchKey))
        {
            // 设置当前状态为蹲伏状态
            state = MovementState.crouching;
            // 设置移动速度为蹲伏速度
            moveSpeed = crouchSpeed;
        }
    }

    private bool OnSlope()
    {
        // 使用射线检测当前位置向下,获取击中信息存储在slopeHit中
        if (Physics.Raycast(transform.position, Vector3.down, out slopeHit, playerHeight * 0.5f + 0.3f))
        {
            // 计算斜坡的角度
            float angle = Vector3.Angle(Vector3.up, slopeHit.normal);

            // 如果角度小于最大允许斜坡角度且不等于0,表示在斜坡上
            return angle < maxSlopAngle && angle != 0;
        }

        // 如果没有击中信息,或者角度不符合条件,表示不在斜坡上
        return false;

    }

    // 获取在斜坡上移动的方向
    private Vector3 GetSlopeMoveDirection()
    {
        // 使用Vector3.ProjectOnPlane将移动方向投影到斜坡法线上,然后进行归一化
        return Vector3.ProjectOnPlane(moveDirection, slopeHit.normal).normalized;

    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

运筹说 第91期 | 网络计划经典例题讲解

通过前几期的学习&#xff0c;我们已经学会了网络图的基本概念、时间参数的计算&#xff0c;并且掌握了随机网络的概念、图解评审法的基本原理和基本解法&#xff0c;本期小编带大家学习网络计划在经济管理中的应用。 在实际工作中&#xff0c;我们能发现网络计划在经济管理中…

ThingsPanel部署和使用

前置条件&#xff1a; 首先默认大家有一台服务器或者云服务器并且已经搭建好环境。小编是基于Linux宝塔环境以Docker安装ThingsPanel平台。 一.Docker和Docker-compose 1.概述 Docker是一个开源的容器化平台&#xff0c;它可以帮助开发者将应用程序与其依赖项打包到一个轻量…

Windows10 Docker Desktop安装

一、简介 Docker Desktop是Docker公司推出的一款桌面应用程序&#xff0c;它提供了一个用户友好的界面&#xff0c;方便开发人员在本地环境中使用容器技术。 容器是一种轻量级的虚拟化技术&#xff0c;可以将应用程序和其依赖项打包在一起&#xff0c;形成一个独立、可移植的…

gateway Redisson接口级别限流解决方案

文章目录 前言1. 计数器算法&#xff08;固定窗口限流器&#xff09;2. 滑动窗口日志限流器3. 漏桶算法&#xff08;Leaky Bucket&#xff09;4. 令牌桶算法&#xff08;Token Bucket&#xff09;5. 限流队列应用场景实现工具 一、Redisson简介二、Redisson限流器的原理三、Red…

Docker实战06|深入剖析Docker Run命令

前几篇文章中&#xff0c;重点讲解了Linux Namespace、Cgroups、AUFS的核心原理&#xff0c;同样也是Docker的底层原理实现。目录如下&#xff1a; • 《Docker实战01&#xff5c;容器与开发语言》 • 《Docker实战02&#xff5c;Namespace》 • 《Docker实战03&#xff5c;C…

RPA与通知机器人的完美结合

写在前面 在现代快节奏的工作环境中&#xff0c;我们经常会面临多个任务同时进行的情况&#xff0c;你还在为时间不够用、忙碌而惆怅吗&#xff1f;你还在为时刻盯着电脑流程而烦恼吗&#xff1f;你还在为及时收不到自己的自动化任务进度而焦躁吗&#xff1f;别担心&#xff0…

6K star! 100%本地运行LLM的AI助手

AI套壳千千万万&#xff0c;你最喜欢哪一款&#xff1f;现在各种ChatGPT替代品层出不穷&#xff0c;但是大部分都是使用OpenAI的API&#xff0c;也就说离不开网络。 今天我们推荐的开源项目它就是要帮你100%在本地运行大模型&#xff0c;进而构建一个属于自己的ChatGPT&#x…

直播岗位认知

一、直播平台特性与规则 作为直播岗位的一员&#xff0c;首先要了解所使用的直播平台的特性与规则。不同的平台有着不同的用户群体和特点&#xff0c;同时也有各自的运营规则和规范。熟悉平台的操作界面、功能特点、用户行为规范、广告和版权等方面的规定&#xff0c;对于保证…

Vue Axios——前端技术栈

文章目录 基本介绍Vue是什么&#xff1f; MVVMVue的使用快速入门注意事项和使用细节 Vue 数据绑定机制分析数据单向渲染注意事项和细节 双向数据绑定事件绑定示例&#xff1a;注意事项和使用细节课后作业1课后作业2 修饰符示例 条件渲染/控制: v-if v-showv-if VS v-show课后作…

[HTML]Web前端开发技术12(HTML5、CSS3、JavaScript )——喵喵画网页

希望你开心&#xff0c;希望你健康&#xff0c;希望你幸福&#xff0c;希望你点赞&#xff01; 最后的最后&#xff0c;关注喵&#xff0c;关注喵&#xff0c;关注喵&#xff0c;佬佬会看到更多有趣的博客哦&#xff01;&#xff01;&#xff01; 喵喵喵&#xff0c;你对我真的…

ArcGIS Pro中怎么加载在线地图

当我们在制图的时候&#xff0c;有的时候需要加载在线地图&#xff0c;在ArcGIS Pro中加载在线地图的方式有很多&#xff0c;这里为大家介绍一下加载的方法&#xff0c;希望能对你有所帮助。 加载底图 在菜单栏上选择地图&#xff0c;点击底图&#xff0c;可以看到所有可加载…

【PyQt小知识 - 7】:QLineEdit设置输入的文本以圆点或星号等方式显示

文章目录 setEchoMode setEchoMode 在PyQt中&#xff0c;QLineEdit是一种用于接收用户输入的小部件&#xff08;widget&#xff09;。setEchoMode是QLineEdit类中的一个方法&#xff0c;可以用于设置文本输入框中的文本显示模式。它接受一个参数来指定要使用的模式。 setEcho…

「JavaSE」类和对象2

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;快来卷Java啦 &#x1f387;欢迎点赞收藏加关注哦&#xff01; 类和对象2 &#x1f349;匿名对象&#x1f349;关键字static&#x1f34c;static修饰成员变量&#x1f34c;static修饰成员方法&…

JavaScript switch case语句

JS switch case 语句与 if else 语句的多分支结构类似&#xff0c;都可以根据不同的条件来执行不同的代码&#xff1b;但是与 if else 多分支结构相比&#xff0c;switch case 语句更加简洁和紧凑&#xff0c;执行效率更高。 JavaScript switch case 语句的语法格式如下&#…

认识SpringBoot中的条件注解

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: 循序渐进学SpringBoot ✨特色专栏: MySQL学习 🥭本文内容:认识SpringBoot中的条件注解 📚个人知识库: Leo知识库,欢迎大家访问 1.前…

实人认证(人像三要素)API:加强用户身份验证

前言 在当今数字化时代&#xff0c;随着互联网应用的广泛普及&#xff0c;用户身份验证的重要性日益凸显。实人认证&#xff08;人像三要素&#xff09;API作为一种新型的身份验证方式&#xff0c;凭借其高效、安全和便捷的特性&#xff0c;正在成为加强用户身份验证的强大工具…

微调您的Embedding模型以最大限度地提高RAG管道中的相关性检索

英文原文地址&#xff1a;https://betterprogramming.pub/fine-tuning-your-embedding-model-to-maximize-relevance-retrieval-in-rag-pipeline-2ea3fa231149 微调您的Embedding模型以最大限度地提高RAG管道中的相关性检索 微调嵌入前后的 NVIDIA SEC 10-K 文件分析 2023 年…

护眼灯有蓝光吗?防蓝光护眼台灯推荐

护眼台灯是家长为孩子购买的常见用品之一&#xff0c;但对于它的了解却不够深入&#xff0c;很多人购买之后反而容易出现眼睛疲劳、不适的情况&#xff01;据了解&#xff0c;主要的原因是因为在选择护眼台灯时&#xff0c;大多数人没有专业知识&#xff0c;没有买到合适的护眼…

Web3与环保:区块链如何推动可持续发展

随着气候变化和环境问题日益严峻&#xff0c;社会对可持续发展的需求变得愈发迫切。在这个背景下&#xff0c;Web3技术和区块链崭露头角&#xff0c;成为推动可持续发展的关键力量。本文将深入探讨Web3技术如何与环保理念相结合&#xff0c;引领我们迈向更加可持续的未来。 1. …

统计学习 复习(知识点+习题)

复习资料&#xff1a;https://github.com/RuijieZhu94/StatisticalLearning_USTC 第一章 线性回归 1. From one to two 最小二乘 课后题 有偏/无偏估计 加权最小二乘 2. Regularization 线性回归&#xff08;二维情况&#xff09; 求解有约束优化问题 正则化最小加权二乘…