Viper Virtual Console official website
Since November 2023, the Viper console has been undergoing a complete rewrite using the Godot Engine. This manual is a work in progress and may not fully reflect the current features of the console. However, the cheatsheet section does reflect the features of the current stable version.
If you’re consulting this from the viper console, an online version of this manual can be found at https://viperconsole.github.io
This is the 3.0.1a stable version manual (the one published at https://jice-nospam.itch.io/viper-console). You can browse the 3.0.2a development version at https://viperconsole.github.io/index_dev.html
Viper is a virtual console inspired by early 90s hardware such as NEC/PCEngine, Amiga 500, and Neo-Geo. While its primary focus is on 2D, pixel-art-based video games, it remains versatile enough to accommodate the development of 3D engines.
Although some 90s limitations have been lifted—like the use of 32-bit colors instead of indexed palettes—the project strives to maintain the nostalgic early 90s aesthetic. Notably, Viper avoids employing the alpha channel extensively, limiting its usage to layer compositing and parallax effects.
Graphics :
- 384x224 screen resolution
- 32 bits colors with alpha channel support
- Display based on a set of transparent layers
- Layers can be moved and resized
- Layer operations supported (mix, mul, add, sub, ...)
- Any number of offscreen spritesheets
- Row/colscroll parameters for smooth parallax effects
Sound :
- 6 channels 44100Hz (native) or 16000Hz (web)
- Subtractive synthetizer
- Saw, triangle, square and noise generators
- Samples support (.wav)
- Midi controller input support
Input :
- Support mouse, keyboard and controller
Resources :
- Can load images (.png) and samples (.wav)
- Supports both local filesystem and web connectivity through HTTPS.
Code :
- Uses GDScript
- Full support of Godot API including coroutines
From the console main menu, open the code editor and paste the code below :
var x = 10
func draw() :
V.gfx.clear()
V.gfx.print(V.gfx.FONT_8X8, "Hello world!", Vector2(x,10))
Then press the Start button from the main menu to run the code.
The draw()
function is invoked every frame, and it’s the designated place to call all rendering methods from V.gfx
. Keep in mind that the framerate is not guaranteed and may vary across different target systems.
The update() function is designed for updating time-dependent variables and is called at a fixed rate of 60 times per second. This consistent rate ensures uniform game speed across all systems. Additionally, it’s the ideal place to manage user input using the V.inp API.
func update() :
x = 10 + V.elapsed()*50 # move at 50 pixels / second
There’s a third function available for setting up things before your game starts :
func init() :
# do some initialization stuff
pass
This is the designated place for loading images and samples. It’s recommended to perform these loading operations here to avoid pauses, particularly when fetching resources from HTTPS. This function can also call rendering functions, as it is executed during the rendering phase of the first frame.
Open the store from the main menu by clicking on and enter ‘tuto’ in the filter field. Here, you will discover a variety of commented tutorials that showcase the different features of the console.
The console features its own internal file system, allowing you to copy files through drag-and-drop directly onto the console window. For instance, you can drag an ‘spritesheet.png’ image onto the console window and then access it in your code simply as ‘spritesheet.png.’
This functionality also facilitates the effortless replacement of resources, be it a sample or an image, while running any game. By dropping a replacement file with the same name onto the window, the console seamlessly utilizes this file instead of the original resource.
You can also access files from outside the console using “file://<path>” syntax (only on native version of the console) or “https://<url>” to access online resources.
You don’t have to edit the code from the console editor, you can use an external editor and simply put the address of the file in the internal code editor :
Type file://C:/mygame.gd
to load the code from the C:\mygame.gd
file.
Type https://mysite.com/mygame.gd
to load the code from the given URL using an HTTP request.
You can use those arguments to control the console’s behavior. For instance, to enable fullscreen at launch :
Use viper.exe --fullscreen
in native mode.
Use https://html.itch.zone/html/9217920/index.html/?fullscreen=1
in web mode
Parameter | Description |
---|---|
Bios | |
cart=<path> |
Start a cartridge at launch. path = the .gd script to run |
no_deepswitch |
Disable deepswitch menu (ctrl-shift-`) |
no_docker |
Disable docker menu |
Parameter | Description |
---|---|
Graphics | |
no_crt |
Disable all CRT effects |
no_crt_warp |
Disable screen warping effect |
no_crt_scan |
Disable scanline effect |
no_crt_mask |
Disable shadow mask effect |
fullscreen |
Start in fullscreen mode |
no_splash |
Disable splash screen (only on native mode) |
no_vsync |
Disable vertical sync (only on native mode) |
Parameter | Description |
---|---|
Audio | |
no_audio |
Start with sound disabled |
audio_rate=<rate> |
Change the audio sample rate (value in Hz) |
Parameter | Description |
---|---|
Input | |
neutral_zone=<value> |
Change the controllers default neutral zone (value between 0.0 and 1.0) |
Key | Command |
---|---|
Escape Joypad 6* |
Toggle docker menu |
F12 | Save a screenshot in %USERPROFILE%\Pictures\Viper |
Ctrl-Shift-` | Toggle deepswitch menu |
X LMB Joypad 0* |
Action1 |
C RMB Joypad 1* |
Action2 |
* : Joypad buttons correspondance
Button | Sony | XBox | Nintendo |
---|---|---|---|
0 | cross | A | B |
1 | square | X | Y |
6 | start | menu | + |
Viper uses GDScript as scripting language.
See https://docs.godotengine.org/en/stable/tutorials/scripting/gdscript/index.html for more information
The following functions are called by the console :
func init()
: called once during the cartridge boot.This is where external resources should be loaded with
V.gfx.load_img
for imagesV.snd.new_instrument
for sound samples
func update()
: called 60 times per secondThis is where you should update anything time dependant. Don’t call drawing methods in this function
func draw()
: called every frameRender one game frame. Framerate might vary from one computer to another. Use V.gfx.clear()
to erase the previous frame.
All the Viper API can be found under the V singleton :
V.gfx
: the graphics APIV.snd
: the audio APIV.inp
: the V.input APIIt also contains a few utilities :
V.elapsed() -> float
This function returns the time elapsed since the game started in seconds.
The viper screen size is 384x224 pixels. You can get those values with V.gfx.SCREEN_WIDTH
and V.gfx.SCREEN_HEIGHT
. The graphics engine can display on screen any number of transparent layers. Viper doesn’t use alpha blending, but a transparent key color that can be changed with V.gfx.set_transparent_color
(default is pure black).
All colors are expressed with integer component between 0 and 255. All coordinates are floats but for a pixel perfect result, you should truncate them to integers. But smooth movement can be achieved using float coordinates.
Each layer can be resized with V.gfx.set_layer_size
and moved with V.gfx.set_layer_offset
.
You can hide and show layers with V.gfx.show_layer
and V.gfx.hide_layer
. By default, only one layer (layer 0) is displayed.
The console renders the layers in increasing id order (first layer 0, then 1 on top of it and so on).
Layers can be used to overlay graphics on screen or store bitmap fonts/sprite sheets offscreen. You can copy an image from a layer to another with V.gfx.set_sprite_layer
, V.gfx.set_active_layer
and V.gfx.blit
. You can load an image in the current active layer with V.gfx.load_img
.
Each visible layer applies a color operation between its color and the underlying color :
V.gfx.LAYEROP_SET
: new pixel color = layer pixel color (default)V.gfx.LAYEROP_ADD
: new pixel color = current pixel color + layer pixel colorV.gfx.LAYEROP_AVERAGE
: new pixel color = (current pixel color + layer pixel color)/2V.gfx.LAYEROP_SUBTRACT
: new pixel color = current pixel color - layer pixel colorV.gfx.LAYEROP_MULTIPLY
: new pixel color = current pixel color * layer pixel colorExample :
V.gfx.set_layer_operation(1, V.gfx.LAYEROP_ADD)
You can draw on any layer by activating it with V.gfx.set_active_layer(id)
.
You can get the number of frames rendered during the last second with :
V.gfx.fps()
set_active_layer(id)
id is an arbitrary integer value. Visible layers are rendered in ascending id order.
load_img(layer, filepath, [resource_name])
filepath is an URL :
'myimage.png'
'https://someserver.com/myimage.png'
'data:image/png; ...'
TODO To convert an image into data url, simply drag and drop it on the console screen.
If resource_name is defined and not empty, this image can be overriden by the player by running the console with res parameters. This makes it easy for users to mod the game graphics by replacing a named resource with another image.
set_layer_size(id, w, h)
resize a layer (w,h in pixels).
get_layer_size(id)
Example :
local w,h = V.gfx.get_layer_size(0)
set_layer_offset(id, x, y)
set a layer scrolling offset. TODO use id -1 to scroll all visible layers (screen shake effect)
set_rowscroll(id,[start_row],[end_row],[start_value],[end_value])
id
: id of the layer. if no other parameter is set, the rowscroll is disabled for this layerstart_row,end_row
: range of row where we want to change the offsetsstart_value,end_value
: offset value is interpolated between these values (or constant if end_value is nil)
set_colscroll(id,[start_col],[end_col],[start_value],[end_value])
id
: id of the layer. if no other parameter is set, the colscroll is disabled for this layerstart_col,end_col
: range of columns where we want to change the offsetsstart_value,end_value
: offset value is interpolated between these values (or constant if end_value is nil)
clear_scroll(id)
Example :
gfx.set_rowscroll(0,180,223,0,40)
Sets a rowscroll offset for rows 180 to 223. The offset ranges from 0 for row 180 to 40 for row 223
set_layer_operation(id, layer_op)
layer_op values : V.gfx.LAYEROP_SET
/V.gfx.LAYEROP_ADD
/V.gfx.LAYEROP_AVERAGE
/V.gfx.LAYEROP_SUBTRACT
/V.gfx.LAYEROP_MULTIPLY
.
clear([r,g,b])
fill the active layer with the color r,g,b
. If the color is not defined, use the transparent color (default black).
blit_pixels(x,y, width, rgb)
V.gfx.to_rgb24(r,g,b)
to get this valueExample :
V.gfx.blit_pixels(0,0,1,{255})
would blit a single blue pixel at position 0,0 (255 = 0x0000FF => r=0,g=0,b=255)
Another way to write it :
V.gfx.blit_pixels(0,0,1,{V.gfx.to_rgb24(0,0,255)})
Note that this function is far slower than the V.gfx.blit
function which is fully running on the GPU.
line(x1,y1, x2,y2, r,g,b)
draw a line
triangle(x1,y1, x2,y2, x3,y3, r,g,b)
fill a triangle
rectangle(x,y, w,h, r,g,b)
fill a rectangle
circle(x,y, radius_x, [radius_y], r,g,b)
draw a circle/ellipse
disk(x,y, radius_x, [radius_y], r,g,b)
set_font
by defining a rectangular zone inside a layer, and the character size :set_font(id, x,y,w,h, char_width,char_height, [charset], [spacing_h],[spacing_v], [chars_width])
id
id of the layer containing the characters spritesx,y,w,h
define a region of a layer as a bitmap font to use with V.gfx.print
char_width,char_height
if the size of a character in this bitmap (in case of non-monotype font, use the chars_width parameter)charset
is a string representing the characters in the bitmap font.charset
is not set, the ascii table order is expected.spacing_h,spacing_v
additional horizontal and vertical spacing between characters when drawing text (default 0,0)chars_width
is an array containing the width of each character.chars_width
is not set, this is a mono font and every character’s width is char_width
V.gfx.FONT_8X8
: the default mono font that contains the complete 128 ascii table characters.V.gfx.FONT_5X7
: a smaller non-mono font that contains the 93 ascii characters from !
to ~
.V.gfx.FONT_4X6
: a very small mono font that contains the 93 ascii characters from !
to ~
.
print(font, text, x,y, [r],[g],[b])
x,y
using a specific fontr,g,b
: multiply the font’s character sprites with this color (default white)Example : print hello at position 0,0 in white
V.gfx.print(V.gfx.FONT_8X8, "hello", 0,0)
You select a spritesheet with set_sprite_layer
(default is V.gfx.SYSTEM_LAYER
). V.gfx.blit
uses it as a source. The destination is the current active layer.
Source and destination cannot be the same layer.
set_sprite_layer(id)
define the current source for sprite blitting operations
blit(sx,sy,sw,sh, dx,dy, [r,g,b], [angle], [dw],[dh], [hflip],[vflip])
sx,sy
: top left pixel position in the spritesheetsw,sh
: rectangular zone size in the spritesheet in pixelsdx,dy
: destination on active pixel buffer (top left position if angle==nil, else center position)r,g,b
: multiply the sprite colors with this color (default white)angle
: an optional rotation angle in radiansdw,dh
: destination size in pixel (if 0,0, or nil,nil, uses the source size). The sprite will be stretched to fill dw,dhhflip, vflip
: whether to flip the sprite horizontally or vertically (default false)
blit_col(sx,sy,sw,sh, dx,dy, [r,g,b], [angle], [dw],[dh], [hflip],[vflip])
sx,sy
: top left pixel position in the spritesheetsw,sh
: rectangular zone size in the spritesheet in pixelsdx,dy
: destination on active pixel buffer (top left position if angle==nil, else center position)r,g,b
: replace all sprite’s pixels with this color (default white)angle
: an optional rotation angle in radiansdw,dh
: destination size in pixel (if 0,0, or nil,nil, uses the source size). The sprite will be stretched to fill dw,dhhflip, vflip
: whether to flip the sprite horizontally or vertically (default false)You can define a spritesheet on any layer using the V.gfx.set_spritesheet
function.
set_spritesheet(layer, sprite_w, sprite_h, [off_x], [off_y], [grid_width])
layer
the layer containing the spritessprite_w, sprite_h
: the size of a sprite in pixelsoff_x, off_y
: the top-left position of the sprite grid in the layer (default 0,0)grid_width
: in case the spritesheet doesn’t use all the layer width, how many sprites are in a rowYou can then blit a sprite from this layer using V.gfx.blit_sprite
:
blit_sprite(spritesheet_id, sprite_num, dx, dy, [r,g,b], [angle], [dw],[dh], [hflip],[vflip])
spritesheet_id
: id returned by the set_spritesheet
functionsprite_num
: number of the sprite in the grid (0 = top-left, row-first order)dx,dy
: destination on active pixel buffer (the sprite’s top left position if angle==nil, else center position)r,g,b
: multiply the sprite colors with this color (default white)angle
: an optional rotation angle in radiansdw,dh
: destination size in pixel (if 0,0, or nil,nil, uses the sprite size). The sprite will be stretched to fill dw,dhhflip, vflip
: whether to flip the sprite horizontally or vertically (default false)Example :
-- define layer 1 as a grid of 32x32 pixels sprites
spritesheet_id = V.gfx.set_spritesheet(1, 32, 32)
-- blit the top left sprite (#0) on the current layer at position 10,10
gfx.blit_sprite(spritesheet_id, 0, 10, 10)
The viper has 6 channels that each can play stereo sound at 48kHz with float32 samples.
You can create any number of instruments that produce sound. Instrument can either use additive synthesis by using various oscillators or read samples from .wav files.
Oscillator instrument properties:
oscillator parameters
OVERTONE
: amount of overtoneOVERTONE_RATIO
: 0 = octave below, 1 = fifth aboveSAW
: amount of sawtooth waveform (0.0-1.0)ULTRASAW
: amount of ultrasaw in the saw waveform (0.0-1.0)SQUARE
: amount of square waveform (0.0-1.0)PULSE
: width of the square pulse should be in ]0..1[
intervalTRIANGLE
: amount of triangle waveform (0.0-1.0)METALIZER
: amount of metalizer in the triangle waveform (0.0-1.0)NOISE
: amount of noise (0.0-1.0)NOISE_COLOR
: from white (0.0) to pink (1.0) noise
filter parameters
FILTER_BAND
: type of filter (LOWPASS
, BANDPASS
, HIGHPASS
, NOTCH
)FILTER_DISTO
: amount of distortion (0-200)FILTER_GAIN
: lowshelf filter boost in Db (-40, 40)FILTER_CUTOFF
: upper limit of frequencies getting a boost (0-8000)
lfo parameters
LFO_AMOUNT
: amplitude of the lfo waveform (0-1)LFO_RATE
: frequency of the lfo waveform (0-8000)LFO_SHAPE
: type of waveform (SAW
, SQUARE
, TRIANGLE
)LFO_PITCH
: whether the lfo affects the notes pitch (0 or 1)LFO_FILTER
: whether the lfo affects the filter cutoff (0 or 1)LFO_PULSE
: whether the lfo affects the pulse width (0 or 1)LFO_METALIZER
: whether the lfo affects the metalizer amount (0 or 1)LFO_OVERTONE
: whether the lfo affects the overtone amount (0 or 1)LFO_ULTRASAW
: whether the lfo affects the ultrasaw amount (0 or 1)
envelop parameters
ATTACK
: duration of attack phase in secondsDECAY
: duration of decay phase in secondsSUSTAIN
: level of sustain phase between 0.0 and 1.0RELEASE
: duration of release phase in seconds
By default, envelop is altering the note volume. But it can also be used to alter other parameters :
ENV_AMOUNT
: scale the effect of the envelop on the parameterENV_PITCH
: amount of envelop altering the note pitchENV_FILTER
: amount of envelop altering the note pitchENV_METALIZER
: amount of envelop altering the metalizer parameter of the oscillatorENV_OVERTONE
: amount of envelop altering the overtone parameter of the oscillatorENV_PULSE
: amount of envelop altering the pulse width of the oscillatorENV_ULTRASAW
: amount of envelop altering the utrasaw parameter of the oscillatorSample instrument properties :
FILE
: path to the .wav fileFREQ
: base frequency of the sound in the fileLOOP_START
: sample index where to start the loopLOOP_END
: sample index where to end the loopATTACK
: duration of attack phaseDECAY
: duration of decay phaseSUSTAIN
: duration of sustain phaseRELEASE
: duration of release phasenew_instrument(description)
: create a new instrument, return a numerical id for the instrument that can be used in the song patterns (the first is 0 then it is incremented for each new instrument).
For oscillator instruments, the description starts with the INST
keyword followed with a list of parameters. It should end with the NAM
parameter with the instrument name.
Example:
var triangle_id = V.snd.new_instrument("INST OVERTONE 1.0 TRIANGLE 1.0 METALIZER 0.85 NAM triangle")
var pulse_id = V.snd.new_instrument("INST OVERTONE 1.0 SQUARE 0.5 PULSE 0.5 TRIANGLE 1.0 METALIZER 1.0 OVERTONE_RATIO 0.5 NAM pulse")
For sample instruments, the description starts with the SAMPLE
keywords followed with a list of parameters.
Example :
snare_id = V.snd.new_instrument("SAMPLE FILE musics/samples/snare.wav FREQ 17000")
set_instrument(id, new_description)
: update the parameters of instrument id from a new descriptionplay_note(instrument_id, frequency, lvolume, [rvolume], [channel])
: start playing a note on a channel (between 0 and 5). If channel is not defined, any free channel will be used. volume is between 0 and 1set_channel_volume(channel, lvolume, [rvolume])
: change the volume of a channel without interrupting the oscillator/sampleset_channel_balance(channel, balance)
: alternative way to change the volume of a channel, balance is between -1 (left) and 1 (right)set_channel_freq(channel, freq)
: change the frequency of a channel without interrupting the oscillator/samplestop_channel(channel)
: mute the channelreserve_channel(channel)
: mark a channel so that it’s not used except if explicitely adressed in play_note, play_pattern or play_musicrelease_channel(channel)
: release a channel so that it can be used by play_note, play_pattern or play_music when the channel are not specifiedA pattern is a list of notes that plays at a specific rate.
new_pattern(description)
: register a new pattern and returns its id (0, then incremented for each new pattern).The description starts with the PAT
keyword followed by the notes duration (or speed at which the pattern plays the notes). The duration is divided by 120. For example :
Then it’s followed by a list of notes. Example :
new_pattern("PAT 02 F.2070 G.2070 D.3070 C.4070")
The note format is [note] [octave] [instrument_id] [volume] [fx] with :
You can add a silence by filling the note format with 6 dots : ......
Example :
new_pattern("PAT 16 C#3915 ...... ...... C#3915 D#3835")
set_pattern(id, new_description)
: update a patternplay_pattern(id, [channel])
: play the pattern on a channel. If channel is not defined, any free channel will be used.A song is an ordered list of patterns to play on one or several of the 6 available channels.
new_music(desc)
: create a new music from a description. return an id (0, then incremented for each new music)The description is a multi-line string.
NAM
parameter.PATLIST
parameter (you can select only a part of all the patterns created).Example :
MUSIC_TITLE = [[NAM title screen
PATLIST 56 57 58 59 60
SEQ 024... 134...]]
snd.new_music(MUSIC_TITLE)
Here the song is named “title screen”. It uses 5 patterns number 56, 57, 58, 59 and 60.
play_pattern
function while the music is playing.If you have more than 16 patterns, a single hexadecimal digit is not enough. You can then use SEQ2 instead of SEQ where each pattern index is a 2 digits hex number :
SEQ2 000204...... 010304......
play_music(id, channel_mask)
: play a music. The channel_mask defines the channels to be used to play the music patterns. There must be enough channel to play all the simultaneous patterns in a sequence.For example with the previous song, which requires 3 channels, you can use the binary mask 111 = 7. This would result in the song using the channels 0,1,2.
TODO
key(key)
: return true if key is pressed.key_pressed(key)
: return true if key was pressed during last framekey_released(key)
: return true if key was released during last frameThe value for the key
scan codes are :
V.inp.KEY_0
..V.inp.KEY_9
: upper digitsV.inp.KEY_A
..V.inp.KEY_Z
: letters (this returns KEY_Q when you press A on an AZERTY keyboard)V.inp.KEY_F1
..V.inp.KEY_F10
: function keysArrow keys : (also triggered by numeric keypad if numlock is disabled)
V.inp.KEY_UP
V.inp.KEY_DOWN
V.inp.KEY_LEFT
V.inp.KEY_RIGHT
Special keys :
V.inp.KEY_TAB
V.inp.KEY_SPACE
V.inp.KEY_BACKSPACE
V.inp.KEY_ENTER
V.inp.KEY_ESCAPE
V.inp.KEY_PRINTSCREEN
V.inp.KEY_SCROLLLOCK
V.inp.KEY_PAUSE
V.inp.KEY_INSERT
V.inp.KEY_HOME
V.inp.KEY_DELETE
V.inp.KEY_END
V.inp.KEY_PAGEDOWN
V.inp.KEY_PAGEUP
V.inp.KEY_CTRL
V.inp.KEY_LSHIFT
V.inp.KEY_RALT
V.inp.KEY_RSHIFT
List of button values :
Functions :
mouse_button(num)
: return true if mouse button num is pressed.You can use any button number or the predefined constants :
V.inp.MOUSE_LEFT
V.inp.MOUSE_MIDDLE
V.inp.MOUSE_RIGHT
mouse_button(num)
: return true if mouse button num was pressed since the last game tickmouse_button_released(num)
: return true if mouse button num was released since the last game tickmouse_pos()
: return the mouse position in pixelsExample :
local mousex,mousey = V.inp.mouse_pos()
Note : you can show/hide the mouse cursor with the V.gfx API :
show_mouse_cursor(onoff)
Example :
V.gfx.show_mouse_cursor(false)
in beta
In the following functions, player_num
value is :
0
: the keyboard (arrows for directions and X,C,V,Z,Escape,Enter corresponding to A,X,B,Y,Select,Start on the controller)1
to 8
: up to 8 controllers supportThis makes it possible to use the same API whether the player is using the keyboard or the controller.
Functions :
pad_button(player_num, num)
: return true if button num for player player_num is pressedpad_button_pressed(player_num, num)
: return true if button num for player player_num was pressed since the last game tickYou can use these constants for the num value :
V.inp.XBOX360_A
V.inp.XBOX360_B
V.inp.XBOX360_X
V.inp.XBOX360_Y
V.inp.XBOX360_LB
V.inp.XBOX360_RB
V.inp.XBOX360_SELECT
V.inp.XBOX360_START
V.inp.XBOX360_LS
V.inp.XBOX360_RS
pad_ls(player_num)
: return the left analog stick axis values (between -1 and 1) for player player_numExample :
local x,y = V.inp.pad_ls(1)
set_ls_neutral_zone(value)
: sets the left analog stick neutral zone (between 0 and 1)pad_rs(player_num)
: return the right analog stick axis values (between -1 and 1) for player player_numset_rs_neutral_zone(value)
: sets the right analog stick neutral zone (between 0 and 1)pad_lt(player_num)
: return the left trigger value (between -1 and 1) for player player_numpad_rt(player_num)
: return the right trigger value (between -1 and 1) for player player_numIf you want to support both keyboard and controller at the same time in a single player game, you can use these generic functions instead :
V.inp.action1()
returns true if the controller A button or keyboard X key are pressedV.inp.action2()
returns true if the controller X button or keyboard C key are pressedV.inp.action3()
returns true if the controller B button or keyboard V key are pressedV.inp.action4()
returns true if the controller Y button or keyboard Z key are pressedThe same functions with the _pressed suffix exist to check if the button was pressed since the last game tick. They all return a boolean.
V.inp.action1_pressed()
V.inp.action2_pressed()
V.inp.action3_pressed()
V.inp.action4_pressed()
Those last function will check controller #1 and keyboard if the player is not defined, else only the controller #player (0=keyboard, 1-8=controller)
V.inp.up([player])
value between 0 and 1V.inp.down([player])
value between 0 and 1V.inp.left([player])
value between 0 and 1V.inp.right([player])
value between 0 and 1V.inp.up_pressed([player])
V.inp.down_pressed([player])
V.inp.left_pressed([player])
V.inp.right_pressed([player])
How can I generate 1D/2D/3D noise ?
See https://docs.godotengine.org/en/stable/classes/class_noise.html
Are there tweening utilities ?
You can use the Tween
class. Example :
var value = Tween.interpolate_value(start_value, delta_value, t, duration, Tween.TRANS_CUBIC, Tween.EASE_IN_OUT)
See https://docs.godotengine.org/en/stable/classes/class_tween.html
How can I save data locally ?
See https://docs.godotengine.org/en/stable/tutorials/io/saving_games.html