Jump to content
Unity Insider Forum

Aufheben-Script und das Kollidieren mit einem aufgehobenem "Item"


Recommended Posts

Hey Leute,

ich hab mich hier mal neu ins Forum gewimmelt, weil ich mit einem Problem nicht zurecht komme.
Ich auf nem simplen Rigidbody First Person Controller meinen Aufheben-Script attached.
Er bewirkt, dass man, sobald man ein Objekt aufhebt, es an den Spieler geparented wird und keine Gravitation hat.

Nun, wenn das aufgehobene Objekt kollidiert, will ich diese komischen Rotationen und Repositionings beseitigen.
Bitte das Video dazu gucken: https://drive.google.com/file/d/10Iu1vvYafrub2zajdAjT2-RE88Jre_Nu/view?usp=sharing

Ich hab schon ma probiert, die Position und Rotation zu speichern, bevor das Objekt kollidiert, und dann in einem FixedUpdate()
die Position dauernd zurückzusetzen.

Allerdings muss mein Script wieder erkennen, wenn "der Spieler wieder nach oben guckt", wenn ihr versteht was ich meine.

Danke für Eure wertvolle Zeit!

LG

Link to post
Share on other sites

Moin!

Du schaltest von dem Item also nur die Gavitiation aus? Warum nicht den ganzen Rigidbody samt Collider? Einfach komplett aus der Gleichung rausnehmen.

Link to post
Share on other sites

Hallo,

erstmal vielen Dank für die Antwort.
Und ja theoretisch könnte ich das machen, allerdings wollte ich, wie unnötig das auch klingen mag, etwas komplexeres ausprobieren.
In meinem Fall wird das aufgehobene Item wieder losgelassen wenn der User die Maustaste loslässt oder das Crosshair nicht mehr auf dem Objekt ist. [Das passiert bei Objektkollisionen]

Ich hab mir in der Zwischenzeit aber noch Gedanken dazu gemacht..
Bei einer Kollision muss ich wissen, welche "Kante" kollidiert ist, um die entsprechende Positionierung und Rotation auf den entsprechenden Axen zu freezen.
Wichtig bei mir ist auch, dass das bei nem Mesh Collider funktioniert, denn bei meinem Projekt habe ich auch sämtliche Props, die komplexere Meshes zur Collision Detection hervorziehen.

 

LG
 

Link to post
Share on other sites

Wenn das Objekt den Collider behalten soll, kannst du mit Physics.IgnoreCollision die Kollision mit dem Spieler ausschalten. Layer-basiertes Ignorieren ginge auch, ist aber so eine Sache, den Player und das Objekt deswegen extra auf dafür vorgesehene Layer zu packen.

Link to post
Share on other sites

Ok, aber das Problem was ich grade lösen wollte ist, dass das Objekt, wenn es z. B. auf den Boden kollidiert, und der Spieler weiter nach unten guckt, nicht die "komischen" Rotationen entstehen. [das Video veranschaulicht das etwas besser].
Die Rotationen entstehen ja, weil das aufgehobene Item ein Child von der Camera ist und die Rotation dann entsprechend angepasst wird, auch wenn das Objekt kollidiert.

Link to post
Share on other sites

Okay hier mein Script zum Aufheben (bisschen lang, denn da ist noch so was wie Werfmechanik und weiteres drinne):

 

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

public class PlayerPickUp : MonoBehaviour
{

    [Header("Script functionalities")]
    [SerializeField] Transform cam;
    [SerializeField] float playerWidth = 1f;

    [Header("Pick up system")]
    [SerializeField] float range = 5f;
    [SerializeField] bool enableThrowing = true;
    [SerializeField] float throwForce = 5f;
    [SerializeField] float throwCompression = 2f;

    [Header("Advanced holding options")]
    [SerializeField] bool enableLeaveCrosshairDrop = true;
    [SerializeField] bool enableOutOfRangeDrop = true;

    float fire1;
    float fire2;
    float fire1_before;
    float fire2_before;

    Transform virtualObj;

    // Start is called before the first frame update
    void Start()
    {

    }

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

    void InitializeInput()
    {
        fire1 = Input.GetAxisRaw("Fire1");
        fire2 = Input.GetAxisRaw("Fire2");
    }

    void FixedUpdate()
    {
        PickupAndDrop();
        InCaseDrop();
        CustomObjCorrection();
        Throwing();

        fire1_before = fire1;
        fire2_before = fire2;

    }

    void PickupAndDrop()
    {

        if (fire1 != fire1_before && fire2 <= 0)
        {

            if (fire1 >= 1)
            {
                ItemIdentifier ident = (ItemIdentifier)StaticFunctions.forwardRay(typeof(ItemIdentifier), cam, playerWidth, range);
                if (ident != null)
                {
                    if (ident.isProp)
                    {
                        holdingObj = ident.transform;
                    }
                }
            }

            else
            {
                holdingObj = null;
            }

        }
    }

    void InCaseDrop()
    {
        if (holdingObj != null)
        {

            if (enableLeaveCrosshairDrop)
            {

                float usedRange = enableOutOfRangeDrop ? range : Mathf.Infinity;
                if ((Transform)StaticFunctions.forwardRay(typeof(Transform), cam, playerWidth, usedRange) != holdingObj)
                {
                    holdingObj = null;
                }

            }

            if (enableOutOfRangeDrop && holdingObj != null)
            {

                float distance = Vector3.Distance(cam.position + cam.forward * playerWidth / 2, holdingObj.position);
                if (distance > range)
                {
                    holdingObj = null;
                }
            }

        }


    }

    void CustomObjCorrection()
    {

        if (holdingObj != null)
        {
            holdingObj.GetComponent<Rigidbody>().velocity = Vector3.zero;
            holdingObj.GetComponent<Rigidbody>().angularVelocity = Vector3.zero;
        }
    }

    void Throwing()
    {
        if (fire2 != fire2_before && enableThrowing)
        {
            if (fire2 >= 1 && fire1 >= 1)
            {
                holdingObj.GetComponent<Rigidbody>().AddForce(cam.forward * throwForce + Vector3.up * throwCompression, ForceMode.Impulse);
                holdingObj = null;
            }
        }
    }

    Transform _holdingObj = null;
    Transform holdingObj
    {
        get
        {
            return _holdingObj;
        }

        set
        {
            
            if (_holdingObj != null)
            {
                _holdingObj.GetComponent<Rigidbody>().useGravity = true;
                _holdingObj.GetComponent<Rigidbody>().freezeRotation = false;
                _holdingObj.parent = null;
            }

            _holdingObj = value;

            if (_holdingObj != null)
            {
                _holdingObj.GetComponent<Rigidbody>().useGravity = false;
                _holdingObj.GetComponent<Rigidbody>().freezeRotation = true;
                _holdingObj.parent = cam;
            }
        }
    }

}

Bei diesen StaticFunctions Dingern handelt es sich noch um eine statische Klasse, mit der ich von mir vordefinierte "Raycast-Presets" benutzen kann.
 

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

public static class StaticFunctions
{

    public static object forwardRay(System.Type t, Transform origin, float originWidth, float range = Mathf.Infinity)
    {

        RaycastHit hit;

        bool hasHit;
        if (range != Mathf.Infinity)
        {
            hasHit = Physics.Raycast(origin.position + origin.forward * originWidth / 2, origin.forward, out hit, range);
        }
        else
        {
            hasHit = Physics.Raycast(origin.position + origin.forward * originWidth / 2, origin.forward, out hit);
        }
        
        if (t == typeof(bool))
        {
            return hasHit;
        }
        else if (hasHit)
        {

            if (t == typeof(RaycastHit))
            {
                return hit;
            }
            if (t == typeof(Transform))
            {
                return hit.collider.transform;
            }
            else if (t == typeof(ItemIdentifier))
            {
                return hit.collider.GetComponentInParent<ItemIdentifier>();
            }

        }

        return null;

    }

    public static RaycastHit[] forwardRayAll(Transform origin, float originWidth, float range = Mathf.Infinity)
    {

        Vector3 rayStart = origin.position + origin.forward * originWidth / 2;

        if (range != Mathf.Infinity)
        {
            return Physics.RaycastAll(rayStart, origin.forward, range);
        }
        else
        {
            return Physics.RaycastAll(rayStart, origin.forward);
        }

    }

    public static RaycastHit[] raysSortByDistance(RaycastHit[] src)
    {

        List<RaycastHit> srcList = new List<RaycastHit>(src);
        float[] distances = new float[srcList.Count];

        for (int i = 0; i < srcList.Count; i++)
        {
            distances[i] = srcList[i].distance;
        }

        System.Array.Sort(distances);

        List<RaycastHit> sortedList = new List<RaycastHit>();
        List<int> usedHitsIndices = new List<int>();

        for (int i = 0; i < distances.Length; i++)
        {
            for (int ii = 0; ii < srcList.Count; ii++)
            {

                if (distances[i] == srcList[ii].distance && !usedHitsIndices.Contains(ii))
                {
                    sortedList.Add(srcList[ii]);
                    usedHitsIndices.Add(ii);
                    continue;
                }

            }

        }

        return sortedList.ToArray();

    }

}



 

Link to post
Share on other sites

Um den ganzen Kram einfach kurz zu fassen:

Wenn ich ein Objekt aufhebe dann mache ich drei Sachen:

  • Ich schalte die Rigidbody Gravitation des Objekts aus
  • Ich schalte die Rigidbody Freeze Rotation des Objekts auf an
  • Ich setze den Parent des Objekts auf meine Spielerkamera.

Wenn ich es fallen lasse, mache ich genau diese Schritte wieder rückgängig.

Ich hab da auch schon einen Ansatz wie ich das fixxen könnte.
Dazu müsste ich bei einer Kollision erfahren, welche "Kante" des Objekts kollidiert ist, und dessen Position auslesen können.
Ich schau nochmal im Web nach, ob ich dazu was finde-

Nicht wundern, programmieren tu ich schon bisschen länger, in Unity noch nicht so lang, deshalb diese Fragen.

LG

Link to post
Share on other sites

Kurzes Update, ich bin jetzt auf collision.contacts gestoßen, damit kann ich feststellen, wo die Kollision stattgefunden hat.

Dann kann ich herausfinden, welche Positions -und Rotationsachsen ich einfrieren muss.

Ich gebe noch ein Update, sollte ich es hingekriegt haben oder warum nicht.

  • Like 1
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
×
×
  • Create New...