I've got a piece of code, it's purpose is to draw a background image on one of the game levels. For this purpose I create this structure.
typedef struct crate_t {
int x = 0;
int y = 0;
int h = 0;
int w = 0;
int type = BACKGROUND;
}crate;
Then in the main function I create a 2D array
crate **Crates = (crate**)malloc(sizeof(crate)*(SCREEN_WIDTH / GrassBlock->w));
for (int i = 0; i <= SCREEN_HEIGHT/GrassBlock->h; i++) {
Crates[i] = (crate*)malloc(sizeof(crate)*(SCREEN_HEIGHT / GrassBlock->h));
}
and I pass it to the function counter = DrawLevelBG(screen, GrassBlock, Border, Crates);. The problem is that the function causes error. "Access violation writing location." at Obstacles[i][j].x = x;
int DrawLevelBG(SDL_Surface *screen, SDL_Surface *sprite, SDL_Surface *border, crate **Obstacles) {
int x = 0;
int y = 0;
int i = 0;
int j = 0;
bool condition = 0;
while (y < SCREEN_HEIGHT + sprite->h) {
DrawSurface(screen, sprite, x + (sprite->w / 2), y + (sprite->h / 2));
if (x >= SCREEN_WIDTH - sprite->w || x == 0 || y == 0 || y >= SCREEN_HEIGHT - sprite->h) {
DrawSurface(screen, border, x + (sprite->w / 2), y + (sprite->h / 2));
Obstacles[i][j].x = x;
Obstacles[i][j].y = y;
Obstacles[i][j].h = border->h;
Obstacles[i][j].w = border->w;
Obstacles[i][j].type = WALL;
i++;
if (x >= SCREEN_WIDTH - sprite->w) {
y += sprite->h;
x = 0;
j++;
condition = 1;
}
}
if (!condition) {
x += sprite->w;
}
condition = 0;
}
return i;
}
I know that these ones are caused by pointers not pointing actually to anything but I can't understand what's wrong here. Any help would be greatly appreciated. Thanks.
EDIT
I've changed my memory allocation piece of code so it looks like that now:
crate **Crates = (crate**)malloc(sizeof(crate*)*(SCREEN_WIDTH / GrassBlock->w)*(SCREEN_HEIGHT / GrassBlock->h));
for (int i = 0; i <= SCREEN_WIDTH/GrassBlock->w; i++) {
Crates[i] = (crate*)malloc(sizeof(crate)*(SCREEN_HEIGHT / GrassBlock->h));
}
According to all your replies guys. Unfortunately this doesnt solve the problem. +Important info, the function DrawLevelBG causes ERROR on the first iteration of loop.
In the first allocation you create an array from pointers. So you need to allocate memory for pointers:
crate **Crates = (crate**)malloc(sizeof(crate*)*(SCREEN_WIDTH / GrassBlock->w));
Thanks for all the help guys. The problem was iterators, not only did I make my 2D array SCREEN_HEIGHT wide and SCREEN_WIDTH high which was the opposite of what I wanted but aswell the iteration in DrawLevelBG was wrong as pointed out. I had to swap my "i" and "j" and make some corrections, so thanks alot Some programmer dude for pointing that out. Thanks alot.
Related
I have this C code of an alogrithm checking whether a given point is inside a polygon. It is supposed to be correct, I also keep seeing this code in various places. However when I use it doesn't work perfectly - about 20% of the answers are wrong.
int pnpoly(int nvert, double *vertx, double *verty, double testx, double testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
Maybe there is something wrong with my main function. Could somone give me a main function to check this algorthm?
This is my main function
int main(){
double vertx[4] = {10, 10, 0, 0};
double verty[4] = {10, 0, 10, 0};
// for those two it returns "Inside"
double testx = 6;
double testy = 4;
/* for those two it returns "Outside"
double testx = 5;
double testy = 4;
*/
int result = pnpoly(4, vertx, verty, testx, testy);
if (result) {
printf("\nInside\n");
}
else {
printf("\nOutside\n");
}
return 0;
}
Your polygon is self intersecting. It's normal that (5,4) is "Outside"
I think you thought that your polygon was a square, the algo works perfectly even with self intersecting polygons.
I'm trying to make this function create X number of variables using an array. I know that this is technically wrong because I need a constant as my array's value (currently 'x'), but excluding that, what am I missing? Looked at so many code samples and can't figure it out, but I know it's got to be simple...
void variables()
{
int i;
int bars = 10;
int x = 1;
for (i = 1; i <= bars+1; i++)
{
int variables[bars] = { x };
x++;
if (i >= bars+1)
{
break;
}
}
void variables()
{
int bars = 10;
if(bars >= Bars) bars = Bars - 1;
// to be able to set array size based on variable,
// make a dynamically sized array
double highvalues[];
ArrayResize(highvalues, bars);
for (int i = 0 /*Note: Array index is zero-based, 0 is first*/; i <= bars; i++)
{
highvalues[i] = iHigh(NULL, 0, i);
// or
highvalues[i] = High[i];
}
}
It is hard to tell what do you want to achieve.
If you want to fill an array with a value ArrayFill() fill help you.
I have two structs: ARRAY2D (multidimensional) and ARRAY (one-dimensional). I would like to get a column from type ARRAY2D and copy it into type ARRAY.
Although my code works below, and I recognize this is probably a poor way of getting a column from an array, I'm curious what optimizations there might be to avoid an O(n2) algorithm. What is an efficient way to get a column from an array in C?
BOOL arr2_getColumn(ARRAY2D *arr, const int column_index, ARRAY *returnedArray)
{
int x, y;
int i = 0;
/* Check for valid array. */
if (arr->blnIsInit != TRUE)
return FALSE;
/* Initialize array with the column's height. */
if (!arr_init(returnedArray, arr->height))
return FALSE;
/* Copy over column. */
for (y = 0; y < arr->height; y++)
{
for (x = 0; x <= column_index; x++)
{
if (x == column_index)
{
returnedArray->array[i] = arr->array[y * arr->width + x];
i++;
}
}
}
/* Set the new size. */
returnedArray->size = arr->height;
return TRUE;
}
Get rid of i and x.
for (y = 0; y < arr->height; y++)
{
returnedArray->array[y] = arr->array[y * arr->width + column_index];
}
/* Copy over column. */
for (y = 0; y < arr->height; y++)
{
x = column_index;
returnedArray->array[i] = arr->array[y * arr->width + x];
i++;
}
I have a 2D pointer setup representing a grid, the grid consists of columns containing 1/0 or null columns (i.e. don't contain 1 in any cell). This function spins the grid by 90deg clockwise, and works except...
I think my malloc could be wrong as it works but I get many over picket-fence errors in dmalloc.
Am I allocating incorrect amounts of memory?
Also I wanted to swap the values of *width and *height to represent the new width and height of the grid but when I try this the program just segfaults on the second spin.
So *width is the dimension of orig's first dimension, so it should be the size of newg's second dimension.
Similarly *height should be the size of newg's first, and hence the two sets of malloc sizes have been flipped the wrong way around.
I think it would be clearer to name the values orig_max_x and orig_max_y, then it should be clear if the function uses the values the wrong way around.
newg = malloc (*height * sizeof(char *));
// Initialise each column
for (x = 0; x < *height; x++) {
newg[x] = malloc (*width);
for (y = 0; y < *width; y++)
newg[x][y] = 0;
}
Further, it should not free any of newg's storage if you want to return values from spin()
Edit: I still had some of those pesky *width and *height mixed. Sorry.
I strongly suggest the names should relate to the thing they talk about, orig_width,
orig_height would be have helped me read the code.
This is probably how I'd do it:
#include <stdio.h>
#include <stdlib.h>
char** alloc_rectangle(int *width, int *height);
void free_rectangle(char **orig, int *width);
char** spin (char **orig, int *width, int *height);
int main (int argc, const char * argv[]) {
int width = 20;
int height = 30;
char** orig = alloc_rectangle(&width, &height);
char** newg = spin(orig, &width, &height);
return 0;
}
char** alloc_rectangle(int *width, int *height)
{
char **newg = calloc (*width, sizeof(char *));
// Initialise each column
for (int x = 0; x < *width; x++) {
newg[x] = calloc (*height, sizeof(char));
}
return newg;
}
void free_rectangle(char **orig, int *width)
{
// free memory for old grid
for (int x = 0; x < *width; x++) {
if (orig[x] != NULL) {
free (orig[x]);
}
}
free (orig);
}
char** spin (char **orig, int *width, int *height)
{
int x;
int y;
char **newg = alloc_rectangle(height, width);
// Rotate
for (x = 0; x < *width; x++) {
for (y = 0; y < *height; y++)
if (orig[x] != NULL)
newg[*height - 1 - y][x] = orig[x][y];
}
return newg;
}
WARNING Untested code - some fun for all :-)
I don't think it is spin's job to free orig. I'd prefer it to just make space to hold the result of spinning. So to make things tidier, I pulled freeing a rectangle into its own function. Similarly, I'd always want the rectangles to be allocated consistently, so that would be its own function.
Take another look at the code that rotates the grid. I don't think you ever want to mix x and y coordinates, so an index like *width - 1 - y looks suspicious. For example, suppose *width = 3 and *height = 5. Then y ranges from 0 to 4, and you can end up with newg[3 - 1 - 4] = newg[-2].
Also, if you've allocated orig the same way you allocated newg you'll need to free it like this:
for (x=0; x < *width; x++) {
free (orig[x]); // Free the individual columns
}
free (orig); // Free the array of pointers.
I just wrote this up quickly and it seemed to work fine with the few tests I ran on it.
char **rotate(char **original, int *width, int *height)
{
int t_width = *height;
int t_height = *width;
char **newgrid = (char**)calloc(t_height, sizeof(char*));
for(int y = 0; y < t_height; y++)
{
newgrid[y] = (char*)calloc(t_width, sizeof(char));
for(int x = 0; x < t_width; x++)
newgrid[y][x] = original[x][y];
}
for(int y = 0; y < *height; y++)
free(original[y]);
free(original);
*width = t_width;
*height = t_height;
return newgrid;
}
Let me know if there are any problems.
I'm hacking away at a simple game to teach myself C and I've come up against an infuriatingly simple problem that I haven't been able to Google an answer to.
Code follows, apologies for its noobie terribleness (criticisms appreciated!):
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
#define AMOUNT_OF_ENEMIES 10
#define AMOUNT_OF_PIXELS_TO_MOVE 50.0
struct enemy
{
int alive;
SDL_Rect rect;
};
void create_enemy(struct enemy *position)
{
// Take a pointer to an array. Iterate through array looking for any 'dead' instances.
// (Re)initialise when found, ignore entirely if array is full of alive instances.
int j = 0;
while(position[j].alive == 1 && j < AMOUNT_OF_ENEMIES)
{
++j;
}
if(position[j].alive == 0)
{
position[j].alive = 1;
position[j].rect.y = 0;
}
}
void update_enemies(struct enemy *position)
{
// Iterate through a passed array looking for alive instances. If found increment vertical position,
// unless instance is at bottom of screen in which case it's marked as dead.
int j = 0;
while(j < AMOUNT_OF_ENEMIES)
{
if(position[j].alive == 1)
{
position[j].rect.y += 1;
if(position[j].rect.y > 570)
{
position[j].alive = 0;
}
}
++j;
}
}
int main(void)
{
// INITS *********************************************************************
int k;
int current_time = 0;
int previous_time = 0;
float difference_in_time = 0.0;
// Load SDL library
if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
{
printf("Problem, yo\n");
return 1;
}
// Setup event queue
SDL_Event event;
// Create array to store enemys, initialise it
struct enemy *enemy_array = malloc(sizeof(struct enemy) * AMOUNT_OF_ENEMIES);
int j;
for(j = 0; j < AMOUNT_OF_ENEMIES; ++j)
{
enemy_array[j].alive = 0;
enemy_array[j].rect.x = 150;
enemy_array[j].rect.y = 0;
}
// Create an array to flag keypresses, initialise it
int pressed_keys[323];
int l;
for(l = 0; l < 323; ++l)
{
pressed_keys[l] = 0;
}
// Create surfaces
SDL_Surface *screen = SDL_SetVideoMode(300, 600, 0, SDL_HWSURFACE);
int black = SDL_MapRGB(screen->format, 0, 0, 0);
SDL_Surface *tower = SDL_LoadBMP("tower.bmp");
SDL_Rect tower_rect;
tower_rect.x = 50;
tower_rect.y = 0;
tower_rect.w = 200;
tower_rect.h = 600;
SDL_Surface *dude = SDL_LoadBMP("dude.bmp");
float dude_x = 0.0;
SDL_Rect dude_rect;
dude_rect.x = 120;
dude_rect.y = 500;
dude_rect.w = 60;
dude_rect.h = 100;
SDL_Surface *enemy = SDL_LoadBMP("enemy.bmp");
// GAME LOOP *****************************************************************
while(1)
{
current_time = SDL_GetTicks();
difference_in_time = (float)(current_time - previous_time) / 1000;
previous_time = current_time;
if(SDL_PollEvent(&event))
{
if(event.key.keysym.sym == SDLK_DOWN)
{
create_enemy(enemy_array);
}
else
{
switch(event.type)
{
case SDL_QUIT:
printf("NOOOOOO\n");
SDL_FreeSurface(screen);
SDL_FreeSurface(tower);
SDL_FreeSurface(enemy);
free(enemy_array);
SDL_Quit();
return 0;
case SDL_KEYDOWN:
pressed_keys[event.key.keysym.sym] = 1;
break;
case SDL_KEYUP:
pressed_keys[event.key.keysym.sym] = 0;
break;
}
}
}
if(pressed_keys[SDLK_LEFT] && dude_rect.x > 50)
{
dude_rect.x -= (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
if(pressed_keys[SDLK_RIGHT] && dude_rect.x < 190)
{
dude_rect.x += (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
update_enemies(enemy_array);
SDL_FillRect(screen, NULL, black);
SDL_BlitSurface(tower, NULL, screen, &tower_rect);
for(k = 0; k < AMOUNT_OF_ENEMIES; ++k)
{
if(enemy_array[k].alive == 1)
{
SDL_BlitSurface(enemy, NULL, screen, &enemy_array[k].rect);
}
}
SDL_BlitSurface(dude, NULL, screen, &dude_rect);
SDL_Flip(screen);
}
return 0;
}
The issue arises at this part:
if(pressed_keys[SDLK_LEFT] && dude_rect.x > 50)
{
dude_rect.x -= (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
if(pressed_keys[SDLK_RIGHT] && dude_rect.x < 190)
{
dude_rect.x += (AMOUNT_OF_PIXELS_TO_MOVE * difference_in_time);
}
The 'dude' object moves to the left correctly, but nothing happens when the right arrow key is pressed.
Adding a printf tells me the if statement is being executed correctly. Removing difference_in_time makes it work, so it's either something to do with that variable or the operation of it and AMOUNT_OF_PIXELS_TO_MOVE.
I just can't for the life of me figure out why the former block executes correctly and the latter (which is essentially the same thing) doesn't. I'm sure it's something simple I've overlooked but I'm going insane trying to find it.
Your problem is due to rounding.
For your "dude" you are using a SDL_Rect, that uses integer coordinates (short int if I remember correct).
You configured your dude speed to 50 and if your game is running at 60fps (probably due to its simplicity and it may be much more if vsync is off) you will get each frame a movement value of 0.83333.
This value will be truncated to a int and the result will be zero, for example, if dude.x is 10 and you press right, the calculated value will be 10.83 and when truncated this will result in 10.
For left, it works because the value is rounded down, assuming again dude.x is 10, when left is pressed, on the first iteration the calculated value would be 9.17, truncating this will give you 9.
Simple, bad and Hack Solution
Increase AMOUNT_OF_PIXELS_TO_MOVE to a higher value that forces the int to increase, this will fix the problem.
Good Solution
Does not use SDL_Rect for storing your characters position, create a "MyRect" and use float values in it and only does rounding when drawing the character. Actually you only need to store the character position, so I would create a Point2D struct with only x and y and use this to keep track of characters position.