Jump to content
Unity Insider Forum

Gleiches Script und unterschiedliches Verhalten


AstroHelsi

Recommended Posts

Hallo leute ich bin neu hier im Forum :)

Ich habe ein Problem, welches mich hier zum verzweifeln bringt.

Ich habe ein Script erstellt, dass eine Kapsel mittels Character Controller bewegen lässt. Jetzt habe ich Gravitation hinzugefügt und alles klappt soweit ganz gut.

Das Script funktioniert jedoch NUR auf dieser Kapsel :D Wenn ich das gleiche Script auf ein anderes Objekt, wie z.B. einen Würfel packe, funktioniert es nicht mehr. Ich habe dem Würfel natürlich den Character Controller hinzugefügt und jegliche Parameter der Kapsel übernommen.

Die Kapsel fällt normal (langsam) runter. Der Würfel jedoch schießt nach unten. Wenn er auf dem Ground steht, läd sich die Gravitation auf. Er wird somit schneller beim Fall.

 

Weis jemand woran es liegt?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TEST : MonoBehaviour
{
    // Variablen

    private CharacterController controller;
    
    
    
    [SerializeField] private float movespeed = 0f;
    [SerializeField] private float walkspeed = 3f;
    [SerializeField] private float runspeed = 4f;

    [SerializeField] private bool isgrounded;
    [SerializeField] private float groundcheckdistance;
    [SerializeField] private LayerMask groundmask;
    [SerializeField] private float gravity;
    private Vector3 velocity;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {
        move();
    }

    void move()
    {

        isgrounded = Physics.CheckSphere(transform.position, groundcheckdistance, groundmask);

        if (isgrounded && velocity.y < 0)
        {
            velocity.y = 2f;
        }

        float zdir = Input.GetAxis("Horizontal");
        Vector3 movedirection = new Vector3(0, 0, zdir);

        if (movedirection != Vector3.zero && !Input.GetKey(KeyCode.LeftShift))
            {
            // WALK
            movespeed = walkspeed;
            }
        else if (movedirection != Vector3.zero && Input.GetKey(KeyCode.LeftShift))
            {
            // RUN
            movespeed = runspeed;
            }
        else if (movedirection == Vector3.zero)
            {
            // IDLE
            }
        controller.Move(movedirection * movespeed * Time.deltaTime);
        velocity.y += gravity * Time.deltaTime;
        controller.Move(velocity * Time.deltaTime);
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Moin!

Wenn du von Würfel und Kapsel redest, redest du dann von GameObjects mit entsprechendem Renderer... und Collider? Wenn ja, dann solltest du dringend den die jeweiligen Collider löschen, weil der CharacterController mit ihnen kollidiert. Dass die zum selben GameObject gehören (oder einander untergeordnet sind) ist dem CharacterController nämlich egal.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Nein der Ground-Check hat problemlos funktioniert. Ich habe das jetzt auch tatsächlich mit isGrounded gelöst, ist wirklich einfacher. Jetzt klappt der Sprung auch super. Wenn ich jedoch von unten an ein Objekt ranspringe, dann bleibt er daran kurz hängen und fällt dann runter. Mich interessiert es, wie man an ein solches Problem in Unity herangeht? Ich habe an einen Raycast gedacht, der prüft, ob eine Kolission über dem Spieler stattfindet. Gibt es da auch eine einfachere Variante? Oder wie gehen die Pros mit so einem Verhalten um ? Die Gravitation hab ich in der neuen Steuerung in einem Vektor gelöst und diese dann auf den movedirection Vektor addiert. Mir ist die Vorgehensweise noch nicht klar.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharController : MonoBehaviour
{
    // Variablen

    private CharacterController controller;
      
    [SerializeField] private float movespeed = 0f;
    [SerializeField] private float walkspeed = 3f;
    [SerializeField] private float runspeed = 4f;
    [SerializeField] private float jumpheight = 12f;



    public float gravity;
    private float currentGravity = 0f;

    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {

    
    

        float zdir = Input.GetAxis("Horizontal");
        Vector3 movedirection = new Vector3(0, 0, zdir);



        if (movedirection != Vector3.zero && !Input.GetKey(KeyCode.LeftShift))
        {
            // WALK
            movespeed = walkspeed;
        }
        else if (movedirection != Vector3.zero && Input.GetKey(KeyCode.LeftShift))
        {
            // RUN
            movespeed = runspeed;
        }
        else if (movedirection == Vector3.zero)
        {
            // IDLE
        }

        if (controller.isGrounded && Input.GetKeyDown(KeyCode.Space))
        {
            // JUMP
            currentGravity *= -jumpheight;
        }
        movedirection *= movespeed;

        Vector3 finalmovement = movedirection + ApplyGravity();
        controller.Move(finalmovement * Time.deltaTime);


    }


    Vector3 ApplyGravity()
    {
        Vector3 gravityMovement = new Vector3(0, -currentGravity, 0);
        currentGravity += gravity * Time.deltaTime;

        if (controller.isGrounded)
        {
            if (currentGravity > 1f)
                currentGravity = 1f;
        }

        return gravityMovement;
    }
} 

 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Da gibt's nicht "die eine Lösung", aber ich mache das ganz gerne über einen Abgleich der neuen mit der alten Position.

Voraussetzung ist, dass du deinen Geschwindigkeitsvektor in einem Feld aufbewahrst, statt ihn in jedem Frame neu anzulegen. Also statt currentGravity direkt den gesamten Bewegungsvektor speichern.

var previousPosition = transform.position;
controller.Move(velocity * Time.deltaTime);
velocity = (transform.position - previousPosition) / Time.deltaTime;

Hiermit wird jedwede Veränderung der Geschwindigkeit, die durch eine Kollision passiert, auf den velocity-Wert angewendet, der im nächsten Frame als Basis für die neue Geschwindigkeitsberechnung ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Danke für deine Hilfe. Ich hab es jetzt gelöst. Bin anders vorgegangen. Es gibt mit Sicherheit schönere, elegantere und logischere Art und Weisen das zu lösen aber so funktioniert es auch ganz gut:D

Ich habe die Kollision mittels CollisionFlags.Above abgefragt. In der If Abfrage habe ich den Wert 0.8 festgelegt. Ich bin nicht logisch auf die 0.8 gekommen, sondern habe paar Werte probiert. Was sagst du dazu ?

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharController : MonoBehaviour
{
    // Variablen

    private CharacterController controller;
      
    [SerializeField] private float movespeed = 0f;
    [SerializeField] private float walkspeed = 3f;
    [SerializeField] private float runspeed = 4f;
    [SerializeField] private float jumpheight = 4f;
    [SerializeField] private float ydir;
    [SerializeField] private float gravity = 9.81f;




    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {



        
        float zdir = Input.GetAxis("Horizontal");
        Vector3 movedirection = new Vector3(0, 0, zdir);



        if (movedirection != Vector3.zero && !Input.GetKey(KeyCode.LeftShift))
        {
            // WALK
            movespeed = walkspeed;
            
        }
        else if (movedirection != Vector3.zero && Input.GetKey(KeyCode.LeftShift))
        {
            // RUN
            movespeed = runspeed;
        }
        else if (movedirection == Vector3.zero)
        {
            // IDLE
        }


        if (controller.isGrounded && Input.GetKey(KeyCode.Space))
        {
            ydir = jumpheight;
      
        }
        else if (controller.isGrounded==true)
        {
            ydir = 0;
        }
        else if (controller.collisionFlags == CollisionFlags.Above)
        {
            ydir = -0.8f;
        }

        ydir -= gravity * Time.deltaTime;
            movedirection.y = ydir;
  



     


        movedirection *= movespeed;
        Vector3 finalmovement = movedirection;
        controller.Move(finalmovement * Time.deltaTime);
        

    }


} 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Woran hapert's denn? Hier hast du ein Grundgerüst, das du erweitern kannst:

using UnityEngine;

[RequireComponent(typeof(CharacterController))]
public class PlayerMovement : MonoBehaviour
{
  private CharacterController characterController;
  private Vector3 velocity;

  private void Awake()
  {
    characterController = Getcomponent<CharacterController>();
  }
  
  private void FixedUpdate()
  {
    // Update velocity here however you want
    
    var previousPosition = transform.position;
    characterController.Move(velocity * Time.deltaTime);
    velocity = (transform.position - previousPosition) / Time.deltaTime;
  }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich weis es leider auch nicht. Ich habe die gespeichert und danach von der aktuellen die alte abgezogen 😕  Ich mache hier irgendwo einen groben Fehler. Habe jetzt die Jump und Move actionen für den Post rausgenommen aus dem Script.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CharController : MonoBehaviour
{
    // Variablen

    private CharacterController controller;
      
    [SerializeField] private float movespeed = 0f;
    [SerializeField] private float walkspeed = 3f;
    [SerializeField] private float runspeed = 4f;
    [SerializeField] private float jumpheight = 4f;
    [SerializeField] private float ydir;
    [SerializeField] private float gravity = 9.81f;
    [SerializeField] private float xdir;
    private float velocity;
    private Vector3 altepos;





    void Start()
    {
        controller = GetComponent<CharacterController>();
    }

    // Update is called once per frame
    void Update()
    {




        float zdir = Input.GetAxis("Horizontal");
        Vector3 movedirection = new Vector3(0, ydir, zdir);


      ydir -= gravity * Time.deltaTime;

        altepos = transform.position;
 
        movedirection *= movespeed;
        controller.Move(movedirection * Time.deltaTime);
        movedirection = (transform.position - altepos) / Time.deltaTime;

     
    }


} 

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich verlinke Mal auf meine Antwort in einem anderen Thread:

Meine Variable "velocity" ist ein Feld, also eine Variable, die Teil des Objekts ist. Deine Variable "movedirection" ist eine lokale Variable, die aufhört zu existieren, sobald die Methode (also Update) durchgelaufen ist. Es wird daher kein Wert von diesem Update in das nächste übernommen.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ist am Ende natürlich deine Entscheidung, aber ich empfehle, da nochmal die Zähne zusammenzubeißen und das zum Laufen zu kriegen. Woran es gerade zu hängen scheint, sind Konzepte, die du sehr oft und überall brauchst. Wenn du etwas brauchst, sag Bescheid.

Aber wie gesagt, deine Entscheidung ;)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Habe es jetzt noch Mal probiert. movedirection (bei deinem Script velocity) ist nicht mehr lokal. Die alte Position wird im Vektor3 "altepos" gespeichert.  Das Sprungverhalten hat sich geändert und ich bleibe weiterhin an der Decke hängen.  Ich scheine bei diesem Script nicht nur an der Decke zu hängen 😕

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class NewBehaviourScript : MonoBehaviour
{
    
    private Vector3 altepos;
    private Vector3 movedirection;
    private float zdir;
    private float ydir;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        	// Bewegungsvektor
	        zdir = Input.GetAxis("Horizontal");
            ydir -= gravity * Time.deltaTime;
            movedirection = new Vector3(0, ydir, zdir * movespeed);

        	altepos = transform.position;
        	controller.Move(movedirection * Time.deltaTime);
        	movedirection = (transform.position - altepos) / Time.deltaTime;

    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...