Jump to content
Unity Insider Forum

Relative Bewegung zur Kamera, Spieler fällt sehr langsam


Garzec

Recommended Posts

Hallo,

ich habe eine 3D Adventure Plattformer Steuerung gebastelt für Spiele, wie Super Mario 64, Banjo Kazooie, Sypro (PS1) etc., die alten N64 Spiele eben :)

Nun habe ich es geschafft, dass sich der Spieler relativ zur Kamera bewegt. So wie es sein soll... Nun fällt dieser aber sehr langsam und kann zudem nicht mehr springen.

Hier mal mein Code:

public class PlayerMovementData : PlayerCommonData
{
    public float MovementSpeed { get { return 25; } }

    public float InputHorizontal { get { return Input.GetAxis("Horizontal"); } }

    public float InputVertical { get { return Input.GetAxis("Vertical"); } }

    public Vector3 MovementDirection { get; set; }

    public bool IsGrounded { get; set; }

    public float JumpPower { get { return 1; } }

    public float Gravity { get { return 3; } }

    public float VerticalVelocity { get; set; }

    public float DistanceToGround { get; set; }

    public float SmoothRotation { get { return 7; } }

    public float GroundCheckSpacing { get { return 0.1f; } }
}
PlayerMovementData movementData;

    private void Start()
    {
        movementData = new PlayerMovementData();
        movementData.DistanceToGround = GetComponent<Collider>().bounds.extents.y + movementData.GroundCheckSpacing;
    }

    private void Update()
    {
         movementData.IsGrounded = Physics.Raycast(transform.position, Vector3.down, movementData.DistanceToGround);
    }

    private void FixedUpdate()
    {
        Vector3 forward = movementData.CameraObject.transform.forward;
        Vector3 right = movementData.CameraObject.transform.right;
        forward.y = 0;

        if (movementData.IsGrounded)
        {
            movementData.VerticalVelocity = -movementData.Gravity * Time.deltaTime;
            if (Input.GetButtonDown("Jump"))
                movementData.VerticalVelocity = movementData.JumpPower;
        }
        else
            movementData.VerticalVelocity -= movementData.Gravity * Time.deltaTime;

        movementData.MovementDirection = new Vector3(movementData.InputHorizontal, movementData.VerticalVelocity, movementData.InputVertical);
        movementData.MovementDirection = forward.normalized * movementData.MovementDirection.z + right.normalized * movementData.MovementDirection.x;

        if (movementData.MovementDirection.magnitude != 0)
            transform.rotation = Quaternion.LookRotation(transform.forward + new Vector3(movementData.MovementDirection.x, 0, movementData.MovementDirection.z) * movementData.SmoothRotation);

        movementData.PlayerRigid.velocity = movementData.MovementDirection * movementData.MovementSpeed;
    }

Ich bin mir nicht ganz sicher, WAS genau 

Vector3 forward = movementData.CameraObject.transform.forward;

speichert, daher konnte ich noch keine passende Bezeichnung finden.

Kommentiere ich 

movementData.MovementDirection = forward.normalized * movementData.MovementDirection.z + right.normalized * movementData.MovementDirection.x;

aus, fällt er wieder ganz normal, kann aber immer noch nicht springen. 

Ebenfalls vermute ich einen Fehler beim Anfang des FixedUpdates, wo ich schreibe 

forward.y = 0;

Hat jemand eine Idee?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn ich die Klasse wie folgt aufbaue, funktionierts

public class PlayerMovementController : PlayerCommonController
{
    PlayerMovementData movementData;

    private void Start()
    {
        movementData = new PlayerMovementData();
        movementData.DistanceToGround = GetComponent<Collider>().bounds.extents.y + movementData.GroundCheckSpacing;
    }

    private void Update()
    {
         movementData.IsGrounded = Physics.Raycast(transform.position, Vector3.down, movementData.DistanceToGround);

        if (movementData.IsGrounded)
        {
            movementData.VerticalVelocity = -movementData.Gravity * Time.deltaTime;
            if (Input.GetButtonDown("Jump"))
                movementData.VerticalVelocity = movementData.JumpPower;
        }
        else
            movementData.VerticalVelocity -= movementData.Gravity * Time.deltaTime;
    }

    private void FixedUpdate()
    {
        Vector3 forward = movementData.CameraObject.transform.forward;
        Vector3 right = movementData.CameraObject.transform.right;
        forward.y = 0;

        movementData.MovementDirection = new Vector3(movementData.InputHorizontal, movementData.VerticalVelocity, movementData.InputVertical);
        movementData.MovementDirection = forward.normalized * movementData.MovementDirection.z + right.normalized * movementData.MovementDirection.x;
        movementData.MovementDirection = new Vector3(movementData.MovementDirection.x, movementData.VerticalVelocity, movementData.MovementDirection.z);

        if (movementData.MovementDirection.magnitude != 0)
            transform.rotation = Quaternion.LookRotation(transform.forward + new Vector3(movementData.MovementDirection.x, 0, movementData.MovementDirection.z) * movementData.SmoothRotation);

        movementData.PlayerRigid.velocity = movementData.MovementDirection * movementData.MovementSpeed;
    }
}

Was mir aber gar nicht daran gefällt, sind diese 3 Zeilen

        movementData.MovementDirection = new Vector3(movementData.InputHorizontal, movementData.VerticalVelocity, movementData.InputVertical);
        movementData.MovementDirection = forward.normalized * movementData.MovementDirection.z + right.normalized * movementData.MovementDirection.x;
        movementData.MovementDirection = new Vector3(movementData.MovementDirection.x, movementData.VerticalVelocity, movementData.MovementDirection.z);

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

vor 7 Stunden schrieb Garzec:

Ich bin mir nicht ganz sicher, WAS genau 


Vector3 forward = movementData.CameraObject.transform.forward;

speichert

Gar nichts! C# besitzt sogenannte "Properties", die nicht zwangsläufig etwas speichern, sondern wie Getter- oder Setter-Methoden funktionieren können.

Transform.forward ist eine solche Proprty und gibt immer den Vektor zurück, der aus Sicht des Transforms aktuell "vorne" ist. Quasi der blaue Pfeil am Objekt, wenn der Editor auf local space gestellt ist. Dreht man das Objekt, ist der Vektor bei der nächsten Abfrage entsprechend ein anderer.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke, so viel hatte ich schon in der Doku rausgefunden, wie du an meinem 2. Post siehst, finde ich das Script aber mittlerweile sehr unsauber.

Also 

      movementData.MovementDirection = new Vector3(movementData.InputHorizontal, movementData.VerticalVelocity, movementData.InputVertical);
        movementData.MovementDirection = forward.normalized * movementData.MovementDirection.z + right.normalized * movementData.MovementDirection.x;
        movementData.MovementDirection = new Vector3(movementData.MovementDirection.x, movementData.VerticalVelocity, movementData.MovementDirection.z);

Gefällt mir gar nicht. Aber es war die Lösung der Probleme.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Du kannst schon einmal eine neue lokale Variable machen, um den Code etwas schlanker zu machen. Transform.forward usw. sind übrigens normalisierte Vektoren, .normalize ist daher nicht nötig. Dann kannst du von der lokalen Variable y noch direkt setzen, anstatt einen neuen Vektor zu erzeugen, bei dem 2/3 Komponenten gleich sind. Heraus kommt dann so etwas:

var newDirection = forward * movementData.InputVertical + right * movementData.InputHorizontal;
newDirection.y = movementData.VerticalVelocity;
movementData.MovementDirection = newDirection;

Was vielleicht noch geht ist, VerticalVelocity rauszunehmen, da der Wert in MovementDirection.y ja schon vorhanden ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

So ich habe die gesamte Klasse mal angepasst, in der Hoffnung, so hattest dus dir vorgestellt:

public class PlayerMovementController : PlayerCommonController
{
    float movementSpeed = 25;
    Vector3 movementDirection = Vector3.zero;
    bool isGrounded;
    bool canDoubleJump = false;
    float jumpPower = 15;
    float smoothRotation = 7;
    float inputHorizontal = 0;
    float inputVertical = 0;
	
    private void Update()
    {
	inputHorizontal = Input.GetAxis("Horizontal");
    	inputVertical = Input.GetAxis("Vertical");

        isGrounded = Physics.Raycast(transform.position, Vector3.down, GetComponent<Collider>().bounds.extents.y + 0.1f);

        if (isGrounded && Input.GetButtonDown("Jump"))
        {
            rigid.AddForce(Vector3.up * jumpPower);
            canDoubleJump = true;
        }
        else if (!isGrounded && canDoubleJump && Input.GetButtonDown("Jump"))
        {
            rigid.AddForce(Vector3.up * jumpPower);
            canDoubleJump = false;
        }
    }

    private void FixedUpdate()
    {
        Vector3 forward = CameraObject.transform.forward;
        Vector3 right = CameraObject.transform.right;
        forward.y = 0;

        Vector3 newDirection = forward * inputVertical + right * inputHorizontal;
        newDirection.y = rigid.velocity.y;
        movementDirection = newDirection;

        if (movementDirection.magnitude != 0)
            transform.rotation = Quaternion.LookRotation(transform.forward + new Vector3(movementData.MovementDirection.x, 0, movementData.MovementDirection.z) * smoothRotation);

        rigid.velocity = movementDirection * movementSpeed;
    }
}

Jetzt sieht der Code schonmal schlanker aus, es treten aber immer noch Probleme durch die Sprungmechanik auf. Nun fällt die Figur extrem schnell auf den Boden, ebenso springt sie extrem schnell hoch, im Inspektor taucht auch eine Warnung auf. Ich lade mal ein Video davon hoch:

2017-03-19 21-14-45.flv

Bzw. hier als Link, falls man sich das Video nicht runterladen möchte

https://sendvid.com/c1hvs2sh

Link zu diesem Kommentar
Auf anderen Seiten teilen

Du weißt, dass mehrere oder keine Updates zwischen zwei FixedUpdates liegen können, oder? Darum solltest du AddForce nicht in FixedUpdate ausführen.

Außerdem würde ich niemals AddForce für Sprünge und ähnliche Impulse nehmen. Die vertikale Geschwindigkeit eines Rigidbodys kann je nach Situation mehr oder weniger hoch sein und AddForce addiert da etwas drauf - da kommt entsprechend mal mehr, mal weniger heraus. Darum setze ich immer die Y-Komponente der velocity direkt auf den Sprung-Geschwindigkeits-Wert.

Ansonsten: Wenn du glaubst, die Warnung ist relevant, dann solltest du sie auch posten ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Morgen, 

jap, das weiß ich, da du aber darauf hingewiesen hattest, AddForce eh nicht für Sprünge zu verwenden, habe ich das Ganze mal zurückgebaut, mit VerticalVelocity.

 private void Start()
    {
        movementData = new PlayerMovementData();
        movementData.DistanceToGround = GetComponent<Collider>().bounds.extents.y + movementData.GroundCheckSpacing;
        movementData.CanDoubleJump = false;
    }

    private void Update()
    {
        movementData.IsGrounded = Physics.Raycast(transform.position, Vector3.down, movementData.DistanceToGround);

        if (movementData.IsGrounded)
        {
            movementData.VerticalVelocity = -movementData.Gravity * Time.deltaTime;
            if (Input.GetButtonDown("Jump"))
            {
                movementData.VerticalVelocity = movementData.JumpPower;
                movementData.CanDoubleJump = true;
            } 
        }
        //else if (!movementData.IsGrounded && movementData.CanDoubleJump)
        //{
        //    movementData.VerticalVelocity = -movementData.Gravity * Time.deltaTime;
        //    if (Input.GetButtonDown("Jump"))
        //    {
        //        movementData.VerticalVelocity = movementData.JumpPower;
        //        movementData.CanDoubleJump = false;
        //    }
        //}
        else
        {
            movementData.VerticalVelocity -= movementData.Gravity * Time.deltaTime;
        }
    }

    private void FixedUpdate()
    {
        Vector3 forward = movementData.CameraObject.transform.forward;
        Vector3 right = movementData.CameraObject.transform.right;
        forward.y = 0;

        Vector3 newDirection = forward * movementData.InputVertical + right * movementData.InputHorizontal;
        newDirection.y = movementData.VerticalVelocity;
        movementData.MovementDirection = newDirection;

        if (movementData.MovementDirection.magnitude != 0)
            transform.rotation = Quaternion.LookRotation(transform.forward + new Vector3(movementData.MovementDirection.x, 0, movementData.MovementDirection.z) * movementData.SmoothRotation);

        movementData.PlayerRigid.velocity = movementData.MovementDirection * movementData.MovementSpeed;
    }

So funktioniert es bei mir problemlos. VerticalVelocity wird unten dann nur noch hier gesetzt

newDirection.y = movementData.VerticalVelocity;

Ich versuche noch den auskommentierten Doppelsprung ordentlich reinzubringen und dann hoffe ich, dass es klappt :) 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...