tween functions

This commit is contained in:
John Alanbrook 2024-01-01 13:44:43 +00:00
parent 6aa44042d7
commit 2983e9f3c6
10 changed files with 133 additions and 18 deletions

View file

@ -144,6 +144,8 @@ component.sprite.impl = {
get color() {return cmd(148,this.id);}, get color() {return cmd(148,this.id);},
get pos() { return cmd(111, this.id); }, get pos() { return cmd(111, this.id); },
set pos(x) { cmd(37,this.id,x); }, 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); }, get angle() { return cmd(217,this.id); },
set angle(x) { cmd(218,this.id,x); }, set angle(x) { cmd(218,this.id,x); },
get scale() { return cmd(215, this.id); }, get scale() { return cmd(215, this.id); },
@ -287,7 +289,7 @@ var SpriteAnim = {
return anim; return anim;
}; };
var json = IO.slurp(ase); var json = IO.slurp(path);
json = JSON.parse(json); json = JSON.parse(json);
var anims = {}; var anims = {};
var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames); var frames = Array.isArray(json.frames) ? json.frames : Object.values(json.frames);
@ -859,6 +861,13 @@ component.circle2d.impl = Object.mix({
}, collider2d.impl); }, collider2d.impl);
component.particle = Object.copy(component, {
get pos() {},
set pos(x) {},
get angle() {},
set angle(x) {},
});
/* ASSETS */ /* ASSETS */

View file

@ -197,15 +197,55 @@ var gameobject = {
pin(to) { pin(to) {
var p = cmd(222,this.body, to.body); 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) { pivot(to, piv) {
piv ??= this.worldpos(); piv ??= this.worldpos();
var p = cmd(221,this.body,to.body,piv); 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; phase ??= 1;
ratio ??= 1; ratio ??= 1;
var phase = this.angle - to.angle;
var p = cmd(223,this.body,to.body,phase,ratio); 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) { path_from(o) {
var p = this.toString(); var p = this.toString();
@ -713,6 +753,16 @@ gameobject.doc = {
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.', cry: 'Make a sound. Can only make one at a time.',
add_component: 'Add a component to the object by name.', 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 */ /* Default objects */

View file

@ -140,7 +140,11 @@ var Tween = {
defn.fn = function(dt) { defn.fn = function(dt) {
defn.accum += dt; defn.accum += dt;
if (defn.accum >= defn.time && defn.loop === 'hold') { 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.pause();
defn.cb.call(obj); defn.cb.call(obj);
return; return;
@ -159,7 +163,10 @@ var Tween = {
if (!defn.whole) if (!defn.whole)
nval = defn.ease(nval); 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; var playing = false;
@ -171,7 +178,10 @@ var Tween = {
}; };
defn.restart = function() { defn.restart = function() {
defn.accum = 0; 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.stop = function() { if (!playing) return; defn.pause(); defn.restart(); };
defn.pause = function() { defn.pause = function() {

View file

@ -122,6 +122,8 @@ JSValue js_getpropidx(JSValue v, uint32_t i)
return p; return p;
} }
static inline cpBody *js2body(JSValue v) { return js2gameobject(v)->body; }
uint64_t js2uint64(JSValue v) uint64_t js2uint64(JSValue v)
{ {
int64_t i; int64_t i;
@ -1386,6 +1388,38 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
str = js2str(argv[1]); str = js2str(argv[1]);
ret = ints2js(gif_delays(str)); ret = ints2js(gif_delays(str));
break; 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) if (str)

View file

@ -79,8 +79,8 @@ emitter *make_emitter() {
e->particles[i].life = 0; e->particles[i].life = 0;
e->life = 10; e->life = 10;
e->explosiveness = 0; e->explosiveness = 1;
e->tte = e->life/e->max; e->tte = lerp(e->life/e->max, 0, e->explosiveness);
e->color = color_white; e->color = color_white;
e->scale = 20; e->scale = 20;
arrpush(emitters,e); arrpush(emitters,e);
@ -179,6 +179,6 @@ void emitter_step(emitter *e, double dt) {
e->tte-=dt; e->tte-=dt;
if (e->tte <= 0) { if (e->tte <= 0) {
emitter_emit(e,1); emitter_emit(e,1);
e->tte = e->life/e->max; e->tte = lerp(e->life/e->max,0,e->explosiveness);
} }
} }

View file

@ -115,4 +115,10 @@ struct glrect {
struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh); struct boundingbox cwh2bb(HMM_Vec2 c, HMM_Vec2 wh);
float *rgba2floats(float *r, struct rgba c); float *rgba2floats(float *r, struct rgba c);
extern sg_blend_state blend_trans; extern sg_blend_state blend_trans;
static inline float lerp(float a, float b, float f)
{
return a * (1.0-f)+(b*f);
}
#endif #endif

View file

@ -60,7 +60,8 @@ int make_sprite(gameobject *go) {
.go = go, .go = go,
.next = -1, .next = -1,
.enabled = 1, .enabled = 1,
.drawmode = DRAW_SIMPLE .drawmode = DRAW_SIMPLE,
.parallax = 1
}; };
int id; int id;
freelist_grab(id, sprites); freelist_grab(id, sprites);
@ -143,6 +144,7 @@ void sprite_initialize() {
[1].format = SG_VERTEXFORMAT_FLOAT2, [1].format = SG_VERTEXFORMAT_FLOAT2,
[2].format = SG_VERTEXFORMAT_UBYTE4N, [2].format = SG_VERTEXFORMAT_UBYTE4N,
[3].format = SG_VERTEXFORMAT_UBYTE4N}}, [3].format = SG_VERTEXFORMAT_UBYTE4N}},
// [4].format = SG_VERTEXFORMAT_FLOAT}},
.primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP, .primitive_type = SG_PRIMITIVETYPE_TRIANGLE_STRIP,
.label = "sprite pipeline", .label = "sprite pipeline",
.colors[0].blend = blend_trans, .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]; struct sprite_vert verts[4];
float w = tex->width*st_s_w(r); float w = tex->width*st_s_w(r);
float h = tex->height*st_s_h(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) { void sprite_draw(struct sprite *sprite) {
if (!sprite->tex) return; 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); 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) { 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_pipeline(pip_sprite);
sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj)); sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE_REF(hudproj));
struct Texture *tex = texture_pullfromfile(img); 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) void slice9_draw(const char *img, HMM_Vec2 pos, HMM_Vec2 dimensions, struct rgba color)

View file

@ -20,6 +20,7 @@ struct sprite {
int enabled; int enabled;
int next; int next;
int drawmode; int drawmode;
float parallax;
}; };
int make_sprite(gameobject *go); int make_sprite(gameobject *go);

View file

@ -103,10 +103,10 @@ void c_init() {
window_resize(sapp_width(), sapp_height()); window_resize(sapp_width(), sapp_height());
script_evalf("Game.init();"); script_evalf("Game.init();");
particle_init(); /* particle_init();
// emitter *e = make_emitter(); emitter *e = make_emitter();
// e->texture = texture_pullfromfile("bolt.gif"); e->texture = texture_pullfromfile("bolt.gif");
// start_emitter(e); start_emitter(e);*/
} }
int frame_fps() { return 1.0/sapp_frame_duration(); } int frame_fps() { return 1.0/sapp_frame_duration(); }

View file

@ -15,7 +15,7 @@ void main()
fcolor = vc; fcolor = vc;
femissive = emissive; femissive = emissive;
texcoords = uv; texcoords = uv;
gl_Position = proj * vec4(vertex, 0.0, 1.0); gl_Position = proj * vec4(vertex, 0, 1.0);
} }
@end @end