Bewegung eines Sprites



  • Hallo Community,

    ich habe ein Problem mit dem Bewegen eines Sprites mit XNA 4.0 C#.
    Wenn ich das Sprite auf einen Punkt bewege, mit einer einer gewissen Geschwindigkeit, will ich das Sprite solange bewegen, bis es ankommt. Dabei soll das Sprite sich nicht über die Position hinaus bewegen, aber auch nicht zu früh stoppen, wie in meinem Fall.
    Hier der relevante Code:

    public Queue<Vector2> Path { get; private set; }
    
    /// <summary>
    /// Update the minion and its location.
    /// </summary>
    /// <param name="gametime">Provides a snapshot of timing values.</param>
    public override void Update(GameTime gametime)
    {
        //if the minion is not at the end
        if (this.Path.Count != 0)
        {
            Vector2 waypoint = this.Path.Peek();
            this.move(gametime, waypoint);
            //if the minion reached the position, remove the position
            if (this.ReachedPoint(waypoint))
            {
                this.Path.Dequeue();
            }
        }
    }
    
    /// <summary>
    /// Return true if the minion reached a position.
    /// </summary>
    /// <param name="position">Position to be checked.</param>
    /// <returns>True if minion is in range.</returns>
    public bool ReachedPoint(Vector2 position)
    {
        //if the minion is in small range of the position
        return Vector2.Distance(this.Center, position) / this.Speed < 0.01f;
    }
    
    private void move(GameTime gametime, Vector2 position)
    {
        Vector2 direction = (position - this.Center);
        direction.Normalize();
    
        //move the minion
        this.Center += direction * this.Speed * (float)gametime.ElapsedGameTime.TotalSeconds;
    }
    

    Die Update-Funktion wird bei XNA pro Frame aufgerufen. Mein Weg des Gegners ist in einer Queue<Vector2>. Immer wenn ein Punkt erreicht wurde, Dequeue ich den letzten Punkt und lasse den Gegner zum nächsten Punkt bewegen.
    In meiner ReachedPoint Funktion prüfe ich, ob der Gegner nah an dem Punkt dran ist, da ich in move-Funktion den Wert eher springen lasse, als das er jeden Wert auf dem Weg zur Position annimmt.
    Daher kommt auch jetzt mein Problem. Durch die Rechnung in ReachedPoint kann bei einer hohen Geschwindigkeit der Gegner zu früh stoppen und erreicht den Punkt nicht ganz.
    Wenn ich allerdings sage "Wenn du nah an dem Wegpunkt bist, aber zu nah, sodass du über den Wegpunkt hinaus gehst, wird deine Position zu dem Wegpunkt" springt mir der Gegner zu sehr, wenn er kurz vor dem Punkt ist.
    Ich wäre über einen Denkansatz erfreut.

    Mit freundlichen Grüßen,
    Freaky



  • Ich habe sowas mal bei einer Verkehrssimulation gemacht:
    Lass ihn über das Ziel hinauslaufen und wenn er hinausgelaufen ist, pack den "Überschuss" auf das folgende Weg-Segment entsprechend drauf.



  • Erstmal danke für deinen Beitrag.
    Wenn ich das richtig verstanden habe, würde das nicht heißen, dass der Gegner weiter läuft und im nächsten movement einen schnellen Sprung in die Richtung des nächsten Punkts macht? Und wenn ich das hinauslaufen nicht zeichne, läuft er dann nicht trotzdem kurz vor dem Punkt diagonal zum nächsten Punkt?

    Edit:
    Mein Problem ist, dass die Bewegung, wenn der Gegner kurz vor dem Punkt ist, mit der gleichen Geschwindigkeit sich auf den Punkt bewegen soll, ohne zu früh oder zu spät zu stoppen. Bei mir stoppt er aber zu früh, oder geht über den Punkt hinaus. Ich brauch also eine Rechnung, die merkt, dass bei dem nächsten move der Gegner über die Position hinaus geht, sie aber einen Wert liefert, die den Gegner an die Position mit der gleichen Geschwindigkeit wie vorher nähert und nicht so sehr springt. Ich hoffe ich kann es einigermaßen verdeutlichen.



  • time t = gametime.elapsed;
    bool reached = false;
    do {
      waypoint = waypoints.Peek();
    
      // move speichert in t ab, wann der zielpunkt erreicht wurde, falls er erreicht wurde und gibt true zurück.
      reached = this.move(t, waypoint, elapsed);
      t -= elapsed;
      //if the minion reached the position, remove the position
      if( reached ) {
         waypoints.Dequeue();
      }
    
    }  while( reached && waypoints.Size() );
    

    So meinte ich das, als halb-pseudo code.
    Oder hast Du Probleme den Zeitpunkt zu berechnen?



  • Tut mir Leid falls ich auf dem Schlauch stehe, aber wofür brauche ich "t"? Ich benutze es ja dann nicht. Der Gegner wird dann über den Punkt hinaus gehen und diagonal zum nächsten gehen (falls er nicht auf der gleichen x oder y Achse liegt).



  • Die Idee ist, dass Move beim Zielpunkt stehen bleibt (falls die Zeit dafür reichte) und zurückgibt, wieviel Zeit noch "übrig" ist. Und dann wird Move mit der übrigen Zeit aufgerufen in Richtung des nächsten Wegpunkts.

    Soll das so nicht laufen? Vielleicht verstehe ich auch nicht ganz so gut, was eigentlich passieren soll.



  • private bool move(float timeLeft, Vector2 position, float& elapsed )
    {
        Vector2 direction = (position - this.Center);
        direction.Normalize();
    
        if( (position - this.Center).Length() < this.Speed * timeLeft ) {
            this.Center = position;
            // div by zero...
            elapsed = (position - this.Center).Length() / this.Speed;
            return true;
        } else {
            this.Center += direction * this.Speed * timeLeft;
            return false;
        }
    }
    


  • Also wenn du dich auf die Zeit festlegst, damit arbeite ich eigentlich garnicht.
    Das

    (float)gametime.ElapsedGameTime.TotalSeconds;
    

    benutze ich eigentlich nur deswegen.

    theGameTime is used to keep how fast the sprite moves consistent across different computers. By always moving by how much time has elapsed, if a computer's refresh rate is faster, the sprite should still move the same speed as it does on a computer with a slower refresh rate.

    Ich will das mein Gegner auch wirklich den Wegpunkt erreicht. Er soll auf diesem Punkt dargestellt werden und erst dann soll er zum nächsten.



  • Nachdem ich jetzt sogar die Move-Funktion gepostet habe, die genau am Zielpunkt stehen bleibt, wenn zuviel Zeit bei gegebener Geschwindigkeit zur Verfügung stand, sollte es Dir doch eigentlich leicht fallen, meine Pfad-Routine um das Ausnutzen der übrigen Zeit zu erleichtern.

    Dann brauchst du natürlich auch keinen bool-rückgabewert mehr und auch kein elapsed per referenz. Dennoch wird natürlich die Zeit, die vergangen ist, benötigt.


Anmelden zum Antworten