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.
Related
I am currently a bit stuck! Lets say, have a grid of shapes (nested For-Loop) and I want to use a wave to animate it. The wave should have an offset. So far, i can achieve it. Currently the offset affects the Y-axis … But how can I manage to have a RADIAL offset – you know – like the clock hand, or a radar line… I really would like the offset to start from (width/2, height/2) – and then walks around clockwise. Here is my code and the point where I am stuck:
void setup() {
size(600, 600);
}
void draw () {
background(255);
float tiles = 60;
float tileSize = width/tiles;
for (int x = 0; x < tiles; x++) {
for (int y = 0; y < tiles; y++) {
float waveOffset = map(y, 0, 60, 0, 300);
float sin = sin(radians(frameCount + waveOffset));
float wave = map(sin, -1, 1, 0, tileSize);
fill(0);
noStroke();
pushMatrix();
translate(tileSize/2, tileSize/2);
ellipse(x*tileSize, y*tileSize, wave, wave);
popMatrix();
}
}
}
I tried different things – like the rotate(); function etc. but I can't manage to combine it!
Thank you for any kind of help!
Right now, you're defining the size of the ellipses based on a transformation of sin(y). A transformation means it looks like a * sin(b * y + c) + d, and in this case you have
a = tileSize / 2
b = 300 / 60 = 5
c = frameCount
d = tileSize / 2
If you want to do a different pattern, you need to use a transformation of sin(theta) where theta is the "angle" of the dot (I put "angle" in quotes because it's really the angle from the vector from the center to the dot and some reference vector).
I suggest using the atan2() function.
Solution:
float waveOffset = 2*(atan2(y - tiles/2, x - tiles/2));
float sin = sin((frameCount/20.0 + waveOffset));
void setup() {
size(600, 600);
}
void draw () {
background(255);
float tiles = 60;
float tileSize = width/tiles;
for (int x = 0; x < tiles; x++) {
for (int y = 0; y < tiles; y++) {
float waveOffset = atan2(y - tiles/2, x - tiles/2)*0.5;
float sin = sin((frameCount*0.05 + waveOffset));
float wave = map(sin, -1, 1, 0, tileSize);
fill(0);
noStroke();
pushMatrix();
translate(tileSize/2, tileSize/2);
ellipse(x*tileSize, y*tileSize, wave, wave);
popMatrix();
}
}
}
Is is just possible to draw a simple dotted line using SDL2 (or with gfx) like
int drawDottedLine(SDL_Renderer *renderer,Sint16 x1,Sint16 y1, Sint16 x2, Sint16 y2, int r, int g, int b, int a);
found absolutely nothing on the web wtf is it so hard ?
Here is a working function, that uses the Bresenham algorithm:
void DrawDottedLine(SDL_Renderer* renderer, int x0, int y0, int x1, int y1) {
int dx = abs(x1-x0), sx = x0<x1 ? 1 : -1;
int dy = -abs(y1-y0), sy = y0<y1 ? 1 : -1;
int err = dx+dy, e2;
int count = 0;
while (1) {
if (count < 10) {SDL_RenderDrawPoint(renderer,x0,y0);}
if (x0==x1 && y0==y1) break;
e2 = 2*err;
if (e2 > dy) { err += dy; x0 += sx; }
if (e2 < dx) { err += dx; y0 += sy; }
count = (count + 1) % 20;
}
}
You must consider that this function has terrible performance, because every point of the dashed line will call SDL_RenderDrawPoint() in order to get rendered.
Here is the code I used for my pong game:
SDL_SetRenderDrawColor(renderer, 155, 155, 155, 255);
for (line.y = 0; line.y < WINDOW_HEIGHT; line.y += 10)
{
SDL_RenderFillRect(renderer, &line);
}
Earlier in the code I initialized the line:
SDL_Rect line;
line.w = 2;
line.h = 8;
line.x = WINDOW_WIDTH / 2;
You can simply implement it yourself ...
Check the "Bresenham algorithm" for draw a line.
For a doted line, it's just many full line, so a pencil and paper with trigonometry should work out :)
Edit : For a dotted line, you even don't have the use to the "Bresenham algorithm", you just need trigonometry.
And by the way, for those who have downvoted, explain yourself ?
I've got an assignment at Uni which involves drawing lots of different shapes, all of whihch has to be drawn using the gdImage library in C language. So far I've used gdImageLine and gdImageRectangle, like this:
gdImageLine ( gdImage, 150, 70, 170, 90, blue);
or
gdImageRectangle( gdImage, 110, 80, 160, 120, blue);
I'm very inexperienced/have no clue about C, so any help would be great!
Hi, sorry I got confused. I wanted to draw a shape using "gdImagePolygon" in the way/similar to how I used the other two, if that makes sense? I've been given this link (http://cnfolio.com/public/libgd_drawing_reference.html), thanks
gdImagePolygon has the following signature:
gdImagePolygon(gdImagePtr im, gdPointPtr points, int pointsTotal, int color)
gdImagePtr is a pointer to a gdImage Structure
gdPointPtr is a pointer to a gdPoint structure (just two ints, x and y of the point):
typedef struct {
int x, y;
} gdPoint, *gdPointPtr;
pointsTotal is the number of points you'll have total (minimum of 3)
color is the color
The sample to draw a triangle:
... inside a function ...
gdImagePtr im;
int black;
int white;
/* Points of polygon */
gdPoint points[3]; // an array of gdPoint structures is used here
im = gdImageCreate(100, 100);
/* Background color (first allocated) */
black = gdImageColorAllocate(im, 0, 0, 0);
/* Allocate the color white (red, green and
blue all maximum). */
white = gdImageColorAllocate(im, 255, 255, 255);
/* Draw a triangle. */
points[0].x = 50;
points[0].y = 0;
points[1].x = 99;
points[1].y = 99;
points[2].x = 0;
points[2].y = 99;
gdImagePolygon(im, points, 3, white);
/* ... Do something with the image, such as
saving it to a file... */
/* Destroy it */
gdImageDestroy(im);
I wrote this code snippet from scratch, please notice me if there is any mistake. Thanks.
int Draw_Polygon (int Side, ...)
{
va_list Ap;
va_start (Ap, Side);
int X_1 = va_arg (Ap, int);
int X_0 = X_1;
int Y_1 = va_arg (Ap, int);
int Y_0 = Y_1;
int Cnt;
for (Cnt = 0; Cnt < Side-1; Cnt++)
{
int X_2 = va_arg (Ap, int);
int Y_2 = va_arg (Ap, int);
gdImageLine ( gdImage, X_1, Y_1, X_2, Y_2, blue);
X_1 = X_2;
Y_1 = Y_2;
}
gdImageLine ( gdImage, X_1, Y_1, X_0, Y_0, blue);
va_end(Ap);
return 0;
}
int main (void)
{
if (Draw_Polygon (5, 0, 0, 0, 10, 12, 12, 16, 8, 5, 0) == 0) // Draw a pentagon.
{
// Success !
}
if (Draw_Polygon (6, 0, 0, 0, 10, 12, 12, 16, 8, 6, 3, 5, 0) == 0) // Draw a hexagon.
{
// Success !
}
}
Quick pseudocode to draw a polygon of N sides, with a side length of L:
Procedure DrawPol (integer N,L)
Integer i
For i=1 To N
Draw (L)
Turn (360/N)
EndFor
EndProcedure
This pseudocode is base on two primitives, which are common in languages like LOGO:
Draw (L) : draws a line of L pixels in the current direction
Turn (A) : changes current direction by adding A degrees to the
current direction
To implement Draw and Turn using the Line function you can use something like this:
Real CurrentAngle = 0 /* global variable */
Integer CurrentX = MAXX / 2 /* last point drawn */
Integer CurrentY = MAXY / 2 /* initialized to the center of the paint area */
Procedure Draw (Integer L)
Integer FinalX,FinalY
FinalX = CurrentX + L*cos(CurrentAngle)
FinalY = CurrentY + L*sin(CurrentAngle)
Line (CurrentX, CurrentY, FinalX, FinalY) /* gdImageLine() function actually */
CurrentX = FinalX
CurrentY = FinalY
EndProcedure
Procedure Turn (Float A)
CurrentAngle = CurrentAngle + A
If (CurrentAngle>360) /* MOD operator usually works */
CurrentAngle = 360-CurrentAngle /* only for integers */
EndIf
EndProcedure
I had to generate an image that's a black circle, black being (0, 0 , 0) and white being (1, 1, 1), but I keep getting a completely black image. Here's all my code:
#include "cast.h"
#include "collisions.h"
#include <stdio.h>
#include "math.h"
int cast_ray(struct ray r, struct sphere spheres[], int num_spheres)
{
int isFound;
struct maybe_point mp;
isFound = 0;
for (int i = 0; i < num_spheres; i++)
{
mp = sphere_intersection_point(r, spheres[i]);
if (mp.isPoint == 1)
{
isFound = 1;
}
else
{
isFound = 0;
}
}
return isFound;
}
void print_pixel(double a, double b, double c)
{
int i, j, k;
i = a * 255;
j = b * 255;
k = c * 255;
printf("%d %d %d ", i, j, k);
}
void cast_all_rays(double min_x, double max_x, double min_y, double max_y,
int width, int height, struct point eye,
struct sphere spheres[], int num_spheres)
{
double width_interval, height_interval, y, x;
int intersect;
width_interval = (max_x - min_x)/width;
height_interval = (max_y - min_y)/height;
for (y = max_y; y > min_y; y = y - height_interval)
{
for (x = min_x; x < max_x; x = x + width_interval)
{
struct ray r;
r.p = eye;
r.dir.x = x;
r.dir.y = y;
r.dir.z = 0.0;
intersect = cast_ray(r, spheres, num_spheres);
if (intersect != 0)
{
print_pixel (0, 0, 0);
}
else
{
print_pixel (1, 1, 1);
}
}
I already had functions that I know are correct which find whether or not the ray intersects with a sphere. The function that I used to find intersection points was in the function cast_ray.
sphere_intersection_point(r, spheres[i]);
The print_pixel function translates the integer values by multiplying them with the max color value, which is 255.
And the cast_all_rays function casts rays into the whole scene from our eyes (going through all the x coordinates before changing the y). If the ray intersects with a sphere, the pixel is black, thus, forming a black circle in the end.
And here are the limits for the x, y, and radius (NOTE: I'M USING THE PPM FORMAT):
Eye at <0.0, 0.0, -14.0>.
A sphere at <1.0, 1.0, 0.0> with radius 2.0.
A sphere at <0.5, 1.5, -3.0> with radius 0.5.
min_x at -10, max_x at 10, min_y of -7.5, max_y at 7.5, width=1024, and height=768.
I need to generate an image of a black circle, but I keep getting an image that's completely black. I have a feeling that the problem lies inside the cast_all_rays function, but I just can't seem to find what it is. Help is appreciated! Thanks.
And just in case something went wrong with my testing, here's my test.c file for cast_all_rays:
#include "collisions.h"
#include "data.h"
#include "cast.h"
#include <stdio.h>
void cast_all_rays_tests(void)
{
printf("P3\n");
printf("%d %d\n", 1024, 768);
printf("255\n");
double min_x, max_x, min_y, max_y;
int width, height;
struct point eye;
struct sphere spheres[2];
eye.x = 0.0;
eye.y = 0.0;
eye.z = -14.0;
spheres[0].center.x = 1.0;
spheres[0].center.y = 1.0;
spheres[0].center.z = 0.0;
spheres[0].radius = 2.0;
spheres[1].center.x = 0.5;
spheres[1].center.y = 1.5;
spheres[1].center.z = -3.0;
spheres[1].radius = 0.5;
min_x = -10;
max_x = 10;
min_y = -7.5;
max_y = 7.5;
cast_all_rays(min_x, max_x, min_y, max_y, width, height, eye, spheres, num_spheres);
}
int main()
{
cast_all_rays_tests();
return 0;
}
Not sure if this is the problem you're having, but you should only set isFound if you intersect a sphere. Don't set it if you don't intersect. Otherwise your image will be governed by only the last sphere in the list.
if (mp.isPoint == 1)
{
isFound = 1;
}
//else
//{
// isFound = 0;
//}
Since your image is entirely black, it seems like your intersection code is bung or your field of view is too narrow. If you don't have any joy with the above change, maybe you should post details on your x- and y-limits, the eye position, and the position and radius of the sphere.
One more thing I noticed is r.dir.z = 0.0. Do you subtract the eye position from this to get a direction, or is that your true ray direction? Surely you need to give a non-zero z-direction. Normally you set the x and the y based on your view plane and provide a constant z such as 1 or -1.
[edit]
To make it clearer from the comments below, I believe that you haven't correctly set up your ray direction. Instead you have simply set the direction to be the view-plane's pixel position, ignoring the eye position. The following would be more usual:
struct ray r;
r.p = eye;
r.dir.x = x - eye.x;
r.dir.y = y - eye.y;
r.dir.z = 0.0 - eye.z;
I am attempting to implement collision response in a simulation that I am creating.
Basically, the program simulates a ball being thrown off a 50 meter building with some initial velocity.
I don't believe that the program is outputting realistic values for time of collision as well as values for x, y and vx, vy.
Here is the program:
#include<stdio.h>
#include<math.h>
#include<stdlib.h>
int main() {
FILE *fp;
FILE *fr;
//Declare and initialize all variables to be used
float ax = 0, ay = 0, x = 0, y = 0, vx = 0, vy = 0;
float time = 0, deltaTime = .001;
float vyImpact = 0, vxImpact = 0, xImpact = 0;
float old_y = 0, old_x = 0, old_vy = 0, old_vx = 0;
float deltaTime2 = 0, deltaTime3 = 0;
int numBounces = 0;
//Coefficient of Restitution; epsilon = ex = ey
float ex = .5;
float ey = .5;
fr = fopen("input_data.txt", "rt"); //Open file for reading
fp = fopen( "output_data.txt", "w" ); // Open file for writing
if(fr == NULL){ printf("File not found");} //if text file is not in directory...
if(fp == NULL){ printf("File not found");} //if text file is not in directory...
fscanf(fr, "ax: %f ay: %f x: %f y: %f vx: %f vy: %f\n", &ax, &ay, &x, &y, &vx, &vy);
while (numBounces < 9) {
//time = time + deltaTime
time = time + deltaTime;
//velocity[new] = velocity[old] + acc * deltaTime
vx = vx + ax*deltaTime;
vy = vy + ay*deltaTime;
//position[new] = position[old] + velocity*deltaTime + .5*acc*(deltaTime)^2
x = x + vx*deltaTime + (.5*ax*deltaTime*deltaTime);
y = y + vy*deltaTime + (.5*ay*deltaTime*deltaTime);
fprintf(fp, "%f\t%f\t%f\t%f\t%f\t%f\t%f\t\n", ax, ay, x, y, vx, vy, time);
//Collision occurs; implement collision response
if (y < 0) {
//"Undo" values for y, x, and velocity
old_y = y - vy*deltaTime - (.5*ay*deltaTime*deltaTime);
old_x = x - vx*deltaTime - (.5*ax*deltaTime*deltaTime);
old_vy = vy - ay*deltaTime;
old_vx = vx - ax*deltaTime;
//Calculate time of collision
deltaTime2 = (-old_y + sqrt((old_y*old_y) - 2*ay*old_y)) / (ay);
printf("Time of Collision = %f\n", time - deltaTime2);
//Calculate velocity and x position at collsion
vyImpact = old_vy + ay*deltaTime2;
vxImpact = old_vx + ax*deltaTime2;
xImpact = old_x + old_vx*deltaTime2 + .5*ax*(deltaTime2*deltaTime2);
//Calculate new time for when ball bounces
deltaTime3 = deltaTime - deltaTime2;
//Calculate new x and y position and velocity for when ball bounces
x = xImpact + (ex)*vxImpact*deltaTime3 + .5*ax*(deltaTime3*deltaTime3);
y = 0 + (-ey)*vyImpact*deltaTime3 + .5*ay*(deltaTime3*deltaTime3);
vy = (-ey)*vyImpact + ay*deltaTime3;
vx = (ex)*vxImpact + ax*deltaTime3;
numBounces++;
printf("Number of Bounce(s) = %d\n", numBounces);
fprintf(fp, "%f\t%f\t%f\t%f\t%f\t%f\t%f\t\n", ax, ay, x, y, vx, vy, time);
}
}
fclose(fp); //Close output file
fclose(fr); //Close input file
//system ("PAUSE");
return 0;
}
Basically, I am trying to produce accurate values so that I can see a plot of what this simulation is supposed to look like. I am assuming the logical errors have something to do with the physics. But being that my physics knowledge is limited, I am not able to see what exactly is wrong.
Here is sample input:
ax: 0 ay: -9.8 x: 0 y: 50 vx: 8.66 vy: 5
It seems to me that your problem may lie in how you're implementing the kinematics equations.
//velocity[new] = velocity[old] + acc * deltaTime
vx = vx + ax*deltaTime;
vy = vy + ay*deltaTime;
//position[new] = position[old] + velocity*deltaTime + .5*acc*(deltaTime)^2
x = x + vx*deltaTime + (.5*ax*deltaTime*deltaTime);
y = y + vy*deltaTime + (.5*ay*deltaTime*deltaTime);
Two things here: you're already taking the acceleration into account in your equations for vx and vy, and you're using summation rather than integrated equations. The .5*ax*deltaTime*deltaTime and .5*ay*deltaTime*deltaTime shouldn't be included. The equation x= 0.5*a*t^2 is used when calculating the distance traveled due to a constant acceleration for the total amount of time, based on the integral of the velocity equation. As you're doing summation and already include the acceleration in your velocity equations, there's no need to include the acceleration in the position equations.