还是不动
这个函数是正常逻辑:
// Include standard libraries and Windows API headers.
#define UNICODE
#define _UNICODE
#include <windows.h>
#include <math.h>
#include <wchar.h>
// Constants for window dimensions, gravity, and animation.
#define WIN_WIDTH 600
#define WIN_HEIGHT 500
#define BALL_RADIUS 10
#define GRAVITY 0.0008
#define REBOUND_FACTOR 0.5
#define GROUND_Y (WIN_HEIGHT - 150)
// UI control IDs and Timer ID
#define IDC_HEIGHT_INPUT 201
#define IDC_REBOUNDS_INPUT 202
#define IDC_SUBMIT_BUTTON 203
#define TIMER_ID 101
// Ball structure for simulation
typedef struct {
double x, y; // Position of the ball (in pixels).
double vy; // Vertical velocity.
double currentHeight; // Maximum height of the ball.
int rebounds; // Number of times the ball has rebounded.
int maxRebounds; // Maximum allowed rebound count.
BOOL isActive; // If the simulation is still active.
BOOL isFalling; // If the ball is in the falling phase.
double holdTime; // Initial wait time before simulation.
double cumulativeDistance; // Total traveled distance (up + down).
BOOL isInitialState; // Marks if the ball is still in initial hold state.
} Ball;
Ball ball = {0};
// Global arrays to store statistics (rebound heights and cumulative distances).
double reboundHeights[100] = {0};
double cumulativeDistances[100] = {0};
// Global handles for UI components and windows.
HWND heightInput, reboundsInput, submitButton;
HWND mainHwnd = NULL, outputHwnd = NULL;
DWORD lastTime = 0;
/* ==================================================================
* Function : InitializeBall
* Purpose : Initializes the ball properties for a simulation.
* Parameters:
* double initialHeightMeters - Initial height in meters.
* int maxRebounds - Maximum number of rebounds allowed.
* Returns:
* void
* ================================================================== */
void InitializeBall(double initialHeightMeters, int maxRebounds) {
if (initialHeightMeters <= 0 || maxRebounds <= 0) return;
double initialHeightPixels = initialHeightMeters * 2.0; // Convert meters to pixels.
ball.x = WIN_WIDTH / 2.0; // Center x-coordinate.
ball.y = GROUND_Y - initialHeightPixels; // Starting y-position.
ball.vy = 0;
ball.currentHeight = initialHeightPixels; // Set initial height.
ball.rebounds = 0;
ball.maxRebounds = maxRebounds;
ball.isActive = TRUE;
ball.isFalling = FALSE;
ball.holdTime = 2000.0; // Initial wait for simulation start (in milliseconds).
ball.cumulativeDistance = 0.0;
ball.isInitialState = TRUE;
// Initialize statistics arrays
for (int i = 0; i < 100; i++) {
reboundHeights[i] = 0;
cumulativeDistances[i] = 0;
}
}
/* ==================================================================
* Function : UpdateBall
* Purpose : Updates ball position and velocity during the simulation.
* Parameters:
* DWORD deltaTime - Time (in milliseconds) since the last frame.
* Returns:
* void
* ================================================================== */
void UpdateBall(DWORD deltaTime) {
if (!ball.isActive) return;
if (ball.isInitialState && ball.holdTime > 0) {
ball.holdTime -= deltaTime;
if (ball.holdTime <= 0) {
ball.holdTime = 0;
ball.isFalling = TRUE; // Start falling.
ball.isInitialState = FALSE; // Transition from initial state.
}
return;
}
if (ball.isFalling) {
ball.vy += GRAVITY * deltaTime;
ball.y += ball.vy * deltaTime;
if (ball.y >= GROUND_Y - BALL_RADIUS) {
ball.y = GROUND_Y - BALL_RADIUS;
ball.isFalling = FALSE;
cumulativeDistances[ball.rebounds] = ball.cumulativeDistance + ball.currentHeight;
reboundHeights[ball.rebounds] = ball.currentHeight * REBOUND_FACTOR;
ball.cumulativeDistance += ball.currentHeight;
ball.rebounds++;
if (ball.rebounds < ball.maxRebounds) {
ball.currentHeight *= REBOUND_FACTOR;
ball.vy = -sqrt(2 * GRAVITY * ball.currentHeight);
} else {
ball.isActive = FALSE; // End simulation after maximum rebounds.
}
}
} else {
ball.y += ball.vy * deltaTime;
ball.vy += GRAVITY * deltaTime;
if (ball.vy >= 0) ball.isFalling = TRUE;
}
}
/* ==================================================================
* Function : RenderGround
* Purpose : Draws ground line onto the screen.
* Parameters:
* HDC hdc - Handle to device context for rendering.
* Returns:
* void
* ================================================================== */
void RenderGround(HDC hdc) {
HPEN groundPen = CreatePen(PS_SOLID, 2, RGB(0, 128, 0));
HPEN oldPen = SelectObject(hdc, groundPen);
MoveToEx(hdc, 0, GROUND_Y, NULL);
LineTo(hdc, WIN_WIDTH, GROUND_Y);
SelectObject(hdc, oldPen);
DeleteObject(groundPen);
}
/* ==================================================================
* Function : RenderBall
* Purpose : Draws the ball onto the screen based on its current state.
* Parameters:
* HDC hdc - Handle to device context for rendering.
* Returns:
* void
* ================================================================== */
void RenderBall(HDC hdc) {
HBRUSH ballBrush = CreateSolidBrush(RGB(139, 69, 19));
HBRUSH oldBrush = SelectObject(hdc, ballBrush);
Ellipse(hdc, (int)(ball.x - BALL_RADIUS),
(int)(ball.y - BALL_RADIUS),
(int)(ball.x + BALL_RADIUS),
(int)(ball.y + BALL_RADIUS));
SelectObject(hdc, oldBrush);
DeleteObject(ballBrush);
}
/* ==================================================================
* Function : RenderScene
* Purpose : Renders the ground and the ball on the screen.
* Parameters:
* HDC hdc - Handle to device context for rendering.
* Returns:
* void
* ================================================================== */
void RenderScene(HDC hdc) {
RenderGround(hdc);
RenderBall(hdc);
}
/* ==================================================================
* Function : OutputWindowProc
* Purpose : Handles the painting and interaction of the result window.
* Parameters:
* HWND hwnd - Handle to the result window.
* UINT msg - Message identifier.
* WPARAM wParam - Additional message information.
* LPARAM lParam - Additional message information.
* Returns:
* LRESULT - Result of the message processing.
* ================================================================== */
LRESULT CALLBACK OutputWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
wchar_t buffer[256];
int offset = 10;
HFONT hFont = CreateFontW(18, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"SimSun");
HFONT oldFont = SelectObject(hdc, hFont);
swprintf(buffer, 256, L"Total Travel Distance: %.2f meters", ball.cumulativeDistance / 2.0);
TextOutW(hdc, 10, offset, buffer, wcslen(buffer));
offset += 20;
for (int i = 1; i <= ball.rebounds; i++) {
swprintf(buffer, 256, L"Bounce %d Height: %.2f meters", i, reboundHeights[i - 1] / 2.0);
TextOutW(hdc, 10, offset, buffer, wcslen(buffer));
offset += 20;
swprintf(buffer, 256, L"Cumulative Distance After %d Bounces: %.2f meters",
i, cumulativeDistances[i - 1] / 2.0);
TextOutW(hdc, 10, offset, buffer, wcslen(buffer));
offset += 20;
}
SelectObject(hdc, oldFont);
DeleteObject(hFont);
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
outputHwnd = NULL;
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
/* ==================================================================
* Function : ShowResultWindow
* Purpose : Displays the summary results of the simulation in a new window.
* Parameters:
* HINSTANCE hInstance - Handle to the application instance.
* Returns:
* void
* ================================================================== */
void ShowResultWindow(HINSTANCE hInstance) {
if (outputHwnd != NULL) {
InvalidateRect(outputHwnd, NULL, TRUE);
return;
}
const wchar_t OUTPUT_CLASS_NAME[] = L"ResultWindow";
WNDCLASS wc = {0};
wc.lpfnWndProc = OutputWindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = OUTPUT_CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
RegisterClass(&wc);
outputHwnd = CreateWindow(
OUTPUT_CLASS_NAME, L"Simulation Results",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
NULL, NULL, hInstance, NULL);
ShowWindow(outputHwnd, SW_SHOW);
}
/* ==================================================================
* Function : MainWindowProc
* Purpose : Processes messages for the main simulation window.
* Parameters:
* HWND hwnd - Handle to the window.
* UINT msg - Message identifier.
* WPARAM wParam - Word parameter of the message.
* LPARAM lParam - Long parameter of the message.
* Returns:
* LRESULT - Result code.
* ================================================================== */
LRESULT CALLBACK MainWindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_CREATE:
CreateWindow(L"STATIC", L"Initial Height (meters):", WS_VISIBLE | WS_CHILD,
20, WIN_HEIGHT - 140, 170, 30, hwnd, NULL, NULL, NULL);
heightInput = CreateWindow(L"EDIT", L"100", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_NUMBER,
190, WIN_HEIGHT - 140, 100, 30, hwnd, (HMENU)IDC_HEIGHT_INPUT, NULL, NULL);
CreateWindow(L"STATIC", L"Max Rebounds:", WS_VISIBLE | WS_CHILD,
20, WIN_HEIGHT - 100, 170, 30, hwnd, NULL, NULL, NULL);
reboundsInput = CreateWindow(L"EDIT", L"10", WS_VISIBLE | WS_CHILD | WS_BORDER | ES_NUMBER,
190, WIN_HEIGHT - 100, 100, 30, hwnd, (HMENU)IDC_REBOUNDS_INPUT, NULL, NULL);
submitButton = CreateWindow(L"BUTTON", L"Submit", WS_VISIBLE | WS_CHILD,
310, WIN_HEIGHT - 120, 100, 40, hwnd, (HMENU)IDC_SUBMIT_BUTTON, NULL, NULL);
SetTimer(hwnd, TIMER_ID, 10, NULL);
return 0;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_SUBMIT_BUTTON) {
wchar_t heightBuffer[256], reboundsBuffer[256];
GetWindowText(heightInput, heightBuffer, 256);
GetWindowText(reboundsInput, reboundsBuffer, 256);
double height = _wtof(heightBuffer);
int maxRebounds = _wtoi(reboundsBuffer);
if (height <= 0 || height > 150) {
MessageBox(hwnd, L"Height out of range! Please enter a value between 0 and 150.",
L"Invalid Input", MB_ICONERROR);
return 0;
}
if (maxRebounds <= 0) {
MessageBox(hwnd, L"Rebound count must be greater than 0.",
L"Invalid Input", MB_ICONERROR);
return 0;
}
KillTimer(hwnd, TIMER_ID); // Reset simulation.
InitializeBall(height, maxRebounds);
lastTime = GetTickCount();
SetTimer(hwnd, TIMER_ID, 10, NULL);
InvalidateRect(hwnd, NULL, TRUE);
}
break;
case WM_TIMER:
if (wParam == TIMER_ID) {
DWORD currentTime = GetTickCount();
DWORD deltaTime = (lastTime == 0) ? 0 : (currentTime - lastTime);
lastTime = currentTime;
if (ball.isActive) {
UpdateBall(deltaTime);
RECT updateRect = {0, 0, WIN_WIDTH, GROUND_Y};
InvalidateRect(hwnd, &updateRect, TRUE);
} else {
KillTimer(hwnd, TIMER_ID); // Stop simulation timer.
ShowResultWindow((HINSTANCE)GetWindowLongPtr(hwnd, GWLP_HINSTANCE));
}
}
break;
case WM_PAINT: {
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
RenderScene(hdc);
// Display simulation status.
wchar_t status[100];
if (ball.isInitialState && ball.holdTime > 0) {
swprintf(status, 100, L"Initial state: %.1f seconds remaining", ball.holdTime / 1000.0);
TextOut(hdc, 20, 20, status, wcslen(status));
}
EndPaint(hwnd, &ps);
break;
}
case WM_DESTROY:
KillTimer(hwnd, TIMER_ID);
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
return 0;
}
/* ==================================================================
* Function : WinMain
* Purpose : Entry point for the Windows application.
* Parameters:
* HINSTANCE hInstance - Handle to application instance.
* HINSTANCE hPrevInstance - Handle to previous instance (not used).
* LPSTR lpCmdLine - Command line arguments (not used).
* int nCmdShow - How the application window should be shown.
* Returns:
* int - Application exit code.
* ================================================================== */
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
const wchar_t CLASS_NAME[] = L"BouncingBallWindow";
WNDCLASS wc = {0};
wc.lpfnWndProc = MainWindowProc;
wc.hInstance = hInstance;
wc.lpszClassName = CLASS_NAME;
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
if (!RegisterClass(&wc)) {
return 0;
}
mainHwnd = CreateWindow(
CLASS_NAME, L"Bouncing Ball Simulation",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
CW_USEDEFAULT, CW_USEDEFAULT,
WIN_WIDTH, WIN_HEIGHT,
NULL, NULL, hInstance, NULL);
if (!mainHwnd) {
return 0;
}
MSG msg = {0};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
最新发布