August 11, 2013

Day 5 Controls များအား အသုံးပြုခြင်း

ပြီးခဲ့သော အခန်းဖြင့် JavaFX တွင် အသုံးပြုနိုင်သော Controls များ အကြောင်းကို အကျဉ်းချုပ်၍ မိတ်ဆက်ခဲ့၏။ ယနေ့ တစ်ခေါက်တွင် ၎င်း Control အချို့အား အသုံးပြု၍ နမှုနာ အပလီကေးရှင်း တစ်ခုအား ရေးသားကြည့်ပါဦးမည်။

အဆိုပါ Controls များအားလုံးကို JavaFX Scene Builder အား အသုံးပြု၍ ရေးသားနိုင်ပါသည်။ ယခုတစ်ခေါက်တွင် SceneBuilder နှင့် FXML အား အသုံးပြု၍ ရေးသားကြည့်ပါဦးမည်။ ရေးသားမည့် နမှုနာမှာ ကျွှန်တော် DTC တွင် Java SE သင်ကြားနေသော ကလေးများအား ရေးခိုင်းလေ့ရှိသော အံစာတုန်း ဂိမ်းလေး တစ်ခု ဖြစ်ပါသည်။

အံစာတုံးမှာ နှစ်လုံးရှိပြီး၊ ကစားသူမှာ ကစားသူနှင့် System နှစ်ယောက်ရှိပါသည်။ အပလီကေးရှင်းအစတွင် တစ်ဦးလျှင် အမှတ် ၅၀၀၀၀ပေးထား၍၊ ရှုန်းသူက နိုင်သူအား လောင်းထားသည့် အမှတ်အတိုင်း  ပြန်ပေးရသော ဂိမ်းဖြစ်ပါသည်။ System ရော User ပါ လောင်းစရာ မကျန်တော့ပါက ရုန်းမည်ဖြစ်ပါသည်။

ဂိမ်း၏ စည်းကမ်းမှာ ၁ပူမှာ အနိုင်ဆုံးဖြစ်ပြီး၊ အခြားသော အပူးဆိုပါက အပွင့်ကြီးသူက နိုင်ပါမည်။ မပူးပါက အပွင့်နှစ်လုံးကို ပေါင်းပြီး အကြီးဆုံးသူက နိုင်ပါမည်။ အဆိုပါဂိမ်းကို JavaFX နှင့် ရေးကြည့်ပါမည်။



Dice Game Utility Classများ


Dice သည် အံစာတုန်းဖြစ်ပြီး၊ ၎င်းတွင် Field အနေဖြင့် ဂဏာန်းခြောက်လုံး ပါဝင်သော List တစ်ခုကို ပိုင်ဆိုင်ပြီး method အနေဖြင့် နံပါတ်တစ်ခုကို Random အနေဖြင့် ပြန်ပေးနိုင်သော getNumber ကို ပိုင်ဆိုင်ပါသည်။
public class Dice {
    
    private List<Integer> indexes;
    
    public Dice() {
        this.indexes = new ArrayList<>();
        for(int i=1; i<=6; i++)
            this.indexes.add(i);
    }
    
    public Integer getNumber() {
        Collections.shuffle(indexes);
        return this.indexes.get(0);
    }
}

တဖန် Dice အား အသုံးပြုနေသော Class မှာ Game  ဖြစ်သည်။ ၎င်းတွင် အံစာတုန်းနှစ်တုန်း၏ အမှတ်များဖြစ်သော value1, value2 နှင့်၊ ပူးသလားမပူးသလား ကိုဖော်ပြနိုင်သော isDouble နှင့် အမှတ်ပေါင်းကို ဖော်ပြနိုင်သော index ကို ပိုင်ဆိုင်ပါသည်။ ပါဝင်ကြသော Method များမှာ ဂိမ်းကစားစေသော doGame နှင့် getter method များ ဖြစ်ကြပါသည်။ Game တစ်ခုနှင့် တစ်ခုအား နှိုင်းယှဉ်နိုင်ရန်အတွက် Comparable Interface အား implement လုပ်ထား၍ compareTo လုပ်ဆောင်ချက်အား Override လုပ်ထားပါသည်။ compareTo လုပ်ဆောင်ချက်အတွင်းတွင် Game တစ်ခုနှင့် တစ်ခု ဘယ်သူကနိုင်သည်ဟု ဆုံးဖြတ်ရန် စီးကမ်းများအား ရေးသားထားရန် လိုအပ်ပါသည်။

doGame လုပ်ဆောင်ချက်အတွင်းမှာမူ Dice အား အသုံးပြု၍ နံပါတ်များအား ရယူ၍ ပူးသလား၊ မပူးဘူးလား၊ ဘယ်နှစ်ပွင့်ရသလဲဆိုသည်ကို ဆုံးဖြတ်ရပါသည်။
    public void doGame() {
        // set value1
        this.value1 = new Dice().getNumber();
        this.value2 = new Dice().getNumber();
        
        if(this.value1 == this.value2) {
            this.isDouble = true;
            this.index = this.value1;
        } else {
            this.isDouble = false;
            this.index = this.value1 + this.value2;
        }
    }

တဖန် Comparable Interface ကို Implements ပြုလုပ်ထားပါသဖြင့်၊ မိမိနှင့် အခြားသော ဂိမ်းတို့အကြား မည်သူကနိုင်မည်ဆိုသည်ကို ဆုံးဖြတ်ရန် compareTo ဆိုသော Method အား Override လုပ်ရန် လိုအပ်ပါသည်။
    @Override
    public int compareTo(Game o) {
        if (this.isDouble() && o.isDouble()) {
            if (this.getValue1() == 1 && o.getValue1() == 1) {
                return 0;
            } else if (this.getValue1() != 1 && o.getValue1() == 1) {
                return -1;
            } else if (this.getValue1() == 1 && o.getValue1() != 1) {
                return 1;
            } else {
                return this.getValue1() - o.getValue1();
            }
        } else if (!this.isDouble() && o.isDouble()) {
            return -1;
        } else if (this.isDouble() && !o.isDouble()) {
            return 1;
        } else {
            return (this.getValue1() + this.getValue2())
                    - (o.getValue1() + o.getValue2());
        }
    }

နောက်ဆုံး Class မှာ Game ကစားသော User Class ဖြစ်ပါသည်။ ပါဝင်သည်မှာ total amount နှင့် Game Class ဖြစ်သည်။ လုပ်ဆောင်ချက်အနေဖြင့် doBalance လုပ်ဆောင်ချက်နှင့် getter လုပ်ဆောင်ချက်တို့ ဖြစ်ကြပါသည်။
package com.dtc.dice.game;

public class User {
    
    private Integer total_ammount;
    private Game game;
    
    public User() {
        this.game = new Game();
        this.total_ammount = 50000;
    }

    public Integer getTotal_ammount() {
        return total_ammount;
    }

    public Game getGame() {
        return game;
    }

    public void doBalance(Integer amount) {
        this.total_ammount += amount;
    }
}


Dice Game UI ရေးသားခြင်း


ဂိမ်းကစားရန် လိုအပ်သော Class များအား ရေးသားပြီး ဖြစ်ပါသည်။ JavaFX အကြောင်းကို မရောက်သေးပါ။ ၎င်း ဂိမ်းကစားသော Class များအား အသုံးပြု၍ JavaFX အတွင်းမှ ဆက်သွယ် အသုံးပြုသွားပါမည်။ ရေးသားရန် ကျန်သည်မှာ UI အပိုင်းနှင့် Controller Class တစ်ခုသာ ဖြစ်သည်။ UI အပိုင်းအတွက်ကတော့ SceneBuilder အား  အသုံးပြု၍ FXML ဖြင့်  ရေးပါမည်။


ဦးစွာ VBox တစ်ခုကို အခြေခံသော FXML ဖိုင်တစ်ခုအား ရေးသားပါသည်။ ပြီးပါက SceneBuilder အား  အသုံးပြု၍ အဆိုပါ FXML ဖိုင်အား Edit လုပ်ပါသည်။ Layout အနေဖြင့် အသုံးပြုရန် HBox သုံးခုကို ဆက်တိုက်ထည့်ပါသည်။

အထက်ဆုံး HBox အတွင်းတွင် Title တွက် Label တစ်ခုနှင့် Result ကို ဖော်ပြရန်အတွက် Label တစ်ခုတို့ပါဝင်ပါသည်။ Result ကို ဖော်ပြရန် Label သာလျှင် Dynamically ပြောင်းလည်းဖော်ပြရန် လိုသောကြောင့် fx:id ကို သတ်မှတ်ရေးသားပါသည်။

ဒုတိယ HBox အတွင်းတွင် System User နှင့် Game User တို့အတွက် AnchorPane နှစ်ခုကို ထားရှိပါသည်။ တစ်ခုစီအတွင်းတွင် ပြောင်းလည်းဖော်ပြနိုင်သော Label များနှင့်၊ အန်စာတုန်းပုံများအား ဖော်ပြနိုင်သော StackPane နှစ်ခုကို ဖြည့်စွက်ထားပါသည်။

အောက်ဆုံး HBox မှာမူ User က Game ကစားရာတွင် လောင်းမည့် အမှတ်ကို ဖြည့်သော TextField တစ်ခု၊ Button နှစ်ခုနှင့် Label တစ်ခုတို့ပါဝင်ကြ၏။


Dice Game Controller Class


Controller Class အဖြစ်အသုံးပြုမည်မှာ GameController.java ဖြစ်ပါသည်။ GameController အတွင်းပါဝင်သော Member Fields များမှာ၊ Dinamically သတ်မှတ်ပေးရန်လိုအပ်သော Label များနှင့်၊ အံစာတုန်းပုံများ၊ ၎င်းအပြင် အံစာတုန်းပုံများအား ထည့်ထားသော ObservableList<Path> နှင့်၊ User များ ဖြစ်ကြသော System User နှင့် Player User တို့ဖြစ်ကြပါသည်။

ရေးသားရန်လိုအပ်သော Public Method များမှာ၊ Reset Button Action အတွက် GameController#reset၊ Play Button Action အတွက် GameController#play နှင့် Initialize လုပ်သည့်အခါတွင် ခေါ်ယူရန်အတွက် GameController#initialize လုပ်ဆောင်ချက်တို့ ဖြစ်ကြပါသည်။

JavaFX ၏ Controller Class များသည် Container မှ Create လုပ်သော Class များဖြစ်သောကြောင့်၊ @FXML ဖြင့် ရေးသားထားသော Component များအား Create လုပ်ပြီးသောအခါတွင်၊ ကနဦး တန်ဖိုးများအား သတ်မှတ်ရာတွင်၊ Constructor များအတွင်းတွင် ရေးသား၍မရပါ။ အဆိုပါ အခြေအနေမျိုးတွင် Initializable Interface အား Implement လုပ်ကာ Override လုပ်ထားသော initialize လုပ်ဆောင်ချက်အတွင်းတွင် ရေးသားရန်လိုအပ်ပါသည်။
    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        try {
            this.system = new User();
            this.user = new User();
            this.setValues("Let's start the game.");

            Path images = Paths.get("img");
            if (Files.isDirectory(images, LinkOption.NOFOLLOW_LINKS)) {
                DirectoryStream<Path> dir = Files.newDirectoryStream(images);
                data = FXCollections.observableArrayList();

                for (Path image : dir) {
                    data.add(image);
                }

                this.setImage(sys_stk1, this.getImageView(data.get(0)));
                this.setImage(sys_stk2, this.getImageView(data.get(0)));
                this.setImage(use_stk1, this.getImageView(data.get(0)));
                this.setImage(use_stk2, this.getImageView(data.get(0)));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

GameController#reset လုပ်ဆောင်ချက်မှာမူ၊ Member များဖြစ်ကြသော system နှင့် user တို့အား အသစ်ပြန် Create လုပ်၍၊ ၎င်း၏ အချက်အလက်တို့အား View တွင် ဖော်ပြပေးရုံသာဖြစ်၏။
    @FXML
    public void doReset() {
        this.system = new User();
        this.user = new User();
        this.setValues("The game has been reset.");
    }

အဓိက ဂိမ်းအား ကစားစေသော လုပ်ဆောင်ချက်မှာ GameController#play လုပ်ဆောင်ချက် ဖြစ်ပါသည်။
    @FXML
    public void doPlay() {
        try {
            int vate = this.getVateMoney();
            if (vate > 0) {
                this.system.doBalance(-vate);
                this.user.doBalance(-vate);

                Game us_game = this.user.getGame();
                Game sy_game = this.system.getGame();

                us_game.doGame();
                sy_game.doGame();

                int game_result = us_game.compareTo(sy_game);

                if (game_result == 0) {
                    this.user.doBalance(vate);
                    this.system.doBalance(vate);
                    this.setValues("Draw!");
                } else if (game_result > 0) {
                    this.user.doBalance(2 * vate);
                    this.setValues("You Win!");
                } else {
                    this.system.doBalance(2 * vate);
                    this.setValues("You Loose!");
                }

                this.judge();
            }
        } catch (NumberFormatException e) {
            this.vote_money.setText("");
            this.result.setText("Please set vate money with digit.");
        }
    }

ဦးစွာ User Input ဖြစ်သော TextField အတွင်းမှရယူကာ၊ system ကော user မှပါ အသီးသီး နှုတ်ယူထားပါသည်။ ပြီးပါက object နှစ်ခုစလုံးမှ game များအား doPlay method အား ခေါ်ယူပြီး ကစားစေပါသည်။

ပြီးလျှင် စာကြောင်း ၁၅ဖြင့် ဂိမ်းအသီးသီးအား Compare လုပ်စေပါသည်။ ရလဒ်သည် သုညဖြစ်ပါက သရေဖြစ်သောကြောင့် နှုတ်ယူထားသော အမှားများအား Object အသီးသီးအား ပြန်ပေါင်းပေးပါသည်။ ရလဒ်သည် သုညထက်ကြီးပါက ကစားသူ အနိုင်ရသောကြောင့် နှုတ်ယူထားသောတန်ဖိုး၏ နှစ်ဆအား ကစားသူဆီသို့ ပြန်ပေါင်းပေးပါသည်။ သို့မဟုတ်ပါက System အနိုင်ရသောကြောင့် System အား တန်ဖိုးနှစ်ဆပြန်ပေးပါသည်။

အဆိုပါ ဂိမ်းအား ကစားကြည့်ပါမည်။


ပြီးပါက Vote Money နေရာတွင် တန်ဖိုး 10000အားဖြည့်၍ Play အား နှိပ်ကြည့်ပါမည်။


Game Player သည် ၆ပွင့်ရရှိကာ၊ System Player သည် ၈ပွင့်ရသောကြောင့်၊ System Player အနိုင်ရပါသည်။ System Player ၏ Total Money  အတွင်းမှ 10000နှုတ်ယူသွားကာ System Player ၏ Total Money အတွင်း သွားပေါင်းပေးပါသည်။ Reset Button အား နှိပ်ကြည့်ပါဦးမည်။


ဤနည်းအားဖြင့် JavaFX အား အသုံးပြုကာ GUI Application တစ်ခုအား လွယ်ကူစွာ ရေးသားနိုင်သည်ကို တွေ့ရပါသည်။ ဤနေရာတွင် Binding, CSS နှင့် Animation တို့အား ရေးသားထားခြင်းမရှိပါ။ အဆိုပါ Features များအား အသုံးပြုပါက ပို၍စိတ်ဝင်စားဖွယ်ကောင်းသော Application တစ်ခုအား Java FX ဖြင့် ရေးသားနိုင်မည် ဆိုသည်မှာ မလွဲပေ။

ရေးသားထားသော Source Code များအား အောက်ပါ GitHub Repository အတွင်းမှ ရယူနိုင်ပါသည်။
https://github.com/minlwin/mmju/tree/master/dice-game

ဆက်ပါဦးမည်။ လေးစားစွာဖြင့်
မင်းလွင်

No comments:

Post a Comment