2048 雙人創新小游戲【JavaFX-FXGL游戲框架】


一個 uml 課程的大作業,項目要求設計並開發一款 2048 與某種游戲類型相結合的創新游戲。可以選擇只建模或者既建模又實現,既然要做當然是選擇實現啦(雖然沒有接觸過游戲...期末周的莽沖hhh,小組內我負責代碼實現,用的是基於JavaFX的游戲開發框架FXGL

游戲介紹

游戲背景

因為這次大作業趕上期末復習周,我們游戲的名字就叫FinalWeek2048,融入了我們學校期末周的背景。以2048游戲元素為主,加入雙人競技碰撞放置的創新元素。
2048中從2-2048共11種方塊,我們用C, C++, java, Python,數據庫,數據結構,計算機組成原理,計算機網絡,Web開發,HTML,UML共11中課程方塊替代,分值上和2048中相對應。(計算機宇宙的盡頭是UML建模設計哈哈哈
游戲元素

游戲玩法

玩家一和玩家二通過按鍵控制角色,隨機釋放不同的方塊,所放置的方塊具有重力屬性,放置后自由下墜,觸碰到其他不同的方塊或游戲邊界則停留,若與其他相同的方塊相撞則合成一個更加高級的方塊,並加上等級相應的分數。
游戲結束條件:堆積的方塊觸到玩家所站的平台或一方勝利
勝利條件:a. 率先得到2048分;b. 率先合成UML方塊;c. 一方觸頂,另一方勝利

游戲開發框架FXGL

以下是FXGL在Github上對自己的介紹和定位(直接谷歌生翻的
image

我選擇使用FXGL,首先是考慮如果在這么短的時間去重新學習目前比較熱門的游戲框架難度更大(自身也沒打算往游戲方向發展,易上癮不敢碰),然后之前已經學習了JavaFX正好FXGL是基於它的,學習成本會小很多,還能鍛煉一下。
事實證明,我想多了,阻力比我想象的大,FXGL在國內外都比較冷門,在國內資料幾乎沒有,官方給的wiki不能滿足我的需求,再配上官方的游戲demo,勉強做了下來。(感覺如果之前用過Unity或者Cocos這樣的框架會好學很多,因為官方也提到了FXGL是參照熱門的一些游戲框架開發的)
然后就是我過菜的英文水平!基本的就是應付官方文檔和wiki,非常關鍵在於在社區找bug的解決方案的時候...翻譯不通
還有一點,FXGL的API文檔版本很舊,目前沒有發布最新的但框架好像已經更到了17...

成果展示

image

1. 主菜單界面

主菜單是繼承了MainMenu自己重新寫了個,藍色是糊掉了學校信息,還加上了與期末周格格不入的歡快背景音樂[doge]
還有個游戲結束時的子菜單,直接用了內置的SimpleGameMenu。
image

2. 游戲主界面

雖然有素材,但沒有給兩個玩家加上移動的動態動作,當時時間趕懶得分開寫。背景是我們學校的一個塔,放這里還挺合適的。方塊碰撞消除會有音效和粒子碰撞效果~
image

實現細節

以下是在實現過程中我覺得難度較大的部分,可以先跳過看源碼了解整體的框架

  1. 在工廠中對方塊實體的設置
    要使得實體間產生碰撞或者具有重力,則需要把它們加入物理世界並且設置參數。
    關於相同的方塊碰撞加分,就是賦予了方塊實體HealthIntComponent部件(一般在游戲中是血條),讓它具有一個整型參數屬性,應該還有更好的處理方法,然后為了方便布置關卡,我是在工廠寫出了這11中方塊實體從a-k。
    @Spawns("a")
    public Entity newA(SpawnData data) {
		// 這里就是設置方塊的物理屬性,設置密度,能在物理世界自由下墜
        PhysicsComponent physics = new PhysicsComponent();
        physics.setBodyType(BodyType.DYNAMIC);
        physics.setFixtureDef(new FixtureDef().density(0.03f));

        return entityBuilder(data)
                .type(FinalWeekType.BOOKBLOCK)
                .viewWithBBox(texture("bookblock_2.png", 80, 80))
                .with(new HealthIntComponent(2))
                .with(physics)
                .collidable()
                .build();
    }
  1. 方塊之間和方塊與平台的碰撞處理
    不同方塊直接堆疊,相同方塊碰撞后移除游戲世界產生特效實體以及新的方塊實體
    處理碰撞的計分歸屬,是在隨機參數的方塊加了IDComponent來識別是玩家一還是玩家二放置的。
@Override
    protected void initPhysics() {
        PhysicsWorld physicsWorld = getPhysicsWorld();
        // 當兩個相同的方塊碰撞在一起后消失,並產生一個加倍的方塊
        physicsWorld.addCollisionHandler(new CollisionHandler(FinalWeekType.BOOKBLOCK, FinalWeekType.BOOKBLOCK) {
            @Override
            protected void onCollision(Entity playerBlock, Entity block) {
                int num1 = playerBlock.getComponent(HealthIntComponent.class).getMaxValue();
                int num2 = block.getComponent(HealthIntComponent.class).getMaxValue();
                String curBlock = "";
                if(playerBlock.isType(block.getType())) {
                    if(playerBlock.hasComponent(IDComponent.class)) {
                        curBlock = playerBlock.getComponent(IDComponent.class).getName();
                    }
                    if(num1 == num2) {
                        Point2D explosionSpawnPoint = playerBlock.getCenter().subtract(64, 64);
                        spawn("explosion", explosionSpawnPoint);
                        runOnce(()->play("combine.wav"), Duration.seconds(0.5));
                        double x = block.getCenter().getX() - 40, y = block.getCenter().getY() - 40;
                        playerBlock.removeFromWorld();
                        block.removeFromWorld();
                        int score = (int)(Math.log(num1) / Math.log(2));
                        char ch = (char) (score + 'a');
                        if(ch >= 'k') {
                            if(curBlock == "firstPlayerScore") showGameOver("玩家一");
                                else showGameOver("玩家二");
                        }
                        String str = "" + ch;
                        spawn(str, x, y);
                        if(curBlock != "") inc(curBlock, +num1);
                    }
                }
            }
        });
	// 處理方塊與玩家所站的平台底部的碰撞
        physicsWorld.addCollisionHandler(new CollisionHandler(FinalWeekType.BOOKBLOCK, FinalWeekType.PLATFORM) {
            @Override
            protected void onCollision(Entity block, Entity platform) {
                if(block.getComponent(IDComponent.class).getName() == "firstPlayerScore") showGameOver("玩家二");
                    else showGameOver("玩家一");
            }
        });
    }

源碼分享

FinalWeek2048 源碼
代碼其實還沒整理好,然后碰撞產生的連鎖碰撞消除的計分還沒有處理好,等之后空閑下來再來整理完善~
一個簡單的小游戲,歡迎大佬們指教!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM