JavaFX游戏开发--第一课 精灵动画

一直在关注JavaFX的发展,最近想试试使用JavaFX开发游戏是什么样的情况。可惜令我汗颜的是--没有找到类似于Java 2D中Graphics/Graphics2D之类的类。自己单纯的继承Node的话,也没办法自己进行绘制。看来目前使用JavaFX进行游戏开发,只能使用JavaFX的Shape和ImageView了。

  

  今天花时间写了个JavaFX的精灵的动画的例子,让我们看看在JavaFX中如何操作精灵的动画吧。

  

  首先创建一个JavaFX项目。

  暂时不进行Scene的创建,因为我们要使用自定义的Parent。


  我们先进行创建一个Sprite类,继承Parent。 这就是我们的精灵类了。

  下面来看看代码:

   

[java] view plain copy
  1. import javafx.geometry.Rectangle2D;  
  2. import javafx.scene.Parent;  
  3. import javafx.scene.image.Image;  
  4. import javafx.scene.image.ImageView;  
  5. /** 
  6.  * 精灵类 
  7.  * @author wing 
  8.  * @date 2012/7/17 
  9.  */  
  10. public class Sprite extends Parent {  
  11.     private enum Direction {  
  12.         Left, Right, Up, Down  
  13.     };  
  14.   
  15.     private Direction direction = Direction.Left;  
  16.     private Direction lastDirection;  
  17.     private int x, y, width, height;  
  18.     private int index = 0;  
  19.     private int indexDiv = 5;  
  20.     private ImageView mImageView;  
  21.     private int speed = 4;  
  22.   
  23.     public Sprite(int x, int y, int width, int height, String url) {  
  24.         this.x = x;  
  25.         this.y = y;  
  26.         this.width = width;  
  27.         this.height = height;  
  28.         Image actor = new Image(getClass().getResourceAsStream(url));  
  29.         mImageView = new ImageView(actor);  
  30.         mImageView.setViewport(new Rectangle2D(00, width, height));  
  31.         mImageView.setLayoutX(x);  
  32.         mImageView.setLayoutY(y);  
  33.         getChildren().add(mImageView);  
  34.     }  
  35.       
  36.     /** 
  37.      * 像下移动 
  38.      */  
  39.     public void moveDown() {  
  40.         direction = Direction.Down;  
  41.         if(lastDirection != direction){  
  42.             index = 0;  
  43.         }  
  44.         index++;  
  45.         if (index / indexDiv > 2) {  
  46.             index = 0;  
  47.         }  
  48.         mImageView.setViewport(new Rectangle2D(((index / indexDiv) % 3) * width, ((index / indexDiv) / 3) * height, width,  
  49.                 height));  
  50.         mImageView.setLayoutY(mImageView.getLayoutY() + speed);  
  51.           
  52.         lastDirection = direction;  
  53.     }  
  54.       
  55.     /** 
  56.      * 像左移动 
  57.      */  
  58.     public void moveLeft() {  
  59.         direction = Direction.Left;  
  60.         if(lastDirection != direction){  
  61.             index = 3 * indexDiv;  
  62.         }  
  63.         index++;  
  64.         if (index / indexDiv > 5) {  
  65.             index = 3 * indexDiv;  
  66.         }  
  67.         mImageView.setViewport(new Rectangle2D(((index / indexDiv) % 3) * width, ((index / indexDiv) / 3) * height, width,  
  68.                 height));  
  69.         mImageView.setLayoutX(mImageView.getLayoutX() - speed);  
  70.           
  71.         lastDirection = direction;  
  72.     }  
  73.       
  74.     /** 
  75.      * 像右移动 
  76.      */  
  77.     public void moveRight() {  
  78.         direction = Direction.Right;  
  79.         if(lastDirection != direction){  
  80.             index = 6 * indexDiv;  
  81.         }  
  82.         index++;  
  83.         if (index / indexDiv > 8) {  
  84.             index = 6 * indexDiv;  
  85.         }  
  86.         mImageView.setViewport(new Rectangle2D(((index / indexDiv) % 3) * width, ((index / indexDiv) / 3) * height, width,  
  87.                 height));  
  88.         mImageView.setLayoutX(mImageView.getLayoutX() + speed);  
  89.           
  90.         lastDirection = direction;  
  91.     }  
  92.       
  93.     /** 
  94.      * 像右移动 
  95.      */  
  96.     public void moveUp() {  
  97.         direction = Direction.Up;  
  98.         if(lastDirection != direction){  
  99.             index = 9 * indexDiv;  
  100.         }  
  101.         index++;  
  102.         if (index / indexDiv > 11) {  
  103.             index = 9 * indexDiv;  
  104.         }  
  105.         mImageView.setViewport(new Rectangle2D(((index / indexDiv) % 3) * width, ((index / indexDiv) / 3) * height, width,  
  106.                 height));  
  107.         mImageView.setLayoutY(mImageView.getLayoutY() - speed);  
  108.           
  109.         lastDirection = direction;  
  110.     }  
  111.       
  112.       
  113.     public int getX() {  
  114.         return x;  
  115.     }  
  116.     public void setX(int x) {  
  117.         this.x = x;  
  118.     }  
  119.     public int getY() {  
  120.         return y;  
  121.     }  
  122.     public void setY(int y) {  
  123.         this.y = y;  
  124.     }  
  125.     public int getWidth() {  
  126.         return width;  
  127.     }  
  128.     public void setWidth(int width) {  
  129.         this.width = width;  
  130.     }  
  131.     public int getHeight() {  
  132.         return height;  
  133.     }  
  134.     public void setHeight(int height) {  
  135.         this.height = height;  
  136.     }  
  137. }  

   1.首先定义了一个枚举类型,用来标明当前精灵的方向。

   2.x, y, width, height这几个参数顾名思义,就是表明精灵的X,Y坐标和宽,高。

   3.我们创建了一个Image,然后基于Image创建了一个ImageView。Image的图片加载是通过getClass().getResourceAsStream(String str)来进行。

   4.ImageView有个setViewport(Rectangle2D rect2D)是个很重要的方法,就是显示这个ImageView中图片以rect2D的x,y为起点,width,height为宽高的一部分。 其实就是切割显示。这在所有的精灵动画中都是很常用的。

  


   至于indexDiv大家暂时可以不用看,这个只是为了减慢精灵动画的(太快看起来不协调)。所以你们可以把index / 

indexDiv都当作index来看待。


  JavaFX游戏开发--第一课 精灵动画_第1张图片

  精灵动画,我这里暂且使用很常见的RPGMaker VX中的默认的精灵图片。

  

  

  我们以这个精灵为标准,从左上到右下,索引也就是Sprite中的index是从0-11。


  那么我们在使用ImageView.setViewport()时就要进行相应的处理。最简单的就是X方向(index % 3) * width, Y方向(index / 3 ) * height。 当index到3时,就进入第二行动画。相应的从0, 0,width, height 也变为了0, height, width, height。 

  然后通过setLayoutX()进行改变精灵的坐标,产生正在行走的效果。


  为了避免精灵方向切换的时候,动画出现异常问题(可能会停留一帧上一个方向的动画帧)。我们又创建了一个lastDirection的方向枚举类型。用来标识上一次的方向。如果方向相同,则不做处理,如果方向不同,则要把当前帧切换到当前方向的第一帧。

  

[java] view plain copy
  1. /** 
  2.  * 像下移动 
  3.  */  
  4. public void moveDown() {  
  5.     direction = Direction.Down;  
  6.     if(lastDirection != direction){  
  7.         index = 0;  
  8.     }  
  9.     index++;  
  10.     if (index / indexDiv > 2) {  
  11.         index = 0;  
  12.     }  
  13.     mImageView.setViewport(new Rectangle2D(((index / indexDiv) % 3) * width, ((index / indexDiv) / 3) * height, width,  
  14.             height));  
  15.     mImageView.setLayoutY(mImageView.getLayoutY() + speed);  
  16.       
  17.     lastDirection = direction;  
  18. }  
  

  另外,由于只有3帧,如果当index 大于当前方向动画帧数的最大值,得重置为最小。我这里只是简单的标注了数字 2 ,5, 8, 11。


  然后创建一个类GamePanel,用来添加我们的所有精灵和地图绘制(以后课程)。

  

[java] view plain copy
  1. import javafx.event.EventHandler;  
  2. import javafx.scene.Parent;  
  3. import javafx.scene.input.KeyCode;  
  4. import javafx.scene.input.KeyEvent;  
  5. /** 
  6.  * @author wing 
  7.  * @date 2012/7/17 
  8.  */  
  9. public class GamePanel extends Parent {  
  10.     private Sprite sprite;  
  11.     public GamePanel() {  
  12.     }  
  13.   
  14.     public void load(){  
  15.         sprite = new Sprite(50503232"actor.png");  
  16.         getChildren().add(sprite);  
  17.         getScene().setOnKeyPressed(new EventHandler<KeyEvent>() {  
  18.             @Override  
  19.             public void handle(KeyEvent event) {  
  20.                 onKeyPressed(event);  
  21.             }  
  22.         });  
  23.     }  
  24.       
  25.       
  26.     public void onKeyPressed(KeyEvent event){  
  27.         if(event.getCode() == KeyCode.LEFT){  
  28.           sprite.moveLeft();  
  29.        }else if(event.getCode() == KeyCode.RIGHT){  
  30.           sprite.moveRight();  
  31.        }else if(event.getCode() == KeyCode.UP){  
  32.           sprite.moveUp();  
  33.        }else if(event.getCode() == KeyCode.DOWN){  
  34.           sprite.moveDown();  
  35.        }  
  36.     }  
  37.       
  38.       
  39.     public void update(long now){  
  40.           
  41.     }  
  42.   
  43. }  

  这个类现在很简单,只是单纯的在50,50坐标处,创建了一个Sprite。然后给Scene添加了一个按键事件,在按Left right up 和 down的时候,将会控制精灵进行各个方向的移动。


  下面来写我们的主类。

  

[java] view plain copy
  1. import javafx.application.Application;  
  2. import javafx.scene.Scene;  
  3. import javafx.scene.paint.Color;  
  4. import javafx.stage.Stage;  
  5.   
  6. public class MainClass extends Application {  
  7.   
  8.     @Override  
  9.     public void start(Stage stage) throws Exception {  
  10.           GamePanel mPanel = new GamePanel();  
  11.           final Scene scene = new Scene(mPanel,800600);  
  12.           mPanel.load();  
  13.           scene.setFill(Color.BLACK);  
  14.           stage.setScene(scene);  
  15.           stage.setTitle("JavaFX游戏开发--第一课  精灵动画");  
  16.           stage.show();  
  17.     }  
  18.   
  19.     /** 
  20.      * @param args 
  21.      */  
  22.     public static void main(String[] args) {  
  23.         launch(MainClass.class, args);  
  24.     }  
  25.   
  26. }  

   我们在主类中创建了GamePanel,根据GamePanel创建了一个Scene,调用了GamePanel的load方法,进行加载精灵和添加事件。然后将Scene背景设为了黑色。

  下面我们来看看运行效果吧~

  向右走:

  JavaFX游戏开发--第一课 精灵动画_第2张图片


  向下走:

  JavaFX游戏开发--第一课 精灵动画_第3张图片


  那么JavaFX游戏开发的第一课就讲到这里了。其实很简单,就是单纯的一个精灵动画的实现而已。所以我们并没有创建精灵的基类等工作。


   后面的课程中,我们将会进行游戏地图,对话框等的加入。

   本人水平不佳,望大家指正。一起进步。

你可能感兴趣的:(JavaFX)