stability

This commit is contained in:
John Alanbrook 2023-05-29 15:47:30 +00:00
parent 591f48c703
commit 9cb53b04af
16 changed files with 248 additions and 159 deletions

View file

@ -50,44 +50,3 @@ 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
explicit path to their associated image file.
.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
.Draw functions
draw()
Called during lower rendering
gui()
Called for screen space over the top rendering
debug()
Called during a debug phase; Will not be called when debug draw is off

View file

@ -1,3 +1,46 @@
# Yugine Scripting
Scripting is done with mruby. MAY CHANGE.
Scripting is done with JS.
Load up objects with functions that are called back at specific times.
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
.Draw functions
draw()
Called during lower rendering
gui()
Called for screen space over the top rendering
debug()
Called during a debug phase; Will not be called when debug draw is off

View file

@ -164,6 +164,8 @@ void phys2d_init()
{
space = cpSpaceNew();
cpSpaceSetSleepTimeThreshold(space, 1);
cpSpaceSetCollisionSlop(space, 0.01);
cpSpaceSetCollisionBias(space, cpfpow(1.0-0.5, 165.f));
}
void phys2d_set_gravity(cpVect v) {
@ -613,6 +615,7 @@ void duk_call_phys_cb(cpVect norm, struct callee c, int hit, cpArbiter *arb) {
JS_SetPropertyStr(js, obj, "sensor", JS_NewBool(js, cpShapeGetSensor(shape2)));
JS_SetPropertyStr(js, obj, "velocity", vec2js(cpArbiterGetSurfaceVelocity(arb)));
JS_SetPropertyStr(js, obj, "pos", vec2js(cpArbiterGetPointA(arb, 0)));
JS_SetPropertyStr(js,obj,"depth", num2js(cpArbiterGetDepth(arb,0)));
JS_SetPropertyStr(js, obj, "id", JS_NewInt32(js,hit));
JS_SetPropertyStr(js,obj,"obj", JS_DupValue(js,id2go(hit)->ref));

View file

@ -81,7 +81,6 @@ static struct circle_vertex circle_b[v_amt];
void debug_flush()
{
if (poly_c != 0) {
sg_apply_pipeline(poly_pipe);
sg_apply_bindings(&poly_bind);
@ -136,7 +135,6 @@ void debug_flush()
sg_draw(0,4,circle_count);
circle_count = 0;
}
}
static sg_shader_uniform_block_desc projection_ubo = {
@ -586,7 +584,7 @@ void draw_poly(cpVect *points, int n, struct rgba color)
/* Find polygon mesh */
int tric = n - 2;
if (n < 1) return;
if (tric < 1) return;
uint32_t tridxs[tric*3];

View file

@ -899,7 +899,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
return JS_NULL;
case 83:
draw_edge(js2cpvec2arr(argv[1]), 2, js2color(argv[2]), 1, 0, 0, js2color(argv[2]), 10);
draw_edge(js2cpvec2arr(argv[1]), js_arrlen(argv[1]), js2color(argv[2]), js2number(argv[3]), 0, 0, js2color(argv[2]), 10);
return JS_NULL;
case 84:
@ -1021,6 +1021,14 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 115:
draw_circle(js2vec2(argv[1]), js2number(argv[2]), js2number(argv[2]), js2color(argv[3]), -1);
break;
case 116:
return str2js(tex_get_path(js2sprite(argv[1])->tex));
case 117:
str = JS_ToCString(js, argv[1]);
ret = JS_NewInt64(js, script_runfile(str));
break;
}
if (str)

View file

@ -53,8 +53,10 @@ void script_init() {
num_cache[i] = int2js(i);
}
void script_run(const char *script) {
JS_FreeValue(js, JS_Eval(js, script, strlen(script), "script", JS_EVAL_FLAGS));
void script_run(const char *script, const char *file) {
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
js_print_exception(obj);
JS_FreeValue(js,obj);
}
void compile_script(const char *file) {
@ -91,20 +93,22 @@ int js_print_exception(JSValue v) {
#ifdef DBG
if (JS_IsException(v)) {
JSValue exception = JS_GetException(js);
/* TODO: Does it need freed if null? */
if (JS_IsNull(exception))
return 0;
JSValue val = JS_GetPropertyStr(js, exception, "stack");
const char *name = JS_ToCString(js, JS_GetPropertyStr(js, exception, "name"));
const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message"));
const char *stack = JS_ToCString(js, val);
YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack);
JS_FreeCString(js, name);
JS_FreeCString(js, msg);
JS_FreeCString(js, stack);
JS_FreeValue(js,val);
JS_FreeValue(js,exception);
JSValue val = JS_GetPropertyStr(js, exception, "stack");
const char *name = JS_ToCString(js, JS_GetPropertyStr(js, exception, "name"));
const char *msg = JS_ToCString(js, JS_GetPropertyStr(js, exception, "message"));
const char *stack = JS_ToCString(js, val);
YughLog(LOG_SCRIPT, LOG_ERROR, "%s :: %s\n%s", name, msg,stack);
JS_FreeCString(js, name);
JS_FreeCString(js, msg);
JS_FreeCString(js, stack);
JS_FreeValue(js,val);
JS_FreeValue(js,exception);
return 1;
}
@ -112,17 +116,27 @@ int js_print_exception(JSValue v) {
return 0;
}
int script_dofile(const char *file) {
YughInfo("Doing script %s", file);
const char *script = slurp_text(file);
if (!script) {
YughError("Can't find file %s.", file);
return 0;
}
JSValue obj = JS_Eval(js, script, strlen(script), file, JS_EVAL_FLAGS);
js_print_exception(obj);
JS_FreeValue(js, obj);
script_run(script,file);
free(script);
return file_mod_secs(file);
}
int script_runfile(const char *file)
{
const char *script = slurp_text(file);
int bufsize = strlen(script)+50;
char scriptbuffer[bufsize];
snprintf(scriptbuffer,bufsize, "(function(){%s})()", script);
script_run(scriptbuffer,file);
free(script);
return file_mod_secs(file);
}

View file

@ -18,8 +18,9 @@ extern JSValue num_cache[100];
void js_stacktrace();
void script_startup();
void script_init();
void script_run(const char *script);
void script_run(const char *script, const char *file);
int script_dofile(const char *file);
int script_runfile(const char *file);
void script_update(double dt);
void script_draw();

View file

@ -19,7 +19,6 @@ static int first = -1;
static sg_pipeline pip_sprite;
static sg_bindings bind_sprite;
static int sprite_c = 0;
int make_sprite(int go) {
struct sprite sprite = {

View file

@ -156,7 +156,7 @@ char *tex_get_path(struct Texture *tex) {
}
}
return NULL;
return "";
}
struct Texture *texture_loadfromfile(const char *path) {

View file

@ -61,8 +61,8 @@ struct TextureOptions {
/* Represents an actual texture on the GPU */
struct Texture {
sg_image id; /* ID reference for the GPU memory location of the texture */
int width;
int height;
uint16_t width;
uint16_t height;
unsigned char *data;
struct TextureOptions opts;
struct TexAnim anim;

View file

@ -73,6 +73,7 @@ void timer_remove(int id) {
struct timer *t = id2timer(id);
if (t->owndata) free(t->data);
t->next = first;
t->on = 0;
first = id;
}

View file

@ -42,8 +42,8 @@ double physlag = 0;
double updatelag = 0;
double renderMS = 1 / 165.f;
double physMS = 1 / 240.f;
double updateMS = 1 / 60.f;
double physMS = 1 / 165.f;
double updateMS = 1 / 165.f;
static int ed = 1;
static int sim_play = 0;
@ -234,14 +234,14 @@ int main(int argc, char **args) {
timer_update(elapsed * timescale);
physlag += elapsed;
call_updates(elapsed * timescale);
while (physlag >= physMS) {
// while (physlag >= physMS) {
phys_step = 1;
physlag -= physMS;
phys2d_update(physMS * timescale);
call_physics(physMS * timescale);
if (sim_play == SIM_STEP) sim_pause();
phys_step = 0;
}
// }
}
renderlag += elapsed;

View file

@ -33,17 +33,13 @@ var sprite = clone(component, {
angle: 0,
rect: {s0:0, s1: 1, t0: 0, t1: 1},
input_kp7_pressed() { this.pos = [-1,0]; },
input_kp6_pressed() { this.pos = [0,-0.5]; },
input_kp5_pressed() { this.pos = [-0.5,-0.5]; },
input_kp4_pressed() { this.pos = [-1,-0.5]; },
input_kp3_pressed() { this.pos = [0, -1]; },
input_kp2_pressed() { this.pos = [-0.5,-1]; },
input_kp1_pressed() { this.pos = [-1,-1]; },
get dimensions() { return cmd(64,this.path); },
set dimensions(x) {},
make(go) {
var old = this;
var sprite = clone(this, {
var sprite = Object.create(this);
sprite.id = make_sprite(go,this.path,this.pos);
complete_assign(sprite, {
get enabled() { return cmd(114,this.id); },
set enabled(x) { cmd(20,this.id,x); },
set color(x) { cmd(96,this.id,x); },
@ -51,10 +47,9 @@ var sprite = clone(component, {
set pos(x) { cmd(37,this.id,x); },
set layer(x) { cmd(60, this.id, x); },
get layer() { return this.gameobject.draw_layer; },
set path(x) { cmd(12,this.id,x,this.rect); },
get boundingbox() {
var dim = cmd(64,this.path);
var dim = this.dimensions;
dim = dim.scale(this.gameobject.scale);
var realpos = this.pos.copy();
realpos.x = realpos.x * dim.x + (dim.x/2);
@ -62,21 +57,25 @@ var sprite = clone(component, {
return cwh2bb(realpos,dim);
},
sync() {
if (this.path)
cmd(12,this.id,this.path,this.rect);
},
kill() { cmd(9,this.id); },
});
sprite = new Proxy(sprite, sync_proxy);
sprite.obscure('boundingbox');
var id = make_sprite(go,old.path,old.pos);
Object.defineProperty(sprite, 'id', {value:id});
Object.assign(sprite, this);
return sprite;
},
input_kp7_pressed() { this.pos = [-1,0]; },
input_kp6_pressed() { this.pos = [0,-0.5]; },
input_kp5_pressed() { this.pos = [-0.5,-0.5]; },
input_kp4_pressed() { this.pos = [-1,-0.5]; },
input_kp3_pressed() { this.pos = [0, -1]; },
input_kp2_pressed() { this.pos = [-0.5,-1]; },
input_kp1_pressed() { this.pos = [-1,-1]; },
});
/* Container to play sprites and anim2ds */
@ -100,10 +99,39 @@ var char2d = clone(sprite, {
},
make(go) {
var char = clone(this);
var char = clone(this, {
get enabled() { return cmd(114,this.id); },
set enabled(x) { cmd(20,this.id,x); },
set color(x) { cmd(96,this.id,x); },
get pos() { return cmd(111, this.id); },
set pos(x) { cmd(37,this.id,x); },
set layer(x) { cmd(60, this.id, x); },
get layer() { return this.gameobject.draw_layer; },
get boundingbox() {
var dim = cmd(64,this.path);
dim = dim.scale(this.gameobject.scale);
dim.x *= 1/6;
var realpos = [0,0];
// var realpos = this.pos.slice();
// realpos.x = realpos.x * dim.x + (dim.x/2);
// realpos.y = realpos.y * dim.y + (dim.y/2);
return cwh2bb(realpos,dim);
},
sync() {
if (this.path)
cmd(12,this.id,this.path,this.rect);
},
kill() { cmd(9,this.id); },
});
char.curplaying = char.anims.array()[0];
char.obscure('curplaying');
Object.defineProperty(char, 'id', {value:make_sprite(go,char.curplaying.path,this.pos)});
char.id = make_sprite(go, char.curplaying.path, this.pos);
char.obscure('id');
char.frame = 0;
char.timer = timer.make(char.advance.bind(char), 1/char.curplaying.fps);
@ -254,11 +282,12 @@ var polygon2d = clone(collider2d, {
complete_assign(poly, this.make_fns);
complete_assign(poly, {
get boundingbox() {
return points2bb(this.points.map(x => x.scale(this.gameobject.scale)));
return points2bb(this.spoints);
},
sync() { cmd_poly2d(0, this.id, this.spoints); }
});
poly.obscure('boundingbox');
poly.defn('points', this.points.copy());
@ -268,6 +297,8 @@ var polygon2d = clone(collider2d, {
Object.defineProperty(poly, 'id', {enumerable:false});
Object.defineProperty(poly, 'shape', {enumerable:false});
poly.sync();
return poly;
},
@ -278,7 +309,6 @@ var polygon2d = clone(collider2d, {
this.points = sortpointsccw(this.points);
},
input_b_pressed() {
if (!Keys.ctrl()) return;

View file

@ -55,7 +55,8 @@ var Debug = {
register_debug(fn,obj);
},
line(points, color, type) {
line(points, color, type, thickness) {
thickness ??= 1;
if (!type)
type = 0;
@ -64,7 +65,7 @@ var Debug = {
switch (type) {
case 0:
cmd(83, points, color);
cmd(83, points, color, thickness);
}
},
};

View file

@ -1,8 +1,5 @@
var files = {};
function load(file) {
if (typeof Log !== 'undefined')
Log.warn(`doing ${file}`);
var modtime = cmd(0, file);
if (modtime === 0) {
@ -12,6 +9,17 @@ function load(file) {
files[file] = modtime;
}
function run(file)
{
var modtime = cmd(117,file);
if (modtime === 0) {
Log.stack();
return false;
}
files[file] = modtime;
}
load("scripts/base.js");
var Log = {
@ -167,6 +175,16 @@ var Yugine = {
};
var timer = {
guardfn(fn) {
if (typeof fn === 'function')
fn();
else {
Log.warn("TIMER TRYING TO EXECUTE WIHTOUT!!!");
Log.warn(this);
this.kill();
}
},
make(fn, secs,obj,loop) {
if (secs === 0) {
fn.call(obj);
@ -174,7 +192,7 @@ var timer = {
}
var t = clone(this);
t.id = make_timer(fn, secs, obj);
t.id = make_timer(this.guardfn.bind(t,fn), secs, obj);
return t;
},
@ -484,6 +502,7 @@ var Register = {
nk_guis: [],
nk_gui() {
this.nk_guis.forEach(x => x[0].call(x[1]));
},
@ -514,12 +533,13 @@ var Register = {
},
unregister_obj(obj) {
// Log.warn(`Unregister ${JSON.stringify(obj)}`);
this.updates = this.updates.filter(x => x[1] !== obj);
this.guis = this.guis.filter(x => x[1] !== obj);
this.nk_guis = this.nk_guis.filter(x => x[1] !== obj);
this.debugs = this.debugs.filter(x => x[1] !== obj);
this.physupdates = this.physupdates.filter(x => x[1] !== obj);
this.draws = this.draws.filter(x => x[1] !== obj);
Player.players.forEach(x => x.uncontrol(obj));
},
@ -538,7 +558,6 @@ var Register = {
},
};
Register.unregister_obj(null);
register(0, Register.update, Register);
register(1, Register.physupdate, Register);
register(2, Register.gui, Register);
@ -568,7 +587,7 @@ function register_debug(fn, obj) {
};
function unregister_gui(fn, obj) {
Register.guis = Register.guis.filter(x => x[0] !== fn && x[1] !== obj);
Register.guis = Register.guis.filter(x => x[0] !== fn || x[1] !== obj);
};
function register_nk_gui(fn, obj) {
@ -608,7 +627,7 @@ var Signal = {
register_collide(3,fn,obj,go.body);
},
clear_obj(obj) {
clera_obj(obj) {
this.signals.filter(function(x) { return x[1] !== obj; });
},
};
@ -635,6 +654,7 @@ function reloadfiles() {
load("scripts/debug.js");
/*
function Color(from) {
var color = Object.create(Array);
Object.defineProperty(color, 'r', setelem(0));
@ -647,6 +667,7 @@ function Color(from) {
return color;
};
*/
load("scripts/components.js");
@ -1266,15 +1287,7 @@ function grab_from_points(pos, points, slop) {
};
var gameobject = {
get scale() { return this._scale; },
set scale(x) {
this._scale = Math.max(0,x);
if (this.body > -1)
cmd(36, this.body, this._scale);
this.sync();
},
_scale: 1.0,
scale: 1.0,
save: true,
@ -1427,11 +1440,11 @@ var gameobject = {
this.instances.forEach(function(x) { x.sync(); });
},
pulse(vec) {
pulse(vec) { /* apply impulse */
set_body(4, this.body, vec);
},
push(vec) {
push(vec) { /* apply force */
set_body(12,this.body,vec);
},
@ -1477,6 +1490,18 @@ var gameobject = {
return bb ? bb : cwh2bb([0,0], [0,0]);
},
set width(x) {},
get width() {
var bb = this.boundingbox;
Log.warn(bb);
return bb.r - bb.l;
},
set height(x) {},
get height() {
var bb = this.boundingbox;
return bb.t-bb.b;
},
stop() {},
kill() {
@ -1490,7 +1515,7 @@ var gameobject = {
this.uncontrol();
this.instances.remove(this);
Register.unregister_obj(this);
Signal.clear_obj(this);
// Signal.clear_obj(this);
this.body = -1;
for (var key in this.components) {
@ -1538,6 +1563,30 @@ var gameobject = {
world2this(pos) { return cmd(70, this.body, pos); },
this2world(pos) { return cmd(71, this.body,pos); },
check_registers(obj) {
Register.unregister_obj(this);
if (typeof obj.update === 'function')
register_update(obj.update, obj);
if (typeof obj.physupdate === 'function')
register_physupdate(obj.physupdate, obj);
if (typeof obj.collide === 'function')
obj.register_hit(obj.collide, obj);
if (typeof obj.separate === 'function')
obj.register_separate(obj.separate, obj);
if (typeof obj.draw === 'function')
register_draw(obj.draw,obj);
obj.components.forEach(function(x) {
if (typeof x.collide === 'function')
register_collide(1, x.collide, x, obj.body, x.shape);
});
},
make(props, level) {
level ??= World;
var obj = Object.create(this);
@ -1600,25 +1649,7 @@ var gameobject = {
}
};
if (typeof obj.update === 'function')
register_update(obj.update, obj);
if (typeof obj.physupdate === 'function')
register_physupdate(obj.physupdate, obj);
if (typeof obj.collide === 'function')
obj.register_hit(obj.collide, obj);
if (typeof obj.separate === 'function')
obj.register_separate(obj.separate, obj);
if (typeof obj.draw === 'function')
register_draw(obj.draw,obj);
obj.components.forEach(function(x) {
if (typeof x.collide === 'function')
register_collide(1, x.collide, x, obj.body, x.shape);
});
obj.check_registers(obj);
if ('begin' in obj) obj.begin();
@ -1641,11 +1672,8 @@ var gameobject = {
}
var locks = ['visible', 'body', 'controlled', 'selectable', 'save', 'velocity', 'angularvelocity', 'alive', 'boundingbox', 'name', 'scale', 'angle', 'properties', 'moi', 'relpos', 'relangle', 'up', 'down', 'right', 'left', 'bodytype', 'gizmo', 'pos'];
locks.forEach(function(x) {
Object.defineProperty(gameobject, x, {enumerable:false});
});
var locks = ['height', 'width', 'visible', 'body', 'controlled', 'selectable', 'save', 'velocity', 'angularvelocity', 'alive', 'boundingbox', 'name', 'scale', 'angle', 'properties', 'moi', 'relpos', 'relangle', 'up', 'down', 'right', 'left', 'bodytype', 'gizmo', 'pos'];
locks.forEach(x => gameobject.obscure(x));
/* Load configs */
function load_configs(file) {
var configs = JSON.parse(IO.slurp(file));
@ -1790,3 +1818,5 @@ for (var key in prototypes) {
}
function save_gameobjects_as_prototypes() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); };
let Gamestate = {};

View file

@ -3,3 +3,5 @@ if (load("game.js") === false) {
quit();
}
sim_start();