-
Notifications
You must be signed in to change notification settings - Fork 52
Extensions (RGSS, Modules)
.load_data(path: String[, restore: Boolean = true])
: Now possesses a second optional Boolean argument. If restore
is false, load_data
will not try to load the file data with Marshal first.
# This will not work, since load_data originally only
# loaded Marshal-dumped data...
stuff = load_data("regular_data/sometext.txt")
# ...but this would work, returning an ASCII-8BIT encoded
# string (or just a string, if built with a version of MRI
# before encodings)
stuff = load_data("regular_data/sometext.txt", false)
This enables you to store any kind of data you want within archives or paths loaded with System.mount
.
mkxp-z can play multiple BGM tracks at once. to enable this functionality, just raise the BGMTrackCount
setting in the JSON configuration to however many tracks you think you'll need.
Each BGM function now has an additional optional argument that indicates which track you want it to operate upon. This value is zero-indexed, compared to the one-indexed value in the JSON, so if you ask for 4 tracks, you can use 0-3 as track values.
When no track is given (nil
or nothing provided), track 0 will be assumed. bgm_play
, bgm_stop
, and bgm_fade
will automatically stop/fade all other currently playing tracks in this case. If a track is given, on the other hand, these functions will operate on that track specifically, not affecting any others.
Two new functions were added to control BGM volume at any point in time, as well:
-
.bgm_volume([track: Integer|Nil])
returns current volume levels, in values from 0 to 100. -
.bgm_set_volume(vol: Integer[, track: Integer|Nil])
sets current volume levels, using a value from 0 to 100.
If a track is provided, then these functions use values specific to the given channel. Otherwise, these two functions use a multiplier that is applied across every track. This way, you can either control the entire BGM "bus" as a whole, or adjust specific sections of the BGM that you wish to be audible.
BGM playback supports FLAC.
mkxp-z has four new functions that mirror the normal input functions: .pressex?
, .triggerex?
, .repeatex?
, and .releaseex?
. These can be used in two ways:
- By using Windows Virtual-Key codes, or
- the names of SDL scancodes, as symbols (minus the
SDL_SCANCODE_
prefix).
# Microsoft VKey-codes
Input.pressex? 0x01 # Left mouse button
Input.triggerex? 0xa1 # Left Shift
# SDL Scancode names, without their "SDL_" prefix...
Input.repeatex? :BACKSPACE
Input.triggerex? :RETURN
# ...except for top row number keys! They are prefixed with `NUMBER_`
Input.releaseex? :NUMBER_7
You may also check the amount of time a key has been pressed using .time?
and .timeex?
for RGSS inputs and raw inputs, respectively. Time is measured in microseconds.
If the .text_input
property is set to true
, mkxp-z will begin receiving proper text input events, so that you can get direct strings from what is inputted through the keyboard. Setting it to false
will disable it again. While accepting text input, calling .gets
will return the text that has been entered since the last time .gets
was called (using it will clear the buffer)
You may also use the .clipboard
property to get and set the user's clipboard.
An example of both of these concepts:
# A buffer to store the text in
text = ""
# Turn on text input
Input.text_input = true
# Wait until Enter gets pressed
until Input.pressex?(:RETURN)
# Check for Ctrl+C and Ctrl+V!
if Input.pressex?(:LCTRL) || Input.pressex?(:RCTRL)
Input.clipboard = text if Input.triggerex?(:C)
# << is faster than +=
text << Input.clipboard if Input.triggerex?(:V)
else
text << Input.gets
end
# Next frame
Input.update
Graphics.update
end
# Disable text input and print the text that got typed in
Input.text_input = false
p text
If you really need it, you can obtain the state of all keys at the time of the last Input.update
by using .raw_key_states
. It returns an array of Booleans for every SDL scancode, in order.
Mouse button states can be checked using "standard" RGSS input codes:
Input.press? Input::MOUSELEFT
Input.press? Input::MOUSEMIDDLE
Input.press? Input::MOUSERIGHT
Input.press? Input::MOUSEX1 # Mouse Button 4
Input.press? Input::MOUSEX2 # Mouse Button 5
- Vertical scroll can be polled by using
.scroll_v
. - Visibility of the cursor can be toggled with the
Graphics.show_cursor
property. A bit unintuitive that it's not in the Input module I think, but it's there in the original version of mkxp and I chose not to change it. - The position of the mouse, as far as the game is concerned, can be polled with
.mouse_x
and.mouse_y
. - Whether or not the mouse is currently within the window can be checked using
.mouse_in_window?
.
There is now an Input::Controller
module that you can use to interact with controllers. It has a bunch of the same methods as the regular Input module, plus some extras for reading sticks, triggers, and other information.
Within the context of this module:
-
.connected?
returns whether or not there is a controller connected in the first place. -
name
returns the connected controller's name. -
.pressex?
,.triggerex?
,.repeatex?
and.releaseex?
are just like the parent module's functions of the same name. Here though, they take the names of SDL_GameControllerButtons, without theSDL_CONTROLLER_BUTTON_
prefix. The integer values also work. -
.power_level
, returns the controller's power level as a symbol. It can be anything from:MAX
,:WIRED
,:HIGH
,:MEDIUM
,:LOW
, or:EMPTY
. It might also just not work, in which case you'll get:UNKNOWN
. -
.axes_left
returns an array containing the X and Y values of the left stick..axes_right
does the same for the right stick. The values are floats that can range from -1 to 1. (-1 is farthest to the left/top) -
.axes_trigger
returns an array containing the values of the left and right trigger. The values are floats that can range from 0 to 1. (0 is not pressed at all) -
.raw_button_states
, likeInput.raw_key_states
, returns an array of booleans, one for each button in the same order listed by SDL. -
.raw_axes
does a similar thing for the axes, in this order.
Input::Controller.connected? # There's a controller connected in the first place, right?
Input::Controller.pressex? :START # Is the start button pressed?
ls_x, ls_y = Input::Controller.axes_left # What is the position of the left stick?
- You may automatically resize the window based on the internal width and height by using the
.scale/.scale=
property. It accepts values between0.5
and4
(but you should only ever need up to2
). - For more fine control, you can use
.resize_window(width: Integer, height: Integer[, center: Boolean = false])
. This will resize the window to any size you want. Ifcenter
is set to true, the window will be centered on the screen as well. - Set and unset fullscreen state by setting
.fullscreen/.fullscreen=
totrue
orfalse
. -
.center
will move the window to the center of the screen. - Important enough to mention: Because most VX Ace functions are now available to XP and VX modes by default, you can use
.resize_screen
to change the internal screen size and available drawing area. -
.resize_screen
doesn't impose an upper limit of 640x480 like Enterbrain's runtime does; you can pick as high a resolution as your GPU can handle. -
.frame_rate=
doesn't impose a range of 10 to 120 like Enterbrain's runtime does; you can pick as high a frame rate as your CPU and GPU can handle, or as low as 1 FPS. - Certain settings can be adjusted by setting these properties to
true
orfalse
:.fixed_aspect_ratio/.fixed_aspect_ratio=
.smooth_scaling/.smooth_scaling=
.integer_scaling/.integer_scaling=
.last_mile_scaling/.last_mile_scaling=
mkxp-z had support for video playback contributed a while back. The function is back, and available on all RGSS versions as with most of the other version-exclusive APIs.
The function has a couple new additions, and a couple of caveats.
The pros: The function's "signature" now looks a bit like this:
# file to play volume scene is skippable?
Graphics.play_movie(filename: String[, volume: Integer[, skip: Boolean = false]])
You may set volume with volume
, and whether or not the scene is allowed to be skipped with skip
. If skipping is allowed, pressing Input::B
or Input::C
will immediately end video playback.
Videos are scaled to fit the game's screen (not the window), with a black letterbox placed behind them when aspect ratios do not match. If the letterbox isn't desired, both the letterbox and the video are just normal Sprites backed by bitmaps; the letterbox has a z-level of 4999, and the video has a z-level of 5001. This means that you can create a new sprite with a z-level of 5000 and it will appear between the letterbox and the video, effectively letting you replace or "remove" the letterbox.
The cons:
You must use Ogg-Theora (.ogv) video with a YUV420p pixel format. If the video isn't OGV, the function will fail. If the video is OGV but not YUV420p, the program will panic and abort (just something that Theoraplay does, apparently).
With FFMPEG, you'd make something in the correct format like this:
ffmpeg -i in.mp4 -b:a 128K -q:v 7 -pix_fmt yuv420p out.ogv
# -q:v - video quality, higher is "better" for theora
# you can also use -b:v to set video bitrate directly
# -pix_fmt - pixel format
# -b:a - audio bitrate
The video processing isn't hardware-accelerated. Theoraplay converts each frame from YUV420p to RGB through CPU, then that gets uploaded to a bitmap and displayed. Basically: be careful with your video resolution and bitrate. If it's too high, it will lag and cause strange things to happen.
The video must use "normal" dimensions. This means any combination of the 240s, 360s, 480s, 720s... no 853s.
In general though, this is still better than not having it at all. Using it functions just like this:
# Just play a video, unskippable, volume 100
Graphics.play_movie("cutscene.ogv")
# Play a video, volume 60%, allow skipping
Graphics.play_movie("cutscene.ogv", 60, true)
.screenshot(path: String)
will take a screenshot and save it to path
in PNG, JPEG, or BMP format depending on the file extension given.
You may also use Graphics.snap_to_bitmap.to_file(path: String)
. They do the same thing.
.delta
returns the amount of time passed since the last call to Graphics.update
. Time is, as usual, in seconds, so if you are running at 60FPS then you should expect a value around 0.016.
You can get the "real" current framerate with Graphics.average_frame_rate
. This is measured based on how long it took the past several calls to Graphics.update to come through, including running all of your code, so it's more accurate in general than normal mkxp's FPS counter. It's the same number you see when you press F2
or on your Touch Bar, only as a Float, and unrounded.