update docs

This commit is contained in:
John Alanbrook 2023-11-12 02:01:42 +00:00
parent 21464c44fb
commit 51438a5328
10 changed files with 146 additions and 162 deletions

View file

@ -8,10 +8,6 @@ In addition, a window showing each entity underneath that entity are shown.
The desktop is the topmost object that exists in the editor. Instead of editing specific files, you simply load them into your desktop, and go from there. This makes it easier to see two different entities simultaneously so you can ensure changes to one are congruous with the vision for the others. The desktop is the topmost object that exists in the editor. Instead of editing specific files, you simply load them into your desktop, and go from there. This makes it easier to see two different entities simultaneously so you can ensure changes to one are congruous with the vision for the others.
## Ur-types
Ur-types are what are loaded into the game world. They are templates for creating entities.
## *'s and %'s ## *'s and %'s
When a '*' is seen next to an entity's name, that means it is altered compared to its ur-type and is unsaved. There are a number of ways to take care of a '*'. If you do not do one of the below, something on the entity will be lost. When a '*' is seen next to an entity's name, that means it is altered compared to its ur-type and is unsaved. There are a number of ways to take care of a '*'. If you do not do one of the below, something on the entity will be lost.

View file

@ -1,45 +1,36 @@
# Yugine # Primum
The yugine essentially is made of a sequence of levels. Levels can be Games are made of entities. Entities are made of components. Components can be thought of as properties that entities poses; entities are a collection of components. Components include things like drawables (textures, sprites), physical colliders, and more.
nested, they can be streamed in, or loaded one at a time. Levels are
made of levels.
Different "modes" of using the engine has unique sequences of level Entities can have control of other entities, in which case the one in control is the 'master' and the controlee the 'padawan'. When a master moves or rotates, all padawans move and rotate with it.
loading orders. Each level has an associated script file. Level
loading functions call the script file, as well as the level file. The
level file can be considered to be a container of objects that the
associated script file can access.
* Game start The first and most masterful entity is the Primum. The Primum has no components, and its rotation and position are zero. It defines the center of the game.
1. Engine scripts
2. config.js
3. game.lvl & game.js
* Editor ## Scripting
1. Engine scripts
2. config.js
3. editor.js
* Editor play There are a number of script hooks which are ran at particular times of engine loading. When a game starts ...
* F5 debug.lvl. Used for custom debug level testing. If doesn't exist, game.lvl is loaded. - config.js
* F6 game.lvl - game.js
* F7 Currently edited level
## Playing, editing, debugging When the editor starts ...
- editorconfig.js
Playing is playing your game. Controls are what are specified for your game. F5 can be pressed in the editor to test the game. In that case ...
- config.js
- debug.js
In debug builds, additional debug controls are available. For example, F12 brings up GUI debug boxes. C-M-f puts you into a flying camera mode, without pausing your game. And when play mode is left ...
- dbgret.js
The game can be paused to edit it. Most editor controls are available here, all of them essentially except for loading new levels, clearing the level, etc. An object can be clicked on and edited, objects can be moved, etc. ## Ur-types
Ur-types are what are loaded into the game world. They are templates for creating entities. Ur-types are defined by providing the engine with .jso files.
A prefab can be opened up to edit on its own, without breaking the currently played level. If you have a 'enemy.jso' file, then on game start you can spawn an enemy via 'Primum.spawn(ur.enemy)'. The 'ur' object holds all ur-types the game knows about.
In edit mode, there are no running scripts; only editing them. Ur-types are loaded on demand, or can be preloaded with 'prototypes.generate_ur()'.
## The ECS system ## The ECS system, revisited
There are two distinct items in the Primum: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world.
There are two distinct items in the Primum Machina: the Entity, and the Component. Components give qualities to Entities. An Entity is any real, tangible thing in the universe, and so every entity has a position. Components do not necessarily have a position; they can be things like the image that draws where the entity is located, and colliders that allow the entity to respond with the world.
### Components ### Components
The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. Javascript does the accounting to make or destroy the sprite as needed - but besides that initial startup, no scripting is done. The most "bare metal" are the components. These are essentially hooks into the engine that tell it how to do particular things. For example, to render a sprite, Javascript does no rendering, but rather tells the engine to create an image and render it in a particular spot. Javascript does the accounting to make or destroy the sprite as needed - but besides that initial startup, no scripting is done.
@ -88,9 +79,7 @@ Ur-ur, the thing all Ur-types derive from
- Variant 2A, overwritten values from Variant 2 - Variant 2A, overwritten values from Variant 2
- Ur-type 2 - Ur-type 2
All ur-types and variants can be created in the world, where they become a true blue ENTITY. Entities can be under entities infinitely. All ur-types and variants can be created in the world, where they become an entity. Entities can be under entities infinitely. (Master-padawan)
Ur-types have a specific combination of components. When a component is removed from an entity, the link to its ur-type breaks.
Entities have access to their ur-type through their .ur parameter. Each ur-type and variant likewise stores a list of entities that have been created from them. Entities have access to their ur-type through their .ur parameter. Each ur-type and variant likewise stores a list of entities that have been created from them.
@ -101,17 +90,9 @@ ur.type : the actual object
ur.instances : instances of it ur.instances : instances of it
ur.tag : the full name of it ur.tag : the full name of it
### Loading traits ### Diverting entities
Traits are defined by code and a data file. When an Ur-type is extended with a trait, the code is run, and then the data file contains modifications and
### Creating entities
Entities are like real world representations of an Ur-type. Ur-types exist only theoretically, but can then be spawned into a true entity in the game world.
An entity can diverge from its ur-type. When this happens, you can either revert the entity, copy how it's changed to its ur-type, or promote it to its own ur-type. An entity can diverge from its ur-type. When this happens, you can either revert the entity, copy how it's changed to its ur-type, or promote it to its own ur-type.
### Efficiency of all this
It is extremely cheap and fast to create entities. Ur-types work as a defined way for the engine to make an object, and can even cache deleted copies of them.
## Resources ## Resources
Assets can generally be used just with their filename. It will be loaded with default values. However, how the engine interprets it can be altered with a sidecar file, named "filename.asset", so "ball.png" will be modified via "ball.png.asset". These are typical JSON files. For images, specify gamma, if it's a sprite or texture, etc, for sound, specify its gain, etc. Assets can generally be used just with their filename. It will be loaded with default values. However, how the engine interprets it can be altered with a sidecar file, named "filename.asset", so "ball.png" will be modified via "ball.png.asset". These are typical JSON files. For images, specify gamma, if it's a sprite or texture, etc, for sound, specify its gain, etc.

View file

@ -562,7 +562,7 @@ var gameobject = {
obj.level = undefined; obj.level = undefined;
obj.reparent(level); obj.reparent(level);
Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level'); Object.hide(obj, 'ur','body', 'components', 'objects', '_ed', 'level', 'timers');
Object.dainty_assign(obj, this); Object.dainty_assign(obj, this);
obj.sync(); obj.sync();

View file

@ -198,7 +198,7 @@ struct phys2d_circle *Make2DCircle(int go) {
struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle)); struct phys2d_circle *new = malloc(sizeof(struct phys2d_circle));
new->radius = 10.f; new->radius = 10.f;
new->offset = cpvzero; new->offset = v2zero;
new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero)); new->shape.shape = cpSpaceAddShape(space, cpCircleShapeNew(id2go(go)->body, new->radius, cpvzero));
new->shape.debugdraw = phys2d_dbgdrawcircle; new->shape.debugdraw = phys2d_dbgdrawcircle;
@ -211,66 +211,33 @@ struct phys2d_circle *Make2DCircle(int go) {
} }
float phys2d_circle_moi(struct phys2d_circle *c, float m) { float phys2d_circle_moi(struct phys2d_circle *c, float m) {
return cpMomentForCircle(m, 0, c->radius, c->offset); return 1;
//TODO: Calculate correctly
//return cpMomentForCircle(m, 0, c->radius, c->offset);
} }
void phys2d_circledel(struct phys2d_circle *c) { void phys2d_circledel(struct phys2d_circle *c) {
phys2d_shape_del(&c->shape); phys2d_shape_del(&c->shape);
} }
cpVect world2go(struct gameobject *go, cpVect worldpos) { HMM_Vec2 bodytransformpoint(cpBody *body, HMM_Vec2 offset) {
cpTransform T = {0}; HMM_Vec2 pos;
cpVect pos = cpBodyGetPosition(go->body); pos.cp = cpBodyGetPosition(body);
worldpos.x -= pos.x; float d = sqrt(pow(offset.X, 2.f) + pow(offset.Y, 2.f));
worldpos.y -= pos.y; float a = atan2(offset.Y, offset.X) + cpBodyGetAngle(body);
// worldpos.x /= go->scale; pos.X += d * cos(a);
// worldpos.y /= go->scale; pos.Y += d * sin(a);
float angle = cpBodyGetAngle(go->body);
T.a = go->flipx * cos(-angle) / go->scale;
T.b = sin(-angle) / go->scale;
T.c = -sin(-angle) / go->scale;
T.d = go->flipy * cos(-angle) / go->scale;
worldpos = cpTransformPoint(T, worldpos);
return worldpos;
}
cpVect go2world(struct gameobject *go, cpVect gopos) {
cpVect pos = cpBodyGetPosition(go->body);
float angle = cpBodyGetAngle(go->body);
cpTransform T = {0};
T.a = go->scale * go->flipx * cos(angle);
T.b = sin(angle) * go->scale * go->flipx;
T.c = -sin(angle) * go->scale * go->flipy;
T.d = go->scale * go->flipy * cos(angle);
T.tx = pos.x;
T.ty = pos.y;
return cpTransformPoint(T, gopos);
}
cpVect gotransformpoint(struct gameobject *go, cpVect point) {
point.x *= go->scale * go->flipx;
point.y *= go->scale * go->flipy;
return point;
}
cpVect bodytransformpoint(cpBody *body, cpVect offset) {
cpVect pos = cpBodyGetPosition(body);
float d = sqrt(pow(offset.x, 2.f) + pow(offset.y, 2.f));
float a = atan2(offset.y, offset.x) + cpBodyGetAngle(body);
pos.x += d * cos(a);
pos.y += d * sin(a);
return pos; return pos;
} }
void phys2d_dbgdrawcpcirc(cpCircleShape *c) { void phys2d_dbgdrawcpcirc(cpCircleShape *c) {
cpVect pos = bodytransformpoint(cpShapeGetBody(c), cpCircleShapeGetOffset(c)); HMM_Vec2 pos = bodytransformpoint(cpShapeGetBody(c), (HMM_Vec2)cpCircleShapeGetOffset(c));
float radius = cpCircleShapeGetRadius(c); float radius = cpCircleShapeGetRadius(c);
struct rgba color = shape_color(c); struct rgba color = shape_color(c);
float seglen = cpShapeGetSensor(c) ? 5 : -1; float seglen = cpShapeGetSensor(c) ? 5 : -1;
draw_circle(pos, radius, 1, color, seglen); draw_circle(pos.cp, radius, 1, color, seglen);
color.a = col_alpha; color.a = col_alpha;
draw_circle(pos,radius,radius,color,-1); draw_circle(pos.cp,radius,radius,color,-1);
} }
void phys2d_dbgdrawcircle(struct phys2d_circle *circle) { void phys2d_dbgdrawcircle(struct phys2d_circle *circle) {
@ -280,11 +247,10 @@ void phys2d_dbgdrawcircle(struct phys2d_circle *circle) {
void phys2d_applycircle(struct phys2d_circle *circle) { void phys2d_applycircle(struct phys2d_circle *circle) {
struct gameobject *go = id2go(circle->shape.go); struct gameobject *go = id2go(circle->shape.go);
float radius = circle->radius * go->scale; float radius = circle->radius * HMM_LenSqrV2(go->scale.XY);
cpVect offset = gotransformpoint(go, circle->offset);
cpCircleShapeSetRadius(circle->shape.shape, radius); cpCircleShapeSetRadius(circle->shape.shape, radius);
cpCircleShapeSetOffset(circle->shape.shape, offset);
cpCircleShapeSetOffset(circle->shape.shape, HMM_MulV2(go->scale.XY, circle->offset).cp);
} }
/************* BOX2D ************/ /************* BOX2D ************/
@ -295,8 +261,7 @@ struct phys2d_box *Make2DBox(int go) {
new->w = 50.f; new->w = 50.f;
new->h = 50.f; new->h = 50.f;
new->r = 0.f; new->r = 0.f;
new->offset[0] = 0.f; new->offset = v2zero;
new->offset[1] = 0.f;
new->shape.go = go; new->shape.go = go;
new->shape.apply = phys2d_applybox; new->shape.apply = phys2d_applybox;
phys2d_applybox(new); phys2d_applybox(new);
@ -310,14 +275,14 @@ float phys2d_box_moi(struct phys2d_box *box, float m) {
return cpMomentForBox(m, box->w, box->h); return cpMomentForBox(m, box->w, box->h);
} }
cpTransform go2transform(struct gameobject *go, cpVect offset, float angle) { cpTransform trs2cpt(HMM_Vec2 t, float angle, HMM_Vec2 s) {
cpTransform T = {0}; cpTransform T;
T.a = cos(angle) * go->scale * go->flipx; T.a = cos(angle) * s.X;
T.b = -sin(angle) * go->scale * go->flipx; T.b = -sin(angle) * s.X;
T.c = sin(angle) * go->scale * go->flipy; T.c = sin(angle) * s.Y;
T.d = cos(angle) * go->scale * go->flipy; T.d = cos(angle) * s.Y;
T.tx = offset.x * go->scale; T.tx = t.X * s.X;
T.ty = offset.y * go->scale; T.ty = t.Y * s.Y;
return T; return T;
} }
@ -328,10 +293,7 @@ void phys2d_boxdel(struct phys2d_box *box) {
void phys2d_applybox(struct phys2d_box *box) { void phys2d_applybox(struct phys2d_box *box) {
phys2d_boxdel(box); phys2d_boxdel(box);
struct gameobject *go = id2go(box->shape.go); struct gameobject *go = id2go(box->shape.go);
cpVect off; cpTransform T = trs2cpt(box->offset, box->rotation, id2go(box->shape.go)->scale.XY);
off.x = box->offset[0];
off.y = box->offset[1];
cpTransform T = go2transform(id2go(box->shape.go), off, box->rotation);
float hh = box->h / 2.f; float hh = box->h / 2.f;
float hw = box->w / 2.f; float hw = box->w / 2.f;
cpVect verts[4] = {{-hw, -hh}, {hw, -hh}, {hw, hh}, {-hw, hh}}; cpVect verts[4] = {{-hw, -hh}, {hw, -hh}, {hw, hh}, {-hw, hh}};
@ -341,10 +303,10 @@ void phys2d_applybox(struct phys2d_box *box) {
void phys2d_dbgdrawbox(struct phys2d_box *box) { void phys2d_dbgdrawbox(struct phys2d_box *box) {
int n = cpPolyShapeGetCount(box->shape.shape); int n = cpPolyShapeGetCount(box->shape.shape);
cpVect points[n * 2]; HMM_Vec2 points[n * 2];
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++)
points[i] = bodytransformpoint(cpShapeGetBody(box->shape.shape), cpPolyShapeGetVert(box->shape.shape, i)); points[i] = bodytransformpoint(cpShapeGetBody(box->shape.shape), cpPolyShapeGetVert(box->shape.shape, i)).cp;
struct rgba c = shape_color(box->shape.shape); struct rgba c = shape_color(box->shape.shape);
struct rgba cl = c; struct rgba cl = c;
@ -386,7 +348,7 @@ void phys2d_polydel(struct phys2d_poly *poly) {
} }
void phys2d_polyaddvert(struct phys2d_poly *poly) { void phys2d_polyaddvert(struct phys2d_poly *poly) {
arrput(poly->points, cpvzero); arrput(poly->points, v2zero);
} }
void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) { void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
@ -395,8 +357,10 @@ void phys2d_poly_setverts(struct phys2d_poly *poly, cpVect *verts) {
arrfree(poly->points); arrfree(poly->points);
arrsetlen(poly->points, arrlen(verts)); arrsetlen(poly->points, arrlen(verts));
for (int i = 0; i < arrlen(verts); i++) for (int i = 0; i < arrlen(verts); i++) {
poly->points[i] = verts[i]; poly->points[i].X = verts[i].x;
poly->points[i].Y = verts[i].y;
}
phys2d_applypoly(poly); phys2d_applypoly(poly);
} }
@ -405,7 +369,7 @@ void phys2d_applypoly(struct phys2d_poly *poly) {
if (arrlen(poly->points) <= 0) return; if (arrlen(poly->points) <= 0) return;
struct gameobject *go = id2go(poly->shape.go); struct gameobject *go = id2go(poly->shape.go);
cpTransform T = go2transform(go, cpvzero, 0); cpTransform T = trs2cpt((HMM_Vec2){0,0}, 0, (HMM_Vec2){1,1});
cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T); cpPolyShapeSetVerts(poly->shape.shape, arrlen(poly->points), poly->points, T);
cpPolyShapeSetRadius(poly->shape.shape, poly->radius); cpPolyShapeSetRadius(poly->shape.shape, poly->radius);
@ -453,7 +417,7 @@ struct phys2d_edge *Make2DEdge(int go) {
float phys2d_edge_moi(struct phys2d_edge *edge, float m) { float phys2d_edge_moi(struct phys2d_edge *edge, float m) {
float moi = 0; float moi = 0;
for (int i = 0; i < arrlen(edge->points) - 1; i++) for (int i = 0; i < arrlen(edge->points) - 1; i++)
moi += cpMomentForSegment(m, edge->points[i], edge->points[i + 1], edge->thickness); moi += cpMomentForSegment(m, edge->points[i].cp, edge->points[i + 1].cp, edge->thickness);
return moi; return moi;
} }
@ -463,7 +427,7 @@ void phys2d_edgedel(struct phys2d_edge *edge) {
} }
void phys2d_edgeaddvert(struct phys2d_edge *edge) { void phys2d_edgeaddvert(struct phys2d_edge *edge) {
arrput(edge->points, cpvzero); arrput(edge->points, v2zero);
if (arrlen(edge->points) > 1) if (arrlen(edge->points) > 1)
arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(id2go(edge->shape.go)->body, cpvzero, cpvzero, edge->thickness))); arrput(edge->shapes, cpSpaceAddShape(space, cpSegmentShapeNew(id2go(edge->shape.go)->body, cpvzero, cpvzero, edge->thickness)));
@ -486,7 +450,7 @@ void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) {
} }
if (index != arrlen(edge->points)) { if (index != arrlen(edge->points)) {
cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1], edge->points[index]); cpSegmentShapeSetEndpoints(edge->shapes[index - 1], edge->points[index - 1].cp, edge->points[index].cp);
} }
cpSpaceRemoveShape(space, edge->shapes[index - 1]); cpSpaceRemoveShape(space, edge->shapes[index - 1]);
@ -498,7 +462,7 @@ void phys2d_edge_rmvert(struct phys2d_edge *edge, int index) {
void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val) { void phys2d_edge_setvert(struct phys2d_edge *edge, int index, cpVect val) {
assert(arrlen(edge->points) > index && index >= 0); assert(arrlen(edge->points) > index && index >= 0);
edge->points[index] = val; edge->points[index].cp = val;
phys2d_applyedge(edge); phys2d_applyedge(edge);
} }
@ -520,12 +484,12 @@ void phys2d_applyedge(struct phys2d_edge *edge) {
struct gameobject *go = id2go(edge->shape.go); struct gameobject *go = id2go(edge->shape.go);
for (int i = 0; i < arrlen(edge->shapes); i++) { for (int i = 0; i < arrlen(edge->shapes); i++) {
cpVect a = gotransformpoint(go, edge->points[i]); HMM_Vec2 a = goscale(go, edge->points[i]);
cpVect b = gotransformpoint(go, edge->points[i + 1]); HMM_Vec2 b = goscale(go, edge->points[i+1]);
cpSegmentShapeSetEndpoints(edge->shapes[i], a, b); cpSegmentShapeSetEndpoints(edge->shapes[i], a.cp, b.cp);
cpSegmentShapeSetRadius(edge->shapes[i], edge->thickness); cpSegmentShapeSetRadius(edge->shapes[i], edge->thickness);
if (i > 0 && i < arrlen(edge->shapes) - 1) if (i > 0 && i < arrlen(edge->shapes) - 1)
cpSegmentShapeSetNeighbors(edge->shapes[i], gotransformpoint(go, edge->points[i - 1]), gotransformpoint(go, edge->points[i + 2])); cpSegmentShapeSetNeighbors(edge->shapes[i], goscale(go,edge->points[i-1]).cp, goscale(go,edge->points[i+2]).cp);
go_shape_apply(NULL, edge->shapes[i], go); go_shape_apply(NULL, edge->shapes[i], go);
cpShapeSetUserData(edge->shapes[i], &edge->shape); cpShapeSetUserData(edge->shapes[i], &edge->shape);
} }
@ -544,11 +508,11 @@ void phys2d_dbgdrawedge(struct phys2d_edge *edge) {
if (arrlen(edge->shapes) < 1) return; if (arrlen(edge->shapes) < 1) return;
cpVect drawpoints[arrlen(edge->points)]; HMM_Vec2 drawpoints[arrlen(edge->points)];
struct gameobject *go = id2go(edge->shape.go); struct gameobject *go = id2go(edge->shape.go);
for (int i = 0; i < arrlen(edge->points); i++) { for (int i = 0; i < arrlen(edge->points); i++) {
drawpoints[i] = gotransformpoint(go, edge->points[i]); drawpoints[i] = goscale(go, edge->points[i]);
drawpoints[i] = bodytransformpoint(cpShapeGetBody(edge->shapes[0]), drawpoints[i]); drawpoints[i] = bodytransformpoint(cpShapeGetBody(edge->shapes[0]), drawpoints[i]);
} }

View file

@ -33,21 +33,21 @@ struct phys2d_shape {
/* Circles are the fastest collier type */ /* Circles are the fastest collier type */
struct phys2d_circle { struct phys2d_circle {
float radius; float radius;
cpVect offset; HMM_Vec2 offset;
struct phys2d_shape shape; struct phys2d_shape shape;
}; };
/* A single segment */ /* A single segment */
struct phys2d_segment { struct phys2d_segment {
float a[2]; HMM_Vec2 a;
float b[2]; HMM_Vec2 b;
float thickness; float thickness;
struct phys2d_shape shape; struct phys2d_shape shape;
}; };
/* A convex polygon; defined as the convex hull around the given set of points */ /* A convex polygon; defined as the convex hull around the given set of points */
struct phys2d_poly { struct phys2d_poly {
cpVect *points; HMM_Vec2 *points;
float radius; float radius;
struct phys2d_shape shape; struct phys2d_shape shape;
}; };
@ -56,15 +56,15 @@ struct phys2d_poly {
struct phys2d_box { struct phys2d_box {
float w; float w;
float h; float h;
float offset[2]; HMM_Vec2 offset;
float rotation; float rotation;
float r; float r; /* radius */
struct phys2d_shape shape; struct phys2d_shape shape;
}; };
/* An edge with no volume. Cannot collide with each other. Join to make levels. Static only. */ /* An edge with no volume. Cannot collide with each other. Join to make levels. Static only. */
struct phys2d_edge { struct phys2d_edge {
cpVect *points; HMM_Vec2 *points;
float thickness; float thickness;
cpShape **shapes; cpShape **shapes;
int closed; /* True if the first and last points should be connected */ int closed; /* True if the first and last points should be connected */
@ -141,8 +141,6 @@ int *phys2d_query_box_points(cpVect pos, cpVect wh, cpVect *points, int n);
void flush_collide_cbs(); void flush_collide_cbs();
void phys2d_reindex_body(cpBody *body); void phys2d_reindex_body(cpBody *body);
cpVect world2go(struct gameobject *go, cpVect worldpos);
cpVect go2world(struct gameobject *go, cpVect gopos);
extern unsigned int category_masks[32]; extern unsigned int category_masks[32];
void set_cat_mask(int cat, unsigned int mask); void set_cat_mask(int cat, unsigned int mask);
int phys2d_in_air(cpBody *body); int phys2d_in_air(cpBody *body);

View file

@ -323,7 +323,7 @@ void draw_drawmodel(struct drawmodel *dm)
if (!dm->model) return; if (!dm->model) return;
struct gameobject *go = id2go(dm->go); struct gameobject *go = id2go(dm->go);
cpVect pos = cpBodyGetPosition(go->body); cpVect pos = cpBodyGetPosition(go->body);
HMM_Mat4 scale = HMM_Scale(id2go(dm->go)->scale3); HMM_Mat4 scale = HMM_Scale(id2go(dm->go)->scale);
HMM_Mat4 trans = HMM_M4D(1.f); HMM_Mat4 trans = HMM_M4D(1.f);
trans.Elements[3][2] = -pos.x; trans.Elements[3][2] = -pos.x;
trans.Elements[3][1] = pos.y; trans.Elements[3][1] = pos.y;

View file

@ -96,6 +96,8 @@
#ifndef HANDMADE_MATH_H #ifndef HANDMADE_MATH_H
#define HANDMADE_MATH_H #define HANDMADE_MATH_H
#include <chipmunk/chipmunk.h>
/* let's figure out if SSE is really available (unless disabled anyway) /* let's figure out if SSE is really available (unless disabled anyway)
(it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support) (it isn't on non-x86/x86_64 platforms or even x86 without explicit SSE support)
=> only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */ => only use "#ifdef HANDMADE_MATH__USE_SSE" to check for SSE support below this block! */
@ -230,6 +232,8 @@ typedef union HMM_Vec2 {
float Elements[2]; float Elements[2];
cpVect cp;
#ifdef __cplusplus #ifdef __cplusplus
inline float &operator[](const int &Index) { inline float &operator[](const int &Index) {
return Elements[Index]; return Elements[Index];
@ -237,6 +241,8 @@ typedef union HMM_Vec2 {
#endif #endif
} HMM_Vec2; } HMM_Vec2;
const HMM_Vec2 v2zero = {0,0};
typedef union HMM_Vec3 { typedef union HMM_Vec3 {
struct struct
{ {
@ -286,6 +292,8 @@ typedef union HMM_Vec3 {
#endif #endif
} HMM_Vec3; } HMM_Vec3;
const HMM_Vec3 v3zero = {0,0,0};
typedef union HMM_Vec4 { typedef union HMM_Vec4 {
struct struct
{ {
@ -1135,7 +1143,6 @@ static inline HMM_Mat3 HMM_SubM3(HMM_Mat3 Left, HMM_Mat3 Right) {
} }
static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector) { static inline HMM_Vec3 HMM_MulM3V3(HMM_Mat3 Matrix, HMM_Vec3 Vector) {
HMM_Vec3 Result; HMM_Vec3 Result;
Result.X = Vector.Elements[0] * Matrix.Columns[0].X; Result.X = Vector.Elements[0] * Matrix.Columns[0].X;
@ -1163,6 +1170,19 @@ static inline HMM_Mat3 HMM_MulM3(HMM_Mat3 Left, HMM_Mat3 Right) {
return Result; return Result;
} }
/*static inline HMM_Mat3 HMM_VMulM3(int c, ...)
{
HMM_Mat3 res = HMM_M3D(1);
va_list args;
va_start(args, c);
for (int i = 0; i < c; i++) {
HMM_Mat3 m = va_arg(args, HMM_Mat3);
res = HMM_MulM3(m, res);
}
va_end(args);
return res;
}
*/
static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar) { static inline HMM_Mat3 HMM_MulM3F(HMM_Mat3 Matrix, float Scalar) {
HMM_Mat3 Result; HMM_Mat3 Result;

View file

@ -85,11 +85,36 @@ HMM_Mat3 transform2d2mat(transform2d t)
r.Columns[0] = (HMM_Vec3){cos(t.angle), sin(t.angle), 0}; r.Columns[0] = (HMM_Vec3){cos(t.angle), sin(t.angle), 0};
r.Columns[1] = (HMM_Vec3){-sin(t.angle), cos(t.angle), 0}; r.Columns[1] = (HMM_Vec3){-sin(t.angle), cos(t.angle), 0};
m = HMM_MulM3(s, r); m = HMM_MulM3(r, s);
m = HMM_MulM3(m, p); m = HMM_MulM3(p, m);
return m; return m;
} }
HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos)
{
return HMM_MulM3V3(t_go2world(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY;
}
HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos)
{
return HMM_MulM3V3(t_world2go(go), (HMM_Vec3){pos.X, pos.Y, 1.0}).XY;
}
HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos);
{
return HMM_MulV2(go->scale.XY, pos);
}
HMM_Mat3 t_go2world(struct gameobject *go)
{
return transform2d2mat(go2t(go));
}
HMM_Mat3 t_world2go(struct gameobject *go)
{
return HMM_InvGeneralM3(transform2d2mat(go2t(go)));
}
int pos2gameobject(cpVect pos) { int pos2gameobject(cpVect pos) {
cpShape *hit = phys2d_query_pos(pos); cpShape *hit = phys2d_query_pos(pos);
@ -127,7 +152,7 @@ transform2d go2t(gameobject *go)
cpVect p = cpBodyGetPosition(go->body); cpVect p = cpBodyGetPosition(go->body);
t.pos.X = p.x; t.pos.Y = p.y; t.pos.X = p.x; t.pos.Y = p.y;
t.angle = cpBodyGetAngle(go->body); t.angle = cpBodyGetAngle(go->body);
t.scale = (HMM_Vec2){go->scale, go->scale}; t.scale = go->scale.XY;
return t; return t;
} }
@ -224,8 +249,7 @@ static void velocityFn(cpBody *body, cpVect gravity, cpFloat damping, cpFloat dt
int MakeGameobject() { int MakeGameobject() {
struct gameobject go = { struct gameobject go = {
.scale = 1.f, .scale = (HMM_Vec3){1.f,1.f,1.f},
.scale3 = (HMM_Vec3){1.f,1.f,1.f},
.bodytype = CP_BODY_TYPE_STATIC, .bodytype = CP_BODY_TYPE_STATIC,
.maxvelocity = INFINITY, .maxvelocity = INFINITY,
.maxangularvelocity = INFINITY, .maxangularvelocity = INFINITY,

View file

@ -25,8 +25,7 @@ HMM_Mat3 transform2d2mat(transform2d t);
typedef struct gameobject { typedef struct gameobject {
cpBodyType bodytype; cpBodyType bodytype;
int next; int next;
float scale; HMM_Vec3 scale;
HMM_Vec3 scale3;
float mass; float mass;
float f; /* friction */ float f; /* friction */
float e; /* elasticity */ float e; /* elasticity */
@ -34,8 +33,6 @@ typedef struct gameobject {
float maxangularvelocity; float maxangularvelocity;
int gravity; int gravity;
float damping; float damping;
int flipx; /* 1 or -1 */
int flipy;
int sensor; int sensor;
unsigned int layer; unsigned int layer;
cpShapeFilter filter; cpShapeFilter filter;
@ -61,6 +58,13 @@ void gameobject_set_sensor(int id, int sensor);
HMM_Vec2 go2pos(struct gameobject *go); HMM_Vec2 go2pos(struct gameobject *go);
float go2angle(struct gameobject *go); float go2angle(struct gameobject *go);
transform2d go2t(gameobject *go); transform2d go2t(gameobject *go);
HMM_Vec2 go2world(struct gameobject *go, HMM_Vec2 pos);
HMM_Vec2 world2go(struct gameobject *go, HMM_Vec2 pos);
HMM_Mat3 t_go2world(struct gameobject *go);
HMM_Mat3 t_world2go(struct gameobject *go);
HMM_Vec2 goscale(struct gameobject *go, HMM_Vec2 pos);
HMM_Vec2 gotpos(struct gameobject *go, HMM_Vec2 pos);
struct gameobject *get_gameobject_from_id(int id); struct gameobject *get_gameobject_from_id(int id);
struct gameobject *id2go(int id); struct gameobject *id2go(int id);

View file

@ -202,24 +202,17 @@ void tex_draw(struct Texture *tex, HMM_Mat3 m, struct glrect r, struct rgba colo
{1.0,1.0}, {1.0,1.0},
}; };
HMM_Vec2 t_scale = { HMM_Vec2 t_scale = {
tex->width * st_s_w(r), //*size.X; tex->width * st_s_w(r), //*size.X;
tex->height * st_s_h(r) // * size.Y tex->height * st_s_h(r) // * size.Y
}; };
m = HMM_MulM3(m, HMM_ScaleM3(t_scale));
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
/* sposes[i] = HMM_AddV2(sposes[i], offset);
sposes[i] = HMM_MulV2(sposes[i], t_scale);
sposes[i] = HMM_MulM2V2(rot, sposes[i]);
sposes[i] = HMM_AddV2(sposes[i], pos);
verts[i].pos = sposes[i];
*/
HMM_Vec3 v = HMM_MulM3V3(m, (HMM_Vec3){sposes[i].X, sposes[i].Y, 1.0}); HMM_Vec3 v = HMM_MulM3V3(m, (HMM_Vec3){sposes[i].X, sposes[i].Y, 1.0});
verts[i].pos = (HMM_Vec2){v.X, v.Y}; verts[i].pos = (HMM_Vec2){v.X, v.Y};
verts[i].color = color; verts[i].color = color;
} }
if (!wrap) { if (!wrap) {
verts[0].uv.X = r.s0; verts[0].uv.X = r.s0;
verts[0].uv.Y = r.t1; verts[0].uv.Y = r.t1;
@ -253,14 +246,18 @@ void sprite_draw(struct sprite *sprite) {
struct gameobject *go = id2go(sprite->go); struct gameobject *go = id2go(sprite->go);
if (sprite->tex) { if (sprite->tex) {
cpVect cpos = cpBodyGetPosition(go->body);
HMM_Vec2 pos = (HMM_Vec2){cpos.x, cpos.y};
HMM_Vec2 size = (HMM_Vec2){sprite->size.X * go->scale * go->flipx, sprite->size.Y * go->scale * go->flipy};
transform2d t = go2t(id2go(sprite->go)); transform2d t = go2t(id2go(sprite->go));
HMM_Mat3 m = transform2d2mat(t); HMM_Mat3 m = transform2d2mat(t);
m.Columns[2].X += sprite->pos.X;
m.Columns[2].Y += sprite->pos.Y; HMM_Mat3 ss = HMM_M3D(1);
tex_draw(sprite->tex, transform2d2mat(t), sprite->frame, sprite->color, 0, pos, 0); ss.Columns[0].X = sprite->size.X * sprite->tex->width * st_s_w(sprite->frame);
ss.Columns[1].Y = sprite->size.Y * sprite->tex->height * st_s_h(sprite->frame);
HMM_Mat3 ts = HMM_M3D(1);
ts.Columns[2] = (HMM_Vec3){sprite->pos.X, sprite->pos.Y, 1};
HMM_Mat3 sm = HMM_MulM3(ss, ts);
m = HMM_MulM3(m, sm);
tex_draw(sprite->tex, m, sprite->frame, sprite->color, 0, (HMM_Vec2){0,0}, 0);
} }
} }