Fistashka & Pipius
Hey Pipius, imagine if we could code a game where the level layout spins around like a spinning top every time you hit a buttonāwould you be up for the challenge?
That sounds insane, but I love insane. Letās hash out a physics engine that treats the map as a rigid body, use a quaternion rotation around the center of mass each button press, and keep the collision mesh updated on the fly. Iāll start with a simple 2D prototype in SDL, then expand to 3D with my own light physics loop. Donāt worry about the UI, Iāll throw that out the window if it slows me down. Ready to spin?
Wow, this is going to be a whirlwind! Iām all ināletās spin this into a wild ride! Just give me the first chunk of code, and Iāll jump in with a crazy idea for the collision mesh update. Letās keep the UI optional, because who needs it when you can dance on the edge of physics? Let's do it!
```c
// spinning_level.c
#include <SDL.h>
#include <math.h>
#define WIDTH 800
#define HEIGHT 600
#define ROT_SPEED 0.05
typedef struct {
SDL_Rect rect;
double angle; // current rotation angle
} Tile;
Tile tiles[10]; // simple 10 tiles for demo
int numTiles = 10;
void initTiles() {
for (int i = 0; i < numTiles; ++i) {
tiles[i].rect.x = i * 70 + 50;
tiles[i].rect.y = HEIGHT / 2 - 25;
tiles[i].rect.w = 60;
tiles[i].rect.h = 50;
tiles[i].angle = 0;
}
}
void rotateTile(Tile *t, double delta) {
t->angle += delta;
if (t->angle > 2*M_PI) t->angle -= 2*M_PI;
if (t->angle < 0) t->angle += 2*M_PI;
}
int main() {
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *win = SDL_CreateWindow("Spin",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
WIDTH, HEIGHT, 0);
SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
initTiles();
int running = 1;
while (running) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT) running = 0;
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_SPACE) {
for (int i = 0; i < numTiles; ++i)
rotateTile(&tiles[i], ROT_SPEED);
}
}
SDL_SetRenderDrawColor(ren, 30, 30, 30, 255);
SDL_RenderClear(ren);
for (int i = 0; i < numTiles; ++i) {
SDL_Rect r = tiles[i].rect;
SDL_Point center = { r.x + r.w/2, r.y + r.h/2 };
SDL_RenderSetScale(ren, 1, 1); // reset scale
SDL_RenderSetViewport(ren, NULL);
// rotate the renderer's matrix
SDL_RenderSetScale(ren, cos(tiles[i].angle), sin(tiles[i].angle));
SDL_SetRenderDrawColor(ren, 200, 100, 50, 255);
SDL_RenderFillRect(ren, &r);
}
SDL_RenderPresent(ren);
SDL_Delay(16);
}
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
```
OMG, thatās already a cool start, but letās crank it up a notch! Instead of trying to spin the renderer matrix, use `SDL_RenderCopyEx` to rotate each tile around its center ā itās way smoother. Also, the scale trick with cos/sin is a bit wonky; youāll end up squashing the tiles. And hey, maybe keep a simple vector for the center of mass and rotate the whole array of tiles around that point, so the whole level feels like a spinning carousel. Ready to swap the math for real rotation and watch the chaos unfold? Let's do it!
Got it, letās ditch the matrix hack and use SDL_RenderCopyEx for true rotation. Iāll keep a global center of mass, rotate each tileās position around it, and pass that to RenderCopyEx. Hereās the updated chunk:
```c
// add this near the top
typedef struct { double x, y; } Vec2;
Vec2 cm = { WIDTH/2.0, HEIGHT/2.0 };
// rotate a point around cm
Vec2 rotatePoint(Vec2 p, double ang) {
double s = sin(ang), c = cos(ang);
Vec2 np;
np.x = (p.x - cm.x)*c - (p.y - cm.y)*s + cm.x;
np.y = (p.x - cm.x)*s + (p.y - cm.y)*c + cm.y;
return np;
}
void renderTiles(SDL_Renderer *ren) {
for (int i = 0; i < numTiles; ++i) {
SDL_Rect dst = tiles[i].rect;
Vec2 pos = {dst.x + dst.w/2, dst.y + dst.h/2};
pos = rotatePoint(pos, tiles[i].angle);
dst.x = pos.x - dst.w/2;
dst.y = pos.y - dst.h/2;
SDL_SetRenderDrawColor(ren, 200, 100, 50, 255);
SDL_RenderFillRect(ren, &dst); // for now, just fill
// eventually swap with RenderCopyEx using a texture
}
}
// in the main loop after input handling
for (int i = 0; i < numTiles; ++i)
rotateTile(&tiles[i], ROT_SPEED);
renderTiles(ren);
```
Now every tile spins around the shared center, and you can later swap the fill for a real sprite via RenderCopyEx. Time to see the chaos.
Sounds like a blast! š Just one quick tweakāmake sure the rotation angle stays in 0ā2Ļ, otherwise the tiles will get a little⦠offābeat. And when you swap in textures, donāt forget to set the pivot point in `SDL_RenderCopyEx` so they spin right where you want. Canāt wait to see that whole level doing the salsa dance! Keep the energy up!
Just keep the angle in [0,2Ļ] with a quick if after rotateTile. For the texture swap, pass the tileās center as the second point in RenderCopyEx. That way the pivot stays fixed and the salsa spins clean. Youāll see the whole level groove. Keep that math tight, donāt let the tiles drift. Let's crank the dance floor.
Got itātight angles, tight groove. Just load a texture per tile, set the pivot to that center, and let RenderCopyEx do the dancing. Weāll make sure nothing drifts, all spinning in sync. Ready to crank this into a full-on rave? Let's spin!
Yeah, letās load a PNG per tile, create a texture array, and in the render loop do
```
SDL_RenderCopyEx(ren, tex[i], NULL, &dst, tiles[i].angle, &pivot, SDL_FLIP_NONE);
```
where `pivot` is the tileās center. Thatāll keep everything in sync and give that perfect salsa spin. Bring on the rave!
Okay, letās fire up the rave!
First load every tileās PNG into a texture array (just one line per tile for now):
SDL_Texture *tex[10];
for (int i=0;i<numTiles;++i){
Ā Ā Ā Ā SDL_Surface *surf = IMG_Load("tile.png"); // use a different name if you want unique images
Ā Ā Ā Ā tex[i] = SDL_CreateTextureFromSurface(ren,surf);
Ā Ā Ā Ā SDL_FreeSurface(surf);
}
Then in your render loop use the pivotācenter trick you mentioned:
for (int i=0;i<numTiles;++i){
Ā Ā Ā Ā SDL_Rect dst = tiles[i].rect;
Ā Ā Ā Ā Vec2 pos = {dst.x+dst.w/2, dst.y+dst.h/2};
Ā Ā Ā Ā pos = rotatePoint(pos,tiles[i].angle);
Ā Ā Ā Ā dst.x = pos.x-dst.w/2;
Ā Ā Ā Ā dst.y = pos.y-dst.h/2;
Ā Ā Ā Ā SDL_Point pivot = {dst.w/2, dst.h/2};
Ā Ā Ā Ā SDL_RenderCopyEx(ren,tex[i],NULL,&dst,tiles[i].angle*180/3.1415926535,&pivot,SDL_FLIP_NONE);
}
Donāt forget to destroy the textures at the end with SDL_DestroyTexture(tex[i]).
Now crank up that music and let the tiles salsa!
Nice, thatās the exact snippet I needāeach tile gets its own texture, we keep the angle wrapped, pivot in the center, and RenderCopyEx does all the heavy lifting. Once I hook up the music and bump the frame rate a bit more, the level will be doing its salsa dance real fast. Time to fire it up!
Woohoo, get ready for the ultimate salsa showdownālet those tiles spin, drop the beat, and watch the level groove faster than a hummingbird on caffeine! Have fun rocking that rave!
Sounds like a codeāfestival! Iāll crank the FPS up, drop a looping drumbeat, and watch those textures spin like a glitchāart rave. Let the pixels dance!