clean up docs

This commit is contained in:
John Alanbrook 2024-02-20 02:31:26 +00:00
parent e5d67431b6
commit 5f33ac53b7
27 changed files with 282 additions and 452 deletions

21
LICENSE Normal file
View file

@ -0,0 +1,21 @@
Prosperon Game Engine
Copyright (c) 2019-2024 John Alanbrook
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View file

@ -324,9 +324,12 @@ crossmac:
clean: clean:
@echo Cleaning project @echo Cleaning project
@rm -rf bin dist @rm -rf bin dist
@rm -f shaders/*.sglsl.h shaders/*.metal core.cdb jso cdb packer scripts/*.jso @rm -f shaders/*.sglsl.h shaders/*.metal core.cdb jso cdb packer scripts/*.jso TAGS
@make -C quickjs clean @make -C quickjs clean
docs:
mkdocs build
TAGINC != find . -name "*.[chj]" TAGINC != find . -name "*.[chj]"
tags: $(TAGINC) tags: $(TAGINC)
@echo Making tags. @echo Making tags.

BIN
doc/dos.ttf Normal file

Binary file not shown.

BIN
doc/orb.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View file

@ -1,12 +1,43 @@
# Primum #+title: Prosperon Documentation
#+DESCRIPTION: Prosperon documentation
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="style.css" />
#+HTML_HEAD: <script defer data-domain="prosperon.dev" data-api="https://net.pockle.world/net/event" src="https://net.pockle.world/bat/script.js"></script>
@@html:
<script src="https://kit.fontawesome.com/a87f68ad0a.js" crossorigin="anonymous"></script>
<div class="floathead">
<a href="https://prosperon.dev">
<img height=50px src="prosperon_orb_horizontal.gif">
</a>
<a href="#top"><i class="fa-solid fa-table-list"></i></a>
<a href="https://github.com/johnalanbrook/prosperon"><i class="fa-brands fa-github"></i></a>
</div>
@@
* Getting Started
** Installation
#+begin_src
Window.name = "Prosperon (V0.1)";
Window.width = 1280;
Window.height = 720;
var Asset = {};
Asset.doc = {
doc: "Functions to manage the loading and unloading of assets, like sounds and images."
};
#+end_src
* Engine Tour
** Entities
Games are made of entities. Entities are made of components. Components can be thought of as properties that entities poses; entities are a collection of components. Components include things like drawables (textures, sprites), physical colliders, and more. Games are made of entities. Entities are made of components. Components can be thought of as properties that entities poses; entities are a collection of components. Components include things like drawables (textures, sprites), physical colliders, and more.
Entities can have control of other entities, in which case the one in control is the 'master' and the controlee the 'padawan'. When a master moves or rotates, all padawans move and rotate with it. Entities can have control of other entities, in which case the one in control is the 'master' and the controlee the 'padawan'. When a master moves or rotates, all padawans move and rotate with it.
The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game. The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game.
## Scripting *** Scripting
There are a number of script hooks which are ran at particular times of engine loading. When a game starts ... There are a number of script hooks which are ran at particular times of engine loading. When a game starts ...
- config.js - config.js
@ -22,17 +53,17 @@ F5 can be pressed in the editor to test the game. In that case ...
And when play mode is left ... And when play mode is left ...
- dbgret.js - dbgret.js
## Ur-types *** Ur-types
Ur-types are what are loaded into the game world. They are templates for creating entities. Ur-types are defined by providing the engine with .jso files. Ur-types are what are loaded into the game world. They are templates for creating entities. Ur-types are defined by providing the engine with .jso files.
If you have a 'enemy.jso' file, then on game start you can spawn an enemy via 'Primum.spawn(ur.enemy)'. The 'ur' object holds all ur-types the game knows about. If you have a 'enemy.jso' file, then on game start you can spawn an enemy via 'Primum.spawn(ur.enemy)'. The 'ur' object holds all ur-types the game knows about.
Ur-types are loaded on demand, or can be preloaded with 'prototypes.generate_ur()'. Ur-types are loaded on demand, or can be preloaded with 'prototypes.generate_ur()'.
## The ECS system, revisited *** The ECS system, revisited
There are two distinct items in the Primum: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world. There are two distinct items in the Primum: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world.
### Components *** Components
The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. Javascript does the accounting to make or destroy the sprite as needed - but besides that initial startup, no scripting is done. The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. Javascript does the accounting to make or destroy the sprite as needed - but besides that initial startup, no scripting is done.
Components are rendered in an "ECS" style. To work, components must be installed on an entity. They have no meaning outside of a physical object in the world. Components are rendered in an "ECS" style. To work, components must be installed on an entity. They have no meaning outside of a physical object in the world.
@ -41,14 +72,7 @@ AI would be components. You could have a "sensor" AI component that detects the
Components cannot be scripted; they are essentially a hardwired thing that you set different flags and values on, and then can query it for information. Components cannot be scripted; they are essentially a hardwired thing that you set different flags and values on, and then can query it for information.
### Entity *** Prototyping model
Entities are holders of components. Anything that needs a component will be an entity. Components rely on entites to render correctly. For example, the engine knows where to draw a sprite wherever its associated entity is.
Entities can be composed of other entities. When that is the case, an entity "under" a different entity will move when the above entity moves, as if it were attached.
The outermost entity that all other entities must exist in is the Primum. It always exists and cannot be removed.
## Prototyping model
All objects follow the prototyping model of inheritence. This makes it trivial to change huge swathes of the game, or make tiny adjustments to single objects, in a natural and intuitive way. All objects follow the prototyping model of inheritence. This makes it trivial to change huge swathes of the game, or make tiny adjustments to single objects, in a natural and intuitive way.
Components cannot be prototyped. They are fundamentally tied to the entity they are bound to. Components cannot be prototyped. They are fundamentally tied to the entity they are bound to.
@ -61,7 +85,7 @@ entity.promote() -> promote the entity to a new Ur-type, as it currently exists.
entity.revert() -> remove all changes of this entity so it again matches its Ur-type. entity.revert() -> remove all changes of this entity so it again matches its Ur-type.
entity.push() -> push changes to this entity to its Ur-type to it matches. entity.push() -> push changes to this entity to its Ur-type to it matches.
### Ur-types *** Ur-types
An Ur-type is a thing which cannot be seen but which can stamp out copies of itself. Objects can be promoted to an ur-type, so if it is deleted, another one can later be made. An Ur-type is a thing which cannot be seen but which can stamp out copies of itself. Objects can be promoted to an ur-type, so if it is deleted, another one can later be made.
Ur-types have a lineage going back to the original gameobject. The ur-type lineage can be as deep as you want it to be; but it should probably be shallow. Ur-types have a lineage going back to the original gameobject. The ur-type lineage can be as deep as you want it to be; but it should probably be shallow.
@ -90,14 +114,12 @@ ur.type : the actual object
ur.instances : instances of it ur.instances : instances of it
ur.tag : the full name of it ur.tag : the full name of it
### Diverting entities *** Resources
An entity can diverge from its ur-type. When this happens, you can either revert the entity, copy how it's changed to its ur-type, or promote it to its own ur-type.
## Resources
Assets can generally be used just with their filename. It will be loaded with default values. However, how the engine interprets it can be altered with a sidecar file, named "filename.asset", so "ball.png" will be modified via "ball.png.asset". These are typical JSON files. For images, specify gamma, if it's a sprite or texture, etc, for sound, specify its gain, etc. Assets can generally be used just with their filename. It will be loaded with default values. However, how the engine interprets it can be altered with a sidecar file, named "filename.asset", so "ball.png" will be modified via "ball.png.asset". These are typical JSON files. For images, specify gamma, if it's a sprite or texture, etc, for sound, specify its gain, etc.
Ur-types are directly related to your file directory hierarchy. In a pinball game where you have a flipper, and then a flipper that is left ... Ur-types are directly related to your file directory hierarchy. In a pinball game where you have a flipper, and then a flipper that is left ...
#+begin_example
@/ @/
/bumper /bumper
hit.wav hit.wav
@ -114,6 +136,7 @@ Ur-types are directly related to your file directory hierarchy. In a pinball gam
left/ left/
flip.wav flip.wav
left.js <-- This will load as an extension to flipper.js left.js <-- This will load as an extension to flipper.js
#+end_example
This is how resources are loaded in any given ur-type. Relative file paths work. So, in 'ball.js', it can reference 'hit.wav', and will play that file when it does; when bumper.js loads 'hit.wav', it will load the one located in its folder. This is how resources are loaded in any given ur-type. Relative file paths work. So, in 'ball.js', it can reference 'hit.wav', and will play that file when it does; when bumper.js loads 'hit.wav', it will load the one located in its folder.
@ -155,7 +178,7 @@ Asset links always follow the directory hierarchy, however, so if you want to re
prototypes.generate_ur(path) will generate all ur-types for a given path. You can preload specific levels this way, or the entire game if it is small enough. prototypes.generate_ur(path) will generate all ur-types for a given path. You can preload specific levels this way, or the entire game if it is small enough.
### Spawning *** Spawning
The outmost sphere of the game is the Primum, the first entity. Your first entity must be spawned in the Primum. Subsequent entities can be spawned in any entity in the game. The outmost sphere of the game is the Primum, the first entity. Your first entity must be spawned in the Primum. Subsequent entities can be spawned in any entity in the game.
Ur-types can remember configurations of entities spawned inside of them. Ur-types can remember configurations of entities spawned inside of them.
@ -176,91 +199,73 @@ The "$" is populated with an object's children. $.sword.damage will properly get
To access the entity's owner, it is through _. For example, the human can access the orc via _.Orc. To access the entity's owner, it is through _. For example, the human can access the orc via _.Orc.
## The REPL ** The REPL
The REPL lets you poke around in the game. The first accessible item is the Primum. Everything else must be child to it. When an object is selected, its children are accessible in a more friendly way. You can do commands as if you "are" that object. The REPL lets you poke around in the game. The first accessible item is the Primum. Everything else must be child to it. When an object is selected, its children are accessible in a more friendly way. You can do commands as if you "are" that object.
The ur-type of the object is always shown in purple. If it has no type, there is nothing shown. The ur-type of the object is always shown in purple. If it has no type, there is nothing shown.
## Entities ** Textures & images
Entities are things that exist in the game world.
|name| description|
|---|---|
|level| the level this object belongs to|
|pos| the global position|
|relpos| the position relative to its level|
angle| the global angle|
|relangle| angle relative to its level|
|velocity| velocity of the object|
|angularvelocity| angular velocity of the object|
|alive| true if the object is valid|
|varname| the variable name of the object (used for friendly naming)|
|friction| physics attribnute|
|elasticity| physics attribute|
|flipx| true if the object is flipped on its x axis|
|flipy| true if the object is mirrored on its y axis|
|body| the internal gameobject id of the object|
|controlled| true if the object is controlled by something|
|phys| set to dynamic; kinematic; or static; explained below|
|moi| the moment of inertia of the object|
|mass| mass of the object|
|visible| true if the object is visible. Set to false to disable all visible features belonging to it|
|in_air()| true if the object is not on the ground|
|on_ground()| !in_air()|
|layer| collision layer for the physics engine|
|draw_layer| draw order. higher numbers draw on top of lower ones|
|scale| change to make the object larger or smaller|
|from| the object this object was created from|
|boundingbox| the boundingbox of this object in world dimensions|
|push(vec)| push this object each frame with vec velocity|
|width| the boundingbox defined width|
|height| the boundingbox defined height|
|kill| destroy the object|
|stop| ???|
|world2this(pos)| return the pos in world coordinates to relative this object|
|this2world(pos)| return the pos in this coordinates relative to the world|
|make(props, level)| instantiate an object based on this, with additional props, in level|
## Editor related object features
|gizmo| path to an image to draw in editor mode|
## Functions for object control
|clone(name; ext)| create a copy of this object and extend it with ext; does not spawn|
|instadup()| create an exact duplicate of this object in the World|
|revert()| remove everything that makes the object unique; make it exactly like what it was spawned from|
## Physics
All objects belong to the physics engine, but may be totally ignored by it.
|static| does not and will not move|
|dynamic| moves under the auspices of the physics engine|
|kinematic| moves under the auspices of the player or other control mechanism|
Physics properties work as such
|mass| affects how much a given force will move an object|
|elasticity| affects momentum loss on collisions; multiplicative between two objects for each collision; 1 for no loss; 0 for total stoppage; >1 for a chaotic increasing entropy simulation|
|friction| affects momentum loss when rubbing against another surface; multiplicative between the two objects|
## Textures & images
A sprite is a display of a specific texture in the game world. The A sprite is a display of a specific texture in the game world. The
underlying texture has values associated with it, like how it should underlying texture has values associated with it, like how it should
be rendered: is it a sprite, is it a texture, does it have mipmaps, be rendered: is it a sprite, is it a texture, does it have mipmaps,
etc. Textures are all file based, and are only accessed through the etc. Textures are all file based, and are only accessed through the
explicit path to their associated image file. explicit path to their associated image file.
## Finding & Addressing Objects ** Finding & Addressing Objects
** Debugging
## Editor & Debugging
Although intertwined, debugging functions and the editor are separate entities. Although intertwined, debugging functions and the editor are separate entities.
### Debugging
Debugging functions are mapped to the F buttons, and are always available during gameplay in a debug build. Pressing the F button toggles the feature; pressing it with ALT shows a legend for that feature; pressing it with CTRL shows additional info Debugging functions are mapped to the F buttons, and are always available during gameplay in a debug build. Pressing the F button toggles the feature; pressing it with ALT shows a legend for that feature; pressing it with CTRL shows additional info
| key | description |
|-----+----------------------------|
| F1 | Draw physics info | | F1 | Draw physics info |
| F3 | Draw bounding boxes | | F3 | Draw bounding boxes |
| F12 | Drawing gui debugging info | | F12 | Drawing gui debugging info |
* Editor Tour
Prosperon's visual editor is just one tool of many you use to make your game. It is not an all in one shop like in other game engines.
The main editor view is made up of objects. Each object can have a number of components attached to it. When an object is selected, its name, position, and list of components are listed.
In addition, a window showing each entity underneath that entity are shown.
** The desktop
The desktop is the topmost object that exists in the editor. Instead of editing specific files, you simply load them into your desktop, and go from there. This makes it easier to see two different entities simultaneously so you can ensure changes to one are congruous with the vision for the others.
** *'s and %'s
When a '*' is seen next to an entity's name, that means it is altered compared to its ur-type and is unsaved. There are a number of ways to take care of a '*'. If you do not do one of the below, something on the entity will be lost.
- Changes can be saved to the ur-type. This makes all other entities derived from the ur-type change.
- Changes can be saved as a sub ur-type. This creates a brand new type that can then be reused over and over again.
- Changes can be saved by saving the containing ur-type. Ur-types remember variances in the entities it 'owns'.
When an entity is different from its ur-type, but the variance is saved due to its container, its name is preceded by a '%'.
The function 'revert()' can be called on any entity to make it like its ur-type again.
** Levels?
The concept of a 'level', a collection of spawned entities, is handled simply by creating sub ur-types of an empty entity.
** Editing level, ur-types, parents, children, etc
- lvl1
- tablebase
- %flipper
In this case, tablebase is saving a modified flipper.
- lvl1
- %tablebase
- %flipper
This is ambiguous. lvl1 could be storing the flipper's diff, or tablebase could be. Additionally, tablebase could have a unique flipper, and then lvl1 also alters it.
* Building
* Tutorials

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

94
doc/style.css Normal file
View file

@ -0,0 +1,94 @@
a:link a:visited a:hover a:active {
color: green;
}
.title {
visibility: hidden;
}
.floathead {
position: fixed;
width: 100%;
top: 0;
left: 0;
z-index: 100;
display flex;
align-items: center;
justify-content: center;
background-color: #3876AD;
}
.floathead a {
float: left; /* Float links side by side */
line-height: 100%;
margin-left: 20px;
margin-top: auto;
margin-bottom: auto;
height: 3rem;
line-height: 3rem;
text-align: center; /* Center-align text */
font-size: 24px;
color: #61bcd7;
}
#content {
max-width: 800px;
}
.floathead a:hover {
color: white;
}
h1 {
color: #61BCD7;
}
#org-div-home-and-up {
position: sticky;
top: 20px;
}
.example {
background-color: #FFFFEC;
border-width: 2px;
border-color: #61bcd7;
margin: 20px;
padding: 20px;
font-family: code;
font-size: 16px;
line-height: 1em;
white-space: pre-line;
display: inline-block;
}
@font-face {
font-family: "code";
src: url(dos.ttf);
}
.navbar {
background-color: #1678b2;
}
.scholium {
background-color: #F8F8F1;
}
.scholium .admonition-title {
background-color: #75FB4C;
color: black;
}
.navbar-brand span {
margin-top: 10px;
margin-left: 10px;
margin-right: 10px;
}
.terminal-prompt {
background-image: url(/prosperon_orb_horizontal.gif);
background-size: contain;
background-repeat: no-repeat;
}
.wm-page-toc-tree li:first-of-type{display:none}

View file

@ -1,43 +0,0 @@
# Building Primum
Building is done via a basic makefile with flags. Type "make" to build for the platform you are on. Targets include:
|crossmac|On an ARM mac, build a bundled intel and arm mac version|
|crosswin|On any POSIX computer with a GCC win32 toolchain, build for windows platforms|
|clean|clean up|
|tags|build tags file|
|cdb|build the cdb tool to inspect primum pak files|
|shaders|rebuild all shader headers|
|packer|tool for building primum pak files|
|input.md|editor input documentation|
|api.md|scripting API|
|switch|build for the nintendo switch|
|ps5|build for the ps5|
|playdate|build for the playdate|
Basic boolean flags, set to 0 or 1, to enable or disable features in the build
|DBG|debugging info in binary|
|NFLAC|true to not build flac ability|
|NMP3|true to not build mp3|
|NSVG|true to build without SVG|
|NEDITOR|true to not include editor|
|STEAM|true to build steam support|
|EGS|true to build with EGS support|
|GOG|true to build with GOG support|
## OPT
-0 No optimization
-1 Full optimization
-small Optimize for smallest binary
## Building for Steam
-Get the steam SDK
-Unpack it into a folder named 'steam' at the top level directory
-Move the steam libs into the lib folders arm64, x86, and x86_64
-Make with STEAM=1
Steam uses a C++ based SDK, so a C-only compiler like TCC will not work.
## Building with Discord
-Get the steam SDK
-Make with DISCORD=1

View file

@ -1,39 +0,0 @@
# Primum Editor
The main editor view is made up of objects. Each object can have a number of components attached to it. When an object is selected, its name, position, and list of components are listed.
In addition, a window showing each entity underneath that entity are shown.
## The desktop
The desktop is the topmost object that exists in the editor. Instead of editing specific files, you simply load them into your desktop, and go from there. This makes it easier to see two different entities simultaneously so you can ensure changes to one are congruous with the vision for the others.
## *'s and %'s
When a '*' is seen next to an entity's name, that means it is altered compared to its ur-type and is unsaved. There are a number of ways to take care of a '*'. If you do not do one of the below, something on the entity will be lost.
- Changes can be saved to the ur-type. This makes all other entities derived from the ur-type change.
- Changes can be saved as a sub ur-type. This creates a brand new type that can then be reused over and over again.
- Changes can be saved by saving the containing ur-type. Ur-types remember variances in the entities it 'owns'.
When an entity is different from its ur-type, but the variance is saved due to its container, its name is preceded by a '%'.
The function 'revert()' can be called on any entity to make it like its ur-type again.
## Levels?
The concept of a 'level', a collection of spawned entities, is handled simply by creating sub ur-types of an empty entity.
## Editing level, ur-types, parents, children, etc
lvl1
tablebase
%flipper
In this case, tablebase is saving a modified flipper.
lvl1
%tablebase
%flipper
This is ambiguous. lvl1 could be storing the flipper's diff, or tablebase could be. Additionally, tablebase could have a unique flipper, and then lvl1 also alters it.

View file

@ -1,36 +0,0 @@
# Entities
Entities are defined by creating a .jso script in your game directory. Variants of the original entity can be created by defining a .json file, typically done via the provided editor. The original entity is known as its ur-type. If you create a player.jso file in your game directory, a player can be spawned by saying Primum.spawn(ur.player).
An entity which differs from its ur will have an asterisk * next to its name.
Entities have components. The components all do a thing. Components are placed relative to the entity.
All entities are child to Primum, once the simulation is running.
Entites can be static, kinematic, or dynamic. Static entities never move. Kinematic entities move via explicit command. Dynamic ones move under the auspices of the game world.
Components, if they have a defined transform, are relative to the entity they reside on. Components cannot have components, ensuring that components can be processed and rendered in any order.
Entities are defined via a typical scene graph system. This allows for easy reuse of components when designing levels.
When the game is run, the movement relationships are broken, and the physics system takes over. In the physics engine, each entity is a direct child of the world. Objects can still be constrained to other objects via the physics system.
The transform properties have local, global, and screen space accessors. For example, for position ..
- pos: the relative position of the object to its master
- worldpos: the position of the object in the world
- screenpos: the position of the object in screen space
The core engine only remembers each object's world position. When its position is requested, it figures its position based on its parent.
## Inheritence? Composition?
The idea behind how the engine is oragnized is to encourage composition. Compisition creates cleaner objects than does inheritence, and is easier to understand. And yet, inheritence is useful for specific circumstances.
- Creating a specific unique object in a level
There are only two cases where inheritence can be utilized in this engine:
1. Whole entities can be subtyped. Only values can be substituted. An ur-type must define all functions and behaviors of an object. but then that can be subtyped to change only a handful of properties.
2. Entities can be subtyped when thrall to another entity. This can only be done once. Thrall objects, like components, can be defined only once on an ur-type. Sub types can only change parameters, and not of the sub objects.

View file

@ -1,19 +0,0 @@
# GUI & Drawing
Register functions with built-in drawing callbacks to have code execute at particular points in time. Some drawing functions take world coordinates, while others take screen coordinates.
gui
Called every frame.
draw
Called every frame.
debug
Called if drawing physics.
gizmo
Called on an object if it is selected in the editor.
# Mum
Mum is the GUI compositing system here. When drawing a mum, the bottom left corner is [0,0]. Change the anchor property of any Mum to change where it is drawn.

View file

@ -1,20 +0,0 @@
# Yugine Input Guide
Any Javascript object can be controlled by a Player, becoming a pawn. Each Player has their input sent to all of their pawns. To receive input, pawns must have a specifically named object. There are multiple possible input systems to receive input on.
## inputs
The 'inputs' object receives emacs-like keyboard controls, like C-K (ctrl-K), M-k (alt-k), k (just k).
inputs['C-k'] | function to call when C-k is pressed
inputs['C-k'].up | function to call when C-k is released
inputs['C-k'].rep | True if this down action is repeatable
These inputs are ideal for editor controls.
For these controls, pawn control order can matter. Pawns that are controlled later consume input commands, making it easy to control a specific editor component to alter the functionality of a portion of the editor.
## actions & input maps
Actions are a named input, ideal for game controls. Rather than say that "x" jumps, it might be better to name a "jump" action.
## Blocking
If 'block' is set to false on the input object, it will not block lower inputs from using the controls.

View file

@ -1,11 +0,0 @@
# Particle system
The particle system works in conjunction with script.
They are CPU-based particles, which enable a greater amount of particle interactivity thando GPU-based particles.
The particles are based on a node system. Particles can have a new set of parameters at different stages of its life.
Each particle can be individually queried for position, angle, life, and so on.
Emitters and even individual particles can have specific callback functions applied for death, birth, and more.

View file

@ -1,14 +0,0 @@
# Primum
The core tenents of Primum are as follows. When choosing features for Primum, these are the guidelines we follow.
- Gameplay first. Visuals are important but should be chosen to be more simple if it makes implementing gameplay more difficult.
- Dynamic first. Video games are dynamic, so as much as possible should be dynamically generated. For example, signed distance fields for particle system collision will not be used, as it requires baking sometimes false geometry. We include midi playback, which can be changed in real time far easier than wavs or mp3s.
- Code first, and marriage of code and editor. Neither completely replaces the other. What is easier to do in code should be done in code, and what should be done in editor should be done in editor. No solutions try to step on the toes of the other solution.
- Uniformity. There should not be a specific wind system that interacts with a specific tree system, for example. If there is a "wind" system, it will affect trees, grass, particles, potentially objects, the clouds in the sky, and everything else.
- Mathematics.
- Fast. 240 frames per second on modest hardware.
- "Does it for you". Advanced baking techniques so you can focus on making the game, and know you will not ship any unneeded files. Bake used textures smartly into sprite sheets for a given platform (ie if the platform supports 1k textures make 1k sheets, etc)
- Source control friendly. No binary data created by the engine, until shipping. Data references are handled with relative file paths.
- Heavily emphasize composition over inheritence. Allow for numerous ways of data sharing (like unity's scriptable objects).
- Crashing encouraged (during development). Very open data access, so that all systems can easily interact with and query all other systems. Robust debugging tools to help sort out the complexities that will surely arise from that.
- Actor model built in.

View file

@ -1,23 +0,0 @@
# The Scene
There are a multitude of representations of your entities in the engine. The two most prominent are the entity system, where entities can be master or thrall to a master. And then there is the physics view, which is mostly flat, where objects are all part of a "world", but can be connected to one another via various physics constraints:
- Pin joints, rigidly connected
- Slide joints, with a mix or max distance
- Pivot points, stuck to position but allow rotation
- Groove joint
- Damped spring
- Damped rotary spring
- Rotary limit
- Ratchet joint
- Gear joint
- Simple motor
The most common sort of connection will be master and thrall. When editing, this relationship allows for simple
## Entity vs Global
The physics engine stores all objects on the global level. The center of the world is [0,0]. Physics does not handle scaling at all.
The master/thrall relationship is closer to a scene graph. When the master moves, its thralls move, and their thralls move, etc. When a master scales, it is the same.
When the game starts simulating, objects ignore their parent relationship after they are created. They become only part of the world and simulate as such.

View file

@ -1,42 +0,0 @@
# Yugine Scripting Guide
Primum programs are organized into two different types of source files: scripts and entities. Scripts end with .js, entities end with .jso.
Actors can be created with jso files. Make one by calling 'actor.spawn(file)'.
Entities are specialized actors, that are in the world of the computer game. While calling delay on actor causes a delay relative to real-life time, delay on an entity causes a delay relative to the game world time. Entities can be thought of as running in parallel, but on a single thread on a local computer. In addition, their timeframe can be thought of as in sync with the computer game world.
The game itself has its own time and memory space.
## Scripts
Script hooks exist to allow to modification of the game.
|config.js|called before any game play, including play from editor|
|game.js|called to start the game|
|editorconfig.js|called when the editor is loaded, used to personalize|
|predbg.js|called when play in editor is selected, before level load|
|debug.js|called when play in editor is selected, after level load|
|dbgret.js|called when play in editor returns to editor|
In addition, any script can be run by running "load".
## Entities
Entities are defined in a jso file. The "this" parameter in the jso file is a reference to the actor, allowing you to define properties on it.
Computation takes place in turns. Each entity has functions called, if they exist. If a machine has multiple threads, multiple entities may be taking turns at a time.
|function|description|
|---|---|
|load|called after the object is loaded, including in editor|
|start|called when the object is loaded during gameplay|
|update(dt)|called once per game frame tick|
|physupdate(dt)|called once per physics tick|
|stop|called when the object is killed|
|debug|use draw functions with the object's world position, during debug pass|
|gui|draw functions in screen space, during gameplay gui pass|
|draw|draw functions in world space|
## Guidelines
When dealing with callbacks, callback registration can include objects or functions, but not both. You should either register an object to a list that always has 'update' called on them, or you should register the object's update function as a closure over the object.

View file

@ -1,30 +0,0 @@
# SOUND
Primum's sound system is well integrated and robust. It comes with flexibility in mind, to enable sounds to easily change as the result of occuring gameplay.
At the highest level, audio sources feed into a series of nodes, which eventually output to the mixer. All DSP is handled as floating point.
The game should specify a SAMPLERATE, BUF_FRAMES, and CHANNELS.
SAMPLERATE: samples per second
CHANNELS: number of output channels.
BUF_FRAMES: Number of frames to keep in the buffer. Smaller is lower latency. Too small might mean choppy audio.
## Audio sources
Audio sources include wav files, midi files, mod files, etc.
## Audio instances
Audio sources can be played multiple times after loaded into the game. Each instance
## DSPs / nodes
Nodes are how audio ends up coming out of the player's speakers. Only one node is specified at runtime: the master node, which outputs its inputs to the computers' speakers. It has 256 inputs.
Each node can have any number of inputs to it, defined when the node is created.
Nodes are run starting with the master node, in a pull fashion. The master node checks for inputs, and from each input pulls audio foward.
Audio instances are a type of node with a single output, and can be fed directly into the master node.
A node has inputs and outputs. All inputs into a node are mixed together, and then processed by the node. The node might clip them, apply a filter, or do any other number of things.
## Scripting

View file

@ -1,10 +0,0 @@
# Yugine video playing
Yugine plays the open source MPEG-TS muxer, using MPEG1 video and MP2 audio.
MPEG-1 video works best at about 1.5 Mbit/s, in SD [720x480] video.
For HD [1920x1080] video, use 9 Mbit/s.
ffmpeg -i "input.video" -c:v mpeg1video -b:v 1.5M -s 720x480 -c:a mp2 -format mpeg "out.mpg"
ffmpeg -i "input.video" -vcodec mpeg1video -b:v 9M -s 1920x1080 -acodec mp2 -format mpeg "out.mpg"

View file

@ -1,9 +0,0 @@
# Warp effects
Warp effects deal with particles as well as physics based rigidbodies.
- Motor: Apply torque.
- Vortex: A whirlpool like force.
- Gravity: A simple gravity force.
- Wind: Wind like force, with simulated turbulence.
- Bomb: Short force radially outwards

View file

@ -1,7 +0,0 @@
# Rendering & Window
## 2D
For a 2D game, you should use sprites for which are the highest resolution you wish to target.
While designing the game, a 'native' resolution should be selected. One unit in the game world is equivalent to one display pixel, so this resolution should be selected based on the 'look' of the game you are going for.

4
readme.md Normal file
View file

@ -0,0 +1,4 @@
# Prosperon Engine
## Installation
Run make.

View file

@ -24,11 +24,6 @@ WeakSet = undefined;
var fmt = {}; var fmt = {};
function arabic2roman(num)
{
if (num <= 0 || num >= 4000)
return "Invalid input. Roman numerals are not defined for numbers less than 1 or greater than 3999.";
var roman_numerals = { var roman_numerals = {
M: 1000, M: 1000,
CM: 900, CM: 900,
@ -45,6 +40,25 @@ function arabic2roman(num)
I: 1 I: 1
}; };
function roman2arabic(roman)
{
var num = 0;
for (var i = 0; i < roman.length; i++) {
var rm = roman_numerals[roman[i]];
if (i + 1 < roman.length && rm < roman_numerals[roman[i+1]])
num -= rm;
else
num += rm;
}
return num;
}
function arabic2roman(num)
{
if (num <= 0 || num >= 4000)
return "Invalid input. Roman numerals are not defined for numbers less than 1 or greater than 3999.";
var result = ''; var result = '';
for (var key in roman_numerals) { for (var key in roman_numerals) {
@ -611,11 +625,9 @@ Object.defineProperty(Object.prototype, 'map', {
} }
}); });
Object.defineProperty(Object.prototype, 'empty', { Object.empty = function(obj) {
get: function() { return Object.keys(obj).length === 0;
return Object.keys(this).empty; }
},
});
Object.defineProperty(Object.prototype, 'nth', { Object.defineProperty(Object.prototype, 'nth', {
value: function(x) { value: function(x) {
@ -646,12 +658,6 @@ Object.defineProperty(Object.prototype, 'push', {
} }
}); });
Object.defineProperty(Object.prototype, 'remove', {
value: function(val) {
delete this[val.toString()];
}
});
Object.defineProperty(Object.prototype, 'findIndex', { Object.defineProperty(Object.prototype, 'findIndex', {
value: function(x) { value: function(x) {
var i = 0; var i = 0;

View file

@ -48,7 +48,7 @@ function equal(x,y) {
}; };
function diffassign(target, from) { function diffassign(target, from) {
if (from.empty) return; if (Object.empty(from)) return;
for (var e in from) { for (var e in from) {
if (typeof from[e] === 'object') { if (typeof from[e] === 'object') {
@ -82,7 +82,7 @@ function objdiff(from,to)
ret[key] = Object.values(ediff(v, [])); ret[key] = Object.values(ediff(v, []));
var diff = ediff(from[key], to[key]); var diff = ediff(from[key], to[key]);
if (diff && !diff.empty) if (diff && !Object.empty(diff))
ret[key] = Object.values(ediff(v,[])); ret[key] = Object.values(ediff(v,[]));
return; return;
@ -90,7 +90,7 @@ function objdiff(from,to)
if (typeof v === 'object') { if (typeof v === 'object') {
var diff = ediff(v, to[key]); var diff = ediff(v, to[key]);
if (diff && !diff.empty) if (diff && !Object.empty(diff))
ret[key] = diff; ret[key] = diff;
return; return;
} }
@ -104,7 +104,7 @@ function objdiff(from,to)
if (!to || v !== to[key]) if (!to || v !== to[key])
ret[key] = v; ret[key] = v;
}); });
if (ret.empty) return undefined; if (Object.empty(ret)) return undefined;
return ret; return ret;
} }
@ -160,7 +160,7 @@ function ediff(from,to)
} }
var diff = ediff(from[key], to[key]); var diff = ediff(from[key], to[key]);
if (diff && !diff.empty) if (diff && !Object.empty(diff))
ret[key] = Object.values(ediff(v,[])); ret[key] = Object.values(ediff(v,[]));
return; return;
@ -168,7 +168,7 @@ function ediff(from,to)
if (typeof v === 'object') { if (typeof v === 'object') {
var diff = ediff(v, to[key]); var diff = ediff(v, to[key]);
if (diff && !diff.empty) if (diff && !Object.empty(diff))
ret[key] = diff; ret[key] = diff;
return; return;
} }
@ -182,7 +182,7 @@ function ediff(from,to)
if (!to || v !== to[key]) if (!to || v !== to[key])
ret[key] = v; ret[key] = v;
}); });
if (ret.empty) return undefined; if (Object.empty(ret)) return undefined;
return ret; return ret;
} }

View file

@ -302,7 +302,7 @@ var editor = {
}, },
redo() { redo() {
if (this.backshots.empty) { if (Object.empty(this.backshots)) {
Log.info("Nothing to redo."); Log.info("Nothing to redo.");
return; return;
} }
@ -316,7 +316,7 @@ var editor = {
}, },
undo() { undo() {
if (this.snapshots.empty) { if (Object.empty(this.snapshots)) {
Log.info("Nothing to undo."); Log.info("Nothing to undo.");
return; return;
} }
@ -620,7 +620,7 @@ editor.inputs.release_post = function() {
editor.edit_level.obj_descend(o => o.pos = o.pos.map(x => Math.round(x))); editor.edit_level.obj_descend(o => o.pos = o.pos.map(x => Math.round(x)));
}; };
editor.inputs['C-a'] = function() { editor.inputs['C-a'] = function() {
if (!editor.selectlist.empty) { editor.unselect(); return; } if (!Object.empty(editor.selectlist)) { editor.unselect(); return; }
editor.unselect(); editor.unselect();
editor.selectlist = editor.edit_level.objects.slice(); editor.selectlist = editor.edit_level.objects.slice();
}; };
@ -912,7 +912,7 @@ editor.inputs['M-y'] = function() { editor.programmode = !editor.programmode; };
editor.inputs['M-y'].doc = "Toggle program mode."; editor.inputs['M-y'].doc = "Toggle program mode.";
editor.inputs.minus = function() { editor.inputs.minus = function() {
if (!editor.selectlist.empty) { if (!Object.empty(editor.selectlist)) {
editor.selectlist.forEach(function(x) { x.draw_layer--; }); editor.selectlist.forEach(function(x) { x.draw_layer--; });
return; return;
} }
@ -923,7 +923,7 @@ editor.inputs.minus = function() {
editor.inputs.minus.doc = "Go down one working layer, or, move selected objects down one layer."; editor.inputs.minus.doc = "Go down one working layer, or, move selected objects down one layer.";
editor.inputs.plus = function() { editor.inputs.plus = function() {
if (!editor.selectlist.empty) { if (!Object.empty(editor.selectlist)) {
editor.selectlist.forEach(x => x.draw_layer++); editor.selectlist.forEach(x => x.draw_layer++);
return; return;
} }
@ -989,7 +989,7 @@ editor.inputs.lm.released = function() {
selects = selects.flat(); selects = selects.flat();
selects = selects.unique(); selects = selects.unique();
if (selects.empty) return; if (Object.empty(selects)) return;
if (Keys.shift()) { if (Keys.shift()) {
selects.forEach(function(x) { selects.forEach(function(x) {
@ -1001,7 +1001,7 @@ editor.inputs.lm.released = function() {
if (Keys.ctrl()) { if (Keys.ctrl()) {
selects.forEach(function(x) { selects.forEach(function(x) {
this.selectlist.remove(x); delete this.selectlist[x.toString()];
}, this); }, this);
return; return;
@ -1687,7 +1687,7 @@ var objectexplorer = Object.copy(inputpanel, {
curobj = curobj.__proto__; curobj = curobj.__proto__;
} }
if (!this.previous.empty) if (!Object.empty(this.previous))
items.push(Mum.text({str:"prev: " + this.previous.last(), action: this.prev_obj})); items.push(Mum.text({str:"prev: " + this.previous.last(), action: this.prev_obj}));
Object.getOwnPropertyNames(this.obj).forEach(key => { Object.getOwnPropertyNames(this.obj).forEach(key => {
@ -1926,7 +1926,7 @@ function tab_complete(val, list) {
var ret = undefined; var ret = undefined;
var i = val.length; var i = val.length;
while (!ret && !list.empty) { while (!ret && !Object.empty(list)) {
var char = list[0][i]; var char = list[0][i];
if (!list.every(function(x) { return x[i] === char; })) if (!list.every(function(x) { return x[i] === char; }))
ret = list[0].slice(0, i); ret = list[0].slice(0, i);

View file

@ -7,6 +7,9 @@ function load(file) {
load("scripts/base.js"); load("scripts/base.js");
load("scripts/std.js"); load("scripts/std.js");
//load("scripts/lunr.js");
var lunrtxt = load("scripts/lunr.js");
eval(lunrtxt);
function run(file) function run(file)
{ {
@ -519,7 +522,7 @@ Game.view_camera = function(cam)
cmd(61, Game.camera.body); cmd(61, Game.camera.body);
} }
Window.name = "Primum Machinam (V0.1)"; Window.name = "Prosperon (V0.1)";
Window.width = 1280; Window.width = 1280;
Window.height = 720; Window.height = 720;

View file

@ -33,7 +33,7 @@ actor.die = function(actor){
actor.timers = []; actor.timers = [];
actor.kill = function(){ actor.kill = function(){
this.timers.forEach(t => t.kill()); this.timers.forEach(t => t.kill());
this.master.remove(this); delete this.master[this.toString()];
this.padawans.forEach(p => p.kill()); this.padawans.forEach(p => p.kill());
this.__dead__ = true; this.__dead__ = true;
}; };
@ -43,7 +43,7 @@ actor.delay = function(fn, seconds) {
t.remain = seconds; t.remain = seconds;
t.kill = () => { t.kill = () => {
timer.kill.call(t); timer.kill.call(t);
this.timers.remove(t); delete this.timers[t.toString()];
} }
t.fire = () => { t.fire = () => {
if (this.__dead__) return; if (this.__dead__) return;
@ -60,7 +60,7 @@ actor.master = undefined;
actor.padawans = []; actor.padawans = [];
actor.remaster = function(to){ actor.remaster = function(to){
this.master.padawans.remove(this); delete this.master.padawans[this.toString()];
this.master = to; this.master = to;
to.padawans.push(this); to.padawans.push(this);
}; };
@ -169,12 +169,12 @@ var gameobject = {
}, },
check_dirty() { check_dirty() {
this._ed.urdiff = this.json_obj(); this._ed.urdiff = this.json_obj();
this._ed.dirty = !this._ed.urdiff.empty; this._ed.dirty = !Object.empty(this._ed.urdiff);
var lur = ur[this.level.ur]; var lur = ur[this.level.ur];
if (!lur) return; if (!lur) return;
var lur = lur.objects[this.toString()]; var lur = lur.objects[this.toString()];
var d = ediff(this._ed.urdiff,lur); var d = ediff(this._ed.urdiff,lur);
if (!d || d.empty) if (!d || Object.empty(d))
this._ed.inst = true; this._ed.inst = true;
else else
this._ed.inst = false; this._ed.inst = false;
@ -577,7 +577,7 @@ var gameobject = {
} }
if (this.__proto__.instances) if (this.__proto__.instances)
this.__proto__.instances.remove(this); delete this.__proto__.instances[this.toString()];
for (var key in this.components) { for (var key in this.components) {
this.components[key].kill(); this.components[key].kill();
@ -905,7 +905,9 @@ prototypes.generate_ur = function(path)
{ {
var ob = IO.glob("**" + prototypes.ur_ext); var ob = IO.glob("**" + prototypes.ur_ext);
ob = ob.concat(IO.glob("**.json")); ob = ob.concat(IO.glob("**.json"));
ob = ob.map(function(path) { return path.set_ext(""); }); ob = ob.map(function(path) { return path.set_ext(""); });
ob = ob.map(function(path) { return path[0] !== '.' ? path : undefined; });
ob.forEach(function(name) { prototypes.get_ur(name); }); ob.forEach(function(name) { prototypes.get_ur(name); });
} }
@ -989,8 +991,3 @@ prototypes.ur_pullout_folder = function(ur)
if (IO.exists(p)) if (IO.exists(p))
*/ */
} }
prototypes.ur_pushin_folder = function(ur)
{
}

View file

@ -134,7 +134,7 @@ struct Texture *texture_pullfromfile(const char *path) {
free(svg); free(svg);
free(rast); free(rast);
#else #else
YughWarn("Primum was built without SVG capabilities."); YughWarn("Prosperon was built without SVG capabilities.");
return; return;
#endif #endif
} else { } else {