This discussion is archived
7 Replies Latest reply: Jan 30, 2013 1:21 PM by KonradZuse RSS

KeyValue confusion?

KonradZuse Explorer
Currently Being Moderated
Okay so I'm trying to get some animation going, and so far I have a rotation.



http://docs.oracle.com/javafx/2/api/javafx/animation/KeyValue.html

        animation.getKeyFrames().addAll(
               new KeyFrame(Duration.ZERO,
                        new KeyValue(c.a.xProperty(), 0d),
                        new KeyValue(c2.rx.angleProperty(), 0d),
                        new KeyValue(c3.rx.angleProperty(), 0d),
                        new KeyValue(c4.ry.angleProperty(), 0d),
                        new KeyValue(c5.rx.angleProperty(), 0d)
                ),
                new KeyFrame(Duration.seconds(1),
                        new KeyValue(c.a.xProperty(), 360d),
                        new KeyValue(c2.rx.angleProperty(), 360d),
                        new KeyValue(c3.rz.angleProperty(), 360d),
                        new KeyValue(c4.rx.angleProperty(), 360d),
                        new KeyValue(c5.ry.angleProperty(), 360d)
                ));
Now if you notice everything uses the angel property except c, which I wanted to translate for testing purposes. Now I'm confused how to do it.. I would think the xProperty() would work, but what about the second paramater... 0d, 360d is for degrees, which I'm assuming the computer knows as it's "endvalue" but what do I do for translation? I tried 0 and 100, but that didn't work...


        final Rotate rx = new Rotate(0,Rotate.X_AXIS);
        final Rotate ry = new Rotate(0,Rotate.Y_AXIS);
        final Rotate rz = new Rotate(10,20,30);
        final Translate a = new Translate(100,10);
I can only find rotation examples, but I did find one that had to do with Interpolator... Apparently by default it's Interpolator.LINEAR but wouldn't that mean translation in a linear sense? I guess I'm just really confused about it, is there a tutorial or something I could look at, or anyone have any advice on how to tackle KeyValues completely for many different tasks:?



Thanks all!!!

~KZ
  • 1. Re: KeyValue confusion?
    James_D Guru
    Currently Being Moderated
    The KeyValue constructor you're invoking takes two values: a WritableValue (such as a property) and a value to which to set it. So
    new KeyValue(c.a.xProperty(), 0d)
    is a specification to set the value of the xProperty of c.a to 0,
    new KeyValue(c.rx.angleProperty(), 360d)
    is a specification to set the value of the angleProperty of c.rx to 360, and so on.

    A KeyFrame takes a Duration (a point in time in the animation) and a collection of KeyValues.
    So
    new KeyFrame(Duration.seconds(1),
      new KeyValue(c.a.xProperty(), 360d),
      new KeyValue(c2.rx.angleProperty(), 360d),
      ...
    )
    means that the animation frame at 1 second will have the xProperty of c.a set to 360 and the angleProperty c2.rx set to 360.

    In your example you specify KeyFrames for 0 and 1 second; the animation will by default use a linear interpolator to calculate the values of the properties in the frames in between.

    Since rx, ry, and rz are defined to be rotations, the have angle properties which represent the amount of the rotation in degrees. So the animation you create will start at 0 (the first KeyValue for each rotation) and make one full rotation (360 degrees) in one second (defined by the second KeyValue for each rotation).

    c.a appears to be a Translation; so the x value is the horizontal translation in local coordinates (typically pixels, but of course if you've used a scale, for example, they may be arbitrary units). So this would animate the node from zero to 360 units horizontally in one second. (Note that you initialize your translation with x=100; so when the animation starts it would jump back to x=0 and then animate to x=360, or whatever you set in the second KeyValue for c.a.xProperty().)

    http://docs.oracle.com/javafx/2/animations/basics.htm#CJAFADFJ has a simple example of animating a translation.

    It what sense did it "not work"?
  • 2. Re: KeyValue confusion?
    James_D Guru
    Currently Being Moderated
    Here's a more complex example. It animates a wheel by using a timeline which manipulates its translateX property.

    The wheel is represented as a Group, containing a rim, a hub, and a bunch of spokes. The rotateProperty is bound to the translateX property so that it rotates as it moves horizontally. Thus when the Timeline manipulates the translateX property, the wheel rotates, giving it the appearance of rolling.

    It would be more natural to use a TranslateTransition to manage this, but you wanted to see an example using KeyValues and KeyFrames.
    import javafx.animation.Animation;
    import javafx.animation.Animation.Status;
    import javafx.animation.KeyFrame;
    import javafx.animation.KeyValue;
    import javafx.animation.Timeline;
    import javafx.application.Application;
    import javafx.beans.binding.Bindings;
    import javafx.event.ActionEvent;
    import javafx.event.EventHandler;
    import javafx.scene.Group;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.layout.AnchorPane;
    import javafx.scene.layout.BorderPane;
    import javafx.scene.paint.Color;
    import javafx.scene.shape.Circle;
    import javafx.scene.shape.Line;
    import javafx.scene.shape.Rectangle;
    import javafx.scene.transform.Rotate;
    import javafx.stage.Stage;
    import javafx.util.Duration;
    
    public class Wheel extends Application {
      
      private static final int NUM_SPOKES = 24 ;
      // Slippage constant determines if the wheel is spinning (>1) on the surface, slipping (<1), or rolling:
      private static final double SLIPPAGE = 1 ;
    
      @Override
      public void start(Stage primaryStage) {
    
        Group wheel = buildWheel(100);
        wheel.setTranslateX(125);
        wheel.setTranslateY(125);
    
        // Animate the wheel to move to the right and left over a 5 second period:
        KeyFrame start = new KeyFrame(Duration.ZERO, 
            new KeyValue(wheel.translateXProperty(), 125.0));
        KeyFrame end = new KeyFrame(Duration.seconds(5), 
            new KeyValue(wheel.translateXProperty(), 675));
        final Timeline animation = new Timeline(start, end);
        animation.setCycleCount(Animation.INDEFINITE);
        animation.setAutoReverse(true);
    
        // Simple button to control the animation:
        Button playButton = createButton(animation);
    
        // Usual layout stuff:
        AnchorPane wheelPane = new AnchorPane();
        wheelPane.getChildren().addAll(wheel, new Rectangle(0,225,800,40));
    
        BorderPane root = new BorderPane();
        root.setCenter(wheelPane);
        root.setBottom(playButton);
        Scene scene = new Scene(root, 800, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
      }
    
      private Group buildWheel(double radius) {
        // Wheel is represented as a rim, hub, and spokes, put together in a Group:
        Group wheel = new Group();
        Circle rim = new Circle(0, 0, radius, Color.TRANSPARENT);
        rim.setStroke(Color.BLACK);
        rim.setStrokeWidth(8.0);
        
        final double hubRadius = 12 ;
        Circle hub = new Circle(0, 0, hubRadius, Color.TRANSPARENT);
        hub.setStroke(Color.BLACK);
        hub.setStrokeWidth(8.0);
        
        wheel.getChildren().addAll(rim, hub);
        for (int i = 0; i < NUM_SPOKES; i++) {
          Line spoke = new Line(0, hubRadius, 0, radius);
          spoke.getTransforms().add(new Rotate(360.0*i/NUM_SPOKES, 0.0, 0.0));
          wheel.getChildren().add(spoke);
        }
    
        // When the wheel translates horizontally, rotate it
        wheel.rotateProperty().bind(
            wheel.translateXProperty().divide(radius * 2 * Math.PI)
                .multiply(360 * SLIPPAGE));
        return wheel;
      }
      
      private Button createButton(final Timeline animation) {
        Button playButton = new Button();
        // Change text in button depending on whether the animation is running
        playButton.textProperty().bind(
            Bindings.when(animation.statusProperty().isEqualTo(Status.RUNNING))
                .then("Pause").otherwise("Play"));
        playButton.setOnAction(new EventHandler<ActionEvent>() {
          @Override
          public void handle(ActionEvent event) {
            if (animation.getStatus().equals(Status.RUNNING)) {
              animation.pause();
            } else {
              animation.play();
            }
          }
        });
        return playButton;
      }
    
      public static void main(String[] args) {
        launch(args);
      }
    }
  • 3. Re: KeyValue confusion?
    KonradZuse Explorer
    Currently Being Moderated
    Interesting example above... Moving the entire group... It also collides with the sides, so that answers another question I was interested in.. I'm going to read it and figure it out, because a group seems to resize itself, so I was finding a container that couldn't reside so I could know when to "bounce back" like this wheel does :D. I see it's a anchor pane, within a borderpane.. interesting :D.



    What I meant by "Does not work" I guess I was really vague, sorry... All of the dice rotate, and this one doesn't move at all. IT is stationary.... It's position is really far away, so I also guess I don't need to put 'd' aftef 360 since d is for degrees and only rotation? The example above sows 125.0 and 675 :O.


    Also I figured out I needed to do c.translateXProperty() from your example... it works now THANKS SOO MUCH :D

    Edited by: KonradZuse on Jan 25, 2013 2:40 PM
  • 4. Re: KeyValue confusion?
    James_D Guru
    Currently Being Moderated
    KonradZuse wrote:
    I'm going to read it and figure it out, because a group seems to resize itself,
    Yes. The bounds of a group are determined by the "collective bounds of its children". So if you have a single node inside a group and translate it, it will move inside a coordinate system which will itself shift in return. I typically only use a Group when I have a collection of Nodes I want to transform together, as in the example of the wheel.
  • 5. Re: KeyValue confusion?
    KonradZuse Explorer
    Currently Being Moderated
    is the reverse is based on a collision, or is it based on that exact point and then you invoke the AutoReverse(true);?


    I am using dice that I want to bounce off of the container, but I'm not sure which can stay a certain size that I can do a intersection call(Does FX have collsion like in Swing Retectangle.intersects())???

    I also am curious if there is a way to know which side of my dice is facing up without a mouse click..?


    Thanks again!!
  • 6. Re: KeyValue confusion?
    James_D Guru
    Currently Being Moderated
    KonradZuse wrote:
    is the reverse is based on a collision, or is it based on that exact point and then you invoke the AutoReverse(true);?
    It reverses at the end of the animation, determined by the maximal duration of all KeyFrames.

    >
    I am using dice that I want to bounce off of the container, but I'm not sure which can stay a certain size that I can do a intersection call(Does FX have collsion like in Swing Retectangle.intersects())???
    Node, Rectangle2D, and Bounds all have intersects(...) methods.

    >
    I also am curious if there is a way to know which side of my dice is facing up without a mouse click..?
    Hmm... trickier. You can probably determine that by examining any rotations you have applied to the dice.
  • 7. Re: KeyValue confusion?
    KonradZuse Explorer
    Currently Being Moderated
    Seems like borderpane also resizes.... Still at a loss..... I was thinking I could create a border around the 5 sides of the borderpane(I can do that with css right)? Then I would know how far it was and I could bounce it!

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points