JavaFX 2 GameTutorial第2部分

介紹

?他的是一系列與一個JavaFX 2游戲教程博客條目的第二批。 如果您尚未閱讀第1部分,請參閱JavaFX 2游戲教程的簡介部分。 在第1部分中,我提到了游戲的某些方面以及原型飛船的簡單演示(原型由簡單的形狀組成),該飛船能夠通過鼠標進行導航。 免責聲明 :這是一個很長的教程,因此如果您只想運行演示,請單擊“ 此處” 。 該演示稱為Atom Smasher,您可以在其中生成碰撞的原子(球體)。 您可以凍結游戲以添加更多原子。 目的是使一個以上的原子活著并反彈。 文本顯示當前漂浮的原子數。 在開始討論游戲循環之前,我想向您介紹一些有關游戲和動畫的背景歷史。

歷史

早在20世紀80年代至90年代期間,許多嘗試制作圖像動畫的游戲程序員都曾遇到過臭名昭著的屏幕閃爍問題。 這是你的精靈 (圖形圖像)往往會閃爍,使游戲看起來相當可怕的。 所有監視器的刷新率均以一定間隔重繪像素(稱為垂直回描CRT )。 例如,如果刷新率是80 Hz,則刷新率大約是每秒80次,屏幕將重新繪制。 如果要在屏幕上進行修改,則由于處于刷新間隔的中間,通常可能會不同步。 你應該怎么做? 好吧,實際上有兩件事可以幫助解決這個問題(雙緩沖和知道周期何時發生)。 一些聰明的開發人員創建了一種稱為雙緩沖的技術。 雙重緩沖是一種由兩個表面組成的技術,其中兩個表面依次輪流變為可顯示的表面,另一個表面外的區域(緩沖表面)。 這種技術實際上是一種數字技巧,開發人員可以在其中預先計算要在屏幕外表面繪制的精靈及其位置。 一旦在屏幕外緩沖區上完成繪制,代碼便會將其切換為可顯示的表面。 需要指出的重要一點是,由于在刷新間隔即將開始重繪過程時需要通知我們,因此仍然存在問題。 在Java中,此功能是通過BufferStrategy API內置的。 那么,我要去哪里呢? 有時解釋過去的策略將有助于我們欣賞今天的狀況。 我們需要在JavaFX中執行此操作嗎? 不。 不用擔心JavaFX在這里! 我已經提到的所有問題都通過使用JavaFX的場景圖API來解決。 但是,大多數游戲仍將使用舊的方式來制作圖形動畫和更新游戲世界,稱為“ 游戲循環”

游戲循環

簡單地說,游戲循環負責更新子畫面(圖形),檢查碰撞和清理。 較早的游戲循環將在循環中檢查按鍵和鼠標事件。 由于JavaFX對事件進行抽象以允許Scene或單個節點處理事件,因此在我們的游戲循環中無需偵聽低級事件。 下面顯示的是典型游戲循環的源代碼片段,該循環將在每個周期更新精靈,檢查碰撞和清理精靈。 您會注意到JavaFX 2.x中的Duration對象,該對象表示60除以1000毫秒或每秒60幀(FPS)。 每個幀都會調用JavaFX的EventHandler接口的handle()方法,以更新游戲世界。 假設地,我創建了三個方法updateSprites()checkCollisions()cleanupSprites() ,它們將被調用以處理游戲中的精靈。

final Duration oneFrameAmt = Duration.millis(1000/60);final KeyFrame oneFrame = new KeyFrame(oneFrameAmt,new EventHandler() {@Overridepublic void handle(javafx.event.ActionEvent event) {// update actorsupdateSprites();// check for collisioncheckCollisions();// removed dead thingscleanupSprites();}}); // oneFrame// sets the game world's game loop (Timeline)TimelineBuilder.create().cycleCount(Animation.INDEFINITE).keyFrames(oneFrame).build().play();

上面的代碼片段實際上是創建簡單游戲或動畫所需的全部。 但是,您可能希望將事情帶到一個新的高度。 您可能想要創建一個可以管理精靈和游戲世界狀態的游戲引擎。

游戲引擎

游戲引擎是負責封裝游戲世界,運行游戲循環,管理子畫面,物理等的實用程序或庫的奇特名稱。這實際上是一個小型游戲框架,允許您擴展或重用,因此您無需從頭開始創建2D游戲時必須重新發明輪子。 為了快速前進,我創建了游戲引擎設計的UML類圖。

下面顯示的是圖1 JavaFX Game Engine類圖。

圖1. JavaFX 2游戲引擎設計

在圖1 JavaFX 2游戲引擎設計中,您會注意到GameWorldSpriteManagerSprite這三個類。 GameWorld類負責初始化游戲狀態,執行游戲循環,更新精靈,處理精靈沖突以及清理。 接下來是SpriteManager類,該類負責通過添加,刪除以及其他內部沖突管理來管理Sprite。 最后是Sprite類,它負責維護圖像(演員)的狀態。 在2D世界中,子畫面可以包含對象的速度,旋轉,場景節點或最終在每個周期(關鍵幀/秒)渲染的圖像。

請快速提醒一下UML表示法:

  • 加號“ + ”表示班級成員是公開的。
  • 減號“ ”表示班級成員是私人的
  • 哈希符號“ ”表示類成員受到保護。

游戲世界

下面是GameWorld類的源代碼實現。 單擊以展開。 稍后,您將看到一個類圖,該類圖描述了將擴展GameWorld類的簡單演示游戲(請參閱AtomSmasher)。

package carlfx.gameengine;import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.animation.TimelineBuilder;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.util.Duration;/*** This application demonstrates a JavaFX 2.x Game Loop.* Shown below are the methods which comprise of the fundamentals to a* simple game loop in JavaFX:
**  <strong>initialize()</strong> - Initialize the game world.*  <strong>beginGameLoop()</strong> - Creates a JavaFX Timeline object containing the game life cycle.*  <strong>updateSprites()</strong> - Updates the sprite objects each period (per frame)*  <strong>checkCollisions()</strong> - Method will determine objects that collide with each other.*  <strong>cleanupSprites()</strong> - Any sprite objects needing to be removed from play.** @author cdea*/
public abstract class GameWorld {/** The JavaFX Scene as the game surface */private Scene gameSurface;/** All nodes to be displayed in the game window. */private Group sceneNodes;/** The game loop using JavaFX's <code>Timeline</code> API.*/private static Timeline gameLoop;/** Number of frames per second. */private final int framesPerSecond;/** Title in the application window.*/private final String windowTitle;/*** The sprite manager.*/private final SpriteManager spriteManager = new SpriteManager();/*** Constructor that is called by the derived class. This will* set the frames per second, title, and setup the game loop.* @param fps - Frames per second.* @param title - Title of the application window.*/public GameWorld(final int fps, final String title) {framesPerSecond = fps;windowTitle = title;// create and set timeline for the game loopbuildAndSetGameLoop();}/*** Builds and sets the game loop ready to be started.*/protected final void buildAndSetGameLoop() {final Duration oneFrameAmt = Duration.millis(1000/getFramesPerSecond());final KeyFrame oneFrame = new KeyFrame(oneFrameAmt,new EventHandler() {@Overridepublic void handle(javafx.event.ActionEvent event) {// update actorsupdateSprites();// check for collisioncheckCollisions();// removed dead thingscleanupSprites();}}); // oneFrame// sets the game world's game loop (Timeline)setGameLoop(TimelineBuilder.create().cycleCount(Animation.INDEFINITE).keyFrames(oneFrame).build());}/*** Initialize the game world by update the JavaFX Stage.* @param primaryStage*/public abstract void initialize(final Stage primaryStage);/**Kicks off (plays) the Timeline objects containing one key frame* that simply runs indefinitely with each frame invoking a method* to update sprite objects, check for collisions, and cleanup sprite* objects.**/public void beginGameLoop() {getGameLoop().play();}/*** Updates each game sprite in the game world. This method will* loop through each sprite and passing it to the handleUpdate()* method. The derived class should override handleUpdate() method.**/protected void updateSprites() {for (Sprite sprite:spriteManager.getAllSprites()){handleUpdate(sprite);}}/** Updates the sprite object's information to position on the game surface.* @param sprite - The sprite to update.*/protected void handleUpdate(Sprite sprite) {}/*** Checks each game sprite in the game world to determine a collision* occurred. The method will loop through each sprite and* passing it to the handleCollision()* method. The derived class should override handleCollision() method.**/protected void checkCollisions() {// check other sprite's collisionsspriteManager.resetCollisionsToCheck();// check each sprite against other sprite objects.for (Sprite spriteA:spriteManager.getCollisionsToCheck()){for (Sprite spriteB:spriteManager.getAllSprites()){if (handleCollision(spriteA, spriteB)) {// The break helps optimize the collisions//  The break statement means one object only hits another// object as opposed to one hitting many objects.// To be more accurate comment out the break statement.break;}}}}/*** When two objects collide this method can handle the passed in sprite* objects. By default it returns false, meaning the objects do not* collide.* @param spriteA - called from checkCollision() method to be compared.* @param spriteB - called from checkCollision() method to be compared.* @return boolean True if the objects collided, otherwise false.*/protected boolean handleCollision(Sprite spriteA, Sprite spriteB) {return false;}/*** Sprites to be cleaned up.*/protected void cleanupSprites() {spriteManager.cleanupSprites();}/*** Returns the frames per second.* @return int The frames per second.*/protected int getFramesPerSecond() {return framesPerSecond;}/*** Returns the game's window title.* @return String The game's window title.*/public String getWindowTitle() {return windowTitle;}/*** The game loop (Timeline) which is used to update, check collisions, and* cleanup sprite objects at every interval (fps).* @return Timeline An animation running indefinitely representing the game* loop.*/protected static Timeline getGameLoop() {return gameLoop;}/*** The sets the current game loop for this game world.* @param gameLoop Timeline object of an animation running indefinitely* representing the game loop.*/protected static void setGameLoop(Timeline gameLoop) {GameWorld.gameLoop = gameLoop;}/*** Returns the sprite manager containing the sprite objects to* manipulate in the game.* @return SpriteManager The sprite manager.*/protected SpriteManager getSpriteManager() {return spriteManager;}/*** Returns the JavaFX Scene. This is called the game surface to* allow the developer to add JavaFX Node objects onto the Scene.* @return*/public Scene getGameSurface() {return gameSurface;}/*** Sets the JavaFX Scene. This is called the game surface to* allow the developer to add JavaFX Node objects onto the Scene.* @param gameSurface The main game surface (JavaFX Scene).*/protected void setGameSurface(Scene gameSurface) {this.gameSurface = gameSurface;}/*** All JavaFX nodes which are rendered onto the game surface(Scene) is* a JavaFX Group object.* @return Group The root containing many child nodes to be displayed into* the Scene area.*/public Group getSceneNodes() {return sceneNodes;}/*** Sets the JavaFX Group that will hold all JavaFX nodes which are rendered* onto the game surface(Scene) is a JavaFX Group object.* @param sceneNodes The root container having many children nodes* to be displayed into the Scene area.*/protected void setSceneNodes(Group sceneNodes) {this.sceneNodes = sceneNodes;}}

精靈管理器

Sprite Manager類是幫助程序類,可幫助游戲循環跟蹤Sprite。 通常,一個精靈管理器將包含所有精靈,每個精靈都包含一個JavaFX節點,該節點顯示在“場景”圖上。
下面顯示的是源代碼。 單擊以展開。

package carlfx.gameengine;import java.util.*;/*** Sprite manager is responsible for holding all sprite objects, and cleaning up* sprite objects to be removed. All collections are used by the JavaFX* application thread. During each cycle (animation frame) sprite management* occurs. This assists the user of the API to not have to create lists to* later be garbage collected. Should provide some performance gain.* @author cdea*/
public class SpriteManager {/** All the sprite objects currently in play */private final static List GAME_ACTORS = new ArrayList<>();/** A global single threaded list used to check collision against other* sprite objects.*/private final static List CHECK_COLLISION_LIST = new ArrayList<>();/** A global single threaded set used to cleanup or remove sprite objects* in play.*/private final static Set CLEAN_UP_SPRITES = new HashSet<>();/** */public List getAllSprites() {return GAME_ACTORS;}/*** VarArgs of sprite objects to be added to the game.* @param sprites*/public void addSprites(Sprite... sprites) {GAME_ACTORS.addAll(Arrays.asList(sprites));}/*** VarArgs of sprite objects to be removed from the game.* @param sprites*/public void removeSprites(Sprite... sprites) {GAME_ACTORS.removeAll(Arrays.asList(sprites));}/** Returns a set of sprite objects to be removed from the GAME_ACTORS.* @return CLEAN_UP_SPRITES*/public Set getSpritesToBeRemoved() {return CLEAN_UP_SPRITES;}/*** Adds sprite objects to be removed* @param sprites varargs of sprite objects.*/public void addSpritesToBeRemoved(Sprite... sprites) {if (sprites.length > 1) {CLEAN_UP_SPRITES.addAll(Arrays.asList((Sprite[]) sprites));} else {CLEAN_UP_SPRITES.add(sprites[0]);}}/*** Returns a list of sprite objects to assist in collision checks.* This is a temporary and is a copy of all current sprite objects* (copy of GAME_ACTORS).* @return CHECK_COLLISION_LIST*/public List getCollisionsToCheck() {return CHECK_COLLISION_LIST;}/*** Clears the list of sprite objects in the collision check collection* (CHECK_COLLISION_LIST).*/public void resetCollisionsToCheck() {CHECK_COLLISION_LIST.clear();CHECK_COLLISION_LIST.addAll(GAME_ACTORS);}/*** Removes sprite objects and nodes from all* temporary collections such as:* CLEAN_UP_SPRITES.* The sprite to be removed will also be removed from the* list of all sprite objects called (GAME_ACTORS).*/public void cleanupSprites() {// remove from actors listGAME_ACTORS.removeAll(CLEAN_UP_SPRITES);// reset the clean up spritesCLEAN_UP_SPRITES.clear();}
}

雪碧

Sprite類表示要顯示在JavaFX Scene圖形上的圖像或節點。 在2D游戲中,子畫面將包含其他信息,例如,對象在場景區域中移動時對象的速度。 游戲循環將在關鍵幀的每個時間間隔調用update()和collide()方法。
下面顯示的是源代碼。 單擊以展開。

package carlfx.gameengine;import java.util.ArrayList;
import java.util.List;
import javafx.animation.Animation;
import javafx.scene.Node;/*** The Sprite class represents a image or node to be displayed.* In a 2D game a sprite will contain a velocity for the image to* move across the scene area. The game loop will call the update()* and collide() method at every interval of a key frame. A list of* animations can be used during different situations in the game* such as rocket thrusters, walking, jumping, etc.* @author cdea*/
public abstract class Sprite {/** Animation for the node */public List animations = new ArrayList<>();/** Current display node */public Node node;/** velocity vector x direction */public double vX = 0;/** velocity vector y direction */public double vY = 0;/** dead? */public boolean isDead = false;/*** Updates this sprite object's velocity, or animations.*/public abstract void update();/*** Did this sprite collide into the other sprite?** @param other - The other sprite.* @return*/public boolean collide(Sprite other) {return false;}
}

JavaFX 2游戲循環演示– Atom Smasher

ew! 如果您已經走了這么遠,那么您就是一個勇敢的靈魂。 讓我們休息一下,嘗試使用上面的游戲引擎創建的演示。
下面顯示的是Java Webstart按鈕,用于啟動游戲演示。 稍后,您將看到設計和源代碼,詳細說明了它是如何創建的。

要求:

  • Java 7或更高版本
  • JavaFX 2.0.2 2.1或更高版本
  • Windows XP或更高版本(應該很快可用于Linux / MacOS)
AtomSmasher游戲循環演示
演示版

GameLoopPart2設計

下面是一個名為Atom Smasher的游戲演示的類圖,它使用前面提到的游戲引擎框架。
下面顯示的是圖2 Atom Smasher類圖。

圖2. Atom Smasher類圖

GameLoopPart2

GameLoopPart2是運行游戲的驅動程序或主要JavaFX應用程序。 這將創建一個要初始化的GameWorld對象,并開始游戲循環。
下面顯示的是源代碼。 單擊以展開。

package carlfx;import carlfx.gameengine.GameWorld;
import javafx.application.Application;
import javafx.stage.Stage;/*** The main driver of the game.* @author cdea*/
public class GameLoopPart2 extends Application {GameWorld gameWorld = new AtomSmasher(60, "JavaFX 2 GameTutorial Part 2 - Game Loop");/*** @param args the command line arguments*/public static void main(String[] args) {launch(args);}@Overridepublic void start(Stage primaryStage) {// setup title, scene, stats, controls, and actors.gameWorld.initialize(primaryStage);// kick off the game loopgameWorld.beginGameLoop();// display windowprimaryStage.show();}}

原子粉碎機

AtomSmasher是GameWorld類的派生類。 它創建了許多以隨機速度,顏色和位置進行動畫處理的球。 按鈕控件使用戶可以生成更多的“原子”(JavaFX Circle節點)。 當每個原子相互碰撞時,它們將調用implode()方法,該方法生成淡入淡出過渡動畫。 您將注意到,僅通過實現initialize(),handleUpdate(),handleCollision()cleanupSprites()方法即可輕松實現此游戲。 一旦實現,游戲引擎就會完成其余的工作。 initialize()方法為用戶創建按鈕控件。 要更新精靈的位置或更改游戲狀態,您將實現handleUpdate()方法。 要比較所有精靈相互碰撞的情況,您將實現handleCollision() 。 游戲循環生命周期的最后一部分是清理精靈。 清理意味著更新精靈管理器并更新JavaFX Scene(刪除節點)。
下面顯示的是源代碼。 單擊以展開。

package carlfx;import carlfx.gameengine.GameWorld;
import carlfx.gameengine.Sprite;
import java.util.Random;
import javafx.animation.Timeline;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ButtonBuilder;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBoxBuilder;
import javafx.scene.layout.VBox;
import javafx.scene.layout.VBoxBuilder;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import static javafx.animation.Animation.Status.RUNNING;
import static javafx.animation.Animation.Status.STOPPED;/*** This is a simple game world simulating a bunch of spheres looking* like atomic particles colliding with each other. When the game loop begins* the user will notice random spheres (atomic particles) floating and* colliding. The user is able to press a button to generate more* atomic particles. Also, the user can freeze the game.** @author cdea*/
public class AtomSmasher extends GameWorld {/** Read only field to show the number of sprite objects are on the field*/private final static Label NUM_SPRITES_FIELD = new Label();public AtomSmasher(int fps, String title){super(fps, title);}/*** Initialize the game world by adding sprite objects.* @param primaryStage*/@Overridepublic void initialize(final Stage primaryStage) {// Sets the window titleprimaryStage.setTitle(getWindowTitle());// Create the scenesetSceneNodes(new Group());setGameSurface(new Scene(getSceneNodes(), 640, 580));primaryStage.setScene(getGameSurface());// Create many spheresgenerateManySpheres(150);// Display the number of spheres visible.// Create a button to add more spheres.// Create a button to freeze the game loop.final Timeline gameLoop = getGameLoop();VBox stats = VBoxBuilder.create().spacing(5).translateX(10).translateY(10).children(HBoxBuilder.create().spacing(5).children(new Label("Number of Particles: "), // show no. particlesNUM_SPRITES_FIELD).build(),// button to build more spheresButtonBuilder.create().text("Regenerate").onMousePressed(new EventHandler() {@Overridepublic void handle(MouseEvent arg0) {generateManySpheres(150);}}).build(),// button to freeze game loopButtonBuilder.create().text("Freeze/Resume").onMousePressed(new EventHandler() {@Overridepublic void handle(MouseEvent arg0) {switch (gameLoop.getStatus()) {case RUNNING:gameLoop.stop();break;case STOPPED:gameLoop.play();break;}}}).build()).build(); // (VBox) stats on children// lay down the controlsgetSceneNodes().getChildren().add(stats);}/*** Make some more space spheres (Atomic particles)*/private void generateManySpheres(int numSpheres) {Random rnd = new Random();Scene gameSurface = getGameSurface();for (int i=0; i (gameSurface.getWidth() - (circle.getRadius() * 2))) {newX = gameSurface.getWidth() - (circle.getRadius()  * 2);}// check for the bottom of screen the height newY is greater than height// minus radius times 2(height of sprite)double newY = rnd.nextInt((int) gameSurface.getHeight());if (newY > (gameSurface.getHeight() - (circle.getRadius() * 2))) {newY = gameSurface.getHeight() - (circle.getRadius() * 2);}circle.setTranslateX(newX);circle.setTranslateY(newY);circle.setVisible(true);circle.setId(b.toString());// add to actors in play (sprite objects)getSpriteManager().addSprites(b);// add sprite'sgetSceneNodes().getChildren().add(0, b.node);}}/*** Each sprite will update it's velocity and bounce off wall borders.* @param sprite - An atomic particle (a sphere).*/@Overrideprotected void handleUpdate(Sprite sprite) {if (sprite instanceof Atom) {Atom sphere = (Atom) sprite;// advance the spheres velocitysphere.update();// bounce off the walls when outside of boundariesif (sphere.node.getTranslateX() > (getGameSurface().getWidth()  -sphere.node.getBoundsInParent().getWidth()) ||sphere.node.getTranslateX() < 0 ) {                 sphere.vX = sphere.vX * -1;             }             if (sphere.node.getTranslateY() > getGameSurface().getHeight()-sphere.node.getBoundsInParent().getHeight() ||sphere.node.getTranslateY() < 0) {sphere.vY = sphere.vY * -1;}}}/*** How to handle the collision of two sprite objects. Stops the particle* by zeroing out the velocity if a collision occurred.* @param spriteA* @param spriteB* @return*/@Overrideprotected boolean handleCollision(Sprite spriteA, Sprite spriteB) {if (spriteA.collide(spriteB)) {((Atom)spriteA).implode(this);((Atom)spriteB).implode(this);getSpriteManager().addSpritesToBeRemoved(spriteA, spriteB);return true;}return false;}/*** Remove dead things.*/@Overrideprotected void cleanupSprites() {// removes from the scene and backend storesuper.cleanupSprites();// let user know how many sprites are showing.NUM_SPRITES_FIELD.setText(String.valueOf(getSpriteManager().getAllSprites().size()));}
}

原子

Atom類是Sprite類的擴展。 原子是一個精靈,看起來像是在整個場景中移動的球形物體。 原子將具有隨機的半徑,顏色和速度。 當每個原子精靈與另一個原子碰撞時,它們將為淡入淡出過渡設置動畫(implode()方法)。
下面顯示的是源代碼。 單擊以展開。

package carlfx;import carlfx.gameengine.GameWorld;
import carlfx.gameengine.Sprite;
import javafx.animation.FadeTransitionBuilder;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.paint.Color;
import javafx.scene.paint.RadialGradient;
import javafx.scene.paint.RadialGradientBuilder;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Circle;
import javafx.scene.shape.CircleBuilder;
import javafx.util.Duration;/*** A spherical looking object (Atom) with a random radius, color, and velocity.* When two atoms collide each will fade and become removed from the scene. The* method called implode() implements a fade transition effect.** @author cdea*/
public class Atom extends Sprite {public Atom(double radius, Color fill) {Circle sphere = CircleBuilder.create().centerX(radius).centerY(radius).radius(radius).cache(true).build();RadialGradient rgrad = RadialGradientBuilder.create().centerX(sphere.getCenterX() - sphere.getRadius() / 3).centerY(sphere.getCenterY() - sphere.getRadius() / 3).radius(sphere.getRadius()).proportional(false).stops(new Stop(0.0, fill), new Stop(1.0, Color.BLACK)).build();sphere.setFill(rgrad);// set javafx node to a circlenode = sphere;}/*** Change the velocity of the atom particle.*/@Overridepublic void update() {node.setTranslateX(node.getTranslateX() + vX);node.setTranslateY(node.getTranslateY() + vY);}@Overridepublic boolean collide(Sprite other) {if (other instanceof Atom) {return collide((Atom)other);}return false;}/*** When encountering another Atom to determine if they collided.* @param other Another atom* @return boolean true if this atom and other atom has collided,* otherwise false.*/private boolean collide(Atom other) {// if an object is hidden they didn't collide.if (!node.isVisible() ||!other.node.isVisible() ||this == other) {return false;}// determine it's sizeCircle otherSphere = other.getAsCircle();Circle thisSphere =  getAsCircle();double dx = otherSphere.getTranslateX() - thisSphere.getTranslateX();double dy = otherSphere.getTranslateY() - thisSphere.getTranslateY();double distance = Math.sqrt( dx * dx + dy * dy );double minDist  = otherSphere.getRadius() + thisSphere.getRadius() + 3;return (distance < minDist);}/*** Returns a node casted as a JavaFX Circle shape.* @return Circle shape representing JavaFX node for convenience.*/public Circle getAsCircle() {return (Circle) node;}/*** Animate an implosion. Once done remove from the game world* @param gameWorld - game world*/public void implode(final GameWorld gameWorld) {vX = vY = 0;FadeTransitionBuilder.create().node(node).duration(Duration.millis(300)).fromValue(node.getOpacity()).toValue(0).onFinished(new EventHandler() {@Overridepublic void handle(ActionEvent arg0) {isDead = true;gameWorld.getSceneNodes().getChildren().remove(node);}}).build().play();}
}

結論

希望您有機會了解游戲循環的基礎,并在以后通過實施強大的游戲引擎來應用這些知識。 雖然,我簡要提到了碰撞,但我將其保存在這些教程的第4部分中。 請繼續關注第3部分,我們將在此使用鍵盤或鼠標進行輸入。 隨時嘗試。 讓我知道你的想法。

要獲取源代碼,請使用瀏覽器中的“ 將鏈接另存為 ”選項, 將鏈接下載到以下jar文件中。 如果您使用的是Windows系統,則可以將擴展名從jar更改為zip以便輕松擴展。 它將包含帶有源代碼的目錄“ src ”。

源代碼位置

http://www.jroller.com/carldea/resource/javafx2.0_games/part2source_code.jar

源代碼的發布版本位于GitHub上,名為( JFXGen ),供您克隆并復制到您的心中內容(可以在其中用于自己的項目)。 請享用。

https://github.com/carldea/JFXGen

git clonegit@github.com:carldea / JFXGen.git

參考:來自我們的JCG合作伙伴 Carl Dea的JavaFX 2 GameTutorial第2部分 ,位于Carl's FX Blog博客上。


翻譯自: https://www.javacodegeeks.com/2012/05/javafx-2-gametutorial-part-2.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/372796.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/372796.shtml
英文地址,請注明出處:http://en.pswp.cn/news/372796.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

sqlyog連接mysql教程_如何用SQLyog實現遠程連接MySQL

SQLyog客戶端&#xff0c;用root用戶遠程鏈接MySQL時&#xff0c;提示ldquo;訪問被拒絕rdquo;&#xff0c;在網上搜索了一下原因。原來是MySQL沒有授權其遠程鏈1&#xff0c;SQLyog客戶端&#xff0c;&#xff0c;用root用戶遠程鏈接MySQL時&#xff0c;提示“訪問被拒絕”&…

動態SQL+變量綁定:解決ORA-01704: 字符串文字太長的問題

最近在做一個ESB項目&#xff0c;有一個trigger里面執行動態SQL的時候報錯&#xff1a; ORA-01704: 字符串文字太長 經檢查發現SQL里面有個字段是clob類型&#xff0c;內容長度4009&#xff0c;在oracle里面&#xff0c; 一對引號內的字符長度如果超過4000&#xff0c;就會報OR…

JavaME:Google靜態地圖API

無論您是需要基于位置的應用程序的地圖還是只是出于娛樂目的&#xff0c;都可以使用有史以來最簡單的方法&#xff1a;Google Static Maps API。 在這篇文章中&#xff0c;我們將看到如何從緯度和經度獲得地圖作為圖像。 可以使用Location API獲得緯度和經度&#xff0c;我們將…

在ASP.NET中實現OAuth2.0(一)之了解OAuth

1、什么是OAuth2.0 是一個開放授權標準&#xff0c;允許用戶讓第三方應用訪問該用戶在某一個網站或平臺上的私密資源&#xff08;如照片、視頻、聯系人等&#xff09;&#xff0c;而無須將用戶名和密碼提供給第三方應用 2、OAuth2.0授權模式 授權碼模式&#xff08;authorizati…

mysql日期條件如何應用_MySQL如何使用時間作為判斷條件

背景&#xff1a;在開發過程中&#xff0c;我們經常需要根據時間作為判斷條件來查詢數據&#xff0c;例如&#xff1a;當月&#xff0c;當日&#xff0c;當前小時&#xff0c;幾天內......1. 當月我們只需要使用一個mysql的month(date)函數即可實現。(注意判斷年份)month(date)…

深入探討JS中的數組排序函數sort()和reverse()

最近在研究Javascript發現了其中一些比較靈異的事情。有點讓人感到無語比如&#xff1a; alert(typeof( NaN NaN));//結果為假。 alert(typeof( NaN ! NaN));//結果為真。 嘿嘿&#xff0c;當然這個不是這篇文章要討論的!!開始我們的正文 首先&#xff0c;我們來看一下JS中sor…

帶有謂詞的Java中的功能樣式-第1部分

您一直在聽到將要席卷全球的函數式編程&#xff0c;而您仍然堅持使用普通Java&#xff1f; 不用擔心&#xff0c;因為您已經可以在日常Java中添加一些功能樣式。 此外&#xff0c;它很有趣&#xff0c;可以節省許多代碼行并減少錯誤。 什么是謂詞&#xff1f; 實際上&#xff…

寶塔添加多占點_寶塔面板啟用WordPress多站點子域名、子目錄

其實在很早以前&#xff0c;陌小雨就聽說了 wordpress 的多站點功能&#xff0c;不過因為不清楚&#xff0c;所以懶得折騰&#xff0c;這不這幾天閑著蛋疼&#xff0c;好好研究了下這玩意&#xff0c;用起來的感覺還是相當不錯的&#xff0c;總結起來就是如果你準備開始用 word…

centos 6.5下安裝文件上傳下載服務

centos 6.5下安裝文件上傳下載服務 由于每次在CentOS中要下載一些配置文件到物理機&#xff0c;和上傳一些文件到服務器&#xff0c;導致來回的開啟ftp軟件有點麻煩&#xff0c;這里我們可以使用文件上傳下載服務&#xff0c;來解決上傳和下載的問題。 1.登錄服務器 2.執行命令…

Jenkins 入門系列--jenkins 介紹

第一章 Jenkins是什么&#xff1f; Jenkins 是一個可擴展的持續集成引擎。 主要用于&#xff1a; l 持續、自動地構建/測試軟件項目。 l 監控一些定時執行的任務。Jenkins擁有的特性包括&#xff1a; l 易于安裝-只要把jenkins.war部署到servlet容器&#xff0c;不需要數據庫支…

在方法參數上使用final關鍵字

經過一些自己的混淆&#xff0c;最終博客方法的具體含義&#xff08;最終聲明的方法參數&#xff09;將對此博客條目進行澄清。 至少可以將方法參數上的final關鍵字視為Java編譯器的指示符&#xff0c;表明該參數不能重新分配給另一個引用。 Java參數處理始終是“按值調用” &a…

PHP MySQLi 增刪改查

最近幾天&#xff0c;我們一直在學習利用MySQLi訪問數據庫并對其中的數據進行操作。今天給大家展現一個完整的例子&#xff0c;我們來制作一個新聞發布系統&#xff0c;利用MySQLi來操作數據庫&#xff0c;實現對新聞的添加、修改、刪除、查詢等基本功能。&#xff08;以下代碼…

20162303《程序設計與數據結構》第一周學習總結

學號 2016-2017-2 《程序設計與數據結構》第1周學習總結 教材學習內容總結 本周學習了基本的JAVA知識&#xff0c;雖然比較基礎&#xff0c;但是在實際過程中還是出現了許許多多的問題&#xff0c;代碼一遍遍的敲錯&#xff0c;又一遍遍的修改&#xff0c;剛開始甚至不會切換模…

Java EE與NoSQL的未來

自一段時間以來&#xff0c;我一直在關注NoSQL的近期發展勢頭&#xff0c;似乎這個流行語也引起了企業Java界的某種關注。 即EclipseLink 2.4開始支持MongoDB和Oracle NoSQL 。 將EclipseLink作為JPA參考實現&#xff0c;您可能想知道這對Java EE 7意味著什么。這里簡短說明&am…

【C/C++開發】C語言實現函數可變參數

函數原型: int printf(const char *format[,argument]...) 返 回 值: 成功則返回實際輸出的字符數&#xff0c;失敗返回-1. 函數說明: 在printf()函數中&#xff0c;format后面的參數個數不確定&#xff0c;且類型也不確定&#xff0c;這些參數都存放在棧內.調用…

java postgresql json_java – 將PostgreSQL JSON列映射到Hibernate值類...

See PgJDBC bug #265.PostgreSQL對數據類型轉換過于嚴格,非常嚴格.它不會隱式地將文本轉換為類似文本的值,例如xml和json.解決此問題的嚴格正確方法是編寫使用JDBC setObject方法的自定義Hibernate映射類型.這可能有點麻煩,所以你可能只想通過創建一個較弱的強制轉換來使Postgr…

面向接口編程詳解(三)——模式研究

通過前面兩篇&#xff0c;我想各位朋友對“面向接口編程”的思想有了一定認識&#xff0c;并通過第二篇的例子&#xff0c;獲得了一定的直觀印象。但是&#xff0c;第二篇中的例子旨在展示面向接口編程的實現方法&#xff0c;比較簡單&#xff0c;不能體現出面向接口編程的優勢…

錯誤學習:Java + OSGi

最近&#xff0c;我致力于在OSGi環境中使Apache Hive工作。 雖然沒有被證明是小菜一碟&#xff08;軟件對嗎&#xff1f;。。為什么我不感到驚訝&#xff1f; &#xff09;&#xff0c;它引導我解決了各種Java和OSGi錯誤。 在這里&#xff0c;我列出了其中一些讓我有些吃力的東…

iOS多Targets管理

序言&#xff1a; 個人不善于寫東西&#xff0c;就直奔主題了。 其實今天會注意到多targets這個東西&#xff0c;是因為在學習一個第三方庫FBMemoryProfiler的時候&#xff0c;用到了&#xff0c;所以就搜索了一些相關資料&#xff0c;就在這里記錄一下。 可能每個人都會遇到這…

優化的34條定律

1.Minimize HTTP Requests 減少HTTP請求 圖片、css、script、flash等等這些都會增加http請求數&#xff0c;減少這些元素的數量就能減少響應時間。把多個JS、CSS在可能的情況下寫進一個文件&#xff0c;頁面里直接寫入圖片也是不好的做法&#xff0c;應該寫進CSS里&#xff0c;…