在这里,我正在尝试制作一个简单的2D平台游戏。我为此尝试了这个YouTube频道(https://www.youtube.com/watch?v=cwcC2tIKObU)系列教程。在视频中进行同样的操作后,我无法将播放器移到斜坡上。这是我的脚本,如果有人可以帮助我,那么请..
问题: 有时玩家会进入斜坡的一半,但我不能顺利地爬上斜坡。如下图所示。有时玩家与斜坡的接触很少而倒下。
Controller2D.cs `
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Controller2D : MonoBehaviour {
/// <summary>
/// -------------------------------------------------------------------------------------
/// Declaring all variables here
/// -------------------------------------------------------------------------------------
/// </summary>
public LayerMask collisionMask; //rays collide with this layer
const float skinWidth = 0.015f;
public int horizontalRayCount = 4, verticalRayCount = 4; //int for determine how many rays are being fire in horizontally and vertically
float horizontalRaySpacing, verticalRaySpacing; //calculate space between horizontal and verticall rays.
private BoxCollider2D collider;
private RaycastOrigins raycastOrigins;//Making reference of method RaycastOrigins
public CollisionInfo collisions;//Making reference of method collsioninfo
float maxClimbAngle = 80f; // Max climb angle between player and surface
/// <summary>
/// /// -------------------------------------------------------------------------------------
/// Starting game 2D controller coding from here.
/// /// -------------------------------------------------------------------------------------
/// </summary>
void Start()
{
collider = GetComponent<BoxCollider2D> ();
CalculateRaySpacing ();
}
void Update()
{
}
public void Move(Vector3 velocity)
{
UpdateRaycastOrirgins ();
//Resetting all bool of collisionInfo method
collisions.Reset();
//Updatting rays that collision with player horizontally using referrence
if (velocity.x != 0)
HorizontalCollisions (ref velocity);
//Updatting rays that collision with player vertically using referrence
if (velocity.y != 0)
VerticalCollisions (ref velocity);
transform.Translate (velocity);
}
/// <summary>
/// -------------------------------------------------------------------------------------
/// We are detectin here a horizontal collsition of rays with player and surface
/// //In this function player move horizontally, so We need to use only horizontal direction
/// If player move forward then We can calculate the distance between player and surface and also can calculate distance
/// between player and other object like obstacles.
/// -------------------------------------------------------------------------------------
/// </summary>
/// <param name="velocity">Velocity.</param>
void HorizontalCollisions(ref Vector3 velocity)
{
//Setting velocity using Mathf.Sign()
float directionX = Mathf.Sign(velocity.x);
//Calculating ray length with adding skinwidth of player
float raylength = Mathf.Abs (velocity.x) + skinWidth;
//THis is for drawing rays in horizontal and vertical direction
for (int i = 0; i < horizontalRayCount; i++)
{
// Making ray from origin (bottomLeft, bottomRight, topLeft, topRight)
//If directionY is equals to -1 then raycast origin is bottom left otherwise top left is origin
//Only bottomLeft or topLeft is because of negative value of Mathf.Sign()
Vector2 rayOrigin = (directionX == -1)?raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
rayOrigin += Vector2.up * (horizontalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, raylength, collisionMask);
Debug.DrawRay (rayOrigin, Vector2.right * directionX * raylength, Color.red);
//Adding vertical velocity after deducting player skin width
if (hit) {
//Calculating slopeANgle here
float slopeAngle = Vector2.Angle(hit.normal, Vector2.up);
if (i == 0 && slopeAngle <= maxClimbAngle) {
print ("Slope angle : " + slopeAngle);
climbSlope(ref velocity, slopeAngle);
}
velocity.x = (hit.distance - skinWidth) * directionX;
raylength = hit.distance;
//First checking direction of player movement, Horizontally positive or negative and then change bool to true
// of CollisionInfo method
collisions.left = directionX == -1;
collisions.right = directionX == 1;
}
}
}
/// <summary>
/// /// -------------------------------------------------------------------------------------
/// We are detectin here a vertical collsition of rays from player to surface
/// If player make any jump then ve can calculate the distance between player and surface and also can calculate distance
/// between player other object like obstacles.
/// -------------------------------------------------------------------------------------
/// </summary>
/// <param name="velocity">Velocity.</param>
void VerticalCollisions(ref Vector3 velocity)
{
//Setting vertical velocity using Mathf.Sign()
float directionY = Mathf.Sign(velocity.y);
//Calculating ray length with adding skinwidth of player
float raylength = Mathf.Abs (velocity.y) + skinWidth;
//THis is for drawing rays in horizontal and vertical direction
for (int i = 0; i < verticalRayCount; i++)
{
// Making ray from origin (bottomLeft, bottomRight, topLeft, topRight)
//If directionY is equals to -1 then raycast origin is bottom left otherwise top left is origin
//Only bottomLeft or topLeft is because of negative value of Mathf.Sign()
Vector2 rayOrigin = (directionY == -1)?raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i * velocity.x);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up * directionY, raylength, collisionMask);
Debug.DrawRay (rayOrigin, Vector2.up * directionY * raylength, Color.red);
//Adding vertical velocity after deducting player skin width
if (hit) {
velocity.y = (hit.distance - skinWidth) * directionY;
raylength = hit.distance;
//First checking direction of player movement, vertically positive or negative and then change bool to true
// of CollisionInfo method
collisions.below = directionY == -1;
collisions.above = directionY == 1;
}
}
}
/// <summary>
/// This method is use to make player able to climb on slope
/// slope calculation done by using trianble formula like y = moveDistance * sin() and x = moveDistance * cos()
/// </summary>
/// <param name="velocity">Velocity.</param>
/// <param name="slopeAngle">Slope angle.</param>
void climbSlope(ref Vector3 velocity, float slopeAngle)
{
float moveDistance = Mathf.Abs (velocity.x);
float climbVelocityY = Mathf.Sin (slopeAngle * Mathf.Deg2Rad) * moveDistance;
if (velocity.y <= climbVelocityY) {
velocity.y = climbVelocityY;
velocity.x = Mathf.Cos (slopeAngle * Mathf.Deg2Rad) * moveDistance * Mathf.Sign (velocity.x);
collisions.below = true;
collisions.climbingslope = true;
}
}
void UpdateRaycastOrirgins()
{
Bounds bounds = collider.bounds;
//Expand the bounds by increasing its size amound along each side.
bounds.Expand (skinWidth * (-2));
//Increasing size of bounds
raycastOrigins.bottomLeft = new Vector2 (bounds.min.x, bounds.min.y);
raycastOrigins.bottomRight = new Vector2 (bounds.max.x, bounds.min.y);
raycastOrigins.topLeft = new Vector2 (bounds.min.x, bounds.max.y);
raycastOrigins.topRight = new Vector2 (bounds.max.x, bounds.max.y);
}
// -------------------------------------------------------------------------------------
//Calculating the spacing between horizontal and verticall rays.
//We will get the horizontal and vertical ray spacing by deviding clamped value respectively.
/// -------------------------------------------------------------------------------------
void CalculateRaySpacing()
{
Bounds bounds = collider.bounds;
//Expand the bounds by increasing its size amound along each side.
bounds.Expand (skinWidth * (-2));
horizontalRayCount = Mathf.Clamp (horizontalRayCount, 2, int.MaxValue);
verticalRayCount = Mathf.Clamp (verticalRayCount, 2, int.MaxValue);
//We can get Horizontal/vertical ray spacing by dividing oposite direction bounds size minus 1 with totalraycounts.
horizontalRaySpacing = bounds.size.y / (horizontalRayCount - 1);
verticalRaySpacing = bounds.size.x / (verticalRayCount - 1);
}
//Create a raycast struct to get rays on player from every sides and corners.
struct RaycastOrigins
{
public Vector2 topLeft, topRight;
public Vector2 bottomLeft, bottomRight;
}
///<summary>
/// -------------------------------------------------------------------------------------
/// Create a new struct for getting info of collision
/// Getting collision info from above, below, left or right side collision of player
/// -------------------------------------------------------------------------------------
/// </summary>
public struct CollisionInfo
{
public bool above, below;
public bool left, right;
public bool climbingslope;
public float slopeangle, slopeangleOld;
//Resetting all bools to false
public void Reset()
{
above = below = false;
left = right = false;
climbingslope = false;
slopeangleOld = slopeangle;
slopeangle = 0;
}
}
}
Player.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent (typeof(Controller2D))]
public class Player : MonoBehaviour {
public float jumpHeight = 4f; // Vertical height of player jump
public float timeToJumpAppex = 0.4f; // Time to reach that jump height
public float moveSpeed = 1f;
float gravity; //custom gravity for player
Vector3 velocity; //storing velocity in variable
float jumpVelocity; //Jump variable
float velocityXsmooth; // For making smooth movement in horizontal direction
Controller2D controller; // Reference of Controller2D script
float accelerationTimeToAirborne = 0.2f;
float accelerationTimetoGrounded = 0.1f;
void Start()
{
controller = GetComponent<Controller2D> ();
//-----------------------------------------------------------------
//Currently we do not have gravity so,
//Calculating gravity by using this equation 2 * jumpHeight
// gravity = --------------------------------
// (timeToJumpApex * timeToJumpApex)
//-----------------------------------------------------------------
gravity = -(2 * jumpHeight) / Mathf.Pow (timeToJumpAppex, 2);
jumpVelocity = Mathf.Abs (gravity) * timeToJumpAppex;
Debug.Log ("Gravity: " + gravity + " JumpVelocity: " + jumpVelocity);
}
void Update()
{
//Player Falling down slowlly after setting vertical velocity to zero
if (controller.collisions.above || controller.collisions.below) {
velocity.y = 0;
}
var input = new Vector2 (Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
//Making code for jump
//Player jump by pressing space key
if (Input.GetKeyDown (KeyCode.Space) && controller.collisions.below)
{
velocity.y = jumpVelocity;
}
//Getting and setting player velocity here for horizonal and vertical direction.
//Smothing movement of player at end time.
float targetVelocityX = input.x * moveSpeed * Time.deltaTime;
velocity.x = Mathf.SmoothDamp (velocity.x, targetVelocityX, ref velocityXsmooth, (controller.collisions.below) ? accelerationTimetoGrounded : accelerationTimeToAirborne); // smooth movement in X direction
velocity.y += gravity * Time.deltaTime;
controller.Move (velocity * Time.deltaTime);
}
}
`