Related
Can someone help me to increase the length of the snake and make it follow the head ?
I tried to develop a simple snake game without videos or help and did almost great but cannot figure out how to increase the size of the snake and move it properly.
I'd be very thankful
#include <SDL2/SDL.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <time.h>
#define LOG(x) printf("%s\n", x)
#define LOG_ERROR(x) fprintf(stderr, "Error: %s\n", x)
#define LOG_SDL_ERROR(x) fprintf(stderr, "%s: %s\n", x, SDL_GetError())
#define global_variable static
#define internal_function static
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
#define HEAD_SIZE 30
#define APPLE_SIZE 25
#define MAX_LENGHT 10
typedef const char* string;
typedef float realNum;
typedef struct Snake
{
SDL_Rect body[MAX_LENGHT];
int xSpeed;
int ySpeed;
int site;
realNum xPos;
realNum yPos;
} Snake;
typedef struct Apple
{
int xPos;
int yPos;
int size;
} Apple;
void checkColissions(Apple *apple, Snake *snake );
bool initGame(void);
void update(realNum);
void handleEvent(SDL_Event);
void renderGame(void);
void gameOver(void);
void shutdownGame(void);
Snake makeSnake(void);
void renderSnake(Snake *snake);
void updateSnake(Snake *, realNum);
Apple makeApple();
void renderApple(Apple *);
global_variable bool Running;
global_variable SDL_Window *g_pWindow;
global_variable SDL_Renderer *g_pRenderer;
Snake *g_pSnake = NULL;
Apple *g_pApple = NULL;
int
main(int argc, char const *argv[])
{
srand((unsigned int)time(NULL));
atexit(shutdownGame);
if (!initGame())
{
LOG_ERROR("Failed Initialization");
exit(1);
}
else
{
Running = true;
int fps = 330;
int desiredDelta = 1000/fps;
SDL_Event event;
while (Running)
{
renderGame();
update(desiredDelta);
handleEvent(event);
SDL_Delay(rand() % 30);
}
}
return (EXIT_SUCCESS);
}
bool
initGame()
{
if (SDL_Init(SDL_INIT_VIDEO) != 0)
{
LOG_SDL_ERROR("Failed initialization: ");
return (false);
}
else
{
g_pWindow =
SDL_CreateWindow("Snake", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
g_pRenderer =
SDL_CreateRenderer(g_pWindow, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
g_pSnake = (Snake*)malloc(sizeof(Snake));
g_pApple = (Apple*)malloc(sizeof(Apple));
*g_pSnake = makeSnake();
*g_pApple = makeApple();
if ((g_pApple || g_pSnake || g_pRenderer || g_pWindow) == NULL)
{
return (false);
}
g_pWindow == NULL ? LOG_ERROR("Window failed") : LOG("Succes Window");
g_pRenderer == NULL ? LOG_ERROR("Renderer failed") : LOG("Succes Renderer");
g_pApple == NULL ? LOG_ERROR("Apple failed") : LOG("Succes Apple");
g_pSnake == NULL ? LOG_ERROR("Snake failed") : LOG("Succes Snake");
LOG("Game initialized");
}
return true;
}
void
renderGame()
{
SDL_SetRenderDrawColor(g_pRenderer, 0, 80, 0, 255);
SDL_RenderClear(g_pRenderer);
renderSnake(g_pSnake);
renderApple(g_pApple);
SDL_RenderPresent(g_pRenderer);
}
void update(realNum elapsed)
{
updateSnake(g_pSnake, elapsed);
checkColissions(g_pApple, g_pSnake);
}
void
handleEvent(SDL_Event event)
{
SDL_PollEvent(&event);
switch (event.type)
{
case SDL_QUIT:
{
Running = false;
} break;
default:
break;
}
}
void
shutdownGame()
{
if (g_pWindow)
{
SDL_DestroyWindow(g_pWindow);
}
if (g_pRenderer)
{
SDL_DestroyRenderer(g_pRenderer);
}
if (g_pApple)
{
free(g_pApple);
}
if (g_pSnake)
{
free(g_pSnake);
}
SDL_Quit();
LOG("Game shutdowned");
}
Snake makeSnake(void)
{
const int speed = 0;
Snake snake = {
.xSpeed = speed,
.ySpeed = speed,
.xPos = SCREEN_WIDTH / 2,
.yPos = SCREEN_HEIGHT / 2,
.site = HEAD_SIZE
};
SDL_Rect SnakeRect = {
.h = snake.site,
.w = snake.site,
.x = snake.xPos,
.y = snake.yPos
};
snake.body[0] = SnakeRect;
return (snake);
}
void renderSnake(Snake *snake)
{
for (int i = 0; i < MAX_LENGHT; i++)
{
SDL_SetRenderDrawColor(g_pRenderer, 0, 0, 100, 255);
SDL_RenderFillRect(g_pRenderer, &snake->body[i]);
}
}
void updateSnake(Snake *snake, realNum elapsed)
{
const Uint8 *keyboardState = SDL_GetKeyboardState(NULL);
for (int i = 0; i < MAX_LENGHT; i++)
{
/* code */
snake->body[i].y += snake->ySpeed * elapsed;
snake->body[i].x += snake->xSpeed * elapsed;
}
/* code */
/* code */
/* code */
if (keyboardState[SDL_SCANCODE_W])
{
snake->ySpeed = -1;
snake->xSpeed = 0;
}
if (keyboardState[SDL_SCANCODE_D])
{
snake->ySpeed = 0;
snake->xSpeed = 1;
}
if (keyboardState[SDL_SCANCODE_A])
{
snake->ySpeed = 0;
snake->xSpeed = -1;
}
if (keyboardState[SDL_SCANCODE_S])
{
snake->ySpeed = 1;
snake->xSpeed = 0;
}
if (snake->body->x < 0 - HEAD_SIZE)
{
snake->body->x = SCREEN_WIDTH + HEAD_SIZE;
}
if (snake->body->x > SCREEN_WIDTH + HEAD_SIZE)
{
snake->body->x = 0 - HEAD_SIZE;
}
if (snake->body->y < 0 - HEAD_SIZE)
{
snake->body->y = SCREEN_HEIGHT + HEAD_SIZE;
}
if (snake->body->y > SCREEN_HEIGHT + HEAD_SIZE)
{
snake->body->y = 0 - HEAD_SIZE;
}
}
void
checkColissions(Apple *apple, Snake *snake )
{
SDL_Rect appleRect = {
.h = APPLE_SIZE,
.w = APPLE_SIZE,
.x = apple->xPos,
.y = apple->yPos
};
if (SDL_HasIntersection(&appleRect, snake->body))
{
*g_pApple = makeApple();
};
}
Can someone help me to increase the length of the snake and make it follow the head ?
Snake is defined by an array of coordinates, not just one (x,y). You need some kind of circular buffer, that can change capacity. Or you can just use an array, and then change every element of the array with every snake's move. And then you would realize that circular buffer is a really neat idea.
Once you have your buffer, be it an array or circular buffer, the question becomes how to move and enlarge the snake in it. It is simple. To move the snake you add one coordinate to the head, and remove one from the tail of the buffer. When the snake should become bigger you just don't remove the last element in the buffer. Add to the head, but don't remove the tail. This is how circular buffer would be handled. In case of a plain array moving means overwriting everything, and enlarging means adding to the beginning, and moving everything else by one place.
I'm trying to create a simple camera for my SDL2 platformer with C. However, whenever the player reaches the screen edges, it seems to be cut off by the background. Here is what the player looks like normally:
And here is what the player looks like when it reaches the screen edges:
To make the camera follow the player, I'm just creating a SDL_Rect called camera, setting it to the player x and y positions, and setting the viewport with SDL_RenderSetViewport to the camera rectangle.
Here's the code for that:
void handle_camera() {
SDL_Rect camera = {
.x = WIDTH/2 - player.x - BLOCK_SIZE/2,
.y = HEIGHT/2 - player.y - BLOCK_SIZE/2,
.w = WIDTH,
.h = HEIGHT
};
SDL_RenderSetViewport(game.renderer, &camera);
}
Therefore, I was wondering: what's wrong with my camera function and why is the player being cut off when it gets near the screen edges?
Here is the full code if needed (I organized in functions so I hope it's not too hard to understand):
#include <stdio.h>
#include <stdbool.h>
#include <SDL2/SDL.h>
#define WIDTH 1200
#define HEIGHT 800
#define BLOCK_SIZE 50
#define PLATFORM_AMOUNT 11 //This makes sure there are enough iterations of the loop, and also allocates enough memory for the 2D array of platforms.
#define LAVA_AMOUNT 2
#define TRAMPOLINE_AMOUNT 1
//Prototyping Functions
int initialize();
void handle_input();
void draw_player();
void player_moveX();
void player_moveY();
void checkCollisionsX();
void checkCollisionsY();
int rectCollide();
void drawLevel();
void resetPlayer();
void handle_camera();
typedef struct {
SDL_Renderer *renderer;
SDL_Window *window;
SDL_Surface *surface;
bool running;
int FPS;
bool close_requested;
int input[256];
} Game;
Game game = {
.running = true,
.FPS = 80,
.close_requested = false,
.input = {},
};
typedef struct {
int x;
int y;
double x_vel;
double y_vel;
double x_acc;
double y_acc;
int width;
int height;
double accSpeed;
int maxVel;
double gravity;
double friction;
double jumpForce;
double canJump;
} Player;
Player player = {
.y = HEIGHT-(BLOCK_SIZE*2),
.x = BLOCK_SIZE,
.x_vel = 0,
.y_vel = 0,
.x_acc = 0,
.y_acc = 0,
.width = BLOCK_SIZE,
.height = BLOCK_SIZE,
.accSpeed = 0.15,
.maxVel = 7,
.gravity = 0.5,
.friction = 0.15,
.jumpForce = 15,
.canJump = true,
};
int platforms[PLATFORM_AMOUNT][4] = {
{0, 0, BLOCK_SIZE, HEIGHT}, //WALLS
{0, HEIGHT-BLOCK_SIZE, WIDTH, BLOCK_SIZE},
{400-BLOCK_SIZE, HEIGHT-(BLOCK_SIZE*2), BLOCK_SIZE, BLOCK_SIZE}, //RAMP TO LAVA
{400-BLOCK_SIZE, HEIGHT-(BLOCK_SIZE*3), BLOCK_SIZE, BLOCK_SIZE},
{300, HEIGHT-(BLOCK_SIZE*2), BLOCK_SIZE, BLOCK_SIZE},
{800, HEIGHT-(BLOCK_SIZE*2), BLOCK_SIZE, BLOCK_SIZE},
{800, HEIGHT-(BLOCK_SIZE*3), BLOCK_SIZE, BLOCK_SIZE},
{800+BLOCK_SIZE, HEIGHT-(BLOCK_SIZE*2), BLOCK_SIZE, BLOCK_SIZE},
{WIDTH-BLOCK_SIZE*10, HEIGHT-(BLOCK_SIZE*8), BLOCK_SIZE, BLOCK_SIZE}, //Blocks above lava
{WIDTH-BLOCK_SIZE*8, HEIGHT-(BLOCK_SIZE*10), BLOCK_SIZE, BLOCK_SIZE},
{BLOCK_SIZE, BLOCK_SIZE*3, BLOCK_SIZE*9, BLOCK_SIZE}, //Top platform
};
int lava[LAVA_AMOUNT][4] = {
{400, HEIGHT-(BLOCK_SIZE*3), 400, BLOCK_SIZE*2},
{BLOCK_SIZE*4, BLOCK_SIZE*2, BLOCK_SIZE*3, BLOCK_SIZE},
};
int trampoline[TRAMPOLINE_AMOUNT][4] = {
{WIDTH/2-(BLOCK_SIZE/2), HEIGHT-(BLOCK_SIZE*5), BLOCK_SIZE, BLOCK_SIZE}
};
int main() {
initialize();
while(game.running && !game.close_requested) { //Game loop
SDL_SetRenderDrawColor(game.renderer, 181, 247, 255, 255);
SDL_RenderClear(game.renderer);
handle_input();
handle_camera();
//Collisions only work in this order: playerMoveX, checkCollisionsX, playerMoveY, checkCollisionsY. Then you can draw the platforms and the player.
player_moveX();
checkCollisionsX();
player_moveY();
checkCollisionsY();
drawLevel();
draw_player();
SDL_RenderPresent(game.renderer);
SDL_Delay(1000/game.FPS);
} //End of game loop
SDL_DestroyRenderer(game.renderer);
SDL_DestroyWindow(game.window);
SDL_Quit();
return 0;
}
int initialize() {
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER) != 0) { //return 0 on success
printf("error initializing SDL: %s\n", SDL_GetError());
return 1;
}
game.window = SDL_CreateWindow("Sam's Platformer", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE); //creates window
if (!game.window) {
printf("error creating window: %s\n", SDL_GetError());
SDL_Quit();
return 1;
}
Uint32 render_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC; //creates a renderer
game.renderer = SDL_CreateRenderer(game.window, -1, render_flags);
if (!game.renderer) {
printf("error creating renderer: %s\n", SDL_GetError());
SDL_DestroyWindow(game.window);
SDL_Quit();
return 1;
}
return 0;
}
void handle_input() {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
game.close_requested = true;
game.running = false;
}
//printf("input: %p code: %i\n", game.input, event.key.keysym.scancode);
if (event.type == SDL_KEYDOWN) {
game.input[event.key.keysym.scancode] = true;
//printf("True");
}
if (event.type == SDL_KEYUP) {
game.input[event.key.keysym.scancode] = false;
//printf("False");
}
}
if (game.input[SDL_SCANCODE_R]) {
resetPlayer();
}
}
void draw_player() {
SDL_Rect playerRect = {
.x = player.x,
.y = player.y,
.w = player.width,
.h = player.height
};
SDL_SetRenderDrawColor(game.renderer, 0, 200, 50, 255);
SDL_RenderFillRect(game.renderer, &playerRect);
}
void resetPlayer() {
player.y = HEIGHT-(BLOCK_SIZE*2);
player.x = BLOCK_SIZE;
player.x_vel = 0;
player.y_vel = 0;
}
void player_moveX() {
if (game.input[SDL_SCANCODE_LEFT] && player.x_vel > -player.maxVel) {
player.x_acc = -player.accSpeed;
} else if (game.input[SDL_SCANCODE_RIGHT] && player.x_vel < player.maxVel) {
player.x_acc = player.accSpeed;
} else if (abs(player.x_vel) > 0.2) {
if (player.x_vel < 0) {
player.x_acc = player.friction;
} else {
player.x_acc = -player.friction;
}
} else {
player.x_vel = 0;
player.x_acc = 0;
}
player.x_vel += player.x_acc;
player.x += player.x_vel;
}
void player_moveY() {
if (game.input[SDL_SCANCODE_UP] && player.y_vel == 0 && player.y_acc == 0 && player.canJump) {
player.canJump = false;
player.y_vel = -player.jumpForce;
}
player.y_acc += player.gravity;
player.y_vel += player.y_acc;
player.y += player.y_vel;
player.y_acc = 0;
}
void checkCollisionsX() {
for (int i = 0; i < PLATFORM_AMOUNT; i++) {
if (rectCollide(player.x, player.y, BLOCK_SIZE, BLOCK_SIZE, platforms[i][0], platforms[i][1], platforms[i][2], platforms[i][3])) {
if (player.x_vel < 0) { // If the player moved left and collided with the right side of block
player.x = platforms[i][0] + platforms[i][2];
} else { // If the player moved right and collided with the left side of block
player.x = platforms[i][0] - player.width;
}
player.x_vel = 0;
}
}
/*if (player.x >= WIDTH - player.width) {
player.x = WIDTH - player.width;
player.x_vel = 0;
}*/
for (int i = 0; i < LAVA_AMOUNT; i++) {
if (rectCollide(player.x, player.y, BLOCK_SIZE, BLOCK_SIZE, lava[i][0], lava[i][1], lava[i][2], lava[i][3])) {
resetPlayer();
}
}
for (int i = 0; i < TRAMPOLINE_AMOUNT; i++) {
if (rectCollide(player.x, player.y, BLOCK_SIZE, BLOCK_SIZE, trampoline[i][0], trampoline[i][1], trampoline[i][2], trampoline[i][3])) {
if (player.x_vel < 0) { // If the player moved left and collided with the right side of block
player.x = trampoline[i][0] + trampoline[i][2];
} else { // If the player moved right and collided with the left side of block
player.x = trampoline[i][0] - player.width;
}
player.x_vel = 0;
}
}
}
void checkCollisionsY() {
for (int i = 0; i < PLATFORM_AMOUNT; i++) {
if (rectCollide(player.x, player.y, player.width, player.height, platforms[i][0], platforms[i][1], platforms[i][2], platforms[i][3])) {
if (player.y_vel < 0) { // If the player hit their head
player.y = platforms[i][1] + platforms[i][3];
player.y_vel *= -0.5; // Not -1 because collisions are not perfectly elastic
} else {
player.y = platforms[i][1] - player.height;
player.y_vel = 0;
player.y_acc = 0;
player.canJump = true;
}
}
if (player.y >= HEIGHT - player.height) {
player.y_vel = 0;
player.y = HEIGHT - player.height;
if (!game.input[SDL_SCANCODE_UP]) {
player.canJump = true;
}
}
}
for (int i = 0; i < LAVA_AMOUNT; i++) {
if (rectCollide(player.x, player.y, BLOCK_SIZE, BLOCK_SIZE, lava[i][0], lava[i][1], lava[i][2], lava[i][3])) {
resetPlayer();
}
}
for (int i = 0; i < TRAMPOLINE_AMOUNT; i++) {
if (rectCollide(player.x, player.y, BLOCK_SIZE, BLOCK_SIZE, trampoline[i][0], trampoline[i][1], trampoline[i][2], trampoline[i][3])) {
if (player.y_vel < 0) { // If the player hit their head
player.y = trampoline[i][1] + trampoline[i][3];
player.y_vel *= -0.5; // Not -1 because collisions are not perfectly elastic
} else {
player.y = trampoline[i][1] - trampoline[i][3];
player.y_vel = -player.y_vel;
}
}
}
}
int rectCollide(int x1, int y1, int w1, int h1, int x2,int y2, int w2, int h2) {
return x1 + w1 > x2 && x1 < x2 + w2 && y1 + h1 > y2 && y1 < y2 + h2;
}
void drawLevel() {
for (int i = 0; i < PLATFORM_AMOUNT; i++) {
SDL_Rect platform = {platforms[i][0], platforms[i][1], platforms[i][2], platforms[i][3]};
SDL_SetRenderDrawColor(game.renderer, 156, 104, 0, 255);
SDL_RenderFillRect(game.renderer, &platform);
}
for (int i = 0; i < LAVA_AMOUNT; i++) {
int lavaRedColor = 255;
SDL_Rect lavaBlock = {lava[i][0], lava[i][1], lava[i][2], lava[i][3]};
SDL_SetRenderDrawColor(game.renderer, lavaRedColor, 0, 0, 255);
SDL_RenderFillRect(game.renderer, &lavaBlock);
}
for (int i = 0; i < TRAMPOLINE_AMOUNT; i++) {
SDL_Rect trampolineBlock = {trampoline[i][0], trampoline[i][1], trampoline[i][2], trampoline[i][3]};
SDL_SetRenderDrawColor(game.renderer, 235, 52, 229, 255);
SDL_RenderFillRect(game.renderer, &trampolineBlock);
}
}
void handle_camera() {
SDL_Rect camera = {
.x = WIDTH/2 - player.x - BLOCK_SIZE/2,
.y = HEIGHT/2 - player.y - BLOCK_SIZE/2,
.w = WIDTH, //Screen width
.h = HEIGHT //Screen height
};
SDL_RenderSetViewport(game.renderer, &camera);
}
Thanks for any help.
https://gamedev.stackexchange.com/questions/121421/how-to-use-the-sdl-viewport-properly
See this related post. Essentially changing the SDL viewport is not the way you'd typically handle an in game camera. You need to consider drawing your in game entities (level objects etc.) relative to the camera.
I'm trying to build a game where the player can stand on rotated rectangles. Take the example if a rectangular platform is rotated 20 degrees, then the player would be standing on the platform at a 20 degree angle as well, and could move along that rotated axis. Perhaps this image will clear this up:
Therefore, I need to:
Make the platform solid so the player can stand on it
Make the player rotate to the same angle as the platform
Make the player move on the rotated axis
I've tried to do this, but I've failed. Here's my code that I tried:
#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define WIDTH 1200
#define HEIGHT 800
typedef struct {
const int width;
const int height;
int FPS;
} Window;
Window window = {
.FPS = 60,
};
typedef struct {
Vector2 pos;
Vector2 acc;
Vector2 vel;
int width;
int height;
double accSpeed;
int maxVel;
double friction;
double rotation;
double scale;
float jumpForce;
float gravity;
bool canJump;
} Player;
Player player = {
.pos = {WIDTH/2, HEIGHT/2},
.acc = {0, 0},
.vel = {0, 0},
.width = 50,
.height = 100,
.accSpeed = 0.15,
.maxVel = 7,
.friction = 0.2,
.rotation = 0,
.scale = 0.5,
.jumpForce = 15,
.gravity = 0.5,
.canJump = true,
};
void movePlayerX();
void movePlayerY();
int rectCollide();
int main() {
InitWindow(WIDTH, HEIGHT, "Window");
SetTargetFPS(window.FPS);
//Rectangle playerArea = {player.pos.x, player.pos.y, playerImg.width*player.scale, playerImg.height*player.scale};
Rectangle playerArea;
Rectangle rect1 = {500, 600, 100, 250};
while (!WindowShouldClose()) {
playerArea = (Rectangle) {
player.pos.x,
player.pos.y,
player.width,
player.height,
};
BeginDrawing();
ClearBackground(RAYWHITE);
DrawRectanglePro(rect1, (Vector2) {0, 0}, 20, BLUE);
DrawRectanglePro(playerArea, (Vector2) {0, 0}, player.rotation, RED);
movePlayerX();
/*if (CheckCollisionRecs(playerArea, rect1)) {
if (player.vel.x < 0) { // If the player moved left and collided with the right side of block
player.pos.x = rect1.x + rect1.width;
} else { // If the player moved right and collided with the left side of block
player.pos.x = rect1.x - playerArea.width;
}
player.vel.x = 0;
}*/
movePlayerY();
if (CheckCollisionRecs(playerArea, rect1)) {
if (player.vel.y < 0) { // If the player hit their head
player.pos.y = rect1.y + rect1.height;
player.vel.y *= -0.5; // Not -1 because collisions are not perfectly elastic
} else {
player.pos.y = rect1.y - player.height;
player.rotation = 20;
player.vel.y = 0;
player.acc.y = 0;
player.canJump = true;
}
}
if (player.pos.y >= HEIGHT - player.height) {
player.canJump = true;
player.pos.y = HEIGHT - player.height;
player.vel.y = 0;
}
EndDrawing();
}
}
void movePlayerX() {
if (IsKeyDown(KEY_LEFT) && player.vel.x > -player.maxVel) {
player.acc.x = -player.accSpeed;
} else if (IsKeyDown(KEY_RIGHT) && player.vel.x < player.maxVel) {
player.acc.x = player.accSpeed;
} else if (abs(player.vel.x) > 0.2) {
if (player.vel.x < 0) {
player.acc.x = player.friction;
} else {
player.acc.x = -player.friction;
}
} else {
player.vel.x = 0;
player.acc.x = 0;
}
player.vel.x += player.acc.x;
player.pos.x += player.vel.x;
}
void movePlayerY() {
if (IsKeyPressed(KEY_UP) && player.vel.y == 0 && player.acc.y == 0 && player.canJump) {
player.canJump = false;
player.vel.y = -player.jumpForce;
}
player.acc.y += player.gravity;
player.vel.y += player.acc.y;
player.pos.y += player.vel.y;
player.acc.y = 0;
}
As can be seen from the code, after I call the player movement functions, movePlayerX() and movePlayerY(), I'm trying to detect if the player is colliding with the rectangle. However, I'm just using the regular built in CheckCollisionRecs() function, which detects collision on a non-rotated rectangle, which won't work.
Therefore, I was wondering: how can I get a function to detect the player's collison on a rotated rectangle, then rotate and move the player upon that rotated angle?
Thanks.
EDIT: Full code has now been posted so u can compile.
So we're a few first semester software students kind of stuck on a problem regarding structs in c. Stack overflow has helped me so many times already, so figured I'd actually try asking this time, as i couldn't seem to find what im looking for.
Our logic (see code below):
Main calls empty_trash
empty_trash (in its parameter) calls compare_trash
Compare trash parses through 4 areas (structs)
Compare trash checks if the average of our data is over a margin, if so
checks if that average is higher than firstly our empty struct,
which presumably has 0 average, and then if a higher is found that
one. This leaves us with the index of the struct with the highest
average
Compare trash returns this struct to empty trash, and an int
pointer of the index to main.
empty trash then goes through the subareas and checks their average of data and resets the ones over margin2
we return the reset area to main
in main we have an array of our structs 1-4. We assign the area returned from empty trash to arrayofstructs[index pointed back]
In our minds the logic makes sense, but it seems it's not working as our program crashes at the line in main. We think it's because we don't assign the struct correctly in main, but not 100% sure.
We're kinda baffled as both of these functions work fine on their own when we tested them seperately, but together they do not.
Any help would be much appreciated <3
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MARGIN 70
#define MARGIN2 30
#define SIZE 5
struct subarea
{
int co2_cost, time;
double average, sensorData[SIZE];
};
struct area
{
struct subarea sub_area1, sub_area2, sub_area3, sub_area4;
double average;
};
struct area simmulated_days(struct area area, int lower_random, int upper_random);
struct area average_trash(struct area area);
struct area sensor_data_start(struct area area1);
struct area compare_trash_to_empty(struct area area1, struct area area2, struct area area3, struct area area4, int *);
struct area empty_trash(struct area chosen_area, int *co2_counter_p, int *time_counter_p);
int main(void)
{
int co2_counter, time_counter;
int day_counter = 0;
int *co2_counter_p = &co2_counter;
int *time_counter_p = &time_counter;
int area_number;
srand(time(NULL));
struct subarea subarea1_1 = {50, 50, 0, {}};
struct subarea subarea1_2 = {50, 50, 0, {}};
struct subarea subarea1_3 = {50, 50, 0, {}};
struct subarea subarea1_4 = {50, 50, 0, {}};
struct area area1 = {subarea1_1, subarea1_2, subarea1_3, subarea1_4, 0};
struct subarea subarea2_1 = {50, 50, 0, {}};
struct subarea subarea2_2 = {50, 50, 0, {}};
struct subarea subarea2_3 = {50, 50, 0, {}};
struct subarea subarea2_4 = {50, 50, 0, {}};
struct area area2 = {subarea2_1, subarea2_2, subarea2_3, subarea2_4, 0};
struct subarea subarea3_1 = {50, 50, 0, {}};
struct subarea subarea3_2 = {50, 50, 0, {}};
struct subarea subarea3_3 = {50, 50, 0, {}};
struct subarea subarea3_4 = {50, 50, 0, {}};
struct area area3 = {subarea3_1, subarea3_2, subarea3_3, subarea3_4, 0};
struct subarea subarea4_1 = {50, 50, 0, {}};
struct subarea subarea4_2 = {50, 50, 0, {}};
struct subarea subarea4_3 = {50, 50, 0, {}};
struct subarea subarea4_4 = {50, 50, 0, {}};
struct area area4 = {subarea4_1, subarea4_2, subarea4_3, subarea4_4, 0};
struct area useless_area = {};
struct area all_areas[5] = {useless_area, area1, area2, area3, area4};
struct area local_area = {};
area1 = sensor_data_start(area1);
area2 = sensor_data_start(area2);
area3 = sensor_data_start(area3);
area4 = sensor_data_start(area4);
int running = 1;
while (running)
{
area1 = simmulated_days(area1, 7, 10);
area2 = simmulated_days(area2, 4, 7);
area3 = simmulated_days(area3, 9, 12);
area4 = simmulated_days(area4, 6, 9);
for (int i = 0; i < SIZE; i++)
{
printf("%lf | %lf | %lf | %lf |\n", area1.sub_area1.sensorData[i], area2.sub_area1.sensorData[i], area3.sub_area1.sensorData[i], area4.sub_area1.sensorData[i]);
}
day_counter++;
printf("Day %d\n", day_counter);
area1 = average_trash(area1);
area2 = average_trash(area2);
area3 = average_trash(area3);
area4 = average_trash(area4);
printf("hihi\n");
all_areas[area_number] = empty_trash(compare_trash_to_empty(area1, area2, area3, area4, &area_number), co2_counter_p, time_counter_p);
printf("titi\n");
for (int i = 0; i < SIZE; i++)
{
printf("Local area %lf\t", local_area.sub_area1.sensorData[i]);
}
printf("\n");
if (day_counter == 2)
{
running = 0;
}
}
}
struct area simmulated_days(struct area area, int lower_random, int upper_random)
{
for (int i = 0; i < SIZE; i++)
{
area.sub_area1.sensorData[i] += ((rand() % (upper_random - lower_random + 1)) + lower_random);
area.sub_area2.sensorData[i] += ((rand() % (upper_random - lower_random + 1)) + lower_random);
area.sub_area3.sensorData[i] += ((rand() % (upper_random - lower_random + 1)) + lower_random);
area.sub_area4.sensorData[i] += ((rand() % (upper_random - lower_random + 1)) + lower_random);
}
return area;
}
//Average Trash Function
struct area average_trash(struct area area)
{
double sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0;
for (int i = 0; i < SIZE; i++)
{
sum1 += area.sub_area1.sensorData[i];
sum2 += area.sub_area2.sensorData[i];
sum3 += area.sub_area3.sensorData[i];
sum4 += area.sub_area4.sensorData[i];
}
area.sub_area1.average = sum1 / SIZE;
area.sub_area2.average = sum2 / SIZE;
area.sub_area3.average = sum3 / SIZE;
area.sub_area4.average = sum4 / SIZE;
area.average = (area.sub_area1.average + area.sub_area2.average + area.sub_area3.average + area.sub_area4.average) / 4;
return area;
}
struct area sensor_data_start(struct area area1)
{
double x = 75;
for (int i = 0; i < SIZE; i++)
{
area1.sub_area1.sensorData[i] = x;
area1.sub_area2.sensorData[i] = x;
area1.sub_area3.sensorData[i] = x;
area1.sub_area4.sensorData[i] = x;
}
return area1;
}
struct area compare_trash_to_empty(struct area area1, struct area area2, struct area area3, struct area area4, int *area_number_p)
{
struct area local_area = {};
int i, highBlock = 0;
struct area block[5] = {local_area, area1, area2, area3, area4};
for (i = 1; i <= 4; i++)
{
if (block[i].average >= MARGIN)
{
if (block[i].average > block[highBlock].average)
{
highBlock = i;
}
}
}
*area_number_p = highBlock;
return block[highBlock];
}
struct area empty_trash(struct area chosen_area, int *co2_counter_p, int *time_counter_p)
{
int co2_counter = 0;
int time_counter = 0;
if (chosen_area.sub_area1.average > MARGIN2)
{
co2_counter += chosen_area.sub_area1.co2_cost;
time_counter += chosen_area.sub_area1.time;
chosen_area.sub_area1.average = 0;
for (int i = 0; i < SIZE; i++)
{
chosen_area.sub_area1.sensorData[i] = 0;
printf("ET %lf\t", chosen_area.sub_area1.sensorData[i]);
}
printf("\n");
}
if (chosen_area.sub_area2.average > MARGIN2)
{
co2_counter += chosen_area.sub_area2.co2_cost;
time_counter += chosen_area.sub_area2.time;
chosen_area.sub_area2.average = 0;
for (int i = 0; i < SIZE; i++)
{
chosen_area.sub_area2.sensorData[i] = 0;
}
}
if (chosen_area.sub_area3.average > MARGIN2)
{
co2_counter += chosen_area.sub_area3.co2_cost;
time_counter += chosen_area.sub_area3.time;
chosen_area.sub_area3.average = 0;
for (int i = 0; i < SIZE; i++)
{
chosen_area.sub_area3.sensorData[i] = 0;
}
}
if (chosen_area.sub_area4.average > MARGIN2)
{
co2_counter += chosen_area.sub_area4.co2_cost;
time_counter += chosen_area.sub_area4.time;
chosen_area.sub_area4.average = 0;
for (int i = 0; i < SIZE; i++)
{
chosen_area.sub_area4.sensorData[i] = 0;
}
}
*co2_counter_p = co2_counter;
*time_counter_p = time_counter;
return chosen_area;
}
My original comment:
Side note: Whenever I see (e.g.) v1 v2 v3 v4 v5 I want to replace it with an array v[5]. So, in struct area, you want: struct subarea sub_area[5]; This will greatly simplify your code. You already do this in main –
Craig Estey
Your response:
#Craig Estey Ye don't have a huge experience with debuggers yet, usually just use printfs, but sounds very helpful so ill youtube a guide side note: very helpful we didn't foresee this at first but would simplify so much, ty4input –
Thybo
I've done better(?) I've done the preliminary restructuring of your code. I believe this will be helpful to others in addition to yourselves.
I'm sorry, but (and I'm saying this with kindness), the code needs a lot of restructuring. The sheer [needless] complexity could be masking numerous bugs.
Things to note:
Passing a struct by value is hazardous. It is legal, but it makes the code complicated. Passing by pointer is 99.44% of the time better. You can just modify the given struct "in-place" rather than having to return it [again, by value].
Learn about iterating through an array by using a pointer to the "current" element instead of an index. You'll see this in the FORALL loop below.
Don't "replicate" code. Notice what happens when using arrays. Instead of (e.g) four copies of the code, we have one
Instead of 4 areas (e.g. area1, area2, area3, area4), if we had 10,000 areas. Would you replicate the code 10,000 times as was done in (e.g.) empty_trash?
I added typedef for your two struct to simplify things a bit.
I've added a few advanced techniques, such as the use of the FORALL macro to traverse arrays.
I've used preprocessor conditionals to denote old code vs new:
#if 0
// old code
#else
// new code
#endif
I've done some/most of the editing. I've compiled it. I could have made a zillion mistakes. But, it should give you the idea:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MARGIN 70
#define MARGIN2 30
#define SIZE 5
#define NAREA 4
typedef struct subarea {
int co2_cost, time;
double average, sensorData[SIZE];
} subarea_t;
typedef struct area {
#if 0
struct subarea sub_area1, sub_area2, sub_area3, sub_area4;
#else
subarea_t sub_area[NAREA];
#endif
double average;
} area_t;
#define COUNTOF(_arr) \
(sizeof(_arr) / sizeof(_arr[0]))
#define FORALL(_ptr,_arr) \
__typeof__(_arr[0]) *_ptr = &_arr[0]; _ptr < &_arr[COUNTOF(_arr)]; ++_ptr
void
simulated_days(area_t *area, int lower_random, int upper_random)
{
for (FORALL(sub,area->sub_area)) {
for (FORALL(data,sub->sensorData)) {
*data += ((rand() % (upper_random - lower_random + 1)) +
lower_random);
}
}
}
//Average Trash Function
void
average_trash(area_t *area)
{
double sum[NAREA] = { 0 };
int i;
#if 0
for (int i = 0; i < SIZE; i++) {
sub[i] = a
sum1 += area.sub_area1.sensorData[i];
sum2 += area.sub_area2.sensorData[i];
sum3 += area.sub_area3.sensorData[i];
sum4 += area.sub_area4.sensorData[i];
}
#else
for (FORALL(sub,area->sub_area), ++i) {
i = 0;
for (FORALL(data,sub->sensorData), ++i)
sum[i] += *data;
}
#endif
#if 0
area.sub_area1.average = sum1 / SIZE;
area.sub_area2.average = sum2 / SIZE;
area.sub_area3.average = sum3 / SIZE;
area.sub_area4.average = sum4 / SIZE;
#else
i = 0;
for (FORALL(sub,area->sub_area), ++i)
sub->average = sum[i] / SIZE;
#endif
#if 0
area.average = (area.sub_area1.average +
area.sub_area2.average +
area.sub_area3.average +
area.sub_area4.average) / 4;
#else
area->average = 0;
for (FORALL(sub,area->sub_area))
area->average += sub->average;
area->average /= NAREA;
#endif
}
#if 0
area_t
sensor_data_start(area_t area1)
{
double x = 75;
for (int i = 0; i < SIZE; i++) {
area1.sub_area1.sensorData[i] = x;
area1.sub_area2.sensorData[i] = x;
area1.sub_area3.sensorData[i] = x;
area1.sub_area4.sensorData[i] = x;
}
return area1;
}
#else
void
sensor_data_start(area_t *area)
{
double x = 75;
for (FORALL(sub,area->sub_area)) {
for (FORALL(data,sub->sensorData))
*data = x;
}
}
#endif
#if 0
area_t
compare_trash_to_empty(area_t area1, area_t area2, area_t area3, area_t area4, int *area_number_p)
{
area_t local_area = { };
int i,
highBlock = 0;
area_t block[5] = { local_area, area1, area2, area3, area4 };
for (i = 1; i <= 4; i++) {
if (block[i].average >= MARGIN) {
if (block[i].average > block[highBlock].average) {
highBlock = i;
}
}
}
*area_number_p = highBlock;
return block[highBlock];
}
#else
area_t *
compare_trash_to_empty(const area_t *blocks, area_t *all_areas)
{
area_t local_area = { };
int i, highBlock = 0;
#if 0
area_t block[5] = { local_area, area1, area2, area3, area4 };
#else
const area_t *block;
#endif
for (i = 1; i < NAREA; ++i) {
block = &blocks[i];
if (block->average >= MARGIN) {
if (block->average > blocks[highBlock].average)
highBlock = i;
}
}
all_areas[highBlock] = blocks[highBlock];
return &all_areas[highBlock];
}
#endif
#if 0
area_t
empty_trash(area_t chosen_area, int *co2_counter_p, int *time_counter_p)
{
int co2_counter = 0;
int time_counter = 0;
if (chosen_area.sub_area1.average > MARGIN2) {
co2_counter += chosen_area.sub_area1.co2_cost;
time_counter += chosen_area.sub_area1.time;
chosen_area.sub_area1.average = 0;
for (int i = 0; i < SIZE; i++) {
chosen_area.sub_area1.sensorData[i] = 0;
printf("ET %lf\t", chosen_area.sub_area1.sensorData[i]);
}
printf("\n");
}
if (chosen_area.sub_area2.average > MARGIN2) {
co2_counter += chosen_area.sub_area2.co2_cost;
time_counter += chosen_area.sub_area2.time;
chosen_area.sub_area2.average = 0;
for (int i = 0; i < SIZE; i++) {
chosen_area.sub_area2.sensorData[i] = 0;
}
}
if (chosen_area.sub_area3.average > MARGIN2) {
co2_counter += chosen_area.sub_area3.co2_cost;
time_counter += chosen_area.sub_area3.time;
chosen_area.sub_area3.average = 0;
for (int i = 0; i < SIZE; i++) {
chosen_area.sub_area3.sensorData[i] = 0;
}
}
if (chosen_area.sub_area4.average > MARGIN2) {
co2_counter += chosen_area.sub_area4.co2_cost;
time_counter += chosen_area.sub_area4.time;
chosen_area.sub_area4.average = 0;
for (int i = 0; i < SIZE; i++) {
chosen_area.sub_area4.sensorData[i] = 0;
}
}
*co2_counter_p = co2_counter;
*time_counter_p = time_counter;
return chosen_area;
}
#else
void
empty_trash(area_t *chosen_area, int *co2_counter_p, int *time_counter_p)
{
int co2_counter = 0;
int time_counter = 0;
for (FORALL(sub,chosen_area->sub_area)) {
if (sub->average > MARGIN2) {
co2_counter += sub->co2_cost;
time_counter += sub->time;
for (FORALL(data,sub->sensorData))
*data = 0;
}
}
*co2_counter_p = co2_counter;
*time_counter_p = time_counter;
}
#endif
int
main(void)
{
int co2_counter, time_counter;
int day_counter = 0;
int *co2_counter_p = &co2_counter;
int *time_counter_p = &time_counter;
int area_number;
srand(time(NULL));
#if 0
subarea_t subarea1_1 = { 50, 50, 0, {} };
subarea_t subarea1_2 = { 50, 50, 0, {} };
subarea_t subarea1_3 = { 50, 50, 0, {} };
subarea_t subarea1_4 = { 50, 50, 0, {} };
area_t area1 = { subarea1_1, subarea1_2, subarea1_3, subarea1_4, 0 };
subarea_t subarea2_1 = { 50, 50, 0, {} };
subarea_t subarea2_2 = { 50, 50, 0, {} };
subarea_t subarea2_3 = { 50, 50, 0, {} };
subarea_t subarea2_4 = { 50, 50, 0, {} };
area_t area2 = { subarea2_1, subarea2_2, subarea2_3, subarea2_4, 0 };
subarea_t subarea3_1 = { 50, 50, 0, {} };
subarea_t subarea3_2 = { 50, 50, 0, {} };
subarea_t subarea3_3 = { 50, 50, 0, {} };
subarea_t subarea3_4 = { 50, 50, 0, {} };
area_t area3 = { subarea3_1, subarea3_2, subarea3_3, subarea3_4, 0 };
subarea_t subarea4_1 = { 50, 50, 0, {} };
subarea_t subarea4_2 = { 50, 50, 0, {} };
subarea_t subarea4_3 = { 50, 50, 0, {} };
subarea_t subarea4_4 = { 50, 50, 0, {} };
area_t area4 = { subarea4_1, subarea4_2, subarea4_3, subarea4_4, 0 };
#else
area_t areamain[NAREA];
for (FORALL(area,areamain)) {
for (FORALL(sub,area->sub_area)) {
sub->co2_cost = 50;
sub->time = 50;
sub->average = 50;
for (FORALL(data,sub->sensorData))
*data = 0.0;
}
}
#endif
#if 0
area_t useless_area = { };
area_t all_areas[5] = { useless_area, area1, area2, area3, area4 };
#else
area_t *all_areas = areamain;
#endif
area_t local_area = { };
#if 0
area1 = sensor_data_start(area1);
area2 = sensor_data_start(area2);
area3 = sensor_data_start(area3);
area4 = sensor_data_start(area4);
#else
for (FORALL(area,areamain))
sensor_data_start(area);
#endif
int running = 1;
while (running) {
simulated_days(&areamain[0], 7, 10);
simulated_days(&areamain[1], 4, 7);
simulated_days(&areamain[2], 9, 12);
simulated_days(&areamain[3], 6, 9);
#if 0
for (int i = 0; i < SIZE; i++) {
printf("%lf | %lf | %lf | %lf |\n",
area1.sub_area1.sensorData[i],
area2.sub_area1.sensorData[i],
area3.sub_area1.sensorData[i],
area4.sub_area1.sensorData[i]);
}
#else
for (int i = 0; i < SIZE; i++) {
for (FORALL(area,areamain))
printf("%lf |",area->sub_area[i]);
printf("\n");
}
#endif
day_counter++;
printf("Day %d\n", day_counter);
#if 0
area1 = average_trash(area1);
area2 = average_trash(area2);
area3 = average_trash(area3);
area4 = average_trash(area4);
#else
for (FORALL(area,areamain))
average_trash(area);
#endif
printf("hihi\n");
#if 0
all_areas[area_number] =
empty_trash(compare_trash_to_empty(area1, area2, area3, area4,
&area_number), co2_counter_p, time_counter_p);
#else
area_t *area_out = compare_trash_to_empty(areamain,all_areas);
empty_trash(area_out, co2_counter_p, time_counter_p);
#endif
printf("titi\n");
#if 0
for (int i = 0; i < SIZE; i++) {
printf("Local area %lf\t", local_area.sub_area1.sensorData[i]);
}
printf("\n");
#else
do {
subarea_t *sub = area_out->sub_area;
printf("Local area ");
for (FORALL(data,sub->sensorData))
printf("%f\t", *data);
printf("\n");
} while (0);
#endif
if (day_counter == 2) {
running = 0;
}
}
}
I am currently trying to figure out how structs work in C.
I assume that this code is setting the values x and y for the respective position1, position2 to the assigned ones.
However, I keep getting the following error message:
error: expected '=', ',', ';', 'asm' or '__attribute__; before '.' token
Here is the code:
struct position {
int x;
int y;
} position1, position2;
position1.x = 60;
position1.y = 0;
position2.x = 60;
position2.y = 120;
Why is it throwing me that error?
You can initialize your global structs like this:
struct position {
int x;
int y;
} position1 = {60, 0}, position2 = {60, 120};
Or, with a little bit more clarity and designated initializers:
...
} position1 = {.x = 60, .y = 0},
position2 = {.x = 60, .y = 120};
Try:
#include <stdlib.h>
struct position_t {
int x;
int y;
};
int main()
{
struct position_t position1, position2;
position1.x = 60;
position1.y = 0;
position2.x = 60;
position2.y = 120;
return 0;
}
Another way is to use typedef to give the struct an alias:
#include <stdlib.h>
typedef struct position_t {
int x;
int y;
} position;
int main()
{
position position1, position2;
position1.x = 60;
position1.y = 0;
position2.x = 60;
position2.y = 120;
return 0;
}
It seems the problem is that you are trying to place these assignment statements outside a function. You may not do this. You may place only declarations outside a function.
So write the following way
struct position {
int x;
int y;
} position1 = { 60, 6 }, position2 = { .x = 60, .y = 120 };
Also inside a function you may use a compound literal to assign a value to an object of the structure.
Here is a demonstrative program
#include <stdio.h>
struct position {
int x;
int y;
} position1 = { 60, 6 }, position2 = { .x = 60, .y = 120 };
int main( void )
{
printf( "position1: { %d, %d }\n", position1.x, position1.y );
printf( "position2: { %d, %d }\n", position2.x, position2.y );
position1 = ( struct position ) { 10, 20 };
position2 = ( struct position ) { .x = 30, .y = 40 };
printf( "position1: { %d, %d }\n", position1.x, position1.y );
printf( "position2: { %d, %d }\n", position2.x, position2.y );
position1.x = 50;
position1.y = 60;
position2.x = 70;
position2.y = 80;
printf( "position1: { %d, %d }\n", position1.x, position1.y );
printf( "position2: { %d, %d }\n", position2.x, position2.y );
return 0;
}
Its output is
position1: { 60, 6 }
position2: { 60, 120 }
position1: { 10, 20 }
position2: { 30, 40 }
position1: { 50, 60 }
position2: { 70, 80 }
You just have to put all the code after the struct declaration inside the main() function and it does not throw any error. Like that:
#include <stdio.h>
struct position {
int x;
int y;
} position1, position2;
int main(void) {
position1.x = 60;
position1.y = 0;
position2.x = 60;
position2.y = 120;
printf("%d\n", position2.y); // this line is just for testing
}