Jump to content
Unity Insider Forum

Rigidbody2D Kreis mit Touch in die richtige Richtung drehen (AddTorque)


Recommended Posts

Hi,

seit gestern zerbreche ich mir den Kopf darüber, wie ich ein Sprite (in dem Fall einen Kreis) mittels Touch.move in die richtige Richtung drehen kann. Hier mal eine Zeichnung wie das gemeint ist:

kreiss_drehen_touch.thumb.png.7e0e3bac9b17fdebcd2e055f6ab6a21f.png

Fall 1-4 habe ich mehr oder weniger hinbekommen. Ich habe den Bildschirm einfach in 4 Sektionen unterteilt und prüfe bei Touch.began wo ich anfange. Bei Touch.ended prüfe ich den direction Vector2, was größer war, X oder Y um zu erfahren, ob ich quer oder längs gewischt habe und daraus kann ich dann entscheiden, wie der Kreis sich drehen sollte. Wenn ich nun aber wie in Bild 5 z.B. von oben rechts nach unten Links wischt und eigentlich mehr nach links als rechts, Y aber länger ist, dreht sich der Kreis im Uhrzeigersinn anstatt gegen den Uhrzeigersinn.

Soweit verständlich? Ich habe nun schon einige Spiele gesehen wo man ein Sprite mit dem Finger so drehen kann, wie es normal wäre, aber ich komme einfach nicht dahinter, wie ich dieses Lösen kann und bei Google werde ich auch nicht wirklich fündig.

Hier mal mein Code bei dem ich jedes mal ein Schmunzeln habe, da dieser wirklich nicht sauber ist:

Hier prüfe ich, wo ich auf dem Bildschirm beginne zu wischen.

switch (touch.phase)
            {
                // Record initial touch position.
                case TouchPhase.Began:
                    startPos = touch.position;
                    startTime = Time.time;
                    moveTime = 0;
                    //top left
                    if (touch.position.x < Screen.width / 2 && touch.position.y > Screen.height / 2)
                    {
                        this.touchBeganLocation = 0;
                    }
                    //top right
                    else if(touch.position.x > Screen.width / 2 && touch.position.y > Screen.height / 2)
                    {
                        this.touchBeganLocation = 1;
                    }
                    //bottom left
                    else if(touch.position.x < Screen.width / 2 && touch.position.y < Screen.height / 2)
                    {
                        this.touchBeganLocation = 2;
                    }
                    //bottom right
                    else if(touch.position.x > Screen.width / 2 && touch.position.y < Screen.height / 2)
                    {
                        this.touchBeganLocation = 3;
                    }
                    this.location.text = "Loc ID: " + this.touchBeganLocation.ToString();
                    break;

 

Hier prüfe ich die Wischrichtung und wie sich der Kreis drehen sollte. Die Funktion wird in der touch.ended aufgerufen:

void calculatePower(float force, Vector2 direction, int touchBeganLocation)
    {
        switch (touchBeganLocation)
        {
            //top left
            case 0:
                if(Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
                {
                    //horizontal
                    if(direction.x > 0)
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                }
                else
                {
                    //vertically
                    if(direction.y < 0)
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                }
                break;
            //top right
            case 1:
                if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
                {
                    //horizontal
                    if (direction.x > 0)
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                }
                else
                {
                    //vertically
                    if (direction.y < 0)
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                }
                break;
            //bottom left
            case 2:
                if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
                {
                    //horizontal
                    if (direction.x > 0)
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                }
                else
                {
                    //vertically
                    if (direction.y < 0)
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                }
                break;
            //bottom right
            case 3:
                if (Mathf.Abs(direction.x) > Mathf.Abs(direction.y))
                {
                    //horizontal
                    if (direction.x > 0)
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                }
                else
                {
                    //vertically
                    if (direction.y < 0)
                    {
                        //cw
                        this.GetComponent<Rigidbody2D>().AddTorque(-force, ForceMode2D.Impulse);
                    }
                    else
                    {
                        //ccw
                        this.GetComponent<Rigidbody2D>().AddTorque(force, ForceMode2D.Impulse);
                    }
                }
                break;
        }
    }

Ich finde das irgendwie viel zu umständlich...oder befinde ich mich auf dem richtigen Pfad?

 

Danke für Eure Hilfe und Kritik

 

Jochen

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ich habe nun noch was anderes via Google gefunden:

(Zum Testen im Editor mit Maus) - OnMouseDrag funktioniert nun super. Das Sprite dreht sich in die gewünscht Richtung. Allerdings sollte es sich auch bei MouseUp weiterdrehen mit der Kraft, die ich durch die "Länge" und Geschwindigkeit des Swipes berechnet habe/werde...

Ich dachte ich bekomme in der DragFunction angularVelocity, dem ist aber nicht so. Wie könnte ich denn nun am besten das Rad weiterdrehen?

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

public class RotateController : MonoBehaviour {

    private float baseAngle = 0.0f;
    private float velo = 0;
    void OnMouseDown()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        pos = Input.mousePosition - pos;
        baseAngle = Mathf.Atan2(pos.y, pos.x) * Mathf.Rad2Deg;
        baseAngle -= Mathf.Atan2(transform.right.y, transform.right.x) * Mathf.Rad2Deg;
    }

    void OnMouseDrag()
    {
        Vector3 pos = Camera.main.WorldToScreenPoint(transform.position);
        pos = Input.mousePosition - pos;
        float ang = Mathf.Atan2(pos.y, pos.x) * Mathf.Rad2Deg - baseAngle;
        //transform.rotation = Quaternion.AngleAxis(ang, Vector3.forward);
        this.GetComponent<Rigidbody2D>().MoveRotation(ang);
        //this.velo = this.GetComponent<Rigidbody2D>().;
        Debug.Log("Drag: "+this.velo);
    }

    private void OnMouseUp()
    {
        Debug.Log("Up: "+this.velo);
        this.GetComponent<Rigidbody2D>().AddTorque(velo);
    }
}

 

Link zu diesem Kommentar
Auf anderen Seiten teilen

Puh, das war eine harte Nuss und ich habe "böse" getrickst:

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

public class RotateController : MonoBehaviour
{

    private Vector3 startSwipe;
    private Vector3 endSwipe;
    private Rigidbody2D rb;

    void Start()
    {
        rb = this.GetComponent<Rigidbody2D>();
    }

    void OnMouseDown()
    {
        startSwipe = Input.mousePosition;
    }

    void OnMouseDrag()
    {
        endSwipe = Input.mousePosition;
        Vector3 SwipeDirection = endSwipe - startSwipe;
        Vector3 startSwipeWP = Camera.main.ScreenToWorldPoint(new Vector3(startSwipe.x, startSwipe.y, transform.position.z - Camera.main.transform.position.z));
        Vector3 endSwipeWP = Camera.main.ScreenToWorldPoint(new Vector3(endSwipe.x, endSwipe.y, transform.position.z - Camera.main.transform.position.z));

        RaycastHit2D hit = Physics2D.Raycast(startSwipeWP, endSwipeWP - startSwipeWP);

        if (hit.collider != null)
        {
            Vector3 originalVelocity = rb.velocity;
            rb.velocity = new Vector3(0, 0, 0);
            rb.constraints = RigidbodyConstraints2D.FreezePositionX | RigidbodyConstraints2D.FreezePositionY;
            rb.AddForceAtPosition(endSwipeWP - startSwipeWP, hit.point, ForceMode2D.Impulse);
            rb.velocity = originalVelocity;
            rb.constraints = RigidbodyConstraints2D.None;
        }
        //startSwipe = Input.mousePosition;
    }
}

Der Vorteil dieser Methode ist, das die Rotation abhängig davon ist, wo die Kraft angreift, je weiter der Spieler sich an den Rand des Objekts bewegt, desto mehr Rotation wird dem Objekt hinzugefügt.
Ich habe die Kraft, die das Objekt eigentlich aus der Bahn werfen würde dabei verworfen (velocity). Die benötigte "angularVelocity" wird dabei über die "AddForceAtPosition"-Methode erzeugt. Ebenfalls könnte man den Punkt an dem die Kraft ansetzt leicht verbessern, indem man nicht "Raycast" verwendet, sondern alle Kontaktpunkte zum Collider ermittelt und daraus einen gemittelten Kraftansatzpunkt ermittelt. Aktuell setzt die Kraft einfach an der 1. getroffenen "Kante" an, die in Richtung des Swipevektors liegt. Zusätzlich kann man sich überlegen, ob man den Start des Swipevektors in der OnMouseDrag-Funktion wieder neu setzt, ich habe es mal auskommentiert (damit dreht man etwas ruhiger).
Vermutlich kann man sich das Setzen der Contraints auch schenken, da in einem Frame nix passiert.
(ps: Ich hasse die "ScreenToWorldPoint"-Methode die hat wieder unnötig viel Zeit gekostet, auch das Codebeispiel von Unity ist unbrauchbar)

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

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

×
×
  • Neu erstellen...