Mirai's Miscellaneous Misadventures

M34 / core / collisions.c

// copyright 2022 zamfofex
// license: AGPLv3 or later

#include <mimimi/compound-behaviors.h>
#include <mimimi/collisions.h>
#include <mimimi/allocators.h>
#include <mimimi/geometry.h>

struct mimimi_collision
{
	int count;
	struct mimimi_position **positions;
	int strength;
	int proximity;
	int height;
	int tolerance;
};

static void mimimi_collide(void *data)
{
	struct mimimi_collision *collision = data;
	struct mimimi_position **positions = collision->positions;
	
	for (int i = 0 ; i < collision->count ; i++)
	{
		int a = positions[i]->x;
		
		int k = i;
		for (int j = i - 1 ; j >= 0 ; j--)
		{
			int b = positions[j]->x;
			if (a <= b) break;
			
			struct mimimi_position *position = positions[k];
			positions[k] = positions[j];
			positions[j] = position;
			
			k = j;
		}
	}
	
	for (int i = 1 ; i < collision->count ; i++)
	{
		int y = positions[i]->y - positions[i - 1]->y;
		if (y > collision->height) continue;
		if (y < -collision->height) continue;
		
		int *a = &positions[i]->x;
		int *b = &positions[i - 1]->x;
		int d = *b - *a;
		if (d < collision->proximity)
		{
			int push = collision->strength / (d + collision->tolerance);
			*a -= push;
			*b += push;
		}
	}
}

struct mimimi_behavior *mimimi_collision(int count, struct mimimi_position **positions, int proximity, int height, int strength, int tolerance, struct mimimi_allocator *allocator)
{
	struct mimimi_behavior *compound = mimimi_compound_behavior(allocator);
	struct mimimi_collision *collision = mimimi_compound_allocate(compound, sizeof *collision, allocator);
	collision->count = count;
	collision->positions = positions;
	collision->strength = strength;
	collision->proximity = proximity;
	collision->height = height;
	collision->tolerance = tolerance;
	mimimi_compound(compound, mimimi_function(collision, &mimimi_collide, allocator));
	return compound;
}