From 2983e9f3c6f0cdf330964aa6179744af557a7169 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 1 Jan 2024 13:44:43 +0000 Subject: [PATCH] tween functions --- scripts/components.js | 11 +++++++- scripts/entity.js | 52 ++++++++++++++++++++++++++++++++++++- scripts/tween.js | 16 +++++++++--- source/engine/jsffi.c | 34 ++++++++++++++++++++++++ source/engine/particle.c | 6 ++--- source/engine/render.h | 6 +++++ source/engine/sprite.c | 15 +++++++---- source/engine/sprite.h | 1 + source/engine/yugine.c | 8 +++--- source/shaders/sprite.sglsl | 2 +- 10 files changed, 133 insertions(+), 18 deletions(-) diff --git a/scripts/components.js b/scripts/components.js index dc4273f..206b277 100644 --- a/scripts/components.js +++ b/scripts/components.js @@ -144,6 +144,8 @@ component.sprite.impl = { get color() {return cmd(148,this.id);}, get pos() { return cmd(111, this.id); }, set pos(x) { cmd(37,this.id,x); }, + get parallax() { return cmd(232, this.id); }, + set parallax(x) { cmd(233,this.id,x); }, get angle() { return cmd(217,this.id); }, set angle(x) { cmd(218,this.id,x); }, get scale() { return cmd(215, this.id); }, @@ -287,7 +289,7 @@ var SpriteAnim = { return anim; }; - var json = IO.slurp(ase); + var json = IO.slurp(path); json = JSON.parse(json); var anims = {}; var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames); @@ -859,6 +861,13 @@ component.circle2d.impl = Object.mix({ }, collider2d.impl); +component.particle = Object.copy(component, { + get pos() {}, + set pos(x) {}, + get angle() {}, + set angle(x) {}, +}); + /* ASSETS */ diff --git a/scripts/entity.js b/scripts/entity.js index 4be029d..6d1f991 100644 --- a/scripts/entity.js +++ b/scripts/entity.js @@ -197,15 +197,55 @@ var gameobject = { pin(to) { var p = cmd(222,this.body, to.body); }, + slide(to, a, b, min, max) { + a ??= [0,0]; + b ??= [0,0]; + min ??= 0; + max ??= 50; + var p = cmd(229,this.body,to.body,a,b,min,max); + }, pivot(to, piv) { piv ??= this.worldpos(); var p = cmd(221,this.body,to.body,piv); }, - gear(to, phase, ratio) { + /* groove is on to, from local points a and b, anchored to this at local anchor */ + groove(to, a, b, anchor) { + anchor ??= [0,0]; + var p = cmd(228, to.body, this.body, a, b, anchor); + }, + damped_spring(to, length, stiffness, damping) { + length ??= Vector.length(this.worldpos(), to.worldpos()); + stiffness ??= 1; + damping ??= 1; + var dc = 2*Math.sqrt(stiffness*this.mass); + var p = cmd(227, this.body, to.body, [0,0], [0,0], stiffness, damping*dc); + }, + damped_rotary_spring(to, angle, stiffness, damping) { + angle ??= 0; + stiffness ??= 1; + damping ??= 1; + /* calculate actual damping value from the damping ratio */ + /* damping = 1 is critical */ + var dc = 2*Math.sqrt(stiffness*this.get_moi()); /* critical damping number */ + /* zeta = actual/critical */ + var p = cmd(226,this.body,to.body,angle,stiffness,damping*dc); + }, + rotary_limit(to, min, max) { + var p = cmd(225,this.body,to.body, Math.turn2rad(min),Math.turn2rad(max)); + }, + ratchet(to,ratch) { + var phase = this.angle - to.angle; + var p = cmd(230, this.body, to.body, phase, Math.turn2rad(ratch)); + }, + gear(to, ratio) { phase ??= 1; ratio ??= 1; + var phase = this.angle - to.angle; var p = cmd(223,this.body,to.body,phase,ratio); }, + motor(to, rate) { + var p = cmd(231, this.body, to.body, rate); + }, path_from(o) { var p = this.toString(); @@ -713,6 +753,16 @@ gameobject.doc = { delay: 'Run the given function after the given number of seconds has elapsed.', cry: 'Make a sound. Can only make one at a time.', add_component: 'Add a component to the object by name.', + pin: 'Pin joint to another object. Acts as if a rigid rod is between the two objects.', + slide: 'Slide joint, similar to a pin but with min and max allowed distances.', + pivot: 'Pivot joint to an object, with the pivot given in world coordinates.', + groove: 'Groove joint. The groove is on to, from to local coordinates a and b, with this object anchored at anchor.', + damped_spring: 'Damped spring to another object. Length is the distance it wants to be, stiffness is the spring constant, and damping is the damping ratio. 1 is critical, < 1 is underdamped, > 1 is overdamped.', + damped_rotary_spring: 'Similar to damped spring but for rotation. Rest angle is the attempted angle.', + rotary_limit: 'Limit the angle relative to the to body between min and max.', + ratchet: 'Like a socket wrench, relative to to. ratch is the distance between clicks.', + gear: 'Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.', + motor: 'Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.' }; /* Default objects */ diff --git a/scripts/tween.js b/scripts/tween.js index e978869..9fe95d3 100644 --- a/scripts/tween.js +++ b/scripts/tween.js @@ -140,7 +140,11 @@ var Tween = { defn.fn = function(dt) { defn.accum += dt; if (defn.accum >= defn.time && defn.loop === 'hold') { - obj[target] = tvals[tvals.length-1]; + if (typeof target === 'string') + obj[target] = tvals[tvals.length-1]; + else + target(tvals[tvals.length-1]); + defn.pause(); defn.cb.call(obj); return; @@ -159,7 +163,10 @@ var Tween = { if (!defn.whole) nval = defn.ease(nval); - obj[target] = tvals[i].lerp(tvals[i+1], nval); + if (typeof target === 'string') + obj[target] = tvals[i].lerp(tvals[i+1], nval); + else + target(tvals[i].lerp(tvals[i+1],nval)); }; var playing = false; @@ -171,7 +178,10 @@ var Tween = { }; defn.restart = function() { defn.accum = 0; - obj[target] = tvals[0]; + if (typeof target === 'string') + obj[target] = tvals[0]; + else + target(tvals[0]); }; defn.stop = function() { if (!playing) return; defn.pause(); defn.restart(); }; defn.pause = function() { diff --git a/source/engine/jsffi.c b/source/engine/jsffi.c index 5e8f52b..4be5901 100644 --- a/source/engine/jsffi.c +++ b/source/engine/jsffi.c @@ -122,6 +122,8 @@ JSValue js_getpropidx(JSValue v, uint32_t i) return p; } +static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; } + uint64_t js2uint64(JSValue v) { int64_t i; @@ -1386,6 +1388,38 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv) str = js2str(argv[1]); ret = ints2js(gif_delays(str)); break; + case 225: + ret = ptr2js(cpRotaryLimitJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2number(argv[3]), js2number(argv[4]))); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; + case 226: + ret = ptr2js(cpDampedRotarySpringNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2number(argv[3]), js2number(argv[4]), js2number(argv[5]))); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; + case 227: + ret = ptr2js(cpDampedSpringNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2vec2(argv[3]).cp, js2vec2(argv[4]).cp, js2number(argv[5]), js2number(argv[6]), js2number(argv[7]))); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; + case 228: + ret = ptr2js(cpGrooveJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2vec2(argv[3]).cp, js2vec2(argv[4]).cp, js2vec2(argv[5]).cp)); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; + case 229: + ret = ptr2js(cpSlideJointNew(js2gameobject(argv[1])->body, js2gameobject(argv[2])->body, js2vec2(argv[3]).cp, js2vec2(argv[4]).cp, js2number(argv[5]), js2number(argv[6]))); + cpSpaceAddConstraint(space,js2ptr(ret)); + break; + case 230: + ret = ptr2js(cpSpaceAddConstraint(space, cpRatchetJointNew(js2body(argv[1]), js2body(argv[2]), js2number(argv[3]), js2number(argv[4])))); + break; + case 231: + ret = ptr2js(cpSpaceAddConstraint(space, cpSimpleMotorNew(js2body(argv[1]), js2body(argv[2]), js2number(argv[3])))); + break; + case 232: + ret = num2js(js2sprite(argv[1])->parallax); + break; + case 233: + js2sprite(argv[1])->parallax = js2number(argv[2]); + break; } if (str) diff --git a/source/engine/particle.c b/source/engine/particle.c index 379eac8..5f2f0fd 100644 --- a/source/engine/particle.c +++ b/source/engine/particle.c @@ -79,8 +79,8 @@ emitter *make_emitter() { e->particles[i].life = 0; e->life = 10; - e->explosiveness = 0; - e->tte = e->life/e->max; + e->explosiveness = 1; + e->tte = lerp(e->life/e->max, 0, e->explosiveness); e->color = color_white; e->scale = 20; arrpush(emitters,e); @@ -179,6 +179,6 @@ void emitter_step(emitter *e, double dt) { e->tte-=dt; if (e->tte <= 0) { emitter_emit(e,1); - e->tte = e->life/e->max; + e->tte = lerp(e->life/e->max,0,e->explosiveness); } } diff --git a/source/engine/render.h b/source/engine/render.h index d326b2b..e73e58e 100644 --- a/source/engine/render.h +++ b/source/engine/render.h @@ -115,4 +115,10 @@ struct glrect { struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh); float *rgba2floats(float *r, struct rgba c); extern sg_blend_state blend_trans; + +static inline float lerp(float a, float b, float f) +{ + return a * (1.0-f)+(b*f); +} + #endif diff --git a/source/engine/sprite.c b/source/engine/sprite.c index 11231dc..87d3d56 100644 --- a/source/engine/sprite.c +++ b/source/engine/sprite.c @@ -60,7 +60,8 @@ int make_sprite(gameobject *go) { .go = go, .next = -1, .enabled = 1, - .drawmode = DRAW_SIMPLE + .drawmode = DRAW_SIMPLE, + .parallax = 1 }; int id; freelist_grab(id, sprites); @@ -143,6 +144,7 @@ void sprite_initialize() { [1].format = SG_VERTEXFORMAT_FLOAT2, [2].format = SG_VERTEXFORMAT_UBYTE4N, [3].format = SG_VERTEXFORMAT_UBYTE4N}}, +// [4].format = SG_VERTEXFORMAT_FLOAT}}, .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP, .label = "sprite pipeline", .colors[0].blend = blend_trans, @@ -183,7 +185,7 @@ void sprite_initialize() { }); } -void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, HMM_Vec2 wrapscale, struct rgba emissive) { +void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba color, int wrap, HMM_Vec2 wrapoffset, HMM_Vec2 wrapscale, struct rgba emissive, float parallax) { struct sprite_vert verts[4]; float w = tex->width*st_s_w(r); float h = tex->height*st_s_h(r); @@ -226,17 +228,20 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo void sprite_draw(struct sprite *sprite) { if (!sprite->tex) return; - HMM_Mat3 m = t_go2world(sprite->go); + transform2d t = go2t(sprite->go); + t.pos.x += (cam_pos().x - (cam_pos().x/sprite->parallax)); + t.pos.y += (cam_pos().y - (cam_pos().y/sprite->parallax)); + HMM_Mat3 m = transform2d2mat(t); HMM_Mat3 sm = transform2d2mat(sprite->t); - tex_draw(sprite->tex, HMM_MulM3(m, sm), sprite->frame, sprite->color, sprite->drawmode, (HMM_Vec2){0,0}, sprite->t.scale, sprite->emissive); + tex_draw(sprite->tex, HMM_MulM3(m, sm), sprite->frame, sprite->color, sprite->drawmode, (HMM_Vec2){0,0}, sprite->t.scale, sprite->emissive, sprite->parallax); } void gui_draw_img(const char *img, transform2d t, int wrap, HMM_Vec2 wrapoffset, float wrapscale, struct rgba color) { sg_apply_pipeline(pip_sprite); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj)); struct Texture *tex = texture_pullfromfile(img); - tex_draw(tex, transform2d2mat(t), tex_get_rect(tex), color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}); + tex_draw(tex, transform2d2mat(t), tex_get_rect(tex), color, wrap, wrapoffset, (HMM_Vec2){wrapscale,wrapscale}, (struct rgba){0,0,0,0}, 0); } void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color) diff --git a/source/engine/sprite.h b/source/engine/sprite.h index 03a7292..a2a43e8 100644 --- a/source/engine/sprite.h +++ b/source/engine/sprite.h @@ -20,6 +20,7 @@ struct sprite { int enabled; int next; int drawmode; + float parallax; }; int make_sprite(gameobject *go); diff --git a/source/engine/yugine.c b/source/engine/yugine.c index ebb34c8..892ee23 100644 --- a/source/engine/yugine.c +++ b/source/engine/yugine.c @@ -103,10 +103,10 @@ void c_init() { window_resize(sapp_width(), sapp_height()); script_evalf("Game.init();"); - particle_init(); -// emitter *e = make_emitter(); -// e->texture = texture_pullfromfile("bolt.gif"); -// start_emitter(e); +/* particle_init(); + emitter *e = make_emitter(); + e->texture = texture_pullfromfile("bolt.gif"); + start_emitter(e);*/ } int frame_fps() { return 1.0/sapp_frame_duration(); } diff --git a/source/shaders/sprite.sglsl b/source/shaders/sprite.sglsl index bd29e9b..3bc696b 100644 --- a/source/shaders/sprite.sglsl +++ b/source/shaders/sprite.sglsl @@ -15,7 +15,7 @@ void main() fcolor = vc; femissive = emissive; texcoords = uv; - gl_Position = proj * vec4(vertex, 0.0, 1.0); + gl_Position = proj * vec4(vertex, 0, 1.0); } @end