Add all files needed for engine into main branch
4
Makefile
|
@ -114,12 +114,14 @@ $(BIN)$(NAME): $(objprefix)/source/engine/yugine.o $(ENGINE) $(BIN)libquickjs.a
|
||||||
$(CC) $< $(LINK) -o $(BIN)$(NAME)
|
$(CC) $< $(LINK) -o $(BIN)$(NAME)
|
||||||
@echo Finished build
|
@echo Finished build
|
||||||
|
|
||||||
$(BIN)$(DIST): $(BIN)$(NAME) source/shaders/*
|
$(BIN)$(DIST): $(BIN)$(NAME) source/shaders/* source/scripts/* assets/*
|
||||||
@echo Creating distribution $(DIST)
|
@echo Creating distribution $(DIST)
|
||||||
@mkdir -p $(BIN)dist
|
@mkdir -p $(BIN)dist
|
||||||
@cp $(BIN)$(NAME) $(BIN)dist
|
@cp $(BIN)$(NAME) $(BIN)dist
|
||||||
@cp -rf assets/fonts $(BIN)dist
|
@cp -rf assets/fonts $(BIN)dist
|
||||||
|
@cp -rf assets/icons $(BIN)dist
|
||||||
@cp -rf source/shaders $(BIN)dist
|
@cp -rf source/shaders $(BIN)dist
|
||||||
|
@cp -r source/scripts $(BIN)dist
|
||||||
@tar czf $(DIST) --directory $(BIN)dist .
|
@tar czf $(DIST) --directory $(BIN)dist .
|
||||||
@mv $(DIST) $(BIN)
|
@mv $(DIST) $(BIN)
|
||||||
|
|
||||||
|
|
BIN
assets/fonts/LessPerfectDOSVGA.ttf
Normal file
4
assets/fonts/dos.font
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
(font
|
||||||
|
:path "LessPerfectDOSVGA.ttf"
|
||||||
|
:size 16
|
||||||
|
)
|
BIN
assets/icons/icons8-bug-16.png
Normal file
After Width: | Height: | Size: 298 B |
BIN
assets/icons/icons8-console-16.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
assets/icons/icons8-factory-16.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
assets/icons/icons8-gear-16.png
Normal file
After Width: | Height: | Size: 293 B |
BIN
assets/icons/icons8-light-switch-16.png
Normal file
After Width: | Height: | Size: 157 B |
BIN
assets/icons/icons8-lock-16.png
Normal file
After Width: | Height: | Size: 197 B |
BIN
assets/icons/icons8-music-16.png
Normal file
After Width: | Height: | Size: 226 B |
BIN
assets/icons/icons8-pause-16.png
Normal file
After Width: | Height: | Size: 108 B |
BIN
assets/icons/icons8-radio-tower-16.png
Normal file
After Width: | Height: | Size: 339 B |
BIN
assets/icons/icons8-record-16.png
Normal file
After Width: | Height: | Size: 234 B |
BIN
assets/icons/icons8-resume-button-16.png
Normal file
After Width: | Height: | Size: 187 B |
BIN
assets/icons/icons8-shuffle-16.png
Normal file
After Width: | Height: | Size: 224 B |
BIN
assets/icons/icons8-skip-to-start-16.png
Normal file
After Width: | Height: | Size: 206 B |
BIN
assets/icons/icons8-spotlight-16.png
Normal file
After Width: | Height: | Size: 304 B |
BIN
assets/icons/no_tex.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
164
docs/editor.adoc
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
= Yugine 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.
|
||||||
|
|
||||||
|
.Basic controls
|
||||||
|
* Ctrl-Z Undo
|
||||||
|
* Ctrl-Shift-Z Redo
|
||||||
|
* Ctrl-A Select all
|
||||||
|
* Ctrl-S Save
|
||||||
|
* Ctrl-N New
|
||||||
|
* Ctrl-O Open level
|
||||||
|
* Ctrl-X Cut
|
||||||
|
* Ctrl-C Copy
|
||||||
|
* Ctrl-V Paste
|
||||||
|
* Alt-O Add level to current level
|
||||||
|
* Alt-A or Alt-P Add a prefab
|
||||||
|
* Ctrl-I Objects on the level
|
||||||
|
* Ctrl-M Asset viewer. When on a component like a sprite, serves to select that sprite's texture
|
||||||
|
* Ctrl-[ Downsize grid
|
||||||
|
* Ctrl-] Upsize grid
|
||||||
|
* Backtick REPL
|
||||||
|
* Ctrl-[1-9] to set camera positions
|
||||||
|
* [1-9] to recall camera positions
|
||||||
|
* 0 Set camera to home view
|
||||||
|
* ESC quit
|
||||||
|
* Alt-1 Normal view
|
||||||
|
* Alt-2 Wireframe view
|
||||||
|
* Shift-Middle Set editor cursor to mouse position (Cursor affects how objects rotate)
|
||||||
|
* Shift-Ctrl-Middle Set cursor to object selection
|
||||||
|
* Shift-Right Remove cursor
|
||||||
|
|
||||||
|
.Editor Mode select
|
||||||
|
* Alt-F1 Basic mode
|
||||||
|
* Alt-F2 Brush mode
|
||||||
|
- Clicking will place what is on clipboard
|
||||||
|
|
||||||
|
.Object controls
|
||||||
|
* G Translate
|
||||||
|
* Alt-G Snap objects to cursor
|
||||||
|
* S Scale
|
||||||
|
* R Rotate
|
||||||
|
* Ctrl-P Save object changes to prefab
|
||||||
|
* Ctrl-shift-P Save object changes as a unique prefab ("Parent")
|
||||||
|
* Ctrl-shift-T Save object changes to a side prefab ("Type")
|
||||||
|
* Ctrl-J Bake name to expose to level script
|
||||||
|
* Alt-J Remove baked name
|
||||||
|
* Ctrl-Y Show obj chain
|
||||||
|
* Alt-Y Start prototype explorer
|
||||||
|
* Ctrl-U Revert object or component to match prototype
|
||||||
|
* Alt-U Make object unique. If a level, allows setting of internal object position and rotation.
|
||||||
|
* Ctrl-shift-G Save group as a level
|
||||||
|
* Arrows Translate 1 px
|
||||||
|
* Shift-Arrows Translate 10 px
|
||||||
|
* Tab Select component
|
||||||
|
* F Zoom to object(s)
|
||||||
|
* Ctrl-F Focus on a selected sublevel. Edit and save it in place.
|
||||||
|
* Ctrl-Shift-F Go up one level in the editing chain.
|
||||||
|
* M Flip horizontally
|
||||||
|
* Ctrl-M Flip vertically
|
||||||
|
* Ctrl-D Duplicate
|
||||||
|
* H Hide
|
||||||
|
* Ctrl-H Unhide all
|
||||||
|
* T Lock
|
||||||
|
* Alt-T Unlock all
|
||||||
|
* Q Toggle component help
|
||||||
|
* Ctrl-Shift-Alt-Click Set object center
|
||||||
|
|
||||||
|
.Mouse controls
|
||||||
|
* Left Select
|
||||||
|
* Middle Quick grab
|
||||||
|
* Right Unselect
|
||||||
|
|
||||||
|
.Level controls
|
||||||
|
* Ctrl-L Open level script
|
||||||
|
|
||||||
|
.Game controls
|
||||||
|
* F1 Debug draw
|
||||||
|
* F2 Config menu
|
||||||
|
* F3 Show bounding boxes
|
||||||
|
* F4 Show gizmos
|
||||||
|
* F5 Start
|
||||||
|
* F6 Pause
|
||||||
|
* F7 Stop
|
||||||
|
* F10 Toggle slow motion
|
||||||
|
|
||||||
|
== Components
|
||||||
|
Components all have their own set of controls. Many act similar to
|
||||||
|
objects. If a component has a position attribute, it will react as
|
||||||
|
expected to object grabbing; same with scaling, rotation, and so on.
|
||||||
|
|
||||||
|
If a component uses an asset, the asset viewer will serve to pick new
|
||||||
|
assets for it.
|
||||||
|
|
||||||
|
.Spline controls
|
||||||
|
* Ctrl-click Add a point
|
||||||
|
* Shift-click remove a point
|
||||||
|
* +,- Increase or decrease spline segments
|
||||||
|
* Ctrl-+,- Increase or decrease spline degrees. Put this to 1 for the spline to go point to point
|
||||||
|
* Alt-B,V Increase or decrease spline thickness
|
||||||
|
|
||||||
|
.Collider controls
|
||||||
|
* Alt-S Toggle sensor
|
||||||
|
|
||||||
|
= Yugine Programming
|
||||||
|
|
||||||
|
.Object functions
|
||||||
|
|
||||||
|
* start(): Called when the object is created, before the first update is ran
|
||||||
|
* update(dt): Called once per frame
|
||||||
|
* physupdate(dt): Called once per physics calculation
|
||||||
|
* stop(): Called when the object is killed
|
||||||
|
* collide(hit): Called when this object collides with another. If on a collider, specific to that collider
|
||||||
|
- hit.hit: Gameobject ID of what's being hit
|
||||||
|
- hit.velocity: Velocity of impact
|
||||||
|
- hit.normal: Normal of impact
|
||||||
|
|
||||||
|
.Input
|
||||||
|
Input works by adding functions to an object, and then "controlling"
|
||||||
|
them. The format for a function is "input_[key]_[action]". [Action]
|
||||||
|
can be any of
|
||||||
|
|
||||||
|
- down: Called once per frame the key is down
|
||||||
|
- pressed: Called when the key is pressed
|
||||||
|
- released: called when the key is released
|
||||||
|
|
||||||
|
For example, "input_p_pressed()" will be called when p is pressed, and not again
|
||||||
|
until it is released and pressed again.
|
||||||
|
|
||||||
|
.Your game
|
||||||
|
|
||||||
|
When the engine runs, it executes config.js, and then game.js. A
|
||||||
|
window should be created in config.js, and custom code for prototypes
|
||||||
|
should be executed.
|
||||||
|
|
||||||
|
game.js is the place to open your first level.
|
||||||
|
|
||||||
|
.Levels
|
||||||
|
|
||||||
|
A level is a collection of objects. A level has a script associated
|
||||||
|
with it. The script is ran when the level is loaded.
|
||||||
|
|
||||||
|
Levels can be added to other levels. Each is independent and unique.
|
||||||
|
In this way, complicated behavior can easily be added up. For example,
|
||||||
|
a world might have a door that opens with a lever. The door and lever
|
||||||
|
can be saved off as their own level, and the level script can contain
|
||||||
|
the code that causes the door to open when the lever is thrown. Then,
|
||||||
|
as many door-lever levels can be added to your game as you want.
|
||||||
|
|
||||||
|
The two primary ways to add objects to the game are World.spawn, and
|
||||||
|
Level.add. World.spawn creates a single object in the world, Level.add
|
||||||
|
adds an entire level, along with its script.
|
||||||
|
|
||||||
|
Levels also can be checked for "completion". A level can be loaded
|
||||||
|
over many frames, and only have all of its contents appear once it's
|
||||||
|
finished loading. World.spawn is immediate.
|
||||||
|
|
||||||
|
Level.clear removes the level from the game world.
|
||||||
|
|
||||||
|
.Level scripting
|
||||||
|
Each level has a script which is ran when the level is loaded, or the
|
||||||
|
game is played. A single object declared in it called "scene" can be
|
||||||
|
used to expose itself to the rest of the game.
|
65
docs/game.adoc
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
= Yugine Engine
|
||||||
|
|
||||||
|
The yugine essentially is made of a sequence of levels. Levels can be
|
||||||
|
nested, they can be streamed in, or loaded one at a time. Levels are
|
||||||
|
made of levels.
|
||||||
|
|
||||||
|
Different "modes" of using the engine has unique sequences of level
|
||||||
|
loading orders. Each level has an associated script file. Level
|
||||||
|
loading functions call the script file, as well as the level file. The
|
||||||
|
level file can be considered to be a container of objects that the
|
||||||
|
associated script file can access.
|
||||||
|
|
||||||
|
.Game start
|
||||||
|
|
||||||
|
* Engine scripts
|
||||||
|
* config.js
|
||||||
|
* game.lvl & game.js
|
||||||
|
|
||||||
|
.Editor
|
||||||
|
|
||||||
|
* Engine scripts
|
||||||
|
* config.js
|
||||||
|
* editor.js
|
||||||
|
|
||||||
|
.Editor play
|
||||||
|
|
||||||
|
* F5 debug.lvl
|
||||||
|
- Used for custom debug level testing. If doesn't exist, game.lvl is loaded.
|
||||||
|
* F6 game.lvl
|
||||||
|
* F7 Currently edited level
|
||||||
|
|
||||||
|
While playing ...
|
||||||
|
* F7 Stop
|
||||||
|
|
||||||
|
.Scripting
|
||||||
|
|
||||||
|
Levels and objects have certain functions you can use that will be
|
||||||
|
called at particular times during the course of the game running.
|
||||||
|
|
||||||
|
setup
|
||||||
|
Called once, when the object is created.
|
||||||
|
|
||||||
|
start
|
||||||
|
Called once when the gameplay is simulating.
|
||||||
|
|
||||||
|
update(dt)
|
||||||
|
Called once per frame, while the game is simulating
|
||||||
|
|
||||||
|
physupdate(dt)
|
||||||
|
Called once per physics step
|
||||||
|
|
||||||
|
stop
|
||||||
|
Called when the object is destroyed, either by being killed or otherwise.
|
||||||
|
|
||||||
|
.Collider functions
|
||||||
|
Colliders get special functions to help with collision handling.
|
||||||
|
|
||||||
|
collide(hit)
|
||||||
|
Called when an object collides with the object this function is on.
|
||||||
|
|
||||||
|
"hit" object
|
||||||
|
normal - A vector in the direction the hit happened
|
||||||
|
hit - Object ID of colliding object
|
||||||
|
sensor - True if the colliding object is a sensor
|
||||||
|
velocity - A vector of the velocity of the collision
|
10
docs/video.adoc
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
.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" -vcodec mpeg1video -b:v 1.5M -s 720x480 -acodec mp2 "out.ts"
|
||||||
|
ffmpeg -i "input.video" -vcodec mpeg1video -b:v 9M -s 1920x1080 -acodec mp2 "out.ts"
|
||||||
|
|
|
@ -553,7 +553,8 @@ JSValue dukext2paths(char *ext)
|
||||||
JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
{
|
{
|
||||||
int cmd = js2int(argv[0]);
|
int cmd = js2int(argv[0]);
|
||||||
const char *str;
|
const char *str = NULL;
|
||||||
|
const char *str2 = NULL;
|
||||||
JSValue ret = JS_NULL;
|
JSValue ret = JS_NULL;
|
||||||
|
|
||||||
switch(cmd) {
|
switch(cmd) {
|
||||||
|
@ -611,16 +612,23 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
case 12:
|
case 12:
|
||||||
sprite_loadtex(id2sprite(js2int(argv[1])), JS_ToCString(js, argv[2]), js2glrect(argv[3]));
|
str = JS_ToCString(js,argv[2]);
|
||||||
|
sprite_loadtex(id2sprite(js2int(argv[1])), str, js2glrect(argv[3]));
|
||||||
|
JS_FreeCString(js,str);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 13:
|
case 13:
|
||||||
|
str = JS_ToCString(js,argv[1]);
|
||||||
play_song(JS_ToCString(js, argv[1]), JS_ToCString(js, argv[2]));
|
str2 = JS_ToCString(js,argv[2]);
|
||||||
|
play_song(str,str2);
|
||||||
|
JS_FreeCString(js,str);
|
||||||
|
JS_FreeCString(js,str2);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 14:
|
case 14:
|
||||||
mini_sound(JS_ToCString(js, argv[1]));
|
str = JS_ToCString(js, argv[1]);
|
||||||
|
mini_sound(str);
|
||||||
|
JS_FreeCString(js,str);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 15:
|
case 15:
|
||||||
|
@ -712,10 +720,18 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 38:
|
case 38:
|
||||||
return JS_NewString(js, slurp_text(JS_ToCString(js, argv[1])));
|
str = JS_ToCString(js,argv[1]);
|
||||||
|
ret = JS_NewString(js, slurp_text(str));
|
||||||
|
JS_FreeCString(js,str);
|
||||||
|
return ret;
|
||||||
|
|
||||||
case 39:
|
case 39:
|
||||||
return JS_NewInt64(js, slurp_write(JS_ToCString(js, argv[1]), JS_ToCString(js, argv[2])));
|
str = JS_ToCString(js,argv[1]);
|
||||||
|
str2 = JS_ToCString(js,argv[2]);
|
||||||
|
ret = JS_NewInt64(js, slurp_write(str, str2));
|
||||||
|
JS_FreeCString(js,str);
|
||||||
|
JS_FreeCString(js,str2);
|
||||||
|
return ret;
|
||||||
|
|
||||||
case 40:
|
case 40:
|
||||||
id2go(js2int(argv[1]))->filter.categories = js2bitmask(argv[2]);
|
id2go(js2int(argv[1]))->filter.categories = js2bitmask(argv[2]);
|
||||||
|
@ -805,13 +821,19 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
return JS_NewFloat64(js, deltaT);
|
return JS_NewFloat64(js, deltaT);
|
||||||
|
|
||||||
case 64:
|
case 64:
|
||||||
return vec2js(tex_get_dimensions(texture_pullfromfile(JS_ToCString(js, argv[1]))));
|
str = JS_ToCString(js,argv[1]);
|
||||||
|
ret = vec2js(tex_get_dimensions(texture_pullfromfile(str)));
|
||||||
|
break;
|
||||||
|
|
||||||
case 65:
|
case 65:
|
||||||
return JS_NewBool(js, file_exists(JS_ToCString(js, argv[1])));
|
str = JS_ToCString(js,argv[1]);
|
||||||
|
ret = JS_NewBool(js, file_exists(str));
|
||||||
|
break;
|
||||||
|
|
||||||
case 66:
|
case 66:
|
||||||
return dukext2paths(JS_ToCString(js, argv[1]));
|
str = JS_ToCString(js,argv[1]);
|
||||||
|
ret = dukext2paths(str);
|
||||||
|
break;
|
||||||
|
|
||||||
case 67:
|
case 67:
|
||||||
opengl_rendermode(LIT);
|
opengl_rendermode(LIT);
|
||||||
|
@ -885,8 +907,9 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
return ints2js(phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4])));
|
return ints2js(phys2d_query_box_points(js2vec2(argv[1]), js2vec2(argv[2]), js2cpvec2arr(argv[3]), js2int(argv[4])));
|
||||||
|
|
||||||
case 87:
|
case 87:
|
||||||
mini_music_play(JS_ToCString(js, argv[1]));
|
str = JS_ToCString(js, argv[1]);
|
||||||
return JS_NULL;
|
mini_music_play(str);
|
||||||
|
break;
|
||||||
|
|
||||||
case 88:
|
case 88:
|
||||||
mini_music_pause();
|
mini_music_pause();
|
||||||
|
@ -897,10 +920,20 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
|
|
||||||
case 90:
|
case 90:
|
||||||
window_set_icon(JS_ToCString(js, argv[1]));
|
str = JS_ToCString(js, argv[1]);
|
||||||
|
window_set_icon(str);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (str)
|
||||||
|
JS_FreeCString(js,str);
|
||||||
|
|
||||||
|
if (str2)
|
||||||
|
JS_FreeCString(js,str2);
|
||||||
|
|
||||||
|
if (!JS_IsNull(ret))
|
||||||
|
return ret;
|
||||||
|
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,6 @@ void script_init() {
|
||||||
/* Load all prefabs into memory */
|
/* Load all prefabs into memory */
|
||||||
script_dofile("scripts/engine.js");
|
script_dofile("scripts/engine.js");
|
||||||
script_dofile("config.js");
|
script_dofile("config.js");
|
||||||
//ftw(".", load_prefab, 10);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void script_run(const char *script) {
|
void script_run(const char *script) {
|
||||||
|
|
|
@ -122,7 +122,7 @@ struct Texture *texture_loadfromfile(const char *path)
|
||||||
{
|
{
|
||||||
struct Texture *new = texture_pullfromfile(path);
|
struct Texture *new = texture_pullfromfile(path);
|
||||||
|
|
||||||
if (new == NULL) { new = texture_pullfromfile("./ph.png"); }
|
if (new == NULL) { new = texture_pullfromfile("./icons/no_tex.png"); }
|
||||||
|
|
||||||
if (new->id == 0) {
|
if (new->id == 0) {
|
||||||
glGenTextures(1, &new->id);
|
glGenTextures(1, &new->id);
|
||||||
|
|
|
@ -187,7 +187,7 @@ int main(int argc, char **args) {
|
||||||
renderMS = 1.0/vidmode->refreshRate;
|
renderMS = 1.0/vidmode->refreshRate;
|
||||||
|
|
||||||
if (ed)
|
if (ed)
|
||||||
script_dofile("editor.js");
|
script_dofile("scripts/editor.js");
|
||||||
else
|
else
|
||||||
script_dofile("game.js");
|
script_dofile("game.js");
|
||||||
|
|
||||||
|
|
609
source/scripts/base.js
Normal file
|
@ -0,0 +1,609 @@
|
||||||
|
/* Prototypes out an object and extends with values */
|
||||||
|
function clone(proto, binds) {
|
||||||
|
var c = Object.create(proto);
|
||||||
|
complete_assign(c, binds);
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Prototypes out an object and assigns values */
|
||||||
|
function copy(proto, binds) {
|
||||||
|
var c = Object.create(proto);
|
||||||
|
Object.assign(c, binds);
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* OBJECT DEFININTIONS */
|
||||||
|
Object.defineProperty(Object.prototype, 'getOwnPropertyDescriptors', {
|
||||||
|
value: function() {
|
||||||
|
var obj = {};
|
||||||
|
for (var key in this) {
|
||||||
|
obj[key] = Object.getOwnPropertyDescriptor(this, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'hasOwn', {
|
||||||
|
value: function(x) { return this.hasOwnProperty(x); }
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'array', {
|
||||||
|
value: function() {
|
||||||
|
var a = [];
|
||||||
|
for (var key in this)
|
||||||
|
a.push(this[key]);
|
||||||
|
|
||||||
|
return a;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'defn', {
|
||||||
|
value: function(name, val) {
|
||||||
|
Object.defineProperty(this, name, { value:val, writable:true, configurable:true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'nulldef', {
|
||||||
|
value: function(name, val) {
|
||||||
|
if (!this.hasOwnProperty(name)) this[name] = val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* defc 'define constant'. Defines a value that is not writable. */
|
||||||
|
Object.defineProperty(Object.prototype, 'defc', {
|
||||||
|
value: function(name, val) {
|
||||||
|
Object.defineProperty(this,name, {
|
||||||
|
value: val,
|
||||||
|
writable:false,
|
||||||
|
enumerable:true,
|
||||||
|
configurable:false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'deflock', {
|
||||||
|
value: function(prop) {
|
||||||
|
Object.defineProperty(this,prop, {configurable:false});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'forEach', {
|
||||||
|
value: function(fn) {
|
||||||
|
for (var key in this)
|
||||||
|
fn(this[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'empty', {
|
||||||
|
get: function() {
|
||||||
|
return Object.keys(this).empty;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'nth', {
|
||||||
|
value: function(x) {
|
||||||
|
if (this.empty || x >= Object.keys(this).length) return null;
|
||||||
|
|
||||||
|
return this[Object.keys(this)[x]];
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Object.prototype, 'findIndex', {
|
||||||
|
value: function(x) {
|
||||||
|
var i = 0;
|
||||||
|
for (var key in this) {
|
||||||
|
if (this[key] === x) return i;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* STRING DEFS */
|
||||||
|
|
||||||
|
Object.defineProperty(String.prototype, 'next', {
|
||||||
|
value: function(char, from) {
|
||||||
|
if (!Array.isArray(char))
|
||||||
|
char = [char];
|
||||||
|
if (from > this.length-1)
|
||||||
|
return -1;
|
||||||
|
else if (!from)
|
||||||
|
from = 0;
|
||||||
|
|
||||||
|
var find = this.slice(from).search(char[0]);
|
||||||
|
|
||||||
|
if (find === -1)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return from + find;
|
||||||
|
|
||||||
|
var i = 0;
|
||||||
|
var c = this.charAt(from+i);
|
||||||
|
while (!char.includes(c)) {
|
||||||
|
i++;
|
||||||
|
if (from+i >this.length-1) return -1;
|
||||||
|
c = this.charAt(from+i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return from+i;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(String.prototype, 'prev', {
|
||||||
|
value: function(char, from, count) {
|
||||||
|
if (from > this.length-1)
|
||||||
|
return -1;
|
||||||
|
else if (!from)
|
||||||
|
from = this.length-1;
|
||||||
|
|
||||||
|
if (!count) count = 0;
|
||||||
|
|
||||||
|
var find = this.slice(0,from).lastIndexOf(char);
|
||||||
|
|
||||||
|
while (count > 1) {
|
||||||
|
find = this.slice(0,find).lastIndexOf(char);
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (find === -1)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return find;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(String.prototype, 'shift', {
|
||||||
|
value: function(n) {
|
||||||
|
if (n === 0) return this.slice();
|
||||||
|
|
||||||
|
if (n > 0)
|
||||||
|
return this.slice(n);
|
||||||
|
|
||||||
|
if (n < 0)
|
||||||
|
return this.slice(0, this.length+n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* ARRAY DEFS */
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'copy', {
|
||||||
|
value: function() {
|
||||||
|
var c = [];
|
||||||
|
|
||||||
|
this.forEach(function(x, i) {
|
||||||
|
c[i] = deep_copy(x);
|
||||||
|
});
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'rotate', {
|
||||||
|
value: function(a) {
|
||||||
|
return Vector.rotate(this, a);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, '$add', {
|
||||||
|
value: function(b) {
|
||||||
|
for (var i = 0; i < this.length; i++) {
|
||||||
|
this[i] += b[i];
|
||||||
|
}
|
||||||
|
}});
|
||||||
|
|
||||||
|
function setelem(n) {
|
||||||
|
return {
|
||||||
|
get: function() { return this[n]; },
|
||||||
|
set: function(x) { this[n] = x; }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function arrsetelem(str, n)
|
||||||
|
{
|
||||||
|
Object.defineProperty(Array.prototype, str, setelem(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'x', setelem(0));
|
||||||
|
Object.defineProperty(Array.prototype, 'y', setelem(1));
|
||||||
|
Object.defineProperty(Array.prototype, 'z', setelem(2));
|
||||||
|
Object.defineProperty(Array.prototype, 'w', setelem(3));
|
||||||
|
arrsetelem('r', 0);
|
||||||
|
arrsetelem('g', 1);
|
||||||
|
arrsetelem('b', 2);
|
||||||
|
arrsetelem('a', 3);
|
||||||
|
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'add', {
|
||||||
|
value: function(b) {
|
||||||
|
var c = [];
|
||||||
|
for (var i = 0; i < this.length; i++) { c[i] = this[i] + b[i]; }
|
||||||
|
return c;
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'newfirst', {
|
||||||
|
value: function(i) {
|
||||||
|
var c = this.slice();
|
||||||
|
if (i >= c.length) return c;
|
||||||
|
|
||||||
|
do {
|
||||||
|
c.push(c.shift());
|
||||||
|
i--;
|
||||||
|
} while (i > 0);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'doubleup', {
|
||||||
|
value: function(n) {
|
||||||
|
var c = [];
|
||||||
|
this.forEach(function(x) {
|
||||||
|
for (var i = 0; i < n; i++)
|
||||||
|
c.push(x);
|
||||||
|
});
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'sub', {
|
||||||
|
value: function(b) {
|
||||||
|
var c = [];
|
||||||
|
for (var i = 0; i < this.length; i++) { c[i] = this[i] - b[i]; }
|
||||||
|
return c;
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'apply', {
|
||||||
|
value: function(fn) {
|
||||||
|
this.forEach(function(x) { x[fn].apply(x); });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'scale', {
|
||||||
|
value: function(s) {
|
||||||
|
return this.map(function(x) { return x*s; });
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'equal', {
|
||||||
|
value: function(b) {
|
||||||
|
if (this.length !== b.length) return false;
|
||||||
|
if (b == null) return false;
|
||||||
|
if (this === b) return true;
|
||||||
|
|
||||||
|
return JSON.stringify(this) === JSON.stringify(b);
|
||||||
|
|
||||||
|
for (var i = 0; i < this.length; i++) {
|
||||||
|
if (!this[i] === b[i])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}});
|
||||||
|
|
||||||
|
function add(x,y) { return x+y; };
|
||||||
|
function mult(x,y) { return x*y; };
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'mapc', {
|
||||||
|
value: function(fn, arr) {
|
||||||
|
return this.map(function(x, i) {
|
||||||
|
return fn(x, arr[i]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'remove', {
|
||||||
|
value: function(b) {
|
||||||
|
var idx = this.indexOf(b);
|
||||||
|
|
||||||
|
if (idx === -1) return false;
|
||||||
|
|
||||||
|
this.splice(idx, 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'set', {
|
||||||
|
value: function(b) {
|
||||||
|
if (this.length !== b.length) return;
|
||||||
|
|
||||||
|
b.forEach(function(val, i) { this[i] = val; }, this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'flat', {
|
||||||
|
value: function() {
|
||||||
|
return [].concat.apply([],this);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'any', {
|
||||||
|
value: function(fn) {
|
||||||
|
var ev = this.every(function(x) {
|
||||||
|
return !fn(x);
|
||||||
|
});
|
||||||
|
return !ev;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Return true if array contains x */
|
||||||
|
/*Object.defineProperty(Array.prototype, 'includes', {
|
||||||
|
value: function(x) {
|
||||||
|
return this.some(e => e === x);
|
||||||
|
}});
|
||||||
|
*/
|
||||||
|
Object.defineProperty(Array.prototype, 'empty', {
|
||||||
|
get: function() { return this.length === 0; },
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'push_unique', {
|
||||||
|
value: function(x) {
|
||||||
|
if (!this.includes(x)) this.push(x);
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'unique', {
|
||||||
|
value: function() {
|
||||||
|
var c = [];
|
||||||
|
this.forEach(function(x) { c.push_unique(x); });
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'findIndex', {
|
||||||
|
value: function(fn) {
|
||||||
|
var idx = -1;
|
||||||
|
this.every(function(x, i) {
|
||||||
|
if (fn(x)) {
|
||||||
|
idx = i;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'find', {
|
||||||
|
value: function(fn) {
|
||||||
|
var ret;
|
||||||
|
|
||||||
|
this.every(function(x) {
|
||||||
|
if (fn(x)) {
|
||||||
|
ret = x;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'last', {
|
||||||
|
get: function() { return this[this.length-1]; },
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'at', {
|
||||||
|
value: function(x) {
|
||||||
|
return x < 0 ? this[this.length+x] : this[x];
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'wrapped', {
|
||||||
|
value: function(x) {
|
||||||
|
var c = this.slice(0, this.length);
|
||||||
|
|
||||||
|
for (var i = 0; i < x; i++)
|
||||||
|
c.push(this[i]);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'wrap_idx', {
|
||||||
|
value: function(x) {
|
||||||
|
while (x >= this.length) {
|
||||||
|
x -= this.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperty(Array.prototype, 'mirrored', {
|
||||||
|
value: function(x) {
|
||||||
|
var c = this.slice(0);
|
||||||
|
if (c.length <= 1) return c;
|
||||||
|
for (var i = c.length-2; i >= 0; i--)
|
||||||
|
c.push(c[i]);
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/* MATH EXTENSIONS */
|
||||||
|
|
||||||
|
Math.clamp = function (x, l, h) { return x > h ? h : x < l ? l : x; }
|
||||||
|
|
||||||
|
Math.lerp = function (s, f, dt) {
|
||||||
|
return s + (Math.clamp(dt, 0, 1) * (f - s));
|
||||||
|
};
|
||||||
|
|
||||||
|
Math.snap = function(val, grid) {
|
||||||
|
if (!grid || grid === 1) return Math.round(val);
|
||||||
|
|
||||||
|
var rem = val%grid;
|
||||||
|
var d = val - rem;
|
||||||
|
var i = Math.round(rem/grid)*grid;
|
||||||
|
return d+i;
|
||||||
|
}
|
||||||
|
|
||||||
|
Math.angledist = function (a1, a2) {
|
||||||
|
var dist = a2 - a1;
|
||||||
|
var wrap = dist >= 0 ? dist+360 : dist-360;
|
||||||
|
wrap %= 360;
|
||||||
|
|
||||||
|
if (Math.abs(dist) < Math.abs(wrap))
|
||||||
|
return dist;
|
||||||
|
|
||||||
|
return wrap;
|
||||||
|
};
|
||||||
|
|
||||||
|
Math.deg2rad = function(deg) { return deg * 0.0174533; }
|
||||||
|
Math.rad2deg = function(rad) { return rad / 0.0174533; }
|
||||||
|
|
||||||
|
/* BOUNDINGBOXES */
|
||||||
|
function cwh2bb(c, wh) {
|
||||||
|
return {
|
||||||
|
t: c.y+wh.y/2,
|
||||||
|
b: c.y-wh.y/2,
|
||||||
|
l: c.x-wh.x/2,
|
||||||
|
r: c.x+wh.x/2
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function points2bb(points) {
|
||||||
|
var b= {t:0,b:0,l:0,r:0};
|
||||||
|
|
||||||
|
points.forEach(function(x) {
|
||||||
|
if (x.y > b.t) b.t = x.y;
|
||||||
|
if (x.y < b.b) b.b = x.y;
|
||||||
|
if (x.x > b.r) b.r = x.x;
|
||||||
|
if (x.x < b.l) b.l = x.x;
|
||||||
|
});
|
||||||
|
|
||||||
|
return b;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function bb2cwh(bb) {
|
||||||
|
if (!bb) return undefined;
|
||||||
|
var cwh = {};
|
||||||
|
|
||||||
|
var w = bb.r - bb.l;
|
||||||
|
var h = bb.t - bb.b;
|
||||||
|
cwh.wh = [w, h];
|
||||||
|
cwh.c = [bb.l + w/2, bb.b + h/2];
|
||||||
|
|
||||||
|
return cwh;
|
||||||
|
};
|
||||||
|
|
||||||
|
function bb_expand(oldbb, x) {
|
||||||
|
if (!oldbb || !x) return;
|
||||||
|
var bb = {};
|
||||||
|
Object.assign(bb, oldbb);
|
||||||
|
|
||||||
|
if (bb.t < x.t) bb.t = x.t;
|
||||||
|
if (bb.r < x.r) bb.r = x.r;
|
||||||
|
if (bb.b > x.b) bb.b = x.b;
|
||||||
|
if (bb.l > x.l) bb.l = x.l;
|
||||||
|
|
||||||
|
return bb;
|
||||||
|
};
|
||||||
|
|
||||||
|
function bb_draw(bb, color) {
|
||||||
|
if (!bb) return;
|
||||||
|
var draw = bb2cwh(bb);
|
||||||
|
draw.wh[0] /= editor.camera.zoom;
|
||||||
|
draw.wh[1] /= editor.camera.zoom;
|
||||||
|
Debug.box(world2screen(draw.c), draw.wh, color);
|
||||||
|
};
|
||||||
|
|
||||||
|
function bb_from_objects(objs) {
|
||||||
|
var bb = objs[0].boundingbox;
|
||||||
|
objs.forEach(function(obj) { bb = bb_expand(bb, obj.boundingbox); });
|
||||||
|
return bb;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* VECTORS */
|
||||||
|
var Vector = {
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
length(v) {
|
||||||
|
var sum = v.reduce(function(acc, val) { return acc + val**2; }, 0);
|
||||||
|
return Math.sqrt(sum);
|
||||||
|
},
|
||||||
|
norm(v) {
|
||||||
|
var len = Vector.length(v);
|
||||||
|
return [v.x/len, v.y/len];
|
||||||
|
|
||||||
|
},
|
||||||
|
make(x, y) {
|
||||||
|
var vec = Object.create(this, {x:x, y:y});
|
||||||
|
},
|
||||||
|
|
||||||
|
project(a, b) {
|
||||||
|
return cmd(85, a, b);
|
||||||
|
},
|
||||||
|
|
||||||
|
dot(a, b) {
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
random() {
|
||||||
|
var vec = [Math.random()-0.5, Math.random()-0.5];
|
||||||
|
return Vector.norm(vec);
|
||||||
|
},
|
||||||
|
|
||||||
|
angle(v) {
|
||||||
|
return Math.atan2(v.y, v.x);
|
||||||
|
},
|
||||||
|
|
||||||
|
rotate(v,angle) {
|
||||||
|
var r = Vector.length(v);
|
||||||
|
var p = Vector.angle(v) + angle;
|
||||||
|
return [r*Math.cos(p), r*Math.sin(p)];
|
||||||
|
},
|
||||||
|
|
||||||
|
equal(v1, v2, tol) {
|
||||||
|
if (!tol)
|
||||||
|
return v1.equal(v2);
|
||||||
|
|
||||||
|
var eql = true;
|
||||||
|
var c = v1.sub(v2);
|
||||||
|
|
||||||
|
c.forEach(function(x) {
|
||||||
|
if (!eql) return;
|
||||||
|
if (Math.abs(x) > tol)
|
||||||
|
eql = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return eql;
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/* POINT ASSISTANCE */
|
||||||
|
|
||||||
|
function points2cm(points)
|
||||||
|
{
|
||||||
|
var x = 0;
|
||||||
|
var y = 0;
|
||||||
|
var n = points.length;
|
||||||
|
points.forEach(function(p) {
|
||||||
|
x = x + p[0];
|
||||||
|
y = y + p[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
return [x/n,y/n];
|
||||||
|
};
|
||||||
|
|
||||||
|
function sortpointsccw(points)
|
||||||
|
{
|
||||||
|
var cm = points2cm(points);
|
||||||
|
var cmpoints = points.map(function(x) { return x.sub(cm); });
|
||||||
|
var ccw = cmpoints.sort(function(a,b) {
|
||||||
|
aatan = Math.atan2(a.y, a.x);
|
||||||
|
batan = Math.atan2(b.y, b.x);
|
||||||
|
return aatan - batan;
|
||||||
|
});
|
||||||
|
|
||||||
|
return ccw.map(function(x) { return x.add(cm); });
|
||||||
|
}
|
657
source/scripts/components.js
Normal file
|
@ -0,0 +1,657 @@
|
||||||
|
var component = {
|
||||||
|
toString() {
|
||||||
|
if ('gameobject' in this)
|
||||||
|
return this.name + " on " + this.gameobject;
|
||||||
|
else
|
||||||
|
return this.name;
|
||||||
|
},
|
||||||
|
name: "component",
|
||||||
|
component: true,
|
||||||
|
set enabled(x) { },
|
||||||
|
get enabled() { },
|
||||||
|
enable() { this.enabled = true; },
|
||||||
|
disable() { this.enabled = false; },
|
||||||
|
|
||||||
|
make(go) { },
|
||||||
|
kill() { Log.info("Kill not created for this component yet"); },
|
||||||
|
gui() { },
|
||||||
|
gizmo() { },
|
||||||
|
|
||||||
|
prepare_center() {},
|
||||||
|
finish_center() {},
|
||||||
|
clone(spec) {
|
||||||
|
return clone(this, spec);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var sprite = clone(component, {
|
||||||
|
name: "sprite",
|
||||||
|
path: "",
|
||||||
|
_pos: [0, 0],
|
||||||
|
get layer() {
|
||||||
|
if (!this.gameobject)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return this.gameobject.draw_layer;
|
||||||
|
},
|
||||||
|
|
||||||
|
get pos() { return this._pos; },
|
||||||
|
set pos(x) {
|
||||||
|
this._pos = x;
|
||||||
|
this.sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
get boundingbox() {
|
||||||
|
if (!this.gameobject) return null;
|
||||||
|
var dim = cmd(64, this.path);
|
||||||
|
dim = dim.scale(this.gameobject.scale);
|
||||||
|
var realpos = this.pos.copy();
|
||||||
|
realpos.x *= dim.x;
|
||||||
|
realpos.y *= dim.y;
|
||||||
|
realpos.x += (dim.x/2);
|
||||||
|
realpos.y += (dim.y/2);
|
||||||
|
return cwh2bb(realpos, dim);
|
||||||
|
},
|
||||||
|
|
||||||
|
set asset(x) {
|
||||||
|
if (!x) return;
|
||||||
|
if (!x.endsWith(".png")) {
|
||||||
|
Log.error("Can't set texture to a non image.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.path = x;
|
||||||
|
Log.info("path is now " + x);
|
||||||
|
this.sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
_enabled: true,
|
||||||
|
set enabled(x) { this._enabled = x; cmd(20, this.id, x); },
|
||||||
|
get enabled() { return this._enabled; return cmd(21, this.id); },
|
||||||
|
get visible() { return this.enabled; },
|
||||||
|
set visible(x) { this.enabled = x; },
|
||||||
|
|
||||||
|
_angle: 0,
|
||||||
|
get angle() { return this._angle; },
|
||||||
|
set angle(x) {
|
||||||
|
this._angle = x;
|
||||||
|
sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
make(go) {
|
||||||
|
var sprite = clone(this);
|
||||||
|
Object.defineProperty(sprite, 'id', {value:make_sprite(go,this.path,this.pos)});
|
||||||
|
sprite.sync();
|
||||||
|
return sprite;
|
||||||
|
},
|
||||||
|
|
||||||
|
rect: {s0:0, s1: 1, t0: 0, t1: 1},
|
||||||
|
|
||||||
|
sync() {
|
||||||
|
if (!this.hasOwn('id')) return;
|
||||||
|
cmd(60, this.id, this.layer);
|
||||||
|
cmd(37, this.id, this.pos);
|
||||||
|
cmd(12, this.id, this.path, this.rect);
|
||||||
|
},
|
||||||
|
|
||||||
|
load_img(img) {
|
||||||
|
cmd(12, this.id, img);
|
||||||
|
},
|
||||||
|
|
||||||
|
kill() {
|
||||||
|
cmd(9, this.id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/* Container to play sprites and anim2ds */
|
||||||
|
var char2d = clone(sprite, {
|
||||||
|
clone(anims) {
|
||||||
|
var char = clone(this);
|
||||||
|
char.anims = anims;
|
||||||
|
return char;
|
||||||
|
},
|
||||||
|
|
||||||
|
name: "char 2d",
|
||||||
|
|
||||||
|
frame2rect(frames, frame) {
|
||||||
|
var rect = {s0:0,s1:1,t0:0,t1:1};
|
||||||
|
|
||||||
|
var frameslice = 1/frames;
|
||||||
|
rect.s0 = frameslice*frame;
|
||||||
|
rect.s1 = frameslice*(frame+1);
|
||||||
|
return rect;
|
||||||
|
},
|
||||||
|
|
||||||
|
make(go) {
|
||||||
|
var char = clone(this);
|
||||||
|
char.curplaying = char.anims.array()[0];
|
||||||
|
Object.defineProperty(char, 'id', {value:make_sprite(go,this.path,this.pos)});
|
||||||
|
char.frame = 0;
|
||||||
|
char.timer = timer.make(char.advance, 1/char.curplaying.fps, char);
|
||||||
|
char.timer.loop = true;
|
||||||
|
char.rect = char.frame2rect(char.curplaying.frames, char.frame);
|
||||||
|
char.setsprite();
|
||||||
|
return char;
|
||||||
|
},
|
||||||
|
|
||||||
|
frame: 0,
|
||||||
|
|
||||||
|
play(name) {
|
||||||
|
if (!(name in this.anims)) {
|
||||||
|
Log.info("Can't find an animation named " + name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.curplaying === this.anims[name]) return;
|
||||||
|
|
||||||
|
this.curplaying = this.anims[name];
|
||||||
|
this.timer.time = 1/this.curplaying.fps;
|
||||||
|
this.timer.start();
|
||||||
|
this.frame = 0;
|
||||||
|
this.setsprite();
|
||||||
|
},
|
||||||
|
|
||||||
|
setsprite() {
|
||||||
|
this.path = this.curplaying.path;
|
||||||
|
this.rect = this.frame2rect(this.curplaying.frames, this.frame);
|
||||||
|
cmd(12, this.id, this.path, this.rect);
|
||||||
|
},
|
||||||
|
|
||||||
|
advance() {
|
||||||
|
this.frame = (this.frame + 1) % this.curplaying.frames;
|
||||||
|
this.setsprite();
|
||||||
|
},
|
||||||
|
|
||||||
|
devance() {
|
||||||
|
this.frame = (this.frame - 1);
|
||||||
|
if (this.frame === -1) this.frame = this.curplaying.frames-1;
|
||||||
|
this.setsprite();
|
||||||
|
},
|
||||||
|
|
||||||
|
pause() {
|
||||||
|
this.timer.pause();
|
||||||
|
},
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.frame = 0;
|
||||||
|
this.timer.stop();
|
||||||
|
this.setsprite();
|
||||||
|
},
|
||||||
|
|
||||||
|
kill() {
|
||||||
|
this.timer.kill();
|
||||||
|
cmd(9, this.id);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
|
||||||
|
var collider2d = clone(component, {
|
||||||
|
name: "collider 2d",
|
||||||
|
|
||||||
|
_sensor: false,
|
||||||
|
set sensor(x) {
|
||||||
|
this._sensor = x;
|
||||||
|
if (this.shape)
|
||||||
|
cmd(18, this.shape, x);
|
||||||
|
},
|
||||||
|
get sensor() { return this._sensor; },
|
||||||
|
|
||||||
|
input_s_pressed() {
|
||||||
|
if (!Keys.alt()) return;
|
||||||
|
|
||||||
|
this.sensor = !this.sensor;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_t_pressed() {
|
||||||
|
if (!Keys.alt()) return;
|
||||||
|
|
||||||
|
this.enabled = !this.enabled;
|
||||||
|
},
|
||||||
|
|
||||||
|
coll_sync() {
|
||||||
|
cmd(18, this.shape, this.sensor);
|
||||||
|
},
|
||||||
|
|
||||||
|
_enabled: true,
|
||||||
|
set enabled(x) {this._enabled = x; if (this.id) cmd(22, this.id, x); },
|
||||||
|
get enabled() { return this._enabled; },
|
||||||
|
kill() {}, /* No killing is necessary - it is done through the gameobject's kill */
|
||||||
|
|
||||||
|
register_hit(fn, obj) {
|
||||||
|
register_collide(1, fn, obj, this.gameobject.body, this.shape);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
var polygon2d = clone(collider2d, {
|
||||||
|
name: "polygon 2d",
|
||||||
|
points: [],
|
||||||
|
help: "Ctrl-click Add a point\nShift-click Remove a point",
|
||||||
|
clone(spec) {
|
||||||
|
var obj = Object.create(this);
|
||||||
|
obj.points = this.points.copy();
|
||||||
|
Object.assign(obj, spec);
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
make(go) {
|
||||||
|
var poly = Object.create(this);
|
||||||
|
Object.assign(poly, make_poly2d(go, this.points));
|
||||||
|
Object.defineProperty(poly, 'id', {enumerable:false});
|
||||||
|
Object.defineProperty(poly, 'shape', {enumerable:false});
|
||||||
|
|
||||||
|
return poly;
|
||||||
|
},
|
||||||
|
|
||||||
|
get boundingbox() {
|
||||||
|
if (!this.gameobject) return null;
|
||||||
|
var scaledpoints = [];
|
||||||
|
this.points.forEach(function(x) { scaledpoints.push(x.scale(this.gameobject.scale)); }, this);
|
||||||
|
return points2bb(scaledpoints);
|
||||||
|
},
|
||||||
|
|
||||||
|
input_f10_pressed() {
|
||||||
|
this.points = sortpointsccw(this.points);
|
||||||
|
},
|
||||||
|
|
||||||
|
sync() {
|
||||||
|
if (!this.id) return;
|
||||||
|
cmd_poly2d(0, this.id, this.spoints);
|
||||||
|
this.coll_sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
input_b_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
|
||||||
|
this.points = this.spoints;
|
||||||
|
this.mirrorx = false;
|
||||||
|
this.mirrory = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
get spoints() {
|
||||||
|
var spoints = this.points.slice();
|
||||||
|
|
||||||
|
if (this.mirrorx) {
|
||||||
|
spoints.forEach(function(x) {
|
||||||
|
var newpoint = x.slice();
|
||||||
|
newpoint.x = -newpoint.x;
|
||||||
|
spoints.push(newpoint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mirrory) {
|
||||||
|
spoints.forEach(function(x) {
|
||||||
|
var newpoint = x.slice();
|
||||||
|
newpoint.y = -newpoint.y;
|
||||||
|
spoints.push(newpoint);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return spoints;
|
||||||
|
},
|
||||||
|
|
||||||
|
gizmo() {
|
||||||
|
if (!this.hasOwn('points')) this.points = this.__proto__.points.copy();
|
||||||
|
|
||||||
|
this.spoints.forEach(function(x) {
|
||||||
|
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.points.forEach(function(x, i) {
|
||||||
|
Debug.numbered_point(this.gameobject.this2world(x), i);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
|
||||||
|
this.sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
input_lmouse_pressed() {
|
||||||
|
if (Keys.ctrl()) {
|
||||||
|
this.points.push(this.gameobject.world2this(Mouse.worldpos));
|
||||||
|
} else if (Keys.shift()) {
|
||||||
|
var idx = grab_from_points(screen2world(Mouse.pos), this.points.map(this.gameobject.this2world,this.gameobject), 25);
|
||||||
|
if (idx === -1) return;
|
||||||
|
this.points.splice(idx, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pick(pos) {
|
||||||
|
return Gizmos.pick_gameobject_points(pos, this.gameobject, this.points);
|
||||||
|
},
|
||||||
|
|
||||||
|
query() {
|
||||||
|
return cmd(80, this.shape);
|
||||||
|
},
|
||||||
|
|
||||||
|
mirrorx: false,
|
||||||
|
mirrory: false,
|
||||||
|
|
||||||
|
input_m_pressed() {
|
||||||
|
if (Keys.ctrl())
|
||||||
|
this.mirrory = !this.mirrory;
|
||||||
|
else
|
||||||
|
this.mirrorx = !this.mirrorx;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var bucket = clone(collider2d, {
|
||||||
|
name: "bucket",
|
||||||
|
help: "Ctrl-click Add a point\nShift-click Remove a point\n+,- Increase/decrease spline segs\nCtrl-+,- Inc/dec spline degrees\nCtrl-b,v Inc/dec spline thickness",
|
||||||
|
clone(spec) {
|
||||||
|
var obj = Object.create(this);
|
||||||
|
obj.cpoints = this.cpoints.copy();
|
||||||
|
dainty_assign(obj, spec);
|
||||||
|
return obj;
|
||||||
|
},
|
||||||
|
|
||||||
|
cpoints:[],
|
||||||
|
degrees:2,
|
||||||
|
dimensions:2,
|
||||||
|
/* open: 0
|
||||||
|
clamped: 1
|
||||||
|
beziers: 2
|
||||||
|
looped: 3
|
||||||
|
*/
|
||||||
|
type: 3,
|
||||||
|
|
||||||
|
get boundingbox() {
|
||||||
|
if (!this.gameobject) return null;
|
||||||
|
var scaledpoints = [];
|
||||||
|
this.points.forEach(function(x) { scaledpoints.push(x.scale(this.gameobject.scale)); }, this);
|
||||||
|
return points2bb(scaledpoints);
|
||||||
|
},
|
||||||
|
|
||||||
|
mirrorx: false,
|
||||||
|
mirrory: false,
|
||||||
|
|
||||||
|
input_m_pressed() {
|
||||||
|
if (Keys.ctrl()) {
|
||||||
|
this.mirrory = !this.mirrory;
|
||||||
|
} else {
|
||||||
|
this.mirrorx = !this.mirrorx;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
hollow: false,
|
||||||
|
input_h_pressed() {
|
||||||
|
this.hollow = !this.hollow;
|
||||||
|
},
|
||||||
|
|
||||||
|
get spoints() {
|
||||||
|
var spoints = this.cpoints.slice();
|
||||||
|
|
||||||
|
if (this.mirrorx) {
|
||||||
|
for (var i = spoints.length-1; i >= 0; i--) {
|
||||||
|
var newpoint = spoints[i].slice();
|
||||||
|
newpoint.x = -newpoint.x;
|
||||||
|
spoints.push(newpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.mirrory) {
|
||||||
|
for (var i = spoints.length-1; i >= 0; i--) {
|
||||||
|
var newpoint = spoints[i].slice();
|
||||||
|
newpoint.y = -newpoint.y;
|
||||||
|
spoints.push(newpoint);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return spoints;
|
||||||
|
|
||||||
|
if (this.hollow) {
|
||||||
|
var hpoints = [];
|
||||||
|
var inflatep = inflate_cpv(spoints, spoints.length, this.hollowt);
|
||||||
|
inflatep[0].slice().reverse().forEach(function(x) { hpoints.push(x); });
|
||||||
|
|
||||||
|
inflatep[1].forEach(function(x) { hpoints.push(x); });
|
||||||
|
return hpoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
return spoints;
|
||||||
|
},
|
||||||
|
|
||||||
|
hollowt: 0,
|
||||||
|
|
||||||
|
input_g_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
this.hollowt--;
|
||||||
|
if (this.hollowt < 0) this.hollowt = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_f_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
this.hollowt++;
|
||||||
|
},
|
||||||
|
|
||||||
|
sample(n) {
|
||||||
|
var spoints = this.spoints;
|
||||||
|
|
||||||
|
this.degrees = Math.clamp(this.degrees, 1, spoints.length-1);
|
||||||
|
|
||||||
|
if (spoints.length === 2)
|
||||||
|
return spoints;
|
||||||
|
if (spoints.length < 2)
|
||||||
|
return [];
|
||||||
|
if (this.degrees < 2) {
|
||||||
|
if (this.type === 3)
|
||||||
|
return spoints.wrapped(1);
|
||||||
|
|
||||||
|
return spoints;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
order = degrees+1
|
||||||
|
knots = spoints.length + order
|
||||||
|
assert knots%order != 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (this.type === 3)
|
||||||
|
return spline_cmd(0, this.degrees, this.dimensions, 0, spoints.wrapped(this.degrees), n);
|
||||||
|
|
||||||
|
return spline_cmd(0, this.degrees, this.dimensions, this.type, spoints, n);
|
||||||
|
},
|
||||||
|
|
||||||
|
samples: 10,
|
||||||
|
points:[],
|
||||||
|
|
||||||
|
make(go) {
|
||||||
|
var edge = Object.create(this);
|
||||||
|
Object.assign(edge, make_edge2d(go, this.points, this.thickness));
|
||||||
|
Object.defineProperty(edge, 'id', {enumerable:false});
|
||||||
|
Object.defineProperty(edge, 'shape', {enumerable:false});
|
||||||
|
edge.defn('points', []);
|
||||||
|
// Object.defineProperty(edge, 'points', {enumerable:false});
|
||||||
|
edge.sync();
|
||||||
|
return edge;
|
||||||
|
},
|
||||||
|
|
||||||
|
sync() {
|
||||||
|
if (!this.gameobject) return;
|
||||||
|
this.points = this.sample(this.samples);
|
||||||
|
cmd_edge2d(0, this.id, this.points);
|
||||||
|
cmd_edge2d(1, this.id, this._thickness * this.gameobject.scale);
|
||||||
|
this.coll_sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
gizmo() {
|
||||||
|
if (!this.hasOwn('cpoints')) this.cpoints = this.__proto__.cpoints.copy();
|
||||||
|
|
||||||
|
this.spoints.forEach(function(x) {
|
||||||
|
Debug.point(world2screen(this.gameobject.this2world(x)), 3, Color.green);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.cpoints.forEach(function(x, i) {
|
||||||
|
Debug.numbered_point(this.gameobject.this2world(x), i);
|
||||||
|
}, this);
|
||||||
|
|
||||||
|
this.sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
_thickness:0, /* Number of pixels out the edge is */
|
||||||
|
get thickness() { return this._thickness; },
|
||||||
|
set thickness(x) {
|
||||||
|
this._thickness = Math.max(x, 0);
|
||||||
|
cmd_edge2d(1, this.id, this._thickness);
|
||||||
|
},
|
||||||
|
|
||||||
|
input_v_pressrep() {
|
||||||
|
if (!Keys.alt()) return;
|
||||||
|
this.thickness--;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_b_pressrep() {
|
||||||
|
if (Keys.alt()) {
|
||||||
|
this.thickness++;
|
||||||
|
} else if (Keys.ctrl()) {
|
||||||
|
this.cpoints = this.spoints;
|
||||||
|
this.mirrorx = false;
|
||||||
|
this.mirrory = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
finish_center(change) {
|
||||||
|
this.cpoints = this.cpoints.map(function(x) { return x.sub(change); });
|
||||||
|
this.sync();
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
input_plus_pressrep() {
|
||||||
|
if (Keys.ctrl())
|
||||||
|
this.degrees++;
|
||||||
|
else
|
||||||
|
this.samples += 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_minus_pressrep() {
|
||||||
|
if (Keys.ctrl())
|
||||||
|
this.degrees--;
|
||||||
|
else {
|
||||||
|
this.samples -= 1;
|
||||||
|
if (this.samples < 1) this.samples = 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
input_r_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
|
||||||
|
this.cpoints = this.cpoints.reverse();
|
||||||
|
},
|
||||||
|
|
||||||
|
input_l_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
this.type = 3;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_c_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
this.type = 1;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_o_pressed() {
|
||||||
|
if (!Keys.ctrl()) return;
|
||||||
|
this.type = 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_lmouse_pressed() {
|
||||||
|
if (Keys.ctrl()) {
|
||||||
|
if (Keys.alt()) {
|
||||||
|
var idx = grab_from_points(Mouse.worldpos, this.cpoints.map(this.gameobject.world2this,this.gameobject), 25);
|
||||||
|
if (idx === -1) return;
|
||||||
|
|
||||||
|
this.cpoints = this.cpoints.newfirst(idx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var idx = 0;
|
||||||
|
|
||||||
|
if (this.cpoints.length >= 2) {
|
||||||
|
idx = cmd(59, screen2world(Mouse.pos).sub(this.gameobject.pos), this.cpoints, 1000);
|
||||||
|
if (idx === -1) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx === this.cpoints.length)
|
||||||
|
this.cpoints.push(this.gameobject.world2this(screen2world(Mouse.pos)));
|
||||||
|
else
|
||||||
|
this.cpoints.splice(idx, 0, this.gameobject.world2this(screen2world(Mouse.pos)));
|
||||||
|
return;
|
||||||
|
} else if (Keys.shift()) {
|
||||||
|
var idx = grab_from_points(screen2world(Mouse.pos), this.cpoints.map(function(x) {return x.add(this.gameobject.pos); }, this), 25);
|
||||||
|
if (idx === -1) return;
|
||||||
|
|
||||||
|
this.cpoints.splice(idx, 1);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
pick(pos) { return Gizmos.pick_gameobject_points(pos, this.gameobject, this.cpoints); },
|
||||||
|
|
||||||
|
input_lbracket_pressrep() {
|
||||||
|
var np = [];
|
||||||
|
|
||||||
|
this.cpoints.forEach(function(c) {
|
||||||
|
np.push(Vector.rotate(c, Math.deg2rad(-1)));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cpoints = np;
|
||||||
|
},
|
||||||
|
|
||||||
|
input_rbracket_pressrep() {
|
||||||
|
var np = [];
|
||||||
|
|
||||||
|
this.cpoints.forEach(function(c) {
|
||||||
|
np.push(Vector.rotate(c, Math.deg2rad(1)));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.cpoints = np;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
var circle2d = clone(collider2d, {
|
||||||
|
name: "circle 2d",
|
||||||
|
get radius() {
|
||||||
|
return this.rradius;
|
||||||
|
},
|
||||||
|
rradius: 10,
|
||||||
|
set radius(x) {
|
||||||
|
this.rradius = x;
|
||||||
|
cmd_circle2d(0, this.id, this.rradius);
|
||||||
|
},
|
||||||
|
|
||||||
|
get boundingbox() {
|
||||||
|
if (!this.gameobject) return null;
|
||||||
|
var radius = this.radius*2*this.gameobject.scale;
|
||||||
|
return cwh2bb(this.offset.scale(this.gameobject.scale), [radius, radius]);
|
||||||
|
},
|
||||||
|
|
||||||
|
get scale() { return this.radius; },
|
||||||
|
set scale(x) { this.radius = x; },
|
||||||
|
|
||||||
|
ofset: [0,0],
|
||||||
|
get offset() { return this.ofset; },
|
||||||
|
set offset(x) { this.ofset = x; cmd_circle2d(1, this.id, this.ofset); },
|
||||||
|
|
||||||
|
get pos() { return this.ofset; },
|
||||||
|
set pos(x) { this.offset = x; },
|
||||||
|
|
||||||
|
make(go) {
|
||||||
|
var circle = clone(this);
|
||||||
|
var circ = make_circle2d(go, circle.radius, circle.offset);
|
||||||
|
Object.assign(circle, circ);
|
||||||
|
Object.defineProperty(circle, 'id', {enumerable:false});
|
||||||
|
Object.defineProperty(circle, 'shape', {enumerable:false});
|
||||||
|
return circle;
|
||||||
|
},
|
||||||
|
|
||||||
|
gui() {
|
||||||
|
Nuke.newline();
|
||||||
|
Nuke.label("circle2d");
|
||||||
|
this.radius = Nuke.pprop("Radius", this.radius);
|
||||||
|
this.offset = Nuke.pprop("offset", this.offset);
|
||||||
|
},
|
||||||
|
|
||||||
|
sync() {
|
||||||
|
cmd_circle2d(0, this.id, this.rradius);
|
||||||
|
cmd_circle2d(-1, this.id);
|
||||||
|
this.coll_sync();
|
||||||
|
},
|
||||||
|
});
|
207
source/scripts/debug.js
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
var Gizmos = {
|
||||||
|
pick_gameobject_points(worldpos, gameobject, points) {
|
||||||
|
var idx = grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
||||||
|
if (idx === -1) return null;
|
||||||
|
return points[idx];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var Debug = {
|
||||||
|
draw_grid(width, span) {
|
||||||
|
cmd(47, width, span);
|
||||||
|
},
|
||||||
|
|
||||||
|
point(pos, size, color) {
|
||||||
|
color = color ? color : Color.blue;
|
||||||
|
cmd(51, pos, size,color);
|
||||||
|
},
|
||||||
|
|
||||||
|
arrow(start, end, color, capsize) {
|
||||||
|
color = color ? color : Color.red;
|
||||||
|
if (!capsize)
|
||||||
|
capsize = 4;
|
||||||
|
cmd(81, start, end, color, capsize);
|
||||||
|
},
|
||||||
|
|
||||||
|
box(pos, wh, color) {
|
||||||
|
color = color ? color : Color.white;
|
||||||
|
cmd(53, pos, wh, color);
|
||||||
|
},
|
||||||
|
|
||||||
|
numbered_point(pos, n) {
|
||||||
|
Debug.point(world2screen(pos), 3);
|
||||||
|
gui_text(n, world2screen(pos).add([0,4]), 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
phys_drawing: false,
|
||||||
|
draw_phys(on) {
|
||||||
|
this.phys_drawing = on;
|
||||||
|
cmd(4, this.phys_drawing);
|
||||||
|
},
|
||||||
|
|
||||||
|
draw_obj_phys(obj) {
|
||||||
|
cmd(82, obj.body);
|
||||||
|
},
|
||||||
|
|
||||||
|
register_call(fn, obj) {
|
||||||
|
register_debug(fn,obj);
|
||||||
|
},
|
||||||
|
|
||||||
|
print_callstack() {
|
||||||
|
for (var i = -3;; i--) {
|
||||||
|
var t = Duktape.act(i);
|
||||||
|
if (!t) break;
|
||||||
|
var file = t.function ? t.function.fileName : "";
|
||||||
|
var line = t.lineNumber;
|
||||||
|
Log.info(file + ":" + line);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
line(points, color, type) {
|
||||||
|
if (!type)
|
||||||
|
type = 0;
|
||||||
|
|
||||||
|
if (!color)
|
||||||
|
color = Color.white;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case 0:
|
||||||
|
cmd(83, points, color);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
var Gizmos = {
|
||||||
|
pick_gameobject_points(worldpos, gameobject, points) {
|
||||||
|
var idx = grab_from_points(worldpos, points.map(gameobject.this2world,gameobject), 25);
|
||||||
|
if (idx === -1) return null;
|
||||||
|
return points[idx];
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var Nuke = {
|
||||||
|
newline(cols) { nuke(3, cols ? cols : 1); },
|
||||||
|
newrow(height) { nuke(13,height); },
|
||||||
|
|
||||||
|
wins: {},
|
||||||
|
curwin:"",
|
||||||
|
|
||||||
|
prop(str, v) {
|
||||||
|
var ret = nuke(2, str, v);
|
||||||
|
if (Number.isFinite(ret)) return ret;
|
||||||
|
return 0;
|
||||||
|
},
|
||||||
|
|
||||||
|
treeid: 0,
|
||||||
|
|
||||||
|
tree(str) { var on = nuke(11, str, this.treeid); this.treeid++; return on; },
|
||||||
|
tree_pop() { nuke(12);},
|
||||||
|
|
||||||
|
prop_num(str, num) { return nuke(2, str, num, -1e10, 1e10, 0.01); },
|
||||||
|
prop_bool(str, val) { return nuke(4, str, val); },
|
||||||
|
checkbox(val) { return nuke(4,"",val); },
|
||||||
|
label(str) { nuke(5, str); },
|
||||||
|
textbox(str) { return nuke(7, str); },
|
||||||
|
scrolltext(str) { nuke(14,str); },
|
||||||
|
|
||||||
|
defaultrect: { x:10, y:10, w:400, h:600 },
|
||||||
|
window(name) {
|
||||||
|
this.curwin = name;
|
||||||
|
var rect;
|
||||||
|
if (name in this.wins)
|
||||||
|
rect = this.wins[name];
|
||||||
|
else
|
||||||
|
rect = { x:10, y:10, w:400, h:600 };
|
||||||
|
|
||||||
|
nuke(0, name, rect);
|
||||||
|
},
|
||||||
|
button(name) { return nuke(6, name); },
|
||||||
|
radio(name, val, cmp) { return nuke(9, name, val, cmp); },
|
||||||
|
img(path) { nuke(8, path); },
|
||||||
|
end() {
|
||||||
|
this.wins[this.curwin] = nuke(10);
|
||||||
|
this.treeid = 0;
|
||||||
|
nuke(1);
|
||||||
|
},
|
||||||
|
|
||||||
|
pprop(str, p, nonew) {
|
||||||
|
switch(typeof p) {
|
||||||
|
case 'number':
|
||||||
|
if (!nonew) Nuke.newline();
|
||||||
|
return Nuke.prop_num(str, p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'boolean':
|
||||||
|
if (!nonew) Nuke.newline();
|
||||||
|
return Nuke.prop_bool(str, p);
|
||||||
|
|
||||||
|
case 'object':
|
||||||
|
if (Array.isArray(p)) {
|
||||||
|
var arr = [];
|
||||||
|
Nuke.newline(p.length+1);
|
||||||
|
Nuke.label(str);
|
||||||
|
arr[0] = Nuke.pprop("#x", p[0], true);
|
||||||
|
arr[1] = Nuke.pprop("#y", p[1], true);
|
||||||
|
return arr;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (!nonew)Nuke.newline(2);
|
||||||
|
Nuke.label(str);
|
||||||
|
Nuke.label(p);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'string':
|
||||||
|
if (!nonew) Nuke.newline();
|
||||||
|
Nuke.label(str);
|
||||||
|
return Nuke.textbox(p);
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (!nonew) Nuke.newline(2);
|
||||||
|
Nuke.label(str);
|
||||||
|
Nuke.label(p);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
Object.defineProperty(Nuke, "curwin", {enumerable:false});
|
||||||
|
Object.defineProperty(Nuke, "defaultrect", {enumerable:false});
|
||||||
|
|
||||||
|
|
||||||
|
var Log = {
|
||||||
|
print(msg, lvl) {
|
||||||
|
var lg;
|
||||||
|
if (typeof msg === 'object') {
|
||||||
|
lg = JSON.stringify(msg, null, 2);
|
||||||
|
} else {
|
||||||
|
lg = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
var stack = (new Error()).stack;
|
||||||
|
var n = stack.next('\n',0)+1;
|
||||||
|
n = stack.next('\n', n)+1;
|
||||||
|
var nnn = stack.slice(n);
|
||||||
|
var fmatch = nnn.match(/\(.*\:/);
|
||||||
|
var file = fmatch ? fmatch[0].shift(1).shift(-1) : "nofile";
|
||||||
|
var lmatch = nnn.match(/\:\d*\)/);
|
||||||
|
var line = lmatch ? lmatch[0].shift(1).shift(-1) : "0";
|
||||||
|
|
||||||
|
yughlog(lvl, lg, file, line);
|
||||||
|
},
|
||||||
|
|
||||||
|
info(msg) {
|
||||||
|
this.print(msg, 0);
|
||||||
|
},
|
||||||
|
|
||||||
|
warn(msg) {
|
||||||
|
this.print(msg, 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
error(msg) {
|
||||||
|
this.print(msg, 2);
|
||||||
|
},
|
||||||
|
|
||||||
|
};
|
||||||
|
|
141
source/scripts/diff.js
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
function deep_copy(from) {
|
||||||
|
if (typeof from !== 'object')
|
||||||
|
return from;
|
||||||
|
|
||||||
|
if (Array.isArray(from)) {
|
||||||
|
var c = [];
|
||||||
|
from.forEach(function(x,i) { c[i] = deep_copy(x); });
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
var obj = {};
|
||||||
|
for (var key in from)
|
||||||
|
obj[key] = deep_copy(from[key]);
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
var walk_up_get_prop = function(obj, prop, endobj) {
|
||||||
|
var props = [];
|
||||||
|
var cur = obj;
|
||||||
|
while (cur !== Object.prototype) {
|
||||||
|
if (cur.hasOwn(prop))
|
||||||
|
props.push(cur[prop]);
|
||||||
|
|
||||||
|
cur = cur.__proto__;
|
||||||
|
}
|
||||||
|
|
||||||
|
return props;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function complete_assign(target, source) {
|
||||||
|
var descriptors = {};
|
||||||
|
var assigns = {};
|
||||||
|
if (typeof source === 'undefined') return target;
|
||||||
|
Object.keys(source).forEach(function (k) {
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(source, k);
|
||||||
|
|
||||||
|
if (desc.value) {
|
||||||
|
if (typeof desc.value === 'object' && desc.value.hasOwn('value'))
|
||||||
|
descriptors[k] = desc.value;
|
||||||
|
else
|
||||||
|
assigns[k] = desc.value;
|
||||||
|
} else
|
||||||
|
descriptors[k] = desc;
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperties(target, descriptors);
|
||||||
|
Object.assign(target, assigns);
|
||||||
|
return target;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Assigns properties from source to target, only if they exist in target */
|
||||||
|
function dainty_assign(target, source)
|
||||||
|
{
|
||||||
|
for (var key in source) {
|
||||||
|
if (typeof source[key] === 'function') {
|
||||||
|
target[key] = source[key];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!(key in target)) continue;
|
||||||
|
if (Array.isArray(target[key]))
|
||||||
|
target[key] = source[key];
|
||||||
|
else if (typeof target[key] === 'object')
|
||||||
|
dainty_assign(target[key], source[key]);
|
||||||
|
else
|
||||||
|
target[key] = source[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Deeply remove source keys from target, not removing objects */
|
||||||
|
function unmerge(target, source) {
|
||||||
|
for (var key in source) {
|
||||||
|
if (typeof source[key] === 'object' && !Array.isArray(source[key]))
|
||||||
|
unmerge(target[key], source[key]);
|
||||||
|
else
|
||||||
|
delete target[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Deeply merge two objects, not clobbering objects on target with objects on source */
|
||||||
|
function deep_merge(target, source)
|
||||||
|
{
|
||||||
|
for (var key in source) {
|
||||||
|
if (typeof source[key] === 'object' && !Array.isArray(source[key]))
|
||||||
|
deep_merge(target[key], source[key]);
|
||||||
|
else
|
||||||
|
target[key] = source[key];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function equal(x,y) {
|
||||||
|
if (typeof x === 'object')
|
||||||
|
for (var key in x)
|
||||||
|
return equal(x[key],y[key]);
|
||||||
|
|
||||||
|
return x === y;
|
||||||
|
};
|
||||||
|
|
||||||
|
function diffassign(target, from) {
|
||||||
|
if (from.empty) return;
|
||||||
|
|
||||||
|
for (var e in from) {
|
||||||
|
if (typeof from[e] === 'object') {
|
||||||
|
if (!target.hasOwnProperty(e))
|
||||||
|
target[e] = from[e];
|
||||||
|
else
|
||||||
|
diffassign(target[e], from[e]);
|
||||||
|
} else {
|
||||||
|
if (from[e] === "DELETE") {
|
||||||
|
delete target[e];
|
||||||
|
} else {
|
||||||
|
target[e] = from[e];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function diff(from, to) {
|
||||||
|
var obj = {};
|
||||||
|
|
||||||
|
for (var e in to) {
|
||||||
|
if (typeof to[e] === 'object' && from.hasOwnProperty(e)) {
|
||||||
|
obj[e] = diff(from[e], to[e]);
|
||||||
|
if (obj[e].empty)
|
||||||
|
delete obj[e];
|
||||||
|
} else {
|
||||||
|
if (from[e] !== to[e])
|
||||||
|
obj[e] = to[e];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var e in from) {
|
||||||
|
if (!to.hasOwnProperty(e))
|
||||||
|
obj[e] = "DELETE";
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj;
|
||||||
|
};
|