日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

javafx2_JavaFX 2 GameTutorial第3部分

發(fā)布時(shí)間:2023/12/3 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 javafx2_JavaFX 2 GameTutorial第3部分 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

javafx2

介紹

?他是與一個(gè)六個(gè)部分組成的系列的第3部分的JavaFX 2游戲教程。 如果您錯(cuò)過(guò)了第1部分第2部分 ,我建議您在開(kāi)始本教程之前仔細(xì)閱讀它們。 回顧第2部分,我討論了游戲循環(huán)的內(nèi)部工作原理,其中我們使用動(dòng)畫(huà)(JavaFX Timeline )更新精靈,檢查碰撞并清理游戲世界元素,然后我被迫創(chuàng)建一個(gè)簡(jiǎn)單的游戲引擎來(lái)簡(jiǎn)化游戲過(guò)程開(kāi)發(fā)2D游戲。 本教程是關(guān)于使用游戲引擎并使用鼠標(biāo)和鍵盤來(lái)演示輸入的。在本教程中,我將為您提供一些背景歷史記錄,事件處理基礎(chǔ)知識(shí),演示游戲以及最終的實(shí)現(xiàn)。 該演示將展示一艘能夠在浮球上射擊的太空船,類似于電子游戲“ 小行星” 。 如果要運(yùn)行演示,請(qǐng)向下滾動(dòng)并單擊下面的WebStart按鈕。 在啟動(dòng)游戲之前,請(qǐng)先閱讀要求。

歷史

在上世紀(jì)80年代那年小時(shí)候,這里有拱廊中心,保齡球館,披薩店和7家11家商店,我花了大量時(shí)間在玻璃展示區(qū)擺上四分之一的空間,以便在玻璃陳列區(qū)旁邊目前正在玩激烈的電子游戲的家伙。 當(dāng)每個(gè)人都擁擠在他身邊時(shí),看著他擊敗了所有的最高分?jǐn)?shù),當(dāng)我們看到偉大時(shí),我們所有人都為之歡呼。 Atari Inc.創(chuàng)建的“ 小行星 ”是其中一款非常出色的街機(jī)游戲(可訪問(wèn)visit play.vg進(jìn)行播放)

說(shuō)到高分,并不是很多人都知道,但是斯科特·賽峰 ( Scott Safran) (1967年2月3日至1989年3月27日)是有史以來(lái)玩小行星的最高記錄。 他在當(dāng)?shù)氐?-11便利店里連續(xù)玩了大約二十個(gè)小時(shí)才達(dá)到了這個(gè)目的。 在生命的后期(還很小的時(shí)候),他在1989年3月27日的一場(chǎng)不幸事故中去世了。為了紀(jì)念Scott,我創(chuàng)建了本教程。 我希望人們會(huì)記得他是有史以來(lái)最偉大的視頻游戲玩家之一(我敢肯定,他也是個(gè)好兄弟)。

關(guān)于游戲,小行星基于矢量的硬件用于渲染形狀,而不是柵格圖形(位圖)。 另外,使用光柵圖形創(chuàng)建了Midway Inc.的Space Invaders。 令人興奮的是,有關(guān)JavaFX 2.x的討論能夠使用稱為JavaFX Canvas Node的位圖,該位圖可以提供柵格圖形以使開(kāi)發(fā)人員能夠利用像素級(jí)操作。 這些拱廊風(fēng)格的機(jī)柜的構(gòu)造讓我仍然感到驚訝,這些機(jī)柜容納了CRT,主板和諸如按鈕,操縱桿,跟蹤球和旋鈕之類的控制器(輸入設(shè)備)。

經(jīng)典街機(jī)游戲

以下是一些具有多種輸入設(shè)備的經(jīng)典街機(jī)游戲

  • 僅按鈕 :小行星,太空侵略者,翻錄,鳳凰
  • 僅操縱桿 :Q * bert,PacMan
  • 僅旋鈕 :Pong
  • 僅軌跡球 :大理石瘋狂
  • 操縱桿和按鈕 : 星球大戰(zhàn) ,桿位,間諜獵人
  • 自行車車把 :特技自行車,紙男孩
  • 按鈕和油門桿 :月球著陸器
  • 潛望鏡和按鈕 :海狼
  • 按鈕和軛 :Tron,戰(zhàn)區(qū)
  • 按鈕,旋鈕和撥叉 :《星際迷航》,《暴風(fēng)雨》
  • 按鈕和軌跡球 :導(dǎo)彈司令部,enti
  • 按鈕和操縱桿 :防御者,護(hù)手,蛙人,喬斯特,狂風(fēng),馬里奧兄弟,金剛,西捷,加拉加,功夫,魂斗羅,街頭霸王,雙龍,忍者魔法(或精神),挖土機(jī),龍之巢穴。

輸入/(鼠標(biāo),鍵盤)

拋開(kāi)過(guò)去,我們目前遇到了新型輸入設(shè)備,例如觸摸屏,加速度計(jì),紅外接收器,照相機(jī)等。當(dāng)今臺(tái)式機(jī)上最常見(jiàn)的輸入是鼠標(biāo)和鍵盤。 當(dāng)然,觸摸屏已廣泛應(yīng)用于移動(dòng)設(shè)備和平板電腦,但是在本教程中,我們將僅著眼于“ 鼠標(biāo) ”和“ 鍵盤 ”作為控制游戲的輸入。 基于JavaFX路線圖 ,正在進(jìn)行多點(diǎn)觸摸輸入 (在您閱讀本文時(shí),它已經(jīng)實(shí)現(xiàn)了)。

偵聽(tīng)鍵盤和鼠標(biāo)事件時(shí),JavaFX 2.x具有許多類型的事件,這些事件為開(kāi)發(fā)人員提供了機(jī)會(huì)來(lái)實(shí)現(xiàn)偵聽(tīng)觸發(fā)事件的事件處理程序。 用于節(jié)點(diǎn)或場(chǎng)景的JavaFX 2.x API包含許多帶有前綴“ on”的方法,例如onMousePressProperty()或onKeyPressProperty()方法。 無(wú)論何時(shí)實(shí)現(xiàn)這些方法,您都將使用Java的泛型類型簡(jiǎn)單地實(shí)現(xiàn)handle()方法,以指定要傳遞給查詢的事件對(duì)象。 因此,當(dāng)實(shí)例化EventHandler <MouseEvent>類時(shí),將實(shí)現(xiàn)一個(gè)handle()方法,該方法將MouseEvent作為要傳入的參數(shù)。

下面顯示的代碼段將兩個(gè)事件處理程序添加到JavaFX Scene。 第一個(gè)處理程序?qū)㈨憫?yīng)鼠標(biāo)事件。 在我們的簡(jiǎn)單游戲中,當(dāng)發(fā)生鼠標(biāo)按下時(shí),該處理程序?qū)⑼ㄟ^(guò)發(fā)射武器或在飛船上進(jìn)行響應(yīng)。 下面顯示的第二個(gè)處理程序?qū)㈨憫?yīng)按鍵事件。 當(dāng)按下一個(gè)鍵時(shí),此處理程序?qū)⑻幚鞬eyEvent對(duì)象。 在我們的游戲中,按鍵“ 2 ”會(huì)將您的輔助武器變成更大的沖擊波(更慢)。 其他任何擊鍵將默認(rèn)返回到較小的沖擊波(更快)。

移動(dòng)船和火武器

EventHandler fireOrMove = new EventHandler<MouseEvent>() {@Overridepublic void handle(MouseEvent event) {if (event.getButton() == MouseButton.PRIMARY) {// Fire weapon systems. On Windows left mouse button} else if (event.getButton() == MouseButton.SECONDARY) {// Navigate ship thrust. On Windows right mouse button}}};primaryStage.getScene().setOnMousePressed(fireOrMove);

更換武器

EventHandler changeWeapons = new EventHandler<KeyEvent>() {@Overridepublic void handle(KeyEvent event) {myShip.changeWeapon(event.getCode());}};primaryStage.getScene().setOnKeyPressed(changeWeapons);

JavaFX 2輸入演示–“擴(kuò)展”

簡(jiǎn)單的演示游戲?qū)⑹切请H爭(zhēng)霸和小行星之間的混合體。 使用鼠標(biāo)導(dǎo)航飛船時(shí),其外觀類似于《星際爭(zhēng)霸》的《 戰(zhàn)艦巡洋艦》 。 如果您還記得本系列文章的第2部分,那么我創(chuàng)建了球體反彈。 我重用了第2部分“原子粉碎機(jī)”中的代碼,像著名的街機(jī)游戲一樣充當(dāng)小行星。 除了在這個(gè)游戲中,您根本不會(huì)受到傷害。 目的是在您的武器擊中其他撞擊沖擊力的球體之前向它們發(fā)射武器。 由于這是一個(gè)簡(jiǎn)單的教程,甚至是處于開(kāi)發(fā)初期的游戲,因此該游戲無(wú)法跟蹤得分。 我鼓勵(lì)您去GitHub下載代碼并增強(qiáng)游戲。 稍后,您將看到一個(gè)高級(jí)UML類圖,該圖描述了組成游戲的類。 為了簡(jiǎn)潔起見(jiàn),我不會(huì)詳細(xì)介紹每個(gè)類,但是我相信您會(huì)在這里訪問(wèn)GitHub: https : //github.com/carldea/JFXGen,以獲取所有演示和源代碼。

要求

  • Java 7或更高版本
  • JavaFX 2.1或更高版本
  • Windows XP或更高版本(應(yīng)該很快可用于Linux / MacOS)

一個(gè)簡(jiǎn)單的小行星類型游戲,名為“ The Expanse”。

說(shuō)明:

  • 右鍵單擊(在Windows上)以飛船。
  • 鼠標(biāo)左鍵單擊(Windows鼠標(biāo)左鍵)開(kāi)火。
  • 按鍵'2? 變成大型導(dǎo)彈。(藍(lán)色圓形彈丸)
  • 其他按鍵默認(rèn)為較小的導(dǎo)彈。 (紅色圓形彈丸)
第三部分“廣闊”

下面顯示的是高級(jí)類圖的圖2,該圖描述了為此演示創(chuàng)建的所有類。 GameWorld和Sprite類是上一篇文章的游戲引擎的一部分。 其余的類是新的,它們構(gòu)成了本教程的演示。

InputPart3

InputPart3是運(yùn)行游戲的驅(qū)動(dòng)程序或主要JavaFX應(yīng)用程序。 這將創(chuàng)建一個(gè)要初始化的GameWorld對(duì)象,并開(kāi)始游戲循環(huán)。
下面顯示的是主要JavaFX應(yīng)用程序Input Part3的源代碼。

import carlfx.gameengine.GameWorld; package carlfx.demos.navigateship;import javafx.application.Application; import javafx.stage.Stage;/*** The main driver of the game.* @author cdea*/ public class InputPart3 extends Application {GameWorld gameWorld = new TheExpanse(59, "JavaFX 2 GameTutorial Part 3 - Input");/*** @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();}}

廣袤

TheExpanse類繼承自GameWorld類。 這實(shí)際上與第2部分的“ AtomSmasher”相同,在該部分中,驅(qū)動(dòng)程序應(yīng)用程序?qū)⒄{(diào)用GameWorld實(shí)例的initialize()方法來(lái)設(shè)置所有游戲元素,例如inputspaceship和那些討厭的浮動(dòng)球體 。 此類任務(wù)是確保小行星或球體從墻壁反彈,并清除到達(dá)屏幕邊緣的所有導(dǎo)彈。 負(fù)責(zé)任的主要是管理資產(chǎn)并創(chuàng)建新級(jí)別。 當(dāng)沒(méi)有移動(dòng)物體并且玩家在屏幕上移動(dòng)飛船時(shí),將為下一個(gè)級(jí)別生成新的球體。該類的關(guān)鍵是setupInput()方法。 我創(chuàng)建的setupInput()方法負(fù)責(zé)建立事件處理程序,使其能夠偵聽(tīng)鍵事件和鼠標(biāo)事件。

package carlfx.demos.navigateship;import carlfx.gameengine.GameWorld; import carlfx.gameengine.Sprite; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.Label; import javafx.scene.control.TextField; import javafx.scene.input.KeyEvent; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.stage.Stage;import java.util.Random;/*** 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 will navigate his/her ship by right clicking the mouse to* trust forward and left click to fire weapon to atoms.** @author cdea*/ public class TheExpanse extends GameWorld {// mouse pt labelLabel mousePtLabel = new Label();// mouse press pt labelLabel mousePressPtLabel = new Label();TextField xCoordinate = new TextField("234");TextField yCoordinate = new TextField("200");Button moveShipButton = new Button("Rotate ship");Ship myShip = new Ship();public TheExpanse(int fps, String title) {super(fps, title);}/*** Initialize the game world by adding sprite objects.** @param primaryStage The game window or primary stage.*/@Overridepublic void initialize(final Stage primaryStage) {// Sets the window titleprimaryStage.setTitle(getWindowTitle());//primaryStage.setFullScreen(true);// Create the scenesetSceneNodes(new Group());setGameSurface(new Scene(getSceneNodes(), 800, 600));getGameSurface().setFill(Color.BLACK);primaryStage.setScene(getGameSurface());// Setup Game inputsetupInput(primaryStage);// Create many spheresgenerateManySpheres(2);// 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();getSpriteManager().addSprites(myShip);getSceneNodes().getChildren().add(myShip.node);// mouse pointVBox stats = new VBox();HBox row1 = new HBox();mousePtLabel.setTextFill(Color.WHITE);row1.getChildren().add(mousePtLabel);HBox row2 = new HBox();mousePressPtLabel.setTextFill(Color.WHITE);row2.getChildren().add(mousePressPtLabel);stats.getChildren().add(row1);stats.getChildren().add(row2);// mouse pointHBox enterCoord1 = new HBox();enterCoord1.getChildren().add(xCoordinate);enterCoord1.getChildren().add(yCoordinate);enterCoord1.getChildren().add(moveShipButton);stats.getChildren().add(enterCoord1);moveShipButton.setOnAction(new EventHandler() {@Overridepublic void handle(ActionEvent actionEvent) {double x = Double.parseDouble(xCoordinate.getText());double y = Double.parseDouble(yCoordinate.getText());myShip.plotCourse(x, y, false);}});// ===================================================// Debugging purposes// uncomment to test mouse press and rotation angles.//getSceneNodes().getChildren().add(stats);}/*** Sets up the mouse input.** @param primaryStage The primary stage (app window).*/private void setupInput(Stage primaryStage) {System.out.println("Ship's center is (" + myShip.getCenterX() + ", " + myShip.getCenterY() + ")");EventHandler fireOrMove = new EventHandler() {@Overridepublic void handle(MouseEvent event) {mousePressPtLabel.setText("Mouse Press PT = (" + event.getX() + ", " + event.getY() + ")");if (event.getButton() == MouseButton.PRIMARY) {// AimmyShip.plotCourse(event.getX(), event.getY(), false);// fireMissile m1 = myShip.fire();getSpriteManager().addSprites(m1);getSceneNodes().getChildren().add(0, m1.node);} else if (event.getButton() == MouseButton.SECONDARY) {// determine when all atoms are not on the game surface. Ship should be one sprite left.if (getSpriteManager().getAllSprites().size() generateManySpheres(30);}// stop ship from moving forwardmyShip.applyTheBrakes(event.getX(), event.getY());// move forward and rotate shipmyShip.plotCourse(event.getX(), event.getY(), true);}}};// Initialize inputprimaryStage.getScene().setOnMousePressed(fireOrMove);//addEventHandler(MouseEvent.MOUSE_PRESSED, me);// set up statsEventHandler changeWeapons = new EventHandler() {@Overridepublic void handle(KeyEvent event) {myShip.changeWeapon(event.getCode());}};primaryStage.getScene().setOnKeyPressed(changeWeapons);// set up statsEventHandler showMouseMove = new EventHandler() {@Overridepublic void handle(MouseEvent event) {mousePtLabel.setText("Mouse PT = (" + event.getX() + ", " + event.getY() + ")");}};primaryStage.getScene().setOnMouseMoved(showMouseMove);}/*** Make some more space spheres (Atomic particles)** @param numSpheres The number of random sized, color, and velocity atoms to generate.*/private void generateManySpheres(int numSpheres) {Random rnd = new Random();Scene gameSurface = getGameSurface();for (int i = 0; i < numSpheres; i++) { Color c = Color.rgb(rnd.nextInt(255), rnd.nextInt(255), rnd.nextInt(255)); Atom b = new Atom(rnd.nextInt(15) + 5, c, true); Circle circle = b.getAsCircle(); // random 0 to 2 + (.0 to 1) * random (1 or -1) b.vX = (rnd.nextInt(2) + rnd.nextDouble()) * (rnd.nextBoolean() ? 1 : -1); b.vY = (rnd.nextInt(2) + rnd.nextDouble()) * (rnd.nextBoolean() ? 1 : -1); // random x between 0 to width of scene double newX = rnd.nextInt((int) gameSurface.getWidth()); // check for the right of the width newX is greater than width // minus radius times 2(width of sprite) if (newX > (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());circle.setCache(true);circle.setCacheHint(CacheHint.SPEED);circle.setManaged(false);// 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) {// advance objectsprite.update();if (sprite instanceof Missile) {removeMissiles((Missile) sprite);} else {bounceOffWalls(sprite);}}/*** Change the direction of the moving object when it encounters the walls.** @param sprite The sprite to update based on the wall boundaries.* TODO The ship has got issues.*/private void bounceOffWalls(Sprite sprite) {// bounce off the walls when outside of boundariesNode displayNode;if (sprite instanceof Ship) {displayNode = sprite.node;//((Ship)sprite).getCurrentShipImage();} else {displayNode = sprite.node;}// Get the group node's X and Y but use the ImageView to obtain the width.if (sprite.node.getTranslateX() > (getGameSurface().getWidth() - displayNode.getBoundsInParent().getWidth()) ||displayNode.getTranslateX() < 0) { // bounce the opposite direction sprite.vX = sprite.vX * -1; } // Get the group node's X and Y but use the ImageView to obtain the height. if (sprite.node.getTranslateY() > getGameSurface().getHeight() - displayNode.getBoundsInParent().getHeight() ||sprite.node.getTranslateY() < 0) { sprite.vY = sprite.vY * -1; } } /** * Remove missiles when they reach the wall boundaries. * * @param missile The missile to remove based on the wall boundaries. */ private void removeMissiles(Missile missile) { // bounce off the walls when outside of boundaries if (missile.node.getTranslateX() > (getGameSurface().getWidth() -missile.node.getBoundsInParent().getWidth()) ||missile.node.getTranslateX() < 0) { getSpriteManager().addSpritesToBeRemoved(missile); getSceneNodes().getChildren().remove(missile.node); } if (missile.node.getTranslateY() > getGameSurface().getHeight() -missile.node.getBoundsInParent().getHeight() ||missile.node.getTranslateY() < 0) {getSpriteManager().addSpritesToBeRemoved(missile);getSceneNodes().getChildren().remove(missile.node);}}/*** How to handle the collision of two sprite objects. Stops the particle* by zeroing out the velocity if a collision occurred.** @param spriteA Sprite from the first list.* @param spriteB Sprite from the second list.* @return boolean returns a true if the two sprites have collided otherwise false.*/@Overrideprotected boolean handleCollision(Sprite spriteA, Sprite spriteB) {if (spriteA != spriteB) {if (spriteA.collide(spriteB)) {if (spriteA instanceof Atom && spriteB instanceof Atom) {((Atom) spriteA).implode(this); // will remove from the Scene onFinish()((Atom) spriteB).implode(this);getSpriteManager().addSpritesToBeRemoved(spriteA, spriteB);return true;}}}return false;}}

Ship類代表我們很酷的太空飛船。 Ship類繼承自Sprite類,以幫助我們包含速度信息(向量)。 該類還將包含一個(gè)雙向鏈接列表,該列表包含32個(gè)ImageView ( RotatedShipImage )實(shí)例,這些實(shí)例表示模擬船繞其中心(質(zhì)心)旋轉(zhuǎn)的每個(gè)方向。 在某些時(shí)候,我想通過(guò)使單個(gè)SVGPath對(duì)象旋轉(zhuǎn)來(lái)更改此設(shè)置(我知道有一些折衷)。 在本教程中,我通過(guò)將ImageView的對(duì)象從0到360度均勻旋轉(zhuǎn)32方向來(lái)實(shí)現(xiàn)飛船。 下面的圖3中顯示的是使用32個(gè)ImageView實(shí)例和飛船圖像的單個(gè)Image對(duì)象的所有32個(gè)方向,以模擬圍繞其中心(樞軸點(diǎn))的旋轉(zhuǎn)。

在為船旋轉(zhuǎn)動(dòng)畫(huà)時(shí),我可以使用ImageView節(jié)點(diǎn)上的setVisible(true)方法將當(dāng)前圖像以外的所有圖像設(shè)置為可見(jiàn)。

免責(zé)聲明 :在游戲中,您不可避免地會(huì)遇到數(shù)學(xué)(三角學(xué))。 如果您有興趣并想進(jìn)一步研究,請(qǐng)查看TheExpanse類的initialize()方法的源代碼。 在該方法的末尾取消注釋該語(yǔ)句: getSceneNodes()。getChildren()。add(stats); 。 這將顯示控件,使您可以用來(lái)調(diào)試和檢查鼠標(biāo)按下的坐標(biāo)。 此外,您還可以在控制臺(tái)(stdout)中看到與角度,向量等有關(guān)的輸出。

船舶的成員變量

  • turnDirection –枚舉DIRECTION,具有順時(shí)針,逆時(shí)針?lè)较?#xff0c;并且兩者都不
  • u – Vec對(duì)象,該對(duì)象包含相對(duì)于船舶坐標(biāo)中心的矢量,該矢量表示船舶開(kāi)始旋轉(zhuǎn)的起始方向
  • directionalShips – RotatedShipImage對(duì)象的列表,每個(gè)對(duì)象具有對(duì)其他RotatedShipImage對(duì)象的上一個(gè)和下一個(gè)引用。 零度(uInde??x = 0)是太空飛船朝東的時(shí)間。 旋轉(zhuǎn)JavaFX節(jié)點(diǎn)時(shí),沿逆時(shí)針?lè)较蛐D(zhuǎn)時(shí),其正數(shù)為度
  • uInde??x –當(dāng)前RotatedShipImage在directionShips列表中將顯示的索引
  • vIndex –旋轉(zhuǎn)動(dòng)畫(huà)結(jié)束時(shí)將顯示的directionalShips列表中RotatedShipImage的索引
  • stopArea –一個(gè)JavaFX Circle,其半徑為船舶知道何時(shí)停止船舶移動(dòng)
  • flipBook –一個(gè)JavaFX組,其中包含所有RotatedShipImage對(duì)象(32)。 該組將在場(chǎng)景上渲染。 就像動(dòng)畫(huà)中的翻書(shū)一樣,每個(gè)RotatedShipImage都將根據(jù)uInde??x和vIndex確定要顯示
  • keyCode – JavaFX KeyCode將幫助確定是否按鍵可以幫助您改變武器(字符“ 2”?)

該船的會(huì)員職能

  • update() –更新船只的速度和方向。 還將確定何時(shí)停止移動(dòng)。
  • getCurrentShipImage() –基于uInde??x,它返回ImageView,該ImageView是正在顯示的當(dāng)前船方向圖像
  • getCenterX() –返回屏幕的船中心X坐標(biāo)
  • getCenterY() –返回屏幕的X軸坐標(biāo)
  • plotCourse(double screenX,double screenY,boolean推力) –用戶在屏幕上單擊鼠標(biāo)后,此方法將計(jì)算旋轉(zhuǎn)船的角度并更改速度以將坐標(biāo)推向目標(biāo)點(diǎn)。 使用Vec對(duì)象時(shí),屏幕坐標(biāo)將轉(zhuǎn)換為直角坐標(biāo),以確定兩個(gè)向量(U和V)之間的角度。
  • turnShip() – plotCourse()方法調(diào)用turnShip()方法來(lái)執(zhí)行船舶旋轉(zhuǎn)的實(shí)際動(dòng)畫(huà)
  • applyTheBrakes(double screenX,double screenY) –用戶選擇(右鍵單擊)船只將導(dǎo)航到的位置applyTheBrakes()方法只需設(shè)置stopArea ( Circle )對(duì)象即可讓船只知道何時(shí)停止
  • fire() –返回供游戲引擎放入場(chǎng)景中的導(dǎo)彈(Sprite)對(duì)象。 每個(gè)導(dǎo)彈都以增加的速度(增加的速度)包含與船相同的方向。 應(yīng)該比飛船飛得更快。
  • changeWeapon(KeyCode keyCode) –用戶(玩家)擊鍵'2? 武器將改變以產(chǎn)生更大的導(dǎo)彈射彈,但速度稍慢。 其他任何按鍵操作都將是默認(rèn)武器,它可以產(chǎn)生速度更快的小型導(dǎo)彈彈丸。

下面顯示的是類圖的圖4,顯示了Ship類的成員。

船級(jí)圖

下面顯示的是Ship類的源代碼。

package carlfx.demos.navigateship;import carlfx.gameengine.Sprite; import javafx.animation.KeyFrame; import javafx.animation.Timeline; import javafx.animation.TimelineBuilder; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.CacheHint; import javafx.scene.Group; import javafx.scene.Node; import javafx.scene.image.Image; import javafx.scene.input.KeyCode; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.util.Duration; import java.util.ArrayList; import java.util.List;/*** A space ship with 32 directions* 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 Ship extends Sprite {/*** 360 degree turn*/private final static int TWO_PI_DEGREES = 360;/*** Number of ship frames and directions the ship is pointing nose*/private final static int NUM_DIRECTIONS = 32;/*** The angle of one direction (adjacent directions) (11.25 degrees)*/private final static float UNIT_ANGLE_PER_FRAME = ((float) TWO_PI_DEGREES / NUM_DIRECTIONS);/*** Amount of time it takes the ship to move 180 degrees in milliseconds.*/private final static int MILLIS_TURN_SHIP_180_DEGREES = 300;/*** When the ship turns on each direction one amount of time for one frame or turn of the ship. (18.75 milliseconds)*/private final static float MILLIS_PER_FRAME = (float) MILLIS_TURN_SHIP_180_DEGREES / (NUM_DIRECTIONS / 2);/*** All possible turn directions Clockwise, Counter Clockwise, or Neither when the user clicks mouse around ship*/private enum DIRECTION {CLOCKWISE, COUNTER_CLOCKWISE, NEITHER}/*** Velocity amount used vector when ship moves forward. scale vector of ship. See flipBook translateX and Y.*/private final static float THRUST_AMOUNT = 3.3f;/***/private final static float MISSILE_THRUST_AMOUNT = 6.3F;/*** Angle in degrees to rotate ship.*//*** Current turning direction. default is NEITHER. Clockwise and Counter Clockwise.*/private DIRECTION turnDirection = DIRECTION.NEITHER;/*** The current starting position of the vector or coordinate where the nose of the ship is pointing towards.*/private Vec u; // current or start vector/*** All ImageViews of all the possible image frames for each direction the ship is pointing. ie: 32 directions.*/private final List directionalShips = new ArrayList<>();/*** The Timeline instance to animate the ship rotating using images. This is an optical illusion similar to page* flipping as each frame is displayed the previous visible attribute is set to false. No rotation is happening.*/private Timeline rotateShipTimeline;/*** The current index into the list of ImageViews representing each direction of the ship. Zero is the ship* pointing to the right or zero degrees.*/private int uIndex = 0;/*** The end index into the list of ImageViews representing each direction of the ship. Zero is the ship* pointing to the right or zero degrees.*/private int vIndex = 0;/*** The spot where the user has right clicked letting the engine check the ship's center is in this area.*/private final Circle stopArea = new Circle();/*** A group contain all of the ship image view nodes.*/private final Group flipBook = new Group();/*** A key code will be used for weapon selection.*/private KeyCode keyCode;public Ship() {// Load one image.Image shipImage = new Image(getClass().getClassLoader().getResource("ship.png").toExternalForm(), true);stopArea.setRadius(40);RotatedShipImage prev = null;// create all the number of directions based on a unit angle. 360 divided by NUM_DIRECTIONSfor (int i = 0; i < NUM_DIRECTIONS; i++) {RotatedShipImage imageView = new RotatedShipImage();imageView.setImage(shipImage);imageView.setRotate(-1 * i * UNIT_ANGLE_PER_FRAME);imageView.setCache(true);imageView.setCacheHint(CacheHint.SPEED);imageView.setManaged(false);imageView.prev = prev;imageView.setVisible(false);directionalShips.add(imageView);if (prev != null) {prev.next = imageView;}prev = imageView;flipBook.getChildren().add(imageView);}RotatedShipImage firstShip = directionalShips.get(0);firstShip.prev = prev;prev.next = firstShip;// set javafx node to an imagefirstShip.setVisible(true);node = flipBook;flipBook.setTranslateX(200);flipBook.setTranslateY(300);}/*** Change the velocity of the atom particle.*/@Overridepublic void update() {flipBook.setTranslateX(flipBook.getTranslateX() + vX);flipBook.setTranslateY(flipBook.getTranslateY() + vY);if (stopArea.contains(getCenterX(), getCenterY())) {vX = 0;vY = 0;}}private RotatedShipImage getCurrentShipImage() {return directionalShips.get(uIndex);}/*** The center X coordinate of the current visible image. See <code>getCurrentShipImage()</code> method.** @return The scene or screen X coordinate.*/public double getCenterX() {RotatedShipImage shipImage = getCurrentShipImage();return node.getTranslateX() + (shipImage.getBoundsInLocal().getWidth() / 2);}/*** The center Y coordinate of the current visible image. See <code>getCurrentShipImage()</code> method.** @return The scene or screen Y coordinate.*/public double getCenterY() {RotatedShipImage shipImage = getCurrentShipImage();return node.getTranslateY() + (shipImage.getBoundsInLocal().getHeight() / 2);}/*** Determines the angle between it's starting position and ending position (Similar to a clock's second hand).* When the user is shooting the ship nose will point in the direction of the mouse press using the primary button.* When the user is thrusting to a location on the screen the right click mouse will pass true to the thrust* parameter.** @param screenX The mouse press' screen x coordinate.* @param screenY The mouse press' screen ycoordinate.* @param thrust Thrust ship forward or not. True move forward otherwise false.*/public void plotCourse(double screenX, double screenY, boolean thrust) {// get center of shipdouble sx = getCenterX();double sy = getCenterY();// get user's new turn position based on mouse clickVec v = new Vec(screenX, screenY, sx, sy);if (u == null) {u = new Vec(1, 0);}double atan2RadiansU = Math.atan2(u.y, u.x);double atan2DegreesU = Math.toDegrees(atan2RadiansU);double atan2RadiansV = Math.atan2(v.y, v.x);double atan2DegreesV = Math.toDegrees(atan2RadiansV);double angleBetweenUAndV = atan2DegreesV - atan2DegreesU;// if abs value is greater than 180 move counter clockwise//(or opposite of what is determined)double absAngleBetweenUAndV = Math.abs(angleBetweenUAndV);boolean goOtherWay = false;if (absAngleBetweenUAndV > 180) {if (angleBetweenUAndV < 0) { turnDirection = DIRECTION.COUNTER_CLOCKWISE; goOtherWay = true; } else if (angleBetweenUAndV > 0) {turnDirection = DIRECTION.CLOCKWISE;goOtherWay = true;} else {turnDirection = Ship.DIRECTION.NEITHER;}} else {if (angleBetweenUAndV < 0) { turnDirection = Ship.DIRECTION.CLOCKWISE; } else if (angleBetweenUAndV > 0) {turnDirection = Ship.DIRECTION.COUNTER_CLOCKWISE;} else {turnDirection = Ship.DIRECTION.NEITHER;}}double degreesToMove = absAngleBetweenUAndV;if (goOtherWay) {degreesToMove = TWO_PI_DEGREES - absAngleBetweenUAndV;}//int q = v.quadrant();uIndex = Math.round((float) (atan2DegreesU / UNIT_ANGLE_PER_FRAME));if (uIndex < 0) {uIndex = NUM_DIRECTIONS + uIndex;}vIndex = Math.round((float) (atan2DegreesV / UNIT_ANGLE_PER_FRAME));if (vIndex < 0) { vIndex = NUM_DIRECTIONS + vIndex; } String debugMsg = turnDirection + " U [m(" + u.mx + ", " + u.my + ") => c(" + u.x + ", " + u.y + ")] " +" V [m(" + v.mx + ", " + v.my + ") => c(" + v.x + ", " + v.y + ")] " +" start angle: " + atan2DegreesU +" end angle:" + atan2DegreesV +" Angle between: " + degreesToMove +" Start index: " + uIndex +" End index: " + vIndex;System.out.println(debugMsg);if (thrust) {vX = Math.cos(atan2RadiansV) * THRUST_AMOUNT;vY = -Math.sin(atan2RadiansV) * THRUST_AMOUNT;}turnShip();u = v;}private void turnShip() {final Duration oneFrameAmt = Duration.millis(MILLIS_PER_FRAME);RotatedShipImage startImage = directionalShips.get(uIndex);RotatedShipImage endImage = directionalShips.get(vIndex);List frames = new ArrayList<>();RotatedShipImage currImage = startImage;int i = 1;while (true) {final Node displayNode = currImage;KeyFrame oneFrame = new KeyFrame(oneFrameAmt.multiply(i),new EventHandler() {@Overridepublic void handle(javafx.event.ActionEvent event) {// make all ship images invisiblefor (RotatedShipImage shipImg : directionalShips) {shipImg.setVisible(false);}// make current ship image visibledisplayNode.setVisible(true);// update the current index//uIndex = directionalShips.indexOf(displayNode);}}); // oneFrameframes.add(oneFrame);if (currImage == endImage) {break;}if (turnDirection == DIRECTION.CLOCKWISE) {currImage = currImage.prev;}if (turnDirection == DIRECTION.COUNTER_CLOCKWISE) {currImage = currImage.next;}i++;}if (rotateShipTimeline != null) {rotateShipTimeline.stop();rotateShipTimeline.getKeyFrames().clear();rotateShipTimeline.getKeyFrames().addAll(frames);} else {// sets the game world's game loop (Timeline)rotateShipTimeline = TimelineBuilder.create().keyFrames(frames).build();}rotateShipTimeline.playFromStart();}/*** Stops the ship from thrusting forward.** @param screenX the screen's X coordinate to stop the ship.* @param screenY the screen's Y coordinate to stop the ship.*/public void applyTheBrakes(double screenX, double screenY) {stopArea.setCenterX(screenX);stopArea.setCenterY(screenY);}public Missile fire() {Missile m1;float slowDownAmt = 0;if (KeyCode.DIGIT2 == keyCode) {m1 = new Missile(10, Color.BLUE);slowDownAmt = 2.3f;} else {m1 = new Missile(Color.RED);}// velocity vector of the missilem1.vX = Math.cos(Math.toRadians(uIndex * UNIT_ANGLE_PER_FRAME)) * (MISSILE_THRUST_AMOUNT - slowDownAmt);m1.vY = -Math.sin(Math.toRadians(uIndex * UNIT_ANGLE_PER_FRAME)) * (MISSILE_THRUST_AMOUNT - slowDownAmt);// make the missile launch in the direction of the current direction of the ship nose. based on the// current frame (uIndex) into the list of image view nodes.RotatedShipImage shipImage = directionalShips.get(uIndex);// start to appear in the center of the ship to come out the direction of the nose of the ship.double offsetX = (shipImage.getBoundsInLocal().getWidth() - m1.node.getBoundsInLocal().getWidth()) / 2;double offsetY = (shipImage.getBoundsInLocal().getHeight() - m1.node.getBoundsInLocal().getHeight()) / 2;// initial launch of the missilem1.node.setTranslateX(node.getTranslateX() + offsetX + m1.vX);m1.node.setTranslateY(node.getTranslateY() + offsetY + m1.vY);return m1;}public void changeWeapon(KeyCode keyCode) {this.keyCode = keyCode;}}

Vec

Vec類是一個(gè)簡(jiǎn)單的幫助程序容器類,可幫助您保持鼠標(biāo)單擊的屏幕坐標(biāo),并根據(jù)子畫(huà)面,圖像或形狀的中心將其轉(zhuǎn)換為笛卡爾坐標(biāo)。 此類用于幫助確定兩個(gè)向量[Math.atan2(y,x)]之間的角度。 通過(guò)確定角度,船可以執(zhí)行子畫(huà)面圖像的旋轉(zhuǎn)動(dòng)畫(huà)。

下面顯示的是Vec類的源代碼。

package carlfx.demos.navigateship;/*** This class represents a container class to hold a Vector in space and direction* the ship will move. Assuming the center of the ship is the origin the angles can* be determined by a unit circle via Cartesian coordinates.* When the user clicks on the screen the mouse coordinates or screen coordinates* will be stored into the mx and my instance variables.* The x and y data members are converted to cartesian coordinates before storing.** I purposefully left out getters and setters. In gaming just keep things minimalistic.* @author cdea*/ public class Vec {public double mx;public double my;public double x;public double y;/*** This is a default constructor which will take a Cartesian coordinate.* @param x X coordinate of a point on a Cartesian system.* @param y Y coordinate of a point on a Cartesian system.*/public Vec(float x, float y) {this.x = x;this.y = y;}/*** Constructor will convert mouse click points into Cartesian coordinates based on the sprite's center point as* the origin.* @param mx Mouse press' screen X coordinate.* @param my Mouse press' screen Y coordinate.* @param centerX Screen X coordinate of the center of the ship sprite.* @param centerY Screen Y coordinate of the center of the ship sprite.*/public Vec(double mx, double my, double centerX, double centerY) {this.x = convertX(mx, centerX);this.y = convertY(my, centerY);this.mx = mx;this.my = my;}/*** Returns a Cartesian coordinate system's quadrant from 1 to 4. ** first quadrant - 1 upper right* second quadrant - 2 upper left* third quadrant - 3 lower left* fourth quadrant - 4 lower right** @return int quadrant number 1 through 4*/public int quadrant() {int q = 0;if (x > 0 && y > 0) {q =1;} else if (x < 0 && y > 0) {q = 2;} else if (x < 0 && y < 0) { q = 3; } else if (x > 0 && y < 0) {q = 4;}return q;}@Overridepublic String toString(){return "(" + x + "," + y + ") quadrant=" + quadrant();}/*** Converts point's X screen coordinate into a Cartesian system.* @param mouseX Converts the mouse X coordinate into Cartesian system based on the ship center X (originX).* @param originX The ship center point's X coordinate.* @return double value of a Cartesian system X coordinate based on the origin X.*/static double convertX(double mouseX, double originX) {return mouseX - originX;}/*** Converts point's Y screen coordinate into a Cartesian system.* @param mouseY Converts the mouse Y coordinate into Cartesian system based on the ship center Y (originY).* @param originY The ship center point's Y coordinate.* @return double value of a Cartesian system Y coordinate based on the origin Y.*/static double convertY(double mouseY, double originY) {return originY - mouseY;}}

RotatedShipImage

RotatedShipImage類繼承自JavaFX的ImageView類,但還包含對(duì)上一個(gè)和下一個(gè)RotatedShipImage實(shí)例的引用, 這些實(shí)例構(gòu)成了一個(gè)雙向鏈接列表。 圖3描繪了在每個(gè)RotatedShipImage中呈現(xiàn)的“ ship.png”的32個(gè)圖像,它們?nèi)糠胖迷贘avaFX Group節(jié)點(diǎn)中。 當(dāng)船似乎在旋轉(zhuǎn)時(shí),一次只顯示一幅圖像。

下面顯示的是RotatedShipImage類的源代碼。

package carlfx.demos.navigateship;import javafx.scene.image.ImageView;/*** Represents a double link list to assist in the rotation of the ship.* This helps to move clockwise and counter clockwise.*/ public class RotatedShipImage extends ImageView {public RotatedShipImage next;public RotatedShipImage prev; }

導(dǎo)彈

Missile類繼承自Atom類。 導(dǎo)彈是標(biāo)記類,用于區(qū)分球體(小行星)和導(dǎo)彈。 制造導(dǎo)彈時(shí),它們將以更大的速度包含與船相同的方向(船鼻指向的方向)。

下面顯示的是Missile類的源代碼。

package carlfx.demos.navigateship;import javafx.scene.paint.Color;/*** A missile projectile without the radial gradient.*/ public class Missile extends Atom {public Missile(Color fill) {super(5, fill, false);}public Missile(int radius, Color fill) {super(radius, fill, true);} }

結(jié)論

輸入對(duì)于任何游戲都至關(guān)重要,因此通常很難正確輸入。 較舊的游戲引擎將在游戲循環(huán)中進(jìn)行輪詢。 使用JavaFX 2.x的事件處理時(shí),可以實(shí)現(xiàn)要添加到場(chǎng)景圖或單個(gè)Node對(duì)象中的事件類型。 希望在將來(lái),我們將看到更多用于游戲的巧妙輸入設(shè)備(請(qǐng)參閱Oracle的Java技術(shù)推廣員Simon Ritter )。 睜大眼睛看一下第4部分,它涉及碰撞檢測(cè)。 因此,請(qǐng)繼續(xù)關(guān)注并隨時(shí)發(fā)表評(píng)論。

有用的鏈接:

7-11 :http://www.7-eleven.com

玩小行星 :http://www.play.vg/games/4-Asteroids.html

小行星 :http://en.wikipedia.org/wiki/Asteroids_(video_game)

斯科特·薩夫蘭(Scott Safran) :http://en.wikipedia.org/wiki/Scott_Safran

后院拱廊 :http://www.themysteryworld.com/2011/02/guy-builds-video-arcade-in-his-back.html

縮小《星際大戰(zhàn)》 :http://techland.time.com/2012/04/26/man-builds-16-scale-star-wars-arcade-game/

三角學(xué) :http://en.wikipedia.org/wiki/ 三角學(xué)

JavaFX節(jié)點(diǎn)API :http://docs.oracle.com/javafx/2/api/javafx/scene/Node.html

JavaFX Scene API :http://docs.oracle.com/javafx/2/api/javafx/scene/Scene.html

JavaFX SVGPath API :http: //docs.oracle.com/javafx/2/api/javafx/scene/shape/SVGPath.html

多點(diǎn)觸控和手勢(shì)支持 :http://www.oracle.com/technetwork/java/javafx/overview/roadmap-1446331.html

Pro JavaFX 2 Apress發(fā)布– pg。 62第2章第2節(jié)“處理輸入事件”。 http://www.apress.com/9781430268727

Java 7 Recipe Apress發(fā)行-第pg。 602第16章食譜16-3“沿路徑動(dòng)畫(huà)化”。 http://www.apress.com/9781430240563

電子游戲街機(jī)柜 :http://en.wikipedia.org/wiki/Video_game_arcade_cabinet

柵格圖形 :http://en.wikipedia.org/wiki/Raster_graphics

GitHub上的第3部分源代碼 :https://github.com/carldea/JFXGen/tree/master/demos/navigateship

JavaFX Canvas節(jié)點(diǎn) :http://mail.openjdk.java.net/pipermail/openjfx-dev/2012-April/001210.html

JavaFX-為JavaFX應(yīng)用程序優(yōu)化性能 :http://www.parleys.com/#st=5&id=2738&sl=0

Oracle的Java技術(shù)推廣員Simon

Ritter :https://blogs.oracle.com/javaone/entry/interface_with_the_interface_javafx

視頻游戲高中第1集 :http://www.rocketjump.com/?video = vghs-episode-1

視頻游戲高中第2集 :http://www.rocketjump.com/?video = vghs-episode-2-5

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


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

javafx2

總結(jié)

以上是生活随笔為你收集整理的javafx2_JavaFX 2 GameTutorial第3部分的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。