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:
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)
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
# THE SOFTWARE.
ifeq ($(shell uname -s),Darwin)
CONFIG_DARWIN=y
endif
# Windows cross compilation from Linux
#CONFIG_WIN32=y
# 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
#CONFIG_M32=y
ifdef CONFIG_DARWIN
# use clang instead of gcc
CONFIG_CLANG=y
CONFIG_DEFAULT_AR=y
ifeq ($(CCC),clang)
CONFIG_CLANG=y
CONFIG_DEFAULT_AR=y
endif
# installation directory
prefix=/usr/local
@ -63,10 +61,9 @@ else
CROSS_PREFIX=
EXE=
endif
ifdef CONFIG_CLANG
HOST_CC=clang
ifeq ($(CCC), clang)
CC=$(CROSS_PREFIX)clang
CFLAGS=-g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -g -Wall -MMD -MF $(OBJDIR)/$(@F).d
CFLAGS += -Wextra
CFLAGS += -Wno-sign-compare
CFLAGS += -Wno-missing-field-initializers
@ -91,9 +88,8 @@ endif
endif
endif
else
HOST_CC=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-unused-function -Wno-unused-const-variable
ifdef CONFIG_LTO

View file

@ -485,6 +485,19 @@ Object.defineProperty(String.prototype, 'dir', {
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', {
value: function() {
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.",
box: "Create a box.",
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 */
@ -532,12 +533,12 @@ polygon2d.inputs['C-lm'].doc = "Add a point to location of mouse.";
polygon2d.inputs.lm = 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);
if (idx === -1) return;
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() {
this.points = this.spoints;
@ -637,7 +638,7 @@ component.edge2d = Object.copy(collider2d, {
return Spline.sample(degrees, this.dimensions, this.type, spoints, n);
},
samples: 10,
samples: 1,
boundingbox() {
return points2bb(this.points.map(x => x.scale(this.gameobject.scale)));
@ -678,7 +679,9 @@ component.edge2d = Object.copy(collider2d, {
},
sample_calc() {
return (this.spoints().length-1);
var n = this.spoints().length-1;
if (this.looped) n++;
return n;
},
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['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);
if (idx < 0 || idx > this.cpoints.length) return;
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() {
var np = [];

View file

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

View file

@ -42,11 +42,32 @@ var gameobject = {
this.objects = {};
},
timers:[],
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);
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); },
@ -451,10 +472,7 @@ var gameobject = {
q_body(8,this.body);
Game.unregister_obj(this);
this.timers.forEach(function(t) {
if (!t) return;
t.kill();
});
this.timers.forEach(t => t());
if (this.level) {
this.level.remove_obj(this);
@ -503,6 +521,7 @@ var gameobject = {
obj.body = make_gameobject();
obj.components = {};
obj.objects = {};
obj.timers = [];
assign_impl(obj, gameobject.impl);
obj._ed = {
selectable: true,
@ -656,6 +675,7 @@ gameobject.doc = {
kill: `Remove this object from the world.`,
level: "The entity this entity belongs to.",
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 */
@ -895,3 +915,56 @@ prototypes.resani = function(ur, path)
}
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 = {
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 */
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)
@ -416,6 +425,13 @@ var Tween = {
defn.fn = function(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;
if (defn.loop === 'none' && defn.accum >= defn.time)
defn.stop();
@ -445,8 +461,9 @@ var Tween = {
};
defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); };
defn.pause = function() {
if (!playing) return;
Register.update.unregister(defn.fn);
if (!playing) return;
playing = false;
};

View file

@ -27,7 +27,16 @@ var Sound = {
Log.error(`Cannot play sound ${file}: does not exist.`);
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) {

View file

@ -101,6 +101,15 @@ Log.doc = {
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 = {
exists(file) { return cmd(65, file);},
slurp(file) {
@ -116,6 +125,16 @@ var IO = {
return paths;
},
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) {
var paths = IO.ls();
pat = pat.replaceAll(/([\[\]\(\)\^\$\.\|\+])/g, "\\$1");
@ -137,6 +156,25 @@ IO.doc = {
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 = {};
Cmdline.cmds = [];

View file

@ -546,7 +546,7 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 14:
str = JS_ToCString(js, argv[1]);
play_oneshot(make_sound(str));
ret = ptr2js(play_sound(make_sound(str)));
break;
case 15:
@ -1152,6 +1152,26 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
case 161:
ret = vec2js(mat_t_dir(t_go2world(js2go(argv[1])), js2vec2(argv[2])));
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)

View file

@ -247,6 +247,19 @@ char *slurp_text(const char *filename, size_t *size)
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) {
char *sep = strrchr(path, '/');
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, ...);
char *make_path(const char *file);
char **ls(char *path);
int cp(char *p1, char *p2);
int fexists(char *path);
FILE *fopen_mkdir(char *path, char *mode);
void *slurp_file(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 *new = calloc(1, sizeof(*new));
new->data = wav;
new->bus = first_free_bus(dsp_filter(new, sound_fillbuf));
new->playing = 1;
new->loop = 0;
new->frame = 0;
new->endcb = kill_oneshot;
return new;
}
int sound_playing(const struct sound *s) {
return s->playing;
return !sound_paused(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) {
s->playing = 0;
if (s->bus == NULL) return;
bus_free(s->bus);
s->bus = NULL;
}
void sound_resume(struct sound *s) {
s->playing = 1;
if (s->bus != NULL) return;
s->bus = first_free_bus(dsp_filter(s, sound_fillbuf));
}
void sound_stop(struct sound *s) {
s->playing = 0;
sound_pause(s);
s->frame = 0;
bus_free(s->bus);
}
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) {
return !s->playing && s->frame == 0;
return s->bus == NULL;
}
struct mp3 make_music(const char *mp3) {
@ -298,8 +299,7 @@ void sound_fillbuf(struct sound *s, soundbyte *buf, int n) {
s->frame++;
if (s->frame == s->data->frames) {
bus_free(s->bus);
s->bus = NULL;
sound_stop(s);
s->endcb(s);
return;
}