-
Notifications
You must be signed in to change notification settings - Fork 0
2. Basic shapes, images, text
Thanks to be built-in support of NTE and JCM mods, we can use Java Graphics and Java Graphics2D libraries to draw on our screen.
In this page, all file structures and variable names are in compliance with the Template Resource Pack.
- Constant - a stuff that once created, will not be changed until the code ends. It is defined by this format:
const NAME_OF_CONSTANT = some data;
To draw basic shapes, images and text, we'll make use of info-panel.js and formatting.js.
info-panel.js handles most drawing code, while formatting.js is an optional file to store shape style constants.
To use these two files, we need to include them near the top of main.js, so that main.js can recognise which files to call for graphics drawing. This has already been set in the Template Resource Pack.
// In main.js
include("info-panel.js");
include("formatting.js");
When you code the graphics part, you might use file paths often. Note that for scripting in MTR mod, there are some limitations for file paths:
- The file path should contain no uppercase letters
- It is highly recommended that you put the files inside the js folder
Skip this part if you're using the Template Resource Pack - it has already set these for you.
To allow drawing on the screen, we need to first import the required libraries.
// In info-panel.js and formatting.js
importPackage(java.awt);
importPackage(java.awt.geom);
importPackage(java.lang.math);
Then, in main.js, create a graphics pen. In this case, it is named g, and is created for the screen named info-panel.
// In main.js
let g = state.infoPanel.graphicsFor("info-panel");
Before we draw anything, we need to set a colour for the pen.
// In info-panel.js, use any one of the following every time you set a colour:
g.setColor(Color.decode("#hex RGB value"));
g.setColor(Color(red value, green value, blue value));
g.setColor(Color(red value, green value, blue value, transparency value));
Note that the red, green, blue, and transparency values are from 0 to 1, decimals allowed, which are different from the more common 0-255 values. If you're more comfortable with 0-255 values, you may code like this:
// Use 0-255 values, then add "divided by 255" after each one
Color(red value / 255, green value / 255, blue value / 255, transparency value / 255)
Also, make good use of constants - you can set the colour values as constants, so you won't need to write long colour values every time you set a colour.
// In info-panel.js or formatting.js
const COLOR_1 = Color.decode(...);
const COLOR_2 = Color(...);// In info-panel.js
g.setColor(COLOR_1);
There are two types of basic shapes: filled shapes and outlined shapes. Filled shapes are fully covered by a single colour, while outlined shapes are hollow.
The code for filled shapes are quite straightforward:
// In info-panel.js
g.fillRect(x of upper-left, y of upper-left, width, height);
g.fillOval(x of upper-left, y of upper-left, width, height);
g.fillPolygon([x of vertex 1, x of vertex 2, x of vertex 3, ...], [y of vertex 1, y of vertex 2, y of vertex 3, ...], total number of vertices)
For outlined shapes, they are similar to filled ones, but require setting a stroke before drawing.
Again, make use of constants here.
// In info-panel.js or formatting.js
const STROKE_1 = new BasicStroke(width);// In info-panel.js
g.setStroke(STROKE_1);
g.drawRect(same as fillRect);
g.drawOval(same as fillOval);
g.drawPolygon(same as fillPolygon);
Simple logic: set a constant for the image's path, then display the image.
However, there's an limitation:
- Strictly only .png and .jpeg file extensions are supported, not even .jpg
Also, don't forget about other file name limitations, like it should contain no uppercase letters, and it is highly recommended that you put the image file inside the js folder.
// In info-panel.js or formatting.js
const IMAGE_1 = Resources.readBufferedImage(Resources.idRelative("image path"));
// If the image file is store in the js folder
const IMAGE_2 = Resources.readBufferedImage(Resources.idRelative("./image file name"));// In info-panel.js
g.drawImage(IMAGE_1, x of upper-left, y of upper-left, width, height, null);
Just assume the final null in drawImage is fixed. If you're interested in what it means, check the documentations of Java Graphcis and Java Graphics2D.
Set a constant for font, then set its size, then draw the text.
// In info-panel.js or formatting.js
const FONT_1 = Resources.getSystemFont("MTR mod built-in font name");
const FONT_2 = Resources.readFont(Resources.idr("custom font path"));// In info-panel.js
g.setFont(FONT_1.deriveFont(0, font size));
g.drawString("text with fixed content", x of bottom-left, y of bottom-left); g.drawString(text with variable content, x of bottom-left, y of bottom-left);
Just assume the 0 in deriveFont is fixed. Look up in the Java Graphcis and Java Graphics2D if you want to learn more.
Also, note that the x and y coordinates in drawString represent the bottom-left point of the text, which is different from the upper-left coordinates in other graphics code. That's because we're setting the position for the baseline of the text.
The Template Resource Pack has converted two MTR mod built-in fonts into SANS and SERIF:
// In info-panel.js
g.setFont(SANS.deriveFont(0, font size));
g.setFont(SERIF.deriveFont(0, font size));
The Template Resource Pack includes a few variable text types. We'll talk about how they work in the future. For now, you may simply use them with drawString.
- nextEn - the English (or latin letters) name of the next stop
- nextZh - the Chinese (or Japanese, Korean) name of the next stop
There's also some helper code:
// In info-panel.js
// Align the text to the center of the screen, and squeeze it to the width limit
CentreText(g, "text with fixed content", x of bottom-centre, y of bottom-centre, width limit);
CentreText(g, text with variable content, x of bottom-centre, y of bottom-centre, width limit);
// In info-panel.js
if (hasArrived) {
graphics to show when the train has arrived at a stop
}
else {
graphics to show when the train is still running
}
I can't see part of the graphics on the screen
- Make sure you've set suitable colours for the graphics and their background - they should have enough contrast
- Check the sequence of graphics in your code. Those coded near the top of the file will be displayed first, and will likely be covered by those coded near the bottom.
Previous: Screen size & position | Next: To be updated