[英]A ball animation in simple harmonic motion using SDL2 and C++
我正在嘗試模仿下面的球。 注意球的簡諧運動,與中間的速度相比,球彈跳的最末端的速度更小:
我能夠實現一個彈跳球,但它不是簡單的諧波運動:
對應的代碼如下:
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;
}
}
我有一個簡諧運動 model,像這樣:
對應的代碼如下:
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
}
這個實現的問題是:
(1)。 球的圖像不時出現,而不是像藍球那樣連續出現
(2)。 球遠遠超出 window 的頂部框架,而不是在 window 的最頂部減速,再次像藍色球 model。
對於 (2),我知道我需要添加一個相移,即 A*sin(wt + x) 中的 x,但是更改此值不會阻止球在 window 的頂部消失。
關於如何解決這些問題的任何想法?
編輯:我能夠通過對 mPosY 執行 += 而不是 = 來解決 (1),例如:
mPosY += int(4 * cos(2.4 * 2 * 3.141592 / 60 * current_time + (SCREEN_HEIGHT / 2) ));
但是,我仍然無法讓球在我創建的 window 的框架內上下反彈。
我建議使用實際的簡單諧波方程。 例如,如果您的顯示尺寸為 (500, 500),則中心 Y 為 250。從那里說您的等式形式為 x = a cos(n t + m) + c 其中 x 是位移(米), a 是幅度,n 是周期,例如周期 (T) = 2PI/nt 是時間(秒),m 是相移,c 是中心。 這樣,當您需要 object 的速度時,您就有一個 function 遵循
double Velocity(double time){
double vel = derivative_of_displacement_equation(time);
return vel;
}
因此在程序中,您調整方程以適應顯示尺寸,然后將對象 X/Y 坐標設置為從位移方程返回的值(加上中心偏移,在本例中,如果中心在中間在屏幕上,您可以將 Y 坐標設置為方程 PLUS 250)。 請記住,坐標從 (0,0) 開始,因此您的位移方程(至少涉及比例因子的部分,在這種情況下是時間),改為負數。
這是一些我相信可以回答您的問題的代碼:
#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;
}
通常,您有a0 + a/2*cos (2**t/T + )
其中a0
是垂直行程一半的垂直 position, a
是行程的高度, t
是時間, T
是周期,即., 完成一個完整循環的時間,以返回相同的 state 或上 { position, 動量},以及時間偏移,即高度為零的時刻 cos。
因此,如果您希望球在t=0
時在地板上,您希望 cos 處於最小值,即= -/2
。
您想在游戲時間t
的 function 中管理 position ,因此您可以將計算時間(取決於您的計算能力)和游戲時間(您希望從一台機器到另一台機器保持不變)解耦。
因此你想要:
auto VerticalPosition(double t)
-> double { return CorrectedScreenHeight/2*(1 + cos(2*PI*t/T + phi)); }
並且您將CorrectedScreenHeight = SCREEN_HEIGHT - DOT_HEIGHT
、 T
和phi
定義為系統的屬性。
在兩個連續的圖像之間,您增加t
,以獲得正確的體驗時間。 通常,您有 60 個圖像/秒(WPF、DirectX、web 等),因此連續圖像之間的周期為 1.0/60 秒,這在您的 function 中修改t
。 然后你的球的速度取決於T
,你可以獨立調整。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.