来自油管大神:https://www.youtube.com/watch?v=QPiZSTEuZnw&lc=z22ehdxp5wmrg1jkvacdp431qmalafpquvm0apfrjrxw03c010c&feature=em-comments

核心代码

using System.Collections;
using System.Collections.Generic;
using UnityEngine; public class PlayerController : MonoBehaviour
{ [SerializeField]
private float movementSpeed;
[SerializeField]
private float groundCheckRadius;
[SerializeField]
private float jumpForce;
[SerializeField]
private float slopeCheckDistance;
[SerializeField]
private float maxSlopeAngle;
[SerializeField]
private Transform groundCheck;
[SerializeField]
private LayerMask whatIsGround;
[SerializeField]
private PhysicsMaterial2D noFriction;
[SerializeField]
private PhysicsMaterial2D fullFriction; private float xInput;
private float slopeDownAngle;
private float slopeSideAngle;
private float lastSlopeAngle; private int facingDirection = 1; private bool isGrounded;
private bool isOnSlope;
private bool isJumping;
private bool canWalkOnSlope;
private bool canJump; private Vector2 newVelocity;
private Vector2 newForce;
private Vector2 capsuleColliderSize; private Vector2 slopeNormalPerp; private Rigidbody2D rb;
private CapsuleCollider2D cc; private void Start()
{
rb = GetComponent<Rigidbody2D>();
cc = GetComponent<CapsuleCollider2D>(); capsuleColliderSize = cc.size;
} private void Update()
{
CheckInput();
} private void FixedUpdate()
{
CheckGround();
SlopeCheck();
ApplyMovement();
} private void CheckInput()
{
xInput = Input.GetAxisRaw("Horizontal"); if (xInput == 1 && facingDirection == -1)
{
Flip();
}
else if (xInput == -1 && facingDirection == 1)
{
Flip();
} if (Input.GetButtonDown("Jump"))
{
Jump();
} }
private void CheckGround()
{
isGrounded = Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, whatIsGround); if(rb.velocity.y <= 0.0f)
{
isJumping = false;
} if(isGrounded && !isJumping && slopeDownAngle <= maxSlopeAngle)
{
canJump = true;
} } private void SlopeCheck()
{
Vector2 checkPos = transform.position - (Vector3)(new Vector2(0.0f, capsuleColliderSize.y / 2)); SlopeCheckHorizontal(checkPos);
SlopeCheckVertical(checkPos);
} private void SlopeCheckHorizontal(Vector2 checkPos)
{
RaycastHit2D slopeHitFront = Physics2D.Raycast(checkPos, transform.right, slopeCheckDistance, whatIsGround);
RaycastHit2D slopeHitBack = Physics2D.Raycast(checkPos, -transform.right, slopeCheckDistance, whatIsGround); if (slopeHitFront)
{
isOnSlope = true; slopeSideAngle = Vector2.Angle(slopeHitFront.normal, Vector2.up); }
else if (slopeHitBack)
{
isOnSlope = true; slopeSideAngle = Vector2.Angle(slopeHitBack.normal, Vector2.up);
}
else
{
slopeSideAngle = 0.0f;
isOnSlope = false;
} } private void SlopeCheckVertical(Vector2 checkPos)
{
RaycastHit2D hit = Physics2D.Raycast(checkPos, Vector2.down, slopeCheckDistance, whatIsGround); if (hit)
{ slopeNormalPerp = Vector2.Perpendicular(hit.normal).normalized; slopeDownAngle = Vector2.Angle(hit.normal, Vector2.up); if(slopeDownAngle != lastSlopeAngle)
{
isOnSlope = true;
} lastSlopeAngle = slopeDownAngle; Debug.DrawRay(hit.point, slopeNormalPerp, Color.blue);
Debug.DrawRay(hit.point, hit.normal, Color.green); } if (slopeDownAngle > maxSlopeAngle || slopeSideAngle > maxSlopeAngle)
{
canWalkOnSlope = false;
}
else
{
canWalkOnSlope = true;
} if (isOnSlope && canWalkOnSlope && xInput == 0.0f)
{
rb.sharedMaterial = fullFriction;
}
else
{
rb.sharedMaterial = noFriction;
}
} private void Jump()
{
if (canJump)
{
canJump = false;
isJumping = true;
newVelocity.Set(0.0f, 0.0f);
rb.velocity = newVelocity;
newForce.Set(0.0f, jumpForce);
rb.AddForce(newForce, ForceMode2D.Impulse);
}
} private void ApplyMovement()
{
if (isGrounded && !isOnSlope && !isJumping) //if not on slope
{
Debug.Log("This one");
newVelocity.Set(movementSpeed * xInput, 0.0f);
rb.velocity = newVelocity;
}
else if (isGrounded && isOnSlope && canWalkOnSlope && !isJumping) //If on slope
{
newVelocity.Set(movementSpeed * slopeNormalPerp.x * -xInput, movementSpeed * slopeNormalPerp.y * -xInput);
rb.velocity = newVelocity;
}
else if (!isGrounded) //If in air
{
newVelocity.Set(movementSpeed * xInput, rb.velocity.y);
rb.velocity = newVelocity;
} } private void Flip()
{
facingDirection *= -1;
transform.Rotate(0.0f, 180.0f, 0.0f);
} private void OnDrawGizmos()
{
Gizmos.DrawWireSphere(groundCheck.position, groundCheckRadius);
} }

工程地址:https://drive.google.com/drive/folders/1qxFq3EBkU0JLu_iwXOtEc9-dW6_C1SpL

unity2d 完美斜坡方案的更多相关文章

  1. JMessage是让App 同时集成 Push 功能与 IM 功能最完美的方案

    历经几个月的沉寂,以及兄弟们的奋战,极光推送的兄弟产品诞生了:极光IM,英文名 JMessage. 极光IM 是我们团队基于大量客户的需求反馈,在很多客户的殷切期盼下所开发的.团队成员一方面要支撑极光 ...

  2. X86平台下嵌入式linux触摸屏解决方案(usb触摸屏控制器+完美校准方案+触摸屏QTE开发环境搭建)

    一直在用X86平台,真心不想用WINCE和XPE,一些大的硬件供应商都不提供linux平台下的技术支持,比如研华的3343PC104系列的板子... 开发的问题如下: 1 USB控制器目前只有台湾和竹 ...

  3. Unity2D屏幕适配方案

    看了cnblogs里的一篇文章,终于理解了Unity2D的摄像机系统:http://www.cnblogs.com/flyFreeZn/p/4073655.html 我根据他的方案,改写了两种适配方案 ...

  4. Microsoft.AspNet.Web.Optimization.Bundle的完美替换方案

    Web应用程序中包含大量的样式(css)和脚本(js)文件,这些文件的引用.管理和发布有很多解决方案.在Asp.Net MVC应用程序中,大家最熟悉的解决方案应属Microsoft.AspNet.We ...

  5. C++类的完美单元测试方案——基于C++11扩展的friend语法

    版权相关声明:本文所述方案来自于<深入理解C++11—C++11新特性解析与应用>(Michael Wong著,机械工业出版社,2016.4重印)一书的学习. 项目管理中,C语言工程做单元 ...

  6. Server-U FTP与AD完美集成方案详解

    最近咱有个任务,那就是把公司的文件服务器.FTP服务器.邮件服务器进行迁移并作相应的整合.登陆后台查看了,公司目前正在使用的方案.FTP服务器使用的是Server-u FTP,验证方式选择的windo ...

  7. delphi之完美Splash方案(在TfrmMain.FormCreate里不断调用TfrmSplash显示加载进度文字,并且及时Update显示)

    前言:网上有很多介绍delphi创建闪屏的代码,大多只是在程序开启前显示一个闪屏,但是却没有说如何在闪屏上显示程序加载的进度,于是笔者有意思介绍一下这种闪屏方式. 1.创建一个窗体(TfrmSplas ...

  8. 【jeecg-mybatis版本】 mybatis+spring mvc 完美整合方案 查询,保存,更新,删除自动生成

    Jeecg-Mybatis版本代码生成器演示视频 http://pan.baidu.com/share/link?shareid=243717&uk=2668473880   简要说明  JE ...

  9. Linux终极shell-zsh的完美配置方案!——oh-my-zsh

    Zsh 介绍 Zsh 兼容 Bash,据传说 99% 的 Bash 操作 和 Zsh 是相同的 Zsh 官网:http://www.zsh.org/ 先看下你的 Linux支持哪些 shell:cat ...

  10. ionic3-ng4学习见闻--(轮播图完美方案)

    ionic上 轮播图是最坑的插件了吧,各种bug和 问题. 事件也不好用.. 于是,我终于搞出来了一个完美的方案, 适用于,动态获取轮播图数据,自动循环播放,跳转其他页面回来后自动播放,手指触摸后自动 ...

随机推荐

  1. 数字孪生工厂实战指南:基于Unreal Engine/Omniverse的虚实同步系统开发

    引言:工业元宇宙的基石技术 在智能制造2025与工业元宇宙的交汇点,数字孪生技术正重塑传统制造业.本文将手把手指导您构建基于Unreal Engine 5.4与NVIDIA Omniverse的实时数 ...

  2. RPC实战与核心原理之路由策略

    路由策略:怎么让请求按照设定的规则发到不同的节点上 回顾 健康检测在 RPC 中的作用,简单来讲就是帮助调用方应用来管理所有服务提供方的连接,并动态维护每个连接的状态,方便服务调用方在每次发起请求的时 ...

  3. C#实现MCP Client 与 LLM 连接,抓取网页内容功能!

    前面的课程,我们已经用C#实现了,自己的MCP Client. 下面我们一起来实现,MCP Client与LLM 对接. 一.添加依赖库 目前来说,绝大部分的大模型的API,都是遵循OpenAI的接口 ...

  4. 异步日志监控:FastAPI与MongoDB的高效整合之道

    title: 异步日志监控:FastAPI与MongoDB的高效整合之道 date: 2025/05/27 17:49:39 updated: 2025/05/27 17:49:39 author: ...

  5. Spring注解之@Autowired自动装配bean 综述

    @Autowired的工作原理是什么?在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowire ...

  6. windows系统部署minio

    下载 在官网下载exe https://dl.min.io/server/minio/release/windows-amd64/ 创建文件夹 把minio.exe放到一个文件夹里,然后同目录里再新建 ...

  7. 关于python的一些学习笔记

    一种是利用三引号的方法.三引号下默认允许自动换行,第二种就是在文字之间插入\n这种方式(使用转义字符) 这里是关于转义字符的一些总结. 2.关于运算符号 小学除法取余%,中学开n方**,小学除法取整/ ...

  8. burpsuite插件-验证码识别插件使用教程

    一.插件下载 下载最新插件与验证码识别端(captcha-killer-modified.jar.codereg.py) 使用Burp加载captcha-killer-modified.jar 安装p ...

  9. Java源码分析系列笔记-6.ReentrantLock

    目录 1. 是什么 1.1. synchronized vs ReentranLock 2. 实现原理 2.1. uml图 3. 公平锁 3.1. 如何使用 3.2. 原理分析 3.2.1. 构造方法 ...

  10. Django实战:自定义中间件实现全链路操作日志记录

    一.中间件 介绍 在 Django 中,中间件(Middleware)是一组轻量级.底层的插件系统,用于全局地改变 Django 的输入和输出.中间件可以在请求被处理之前和响应返回之前执行代码,从而实 ...