I'm trying to emulate the following ball. Notice the simple harmonic motion of the ball, with the very ends of the ball bounce having a smaller velocity compared to the velocity in the middle:
I'm able to implement a bouncing ball, however it's not simple harmonic motion:
The corresponding code is as follows:
Dot::Dot() {
//Initialize the offsets
mPosX = 300;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 4;
}
void Dot::move() {
//Move the dot up or down
mPosY += mVelY;
//If the dot went too far up or down
if( ( mPosY < 0 ) || ( mPosY + DOT_HEIGHT > SCREEN_HEIGHT ) )
{
//Move back
mVelY = -mVelY;
}
}
I have a simple harmonic motion model, like so:
The corresponding code is as follows:
Dot::Dot() {
//Initialize the offsets
mPosX = 300;
mPosY = 0;
//Initialize the velocity
mVelX = 0;
mVelY = 0;
}
void Dot::move() {
time_t current_time;
current_time = time(NULL);
mPosY = int(((460) - 10) * sin(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2)
));
//const int SCREEN_HEIGHT = 480
}
The issues with this implementation are that:
(1). the ball image appears every now and then, rather than continuously like in the blue ball model I tried to emulate at the very beginning
(2). the ball goes well beyond the top frame of the window, rather than slowing down at the very top of the window, again like the blue ball model.
For (2), I understand that I need to add a phase shift, i.e x in A*sin(wt + x), however changing this value doesn't do anything to prevent the ball from disappearing at the top of the window.
Any ideas on how to solve these issues?
Edit: I was able to solve (1) by doing += to mPosY rather than =, such as:
mPosY += int(4 * cos(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2) ));
However, I'm still unable to get the ball to bounce up and down within the frame of the window I created.
I recommend using actual simple harmonic equations.
For example, if your display dimensions are (500, 500), the center Y is 250. from there say your equation is in the form of x = acos(nt + m) + c where x is displacement (meters), a is amplitude n is for the period, for example the period (T) = 2PI/n t is time (seconds) and m is for phase shift and c is for the center. That way when you need the velocity of the object, you have a function that follows along the lines of
double Velocity(double time){
double vel = derivative_of_displacement_equation(time);
return vel;
}
And so in the program, you adjust the equation to suit the display dimensions, then you set the objects X/Y coordinates as the value returned from the displacement equation (PLUS THE CENTER OFFSET, in this example, if the center is at the middle of the screen, you would set the Y coordinate to the equation PLUS 250). Keep in mind coordinates begin at (0,0) so your displacement equation (at least the part where it involves the proportional factor, which in this case is time), you make that negative instead.
Here is some code that I believe answers your question:
#include <SDL2/SDL.h>
#include <chrono>
#include <math.h>
#include <iostream>
const double PI = 3.14159265358979;
void draw_circle(SDL_Renderer *renderer, int x, int y, int radius, SDL_Color color)
{
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
for (int w = 0; w < radius * 2; w++)
{
for (int h = 0; h < radius * 2; h++)
{
int dx = radius - w; // horizontal offset
int dy = radius - h; // vertical offset
if ((dx*dx + dy*dy) <= (radius * radius))
{
SDL_RenderDrawPoint(renderer, x + dx, y + dy);
}
}
}
}
double Displacement(double time, double a, double n, double m, double c)
{
double displacement = a*cos(n*time + m) + c;
return displacement;
}
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_VIDEO);
SDL_Window *window = SDL_CreateWindow("SHM", 0, 30, 500, 500, SDL_WINDOW_OPENGL|SDL_WINDOW_RESIZABLE);// | SDL_WINDOW_SHOWN);
SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED );
double timeDifference;
std::chrono::steady_clock::time_point start, finish;
start = std::chrono::steady_clock::now();
finish = start;
SDL_Event event;
bool running = true;
while (running){
while (SDL_PollEvent(&event)){
if (event.type == SDL_QUIT){
running = false;
break;
}
}
SDL_SetRenderDrawColor(renderer, 255,255,255,255);
SDL_RenderClear(renderer);
finish = std::chrono::steady_clock::now();
timeDifference = std::chrono::duration_cast<std::chrono::nanoseconds>(finish - start).count();
timeDifference = timeDifference / 1000000000;
///The "-(250-20) is the center y (250) minus the radius of the circle (20), and its - out the front as negative a due to coordinates
double yPosition = round( Displacement(timeDifference, -(250-20), 2, 0, 250 ) );
draw_circle(renderer, 250, yPosition, 20, {255,0,0});
SDL_RenderPresent(renderer);
}
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
return 0;
}
In general you have a0 + a/2*cos (2*𝝥*t/T + 𝝫) where a0 is the vertical position of the half of the vertical travel, a is the height of the travel, t is time, T the period ie., the time to do a complete cycle for going and coming back to the same state or uple { position, momentum }, and 𝝫 the time shift, ie., the moment where the height is at zero of the cos.
So if you want the ball to be on the floor at t=0, you want cos at the minimum, ie., 𝝫 = -𝝥/2.
You want to manage your position in function of your game's time t, so you can decouple the time to compute (which depend on your compute calpabilities) and the game's time (that you want constant from a machine to another).
Therefore you want:
auto VerticalPosition(double t)
-> double { return CorrectedScreenHeight/2*(1 + cos(2*PI*t/T + phi)); }
And you define CorrectedScreenHeight = SCREEN_HEIGHT - DOT_HEIGHT, T and phi outside, as properties of your system.
Between two consecutive images, you increment t, in order to have the correct experienced time. Typically you have 60 images/s (WPF, DirectX, web, etc), hence a period of 1.0/60s between consecutive images, this goes in your function that modifies t. The speed of your ball then depend on T, that you can tune independently.
Related
// #include loads up library files, the order can matter
// generally load glut.h last
#include <stdio.h> // this library is for standard input and output
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "glut.h"// this library is for glut the OpenGL Utility Toolkit
//this defines a constant for the array size
#define SPRAYSIZE 500
// the properties of a spray particle are defined in a struct
struct sprayParticle {
float x = 0; // current position x
float y = 0; // current position y
float startx = 0; // birth position x
float starty = 0; // birth position y
int startTime; // a birthtime in frames when it will be born
int startRange = 100; // the maximum time at which a birth can happen
bool started = false; // tracks whether the particle has benn born or not
float speed = 0.1;
float radius;
float startxd = 0; // starting direction vector x value
float startyd = 0; // startingdirection vestor y value
float xd = 0; // current direction vector x value
float yd = 0; // current direction vector x value
float alpha = 1.0; // transparency
};
int winWidth = 1000, winHeight = 1000;
int counter = 0;
time_t t;
sprayParticle spray[SPRAYSIZE];
float angle = 90; // the angle of the spray: 0 degrees is to the left,
// 90 degrees straight up, 180 to the right etc
float sprayWidth = 30;// the width of the spray in degrees
float sprayCenterX, sprayCenterY;
//variables for spray colour, set once per spray
float fr = 1; float fg = 1; float fb = 1;
// the gravity vector
float gx = 0;
float gy = -0.0005;
// the position of thepartcle ystem emitter, wher the rocket should be drawn
float rocketstartx = winWidth - 100, rocketstarty = winHeight - 100;
void init() {
glClearColor(0.0, 0.0, 0.0, 0.0); // set what colour you want the background to be
glMatrixMode(GL_PROJECTION); // set the matrix mode, we will look at this later
gluOrtho2D(0.0, winWidth, 0.0, winHeight);
}
void circle(double radius, double xc, double yc) {
int i;
double angle = 2 * 3.1415 / 20; // circle is drawn using 20 line.
double circle_xy[40][2];
circle_xy[0][0] = radius + xc;
circle_xy[0][1] = yc;
glBegin(GL_POLYGON);
for (i = 1; i < 20; i++) {
circle_xy[i][0] = radius * cos(i *angle) + xc;
circle_xy[i][1] = radius * sin(i * angle) + yc;
glVertex2f(circle_xy[i - 1][0], circle_xy[i - 1][1]);
glVertex2f(circle_xy[i][0], circle_xy[i][1]);
}
glEnd();
}
void normalise(int i) {
float mag;
mag = sqrt((spray[i].xd*spray[i].xd) + (spray[i].yd*spray[i].yd));
spray[i].xd = spray[i].xd / mag;
spray[i].yd = spray[i].yd / mag;
}
// we calculate the direction vector of the current particle from the global
variable angle and spread
void setDirectionVector(int i) {
float minAngle, maxAngle, range, newangle;
double newAngleInRadians; // variable
int rangeInt;
minAngle = angle - (sprayWidth / 2.0); // calc the minimum angle the particle could move along
maxAngle = angle + (sprayWidth / 2.0); // calc the maximum angle
range = maxAngle - minAngle;
rangeInt = (int)(range*100.0);
newangle = minAngle + ((float)(rand() % rangeInt) / 100.0); // generate a random angle between mi and max angles
newAngleInRadians = (double)(newangle / 360.0)*(2 * 3.1415); // convert it to radians
spray[i].xd = (float)cos(newAngleInRadians);// calc the diection vector x value
spray[i].yd = (float)sin(newAngleInRadians);// calc the diection vector y value
}
void initspray() {
for (int i = 0; i < SPRAYSIZE; i++) {
spray[i].x = winWidth / 2; // set current start x position
spray[i].y = 100;// set current start y position
spray[i].startx = spray[i].x; spray[i].starty = spray[i].y;// set start x and y position
spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;// speed is 0.1 to 0.25
spray[i].startTime = rand() % spray[i].startRange;// set birth time
spray[i].radius = (float)(rand() % 15); // random radius
setDirectionVector(i);// set the current direction vector
spray[i].startxd = spray[i].xd; spray[i].startyd = spray[i].yd; // set start direction vector to current
}
// set colour of spray
fr = 0.5 + (float)(rand() % 500) / 1000.0;
fg = 0.5 + (float)(rand() % 500) / 1000.0;
fb = 0.5 + (float)(rand() % 500) / 1000.0;
}
void drawsprayParticle(int i) {
glLineWidth(2);
if (!spray[i].started) {
if (counter == spray[i].startTime) {
spray[i].started = true;
}
}
if (spray[i].started) {
glColor4f(fr, fg, fb, spray[i].alpha); // white particiles
circle(spray[i].radius, spray[i].x, spray[i].y);
spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
// this produces a direction vector that is a little longer than 1
spray[i].yd = spray[i].yd + gy;
// so the normalise the vector to make length 1
normalise(i);
// reduce transparency
spray[i].alpha -= 0.00015;
}
if (spray[i].x<0 || spray[i].x>winWidth + 500 || spray[i].y<0 || spray[i].y>winHeight) {
spray[i].x = spray[i].startx; spray[i].y = spray[i].starty; //rocketstartx
spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
spray[i].alpha = 1.0;
}
}
void drawspray() {
// draw each spray particle
for (int i = 0; i < SPRAYSIZE; i++) {
drawsprayParticle(i);
}
// increment rocket position
rocketstartx += 0.2;
// if the rocket is oof the screen more nad 500 pixels to the right the rest it to 0
if (rocketstartx > winWidth + 500) { rocketstartx = 0; }
counter++;
}
// This is the display function it is called when ever you want to draw something
void display() {
glClear(GL_COLOR_BUFFER_BIT); // clear the screen using the background colour
glColor3f(1.0, 1.0, 1.0); // set colour to white
drawspray();
glFlush(); // force all drawing to finish
}
// This is the idle function it is called whenever the program is idle
void idle() {
display();
}
// As with many programming languages the main() function is the entry point for execution of the program
int main(int argc, char** argv) {
srand((unsigned)time(&t));
// initialise first spray work
initspray();
glutInit(&argc, argv); //perform the GLUT initialization
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGBA); // more initialisation
glutInitWindowSize(winWidth, winHeight); // set window position
glutInitWindowPosition(0, 0); // set window size
glutCreateWindow("Fire"); // create a display with a given caption for the title bar
glEnable(GL_BLEND); //Enable blending.
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
init(); // call init function defined above
glutIdleFunc(idle); // define what function to call when the program is idle
glutDisplayFunc(display); // define what function to call to draw
glutMainLoop();
// this line exits the program
return 0;
}
The original code above normally creates a fountain that sprays particles all over the screen, but I have changed the size and range of the spray, so I can create a flame. The problem is that I can't stop the spread of the particles and it keeps moving up. I want it to stay in its position.
This is how it works:
This is how I want it to work:
With the formula
spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
the distance of the points to it origin linear increases. You have to decrease the speed by time to smoothly approach to a limit position.
e.g.
spray[i].speed *= 0.9992f;
Of course you have to rest the speed (spray[i].speed), when the point is "restarted" at its origin. If the speed of the point or the alpha value of the point falls below a threshold, then the point has to be "restarted", too:
void drawsprayParticle(int i) {
glLineWidth(2);
if (!spray[i].started) {
if (counter == spray[i].startTime) {
spray[i].started = true;
}
}
if (spray[i].started) {
glColor4f(fr, fg, fb, spray[i].alpha); // white particles
circle(spray[i].radius, spray[i].x, spray[i].y);
spray[i].x = spray[i].x + (spray[i].xd*spray[i].speed);
spray[i].y = spray[i].y + (spray[i].yd*spray[i].speed);
// this produces a direction vector that is a little longer than 1
spray[i].yd = spray[i].yd + gy;
// so the normalize the vector to make length 1
normalise(i);
// reduce transparency
spray[i].alpha -= 0.0003;
spray[i].speed *= 0.9992f;
}
if ( spray[i].x<0 || spray[i].x>winWidth + 500 ||
spray[i].y<0 || spray[i].y>winHeight ||
spray[i].alpha < 1.0f/256.0f ||
spray[i].speed < 0.04f ) {
spray[i].x = spray[i].startx; spray[i].y = spray[i].starty;
spray[i].xd = spray[i].startxd; spray[i].yd = spray[i].startyd;
spray[i].alpha = 1.0;
spray[i].speed = 0.1 + (float)(rand() % 150) / 1000.0;
}
}
This is an empirical algorithm, so you have to play around with the values, to get the effect of your need.
Additionally I increase the start range: int startRange = 1300;
Preview:
I'm creating a program on my spare time and I'm trying to simulate mouse cursor movements.
I'm trying to make it so that when I start my program it'll move my cursor from [x,y] to [0,0] (which is the top-left corner of my screen).
Is there anyway to do this without having it teleport?
Here is what I have so far for my mouse cursor movement program:
POINT p;
GetCursorPos( &p );
double mouseX = p.x;
double mouseY = p.y;
SetCursorPos(0, 0);
Any way to actually see my mouse being moved instead of just teleporting to [0,0] instantly?
You will need to gradually progress your mouse a little bit at a time. Consider, for example the following pseudo-code function:
def moveMouse (endX, endY, stepCount, stepDelay):
GetCurrentPosTo(startX, startY);
for step = 1 to stepCount
currX = startX + (endX - startX) * step / stepCount
currY = startY + (endY - startY) * step / stepCount
SetCurrentPosFrom(currX, currY)
DelayFor(stepDelay)
endfor
enddef
This calculates the current position (within the loop) as some fraction of the journey from (startX, startY) to (endX, endY), adjusting for the number of steps you wish to take.
So using a stepCount of 100 and stepDelay of ten milliseconds, the mouse cursor would smoothly move over the period of a second.
There could be other possibilities such as moving the cursor at a specific speed rather than taking a specific time, or specifying a minimum speed and maximum time to combine both methods.
I'll leave that as an extra exercise. Suffice to say it would involve the same method of moving the cursor a little at a time rather than just setting its position to the final value immediately.
Heres my little concoction from around the web!
It spins the mouse, and rather fluidly, in an Archimedean spiral from the center of the screen outward. You can also mess with the math in the loop, specifically the `cos()` and `sin()` functions to get it to do different movements. Purely for educational purposes only.
Enjoy :)
#include <Windows.h>
#include <iostream>
void moveMouse(int x, int y){
int count = 800;
int movex, movey;
float angle = 0.0f;
// set mouse at center screen
SetCursorPos(x/2, y/2);
// begin spiral! :)
for(int i = 0; i <= count; i++){
angle = .3 * i;
movex = (angle * cos(angle) * 2) + x/2;
movey = (angle * sin(angle) * 2) + y/2;
SetCursorPos(movex, movey);
Sleep(1);
}
}
int main(){
int Height = GetSystemMetrics(SM_CYSCREEN);
int Width = GetSystemMetrics(SM_CXSCREEN);
moveMouse(Width,Height);
return 0;
}
You will have to call SetCursorPos multiple times with coordinates first close to your point, then gradually closer to (0,0). Without some intentional delay it will just appear to happen instantly anyway, so keep that in mind.
Try this code I used to debug inputs.. I put it where it runs every frame. Get the mouse position, and set the mouse position. Your mouse should not be moving or the math is wrong..
{
POINT pos;
GetCursorPos(&pos);
INPUT input[1];
memset(&input, 0, sizeof(input));
int left = GetSystemMetrics(SM_XVIRTUALSCREEN);
int top = GetSystemMetrics(SM_YVIRTUALSCREEN);
int width = GetSystemMetrics(SM_CXVIRTUALSCREEN);
int heigth = GetSystemMetrics(SM_CYVIRTUALSCREEN);
// 0x1000 because 0 to 0xffff is not 65535, its 65536.
// we add 0.5f to the location to put us in the center of the pixel. to avoid rounding errors. Take it out and your mouse will move up and to the left.
POINT Desired;
Desired.x = ((float)(pos.x - left ) + 0.5f) * (float) (0x10000) / (float) (width);
Desired.y = ((float)(pos.y - top) + 0.5f) * (float) (0x10000) / (float) (heigth);
// move to new location
input[0].type = INPUT_MOUSE;
input[0].mi.dx = Desired.x;
input[0].mi.dy = Desired.y;
input[0].mi.mouseData = 0;
input[0].mi.dwFlags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE_NOCOALESCE | MOUSEEVENTF_MOVE | MOUSEEVENTF_VIRTUALDESK;
input[0].mi.time = 0;
SendInput(1, &input[0], sizeof(INPUT));
}
I am trying to get my tokens on a board game to fall slowly. Right now, they fall, but they fall so fast. How could I implement the timer function in my code? Right now I do a loop, that updates the y coordinate of glTranslate. But it is still too fast! the top y is the y coordinate where I press on the screen, and the bottomy is the coordinates of the lowest open spot for a token.
col =0;
double bottomy = 0;
int row = 0;
circlex = (double)x / width ;
circley = (double)y / height ;
row = board.getRow(col) + 1;
bottomy = 500 - (25*row);
for( double topy = y ; topy <= bottomy; topy += 2 ){
glTranslatef(circlex, circley, 0.0f);
circley += .0000000000000000001;
display();
}
r = board.makeMove(col);
You can use glutTimerFunc to execute a function at a regular time period. This has the signature
void glutTimerFunc(unsigned int msecs,
void (*func)(int value),
value);
For example if your drawing function was
void UpdateTokens(int time);
Then you could call an update every 0.5 seconds with the following call (where current_time was the current simulation time)
glutTimerFunc(500, UpdateTokens, current_time);
For more precise timing, I would recommend using <chrono> instead, and performing your timing using things like std::chrono::duration with a std::chrono::steady_clock.
The actual problem here is how glut works. Basically, the user only gets a image presented at the end of the main loop. As long as you do not return from the mouse function, nothing is presented on screen. You can solve the problem by transferring the work to the display function and distribute the translation across multiple frames:
global variables:
double circlex = 0, circley = 0, bottomy = 0;
bool isfalling = false;
int topy = 0;
mouse_func:
if (isfalling == false) //Prevents the user from clicking during an animation
{
circlex = (double)x / width ;
circley = (double)y / height ;
int row = board.getRow(col) + 1;
bottomy = 500 - (25*row);
topy = y;
isfalling = true;
}
display_func:
if (isfalling)
{
circley += .0000000000000000001;
topy += 2;
if (topy >= bottomy)
isfalling = false;
}
glTranslatef(circlex, circley, 0.0f);
display();
I'm making a 2D game with SFML in C++ and I have a problem with collision. I have a player and a map made of tiles. Thing that doesn't work is that my collision detection is not accurate. When I move player up and then down towards tiles, it ends up differently.
I am aware that source of this problem may be calculating player movement with use of delta time between frames - so it is not constant. But it smooths movement, so I don't know how to do it other way. I tried with constant speed valuses and to make collision fully accurate - speed had to be very low and I am not satisfied with that.
void Player::move() {
sf::Vector2f offsetVec;
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
offsetVec += sf::Vector2f(0, -10);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
offsetVec += sf::Vector2f(0, 10);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
offsetVec += sf::Vector2f(-10, 0);
if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
offsetVec += sf::Vector2f(10, 0);
this->moveVec += offsetVec;
}
void Player::update(float dt, Map *map) {
sf::Vector2f offset = sf::Vector2f(this->moveVec.x * this->playerSpeed * dt,
this->moveVec.y * this->playerSpeed * dt);
sf::Sprite futurePos = this->sprite;
futurePos.move(offset);
if (map->isCollideable(this->pos.x, this->pos.y, futurePos.getGlobalBounds())) {
this->moveVec = sf::Vector2f(0, 0);
return;
}
this->sprite.move(offset);
this->pos += offset;
this->moveVec = sf::Vector2f(0, 0);
return;
}
In player position update I create future sprite object, which is object after applying movement, to get it's boundaries and pass it to collision checker. To collision checker I also pass player pos, because my map is stored in 2d array of tile pointers, so I check only these in player range.
bool Map::isCollideable(float x, float y, const sf::FloatRect &playerBounds) {
int startX = int(x) / Storage::tileSize;
int startY = int(y) / Storage::tileSize;
Tile *tile;
for (int i = startX - 10; i <= startX + 10; ++i) {
for (int j = startY - 10; j <= startY + 10; ++j) {
if (i >= 0 && j >= 0) {
tile = getTile(i, j);
if (tile != nullptr && playerBounds.intersects(tile->getGlobalBounds()))
return true;
}
}
}
return false;
}
Full project on Github
My solution
I have changed if statement in update function to while statement, which decreases my offset vector till no collision is present. I still have to make some adjustments, but general idea is:
void Player::update(float dt, Map *map) {
int repeats = 0;
sf::Vector2f offset = sf::Vector2f(this->moveVec.x * this->playerSpeed * dt,
this->moveVec.y * this->playerSpeed * dt);
sf::Sprite futurePos = this->sprite;
while (map->isCollideable(this->pos.x, this->pos.y, futurePos, offset)) {
offset = 0.7f * offset;
repeats++;
if (repeats > 5) {
this->moveVec = sf::Vector2f(0, 0);
return;
}
}
this->sprite.move(offset);
this->pos += offset;
this->moveVec = sf::Vector2f(0, 0);
return;
}
I also had to rework isCollideable method a little, so it accepts sf::Sprite and offset vector so it can calculate boundaries on it's own.
When the player collides with a tile, you should calculate the penetration, that is, the value of "how much the player went into the tile". When you have this value, nudge your player back that much.
This is just a thought but you could have some inaccuracies in your collision detection when you typecast the float x, and y to integers and then divide them. This could cause problems because some of the data in the float could be lost. If the float was 3.5 or 3.3 or 3.9 then it would become 3 which throws off your collision calculations.
i wrote a code that draw filled circle, but it uses CPU a lot.
The thing is i draw pixel by pixel, first outter circle with radius n the second circle with radius n-1 and so on while n is not equal to 0.
I'm drawing 4 pixel in e cycle, for each circle part. Every part, as i thought, has ~ Pi/(2*R) pixels, but it is not enough and circle fill wrong, so i used Pi/(4*R) and now circle fills normaly.
Deg0 = 0;
Deg90 = M_PI / 2;
DegStep = Deg90 / (R * 4);
CurrDeg = Deg0;
OffsetX = R;
OffsetY = 0;
TmpR = R;
while(TmpR>0 )
{
while(CurrDeg < Deg90)
{
OffsetX = cos(CurrDeg) * TmpR;
OffsetY = sin(CurrDeg) * TmpR;
SDL_RenderDrawPoint(Renderer, CX+(int)OffsetX, CY+(int)OffsetY);
SDL_RenderDrawPoint(Renderer, CX-(int)OffsetY, CY+(int)OffsetX);
SDL_RenderDrawPoint(Renderer, CX-(int)OffsetX, CY-(int)OffsetY);
SDL_RenderDrawPoint(Renderer, CX+(int)OffsetY, CY-(int)OffsetX);
CurrDeg+=DegStep;
}
CurrDeg = Deg0;
TmpR-=1;
}
So, is there any way to improve my realisation?
You could use the circle drawing capabilities of SDL, or you could optimize your own code by not actually using cos and sin. Use lookup tables instead.