How do I fix warped walls in my raycaster? - c
I am writing a raycaster using the SDL library with C. I have been dealing with the fisheye effect for many weeks now. For a field of view like 60 degrees, I multiply the distance to the wall by the cosine of the relative angle (ranging from -30 to 30), but still, I get the same fisheye. Here's what that looks like:
I don't know what to do at this point, given that so many sources have recommended cosine correction and it just does not fix the distortion in my case.
I am compiling like this:
clang `pkg-config --cflags --libs sdl2` raycaster.c
To go forward and back, press the up and down keys. Press left and right to strafe. You can use the a and s keys to turn left and right respectively.
My code is below if you want to take a look. If you manage to figure out why I am getting a warped perspective in my engine, please let me know.
#include <SDL2/SDL.h>
#include <math.h>
#define SET_COLOR(r, g, b) SDL_SetRenderDrawColor(renderer, r, g, b, SDL_ALPHA_OPAQUE)
typedef struct {
float x, y, prev_x, prev_y, angle, fov;
} Player;
enum {
map_width = 12, map_height = 15,
screen_width = 800, screen_height = 500
};
const float
move_speed_decr = 0.08,
angle_turn = 2.0,
theta_step = 0.05,
dist_step = 0.8,
width_ratio = (float) screen_width / map_width,
height_ratio = (float) screen_height / map_height;
const unsigned char map[map_height][map_width] = {
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1},
{1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1},
{1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
SDL_Window* window;
SDL_Renderer* renderer;
float to_radians(float degrees) {
return degrees * (M_PI / 180.0f);
}
void draw_rectangle(SDL_Rect rectangle, int r, int g, int b) {
SET_COLOR(r, g, b);
SDL_RenderFillRect(renderer, &rectangle);
SDL_RenderDrawRect(renderer, &rectangle);
}
void raycast(Player player) {
SET_COLOR(210, 180, 140);
float
half_fov = player.fov / 2,
rel_x = player.x * width_ratio, rel_y = player.y * height_ratio;
float screen_x = 0, step_x = (screen_width / player.fov) * theta_step;
for (float theta = player.angle - half_fov; theta < player.angle + half_fov; theta += theta_step) {
float rad_theta = to_radians(theta);
float cos_theta = cos(rad_theta), sin_theta = sin(rad_theta);
float dist = 0;
while (dist += dist_step) {
float
new_x = cos_theta * dist + rel_x,
new_y = sin_theta * dist + rel_y;
if (map[(int) (new_y / height_ratio)][(int) (new_x / width_ratio)]) {
dist *= cos(to_radians(theta - player.angle));
float double_dist = 2 * dist;
if (double_dist >= screen_height) break;
SDL_Rect column = {screen_x, dist, step_x + 1, screen_height - double_dist};
SDL_RenderFillRect(renderer, &column);
SDL_RenderDrawRect(renderer, &column);
break;
}
}
screen_x += step_x;
}
}
void handle_input(const Uint8* keys, Player* player) {
SDL_Event event;
while (SDL_PollEvent(&event)) {
if (event.type == SDL_QUIT) {
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
exit(0);
}
else if (event.type == SDL_KEYDOWN) {
float radian_theta = to_radians(player -> angle);
float move_x = cos(radian_theta) * move_speed_decr,
move_y = sin(radian_theta) * move_speed_decr;
// handle arrow keys
if (keys[SDL_SCANCODE_UP]) player -> x += move_x, player -> y += move_y;
if (keys[SDL_SCANCODE_DOWN]) player -> x -= move_x, player -> y -= move_y;
if (keys[SDL_SCANCODE_LEFT]) player -> x += move_y, player -> y -= move_x;
if (keys[SDL_SCANCODE_RIGHT]) player -> x -= move_y, player -> y += move_x;
// handle 'a' and 's' for angle changes
if (keys[SDL_SCANCODE_A]) player -> angle -= angle_turn;
if (keys[SDL_SCANCODE_S]) player -> angle += angle_turn;
// safeguards for invalid positions and angles
if (player -> x < 0) player -> x = 0;
else if (player -> x > screen_width) player -> x = screen_width;
if (player -> y < 0) player -> y = 0;
else if (player -> y > screen_height) player -> y = screen_height;
// move the player to their previous coordinate if they're in a wall
if (map[(int) player -> y][(int) player -> x])
player -> y = player -> prev_y, player -> x = player -> prev_x;
if (player -> angle > 360) player -> angle = 0;
else if (player -> angle < 0) player -> angle = 360;
player -> prev_y = player -> y, player -> prev_x = player -> x;
}
}
}
int main() {
SDL_CreateWindowAndRenderer(screen_width, screen_height, 0, &window, &renderer);
SDL_SetWindowTitle(window, "Raycaster");
Player player = {5, 5, 0, 0, 0, 60};
SDL_Rect the_ceiling = {0, 0, screen_width, screen_height / 2};
SDL_Rect the_floor = {0, screen_height / 2, screen_width, screen_height};
const Uint8* keys = SDL_GetKeyboardState(NULL);
while (1) {
handle_input(keys, &player);
draw_rectangle(the_ceiling, 96, 96, 96);
draw_rectangle(the_floor, 255,69,0);
raycast(player);
SDL_RenderPresent(renderer);
SDL_UpdateWindowSurface(window);
}
}
You need to apply following diff:
diff --git a/so33.c b/so33.c
index e65cff8..b0f6d8a 100644
--- a/so33.c
+++ b/so33.c
## -56,7 +56,7 ## void raycast(Player player) {
float
half_fov = player.fov / 2,
- rel_x = player.x * width_ratio, rel_y = player.y * height_ratio;
+ rel_x = player.x, rel_y = player.y;
float screen_x = 0, step_x = (screen_width / player.fov) * theta_step;
## -70,12 +70,12 ## void raycast(Player player) {
new_x = cos_theta * dist + rel_x,
new_y = sin_theta * dist + rel_y;
- if (map[(int) (new_y / height_ratio)][(int) (new_x / width_ratio)]) {
+ if (map[(int) (new_y)][(int) (new_x)]) {
dist *= cos(to_radians(theta - player.angle));
- float double_dist = 2 * dist;
-
- if (double_dist >= screen_height) break;
- SDL_Rect column = {screen_x, dist, step_x + 1, screen_height - double_dist};
+ float wall_height = screen_height / dist;
+ if (wall_height > screen_height)
+ wall_height = screen_height;
+ SDL_Rect column = {screen_x, screen_height/2 - wall_height/2, step_x + 1, wall_height};
SDL_RenderFillRect(renderer, &column);
SDL_RenderDrawRect(renderer, &column);
A few issues were identified.
Coefficients width_ratio and height_ratio seems to mix coordinates in the map space with coordinates in the screen space. It is pointless. Moreover, it breaks navigation by moving faster along specific axis.
After projecting dist to the ray cast through the center of the screen (dist *= cos(...) you have to apply simple perspective to compute height of the wall (variable wall_height)
Finally, draw a rectangle of height wall_height around the middle horizontal line.
Edit. Set
dist_step = 0.01
There are two major problem in this code. The distance to the wall must be calculated for the intersection point of your ray to the wall instead of just relying that your endpoint lies inside the wall square.
Having a camera at C, the distortion is solved by casting rays from C through a sufficient number of points between A and B, just dividing this plane (your screen) to equally wide columns (pixels).
I'm fairly pessimistic about the cosine correction, since what I can tell, one should more likely adjust the drawn column width or position with it, than the column height.
Related
How do I fix the warped perspective in my raycaster?
I am writing a raycaster using SDL's C API. I have spent weeks trying to fix the notorious fisheye effect to no avail. According to this source, I can multiply my calculated distance by the cosine of half of the FOV to fix it. That has not worked for me. I still have the cosine correction in my code nonetheless. Here are two images demonstrating the distortion: I think a core problem of my code may be that my angle increment is constant, while the increment should be smaller as I'm closer to the screen borders. Unfortunately, I don't know how to start implementing this. If possible, could anyone please take a look at my code and give me a tip on how to remove the fisheye? To move in any direction, use the arrow keys. Use the 'a' and 's' keys to turn left and right respectively. This is how I'm compiling: clang `pkg-config --cflags --libs sdl2` raycaster.c #include <SDL2/SDL.h> #include <math.h> typedef struct { float x, y, prev_x, prev_y, angle, fov; } Player; enum { map_width = 12, map_height = 15, screen_width = 800, screen_height = 500 }; const float move_speed_decr = 0.08, angle_turn = 2.0, ray_theta_step = 0.4, ray_dist_step = 0.8, darkening = 1.8, width_ratio = (float) screen_width / map_width, height_ratio = (float) screen_height / map_height; const unsigned char map[map_height][map_width] = { {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, {1, 0, 4, 3, 2, 0, 0, 0, 2, 0, 0, 1}, {1, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 1}, {1, 0, 0, 0, 4, 3, 2, 1, 4, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} }; SDL_Window* window; SDL_Renderer* renderer; float to_radians(float degrees) { return degrees * M_PI / 180; } float distance(float x0, float y0, float x1, float y1) { return sqrt(((x1 - x0) * (x1 - x0)) + ((y1 - y0) * (y1 - y0))); } void shade(int* color, int darkener) { int darkened = *color - darkener; *color = darkened < 0 ? 0 : darkened; } void draw_rectangle(SDL_Rect rectangle, int r, int g, int b) { SDL_SetRenderDrawColor(renderer, r, g, b, SDL_ALPHA_OPAQUE); SDL_RenderFillRect(renderer, &rectangle); SDL_RenderDrawRect(renderer, &rectangle); } void raycast(Player player) { float relative_x = player.x * width_ratio; float relative_y = player.y * height_ratio; float half_fov = player.fov / 2; float width_fov_ratio = (screen_width / player.fov) / 2; float distort_adjust = cos(to_radians(half_fov)); // the core of my problem may be in the constant increment of my angle for (float theta = player.angle - half_fov, screen_x = 0; theta < player.angle + half_fov; theta += ray_theta_step, screen_x += width_fov_ratio) { float radian_theta = to_radians(theta); float cos_theta = cos(radian_theta), sin_theta = sin(radian_theta); float d = 0, new_x, new_y; while (d += ray_dist_step) { new_x = cos_theta * d + relative_x; new_y = sin_theta * d + relative_y; int map_x = new_x / width_ratio, map_y = new_y / height_ratio; int map_point = map[map_y][map_x]; if (map_point) { int dist_wall = distance(relative_x, relative_y, new_x, new_y) * distort_adjust; int twice_dist_wall = 2 * dist_wall; if (twice_dist_wall >= screen_height) break; else if (map_point) { // succeeds when a wall is present int r, g, b; switch (map_point) { case 1: r = 255, g = 255, b = 0; break; case 2: r = 0, g = 128, b = 128; break; case 3: r = 255, g = 165, b = 0; break; case 4: r = 255, g = 0, b = 0; break; } int color_decr = dist_wall / darkening; shade(&r, color_decr); shade(&g, color_decr); shade(&b, color_decr); SDL_Rect vertical_line = { screen_x, dist_wall, width_fov_ratio + 1, screen_height - twice_dist_wall }; draw_rectangle(vertical_line, r, g, b); break; } } } } } void handle_input(const Uint8* keys, Player* player) { SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { SDL_DestroyWindow(window); SDL_DestroyRenderer(renderer); exit(0); } else if (event.type == SDL_KEYDOWN) { float radian_theta = to_radians(player -> angle); float move_x = cos(radian_theta) * move_speed_decr, move_y = sin(radian_theta) * move_speed_decr; // handle arrow keys if (keys[SDL_SCANCODE_UP]) player -> x += move_x, player -> y += move_y; if (keys[SDL_SCANCODE_DOWN]) player -> x -= move_x, player -> y -= move_y; if (keys[SDL_SCANCODE_LEFT]) player -> x += move_y, player -> y -= move_x; if (keys[SDL_SCANCODE_RIGHT]) player -> x -= move_y, player -> y += move_x; // handle 'a' and 's' for angle changes if (keys[SDL_SCANCODE_A]) player -> angle -= angle_turn; if (keys[SDL_SCANCODE_S]) player -> angle += angle_turn; // safeguards for invalid positions and angles if (player -> x < 0) player -> x = 0; else if (player -> x > screen_width) player -> x = screen_width; if (player -> y < 0) player -> y = 0; else if (player -> y > screen_height) player -> y = screen_height; // move the player to their previous coordinate if they're in a wall if (map[(int) player -> y][(int) player -> x]) player -> y = player -> prev_y, player -> x = player -> prev_x; if (player -> angle > 360) player -> angle = 0; else if (player -> angle < 0) player -> angle = 360; player -> prev_y = player -> y, player -> prev_x = player -> x; } } } int main() { SDL_CreateWindowAndRenderer(screen_width, screen_height, 0, &window, &renderer); SDL_SetWindowTitle(window, "Raycaster"); Player player = {5, 5, 0, 0, 0, 60}; SDL_Rect the_ceiling = {0, 0, screen_width, screen_height / 2}; SDL_Rect the_floor = {0, screen_height / 2, screen_width, screen_height}; const Uint8* keys = SDL_GetKeyboardState(NULL); while (1) { handle_input(keys, &player); draw_rectangle(the_ceiling, 96, 96, 96); draw_rectangle(the_floor, 210, 180, 140); raycast(player); SDL_RenderPresent(renderer); SDL_UpdateWindowSurface(window); } } After help from RandomDavis, the distortion is lessened. Here is the new result. Nonetheless, some warping remains: NOTE: To anyone who is still struggling with this problem, I solved it here: How do I fix warped walls in my raycaster?
Okay I found a guide which talks about this exact issue. Before drawing the wall, there is one problem that must be taken care of. This problem is known as the "fishbowl effect." Fishbowl effect happens because ray-casting implementation mixes polar coordinate and Cartesian coordinate together. Therefore, using the above formula on wall slices that are not directly in front of the viewer will gives a longer distance. This is not what we want because it will cause a viewing distortion such as illustrated below. Thus to remove the viewing distortion, the resulting distance obtained from equations in Figure 17 must be multiplied by cos(BETA); where BETA is the angle of the ray that is being cast relative to the viewing angle. On the figure above, the viewing angle (ALPHA) is 90 degrees because the player is facing straight upward. Because we have 60 degrees field of view, BETA is 30 degrees for the leftmost ray and it is -30 degrees for the rightmost ray.
How to draw circle with sin and cos in C?
I have a problem about make some circle orbit (solar system stimulation) in C. Actually, I did it about a day. but I can't figure it out. First, how to change the planets movement speed? Some friends told me that I can use "If" for speed arrange, but I failed.... Second, Location setting. I draw some circle with ellipse but I don't know how to make orbit. my earth orbit goes wrong... there are some codes that I made. #include <Windows.h> #include <stdio.h> #include <math.h> #define solar_size 30 #define earth_size 16 #define PI 3.141592654 #define MOVE_SPEED 3 #define rad angle*180/PI int angle; double sun_x,sun_y,earth_x,earth_y; double x,y; int dx; int dy; int i; int main(void) { HWND hwnd = GetForegroundWindow(); HDC hdc = GetWindowDC(hwnd); SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 0))); Rectangle(hdc, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)); TextOut(hdc, 250, 450, L"solar system Simulation", 23); while (1) { sun_x = 250; sun_y = 250; earth_x = sun_x + 40; earth_y = sun_y + 40; SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(255, 0, 0))); SelectObject(hdc, CreateSolidBrush(RGB(255, 0, 0))); Ellipse(hdc, sun_x, sun_y, sun_x + solar_size, sun_y + solar_size); for (angle = 0; angle <= 360; angle++) { SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(0, 0, 220))); SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 220))); Ellipse(hdc, earth_x, earth_y, earth_x + earth_size, earth_y + earth_size); Sleep(50); SelectObject(hdc, CreatePen(PS_SOLID, 3, RGB(0, 0, 0))); SelectObject(hdc, CreateSolidBrush(RGB(0, 0, 0))); Ellipse(hdc, earth_x + 30, earth_y + 30, earth_x + earth_size, earth_y + earth_size); earth_x = 40 * cos(rad)+40; earth_y = 40 * sin(rad)+40; } continue; } }
Your code suffers from being unorganized. For example, you mix the variables like earth_size and hard-wired numbers like 16 freely. That's a recipe for disaster. Please try to be more systematic. It's hard not to make an answer a laundry list of errors. The position (px, py) on a circle with centre (cx, cy) and radius r is: px = cx + r * cos(angle) py = cy + r * sin(angle) Therefore, your initialization is wrong: earth_x = sun_x + 40; earth_y = sun_y + 40; // should be just sun_y The way the Ellipse function in GDI works, your drawing command should look like: Ellipse(hdc, earth_x - earth_size / 2, earth_y - earth_size / 2, earth_x + earth_size / 2, earth_y + earth_size / 2); Perhaps it is useful to collect the data of the celestial bodies (position, size, colour) in a struct and write a drawing function for it that just says DrawBody(hdc, earth), so that you don't have to repeat (viz copy and paste) the drawing code. As for your speed: One possible source of error is here: #define rad angle*180/PI That's the wrong way round. Finally, learn how SelectObject works: You should save the return value in a variable and select it back to the DC after you are done. If you don't do that, you will leak GDI objects. You can see how many GDI objects your application uses in the Task Manager. If that number grows constantly, you are leaking objects. Eventually, your application will behave strangely.
stb_truetype.h and SDL2 change font color
I am using stb_truetype.h and SDL2 to render text. Is there an easy way to change the font color? Here is what I have (text is a char*): while (*text) { if (*text >= 32 && *text < 128) { stbtt_aligned_quad q; stbtt_GetBakedQuad(font->cdata, 512, 512, *text - 32, &x, &y, &q, 1); SDL_Rect src_rect = {.x = (int)512 * q.s0 - 1, .y = (int)512 * (q.t0) - 1, .w = (int)512 * (q.s1 - q.s0) + 1, .h = (int)512 * (q.t1 - q.t0) + 1}; SDL_Rect dst_rect = { .x = q.x0, .y = q.y0, .w = q.x1 - q.x0, .h = q.y1 - q.y0}; // Has no effect because I am just grabbing a rect from the font data. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); // Always renders the font white. SDL_RenderCopy(renderer, font->texture, &src_rect, &dst_rect); } ++text; } I would like to be able to render the font in different colors. Right now the font is always white.
Found a way to do this, using SDL_SetTextureColorMod : (https://wiki.libsdl.org/SDL_SetTextureColorMod) SDL_SetTextureColorMod(font->texture, 255, 0, 0); will turn the font red for example. My original code using this: while (*text) { if (*text >= 32 && *text < 128) { stbtt_aligned_quad q; stbtt_GetBakedQuad(font->cdata, 512, 512, *text - 32, &x, &y, &q, 1); SDL_Rect src_rect = {.x = (int)512 * q.s0 - 1, .y = (int)512 * (q.t0) - 1, .w = (int)512 * (q.s1 - q.s0) + 1, .h = (int)512 * (q.t1 - q.t0) + 1}; SDL_Rect dst_rect = { .x = q.x0, .y = q.y0, .w = q.x1 - q.x0, .h = q.y1 - q.y0}; // set the font texture to display red. SDL_SetTextureColorMod(font->texture, 255, 0, 0); SDL_RenderCopy(renderer, font->texture, &src_rect, &dst_rect); } ++text; }
Making projectile shoot using with allegro library in C
I'm trying to make a projectile shoot using with allegro library in C.And I couldn't do it in no way.My all code is below.My circle goes up but then disappear.Even if not I can't bring it down to the ground.I'm not good at physic so if my equals are wrong please forgive me. #include <allegro.h> #include < math.h > void StartAlleg(); // my start program function void EndAlleg(); int main() { StartAlleg(); BITMAP *buffer = create_bitmap(640, 480); int g = 10, Vo = 0 , Vx = 5, Vy = 475, angle= 0; double time = 0, tUp = 0,hmax=0; //g is gravity show_mouse(screen); while (!key[KEY_ESC]) { circle(buffer, Vx, Vy, 5, makecol(255, 0, 0)); if (key[KEY_UP]&&angle<360) angle++; if (key[KEY_RIGHT]) Vo++; if (key[KEY_DOWN] && angle>0) angle--; if (key[KEY_LEFT] && Vo>0) Vo--; textout_ex(buffer, font, "Player 1 : ", 0, 0, makecol(255, 255, 13), -1); textprintf(buffer, font, 0, 25, makecol(255, 255, 13), "Angle = %d ",angle); textprintf(buffer, font, 0, 15, makecol(255, 255, 13), "Speed = %d ", Vo); if (key[KEY_Z] ){ Vx = Vo*cos(double(angle)); Vy = Vo*sin(double(angle)); if (angle== 180 || angle == 360) Vy = 0; if (angle== 90 || angle== 270) Vx = 0; if (Vx < 0) Vx *= (-1); if (Vy < 0) Vy *= (-1); tUp = Vy / g; time = tUp * 2; hmax = (Vy*Vy) / (2*g); } textprintf(buffer, font, 0, 35, makecol(255, 255, 13), "tUp Value = %.2f ", tUp); for (int i = 1; i <= time; i++) { if (i<tUp){ Vx = Vx + g; Vy += g; } else{ Vy -= g; Vx = Vx + g; } } blit(buffer, screen, 0, 0, 0, 0, 640, 480); rest(60); clear_bitmap(buffer); } EndAlleg(); // my end program function return 0; } END_OF_MAIN() void StartAlleg() { int depth, res; allegro_init(); depth = desktop_color_depth(); if (depth == 0) depth = 32; set_color_depth(depth); res = set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); if (res != 0) { allegro_message(allegro_error); exit(-1); } install_timer(); install_keyboard(); install_mouse(); install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, "A"); } void EndAlleg() { clear_keybuf(); } I think , the main problem is here : for (int i = 1; i <= time; i++) { if (i<tUp){ Vx = Vx + g; Vy += g; } else{ Vy -= g; Vx = Vx + g; } }
I didn't try to understand all your code, but it seems that your calculations are wrong. Here is how gravity can be implemented : First, you need to keep track of your projectile position, with variables like Px Py. This position will give you the drawing coordinates. Then you need to keep track of its speed, usually horizontal and vertical speed, with variables like Vx Vy. If your initial speed is a single vector with angle, convert it once. Every tick of your game (every loop iteration in your case), you add the speeds to the positions. Then to add gravity, you subtract 10 to the vertical speed, also at every tick (it implements acceleration of -10). And thats all. Negative speeds and accelerations are normal, you don't need to check, but you can check for borders for positions. Also, you should note that you usually divide the speeds and accelerations by the frequency of your ticks, or else the faster your loop the faster the projectile will move. You should note that this isn't the best way to implement gravity, because this only approximate physics (more ticks per second will give you more accurate simulation). You should google "game implement gravity properly" for an accurate algorithm, I'm not an expert.
no more memory for NDSolve
I am Solving a nonlinear partial differential equation and I have to apply very small steps since I am dealing with a physical phenomenon.But as I decrease the step size and even I am using MaxSteps, I still get the error no more memory for NDSolve. Here is my program: a = 0.05; b = 0.5; L = 20; T = 6 \[Pi]; h = 4; NDSolve[{b*D[u[t, x], t, t] + a*D[u[t, x], t] == D[u[t, x], x, x] - Sin[u[t, x]], u[0, x] == 0, Derivative[1, 0][u][0, x] == 0, Derivative[0, 1][u][t, 0] == h*Sin[t], Derivative[0, 1][u][t, L] == 0}, u, {t, 0, T}, {x, 0, L}, MaxStepSize -> 0.0001, MaxSteps -> 10^6]