2016-11-29 1 views
2

Мы находимся в середине перехода от JavaFX к libGDX. Удивительно, если в libGDX есть эквивалент PathTransition.В libGDX есть эквивалент PathTransition JavaFX?

Что особенно удивительно в PathTransition, так это то, что он вращает ваш узел соответственно, когда он проходит через Путь. Какая увлекательность в PathTransition заключается в том, что вам нужно рассчитать скорость самостоятельно, то есть вы укажете, сколько времени потребуется для завершения обхода, но вам нужно выяснить, как долго путь будет таким, чтобы вы могли установить соответствующую продолжительность ,

Надеюсь, что у libGDX было что-то похожее или лучше, но улучшенная версия PathTransition.

ответ

1

Основываясь на примере, который вы опубликовали, я не думаю, что есть прямой эквивалент в libGDX, но мы можем его создать.

libGDX поставляется с графиком сцены под названием Scene2d, который позволяет применять действия к Актерам или группам Актеров. Есть куча встроенных действий (MoveTo, RotateBy), и вы можете выполнять их параллельно друг другу или последовательно. Вы также можете применить классы Interpolation для твинирования.

libGDX также поставляется с интерфейсом Path, но на 1.9.4 не существует PathAction, но это не значит, что вы не можете построить что-то, как показано ниже:

package tech.otter.gdxsandbox.demos; 

import com.badlogic.gdx.graphics.g2d.Batch; 
import com.badlogic.gdx.graphics.glutils.ShapeRenderer; 
import com.badlogic.gdx.math.CatmullRomSpline; 
import com.badlogic.gdx.math.Path; 
import com.badlogic.gdx.math.Vector2; 
import com.badlogic.gdx.scenes.scene2d.Action; 
import com.badlogic.gdx.scenes.scene2d.Actor; 
import com.badlogic.gdx.scenes.scene2d.Stage; 

public class PathDemo extends Demo { 
    private ShapeRenderer sr; 
    private Stage stage; 

    public PathDemo() { 
     super("Action Demo"); 
     stage = new Stage(); 
    } 

    @Override 
    public void show() { 
     sr = new ShapeRenderer(); 
     Actor ourCircle = new SimpleCircleActor(sr, 10f); 
     stage.addActor(ourCircle); 

     ourCircle.addAction(new PathAction(5f, 50f, 50f, 100f, 60f, 300f, 200f, 100f, 400f)); 
    } 

    @Override 
    public void render(float delta) { 
     sr.setAutoShapeType(true); 
     sr.begin(); 
     sr.set(ShapeRenderer.ShapeType.Filled); 
     stage.act(delta); 
     stage.draw(); 
     sr.end(); 
    } 

    @Override 
    public void dispose() { 
     stage.dispose(); 
     sr.dispose(); 
    } 

    private class SimpleCircleActor extends Actor { 
     private ShapeRenderer renderer; 
     private float radius; 

     public SimpleCircleActor(ShapeRenderer renderer, float radius) { 
      this.renderer = renderer; 
      this.radius = radius; 
     } 

     /** 
     * Assumes something outside is setting the ShapeRenderer type/begin/end. 
     * Don't do this at home, kids. 
     */ 
     @Override 
     public void draw(Batch batch, float delta) { 
      renderer.circle(this.getX(), this.getY(), this.radius); 
     } 
    } 

    private class PathAction extends Action { 
     private Path<Vector2> path; 
     private float current; 
     private float duration; 
     public PathAction(float duration, float... coordinates) { 
      this.duration = duration; 
      this.current = 0; 

      Vector2[] dataSet = new Vector2[coordinates.length/2]; 
      for(int i = 0; i < dataSet.length; i++) { 
       dataSet[i] = new Vector2(coordinates[2*i], coordinates[2*i+1]); 
      } 
      this.path = new CatmullRomSpline<Vector2>(dataSet, true); 
     } 
     @Override 
     public boolean act(float delta) { 
      if(duration == current) return true; // The action has already completed. 

      if(current + delta >= duration) { 
       current = duration; 
      } else { 
       current += delta; 
      } 

      Vector2 out = new Vector2(); // Get our position on the path. 
      this.path.valueAt(out, current/duration); 
      this.actor.setPosition(out.x, out.y); 

      return duration == current; // Return whether we are now complete. 
     } 
    } 
} 
+0

Я надеялся легко запустить ваш пример. Не могли бы вы предоставить исходный код класса Demo? Или их две разные зависимости? – DavidS

+1

Это часть небольшой песочницы, которую я собрал, которая находится на github: https://github.com/madigan/gdx-sandbox – John

+0

Однако стоит отметить, что почти все, что делает PathDemo.java, может быть скопировано и вставлен в класс, расширяющий Game или реализующий ApplicationListener, и он будет работать с небольшой настройкой. – John

0

Так Я заработал. В приведенном ниже классе создается пример Action, например, SequenceAction. Созданный Action будет пересекать Actor через точки, которые предоставляет пользователь. Он учитывает скорость, продолжительность, смещение позиции Actor на пути, поворот Actor и даже отступы Actor при выходе и выходе на экран.

import com.badlogic.gdx.scenes.scene2d.actions.Actions; 
import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction; 
import java.util.ArrayList; 
import java.util.List; 

/** 
* 
* @author jmart 
*/ 
public class PathActionMaker { 

    private final float[][] points; 
    private float speed = 0; 
    private final float rotationSpeed = 600; 
    private float[] screenSize; 

    /** 
    * 
    * @param points - all the path points that must be traversed 
    * @param duration - how long it should take to traverse the path points 
    * @param screenSize - the size of the screen 
    */ 
    public PathActionMaker(float[][] points, float duration, float[] screenSize) { 
     this.points = points; 
     this.speed = getSpeed(points, duration); 
     this.screenSize = screenSize; 
    } 

    /** 
    * 
    * @param speed - the speed at which the Actor should move traverse through 
    * all the points 
    * @param points - all the path points that must be traversed 
    * @param screenSize - the size of the screen 
    */ 
    public PathActionMaker(float speed, float[][] points, float[] screenSize) { 
     this.points = points; 
     this.speed = speed; 
     this.screenSize = screenSize; 
    } 

    /** 
    * The offsets are used to allow centering of an actor on the provided 
    * points. 
    * 
    * @param xOffset 
    * @param yOffset 
    * @param offScreenIndent number of pixels to move the actor out of screen 
    * when entering and leaving 
    * @return 
    */ 
    public SequenceAction getAction(float xOffset, float yOffset, float offScreenIndent) { 
     float[] prev = null; 
     float prevTheta = 0; 
     int i = 0; 
     SequenceAction seqAction = Actions.sequence(); 
     boolean firstRotation = true; 
     float[][] fixedPoints = getOffSetFixedPoints(points, xOffset, yOffset, offScreenIndent); 
     for (float[] point : fixedPoints) { 
      float[] p = point; 
      if (prev == null) { 
       seqAction.addAction(Actions.moveTo(p[0], p[1])); 
      } else { 
       float dist = MathUtils.getDistance(prev[0], prev[1], p[0], p[1]); 
       float time = dist/speed; 
       float theta = MathUtils.angle(prev[0], prev[1], p[0], p[1]) + 90; 
       if (theta > 360) { 
        theta -= 360; 
       } 
       float dTheta = Math.abs(prevTheta - theta); 
       float rotateDuration = dTheta/rotationSpeed; 
       // the first rotation should be immediate. 
       if (firstRotation) { 
        firstRotation = false; 
        seqAction.addAction(Actions.parallel(
          Actions.moveTo(p[0], p[1], time), 
          Actions.rotateTo(theta)));//...rotation duration is 0, aka immediate 
       } else { 
        seqAction.addAction(Actions.parallel(
          Actions.moveTo(p[0], p[1], time), 
          Actions.rotateTo(theta, rotateDuration))); 
       } 
       prevTheta = theta; 
      } 
      prev = p; 
     } 
     return seqAction; 
    } 

    public float[][] getOffSetFixedPoints(float[][] points, float xOffset, float yOffset, float offScreenIndent) { 
     List<Float[]> list = new ArrayList<>(); 

     //apply offset indent at beginning of path 
     float[] p1 = points[0]; 
     float[] p2 = points[1]; 
     float slope = (p1[1] - p2[1])/(p1[0] - p2[0]); 
     float c = p1[1] - slope * p1[0]; 

     if (p1[0] == 0) { 
      float x = -offScreenIndent; 
      float y = slope * x + c; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } else if (p1[0] == screenSize[0]) { 
      float x = screenSize[0] + offScreenIndent; 
      float y = slope * x + c; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } else if (p1[1] == 0) { 
      float y = -offScreenIndent; 
      float x = (y - c)/slope; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } else if (p1[1] == screenSize[1]) { 
      float y = screenSize[1] + offScreenIndent; 
      float x = (y - c)/slope; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } 

     //apply the remaining points 
     for (float[] point : points) { 
      float[] p = {point[0] - xOffset, point[1] - yOffset}; 
      addPointToList(p, list); 
     } 

     //apply offscreen indent at end of path 
     float[] p4 = points[points.length - 1]; 
     float[] p3 = points[points.length - 2]; 
     slope = (p3[1] - p4[1])/(p3[0] - p4[0]); 
     c = p3[1] - slope * p3[0]; 

     if (p4[0] <= 0) { 
      float x = -offScreenIndent; 
      float y = slope * x + c; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } else if (p4[0] >= screenSize[0]) { 
      float x = screenSize[0] + offScreenIndent; 
      float y = slope * x + c; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } else if (p4[1] <= 0) { 
      float y = -offScreenIndent; 
      float x = (y - c)/slope; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } else if (p4[1] >= screenSize[1]) { 
      float y = screenSize[1] + offScreenIndent; 
      float x = (y - c)/slope; 
      list.add(new Float[]{x - xOffset, y - yOffset}); 
     } 

     //convert list to float[][] 
     float[][] rv = new float[list.size()][]; 
     int i = 0; 
     for (Float[] p : list) { 
      float[] j = new float[2]; 
      j[0] = p[0]; 
      j[1] = p[1]; 
      rv[i++] = j; 
     } 
     return rv; 
    } 

    private static void addPointToList(float[] point, List<Float[]> list) { 
     list.add(new Float[]{point[0], point[1]}); 
    } 

    private float getSpeed(float[][] points, float duration) { 
     //speed = distance/time 
     float distance = MathUtils.getDistance(points); 
     return distance/duration; 
    } 

} 

 Смежные вопросы

  • Нет связанных вопросов^_^