【发布时间】:2021-12-09 18:03:19
【问题描述】:
我有一个脚本可以检测玩家何时触摸名为“Ground”的图层,它运行良好,但我的问题是当我使用允许我跳过平台的“Platform Effector 2D”时。所以,当我的角色通过平台时,我的布尔“isGrounded”为真,但他实际上不在地面,发生的情况是我用来检查的点是与地面层的对象“碰撞” .
我觉得我解释的不是很好,所以我在 Youtube 上上传了一个未列出的视频来展示
www.youtube.com/watch?v=EQpF4iSNC0Yt
这是代码
[Header("Components")]
[HideInInspector]public Rigidbody2D _rb;
[Header("Layer Masks")]
[SerializeField] private LayerMask groundLayer;
[Header("Movement Variables")]
[SerializeField] private float _movementAcceleration;
[SerializeField] private float _maxMoveSpeed;
[SerializeField] private float _linearDrag;
[SerializeField] private float dashPower;
private float horizontalDirection;
private bool changingDirection => (_rb.velocity.x > 0f && horizontalDirection < 0f) || (_rb.velocity.x < 0f && horizontalDirection > 0f);
public bool isFalling => _rb.velocity.y < 0.0f;
private bool isRunning => horizontalDirection != 0;
[Header("Jump Variables")]
[SerializeField] private float jumpForce = 12f;
[SerializeField] private float airLinearDrag = 2.5f;
[SerializeField] private float fallMultiplier = 8f;
[SerializeField] private float lowJumpFallMultiplier = 5f;
private bool canJump => Input.GetButtonDown("Jump") && isGround;
[Header("Ground Colission Variables")]
[SerializeField] private float groundRayCastLenght;
private bool isGround;
private bool jumped;
private bool facinRight = true;
private Animator animator;
private SpriteRenderer sprite;
GameController controller;
public Transform groundCheck ;
public bool canPassThrough = false;
void Start()
{
sprite = GetComponent<SpriteRenderer>();
animator = GetComponent<Animator>();
_rb = GetComponent<Rigidbody2D>();
controller = FindObjectOfType<GameController>();
}
// Update is called once per frame
void Update()
{
Debug.Log(_rb.velocity.y);
isGround = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
horizontalDirection = GetInput().x;
if(canJump && !controller.gamePaused){
Jump();
}
if(Input.GetKeyDown(KeyCode.LeftShift)){
ApplyDash();
}
setAnimations();
}
void FixedUpdate()
{
//CheckCollisions();
if(!controller.gamePaused){
//checkDirection();
MoveCharacter();
}
if(isGround){
jumped = false;
ApplyLinearDrag();
}else{
ApplyAirLinearDrag();
FallMultiplier();
}
}
private Vector2 GetInput()
{
return new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
}
private void MoveCharacter(){
if(horizontalDirection < 0 && facinRight || horizontalDirection > 0 && !facinRight){
checkDirection();
}
Vector3 v = _rb.velocity;
_rb.AddForce(new Vector2(horizontalDirection* _movementAcceleration, 0f) );
if(Mathf.Abs(_rb.velocity.x) > _maxMoveSpeed){
v.x = Mathf.Sign(_rb.velocity.x) * _maxMoveSpeed;
_rb.velocity = v;
//_rb.velocity = new Vector2(Mathf.Sign(_rb.velocity.x) * _maxMoveSpeed, _rb.velocity.y );
}
}
private void CheckCollisions(){
isGround = Physics2D.Raycast(transform.position * groundRayCastLenght, Vector2.down, groundRayCastLenght, groundLayer);
}
private void ApplyLinearDrag(){
if(Mathf.Abs(horizontalDirection) < 0.4f || changingDirection){
_rb.drag = _linearDrag;
}else{
_rb.drag = 0f;
}
}
private void ApplyDash(){
_rb.AddForce(new Vector2(horizontalDirection * dashPower, _rb.velocity.y));
}
void ApplyAirLinearDrag(){
_rb.drag = airLinearDrag;
}
void Jump(){
jumped = true;
if(horizontalDirection != 0){
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
_rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
}else{
_rb.velocity = new Vector2(_rb.velocity.x, 0f);
_rb.AddForce(Vector2.up * jumpForce * 2f, ForceMode2D.Impulse);
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.green;
Gizmos.DrawLine(transform.position, transform.position + Vector3.down * groundRayCastLenght);
}
void FallMultiplier(){
if(_rb.velocity.y < 0){
_rb.gravityScale = fallMultiplier;
}else if(_rb.velocity.y > 0 && !Input.GetButtonDown("Jump")){
_rb.gravityScale = lowJumpFallMultiplier;
}else{
_rb.gravityScale = 1f;
}
}
void setAnimations(){
animator.SetBool("Run", isRunning && isGround);
animator.SetBool("isGround", isGround);
animator.SetBool("Jump", jumped);
animator.SetBool("isFalling", isFalling);
animator.SetFloat("eixoY", Mathf.Abs(_rb.velocity.y));
}
void checkDirection(){
facinRight = !facinRight;
transform.localScale = new Vector3( - transform.localScale.x, transform.localScale.y, transform.localScale.z);
}
void OnCollisionEnter2D(Collision2D other)
{
if(LayerMask.LayerToName(other.gameObject.layer) == "Ground") //check layer is ground
{
if (gameObject.GetComponent<Rigidbody2D>().velocity.y <= 0) //check velocity.y is 0
{
Debug.Log("in ground"); //debug console
canPassThrough = false;
}else{
Debug.Log("Not in ground");
canPassThrough = true;
}
}
}
【问题讨论】:
-
您是否还要在您的条件中添加对仅在角色处于跳跃状态时才为真的指示的依赖?因为实际上他正在接触地面,但既然你想让用户跳过一个平台,那么显然有一个案例需要更多关注。另外,您能否在问题中提供最少的代码和场景设置详细信息,以便我们进一步提供帮助。
-
我贴出了播放器代码
-
如何为玩家跳跃添加其他条件?因为当玩家在地面上时我设置为 false,但是当玩家通过平台时,变量 isground 检测到他在地面上,而实际上他不是
-
我认为你会从学习状态和状态机中受益。不需要包含所有内容的大型状态机,将状态机分解为重要的相关组件会有所帮助。有这么多结果。如果您有兴趣,Mit 有点冗长。但是您可能还可以找到其他更简单的方法。
-
依赖过多的
bools 可能会导致许多边缘情况和错误以及(远远超过需要的)代码分支。如果您在阅读状态机后有任何困难,或者只是不知道如何应用它 lmk,我可以进一步解释。
标签: c# unity3d game-development