0.0.2
PIURED is a Pump It Up stage simulator that works directly in your browser. There are already a number of dance simulators for Windows and Linux, most of them being StepMania-based. Stepmania is a great choice for DDR-style rhythm games, however it lacks to capture the behaviour as well as the feel & look of a Pump It Up arcade.
In this sense, PIURED's goal is to recreate as accurately as possible the Pump It Up-style experience whilst keeping the engine cross-platform (web-based), so it can be enjoyed anywhere and anytime.
PIURED is written in its whole in Javascript using ThreeJS. The code is organized
trying to mimick the structure of any game engine. The source code can be found in this repo under the folder js
.
This engine features:
There are, however, some features available in Stepmania that PIURED does not support:
The Engine class is the main abstraction for creating a pump it up stage and playing a chart. It contains all methods necessary to create a new stage, add an indefinite number of local and remote players, load Stepmania SSC files, and report players' performance.
This class is intended to be used only as javascript code on the client-side, as it will attempt to draw stuff on the browser.
Importing the engine via ES6 modules
import {PiuredEngine, StageConfig, PlayerConfig, KeyInputConfig} from '@piured/engine'
Full example to configure a working engine.
import {PiuredEngine, StageConfig, PlayerConfig, KeyInputConfig} from '@piured/engine'
async function setUpEngine (dom) {
let engine = new Engine()
function stageCleared(performance) {
console.log(performance);
engine = null;
}
function onKeyDown(event) {
engine.keyDown(event);
}
function onKeyUp(event) {
engine.keyUp(event);
}
let speed = 4.0;
let playback = 1.0;
let offset = 0.0;
let noteskin = 'NX';
let touchpadSize = 1.0;
let leftKeyMap = {
dl: 'Z',
ul: 'Q',
c: 'S',
ur: 'E',
dr: 'C'
}
let rightKeyMap = {
dl: 'V',
ul: 'R',
c: 'G',
ur: 'Y',
dr: 'N'
}
let chartLevel = 0;
let innerWidth = 800
let innerHeight = 800
let pixelRatio = window.devicePixelRatio
engine.init(innerWidth, innerHeight, pixelRatio, window)
let stageConfig = new StageConfig('<mp3-url>',
'<ssc-url>',
playback,
offset,
[noteskin],
() => {
let dateToStart = new Date();
// delay of 2 secs
dateToStart.setMilliseconds(dateToStart.getMilliseconds() + 2000.0);
engine.startPlayBack(dateToStart, () => {
return new Date();
});
}
);
await engine.configureStage(stageConfig);
let p1InputConfig;
let accuracyMargin = 0.15;
accuracyMargin = 0.25;
window.onkeydown = onKeyDown;
window.onkeyup = onKeyUp;
p1InputConfig = new KeyInputConfig(leftKeyMap, rightKeyMap);
let p1Config = new PlayerConfig(p1InputConfig,
noteskin,
chartLevel,
speed,
accuracyMargin);
engine.addPlayer(p1Config);
engine.addToDOM(dom);
window.addEventListener( 'resize', engine.onWindowResize.bind(engine), false );
engine.onStageCleared = stageCleared;
engine.start();
}
await setUpEngine('<container>')
Configures the renderer and sets the camera into position. Call this method before setting up the stage through Engine#configureStage.
(any)
width of canvas
(any)
height of canvas
(any)
pixel ratio of screen
(any)
window object from browser, to respond to frames requests
Initializing a new engine.
engine.init( 1270, 768, window.devicePixelRatio, window )
Constructs the stage where one or more players will dance. In a nutshell, the stage sets up the environment needed to play a specific tune associated with its Stepmania step definition file (i.e., mp3+SSC). This method must be called before adding new players to the stage through Engine#addPlayer.
(StageConfig)
stage configuration
undefined
:
Configuring a new stage. Details of the StageConfig object are omitted.
let stageConfig = new StageConfig( ... ) ;
engine.configureStage(stageConfig) ;
Adds a new player to the dance stage. This method must be called after configuring the stage through Engine#configureStage. There is no upper limit for the number of players that can join, but for some number the camera position must be updated to show the whole stage. Players could play locally by using traditional input methods (e.g., Keyboard, Touch) or remotely (via logging FrameLogs).
(PlayerConfig)
player configuration
number
:
player identifier
Adding a new player to the stage. Details of the PlayerConfig object are omitted.
let p1Config = new PlayerConfig( ... ) ;
let p1Id = engine.addPlayer(p1Config) ;
Appends the renderer's DOM element to a container with id containerId
present in your HTML document.
You need to call this function so that the engine has a canvas to draw on.
(String)
container id in the HTML document
undefined
:
Granted we have defined in a HTML document the following container <div id="container"></div>
, we add the engine to the DOM
engine.addToDOM('container') ;
Updates the player's stage playerId
offset. This function can be used to sync off-beat steps on-the-fly when the
engine is running.
(number)
player identifier
(number)
new offset to be applied in seconds.
newOffsetOffset
must be a floating point number
undefined
:
Updating the offset by 0.01 seconds for player with id p1Id := 0
.
engine.updateOffset(p1Id, 0.01) ;
Updates the stage's audio playback rate (i.e., increases or decreases the audio & step speed). This function might be called while the engine is running. This function won't have any effect if there are remote players logged in the engine.
(number)
new playback speed to be applied in percentage.
playBackSpeed
must be a floating point
undefined
:
Speeding up the playback rate to 110% (1.1x)
// changes the playback speed to 110%
engine.tunePlayBackSpeed(1.1) ;
// Essentially stops the playback
engine.tunePlayBackSpeed(0.0) ;
Logs a key down event from the browser into the engine. Keyboard events must be logged if any player is using KeyInputConfig (i.e. keyboard) as input method.
(KeyboardEvent)
keyboard event
undefined
:
Configuring the browser to log the key strokes into the engine
window.onkeydown = engine.keyDown ;
Logs a key up event from the browser into the engine. Keyboard events must be logged if any player is using KeyInputConfig (i.e. keyboard) as input method.
(KeyboardEvent)
keyboard event
undefined
:
Configuring the browser to log the key strokes into the engine
window.onkeyup = engine.keyUp ;
Logs a touch down event from the browser into the engine. Touch events must be logged if any player is using TouchInputConfig (i.e. Touch capable device) as input method.
(TouchEvent)
touch event
undefined
:
Configuring the browser to log touch down events into the engine
document.addEventListener( 'touchstart', (event) => {
// disable default actions
event.preventDefault();
event.stopPropagation();
engine.touchDown(event) ;
}, false );
Logs a touch up event from the browser into the engine. Touch events must be logged if any player is using TouchInputConfig (i.e. Touch capable device) as input method.
(TouchEvent)
touch event
undefined
:
Configuring the browser to log touch down events into the engine
document.addEventListener( 'touchend', (event) => {
// disable default actions
event.preventDefault();
event.stopPropagation();
engine.touchUp(event) ;
}, false );
Repositions the camera. Use this method to configure how the stage is displayed.
(number)
x position in the euclidean space
(number)
y position in the euclidean space
(number)
z position in the euclidean space
undefined
:
Moving the camera backwards to fully show players' stages when both are playing pump-double
styles
engine.setCameraPosition(0,-3.4,12) ;
Query the style of a specific level from the configured stage.
(number)
level identifier in the range [0-<no_levels-1>]
String
:
level style defined in the SSC file. Common values are
pump-single
,
pump-double
, and
pump-halfdobule
Query if one player is playing pump-double
to reposition the camera
let p1StageType = engine.queryStageType(P1chartLevel) ;
if (p1StageType === 'pump-double') {
engine.setCameraPosition(0,-3.4,12) ;
}
Sets the engine into a valid state and prepares it to start the song playback. Call this function once the stage and all players have been configured. This method will trigger the function StageConfig#onReadyToStart once the initialization is completed.
undefined
:
Starting the engine
engine.start() ;
Schedules when the engine should start playing the song and starts the rendering main loop. You may only call this function once StageConfig#onReadyToStart callback is called.
(Date)
date to start playing
(Function?
= ()=>{return new Date();}
)
function getting the current date
undefined
:
We let the engine start playing back after 2 seconds once the engine has loaded up
let onReadyToStart = () => {
let dateToStart = new Date() ;
// delay of 2 secs
dateToStart.setMilliseconds(dateToStart.getMilliseconds() + 2000.0) ;
engine.startPlayBack(dateToStart, () => { return new Date() ; }
}
Update size of drawable canvas. You might call this function when the engine is running.
(any)
new width of canvas
(any)
new height of canvas
undefined
:
Resize drawable canvas to 500x500 px
engine.resize(500, 500)
It logs frameLogs into the engine. FrameLogs are JSON messages that are passed between engines when remote players are configured. They enable the engine to know what is the current status of a remote player.
(JSON)
frame to be logged
undefined
:
To learn more about how to use frame logs for communicating a pair of engines, have a look at the repo at https://github.com/piulin/piured
engine.logFrame(JSON) ;
Sets the callback function onFrameLog
. This function is called once the engine has a frame to be logged from any
local player. Ideally, the content of the JSON is sent through the network somehow and logged into a target engine.
(Function)
undefined
:
To learn more about how to use frame logs for communicating a pair of engines, have a look at the repo at https://github.com/piulin/piured
engine.onFrameLog = (frameLog) {
//send it to the remote engine somehow
mm.sendFrameLog(frameLog) ;
}
Sets the callback function onStageCleared
. This function is called once the engine is stopped (either by calling Engine#stop or
by reaching the end of the song). It can be used to report the player's performance.
(Function)
We report the player's performance when the stage is cleared
engine.onStageCleared = (performance) => {
console.log(performance) ;
window.close() ;
}
Here you can find the configuration helper classes to configure the engine.
This class holds the configuration of a stage.
(string)
path to the Stepmania SSC file describing the levels and steps available. This parameter can be
undefined
if parsedSSC is provided.
(string)
parsed SSC file in JSON format (output of ssc-parser). If this parameter is
undefined
then, parameter
SSCFile
must be provided.
(string)
path to the audio file in mp3 or ogg format associated with the SSC file
(number)
song playback rate. A
playBackSpeed
equal to 1.0 configure the engine to play the song at the normal speed
(number)
synchronization offset. Use it to synchronize off-the-beat charts with the audio
(Array)
list of noteskins available to use for playerStages. Include those only used in them.
(Function
= ()=>{}
)
callback function. This function will be called once the engine has loaded up completely the stage
and it's ready to begin the playback
let stageConfig = new StageConfig('song.ssc',
undefined,
'song.mp3',
1.0,
0.0,
'piured-engine,
['NXA'],
() => {
let dateToStart = new Date() ;
// delay of 2 secs
dateToStart.setMilliseconds(dateToStart.getMilliseconds() + 2000.0) ;
engine.startPlayBack(dateToStart, () => {return new Date() ;}) ;
}
) ;
This class holds the configuration for a player.
((KeyInputConfig | TouchInputConfig | RemoteInput))
input configuration
(string)
player's noteskin. Note that
noteskin
needs to be previously passed in the constructor of
StageConfig
.
(number)
levelId to be played by the player
(number
= 1.0
)
rate in which the steps traverse the screen from the bottom to the receptor
(number
= 0.15
)
span of time (in seconds) in which a step is considered to be pressed
(number
= 0
)
X position of player stage with respect to the stage
(number
= 0
)
Y position of player stage with respect to the stage
(number
= 1.0
)
scale applied to the player stage
let p1InputConfig = RemoteInput() ;
let p1Config = new PlayerConfig(p1InputConfig,
'NXA',
0,
3.0,
0.15) ;
Class for configuring the keyboard as input method. For registering key strokes, it is necessary to pass the key events into the engine through methods Engine#keyDown and Engine#keyUp.
let p1InputConfig = new KeyInputConfig({
dl: 'Z',
ul : 'Q',
c : 'S',
ur : 'E',
dr: 'C'
},
{
dl: 'V',
ul : 'R',
c : 'G',
ur : 'Y',
dr: 'N'
}) ;
Class for configuring the input for a touch-capable device. The input pad will be drawn on the screen. For registering the touch input, it is necessary to pass the touch events into the engine through methods Engine#touchDown and Engine#touchUp.
(number
= 1.0
)
scaling factor
(number
= 0
)
X position of the pad with respect to the player's stage
(number
= 0
)
Y position of the pad with respect to the player's stage
let p1InputConfig = new TouchInputConfig() ;
This class configures a remote input for a remote player. Make sure you frame the logs corresponding to players using remote input through Engine#logFrame
let remoteInputConfig = new remoteInput() ;