Animation 在关键点输入上使用JavaFX设置精灵动画
我是JavaFX新手,但对面向对象的Java有很好的理解。下面的程序是两个示例的组合,一个用于设置和移动形状的动画,另一个用于在按下鼠标按钮时设置对象的动画。许多功能已被删除或更改,以满足我的需要 我已经搜索了很多例子,但没有找到一个我完全理解的关于移动精灵和按键动画的例子。在我的程序中,我确信我没有使用正确的类来创建游戏对象,即使经过一些调整,我确信它可以工作 我添加了一些Animation 在关键点输入上使用JavaFX设置精灵动画,animation,javafx,sprite,timeline,keyframe,Animation,Javafx,Sprite,Timeline,Keyframe,我是JavaFX新手,但对面向对象的Java有很好的理解。下面的程序是两个示例的组合,一个用于设置和移动形状的动画,另一个用于在按下鼠标按钮时设置对象的动画。许多功能已被删除或更改,以满足我的需要 我已经搜索了很多例子,但没有找到一个我完全理解的关于移动精灵和按键动画的例子。在我的程序中,我确信我没有使用正确的类来创建游戏对象,即使经过一些调整,我确信它可以工作 我添加了一些println函数来测试动画。问题似乎是walkSouth动画中的关键帧部分无法工作/播放 我的问题是: 我应该使用不同的
println
函数来测试动画。问题似乎是walkSouth
动画中的关键帧
部分无法工作/播放
我的问题是:
package testing;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
private enum UserAction{
NONE,NORTH,SOUTH;
}
private static int APP_W = 200;
private static int APP_H = 200;
private Scene scene;
private UserAction action = UserAction.NONE;
private Timeline timeline = new Timeline();
private boolean running = true;
private int FPS = 60;
private Parent createContent(){
Pane root = new Pane();
root.setPrefSize(APP_W,APP_H);
Image cat_image = new Image("file:res/cata.png");
GameObject obj = new GameObject(cat_image,12,8);
obj.setTranslateX(100);
obj.setTranslateY(100);
KeyFrame frame = new KeyFrame(Duration.millis(1000/FPS), event -> {
if(!running)
return;
switch(action){
case NORTH:
obj.setTranslateY(obj.getTranslateY()-1);
break;
case SOUTH:
obj.walkSouth();
obj.setTranslateY(obj.getTranslateY()+1);
break;
case NONE:
obj.pauseAnimation();
break;
}
});
timeline.getKeyFrames().add(frame);
timeline.setCycleCount(Timeline.INDEFINITE);
root.getChildren().add(obj);
return root;
}
private void restartGame(){
stopGame();
startGame();
}
private void stopGame(){
running = false;
timeline.stop();
}
private void startGame(){
timeline.play();
running = true;
}
public void start(Stage primaryStage) throws Exception{
scene = new Scene(createContent());
scene.setOnKeyPressed(event -> {
switch (event.getCode()) {
case W:
action = UserAction.NORTH;
break;
case S:
action = UserAction.SOUTH;
break;
}
});
scene.setOnKeyReleased(event -> {
switch (event.getCode()) {
case W:
action = UserAction.NONE;
break;
case S:
action = UserAction.NONE;
break;
}
});
primaryStage.setTitle("Simple Animation");
primaryStage.setScene(scene);
primaryStage.show();
startGame();
}
public static void main(String[] args) {
launch(args);
}
}
以下是GameObject类:
package testing;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.util.Duration;
/**
* Created by matt on 26/02/17.
*/
public class GameObject extends Pane {
ObjectImage objectImage;
public GameObject( Image image, int columns, int rows){
objectImage = new ObjectImage(image,columns,rows);
getChildren().setAll(objectImage);
}
public void pauseAnimation(){
getChildren().setAll(objectImage);
objectImage.pauseAnimation();
}
public void walkSouth(){
getChildren().setAll(objectImage);
objectImage.walkSouth();
}
}
class ObjectImage extends ImageView {
private Rectangle2D[] clips;
private double width,height;
private Timeline timeline = new Timeline();
public ObjectImage(Image image,int columns,int rows){
width = image.getWidth()/columns;
height = image.getHeight()/rows;
clips = new Rectangle2D[rows*columns];
int count=0;
for(int row =0;row < rows;row++ )
for(int column = 0 ; column < columns; column++,count++)
clips[count] = new Rectangle2D(width * column, height * row,width,height);
setImage(image);
setViewport(clips[0]);
}
public void pauseAnimation(){
timeline.pause();
}
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
KeyFrame frame = new KeyFrame( Duration.millis(1000/5), event -> {
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
System.out.println("frame test");
});
timeline.setCycleCount(timeline.INDEFINITE);
timeline.getKeyFrames();
timeline.play();
}
}
封装测试;
导入javafx.animation.KeyFrame;
导入javafx.animation.Timeline;
导入javafx.beans.property.IntegerProperty;
导入javafx.beans.property.SimpleIntegerProperty;
导入javafx.geometry.Rectangle2D;
导入javafx.scene.image.image;
导入javafx.scene.image.ImageView;
导入javafx.scene.layout.Pane;
导入javafx.util.Duration;
/**
*马特于2017年2月26日创作。
*/
公共类游戏对象扩展窗格{
客观形象客观形象;
公共游戏对象(图像、整数列、整数行){
objectImage=新的objectImage(图像、列、行);
getChildren().setAll(objectImage);
}
公共无效暂停激活(){
getChildren().setAll(objectImage);
objectImage.pauseAnimation();
}
公共图书馆(南){
getChildren().setAll(objectImage);
objectImage.walkSouth();
}
}
类ObjectImage扩展了ImageView{
私人矩形2D[]剪辑;
私人双宽,高;
私有时间线=新时间线();
公共对象图像(图像图像、int列、int行){
宽度=image.getWidth()/列;
高度=image.getHeight()/行;
clips=新矩形2D[行*列];
整数计数=0;
对于(int row=0;row{
if(count.get()<2)count.set(count.get()+1);
else计数集(0);
setViewport(剪辑[count.get()]);
系统输出打印项次(“帧测试”);
});
timeline.setCycleCount(timeline.unfinite);
timeline.getKeyFrames();
timeline.play();
}
}
正如评论所暗示的,您确实忘记了在walkSouth方法中添加帧。(您还将walkSouth方法中的每一帧设置为200ms。您是否打算更改它?)更改后的代码如下:
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
KeyFrame frame = new KeyFrame( Duration.millis(1000/FPS), event -> {
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
});
timeline.setCycleCount(timeline.INDEFINITE);
timeline.getKeyFrames().add(frame); //This was the offending line.
timeline.play();
}
但是,如果您不希望在每一帧中调用动画,则可以扩展Transition
。转换的frac
(分数)值范围为0到1,随时间增加。我不打算讲太多细节,但我相信你可以在网上查到更多的信息
public void walkSouth(){
System.out.println(“向南行走测试”);
IntegerProperty计数=新的SimpleIntegerProperty(0);
Transition trans=新的Transition(){
{
设置循环次数(持续时间.毫秒(1000/60.0));
}
@凌驾
公共空隙插值(双分形)
{
如果(分数!=1)
返回;
//一个周期的结束。
if(count.get()<2)count.set(count.get()+1);
else计数集(0);
setViewport(剪辑[count.get()]);
}
};
trans.setCycleCount(Animation.unfinite);
trans.playFromStart();
//使用trans.pause暂停,trans.stop停止。
}
我现在可能无法回答您的2个问题,但我可以看到您忘记在walkSouth方法中的时间线中添加帧,这就是动画无法工作的原因。太好了,谢谢您,我现在可以工作了,一定会尝试将其转换为使用动画和过渡类。需要注意的一点是,IntegerProperty
在walksuth
方法中,我应该在方法之外创建并初始化它,因为每次调用它时,它都会重置计数周期,即使在按住按钮时也是如此。您可以尝试使用常规实例整数变量
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
AnimationTimer tmr = new AnimationTimer() {
@Override
public void handle(long nanoTime)
{
//nanoTime specifies the current time at the beginning of the frame in nano seconds.
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
}
};
tmr.start();
//call tmr.stop() to stop/ pause timer.
}
public void walkSouth(){
System.out.println("walk south test");
IntegerProperty count = new SimpleIntegerProperty(0);
Transition trans = new Transition() {
{
setCycleDuration(Duration.millis(1000 / 60.0));
}
@Override
public void interpolate(double frac)
{
if (frac != 1)
return;
//End of one cycle.
if(count.get() < 2) count.set(count.get()+1);
else count.set(0);
setViewport(clips[count.get()]);
}
};
trans.setCycleCount(Animation.INDEFINITE);
trans.playFromStart();
//Use trans.pause to pause, trans.stop to stop.
}