______ __
__ /\\\\\\\\_ /\\\
/\\\ /\\\//////\\\_ \/\\\
/\\\// \/// \//\\\ ________ ___\/\\\ _______
/\\\// /\\\ /\\\\\\\\\_ /\\\\\\\\\ /\\\\\\\\_
/\\\//_ /\\\\/ /\\\/////\\\ /\\\////\\\ /\\\/////\\\
\////\\\ __ /\\\/ \/\\\ \/\\\ \/\\\ \/\\\ /\\\\\\\\\\\
\////\\\ __ \///_ \/\\\___\/\\\ \/\\\__\/\\\ \//\\\//////_
\////\\\ /\\\ \/\\\\\\\\\\ \//\\\\\\\\\ \//\\\\\\\\\
\/// \/// \/\\\////// \///////// \/////////
\/\\\
\///
/P(?:ointless|ortable|HP) Demo Engine/
A bit of fun. An ASCII/ANSI terminal display with stackable routines, sequenced and controlled from a simple text file.
Execute ./display <path to json file>
$ docker build -t php-demo-engine .
$ docker run php-demo-engine php display
Displays provide the render target. For now this is limited to basic ASCII output.
Routines provide the effects. Routines are classes that implement the IRoutine interface which mandates how they are created, rendered and parameterised. Routines can be stacked, meaning more than one routine is rendered per frame, in a given priority order.
Pretty simples. Implement the IRoutine
interface directly or extend the Routine\Base
class which handles a lot of the lower level drudgery already:
namespace ABadCafe\PDE\Routine;
use ABadCafe\PDE;
/**
* MyRoutine. Does something cool. Probably.
*/
class MyRoutine extends Base {
const DEFAULT_PARAMETERS = [
// These are the parameter names that can be set from the demo file and their initial value/types.
// Define these as you need them. They will populate a member oParameters tuple at runtime.
'iMyIntParameter' => 0,
'fMyFloatParamter' => 1.5,
'sMyStringParameter' => 'pde',
'aMyArrayParameter' => []
];
/**
* @inheritDoc
*
* Whenever the display changes, this is invoked. It is always called before render() in any given frame.
*/
public function setDisplay(PDE\IDisplay $oDisplay) : self {
// Be prepared here to check if this display is suitable for your routine.
$this->oDisplay = $oDisplay;
return $this;
}
/**
* @inheritDoc
*
* Do your thing. It is expected that your routine will render a single frame. The parameters provide the
* current frame number and the current time in seconds since the demo began execution.
*/
public function render(int $iFrameNumber, float $fTimeIndex) : self {
// Your magic here...
// You have access to:
// $this->oParameters for the current parameter values
// $this->oDisplay for the current render target
return $this;
}
/**
* @inheritDoc
*/
protected function parameterChange() {
// This is called after the an update event in the demo file if any of our parameters change.
}
}
Once your routine is implemented, it must be added to the Routine\Factory
types array so that it can be found and instantiated by the loader:
namespace ABadCafe\PDE\Routine;
class Factory {
const TYPES = [
'MyRoutine' => MyRoutine::class,
];
// ... snip
}
Any time you add new code, you should run the provided createclassmap
script. This isn't PSR autoloading.
Loaders import definition files which describe the components and timeline of a demo. Loaders are classes that implement the ILoader interface. A JSON model is provided by default, but adding other formats should be trivial.