How to make a mechanic (With example!) - matan1905/GameMechanicManager GitHub Wiki

In this example we would learn how to make a mechanic! and we will make a Fishing mechanic along the way.

The way this page explains is:

  • "Abstract" what to do
  • code example with a simple Fishing mechanic

So first of all, write the possible lifecycle of your mechanic(it could save a lot of time and rewriting)

Fishing mechanic (Game developer perspective): The player would start fishing. which will wait a random amount of time and then show a subtle indicator of a fish biting for a small window of time, if the player recognized it and pulled the fishing rod in time he will get a fish! otherwise if the player pull too early or too late he will get nothing!

To make a mechanic, first make sure you have Defined the following:

  • Events and their arguments (and callback arguments, if any)
  • Notifications and their arguments.
  • Any possible setting and their defaults

Fishing mechanic events and notifications:

Events:
* start_fishing (no arguments,no callback arguments)
  -When the player starts fishing
* cancel_fishing (no arguments,no callback arguments)
  -When the player no longer desire fishing
* pull_rod (no arguments,callback arguments: boolean: caught a fish)
  -The player has decided to pull the fishing rod to see if a fish has bite the bait

Notifications:
* fish_bite
  -A fish has bitten the bait! tell the game to show their indication

Settings:
* fish_rod_window_time (10 seconds)
  -The amount of time the player could still pull his fishing rod
* min_fishing_time (5 seconds)
  -Minimum time the player needs to wait before any fish will start biting
* max_fishing_time (15 seconds)
  -Maximum time the player needs to wait before any fish will start biting

after you have defined those you need to create your class , extend GameMechanic and implement required methods and write your logic.

Pay attention to the comments:

import com.opedea.GameMechanicManager;
import com.opedea.datasource.DataSource;
import com.opedea.mechanics.EventReceiver;
import com.opedea.mechanics.GameMechanic;
import com.opedea.mechanics.Settings;

public class FishingMechanicExample extends GameMechanic {
    //These are the settings
    private float windowTime;
    private float minFishingTime;
    private float maxFishingTime;

    private boolean fishing=false;//Whether the player is fishing or not

    private float timePassed=0;//the time passed in seconds
    private boolean fishInBait=false;//whether a fish is eating the bait or not
    private float fishTime;//a random value between min-max fishing time, used to tell when a fish is biting in a simple manner

    //Using the event receivers as fields makes the code look cleaner in my opinion, Do as you please though!
    EventReceiver startFishing = new EventReceiver() {
        @Override
        public void receive(Callback callback, Object... objects) {
            fishing=true;
            reset();
        }
    };
    EventReceiver cancelFishing = new EventReceiver() {
        @Override
        public void receive(Callback callback, Object... objects) {
            fishing=false;
            reset();
        }
    };
    EventReceiver pullRod = new EventReceiver() {
        @Override
        public void receive(Callback callback, Object... objects) {
                callback.callback(fishing&&fishInBait);//returns if the player got himself a fish

        }
    };

    //Reset everything and get ready to a new session
    private void reset(){
        fishInBait=false;
        timePassed=0;
        fishTime = (float) (Math.random()*maxFishingTime +minFishingTime);//a random value between min and max
    }
    //Overriding a none abstract method to keep track of the time.
    //It is important to use gameMechanicManager.tick() in the main game loop for this to work!
    @Override
    public void tick(float delta) {
        if(fishing) {//we don't want to do this while the player isn't fishing
            timePassed += delta;//updating the time
            if(!fishInBait){
                if(timePassed-fishTime >= 0){
                    //it's biting time!
                    fishInBait=true;
                    getGameMechanicManager().sendNotification("fish_bite",null);//sends the notification
                    timePassed=0;
                }
            } else{
                if(timePassed-windowTime>0){
                    //the player missed his chance! the fish escaped
                    reset();
                }
            }
        }
    }


    @Override
    protected void registerAllEvents(GameMechanicManager gmm) {
        gmm.registerReceiver("start_fishing",startFishing);
        gmm.registerReceiver("cancel_fishing",cancelFishing);
        gmm.registerReceiver("pull_rod",pullRod);
    }

    @Override
    protected void loadModels(DataSource dataSource) {
        //Unused for this example as we don't need persistent data storage
    }

    @Override
    protected void loadSettings(Settings settings) {
        //Any setting that doesn't exist already will be created.
        //All values are Strings, so we need to parse them first.
        windowTime = Float.parseFloat(settings.getSetting("fish_rod_window_time","10"));
        minFishingTime = Float.parseFloat(settings.getSetting("min_fishing_time","5"));
        maxFishingTime = Float.parseFloat(settings.getSetting("max_fishing_time","15"));
    }


    @Override
    public void reloadSettings(Settings settings) {
        //this gets called everytime the developer desires to reload the settings, because we might need to reload all of the
        //settings, might as well just forward it to the regular loadSettings(but remember you can force settings to only be reloaded after restart).
        loadSettings(settings);
    }
}

And there you have it!

in the page "how to implement a mechanic" we will go through how to implement this very mechanic in a game