Die Sache ist, ich verstehe nicht, wie sie funktionieren, und meine Algorithmen haben nicht funktioniert. Wenn jemand etwas Ähnliches gemacht und erfolgreich einen Controller erstellt hat, teilen Sie mir bitte mit, wie Sie Ihren Controller implementiert haben.
Nun ein wenig darüber, wie ich versucht habe, ihn selbst zu implementieren:
1. Ich habe zwei Systeme – die Player State Machine und den „Player Motor“-Dienst. In der Zustandsmaschine rufe ich einfach die Servicemethoden auf.
Code: Select all
// Grounded state
public override void FixedTick()
{
base.FixedTick();
Vector3 inputMove = _inputReader.Move;
(Vector3 forward, Vector3 right) = _motor.GetPlayerDirs();
Vector3 desiredMove = forward * inputMove.y + right * inputMove.x;
_motor.Move(desiredMove * SPEED * Time.fixedDeltaTime);
if (!_motor.IsGrounded || _inputReader.IsJumping)
{
_stateMachine.SwitchState
();
return;
}
}
// Airborne state
public override void FixedTick()
{
base.FixedTick();
_verticalVelocity += GRAVITY * Time.fixedDeltaTime;
Vector3 inputMove = _inputReader.Move;
(Vector3 forward, Vector3 right) = _motor.GetPlayerDirs();
Vector3 offsetMove = (forward * inputMove.y + right * inputMove.x).normalized;
Vector3 downMove = Vector3.down;
_motor.Move(downMove * _verticalVelocity * Time.fixedDeltaTime + offsetMove * 2f * Time.fixedDeltaTime);
if (_motor.IsGrounded)
{
_stateMachine.SwitchState();
return;
}
}
Code: Select all
public void Move(Vector3 desiredMove)
{
CheckGround();
Vector3 position = _playerRigidbody.position;
position = MoveWithSlide(position, desiredMove);
position = SnapToGround(position);
_playerRigidbody.MovePosition(position);
}
Code: Select all
private void CheckGround()
{
float halfHeight = _playerCollider.height * 0.5f;
float radius = _playerCollider.radius;
float dist = halfHeight - radius + PROBE_DOWN;
Vector3 center = _playerCollider.transform.TransformPoint(_playerCollider.center);
Ray sphereRay = new Ray(center, Vector3.down);
bool isSupported = Physics.SphereCast(sphereRay, radius, dist,
_worldMask, QTI);
_isGrounded = isSupported;
}
Code: Select all
private Vector3 MoveWithSlide(Vector3 position, Vector3 desiredMove)
{
float desiredDist = desiredMove.magnitude;
Vector3 desiredDir = desiredMove / desiredDist;
GetCapsulePoints(position, out Vector3 p1, out Vector3 p2, out float radius);
if(!Physics.CapsuleCast(p1, p2, radius, desiredDir,
out RaycastHit hit,
desiredDist + SKIN,
_worldMask, QTI))
{
return position + desiredMove;
}
float travel = Mathf.Max(0f, hit.distance - SKIN);
position += desiredDir * travel;
Vector3 left = desiredMove - desiredDir * travel;
Vector3 slide;
if(CheckSlopeAngle(hit.normal))
{
slide = Vector3.ProjectOnPlane(left, hit.normal);
}
else
{
Vector3 horiz = Vector3.ProjectOnPlane(left, Vector3.up);
Vector3 wallNormal = Vector3.ProjectOnPlane(hit.normal, Vector3.up);
if (wallNormal.sqrMagnitude < EPS)
return position;
wallNormal.Normalize();
slide = Vector3.ProjectOnPlane(horiz, wallNormal);
}
float slideDist = slide.magnitude;
if (slideDist < EPS)
return position;
Vector3 slideDir = slide / slideDist;
GetCapsulePoints(position, out Vector3 sp1, out Vector3 sp2, out float sradius);
if (Physics.CapsuleCast(sp1, sp2, sradius, slideDir,
out RaycastHit shit,
slideDist + SKIN, _worldMask, QTI))
{
float md2 = Mathf.Max(0f, shit.distance - SKIN);
return position + slideDir * md2;
}
return position + slide;
}
Code: Select all
private Vector3 SnapToGround(Vector3 position)
{
GetCapsulePoints(position, out Vector3 p1, out Vector3 p2, out float radius);
if (Physics.CapsuleCast(p1, p2, radius, Vector3.down,
out RaycastHit hit,
SNAP_DOWN_DIST + SKIN,
_worldMask, QTI)
&& CheckSlopeAngle(hit.normal))
{
float down = hit.distance - SKIN;
position += Vector3.down * down;
_isGrounded = true;
}
return position;
}

Ich weiß, dass das Problem in den Besetzungen liegt. Wenn ich einen normalen Raycast machen würde, würde die Oberflächennormale korrekt zurückgegeben und die Oberflächenkollision wäre dann wie in normalen Spielen. Aber ich hatte einige Probleme, an die ich mich ehrlich gesagt nicht mehr erinnern kann (sorry, ich arbeite jetzt schon seit einer Woche an diesem Controller).
Es gab die Idee, CapsuleCast und SphereCast durch Strahlen zu ersetzen, die kreisförmig verlaufen, mit dem Radius der Spielerkapsel, nach unten, und so nach dem Normalen für die Projektion suchen. Aber ich bin mir nicht sicher, ob das eine gute Idee ist.
Mobile version