Tween and delay fixes now entity lifetime; spline symmetry

This commit is contained in:
John Alanbrook 2023-11-17 21:16:13 +00:00
parent e712d06244
commit cccd472f12
13 changed files with 231 additions and 46 deletions

View file

@ -198,7 +198,7 @@ input.md: $(INPUTMD)
$(BIN)/libquickjs.a: $(BIN)/libquickjs.a:
make -C quickjs clean make -C quickjs clean
make -C quickjs SYSRT=$(SYSRT) TTARGET=$(TTARGET) ARCH=$(ARCH) DBG=$(DBG) OPT=$(OPT) HOST_CC=$(CC) AR=$(AR) libquickjs.a libquickjs.lto.a CC=$(CC) make -C quickjs SYSRT=$(SYSRT) TTARGET=$(TTARGET) ARCH=$(ARCH) DBG=$(DBG) OPT=$(OPT) HOST_CC=$(CC) CCC=$(CC) AR=$(AR) libquickjs.a libquickjs.lto.a CC=$(CC)
@mkdir -p $(BIN) @mkdir -p $(BIN)
cp -rf quickjs/libquickjs.* $(BIN) cp -rf quickjs/libquickjs.* $(BIN)

View file

@ -22,9 +22,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE. # THE SOFTWARE.
ifeq ($(shell uname -s),Darwin)
CONFIG_DARWIN=y
endif
# Windows cross compilation from Linux # Windows cross compilation from Linux
#CONFIG_WIN32=y #CONFIG_WIN32=y
# use link time optimization (smaller and faster executables but slower build) # use link time optimization (smaller and faster executables but slower build)
@ -34,12 +31,13 @@ CONFIG_LTO=y
# force 32 bit build for some utilities # force 32 bit build for some utilities
#CONFIG_M32=y #CONFIG_M32=y
ifdef CONFIG_DARWIN
# use clang instead of gcc # use clang instead of gcc
CONFIG_CLANG=y ifeq ($(CCC),clang)
CONFIG_DEFAULT_AR=y CONFIG_CLANG=y
CONFIG_DEFAULT_AR=y
endif endif
# installation directory # installation directory
prefix=/usr/local prefix=/usr/local
@ -63,10 +61,9 @@ else
CROSS_PREFIX= CROSS_PREFIX=
EXE= EXE=
endif endif
ifdef CONFIG_CLANG ifeq ($(CCC), clang)
HOST_CC=clang
CC=$(CROSS_PREFIX)clang CC=$(CROSS_PREFIX)clang
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d CFLAGS += -g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -Wextra CFLAGS += -Wextra
CFLAGS += -Wno-sign-compare CFLAGS += -Wno-sign-compare
CFLAGS += -Wno-missing-field-initializers CFLAGS += -Wno-missing-field-initializers
@ -91,9 +88,8 @@ endif
endif endif
endif endif
else else
HOST_CC=gcc
CC=$(CROSS_PREFIX)gcc CC=$(CROSS_PREFIX)gcc
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d CFLAGS += -g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -Wno-array-bounds -Wno-format-truncation CFLAGS += -Wno-array-bounds -Wno-format-truncation
CFLAGS += -Wno-unused-function -Wno-unused-const-variable CFLAGS += -Wno-unused-function -Wno-unused-const-variable
ifdef CONFIG_LTO ifdef CONFIG_LTO

View file

@ -485,6 +485,19 @@ Object.defineProperty(String.prototype, 'dir', {
value: function() { return this.tolast('/'); } value: function() { return this.tolast('/'); }
}); });
Object.defineProperty(String.prototype, 'splice', {
value: function(index, str, ) {
return this.slice(0,index) + str + this.slice(index);
}
});
Object.defineProperty(String.prototype, 'rm', {
value: function(index, endidx) {
endidx ??= index+1;
return this.slice(0,index) + this.slice(endidx);
}
});
Object.defineProperty(String.prototype, 'updir', { Object.defineProperty(String.prototype, 'updir', {
value: function() { value: function() {
if (this.lastIndexOf('/') === this.length-1) if (this.lastIndexOf('/') === this.length-1)

View file

@ -415,7 +415,8 @@ Geometry.doc = {
doc: "Functions for creating a list of points for various geometric shapes.", doc: "Functions for creating a list of points for various geometric shapes.",
box: "Create a box.", box: "Create a box.",
arc: "Create an arc, made of n points.", arc: "Create an arc, made of n points.",
circle: "Create a circle, made of n points." circle: "Create a circle, made of n points.",
ngon: "Create a polygon of n sides.",
}; };
/* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */ /* For all colliders, "shape" is a pointer to a phys2d_shape, "id" is a pointer to the shape data */
@ -532,12 +533,12 @@ polygon2d.inputs['C-lm'].doc = "Add a point to location of mouse.";
polygon2d.inputs.lm = function(){}; polygon2d.inputs.lm = function(){};
polygon2d.inputs.lm.released = function(){}; polygon2d.inputs.lm.released = function(){};
polygon2d.inputs['S-lm'] = function() { polygon2d.inputs['C-M-lm'] = function() {
var idx = grab_from_points(Mouse.worldpos, this.points.map(p => this.gameobject.this2world(p)), 25); var idx = grab_from_points(Mouse.worldpos, this.points.map(p => this.gameobject.this2world(p)), 25);
if (idx === -1) return; if (idx === -1) return;
this.points.splice(idx, 1); this.points.splice(idx, 1);
}; };
polygon2d.inputs['S-lm'].doc = "Remove point under mouse."; polygon2d.inputs['C-M-lm'].doc = "Remove point under mouse.";
polygon2d.inputs['C-b'] = function() { polygon2d.inputs['C-b'] = function() {
this.points = this.spoints; this.points = this.spoints;
@ -637,7 +638,7 @@ component.edge2d = Object.copy(collider2d, {
return Spline.sample(degrees, this.dimensions, this.type, spoints, n); return Spline.sample(degrees, this.dimensions, this.type, spoints, n);
}, },
samples: 10, samples: 1,
boundingbox() { boundingbox() {
return points2bb(this.points.map(x => x.scale(this.gameobject.scale))); return points2bb(this.points.map(x => x.scale(this.gameobject.scale)));
@ -678,7 +679,9 @@ component.edge2d = Object.copy(collider2d, {
}, },
sample_calc() { sample_calc() {
return (this.spoints().length-1); var n = this.spoints().length-1;
if (this.looped) n++;
return n;
}, },
samples_per_cp() { samples_per_cp() {
@ -781,14 +784,17 @@ bucket.inputs['C-lm'] = function() {
}; };
bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position."; bucket.inputs['C-lm'].doc = "Add a point to the spline at the mouse position.";
bucket.inputs['S-lm'] = function() { bucket.inputs['C-M-lm'] = function() {
var idx = grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25); var idx = grab_from_points(Mouse.worldpos, this.cpoints.map(p => this.gameobject.this2world(p)), 25);
if (idx < 0 || idx > this.cpoints.length) return; if (idx < 0 || idx > this.cpoints.length) return;
this.cpoints.splice(idx, 1); this.cpoints.splice(idx, 1);
}; };
bucket.inputs['S-lm'].doc = "Remove point from the spline."; bucket.inputs['C-M-lm'].doc = "Remove point from the spline.";
bucket.inputs.lm = function(){};
bucket.inputs.lm.released = function(){};
bucket.inputs.lb = function() { bucket.inputs.lb = function() {
var np = []; var np = [];

View file

@ -895,9 +895,7 @@ editor.inputs['C-s'] = function() {
var savejs = saveobj.json_obj(); var savejs = saveobj.json_obj();
Object.merge(saveobj.__proto__, savejs); Object.merge(saveobj.__proto__, savejs);
if (savejs.objects) saveobj.__proto__.objects = savejs.objects; if (savejs.objects) saveobj.__proto__.objects = savejs.objects;
var path = saveobj.ur.toString(); var path = prototypes.ur_stem(saveobj.ur.toString()) + ".json";
path = path.replaceAll('.','/');
path = path + "/" + path.name() + ".json";
IO.slurpwrite(JSON.stringify(saveobj.__proto__,null,1), path); IO.slurpwrite(JSON.stringify(saveobj.__proto__,null,1), path);
Log.warn(`Wrote to file ${path}`); Log.warn(`Wrote to file ${path}`);

View file

@ -42,11 +42,32 @@ var gameobject = {
this.objects = {}; this.objects = {};
}, },
timers:[],
delay(fn, seconds) { delay(fn, seconds) {
var t = timer.oneshot(fn.bind(this), seconds, this, false); var t = timer.delay(fn.bind(this), seconds, false);
this.timers.push(t); this.timers.push(t);
return function() { t.kill(); }; return t;
},
tween(prop, values, def){
var t = Tween.make(this, prop, values, def);
t.play();
var k = function() { t.pause(); }
this.timers.push(k);
return k;
},
cry(file) {
Sound.play(file);
return;
if (this.curcry && !Sound.finished(this.curcry)) return;
this.curcry = Sound.play(file);
var r = this.curcry;
Log.warn(r);
var fn = function() { Log.warn(r); if (r) Sound.stop(r); };
this.timers.push(fn);
return fn;
}, },
set max_velocity(x) { cmd(151, this.body, x); }, set max_velocity(x) { cmd(151, this.body, x); },
@ -451,10 +472,7 @@ var gameobject = {
q_body(8,this.body); q_body(8,this.body);
Game.unregister_obj(this); Game.unregister_obj(this);
this.timers.forEach(function(t) { this.timers.forEach(t => t());
if (!t) return;
t.kill();
});
if (this.level) { if (this.level) {
this.level.remove_obj(this); this.level.remove_obj(this);
@ -503,6 +521,7 @@ var gameobject = {
obj.body = make_gameobject(); obj.body = make_gameobject();
obj.components = {}; obj.components = {};
obj.objects = {}; obj.objects = {};
obj.timers = [];
assign_impl(obj, gameobject.impl); assign_impl(obj, gameobject.impl);
obj._ed = { obj._ed = {
selectable: true, selectable: true,
@ -656,6 +675,7 @@ gameobject.doc = {
kill: `Remove this object from the world.`, kill: `Remove this object from the world.`,
level: "The entity this entity belongs to.", level: "The entity this entity belongs to.",
delay: 'Run the given function after the given number of seconds has elapsed.', delay: 'Run the given function after the given number of seconds has elapsed.',
cry: 'Make a sound. Can only make one at a time.',
}; };
/* Default objects */ /* Default objects */
@ -895,3 +915,56 @@ prototypes.resani = function(ur, path)
} }
return restry; return restry;
} }
prototypes.ur_dir = function(ur)
{
var path = ur.replaceAll('.', '/');
Log.warn(path);
Log.warn(IO.exists(path));
Log.warn(`${path} does not exist; sending ${path.dir()}`);
}
prototypes.ur_json = function(ur)
{
var path = ur.replaceAll('.', '/');
if (IO.exists(path))
path = path + "/" + path.name() + ".json";
else
path = path + ".json";
return path;
}
prototypes.ur_stem = function(ur)
{
var path = ur.replaceAll('.', '/');
if (IO.exists(path))
return path + "/" + path.name();
else
return path;
}
prototypes.ur_file_exts = ['.jso', '.json'];
prototypes.ur_folder = function(ur)
{
var path = ur.replaceAll('.', '/');
return IO.exists(path);
}
prototypes.ur_pullout_folder = function(ur)
{
if (!prototypes.ur_folder(ur)) return;
var stem = prototypes.ur_stem(ur);
/* prototypes.ur_file_exts.forEach(function(e) {
var p = stem + e;
if (IO.exists(p))
*/
}
prototypes.ur_pushin_folder = function(ur)
{
}

View file

@ -391,10 +391,19 @@ Ease.elastic.c5 = 2*Math.PI / 4.5;
var Tween = { var Tween = {
default: { default: {
loop: "restart", /* none, restart, yoyo, circle */ loop: "restart",
/*
loop types
none: when done, return to first value
hold: hold last value of tween
restart: restart at beginning, looping
yoyo: go up and then back down
circle: go up and back down, looped
*/
time: 1, /* seconds to do */ time: 1, /* seconds to do */
ease: Ease.linear, ease: Ease.linear,
whole: true, whole: true, /* True if time is for the entire tween, false if each stage */
cb: function(){},
}, },
start(obj, target, tvals, options) start(obj, target, tvals, options)
@ -416,6 +425,13 @@ var Tween = {
defn.fn = function(dt) { defn.fn = function(dt) {
defn.accum += dt; defn.accum += dt;
if (defn.accum >= defn.time && defn.loop === 'hold') {
obj[target] = tvals[tvals.length-1];
defn.pause();
defn.cb.call(obj);
return;
}
defn.pct = (defn.accum % defn.time) / defn.time; defn.pct = (defn.accum % defn.time) / defn.time;
if (defn.loop === 'none' && defn.accum >= defn.time) if (defn.loop === 'none' && defn.accum >= defn.time)
defn.stop(); defn.stop();
@ -445,8 +461,9 @@ var Tween = {
}; };
defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); }; defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); };
defn.pause = function() { defn.pause = function() {
Register.update.unregister(defn.fn);
if (!playing) return; if (!playing) return;
Register.update.unregister(defn.fn);
playing = false; playing = false;
}; };

View file

@ -27,7 +27,16 @@ var Sound = {
Log.error(`Cannot play sound ${file}: does not exist.`); Log.error(`Cannot play sound ${file}: does not exist.`);
return; return;
} }
this.id = cmd(14,file); var p = cmd(14,file);
return p;
},
finished(sound) {
return cmd(165, sound);
},
stop(sound) {
cmd(164, sound);
}, },
music(midi, sf) { music(midi, sf) {

View file

@ -101,6 +101,15 @@ Log.doc = {
clear: "Clear console." clear: "Clear console."
}; };
/*
IO path rules. Starts with, meaning:
"@": playerpath
"/": game room
"#": Force look locally (instead of in db first)
- This is combined with others. #/, #@, etc
"": Local path relative to script defined in
*/
var IO = { var IO = {
exists(file) { return cmd(65, file);}, exists(file) { return cmd(65, file);},
slurp(file) { slurp(file) {
@ -116,6 +125,16 @@ var IO = {
return paths; return paths;
}, },
ls() { return cmd(66); }, ls() { return cmd(66); },
/* Only works on text files currently */
cp(f1, f2) {
cmd(166, f1, f2);
},
mv(f1, f2) {
return cmd(163, f1, f2);
},
rm(f) {
return cmd(f);
},
glob(pat) { glob(pat) {
var paths = IO.ls(); var paths = IO.ls();
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1"); pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
@ -137,6 +156,25 @@ IO.doc = {
glob: "Glob files in game directory.", glob: "Glob files in game directory.",
}; };
var Parser = {};
Parser.replstrs = function(path)
{
var script = IO.slurp(path);
var regexp = /"[^"\s]*?\.[^"\s]+?"/g;
var stem = path.dir();
script = script.replace(regexp,function(str) {
if (str[1] === "/")
return str.rm(1);
if (str[1] === "@")
return str.rm(1).splice(1, "playerpath/");
return str.splice(1, stem + "/");
});
Log.warn(script);
}
var Cmdline = {}; var Cmdline = {};
Cmdline.cmds = []; Cmdline.cmds = [];

View file

@ -546,7 +546,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 14: case 14:
str = JS_ToCString(js, argv[1]); str = JS_ToCString(js, argv[1]);
play_oneshot(make_sound(str)); ret = ptr2js(play_sound(make_sound(str)));
break; break;
case 15: case 15:
@ -1152,6 +1152,26 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 161: case 161:
ret = vec2js(mat_t_dir(t_go2world(js2go(argv[1])), js2vec2(argv[2]))); ret = vec2js(mat_t_dir(t_go2world(js2go(argv[1])), js2vec2(argv[2])));
break; break;
case 162:
str = JS_ToCString(js, argv[1]);
ret = int2js(remove(str));
break;
case 163:
str = JS_ToCString(js,argv[1]);
str2 = JS_ToCString(js,argv[2]);
ret = int2js(rename(str, str2));
break;
case 164:
sound_stop(js2ptr(argv[1]));
break;
case 165:
ret = bool2js(sound_paused(js2ptr(argv[1])));
break;
case 166:
str = js2str(argv[1]);
str2 = js2str(argv[2]);
ret = int2js(cp(str, str2));
break;
} }
if (str) if (str)

View file

@ -247,6 +247,19 @@ char *slurp_text(const char *filename, size_t *size)
return retstr; return retstr;
} }
int cp(char *p1, char *p2)
{
long len;
void *data = slurp_file(p1, &len);
FILE *f = fopen_mkdir(p2, "w");
if (!f) return 1;
fwrite(data, len, 1, f);
free(data);
fclose(f);
return 0;
}
void rek_mkdir(char *path) { void rek_mkdir(char *path) {
char *sep = strrchr(path, '/'); char *sep = strrchr(path, '/');
if(sep != NULL) { if(sep != NULL) {

View file

@ -14,7 +14,9 @@ FILE *res_open(char *path, const char *tag);
FILE *path_open(const char *tag, const char *fmt, ...); FILE *path_open(const char *tag, const char *fmt, ...);
char *make_path(const char *file); char *make_path(const char *file);
char **ls(char *path); char **ls(char *path);
int cp(char *p1, char *p2);
int fexists(char *path); int fexists(char *path);
FILE *fopen_mkdir(char *path, char *mode);
void *slurp_file(const char *filename, size_t *size); void *slurp_file(const char *filename, size_t *size);
char *slurp_text(const char *filename, size_t *size); char *slurp_text(const char *filename, size_t *size);

View file

@ -233,42 +233,43 @@ void play_oneshot(struct wav *wav) {
struct sound *play_sound(struct wav *wav) { struct sound *play_sound(struct wav *wav) {
struct sound *new = calloc(1, sizeof(*new)); struct sound *new = calloc(1, sizeof(*new));
new->data = wav; new->data = wav;
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf)); new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
new->playing = 1; new->playing = 1;
new->loop = 0;
new->frame = 0;
new->endcb = kill_oneshot;
return new; return new;
} }
int sound_playing(const struct sound *s) { int sound_playing(const struct sound *s) {
return s->playing; return !sound_paused(s);
} }
int sound_paused(const struct sound *s) { int sound_paused(const struct sound *s) {
return (!s->playing && s->frame < s->data->frames); return s->bus == NULL;
} }
void sound_pause(struct sound *s) { void sound_pause(struct sound *s) {
s->playing = 0; if (s->bus == NULL) return;
bus_free(s->bus); bus_free(s->bus);
s->bus = NULL;
} }
void sound_resume(struct sound *s) { void sound_resume(struct sound *s) {
s->playing = 1; if (s->bus != NULL) return;
s->bus = first_free_bus(dsp_filter(s, sound_fillbuf)); s->bus = first_free_bus(dsp_filter(s, sound_fillbuf));
} }
void sound_stop(struct sound *s) { void sound_stop(struct sound *s) {
s->playing = 0; sound_pause(s);
s->frame = 0; s->frame = 0;
bus_free(s->bus);
} }
int sound_finished(const struct sound *s) { int sound_finished(const struct sound *s) {
return !s->playing && s->frame == s->data->frames; return s->frame == s->data->frames;
} }
int sound_stopped(const struct sound *s) { int sound_stopped(const struct sound *s) {
return !s->playing && s->frame == 0; return s->bus == NULL;
} }
struct mp3 make_music(const char *mp3) { struct mp3 make_music(const char *mp3) {
@ -298,8 +299,7 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
s->frame++; s->frame++;
if (s->frame == s->data->frames) { if (s->frame == s->data->frames) {
bus_free(s->bus); sound_stop(s);
s->bus = NULL;
s->endcb(s); s->endcb(s);
return; return;
} }