progress on physics
This commit is contained in:
parent
6cc16cf1f8
commit
c7e6b2aa29
|
@ -1187,8 +1187,8 @@
|
||||||
"padding": 0,
|
"padding": 0,
|
||||||
"tags": ["World"],
|
"tags": ["World"],
|
||||||
"tagsSourceEnumUid": 477,
|
"tagsSourceEnumUid": 477,
|
||||||
"enumTags": [ { "enumValueId": "none", "tileIds": [] }, { "enumValueId": "fullrect", "tileIds": [4,6,7,10,11,12,13,14,15,16,17,21,24,25,26,27,31,34,35,36,37,44,45] }, { "enumValueId": "pointshape", "tileIds": [0,2,3,20,22,23,30,32] } ],
|
"enumTags": [ { "enumValueId": "fullrect", "tileIds": [1,4,6,7,10,11,12,13,14,15,16,17,21,24,25,26,27,31,34,35,36,37,44,45] }, { "enumValueId": "pointshape", "tileIds": [0,2,3,20,22,23,30,32] } ],
|
||||||
"customData": [],
|
"customData": [ { "tileId": 0, "data": "\"collisionShape\": [\n [0.0, 0.0], [1.0, 1.0],\n [1.0, 0.0]\n]" }, { "tileId": 2, "data": "\"collisionsPoints\": [\n [0.0, 0.0], [0.0, 1.0], [1.0, 0.0]\n]" } ],
|
||||||
"savedSelections": [],
|
"savedSelections": [],
|
||||||
"cachedPixelData": {
|
"cachedPixelData": {
|
||||||
"opaqueTiles": "0000000100010011000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"opaqueTiles": "0000000100010011000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
@ -1236,11 +1236,7 @@
|
||||||
"savedSelections": [],
|
"savedSelections": [],
|
||||||
"cachedPixelData": { "opaqueTiles": "000", "averageColors": "187928790bbd" }
|
"cachedPixelData": { "opaqueTiles": "000", "averageColors": "187928790bbd" }
|
||||||
}
|
}
|
||||||
], "enums": [{ "identifier": "tilecollisiontype", "uid": 477, "values": [
|
], "enums": [{ "identifier": "tilecollisiontype", "uid": 477, "values": [ { "id": "fullrect", "tileRect": { "tilesetUid": 3, "x": 272, "y": 272, "w": 16, "h": 16 }, "color": 16723968 }, { "id": "pointshape", "tileRect": { "tilesetUid": 3, "x": 288, "y": 48, "w": 16, "h": 16 }, "color": 8698879 } ], "iconTilesetUid": 3, "externalRelPath": null, "externalFileChecksum": null, "tags": ["Tiles"] }], "externalEnums": [], "levelFields": [] },
|
||||||
{ "id": "none", "tileRect": { "tilesetUid": 3, "x": 384, "y": 64, "w": 16, "h": 16 }, "color": 16777215 },
|
|
||||||
{ "id": "fullrect", "tileRect": { "tilesetUid": 3, "x": 272, "y": 272, "w": 16, "h": 16 }, "color": 16723968 },
|
|
||||||
{ "id": "pointshape", "tileRect": { "tilesetUid": 3, "x": 288, "y": 48, "w": 16, "h": 16 }, "color": 8698879 }
|
|
||||||
], "iconTilesetUid": 3, "externalRelPath": null, "externalFileChecksum": null, "tags": ["Tiles"] }], "externalEnums": [], "levelFields": [] },
|
|
||||||
"levels": [
|
"levels": [
|
||||||
{
|
{
|
||||||
"identifier": "level_0",
|
"identifier": "level_0",
|
||||||
|
|
|
@ -1,21 +1,4 @@
|
||||||
[
|
[
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/lib64/ccache/cc",
|
|
||||||
"-c",
|
|
||||||
"-Wall",
|
|
||||||
"-g3",
|
|
||||||
"-DVMATH_SDL=1",
|
|
||||||
"-Iinclude",
|
|
||||||
"-Isrc",
|
|
||||||
"-o",
|
|
||||||
"bin/fencer",
|
|
||||||
"src/fencer.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/sara/Documents/c-projects/fencer",
|
|
||||||
"file": "/home/sara/Documents/c-projects/fencer/src/fencer.c",
|
|
||||||
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"arguments": [
|
"arguments": [
|
||||||
"/usr/lib64/ccache/cc",
|
"/usr/lib64/ccache/cc",
|
||||||
|
@ -50,23 +33,6 @@
|
||||||
"file": "/home/sara/Documents/c-projects/fencer/src/render.c",
|
"file": "/home/sara/Documents/c-projects/fencer/src/render.c",
|
||||||
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"arguments": [
|
|
||||||
"/usr/lib64/ccache/cc",
|
|
||||||
"-c",
|
|
||||||
"-Wall",
|
|
||||||
"-g3",
|
|
||||||
"-DVMATH_SDL=1",
|
|
||||||
"-Iinclude",
|
|
||||||
"-Isrc",
|
|
||||||
"-o",
|
|
||||||
"bin/fencer",
|
|
||||||
"src/tilemap.c"
|
|
||||||
],
|
|
||||||
"directory": "/home/sara/Documents/c-projects/fencer",
|
|
||||||
"file": "/home/sara/Documents/c-projects/fencer/src/tilemap.c",
|
|
||||||
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"arguments": [
|
"arguments": [
|
||||||
"/usr/lib64/ccache/cc",
|
"/usr/lib64/ccache/cc",
|
||||||
|
@ -134,5 +100,243 @@
|
||||||
"directory": "/home/sara/Documents/c-projects/fencer",
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
"file": "/home/sara/Documents/c-projects/fencer/src/assets.c",
|
"file": "/home/sara/Documents/c-projects/fencer/src/assets.c",
|
||||||
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/level.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/level.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/tileset.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/tileset.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/debug.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/debug.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/input.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/input.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/shape.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/shape.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/fencer.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/fencer.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/rigidbody.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/rigidbody.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/collision.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/collision.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/player.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/player.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/physics_world.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/physics_world.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/tilemap.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/tilemap.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/sprite_entity.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/sprite_entity.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/transformable.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/transformable.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"arguments": [
|
||||||
|
"/usr/lib64/ccache/cc",
|
||||||
|
"-c",
|
||||||
|
"-Wall",
|
||||||
|
"-g3",
|
||||||
|
"-DVMATH_SDL=1",
|
||||||
|
"-Iinclude",
|
||||||
|
"-Isrc",
|
||||||
|
"-o",
|
||||||
|
"bin/fencer",
|
||||||
|
"src/list.c"
|
||||||
|
],
|
||||||
|
"directory": "/home/sara/Documents/c-projects/fencer",
|
||||||
|
"file": "/home/sara/Documents/c-projects/fencer/src/list.c",
|
||||||
|
"output": "/home/sara/Documents/c-projects/fencer/bin/fencer"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
10
levels.ldtk
10
levels.ldtk
|
@ -1187,8 +1187,8 @@
|
||||||
"padding": 0,
|
"padding": 0,
|
||||||
"tags": ["World"],
|
"tags": ["World"],
|
||||||
"tagsSourceEnumUid": 477,
|
"tagsSourceEnumUid": 477,
|
||||||
"enumTags": [ { "enumValueId": "none", "tileIds": [] }, { "enumValueId": "fullrect", "tileIds": [4,6,7,10,11,12,13,14,15,16,17,21,24,25,26,27,31,34,35,36,37,44,45] }, { "enumValueId": "pointshape", "tileIds": [0,2,3,20,22,23,30,32] } ],
|
"enumTags": [ { "enumValueId": "fullrect", "tileIds": [1,4,6,7,10,11,12,13,14,15,16,17,21,24,25,26,27,31,34,35,36,37,44,45] }, { "enumValueId": "pointshape", "tileIds": [0,2,3,20,22,23,30,32] } ],
|
||||||
"customData": [],
|
"customData": [ { "tileId": 0, "data": "\"collisionShape\": [\n [0.0, 0.0], [1.0, 1.0],\n [1.0, 0.0]\n]" }, { "tileId": 2, "data": "\"collisionsPoints\": [\n [0.0, 0.0], [0.0, 1.0], [1.0, 0.0]\n]" } ],
|
||||||
"savedSelections": [],
|
"savedSelections": [],
|
||||||
"cachedPixelData": {
|
"cachedPixelData": {
|
||||||
"opaqueTiles": "0000000100010011000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
"opaqueTiles": "0000000100010011000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
|
||||||
|
@ -1236,11 +1236,7 @@
|
||||||
"savedSelections": [],
|
"savedSelections": [],
|
||||||
"cachedPixelData": { "opaqueTiles": "000", "averageColors": "187928790bbd" }
|
"cachedPixelData": { "opaqueTiles": "000", "averageColors": "187928790bbd" }
|
||||||
}
|
}
|
||||||
], "enums": [{ "identifier": "tilecollisiontype", "uid": 477, "values": [
|
], "enums": [{ "identifier": "tilecollisiontype", "uid": 477, "values": [ { "id": "fullrect", "tileRect": { "tilesetUid": 3, "x": 272, "y": 272, "w": 16, "h": 16 }, "color": 16723968 }, { "id": "pointshape", "tileRect": { "tilesetUid": 3, "x": 288, "y": 48, "w": 16, "h": 16 }, "color": 8698879 } ], "iconTilesetUid": 3, "externalRelPath": null, "externalFileChecksum": null, "tags": ["Tiles"] }], "externalEnums": [], "levelFields": [] },
|
||||||
{ "id": "none", "tileRect": { "tilesetUid": 3, "x": 384, "y": 64, "w": 16, "h": 16 }, "color": 16777215 },
|
|
||||||
{ "id": "fullrect", "tileRect": { "tilesetUid": 3, "x": 272, "y": 272, "w": 16, "h": 16 }, "color": 16723968 },
|
|
||||||
{ "id": "pointshape", "tileRect": { "tilesetUid": 3, "x": 288, "y": 48, "w": 16, "h": 16 }, "color": 8698879 }
|
|
||||||
], "iconTilesetUid": 3, "externalRelPath": null, "externalFileChecksum": null, "tags": ["Tiles"] }], "externalEnums": [], "levelFields": [] },
|
|
||||||
"levels": [
|
"levels": [
|
||||||
{
|
{
|
||||||
"identifier": "level_0",
|
"identifier": "level_0",
|
||||||
|
|
Binary file not shown.
|
@ -1,25 +1,32 @@
|
||||||
#include "collision.h"
|
#include "collision.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
|
||||||
// =====================================================
|
// =====================================================
|
||||||
// Shape overlap test using the separating axis theorem
|
// Shape overlap test using the separating axis theorem
|
||||||
// =====================================================
|
// =====================================================
|
||||||
|
|
||||||
typedef struct Range {float min; float max; } Range;
|
typedef struct Range {float min; Vector minpoint; float max; Vector maxpoint; } Range;
|
||||||
|
|
||||||
static
|
static
|
||||||
Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) {
|
Range _internal_collision_get_range_on_axis(PhysicsEntity self, Vector axis) {
|
||||||
Vector point = shape_get_point_transformed(self.tc->get_shape(self.data), 0, *self.transformable->get_transform(self.data));
|
Transform* transform = self.transformable->get_transform(self.data);
|
||||||
|
Shape* shape = self.tc->get_shape(self.data);
|
||||||
|
Vector point = shape_get_point_transformed(shape, 0, *transform);
|
||||||
float dot = vdotf(axis, point);
|
float dot = vdotf(axis, point);
|
||||||
Range range = {dot, dot};
|
Range range = {dot, point, dot, point};
|
||||||
|
|
||||||
for(size_t point_index = 1; point_index < shape_get_points_count(self.tc->get_shape(self.data)); ++point_index) {
|
for(size_t point_index = 1; point_index < shape_get_points_count(shape); ++point_index) {
|
||||||
point = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self.transformable->get_transform(self.data));
|
point = shape_get_point_transformed(shape, point_index, *transform);
|
||||||
dot = vdotf(axis, point);
|
dot = vdotf(axis, point);
|
||||||
if(dot < range.min)
|
if(dot < range.min) {
|
||||||
range.min = fminf(dot, range.min);
|
range.min = dot;
|
||||||
if(dot > range.max)
|
range.minpoint = point;
|
||||||
range.max = fmaxf(dot, range.max);
|
}
|
||||||
|
if(dot > range.max) {
|
||||||
|
range.max = dot;
|
||||||
|
range.maxpoint = point;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return range;
|
return range;
|
||||||
|
@ -30,10 +37,11 @@ Vector _internal_collision_overlap_on_axis(PhysicsEntity self, PhysicsEntity oth
|
||||||
Range a_range = _internal_collision_get_range_on_axis(self, axis);
|
Range a_range = _internal_collision_get_range_on_axis(self, axis);
|
||||||
Range b_range = _internal_collision_get_range_on_axis(other, axis);
|
Range b_range = _internal_collision_get_range_on_axis(other, axis);
|
||||||
|
|
||||||
if(a_range.min <= b_range.max && b_range.min <= b_range.max)
|
if(a_range.min <= b_range.max && a_range.min <= b_range.max) {
|
||||||
return vmulff(axis, fminf(b_range.max - b_range.min, b_range.min - a_range.max));
|
return vmulff(axis, fminf(a_range.max - b_range.min, b_range.min - a_range.max));
|
||||||
else
|
} else {
|
||||||
return ZeroVector;
|
return ZeroVector;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -58,20 +66,26 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col
|
||||||
Vector a = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self_transform);
|
Vector a = shape_get_point_transformed(self.tc->get_shape(self.data), point_index, *self_transform);
|
||||||
Vector b = shape_get_point_transformed(self.tc->get_shape(self.data), next_index, *self_transform);
|
Vector b = shape_get_point_transformed(self.tc->get_shape(self.data), next_index, *self_transform);
|
||||||
// the direction of the line
|
// the direction of the line
|
||||||
Vector diff = vsubf(b, a);
|
Vector normal = vperpendicularf(vsubf(b, a));
|
||||||
|
|
||||||
// the smallest escape vector on this axis
|
// the smallest escape vector on this axis
|
||||||
Vector escape = _internal_collision_overlap_on_axis(self, other, vnormalizedf(diff));
|
Vector escape = _internal_collision_overlap_on_axis(self, other, vnormalizedf(normal));
|
||||||
float sqr_mag = vsqrmagnitudef(escape);
|
float sqr_mag = vsqrmagnitudef(escape);
|
||||||
if(sqr_mag < shortest_sqrmag) {
|
if(sqr_mag < shortest_sqrmag) {
|
||||||
shortest_sqrmag = sqr_mag;
|
shortest_sqrmag = sqr_mag;
|
||||||
shortest_escape = escape;
|
shortest_escape = escape;
|
||||||
shortest_escape_edge = point_index;
|
shortest_escape_edge = point_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(sqr_mag == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RigidBody* rba = self.tc->get_rigidbody(self.data);
|
RigidBody* rba = self.tc->get_rigidbody(self.data);
|
||||||
RigidBody* rbb = self.tc->get_rigidbody(self.data);
|
RigidBody* rbb = other.tc->get_rigidbody(other.data);
|
||||||
|
Vector velocity = rigidbody_get_velocity(rba);
|
||||||
|
velocity = vsubf(velocity, rigidbody_get_velocity(rbb));
|
||||||
|
|
||||||
*out = (Collision) {
|
*out = (Collision) {
|
||||||
.other = other,
|
.other = other,
|
||||||
|
@ -79,7 +93,7 @@ int _internal_collision_get_overlap(PhysicsEntity self, PhysicsEntity other, Col
|
||||||
.point = InfinityVector,
|
.point = InfinityVector,
|
||||||
.normal = vnormalizedf(shortest_escape),
|
.normal = vnormalizedf(shortest_escape),
|
||||||
|
|
||||||
.velocity = vsubf(rigidbody_get_velocity(rba), rigidbody_get_velocity(rbb)),
|
.velocity = velocity,
|
||||||
.separation_force = shortest_escape,
|
.separation_force = shortest_escape,
|
||||||
|
|
||||||
.edge_left = shape_get_point_transformed(self_shape, shortest_escape_edge, *self_transform),
|
.edge_left = shape_get_point_transformed(self_shape, shortest_escape_edge, *self_transform),
|
||||||
|
|
36
src/fencer.c
36
src/fencer.c
|
@ -11,59 +11,31 @@
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static Spritesheet* spr_player_standing = NULL;
|
|
||||||
static Player* player = NULL;
|
static Player* player = NULL;
|
||||||
|
|
||||||
static Level* level = NULL;
|
static Level* level = NULL;
|
||||||
|
|
||||||
static Vector cam_speed = ZeroVector;
|
|
||||||
|
|
||||||
static
|
|
||||||
void cam_move_h(int val) {
|
|
||||||
cam_speed.x = val * 0.1f;
|
|
||||||
}
|
|
||||||
static
|
|
||||||
void cam_move_v(int val) {
|
|
||||||
cam_speed.y = -val * 0.1f;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
static
|
||||||
void play() {
|
void play() {
|
||||||
spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128});
|
|
||||||
|
|
||||||
g_camera.fov = 40;
|
g_camera.fov = 40;
|
||||||
|
|
||||||
player = malloc(sizeof(Player));
|
player = malloc(sizeof(Player));
|
||||||
player->transform.scale = (Vector){4.f, 4.f};
|
player_spawn(player, ZeroVector);
|
||||||
store_asset(player, free);
|
|
||||||
player->sprite = sprite_from_spritesheet(spr_player_standing, 0);
|
|
||||||
player->rigidbody = rigidbody_make(Player_as_Transformable(player));
|
|
||||||
sprite_set_origin(player->sprite, (Vector){0.25f, 1.f});
|
|
||||||
player->shape = shape_new((Vector[]){
|
|
||||||
{-.1f, -.75f},
|
|
||||||
{0.1f, -.75f},
|
|
||||||
{0.1f, 0.00f},
|
|
||||||
{-.1f, 0.00f}
|
|
||||||
}, 4);
|
|
||||||
|
|
||||||
level = level_load("level_0");
|
level = level_load("level_0");
|
||||||
|
|
||||||
input_add_axis_action(SDL_SCANCODE_A, SDL_SCANCODE_D, &cam_move_h);
|
|
||||||
input_add_axis_action(SDL_SCANCODE_S, SDL_SCANCODE_W, &cam_move_v);
|
|
||||||
|
|
||||||
physics_world_add_entity(Player_as_PhysicsEntity(player));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void tick() {
|
void tick() {
|
||||||
g_camera.transform.position = vaddf(g_camera.transform.position, cam_speed);
|
Player_as_BehaviourEntity(player).tc->update(player, delta_time());
|
||||||
player->transform.position = g_camera.transform.position;
|
g_camera.transform.position = player->transform.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void draw() {
|
void draw() {
|
||||||
level_draw(level);
|
level_draw(level);
|
||||||
sprite_entity_draw(Player_as_SpriteEntity(player));
|
sprite_entity_draw(Player_as_SpriteEntity(player));
|
||||||
|
shape_draw(player->shape, player->transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
|
|
16
src/level.c
16
src/level.c
|
@ -1,6 +1,7 @@
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
#include "assets.h"
|
#include "assets.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "physics_world.h"
|
||||||
#include "tilemap.h"
|
#include "tilemap.h"
|
||||||
#include <cjson/cJSON.h>
|
#include <cjson/cJSON.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -23,6 +24,11 @@ static
|
||||||
void _deallocate_level(void* self_void) {
|
void _deallocate_level(void* self_void) {
|
||||||
Level* self = self_void;
|
Level* self = self_void;
|
||||||
|
|
||||||
|
for(size_t map_index = 0; map_index < self->tilemaps_len; ++map_index) {
|
||||||
|
physics_world_remove_map(self->tilemaps[map_index]);
|
||||||
|
tilemap_destroy(self->tilemaps[map_index]);
|
||||||
|
}
|
||||||
|
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,6 +90,7 @@ Level* level_from_json(cJSON* json) {
|
||||||
// load a tilemap as an autolayer
|
// load a tilemap as an autolayer
|
||||||
LOG_INFO("loading autolayer");
|
LOG_INFO("loading autolayer");
|
||||||
*next_tilemap = tilemap_from_autolayer(layer);
|
*next_tilemap = tilemap_from_autolayer(layer);
|
||||||
|
physics_world_add_map(*next_tilemap);
|
||||||
++next_tilemap;
|
++next_tilemap;
|
||||||
} else if(strcmp(type->valuestring, "Entities")) {
|
} else if(strcmp(type->valuestring, "Entities")) {
|
||||||
// load entities
|
// load entities
|
||||||
|
@ -123,3 +130,12 @@ void level_draw(Level* self) {
|
||||||
tilemap_draw(*map, self->transform);
|
tilemap_draw(*map, self->transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tilemap* level_get_tilemap_layer(Level* self, size_t layer) {
|
||||||
|
ASSERT_RETURN(layer < self->tilemaps_len, NULL, "Layer index %zu out of range", layer);
|
||||||
|
return self->tilemaps[layer];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t level_get_tilemap_count(Level* self) {
|
||||||
|
return self->tilemaps_len;
|
||||||
|
}
|
||||||
|
|
|
@ -5,6 +5,8 @@
|
||||||
#include <SDL2/SDL_render.h>
|
#include <SDL2/SDL_render.h>
|
||||||
#include <cjson/cJSON.h>
|
#include <cjson/cJSON.h>
|
||||||
|
|
||||||
|
typedef struct Tilemap Tilemap;
|
||||||
|
|
||||||
typedef struct Level Level;
|
typedef struct Level Level;
|
||||||
|
|
||||||
extern void world_init();
|
extern void world_init();
|
||||||
|
@ -16,4 +18,7 @@ extern void level_destroy(Level* self);
|
||||||
|
|
||||||
extern void level_draw(Level* self);
|
extern void level_draw(Level* self);
|
||||||
|
|
||||||
|
extern Tilemap* level_get_tilemap_layer(Level* self, size_t layer);
|
||||||
|
extern size_t level_get_tilemap_count(Level* self);
|
||||||
|
|
||||||
#endif // !_fencer_level_h
|
#endif // !_fencer_level_h
|
||||||
|
|
|
@ -125,10 +125,12 @@ void _internal_physics_narrow_collision() {
|
||||||
|
|
||||||
for(PhysicsEntity* left = _world_bodies; left < end; ++left) {
|
for(PhysicsEntity* left = _world_bodies; left < end; ++left) {
|
||||||
for(PhysicsEntity* right = _world_bodies; right < half_end; ++right) {
|
for(PhysicsEntity* right = _world_bodies; right < half_end; ++right) {
|
||||||
collision_check(*left, *right, &collision_left, &collision_right);
|
if(left == right) continue;
|
||||||
|
|
||||||
left->tc->on_collision(left->data, collision_left);
|
if(collision_check(*left, *right, &collision_left, &collision_right)) {
|
||||||
right->tc->on_collision(right->data, collision_right);
|
left->tc->on_collision(left->data, collision_left);
|
||||||
|
right->tc->on_collision(right->data, collision_right);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,6 +140,7 @@ void _internal_tilemap_entity_collision_check(Tilemap* map, PhysicsEntity entity
|
||||||
Collision collision_a;
|
Collision collision_a;
|
||||||
Collision collision_b;
|
Collision collision_b;
|
||||||
PhysicsEntity tileentity;
|
PhysicsEntity tileentity;
|
||||||
|
RigidBody* entity_body = entity.tc->get_rigidbody(entity.data);
|
||||||
|
|
||||||
size_t len = tilemap_get_tile_count(map);
|
size_t len = tilemap_get_tile_count(map);
|
||||||
for(size_t i = 0; i < len; ++i) {
|
for(size_t i = 0; i < len; ++i) {
|
||||||
|
@ -145,6 +148,7 @@ void _internal_tilemap_entity_collision_check(Tilemap* map, PhysicsEntity entity
|
||||||
|
|
||||||
if(collision_check(entity, tileentity, &collision_a, &collision_b)) {
|
if(collision_check(entity, tileentity, &collision_a, &collision_b)) {
|
||||||
entity.tc->on_collision(entity.data, collision_a);
|
entity.tc->on_collision(entity.data, collision_a);
|
||||||
|
rigidbody_add_contact(entity_body, collision_a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,12 +165,13 @@ void _internal_physics_tilemap_collision() {
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
void _internal_physics_move() {
|
void _internal_physics_apply() {
|
||||||
PhysicsEntity* end = _world_bodies + _world_bodies_len;
|
PhysicsEntity* end = _world_bodies + _world_bodies_len;
|
||||||
RigidBody* body = NULL;
|
RigidBody* body = NULL;
|
||||||
|
|
||||||
for(PhysicsEntity* entity = _world_bodies; entity < end; ++entity) {
|
for(PhysicsEntity* entity = _world_bodies; entity < end; ++entity) {
|
||||||
body = entity->tc->get_rigidbody(entity->data);
|
body = entity->tc->get_rigidbody(entity->data);
|
||||||
|
rigidbody_solve_contacts(body);
|
||||||
rigidbody_apply_physics(body);
|
rigidbody_apply_physics(body);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,5 +180,5 @@ void physics_world_tick() {
|
||||||
// _internal_physics_broad_collision();
|
// _internal_physics_broad_collision();
|
||||||
_internal_physics_narrow_collision();
|
_internal_physics_narrow_collision();
|
||||||
_internal_physics_tilemap_collision();
|
_internal_physics_tilemap_collision();
|
||||||
_internal_physics_move();
|
_internal_physics_apply();
|
||||||
}
|
}
|
||||||
|
|
41
src/player.c
41
src/player.c
|
@ -1,37 +1,60 @@
|
||||||
#include "player.h"
|
#include "player.h"
|
||||||
|
#include "assets.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "program.h"
|
#include "program.h"
|
||||||
#include "rigidbody.h"
|
#include "rigidbody.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
|
#include "physics_world.h"
|
||||||
|
|
||||||
static Vector directional = ZeroVector;
|
static Vector directional = ZeroVector;
|
||||||
|
static Spritesheet* spr_player_standing = NULL;
|
||||||
|
|
||||||
static
|
static
|
||||||
void player_input_h(int val) {
|
void player_input_h(int val) {
|
||||||
directional.x = val * 0.1f;
|
directional.x = val * 10.f;
|
||||||
}
|
}
|
||||||
static
|
static
|
||||||
void player_input_v(int val) {
|
void player_input_v(int val) {
|
||||||
directional.y = -val * 0.1f;
|
directional.y = -val * 10.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void player_spawn(Player* self, Vector at) {
|
void player_spawn(Player* self, Vector at) {
|
||||||
|
player_start(self);
|
||||||
self->transform.position = at;
|
self->transform.position = at;
|
||||||
input_add_axis_action(SDL_SCANCODE_A, SDL_SCANCODE_D, &player_input_h);
|
|
||||||
input_add_axis_action(SDL_SCANCODE_S, SDL_SCANCODE_W, &player_input_v);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void player_start(Player* self) {
|
void player_start(Player* self) {
|
||||||
|
input_add_axis_action(SDL_SCANCODE_A, SDL_SCANCODE_D, &player_input_h);
|
||||||
|
input_add_axis_action(SDL_SCANCODE_S, SDL_SCANCODE_W, &player_input_v);
|
||||||
|
|
||||||
self->transform = IdentityTransform;
|
self->transform = IdentityTransform;
|
||||||
|
self->transform.scale = (Vector){4.f, 4.f};
|
||||||
|
|
||||||
|
spr_player_standing = spritesheet_load("assets/sprites/player.png", (IVector){128, 128});
|
||||||
|
store_asset(self, free);
|
||||||
|
|
||||||
|
self->sprite = sprite_from_spritesheet(spr_player_standing, 0);
|
||||||
|
sprite_set_origin(self->sprite, (Vector){0.25f, 1.f});
|
||||||
|
|
||||||
|
self->rigidbody = rigidbody_make(Player_as_Transformable(self));
|
||||||
|
|
||||||
|
float ex_w = 0.1f;
|
||||||
|
float h = .75f;
|
||||||
|
float r = 0.05f;
|
||||||
|
self->shape = shape_new((Vector[]){
|
||||||
|
{r-ex_w, 0.f}, {-ex_w, -r},
|
||||||
|
{-ex_w, r-h}, {r-ex_w, -h},
|
||||||
|
{ex_w-r, -h}, {ex_w, r-h},
|
||||||
|
{ex_w, -r}, {ex_w-r, 0.f},
|
||||||
|
}, 8);
|
||||||
|
|
||||||
|
physics_world_add_entity(Player_as_PhysicsEntity(self));
|
||||||
}
|
}
|
||||||
|
|
||||||
void player_update(Player* self, float dt) {
|
void player_update(Player* self, float dt) {
|
||||||
Vector velocity = rigidbody_get_velocity(self->rigidbody);
|
Vector velocity = rigidbody_get_velocity(self->rigidbody);
|
||||||
ASSERT_RETURN(!visnanf(velocity),, "Velocity is NaN (2)");
|
Vector velocity_target = {directional.x, directional.y};
|
||||||
velocity = vmovetowardsf(velocity, vmulff(directional, 100.f), 10000.f * dt);
|
rigidbody_accelerate(self->rigidbody, vmulff(vsubf(velocity_target, velocity), 200.f));
|
||||||
ASSERT_RETURN(!visnanf(velocity),, "Velocity is NaN (3)");
|
|
||||||
rigidbody_set_velocity(self->rigidbody, velocity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void player_collision(Player* self, Collision hit) {
|
void player_collision(Player* self, Collision hit) {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <SDL2/SDL_image.h>
|
#include <SDL2/SDL_image.h>
|
||||||
|
|
||||||
SDL_Window* g_window;
|
SDL_Window* g_window;
|
||||||
|
static double _target_delta_time = 0.0;
|
||||||
static double _delta_time;
|
static double _delta_time;
|
||||||
static double _frame_start;
|
static double _frame_start;
|
||||||
static double _game_start_time;
|
static double _game_start_time;
|
||||||
|
@ -35,9 +36,10 @@ double get_time_s() {
|
||||||
|
|
||||||
int program_run(const struct ProgramSettings* settings) {
|
int program_run(const struct ProgramSettings* settings) {
|
||||||
LOG_INFO("Starting program...");
|
LOG_INFO("Starting program...");
|
||||||
float target_dt = 1.0f/settings->target_fps;
|
|
||||||
if(settings->target_fps <= 0) {
|
if(settings->target_fps <= 0) {
|
||||||
target_dt = 0;
|
_target_delta_time = 0;
|
||||||
|
} else {
|
||||||
|
_target_delta_time = 1.0f/settings->target_fps;
|
||||||
}
|
}
|
||||||
_game_start_time = _frame_start = get_time_s();
|
_game_start_time = _frame_start = get_time_s();
|
||||||
SDL_Init(INITFLAGS);
|
SDL_Init(INITFLAGS);
|
||||||
|
@ -62,19 +64,20 @@ int program_run(const struct ProgramSettings* settings) {
|
||||||
LOG_INFO("Starting program loop");
|
LOG_INFO("Starting program loop");
|
||||||
for(;;) {
|
for(;;) {
|
||||||
render_present();
|
render_present();
|
||||||
double current;
|
|
||||||
do {
|
|
||||||
current = get_time_s();
|
|
||||||
_delta_time = current - _frame_start;
|
|
||||||
SDL_Delay(1);
|
|
||||||
program_handle_events();
|
|
||||||
} while(_delta_time <= target_dt);
|
|
||||||
|
|
||||||
_frame_start = current;
|
double current_time = get_time_s();
|
||||||
|
_delta_time += current_time - _frame_start;
|
||||||
|
_frame_start = current_time;
|
||||||
|
|
||||||
settings->on_tick();
|
while(_delta_time > _target_delta_time) {
|
||||||
|
_delta_time -= _target_delta_time;
|
||||||
|
settings->on_tick();
|
||||||
|
physics_world_tick();
|
||||||
|
}
|
||||||
|
|
||||||
|
program_handle_events();
|
||||||
settings->on_draw();
|
settings->on_draw();
|
||||||
physics_world_tick();
|
SDL_Delay(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_ERROR("Failed to exit");
|
LOG_ERROR("Failed to exit");
|
||||||
|
@ -122,5 +125,5 @@ void program_handle_windowevent(SDL_WindowEvent* event) {
|
||||||
|
|
||||||
inline
|
inline
|
||||||
float delta_time() {
|
float delta_time() {
|
||||||
return _delta_time;
|
return _target_delta_time == 0 ? _delta_time : _target_delta_time;
|
||||||
}
|
}
|
||||||
|
|
136
src/rigidbody.c
136
src/rigidbody.c
|
@ -1,37 +1,156 @@
|
||||||
#include "rigidbody.h"
|
#include "rigidbody.h"
|
||||||
|
#include "camera.h"
|
||||||
|
#include "debug.h"
|
||||||
#include "program.h"
|
#include "program.h"
|
||||||
|
#include "collision.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Collision hit;
|
||||||
|
float warming;
|
||||||
|
int expiry;
|
||||||
|
} Contact;
|
||||||
|
|
||||||
struct RigidBody {
|
struct RigidBody {
|
||||||
Transformable transformable;
|
Transformable transformable;
|
||||||
|
|
||||||
float mass;
|
float mass;
|
||||||
|
|
||||||
Vector linear_velocity;
|
|
||||||
Vector linear_force;
|
Vector linear_force;
|
||||||
|
Vector linear_velocity;
|
||||||
|
|
||||||
int is_static;
|
int is_static;
|
||||||
|
|
||||||
|
List contacts;
|
||||||
};
|
};
|
||||||
|
|
||||||
RigidBody* rigidbody_make(Transformable transform) {
|
RigidBody* rigidbody_make(Transformable transform) {
|
||||||
RigidBody* self = malloc(sizeof(RigidBody));
|
RigidBody* self = malloc(sizeof(RigidBody));
|
||||||
|
ASSERT_RETURN(self != NULL, NULL, "Failed to allocate space for rigidbody");
|
||||||
*self = (RigidBody){
|
*self = (RigidBody){
|
||||||
.transformable = transform,
|
.transformable = transform,
|
||||||
.mass = 0.0f,
|
.mass = 1.0f,
|
||||||
.linear_velocity = ZeroVector,
|
.linear_velocity = ZeroVector,
|
||||||
.linear_force = ZeroVector,
|
.is_static = 0,
|
||||||
.is_static = 0
|
.contacts = list_from_type(Contact),
|
||||||
};
|
};
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rigidbody_destroy(RigidBody* self) {
|
void rigidbody_destroy(RigidBody* self) {
|
||||||
|
list_empty(&self->contacts);
|
||||||
free(self);
|
free(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rigidbody_add_contact(RigidBody* self, Collision hit) {
|
||||||
|
LOG_INFO("contact between rigidbody %p and %p detected", self->transformable.data, hit.other.data);
|
||||||
|
// update an existing contact
|
||||||
|
list_foreach(Contact, contact, &self->contacts) {
|
||||||
|
if(contact->hit.other.data == hit.other.data) {
|
||||||
|
++contact->expiry;
|
||||||
|
contact->hit = hit;
|
||||||
|
contact->warming += delta_time();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a new contact
|
||||||
|
list_add(&self->contacts,
|
||||||
|
&(Contact) {
|
||||||
|
.expiry = 1,
|
||||||
|
.hit = hit,
|
||||||
|
.warming = delta_time()
|
||||||
|
});
|
||||||
|
|
||||||
|
Contact* c = list_at(&self->contacts, self->contacts.len - 1);
|
||||||
|
LOG_INFO("added contact %p with exp %d", c->hit.other.data, c->expiry);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void _internal_rigidbody_collect_contacts(RigidBody* self) {
|
||||||
|
for(size_t i = 0; i < self->contacts.len; ++i) {
|
||||||
|
Contact* contact = list_at(&self->contacts, i);
|
||||||
|
--(contact->expiry);
|
||||||
|
if(contact->expiry <= 0) {
|
||||||
|
list_erase(&self->contacts, i);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void _internal_debug_draw_collision_edge(Vector left, Vector right, Vector normal) {
|
||||||
|
#if !NDEBUG
|
||||||
|
Vector a = camera_world_to_pixel_point(&g_camera, left);
|
||||||
|
Vector b = camera_world_to_pixel_point(&g_camera, right);
|
||||||
|
Vector n = transform_direction(&g_camera.transform, normal);
|
||||||
|
SDL_SetRenderDrawColor(g_renderer, 255, 255, 255, 255);
|
||||||
|
SDL_RenderDrawLine(g_renderer, a.x, a.y, b.x, b.y);
|
||||||
|
a = vlerpf(a, b, 0.5f);
|
||||||
|
b = vaddf(a, vmulff(n, 100.f));
|
||||||
|
SDL_SetRenderDrawColor(g_renderer, 255, 0, 0, 255);
|
||||||
|
SDL_RenderDrawLine(g_renderer, a.x, a.y, b.x, b.y);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
Vector _internal_calculate_contact_force(Contact* contact) {
|
||||||
|
Collision hit = contact->hit;
|
||||||
|
const float warming = fminf(1.f, contact->warming);
|
||||||
|
const float d = 1.f;
|
||||||
|
const float k = 50.0 * warming;
|
||||||
|
const float b = 1.f;
|
||||||
|
|
||||||
|
const Vector damping = vmulff(hit.normal, k * d);
|
||||||
|
const Vector bounce = vprojectf(vmulff(hit.normal, -b), hit.velocity);
|
||||||
|
|
||||||
|
return vsubf(damping, bounce);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline
|
||||||
|
void _internal_rigidbody_solve_contact(RigidBody* self, Contact* contact, Vector* solve_forces) {
|
||||||
|
Collision hit = contact->hit;
|
||||||
|
if (vsqrmagnitudef(contact->hit.separation_force) < 0.001f*0.001f)
|
||||||
|
return;
|
||||||
|
Vector force = _internal_calculate_contact_force(contact);
|
||||||
|
float dot = vdotf(vnormalizedf(*solve_forces), force);
|
||||||
|
if (veqf(*solve_forces, ZeroVector) || dot * dot > vsqrmagnitudef(*solve_forces) || dot <= 0.0f) {
|
||||||
|
#if !NDEBUG
|
||||||
|
LOG_INFO("warming: %f", contact->warming);
|
||||||
|
LOG_INFO("force: %f %f", force.x, force.y);
|
||||||
|
LOG_INFO("dot: %f", dot);
|
||||||
|
LOG_INFO("mag: %f", vmagnitudef(self->linear_force));
|
||||||
|
#endif
|
||||||
|
*solve_forces = vaddf(*solve_forces, force);
|
||||||
|
rigidbody_add_impulse(self, force);
|
||||||
|
}
|
||||||
|
|
||||||
|
_internal_debug_draw_collision_edge(hit.edge_left, hit.edge_right, hit.normal);
|
||||||
|
|
||||||
|
ASSERT_RETURN(!visnanf(force), , "Force contains NaN (1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
void rigidbody_solve_contacts(RigidBody* self) {
|
||||||
|
ASSERT_RETURN(!visnanf(self->linear_velocity),, "Velocity is NaN (0)");
|
||||||
|
|
||||||
|
Vector solve_forces = ZeroVector;
|
||||||
|
list_foreach(Contact, contact, &self->contacts) {
|
||||||
|
_internal_rigidbody_solve_contact(self, contact, &solve_forces);
|
||||||
|
}
|
||||||
|
|
||||||
|
_internal_rigidbody_collect_contacts(self);
|
||||||
|
|
||||||
|
ASSERT_RETURN(!visnanf(self->linear_velocity),, "Velocity is NaN (1)");
|
||||||
|
}
|
||||||
|
|
||||||
void rigidbody_apply_physics(RigidBody* self) {
|
void rigidbody_apply_physics(RigidBody* self) {
|
||||||
|
Vector position = transformable_get_position(self->transformable);
|
||||||
Vector velocity = vmulff(self->linear_velocity, delta_time());
|
Vector velocity = vmulff(self->linear_velocity, delta_time());
|
||||||
Vector* position = (self->transformable.tc->get_position(self->transformable.data));
|
|
||||||
*position = vaddf(*position, velocity);
|
if(vsqrmagnitudef(velocity) > powf(0.00001f, 2)) {
|
||||||
|
transformable_set_position(self->transformable, vaddf(position, velocity));
|
||||||
|
}
|
||||||
|
|
||||||
|
self->linear_force = ZeroVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
float rigidbody_get_mass(const RigidBody* self) {
|
float rigidbody_get_mass(const RigidBody* self) {
|
||||||
|
@ -44,11 +163,11 @@ void rigidbody_set_mass(RigidBody* self, float mass) {
|
||||||
|
|
||||||
void rigidbody_add_impulse(RigidBody* self, Vector force) {
|
void rigidbody_add_impulse(RigidBody* self, Vector force) {
|
||||||
self->linear_force = vaddf(self->linear_force, force);
|
self->linear_force = vaddf(self->linear_force, force);
|
||||||
|
self->linear_velocity = vaddf(self->linear_velocity, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rigidbody_accelerate(RigidBody* self, Vector force) {
|
void rigidbody_accelerate(RigidBody* self, Vector force) {
|
||||||
force = vmulff(force, delta_time());
|
rigidbody_add_impulse(self, vmulff(force, delta_time()));
|
||||||
self->linear_force = vaddf(self->linear_force, force);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int rigidbody_is_static(const RigidBody* self) {
|
int rigidbody_is_static(const RigidBody* self) {
|
||||||
|
@ -64,5 +183,6 @@ Vector rigidbody_get_velocity(const RigidBody* self) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rigidbody_set_velocity(RigidBody* self, Vector velocity) {
|
void rigidbody_set_velocity(RigidBody* self, Vector velocity) {
|
||||||
|
self->linear_force = vaddf(self->linear_force, vsubf(velocity, self->linear_force));
|
||||||
self->linear_velocity = velocity;
|
self->linear_velocity = velocity;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
#include "transformable.h"
|
#include "transformable.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
struct Collision;
|
||||||
|
|
||||||
typedef struct RigidBody RigidBody;
|
typedef struct RigidBody RigidBody;
|
||||||
|
|
||||||
|
@ -10,6 +13,9 @@ typedef struct RigidBody RigidBody;
|
||||||
RigidBody* rigidbody_make(Transformable transform);
|
RigidBody* rigidbody_make(Transformable transform);
|
||||||
void rigidbody_destroy(RigidBody* self);
|
void rigidbody_destroy(RigidBody* self);
|
||||||
|
|
||||||
|
void rigidbody_add_contact(RigidBody* self, struct Collision hit);
|
||||||
|
void rigidbody_solve_contacts(RigidBody* self);
|
||||||
|
|
||||||
void rigidbody_apply_physics(RigidBody* self);
|
void rigidbody_apply_physics(RigidBody* self);
|
||||||
|
|
||||||
float rigidbody_get_mass(const RigidBody* self);
|
float rigidbody_get_mass(const RigidBody* self);
|
||||||
|
|
27
src/shape.c
27
src/shape.c
|
@ -1,5 +1,8 @@
|
||||||
#include "shape.h"
|
#include "shape.h"
|
||||||
|
#include "camera.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "render.h"
|
||||||
|
#include <SDL2/SDL_render.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
struct Shape {
|
struct Shape {
|
||||||
|
@ -86,9 +89,9 @@ Shape* shape_new(const Vector* points, size_t points_len) {
|
||||||
Shape* shape_new_square(Vector size) {
|
Shape* shape_new_square(Vector size) {
|
||||||
return shape_new((Vector[4]){
|
return shape_new((Vector[4]){
|
||||||
ZeroVector,
|
ZeroVector,
|
||||||
(Vector){0.f, size.y},
|
(Vector){size.x, 0.f},
|
||||||
size,
|
size,
|
||||||
(Vector){size.x, 0.f}
|
(Vector){0.f, size.y},
|
||||||
}, 4);
|
}, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,3 +185,23 @@ Vector shape_get_median_point(Shape* self) {
|
||||||
int shape_is_convex(Shape* self) {
|
int shape_is_convex(Shape* self) {
|
||||||
return self->is_convex;
|
return self->is_convex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void shape_draw(Shape* self, Transform transform) {
|
||||||
|
Vector lhs, rhs, normal;
|
||||||
|
for(size_t i = 0; i < self->points_len; ++i) {
|
||||||
|
lhs = shape_get_point_transformed(self, i, transform);
|
||||||
|
rhs = shape_get_point_transformed(self, (i + 1) % self->points_len, transform);
|
||||||
|
normal = vnormalizedf(vperpendicularf(vsubf(rhs, lhs)));
|
||||||
|
lhs = camera_world_to_pixel_point(&g_camera, lhs);
|
||||||
|
rhs = camera_world_to_pixel_point(&g_camera, rhs);
|
||||||
|
normal = transform_direction(&g_camera.transform, normal);
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(g_renderer, 255, 255, 255, 255);
|
||||||
|
SDL_RenderDrawLineF(g_renderer, lhs.x, lhs.y, rhs.x, rhs.y);
|
||||||
|
|
||||||
|
lhs = vlerpf(lhs, rhs, 0.5f);
|
||||||
|
rhs = vaddf(lhs, vmulff(normal, 10.f));
|
||||||
|
SDL_SetRenderDrawColor(g_renderer, 0, 0, 255, 255);
|
||||||
|
SDL_RenderDrawLineF(g_renderer, lhs.x, lhs.y, rhs.x, rhs.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -25,5 +25,6 @@ extern Vector shape_remove_point(Shape* self, size_t at);
|
||||||
|
|
||||||
extern Vector shape_get_median_point(Shape* self);
|
extern Vector shape_get_median_point(Shape* self);
|
||||||
extern int shape_is_convex(Shape* self);
|
extern int shape_is_convex(Shape* self);
|
||||||
|
extern void shape_draw(Shape* self, Transform transform);
|
||||||
|
|
||||||
#endif // !_fencer_shape_h
|
#endif // !_fencer_shape_h
|
||||||
|
|
|
@ -25,7 +25,7 @@ Sprite* sprite_from_spritesheet(Spritesheet* sheet, size_t initial_frame) {
|
||||||
ASSERT_RETURN(self != NULL, NULL, "Failed to allocate memory for new sprite.");
|
ASSERT_RETURN(self != NULL, NULL, "Failed to allocate memory for new sprite.");
|
||||||
|
|
||||||
self->spritesheet = sheet;
|
self->spritesheet = sheet;
|
||||||
self->origin = (Vector){0.5f, 1.0f};
|
self->origin = (Vector){0.5f, 0.5f};
|
||||||
self->current_frame = initial_frame;
|
self->current_frame = initial_frame;
|
||||||
// TODO: replace with a getter for the current game time.
|
// TODO: replace with a getter for the current game time.
|
||||||
self->current_frame_time = 0;
|
self->current_frame_time = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "sprite_entity.h"
|
#include "sprite_entity.h"
|
||||||
#include "sprite.h"
|
#include "sprite.h"
|
||||||
|
|
||||||
void sprite_entity_draw(SpriteEntity self) {
|
void sprite_entity_draw(SpriteEntity self) {
|
||||||
Sprite* sprite = self.tc->get_sprite(self.data);
|
Sprite* sprite = self.tc->get_sprite(self.data);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include "tilemap.h"
|
#include "tilemap.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
#include "rigidbody.h"
|
||||||
#include "tileset.h"
|
#include "tileset.h"
|
||||||
#include "assets.h"
|
#include "assets.h"
|
||||||
#include "camera.h"
|
#include "camera.h"
|
||||||
|
@ -63,6 +64,7 @@ Tilemap* tilemap_from_autolayer(cJSON* json) {
|
||||||
free(self);
|
free(self);
|
||||||
RETURN_ERROR(NULL, "Failed to allocate map memory");
|
RETURN_ERROR(NULL, "Failed to allocate map memory");
|
||||||
}
|
}
|
||||||
|
self->rigidbody = rigidbody_make(Tilemap_as_Transformable(self));
|
||||||
|
|
||||||
const double px_to_ws = 1.0 / grid->valuedouble;
|
const double px_to_ws = 1.0 / grid->valuedouble;
|
||||||
|
|
||||||
|
@ -80,17 +82,30 @@ Tilemap* tilemap_from_autolayer(cJSON* json) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void tilemap_destroy(Tilemap* self) {
|
||||||
|
free(self->map);
|
||||||
|
rigidbody_destroy(self->rigidbody);
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
|
||||||
void tilemap_draw(Tilemap* self, Transform transform) {
|
void tilemap_draw(Tilemap* self, Transform transform) {
|
||||||
Transform tiletrans = transform_apply(transform, self->transform);
|
Transform tiletrans = transform_apply(transform, self->transform);
|
||||||
TileInstance* tile;
|
TileInstance* tile;
|
||||||
|
|
||||||
|
for(int i = 0; i < self->map_num; ++i) {
|
||||||
|
tile = self->map + i;
|
||||||
|
tiletrans = transform_apply(self->transform, tile->transform);
|
||||||
|
shape_draw(tiledef_get_shape(tile->tiledef), tiletrans);
|
||||||
|
}
|
||||||
|
|
||||||
for(int i = 0; i < self->map_num; ++i) {
|
for(int i = 0; i < self->map_num; ++i) {
|
||||||
tile = self->map + i;
|
tile = self->map + i;
|
||||||
tiletrans = transform_apply(self->transform, tile->transform);
|
tiletrans = transform_apply(self->transform, tile->transform);
|
||||||
Sprite* sprite = tiledef_get_sprite(tile->tiledef);
|
Sprite* sprite = tiledef_get_sprite(tile->tiledef);
|
||||||
|
|
||||||
if(sprite != NULL)
|
if(sprite != NULL) {
|
||||||
sprite_draw(sprite, tiletrans);
|
sprite_draw(sprite, tiletrans);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +117,10 @@ TileInstance* tilemap_get_tile(Tilemap* self, size_t at) {
|
||||||
return &self->map[at];
|
return &self->map[at];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Transform* tilemap_get_transform(Tilemap* self ) {
|
||||||
|
return &self->transform;
|
||||||
|
}
|
||||||
|
|
||||||
RigidBody* tile_instance_get_rigidbody(TileInstance* self) {
|
RigidBody* tile_instance_get_rigidbody(TileInstance* self) {
|
||||||
return self->parent_map->rigidbody;
|
return self->parent_map->rigidbody;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,20 +22,20 @@ extern void tilemap_draw(Tilemap* self, Transform transform);
|
||||||
extern size_t tilemap_get_tile_count(Tilemap* self);
|
extern size_t tilemap_get_tile_count(Tilemap* self);
|
||||||
extern TileInstance* tilemap_get_tile(Tilemap* self, size_t at);
|
extern TileInstance* tilemap_get_tile(Tilemap* self, size_t at);
|
||||||
|
|
||||||
|
extern Transform* tilemap_get_transform(Tilemap* self);
|
||||||
|
|
||||||
extern RigidBody* tile_instance_get_rigidbody(TileInstance* self);
|
extern RigidBody* tile_instance_get_rigidbody(TileInstance* self);
|
||||||
extern Transform* tile_instance_get_transform(TileInstance* self);
|
extern Transform* tile_instance_get_transform(TileInstance* self);
|
||||||
extern Shape* tile_instance_get_shape(TileInstance* self);
|
extern Shape* tile_instance_get_shape(TileInstance* self);
|
||||||
extern void tile_instance_on_collision(TileInstance* self, Collision collision);
|
extern void tile_instance_on_collision(TileInstance* self, Collision collision);
|
||||||
|
|
||||||
extern Vector* tile_instance_get_position(TileInstance* self);
|
|
||||||
extern Vector* tile_instance_get_scale(TileInstance* self);
|
impl_Transformable_for(Tilemap,
|
||||||
extern float* tile_instance_get_rotation(TileInstance* self);
|
tilemap_get_transform
|
||||||
|
)
|
||||||
|
|
||||||
impl_Transformable_for(TileInstance,
|
impl_Transformable_for(TileInstance,
|
||||||
tile_instance_get_transform,
|
tile_instance_get_transform
|
||||||
tile_instance_get_position,
|
|
||||||
tile_instance_get_scale,
|
|
||||||
tile_instance_get_rotation
|
|
||||||
)
|
)
|
||||||
impl_PhysicsEntity_for(TileInstance,
|
impl_PhysicsEntity_for(TileInstance,
|
||||||
tile_instance_get_rigidbody,
|
tile_instance_get_rigidbody,
|
||||||
|
|
|
@ -122,6 +122,7 @@ Tileset* tileset_from_json(cJSON* json) {
|
||||||
.sprite = sprite_from_spritesheet(self->atlas, tid),
|
.sprite = sprite_from_spritesheet(self->atlas, tid),
|
||||||
.collision = shape_new_square(OneVector)
|
.collision = shape_new_square(OneVector)
|
||||||
};
|
};
|
||||||
|
sprite_set_origin(self->tiledefs[tid].sprite, ZeroVector);
|
||||||
// TODO: generate/read collision information
|
// TODO: generate/read collision information
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,26 +51,8 @@ Transform* transform_get_transform(Transform* self) {
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
Vector* transform_get_position(Transform* self) {
|
|
||||||
return &self->position;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
Vector* transform_get_scale(Transform* self) {
|
|
||||||
return &self->scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
static
|
|
||||||
float* transform_get_rotation(Transform* self) {
|
|
||||||
return &self->rotation;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl_Transformable_for(Transform,
|
impl_Transformable_for(Transform,
|
||||||
transform_get_transform,
|
transform_get_transform
|
||||||
transform_get_position,
|
|
||||||
transform_get_scale,
|
|
||||||
transform_get_rotation
|
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif // !_fencer_transform_h
|
#endif // !_fencer_transform_h
|
||||||
|
|
41
src/transformable.c
Normal file
41
src/transformable.c
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#include "transformable.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
|
Vector transformable_get_position(Transformable self) {
|
||||||
|
return self.tc->get_transform(self.data)->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transformable_set_position(Transformable self, Vector position) {
|
||||||
|
self.tc->get_transform(self.data)->position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transformable_move(Transformable self, Vector delta) {
|
||||||
|
Vector* position = &self.tc->get_transform(self.data)->position;
|
||||||
|
*position = vaddf(*position, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector transformable_get_scale(Transformable self) {
|
||||||
|
return self.tc->get_transform(self.data)->scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transformable_set_scale(Transformable self, Vector scale) {
|
||||||
|
self.tc->get_transform(self.data)->scale = scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transformable_scale(Transformable self, Vector factor) {
|
||||||
|
Vector* scale = &self.tc->get_transform(self.data)->scale;
|
||||||
|
*scale = vmulf(*scale, factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
float transformable_get_rotation(Transformable self) {
|
||||||
|
return self.tc->get_transform(self.data)->rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transformable_set_rotation(Transformable self, float rotation) {
|
||||||
|
self.tc->get_transform(self.data)->rotation = rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transformable_rotate(Transformable self, float delta) {
|
||||||
|
float* rotation = &self.tc->get_transform(self.data)->rotation;
|
||||||
|
*rotation = *rotation + delta;
|
||||||
|
}
|
|
@ -6,9 +6,6 @@
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
struct Transform* (*const get_transform)(void* self);
|
struct Transform* (*const get_transform)(void* self);
|
||||||
Vector* (*const get_position)(void* self);
|
|
||||||
Vector* (*const get_scale)(void* self);
|
|
||||||
float* (*const get_rotation)(void* self);
|
|
||||||
} ITransformable;
|
} ITransformable;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -16,16 +13,23 @@ typedef struct {
|
||||||
ITransformable const* tc;
|
ITransformable const* tc;
|
||||||
} Transformable;
|
} Transformable;
|
||||||
|
|
||||||
#define impl_Transformable_for(T, get_transform_f, get_position_f, get_scale_f, get_rotation_f)\
|
extern Vector transformable_get_position(Transformable self);
|
||||||
|
extern void transformable_set_position(Transformable self, Vector position);
|
||||||
|
extern void transformable_move(Transformable self, Vector delta);
|
||||||
|
|
||||||
|
extern Vector transformable_get_scale(Transformable self);
|
||||||
|
extern void transformable_set_scale(Transformable self, Vector scale);
|
||||||
|
extern void transformable_scale(Transformable self, Vector factor);
|
||||||
|
|
||||||
|
extern float transformable_get_rotation(Transformable self);
|
||||||
|
extern void transformable_set_rotation(Transformable self, float rotation);
|
||||||
|
extern void transformable_rotate(Transformable self, float delta);
|
||||||
|
|
||||||
|
#define impl_Transformable_for(T, get_transform_f)\
|
||||||
static inline Transformable T##_as_Transformable(T* x) {\
|
static inline Transformable T##_as_Transformable(T* x) {\
|
||||||
TC_FN_TYPECHECK(Transform*, get_transform_f, T*);\
|
TC_FN_TYPECHECK(Transform*, get_transform_f, T*);\
|
||||||
TC_FN_TYPECHECK(Vector*, get_position_f, T*);\
|
|
||||||
TC_FN_TYPECHECK(float*, get_rotation_f, T*);\
|
|
||||||
static ITransformable const tc = {\
|
static ITransformable const tc = {\
|
||||||
.get_transform = (Transform*(*const)(void*)) get_transform_f,\
|
.get_transform = (Transform*(*const)(void*)) get_transform_f\
|
||||||
.get_position = (Vector*(*const)(void*)) get_position_f,\
|
|
||||||
.get_scale = (Vector*(*const)(void*)) get_scale_f,\
|
|
||||||
.get_rotation = (float*(*const)(void*)) get_rotation_f\
|
|
||||||
};\
|
};\
|
||||||
return (Transformable){.tc = &tc, .data = x};\
|
return (Transformable){.tc = &tc, .data = x};\
|
||||||
}
|
}
|
||||||
|
|
33
src/vmath.h
33
src/vmath.h
|
@ -46,6 +46,15 @@ typedef struct IVector {
|
||||||
// Floating point vector maths functions.
|
// Floating point vector maths functions.
|
||||||
///
|
///
|
||||||
static inline
|
static inline
|
||||||
|
int veqf(Vector a, Vector b) {
|
||||||
|
const float e = 0.0001f;
|
||||||
|
return fabsf(a.x - b.x) + fabsf(a.y - b.y) < e;
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
int visnanf(Vector a) {
|
||||||
|
return isnanf(a.x) || isnanf(a.y);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
Vector vaddf(Vector a, Vector b) {
|
Vector vaddf(Vector a, Vector b) {
|
||||||
return (Vector){a.x + b.x, a.y + b.y};
|
return (Vector){a.x + b.x, a.y + b.y};
|
||||||
}
|
}
|
||||||
|
@ -71,14 +80,20 @@ Vector vperpendicularf(Vector a) {
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
float vmagnitudef(Vector a) {
|
float vmagnitudef(Vector a) {
|
||||||
|
if(veqf(a, ZeroVector)) return 0.f;
|
||||||
|
a.x = fabsf(a.x);
|
||||||
|
a.y = fabsf(a.y);
|
||||||
return sqrtf(a.x*a.x + a.y*a.y);
|
return sqrtf(a.x*a.x + a.y*a.y);
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
float vsqrmagnitudef(Vector a) {
|
float vsqrmagnitudef(Vector a) {
|
||||||
return fabsf(a.x*a.x) + fabsf(a.y*a.y);
|
a.x = fabsf(a.x);
|
||||||
|
a.y = fabsf(a.y);
|
||||||
|
return a.x*a.x + a.y*a.y;
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
Vector vnormalizedf(Vector a) {
|
Vector vnormalizedf(Vector a) {
|
||||||
|
if(veqf(a, ZeroVector)) return ZeroVector;
|
||||||
return vmulff(a, 1.0/vmagnitudef(a));
|
return vmulff(a, 1.0/vmagnitudef(a));
|
||||||
}
|
}
|
||||||
static inline
|
static inline
|
||||||
|
@ -104,6 +119,22 @@ Vector vrotatef(Vector a, float t) {
|
||||||
sinf(t) * a.x + cosf(t) * a.y
|
sinf(t) * a.x + cosf(t) * a.y
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
static inline
|
||||||
|
Vector vprojectf(Vector onto, Vector from) {
|
||||||
|
float dot = vdotf(onto, from);
|
||||||
|
return vmulff(onto, dot);
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
Vector vlerpf(Vector start, Vector end, float t) {
|
||||||
|
if(veqf(start, end))
|
||||||
|
return end;
|
||||||
|
t = fminf(fmaxf(0.0f, t), 1.0f);
|
||||||
|
return vaddf(start, vmulff(vsubf(end, start), t));
|
||||||
|
}
|
||||||
|
static inline
|
||||||
|
Vector vmovetowardsf(Vector start, Vector end, float delta) {
|
||||||
|
return vlerpf(start, end, delta / vdistancef(end, start));
|
||||||
|
}
|
||||||
|
|
||||||
static inline
|
static inline
|
||||||
IVector vaddi(IVector a, IVector b) {
|
IVector vaddi(IVector a, IVector b) {
|
||||||
|
|
Loading…
Reference in a new issue