-
Notifications
You must be signed in to change notification settings - Fork 0
Implementation
This page explains the implementation of the guidebook. This means the creation of the new java classes that implement the page and link the buttons to other pages. The layout of the page and the importing of data.
New classes were made to implement the guidebook's new page. Classes that were added were GuidebookActions, GuidebookDisplay, GuidebookScreen and GuidebookExit.
The connection between these classes can be seen in the UML below.
A sequence diagram is shown below to illustrate how the JSON file and content are updated.
A more detailed explanation is below.
A JSON file was created to fill the content of the Guidebook. We chose a JSON file type because it has an easy maintainability feature; if we want to add new things to the Guidebook, we can easily add the contents here without having to change the code that has been written. We separated the JSON into three parts.
[
{
"pageNumber" = ...,
"header" = ...,
"content" = ...,
"image" = ...,
"imagePosition" = ...
},
...
]
The header corresponds to the topics that are covered specifically by the respective section, with content being the actual content displayed on the page. The image and imagePosition sections (which can be the empty string "" [if one is, then the other must be too]). Below is a glimpse of the JSON file for the Guidebook. Please click this link to see the full JSON file.
[
{
"pageNumber": 0,
"header": "Table of Contents",
"content": "Page 1 - How to Play \nPage 2 - Crystal \nPage 3 - Main Character \nPage 4 - Day and Night Cycles \nPage 5 - Enemies \nPage 7 - Types of Buildings \nPage 9 - Resource Buildings \nPage 10 - Currency \nPage 11 - Shop \nPage 13 - Inventory \nPage 14 - Achievements",
"image": "",
"imagePosition": ""
},
...
]
Please note that the number of pages in the JSON file must be even (even if there are empty pages) in order for the guidebook to be displayed and not break the game. And empty page can be created by making all the fields - as an entry of a page in the JSON file - an empty string. Additionally, a page with an empty header will not produce a title and title frame for that page. If the "image" and imagePosition are left as empty strings then no image will be loaded on the screen. The imagePosition controls the layout of the image on the screen. Currently, "UP" and "DOWN" - as the only valid values when parsed - position the image above and below the content respectively. Refer to the image below in Figure 1 to see what this means in practice.
Figure 1: Guidebook with left page having no header and content while right page having both
Animation was achieved first by the creation of assets for each animation step. In summary, 5 unique assets were created, which can be seen below in Figure 2.
Figure 2: Top-left - closed, top-middle - opening, top-right - open, bottom-left - flipping to previous page, bottom-right - flipping to next page
The animation was achieved by using SceduledExecutorServicer and in particular the Executors.newSingleThreadScheduledExecutor() and its schedule method. A simple one-step animation can be achieved in the following way:
ScheduledExecutorService flicking = Executors.newSingleThreadScheduledExecutor();
Runnable flickTask = () -> {
GuidebookScreen.renderTrigger = 1;
Gdx.graphics.requestRendering();
};
flicking.schedule(flickTask, 250, MILLISECONDS);
Code sample used to flick page to either next/previous page
Please note that the Runnable task must call only static methods and variables as a thread is instantiated and is sent out to perform the task which does not have access to the entire game.
In order to create a two-step transition, the Runnable method must schedule another thread task, as shown below:
ScheduledExecutorService opening = Executors.newSingleThreadScheduledExecutor();
Runnable openingTask = () -> {
GuidebookScreen.renderTrigger = 1;
Gdx.graphics.requestRendering();
ScheduledExecutorService open = Executors.newSingleThreadScheduledExecutor();
Runnable openTask = () -> {
GuidebookScreen.renderTrigger = 1;
Gdx.graphics.requestRendering();
};
open.schedule(openTask, 250, MILLISECONDS);
};
opening.schedule(openingTask, 750, MILLISECONDS);
As it can be seen above, after opening task is scheduled an openTask is scheduled from within the Runnable openingTask. This nested behavior can be extended for n-step transitions, but it can quickly become impractical, thus then a different solution might be more feasible.