We hope everyone had a great end to their summer! Our free browser game went up at the end of July, with August being a month dedicated to going hard at prepping the rhythm game. Halfway into the month we did have an unfortunate surprise with the power-supply on Julian's PC failing.
Thankfully - we're getting things shipped to fix up his PC and get him back online soon. Rather than switching up dates on a test build release - we'll at least give an estimated window of any time in the next couple of months based on what we can get done and how soon we can get things up and running. In the future we'll try to be much less erratic with our scheduling. Despite the brief hiccup, we wanted to keep sure things were still moving ahead.
This month served as a perfect opportunity to tackle one of the biggest steps for the rhythm game - breaking everything apart for a proper internalized format.
One of the things we wanted to really ensure with this game was the openness of it, and while we were going to wait until after the first test build to do this, the delay allowed the time needed to really go through and optimize the structure of the game. While it felt daunting initially, it didn't end up being too much trouble to get everything functional.
We can tell development is going to be speeding up significantly after redoing the formatting for how visuals are handled in-game, and it also allows for preparing some screens ahead of time with placeholders as we finalize the artwork for use. Join us today on what may be the lengthiest Patreon post (as well as the dorkiest) that we've ever had.
While some work still needs to be done on a couple of additional formats for game elements (noteskins, lane lights, hitsparks) - we've managed to setup a basic core for how script files can be taken in to generate various effects, animations, or create functional menu screens. There are numerous actions that can be used for sprite manipulation, as well as the option for commands if you want to create animated visuals.
We'll be using this system for almost all of the menus within the game, as well as various screens such as title cards and cutscenes. AVI and MP4 support is present for video files (which a layer can be designated to run the video on), and audio files can be played/looped if they are either WAV, MP3, OGG, or AIFF files. Actions and commands have been setup to properly scale themselves around whatever resolution the game is running at, as well as interpolation being applied if the game's performance is set to run higher than the default framerate. There are still a few additional visual effects we're in the process of adding (snapshotting the screen for use in screen transitions, masking effects, etc) but all of the basics are ready to go.
Here's how information is handled and what sort of things can be utilized by our setup :
Scale can be used to scale a sprite overall. By default it's set to 1.0 which is size of the image.
ScaleX and ScaleY can both be used as well if they're needed to be utilized individually.
Angle is which way the sprite is rotated, the default being 0. Negative values loopback around.
Blend sets the blending mode for the sprite. By default the value None is used.
Color will tint the sprite a certain color which is a 6-digit hex value. Default is FFFFFF (white).
Mode sets different modes for to displaying the sprite differently. This is set to None by default.
All of this information is stored in an ini file that is read by the game to display visuals on-screen. Files are stored in the game's directory and can be called with actions such as loadlayer, loadoverlay. This is how you can hop from script file to script file!
Screens in-game can be displayed as Layers or Overlays, all visual data being flushed from memory and swapped when a file is loaded onto one. The action appendlayer and appendoverlay can be used if you want to replace any layer information with new data, or add new layers on if they're not already present for mixing and matching files together.
While default variables can be set for displaying a sprite, you set CommandStart to trigger a list of actions as soon as the file is loaded. Command allows you to store a list of actions that can be activated through actions like CommandRepeat or CallCommand.
Commands work by reading through a list of actions from left to right with semi-colons to divide them. Commas are used to separate arguments used by the action called, and pauses can be added between actions by using Wait. The game has some built-in variables related to gameplay and unlockables, but variables can also be defined for use (useful for modding purposes!)
Here's a list of all the actions currently available and what information is used by them :
wait,[time]; Waits a number of frames before resuming the rest of the command.
loadlayer,[filepath]; Loads an ini file to the Layer display.
loadoverlay,[filepath]; Loads an ini file to the Overlay display.
appendlayer,[filepath]; Merges current Layer display with an ini file.
appendoverlay,[filepath]; Merges current Overlay display with an ini file.
loadsprite,[filepath]; Loads a new sprite onto the layer.
loadanimsprite,[filepath,width,height,frames,rate]; Loads spritesheet animation.
clearsprites; Flushes all sprites from memory.
setfont,[fontName]; Sets the layer's font.
addfont,[filepath]; Adds a font into the game.
clearfonts; Flushes all fonts from memory.
pos,[x],[y]; Sets the X and Y position of the sprite. (Pixel coordinates)
posx,[x]; Sets the X position of the sprite. (Pixel coordinates)
posy,[y]; Sets the Y position of the sprite. (Pixel coordinates)
rot,[angle]; Sets the angle of the sprite. (0-360 degrees)
opacity,[value]; Changes the opacity of the sprite. Float value from 0 - 1.
color,[rgbhex]; Sets the tint of the sprite. (6-digit hex from 000000 to FFFFFF)
blend,[mode]; Changes the blending mode of the displayed sprite.
animspeed,[newSpeed]; Changes the speed of the sprite's animation that is playing.
animframe,[newFrame]; Changes the frame of the sprite's animation that is playing.
setmessage,[newMessage]; Sets the text that will appear on the current layer.
tween,[time],[newX],[newY]; Makes a sprite tween to a new position within a time limit.
easein,[time],[newX],[newY]; Makes a sprite ease into a new position within a time limit.
easeout,[time],[newX],[newY]; Makes a sprite ease out to a position within a time limit.
ease,[time],[newX],[newY]; Makes a sprite ease from its previous position in a time limit.
xtween,[time],[newX]; Tweens X position within a time limit.
xeasein,[time],[newX]; Eases into X position within a time limit.
xeaseout,[time],[newX]; Eases out to an X position within a time limit.
xease,[time],[newX]; Eases to a new X position within a time limit.
ytween,[time],[newY]; Tweens Y position within a time limit.
yeasein,[time],[newY]; Eases into Y position within a time limit.
yeaseout,[time],[newY]; Eases out to an Y position within a time limit.
yease,[time],[newY]; Eases to a new Y position within a time limit.
rottween,[time],[newAngle]; Tweens an angle rotation within a time limit.
roteasein,[time],[newAngle]; Ease into an angle rotation within a time limit.
roteaseout,[time],[newAngle]; Eases out of an angle rotation within a time limit.
rotease,[time],[newAngle]; Eases an angle rotation within a time limit.
scaletween,[time],[newScale]; Scales the sprite in a linear manner on a timer.
scaleeasein,[time],[newScale]; Sprite eases into a new scale on a timer.
scaleeaseout,[time],[newScale]; Sprite eases out of a scale on a timer.
scaleease,[time],[newScale]; Eases the scale of a sprite on a timer.
xscaletween,[time],[newXScale]; The sprite's X scale is tweened on a timer.
xscaleeasein,[time],[newXScale]; Sprite eases into a new X scale on a timer.
xscaleeaseout,[time],[newXScale]; Sprite eases out of a X scale on a timer.
xscaleease,[time],[newXScale]; Eases the X scale of a sprite on a timer.
yscaletween,[time],[newYScale]; The sprite's Y scale is tweened on a timer.
yscaleeasein,[time],[newYScale]; Sprite eases into a new Y scale on a timer.
yscaleeaseout,[time],[newYScale]; Sprite eases out of a Y scale on a timer.
yscaleease,[time],[newYScale]; Eases the Y scale of a sprite on a timer.
colortween,[time],[newColor]; The sprite's color tweens on a timer.
coloreasein,[time],[newColor]; Ease into a new color on a timer.
coloreaseout,[time],[newColor]; Ease out to a new color on a timer.
colorease,[time],[newColor]; Eases to a color on a timer.
opacitytween,[time],[newOpacity]; Tweens the opacity on a timer.
opacityeasein,[time],[newOpacity]; Eases into an opacity on a timer.
opacityeaseout,[time],[newOpacity]; Eases out of an opacity on a timer.
opacityease,[time],[newOpacity]; Eases opacity on a timer.
sound,[filepath],[volume],[channel]; Plays a sound file on a specific audio channel.
loopsound,[filepath],[volume],[channel]; Loops a sound file on an audio channel.
pausesound,[channel]; Pauses sound file on a channel.
resumesound,[channel]; Resumes the sound file on a channel.
stopsound,[channel]; Stops the sound file on a channel.
pauseallsounds; Pauses every sound that was playing.
resumeallsounds; Resumes every sound that was playing.
stopallsounds; Stops every sound from playing.
video,[filepath]; Loads a video file into the game. (Only one can be used at a time)
videoplay; Plays whatever video file was loaded.
videoloop; Plays and loops the loaded video file.
videopause; Pauses the loaded video file.
videoresume; Unpauses the loaded video file.
videotrack,[offset]; Tracks the video to a specific time. (Millisecond format)
videoclose; Stops and removes the video file from memory.
setvar,[variableName],[value]; Sets the value of a user created variable.
addvar,[variableName],[value]; Adds to the value of a user created variable.
subvar,[variableName],[value]; Subtracts from the value of a user created variable.
multivar,[variableName],[value]; Multiplies the value of a user created variable.
removevar,[variableName]; Deletes a specific user created variable.
clearvars,[variableName]; Flushes all user created variables.
All actions can be applied directly to a layer by putting overlay_ or layer_ before the action. Actions perform the same but the first value taken is the layer to apply the action to.
Example : overlay_opacity,[4],[0.5]; Changes Overlay layer 4's opacity to 0.5.
Tweens/easing effects can be stacked up on a sprite so multiple animations can function at once.
Be sure to flush art out of memory if it's going unused, although the game will also flush assets attached to Layers or Overlays if the loadlayer or loadoverlay actions are used.
While the game can display image files on screen as a sprite, you can also load a spritesheet into memory to use as an animation. Spritesheets can also be utilized for creating bitmap fonts for use in-game whenever text is being drawn to the screen. Animated sprites are treated the same as regular sprites, just with access to a few more actions to let you control what frame is being displayed or to change the speed the animation runs at. Fonts can have custom spacing between characters with the option to have characters be evenly spaced from each other or not
Using a spritesheet is takes a little bit of additional setup compared to regular sprites. In the next section we'll be using a guinea pig, or rather, a chicken. Our test subject will be showing you the process of being converted from a spritesheet to an animation for use in-game.
After converting our test subject into a 3x3 sheet - it's now time to import them into the game. By defining the FrameWidth and FrameHeight of the sprite, the image is cut into pieces based on that information. FrameCount allows the game to know just how many frames are in the animation so it can omit anything unneeded.
( Here is our test subject after being broken up into a sheet. The final result is drawn on Layer 0. )
While we prepare our test chicken for use in the game, maybe we should try creating a font to go alongside him. Fonts can be loaded from ini files containing their information, or can also be added into the game's memory through actions.
Whatever the layer's Message is set to will be displayed to this font by setting the font to Test_Font. Variables can be referred to in messages by typing «VariableName» in the message.
( This is what is contained in Test_Font.ini. addfont,Test_Font.ini will load it into memory. )
Now that we have our animated sprite and font loaded into the game - let's trying adding a little bit of everything on top of that. Scrolling layers tiled layers, tweens, blend modes, rotations, etc. It can all be brought to life through the use of commands.
( Here's various effects being utilized together in harmony. Our little chicken has come so far... )
We're hoping this system will be easy and accessible for anyone who wants to modify their game to create custom themes/menus/interfaces but it also allows us to work much quicker!
Below are a few examples of screens made with the new system we have setup for visuals :
( This example screen utilizes a video file as a background, as well as custom fonts being used! )
( With this example screen we can see an effect can be created by utilizing the Tile mode! )
Despite the light hiccup - we actually were able to make some major progress in the past month by getting this system going. Work is currently going into adding a few more actions for the game to utilize alongside breaking up the gameplay area into this system. We want to offer players a lot of customization and control over how things function in-game, so some systems are being reworked for more dynamic displays that can be adjusted to a player's specific tastes.
Despite the issues with Julian's PC, work at least was started towards designing a results screen for the game. This would be displayed after a song is finished and will have stats displayed on top. The screen is designed to accommodate one to two players with its layout.
We've been fleshing out designs for what the final note designs will look like (every artist on-board throwing ideas around between each other) and we've been feeling this one out as the default look. The 4th button in-game is going to be changed to orange so we'll be adding a third note design representing the center button.
It'll still be a bit before Julian's PC is up and running, but we've at least been making progress towards the visual side of things even if we hit a snag for a bit. With how much we were able to get done during August we want to keep up that momentum.
Thank you again to everyone who has been supporting us, even with ups and downs and all arounds - we're hoping to really keep things moving ahead and get you guys something fun to play (and potentially fun to tinker around with).
We hope the free game was able to provide a bit of summertime fun while we get things setup. The delays made us change our approach on this first test build where we can at least get most core systems functional. The feedback we receive can be much more applicable to where the final result will end up. Our intentions were for the first test to be a very barebones demo, but having something more polished up isn't necessarily a bad thing.
Currently I've been in the process of finishing some last touches with the actions available for use. The second week of this month will be going towards the noteskin formatting for the game, which will allow for much more customizable note designs with the option for animations and effects to be applied (similar to what we showed prior). The goal by the end of the month is to have every element of the game broken apart and completely functional in our new system.
We'll hopefully have some more lengthy posts like this in the future since things have been really hitting a good pace, and hopefully it was of (at least some) interest getting to see how this new system works.
Stay tuned for more updates in the future and we hope you guys have a great September!
~ DD