mirror of
https://git.davidovski.xyz/rectangles.git
synced 2024-08-15 00:43:36 +00:00
Generate non-overlapping collisions
This commit is contained in:
commit
83e3b21ae6
3 changed files with 171 additions and 0 deletions
15
Makefile
Normal file
15
Makefile
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
PROG=rectangles
|
||||||
|
CC=gcc
|
||||||
|
FLAGS=-lm -lraylib
|
||||||
|
|
||||||
|
.DEFAULT_GOAL := build
|
||||||
|
|
||||||
|
install: ${PROG}
|
||||||
|
cp ${PROG} ${PREFIX}/bin/
|
||||||
|
|
||||||
|
build: ${PROG}.c
|
||||||
|
${CC} ${PROG}.c -o ${PROG} ${FLAGS}
|
||||||
|
|
||||||
|
clean: ${PROG}
|
||||||
|
rm ${PROG}
|
||||||
|
|
8
README.md
Normal file
8
README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Rectangles
|
||||||
|
|
||||||
|
A simple proof of concept algorithm to combine multiple tiled rectangles into a smaller number. This can be used to optimise the number of rectangles to check for collision in a game.
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
- C Compiler
|
||||||
|
- raylib
|
148
rectangles.c
Executable file
148
rectangles.c
Executable file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <complex.h>
|
||||||
|
#include <raylib.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#define TILESIZE 50
|
||||||
|
|
||||||
|
#define SCREEN_W 800
|
||||||
|
#define SCREEN_H 600
|
||||||
|
#define RECT_COUNT (SCREEN_H / TILESIZE) * (SCREEN_W / TILESIZE)
|
||||||
|
#define GRID_H (int) (SCREEN_W / TILESIZE);
|
||||||
|
#define GRID_W (int) (SCREEN_H / TILESIZE);
|
||||||
|
|
||||||
|
Rectangle rectangles[RECT_COUNT];
|
||||||
|
|
||||||
|
int draw_grid() {
|
||||||
|
// vertical lines
|
||||||
|
for (int x = 0; x < SCREEN_W; x += TILESIZE) {
|
||||||
|
DrawLine(x, 0, x, SCREEN_H, DARKGRAY);
|
||||||
|
}
|
||||||
|
// vertical lines
|
||||||
|
for (int y = 0; y < SCREEN_H; y += TILESIZE) {
|
||||||
|
DrawLine(0, y, SCREEN_W, y, DARKGRAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rect_valid(Rectangle rect) {
|
||||||
|
return rect.width || rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int draw_rectangles() {
|
||||||
|
for (int i = 0; i < RECT_COUNT; i++) {
|
||||||
|
Rectangle rectangle = rectangles[i];
|
||||||
|
if (rect_valid(rectangle)) {
|
||||||
|
DrawRectangleRec(rectangle, DARKGRAY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int rects_touch_y(Rectangle rect_a, Rectangle rect_b) {
|
||||||
|
return rect_a.x == rect_b.x && rect_a.width == rect_b.width &&
|
||||||
|
(rect_a.y == rect_b.y + rect_b.height ||
|
||||||
|
rect_b.y == rect_a.y + rect_a.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
int rects_touch_x(Rectangle rect_a, Rectangle rect_b) {
|
||||||
|
return rect_a.y == rect_b.y && rect_a.height == rect_b.height &&
|
||||||
|
(rect_a.x == rect_b.x + rect_b.width ||
|
||||||
|
rect_b.x == rect_a.x + rect_a.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int draw_optimised_rectangles() {
|
||||||
|
Rectangle *optimised = malloc(sizeof(Rectangle) * RECT_COUNT);
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
// copy rectangles to optimised
|
||||||
|
|
||||||
|
for (int i = 0; i < RECT_COUNT; i++) {
|
||||||
|
Rectangle rectangle = rectangles[i];
|
||||||
|
if (rect_valid(rectangle)) {
|
||||||
|
optimised[i] = rectangle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle rect_a, rect_b;
|
||||||
|
|
||||||
|
// merge rectangles in x direction
|
||||||
|
|
||||||
|
for (int i = 0; i < RECT_COUNT; i++) {
|
||||||
|
if (rect_valid(rect_a = optimised[i]))
|
||||||
|
for (int j = 0; j < RECT_COUNT; j++) {
|
||||||
|
if (i != j && rect_valid(rect_b = optimised[j])
|
||||||
|
&& rects_touch_x(rect_a, rect_b)) {
|
||||||
|
optimised[i].x = rect_a.x < rect_b.x ? rect_a.x : rect_b.x;
|
||||||
|
optimised[i].width = rect_a.width + rect_b.width;
|
||||||
|
rect_a = optimised[i];
|
||||||
|
// delete j
|
||||||
|
optimised[j].width = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// merge rectangles in y direction
|
||||||
|
|
||||||
|
for (int i = 0; i < RECT_COUNT; i++) {
|
||||||
|
if (rect_valid(rect_a = optimised[i]))
|
||||||
|
for (int j = 0; j < RECT_COUNT; j++) {
|
||||||
|
if (i != j && rect_valid(rect_b = optimised[j])
|
||||||
|
&& rects_touch_y(rect_a, rect_b)) {
|
||||||
|
|
||||||
|
optimised[i].y = rect_a.y < rect_b.y ? rect_a.y : rect_b.y;
|
||||||
|
optimised[i].height = rect_a.height + rect_b.height;
|
||||||
|
rect_a = optimised[i];
|
||||||
|
// delete j
|
||||||
|
optimised[j].width = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle rectangle;
|
||||||
|
for (int i = 0; i < RECT_COUNT; i++) {
|
||||||
|
if (rect_valid(rectangle = optimised[i]))
|
||||||
|
DrawRectangleLinesEx(rectangle, 2, GREEN);
|
||||||
|
}
|
||||||
|
free(optimised);
|
||||||
|
}
|
||||||
|
|
||||||
|
int draw() {
|
||||||
|
BeginDrawing();
|
||||||
|
ClearBackground(LIGHTGRAY);
|
||||||
|
|
||||||
|
draw_grid();
|
||||||
|
draw_rectangles();
|
||||||
|
draw_optimised_rectangles();
|
||||||
|
|
||||||
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
||||||
|
int gridx = (int) floor(GetMouseX() / TILESIZE);
|
||||||
|
int gridy = (int) floor(GetMouseY() / TILESIZE);
|
||||||
|
|
||||||
|
Rectangle rectangle = (Rectangle){gridx * TILESIZE, gridy * TILESIZE, TILESIZE, TILESIZE};
|
||||||
|
|
||||||
|
// keep rectangles in order so that larger y and x are more right / left
|
||||||
|
int rect_index = gridx + gridy*GRID_H;
|
||||||
|
rectangles[rect_index] = rectangle;
|
||||||
|
}
|
||||||
|
|
||||||
|
EndDrawing();
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
SetTargetFPS(60);
|
||||||
|
InitWindow(SCREEN_W, SCREEN_H, "Rectangles");
|
||||||
|
|
||||||
|
for (int i = 0; i < RECT_COUNT; i++) {
|
||||||
|
rectangles[i] = (Rectangle){0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!WindowShouldClose()) {
|
||||||
|
draw();
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseWindow();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue