work
This commit is contained in:
parent
bea5b326cf
commit
d3cb9278a9
|
@ -32,6 +32,24 @@ associated script file can access.
|
|||
While playing ...
|
||||
* F7 Stop
|
||||
|
||||
.Level model
|
||||
The game world is made up of objects. Levels are collections of
|
||||
objects. The topmost level is called "World". Objects are spawned into
|
||||
a specific level. If none are explicitly given, objects are spawned
|
||||
into World. Objects in turn are made up of components - sprites,
|
||||
colliders, and so on. Accessing an object might go like this:
|
||||
|
||||
World.level1.enemy1.sprite.path = "brick.png";
|
||||
|
||||
To set the image of enemy1 in level 1's sprite.
|
||||
|
||||
.Textures & images
|
||||
A sprite is a display of a specific texture in the game world. The
|
||||
underlying texture has values associated with it, like how it should
|
||||
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
|
||||
|
|
|
@ -41,8 +41,8 @@ void set_cat_mask(int cat, unsigned int mask)
|
|||
void color2float(struct color color, float *fcolor)
|
||||
{
|
||||
fcolor[0] = (float)color.r/255;
|
||||
fcolor[1] = (float)color.b/255;
|
||||
fcolor[2] = (float)color.g/255;
|
||||
fcolor[1] = (float)color.g/255;
|
||||
fcolor[2] = (float)color.b/255;
|
||||
}
|
||||
|
||||
struct color float2color(float *fcolor)
|
||||
|
|
|
@ -65,6 +65,11 @@ double js2number(JSValue v)
|
|||
return g;
|
||||
}
|
||||
|
||||
int js2bool(JSValue v)
|
||||
{
|
||||
return JS_ToBool(js,v);
|
||||
}
|
||||
|
||||
JSValue float2js(double g)
|
||||
{
|
||||
return JS_NewFloat64(js,g);
|
||||
|
@ -931,6 +936,23 @@ JSValue duk_cmd(JSContext *js, JSValueConst this, int argc, JSValueConst *argv)
|
|||
|
||||
case 93:
|
||||
ret = int2js(logLevel);
|
||||
break;
|
||||
|
||||
case 94:
|
||||
str = JS_ToCString(js,argv[1]);
|
||||
texture_pullfromfile(str)->opts.mips = js2bool(argv[2]);
|
||||
texture_sync(str);
|
||||
break;
|
||||
|
||||
case 95:
|
||||
str = JS_ToCString(js,argv[1]);
|
||||
texture_pullfromfile(str)->opts.sprite = js2bool(argv[2]);
|
||||
texture_sync(str);
|
||||
break;
|
||||
|
||||
case 96:
|
||||
color2float(js2color(argv[2]), id2sprite(js2int(argv[1]))->color);
|
||||
break;
|
||||
}
|
||||
|
||||
if (str)
|
||||
|
@ -1237,7 +1259,6 @@ JSValue duk_make_sprite(JSContext *js, JSValueConst this, int argc, JSValueConst
|
|||
JS_FreeCString(js,path);
|
||||
|
||||
return JS_NewInt64(js, sprite);
|
||||
|
||||
}
|
||||
|
||||
/* Make anim from texture */
|
||||
|
|
|
@ -189,6 +189,7 @@ void joystick_cb(int jid, int event)
|
|||
|
||||
JSValue jsgamepadstr[15];
|
||||
JSValue jsaxesstr[4];
|
||||
JSValue jsaxis;
|
||||
|
||||
void input_init()
|
||||
{
|
||||
|
@ -205,10 +206,11 @@ void input_init()
|
|||
for (int b = 0; b < 15; b++)
|
||||
jsgamepadstr[b] = str2js(gamepad2str(b));
|
||||
|
||||
jsaxesstr[0] = str2js("axis_ljoy");
|
||||
jsaxesstr[1] = str2js("axis_rjoy");
|
||||
jsaxesstr[2] = str2js("axis_ltrigger");
|
||||
jsaxesstr[3] = str2js("axis_rtrigger");
|
||||
jsaxesstr[0] = str2js("ljoy");
|
||||
jsaxesstr[1] = str2js("rjoy");
|
||||
jsaxesstr[2] = str2js("ltrigger");
|
||||
jsaxesstr[3] = str2js("rtrigger");
|
||||
jsaxis = str2js("axis");
|
||||
|
||||
/* Grab all joysticks initially present */
|
||||
for (int i = 0; i < 16; i++)
|
||||
|
@ -397,7 +399,7 @@ void input_poll(double wait)
|
|||
GLFWgamepadstate state;
|
||||
if (!glfwGetGamepadState(joysticks[i].id, &state)) continue;
|
||||
|
||||
JSValue argv[3];
|
||||
JSValue argv[4];
|
||||
argv[0] = num_cache[joysticks[i].id];
|
||||
for (int b = 0; b < 15; b++) {
|
||||
argv[1] = jsgamepadstr[b];
|
||||
|
@ -417,30 +419,37 @@ void input_poll(double wait)
|
|||
}
|
||||
}
|
||||
|
||||
argv[2] = jsaxis;
|
||||
|
||||
float deadzone = 0.05;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
state.axes[i] = fabs(state.axes[i]) > deadzone ? state.axes[i] : 0;
|
||||
|
||||
argv[1] = jsaxesstr[0];
|
||||
cpVect v;
|
||||
v.x = state.axes[0];
|
||||
v.y = -state.axes[1];
|
||||
argv[2] = vec2js(v);
|
||||
script_callee(gamepad_callee,3,argv);
|
||||
JS_FreeValue(js, argv[2]);
|
||||
argv[3] = vec2js(v);
|
||||
script_callee(gamepad_callee,4,argv);
|
||||
JS_FreeValue(js, argv[3]);
|
||||
|
||||
argv[1] = jsaxesstr[1];
|
||||
v.x = state.axes[2];
|
||||
v.y = -state.axes[3];
|
||||
argv[2] = vec2js(v);
|
||||
script_callee(gamepad_callee,3,argv);
|
||||
JS_FreeValue(js, argv[2]);
|
||||
argv[3] = vec2js(v);
|
||||
script_callee(gamepad_callee,4,argv);
|
||||
JS_FreeValue(js, argv[3]);
|
||||
|
||||
argv[1] = jsaxesstr[2];
|
||||
argv[2] = num2js((state.axes[4]+1)/2);
|
||||
script_callee(gamepad_callee,3,argv);
|
||||
JS_FreeValue(js, argv[2]);
|
||||
argv[3] = num2js((state.axes[4]+1)/2);
|
||||
script_callee(gamepad_callee,4,argv);
|
||||
JS_FreeValue(js, argv[3]);
|
||||
|
||||
argv[1] = jsaxesstr[3];
|
||||
argv[2] = num2js((state.axes[5]+1)/2);
|
||||
script_callee(gamepad_callee,3,argv);
|
||||
JS_FreeValue(js, argv[2]);
|
||||
argv[3] = num2js((state.axes[5]+1)/2);
|
||||
script_callee(gamepad_callee,4,argv);
|
||||
JS_FreeValue(js, argv[3]);
|
||||
|
||||
joysticks[i].state = state;
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ void sprite_initialize()
|
|||
glEnableVertexAttribArray(0);
|
||||
}
|
||||
|
||||
void tex_draw(struct Texture *tex, float pos[2], float angle, float size[2], float offset[2], struct glrect r) {
|
||||
void tex_draw(struct Texture *tex, float pos[2], float angle, float size[2], float offset[2], struct glrect r, mfloat_t color[3]) {
|
||||
mfloat_t model[16] = { 0.f };
|
||||
mfloat_t r_model[16] = { 0.f };
|
||||
mfloat_t s_model[16] = { 0.f };
|
||||
|
@ -142,9 +142,8 @@ void tex_draw(struct Texture *tex, float pos[2], float angle, float size[2], flo
|
|||
|
||||
mat4_translate_vec2(model, pos);
|
||||
|
||||
float white[3] = { 1.f, 1.f, 1.f };
|
||||
shader_setmat4(spriteShader, "model", model);
|
||||
shader_setvec3(spriteShader, "spriteColor", white);
|
||||
shader_setvec3(spriteShader, "spriteColor", color);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
|
@ -173,7 +172,7 @@ void sprite_draw(struct sprite *sprite)
|
|||
cpVect cpos = cpBodyGetPosition(go->body);
|
||||
float pos[2] = {cpos.x, cpos.y};
|
||||
float size[2] = { sprite->size[0] * go->scale * go->flipx, sprite->size[1] * go->scale * go->flipy };
|
||||
tex_draw(sprite->tex, pos, cpBodyGetAngle(go->body), size, sprite->pos, sprite->frame);
|
||||
tex_draw(sprite->tex, pos, cpBodyGetAngle(go->body), size, sprite->pos, sprite->frame, sprite->color);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,7 +189,8 @@ void gui_draw_img(const char *img, float x, float y) {
|
|||
float pos[2] = {x, y};
|
||||
float size[2] = {1.f, 1.f};
|
||||
float offset[2] = { 0.f, 0.f };
|
||||
tex_draw(tex, pos, 0.f, size, offset, tex_get_rect(tex));
|
||||
float white[3] = {1.f,1.f,1.f};
|
||||
tex_draw(tex, pos, 0.f, size, offset, tex_get_rect(tex), white);
|
||||
}
|
||||
|
||||
void sprite_setframe(struct sprite *sprite, struct glrect *frame)
|
||||
|
|
|
@ -34,24 +34,11 @@ struct Texture *texture_pullfromfile(const char *path)
|
|||
|
||||
YughInfo("Loading texture %s.", path);
|
||||
struct Texture *tex = calloc(1, sizeof(*tex));
|
||||
|
||||
/* Find texture's asset; otherwise load default asset */
|
||||
JSON_Value *rv = json_parse_file("texture.asset");
|
||||
JSON_Object *ro = json_value_get_object(rv);
|
||||
tex->opts.sprite = json_object_get_boolean(ro, "sprite");
|
||||
tex->opts.mips = json_object_get_boolean(ro, "mips");
|
||||
json_value_free(rv);
|
||||
|
||||
tex->opts.sprite = 1;
|
||||
tex->opts.mips = 0;
|
||||
tex->opts.gamma = 0;
|
||||
|
||||
|
||||
tex->anim.ms = 2;
|
||||
tex->anim.tex = tex;
|
||||
texanim_fromframes(&tex->anim, 2);
|
||||
tex->anim.loop = 1;
|
||||
|
||||
int n;
|
||||
|
||||
unsigned char *data = stbi_load(path, &tex->width, &tex->height, &n, 4);
|
||||
|
||||
if (data == NULL) {
|
||||
|
@ -89,11 +76,21 @@ struct Texture *texture_pullfromfile(const char *path)
|
|||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
if (tex->opts.sprite) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
if (tex->opts.mips) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
if (tex->opts.mips) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
|
@ -107,6 +104,36 @@ struct Texture *texture_pullfromfile(const char *path)
|
|||
return tex;
|
||||
}
|
||||
|
||||
void texture_sync(const char *path)
|
||||
{
|
||||
struct Texture *tex = texture_pullfromfile(path);
|
||||
glBindTexture(GL_TEXTURE_2D, tex->id);
|
||||
if (tex->opts.mips)
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
if (tex->opts.sprite) {
|
||||
if (tex->opts.mips) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST_MIPMAP_NEAREST);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
} else {
|
||||
if (tex->opts.mips) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
} else {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
}
|
||||
}
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||
|
||||
}
|
||||
|
||||
char *tex_get_path(struct Texture *tex) {
|
||||
for (int i = 0; i < shlen(texhash); i++) {
|
||||
if (tex == texhash[i].value) {
|
||||
|
|
|
@ -68,6 +68,7 @@ struct Texture {
|
|||
|
||||
struct Texture *texture_pullfromfile(const char *path); // Create texture from image
|
||||
struct Texture *texture_loadfromfile(const char *path); // Create texture & load to gpu
|
||||
void texture_sync(const char *path);
|
||||
struct Texture *str2tex(const char *path);
|
||||
void tex_gpu_reload(struct Texture *tex); // gpu_free then gpu_load
|
||||
void tex_gpu_free(struct Texture *tex); // Remove texture data from gpu
|
||||
|
|
|
@ -105,6 +105,10 @@ var sprite = clone(component, {
|
|||
cmd(37, this.id, this.pos);
|
||||
},
|
||||
|
||||
set color(x) {
|
||||
cmd(96, this.id, x);
|
||||
},
|
||||
|
||||
load_img(img) {
|
||||
cmd(12, this.id, img, this.rect);
|
||||
},
|
||||
|
@ -679,3 +683,35 @@ var circle2d = clone(collider2d, {
|
|||
this.coll_sync();
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
/* ASSETS */
|
||||
|
||||
var Texture = {
|
||||
mipmaps(path, x) {
|
||||
cmd(94, path, x);
|
||||
},
|
||||
|
||||
sprite(path, x) {
|
||||
cmd(95, path, x);
|
||||
},
|
||||
};
|
||||
|
||||
var Resources = {
|
||||
load(path) {
|
||||
if (path in this)
|
||||
return this[path];
|
||||
|
||||
var src = {};
|
||||
this[path] = src;
|
||||
src.path = path;
|
||||
|
||||
if (!IO.exists(`${path}.asset`))
|
||||
return this[path];
|
||||
|
||||
var data = JSON.parse(IO.slurp(`${path}.asset`));
|
||||
Object.assign(src,data);
|
||||
return this[path];
|
||||
|
||||
},
|
||||
};
|
||||
|
|
|
@ -420,7 +420,7 @@ var Action = {
|
|||
var Player = {
|
||||
players: [],
|
||||
input(fn, ...args) {
|
||||
this.pawns.forEach(x => { if (fn in x) x[fn](...args); });
|
||||
this.pawns.forEach(x => x[fn]?.(...args));
|
||||
},
|
||||
|
||||
control(pawn) {
|
||||
|
@ -440,6 +440,7 @@ for (var i = 0; i < 4; i++) {
|
|||
}
|
||||
|
||||
function state2str(state) {
|
||||
if (typeof state === 'string') return state;
|
||||
switch (state) {
|
||||
case 0:
|
||||
return "down";
|
||||
|
@ -723,6 +724,7 @@ var Game = {
|
|||
},
|
||||
};
|
||||
|
||||
|
||||
var Level = {
|
||||
levels: [],
|
||||
objects: [],
|
||||
|
@ -922,6 +924,8 @@ var Level = {
|
|||
newobj.defn('level', this);
|
||||
this.objects.push(newobj);
|
||||
Game.register_obj(newobj);
|
||||
newobj.setup?.();
|
||||
newobj.start?.();
|
||||
return newobj;
|
||||
},
|
||||
|
||||
|
@ -1185,9 +1189,11 @@ var Level = {
|
|||
get left() {
|
||||
return [-1,0].rotate(Math.deg2rad(this.angle));
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
var World = Level.create();
|
||||
World.name = "World";
|
||||
|
||||
var gameobjects = {};
|
||||
|
||||
/* Returns the index of the smallest element in array, defined by a function that returns a number */
|
||||
|
@ -1211,7 +1217,13 @@ 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(); },
|
||||
set scale(x) {
|
||||
this._scale = Math.max(0,x);
|
||||
if (this.body > -1)
|
||||
cmd(36, this.body, this._scale);
|
||||
|
||||
this.sync();
|
||||
},
|
||||
_scale: 1.0,
|
||||
|
||||
save: true,
|
||||
|
@ -1310,6 +1322,26 @@ var gameobject = {
|
|||
body: -1,
|
||||
controlled: false,
|
||||
|
||||
get properties() {
|
||||
var keys = [];
|
||||
for (var key of Object.keys(this)) {
|
||||
if (key.startsWith("_"))
|
||||
keys.push(key.substring(1));
|
||||
else
|
||||
keys.push(key);
|
||||
}
|
||||
|
||||
return keys;
|
||||
},
|
||||
|
||||
toJSON() {
|
||||
var obj = {};
|
||||
for (var key of this.properties)
|
||||
obj[key] = this[key];
|
||||
|
||||
return obj;
|
||||
},
|
||||
|
||||
set_center(pos) {
|
||||
var change = pos.sub(this.pos);
|
||||
this.pos = pos;
|
||||
|
@ -1515,6 +1547,7 @@ var gameobject = {
|
|||
this2world(pos) { return cmd(71, this.body,pos); },
|
||||
|
||||
make(props, level) {
|
||||
level ??= World;
|
||||
var obj = Object.create(this);
|
||||
this.instances.push(obj);
|
||||
obj.toString = function() {
|
||||
|
@ -1584,39 +1617,11 @@ var gameobject = {
|
|||
}
|
||||
|
||||
|
||||
var locks = ['draw_layer', 'friction','elasticity', 'visible', 'body', 'flipx', 'flipy', 'scale', 'controlled', 'selectable', 'save', 'velocity', 'angularvelocity', 'alive', 'boundingbox', 'name'];
|
||||
var locks = ['draw_layer', 'friction','elasticity', 'visible', 'body', 'flipx', 'flipy', '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});
|
||||
});
|
||||
|
||||
function private_non_enumerable(obj) {
|
||||
for (var key in obj) {
|
||||
if (key.startsWith('_'))
|
||||
Object.defineProperty(obj, key, {enumerable:false});
|
||||
}
|
||||
}
|
||||
|
||||
function add_sync_prop(obj, prop, syncfn) {
|
||||
var hidden = "_"+prop;
|
||||
Log.info(hidden);
|
||||
Object.defineProperty(obj, hidden, {
|
||||
value: null,
|
||||
writable: true,
|
||||
});
|
||||
|
||||
Object.defineProperty(obj, prop, {
|
||||
get: function() { return obj[hidden]; },
|
||||
set: function(x) {
|
||||
obj[hidden] = x;
|
||||
syncfn(obj[hidden]);
|
||||
},
|
||||
enumerable: true,
|
||||
});
|
||||
|
||||
return obj;
|
||||
|
||||
};
|
||||
|
||||
/* Load configs */
|
||||
function load_configs(file) {
|
||||
var configs = JSON.parse(IO.slurp(file));
|
||||
|
@ -1761,5 +1766,3 @@ for (var key in prototypes) {
|
|||
}
|
||||
|
||||
function save_gameobjects_as_prototypes() { slurpwrite(JSON.stringify(gameobjects,null,2), "proto.json"); };
|
||||
|
||||
Resources = {};
|
||||
|
|
Loading…
Reference in a new issue