目录
目标
熟悉控制台输出的基本函数
使用控制台实现小球的自由落体模拟
开发环境
本项目在Dev-C++环境下开发
基本函数
头文件
在项目开始之前,我们需要引入几个必要的头文件
#include<stdio.h>
#include<stdbool.h>
#include<conio.h>
#include<Windows.h>
光标定位函数 gotoxy
功能:将控制台光标跳转到指定位置(不是鼠标)
void gotoxy(int x,int y){
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
COORD pos={x,y}; // 坐标位置
SetConsoleCursorPosition(handle,pos); // 设置控制台光标位置
}
使用方法:调用 goto(x, y) 即可将光标移动到控制台 (x, y) 位置处
光标隐藏函数 hideCursor
功能:隐藏控制台中的光标(防止连续输出时光标闪烁)
void hideCursor(){
CONSOLE_CURSOR_INFO cursor_info={1,0}; // 0表示隐藏光标
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
使用方法:在主函数中调用 hideCursor()
以上函数的实现过于高级,无需深入理解记忆,用到时直接复制粘贴即可。
绘制背景和小球
绘制背景
为了模拟小球的自由落体,我们首先需要绘制一个25x25的方形区域作为场景
#define MAX_SIZE 25
void drawBackground(){
for(int x=0;x<MAX_SIZE;x++){
for(int y=0;y<MAX_SIZE;y++){
if(x==0 || x==MAX_SIZE-1 || y==0 || y==MAX_SIZE-1)
printf("墙"); // 可以替换为其他奇奇怪怪的符号
else printf(" "); // 注意这里是两个空格
}
printf("\n");
}
}
绘制小球
接下来,我们在场景中添加一个小球
void drawBall(int x,int y){
gotoxy(2*x,y); // 考虑字符长宽比为2:1,x坐标需乘以2
printf("球");
}
效果
drawBackground( ); drawBall(2, 2);
模拟自由落体
边界检测
我们需要确保小球在运动过程中不会超出预定的边界
bool checkBoundary(double x,double y){
if(x<=0 || x>=MAX_SIZE-1 || y<=0 || y>=MAX_SIZE-1)
return true;
else return false;
}
物理模拟
我们将使用自由落体公式来更新小球的位置,并在控制台中显示其运动轨迹。
设置刷新时间(单位:ms)
#define REFRESH_TIME 0.01;
模拟自由落体
void simulateFreeFall(double x,double y,double vx,double vy,double g){
// x,y: 初始位置 vx,vy:初速度 g:重力加速度
double t = 0; // 时间变量
while(true){
drawBall((int)x,(int)y);
Sleep(REFRESH_TIME*1000);
x = x + vx*t;
y = y + vy*t + 0.5*g*t*t; // 根据物理定律计算x,y
t += REFRESH_TIME; // 时间递增
if(checkBoundary(x,y)){ // 边界检测
getchar();
break;
};
}
}
主函数
最后,我们通过主函数来整合所有功能,并启动模拟过程
int main() {
HideCursor(); // 隐藏光标
drawBackground(); // 绘制背景
simulateFreeFall(1,1,2,0,9.8); // 模拟小球自由落体
return 0;
}
完整代码
以下是经过整合并修改的完整代码
#include<stdio.h>
#include<stdbool.h>
#include<conio.h>
#include<Windows.h>
int MAX_SIZE = 25;
double REFRESH_TIME = 0.01;
void gotoxy(int x,int y){
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
COORD pos = {x,y};
SetConsoleCursorPosition(handle,pos);
}
void hideCursor(){
CONSOLE_CURSOR_INFO cursor_info = {1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
bool checkBoundary(double x,double y){
if(x<=0 || x>=MAX_SIZE-1 || y<=0 || y>=MAX_SIZE-1)
return true;
else return false;
}
void drawBackground(){
gotoxy(0,0);
for(int x=0;x<MAX_SIZE;x++){
for(int y=0;y<MAX_SIZE;y++){
if(checkBoundary((double)x,(double)y)) printf("墙");
else printf(" ");
}
printf("\n");
}
}
void drawBall(int x,int y){
gotoxy(2*x,y);
printf("球");
}
void simulateFreeFall(double x,double y,double vx,double vy,double g){
double t = 0;
while(true){
drawBall((int)x,(int)y);
Sleep(REFRESH_TIME*1000);
x = x + vx*t;
y = y + vy*t + 0.5*g*t*t;
t += REFRESH_TIME;
if(checkBoundary(x,y)){
getchar();
break;
};
}
}
int main(){
double x,y,vx,vy,g;
x=1; y=1; vx=1; vy=0; g=9.8;
//此处可自行修改参数
//printf("画布大小(m):"); scanf("%d",&MAX_SIZE);
//printf("\n刷新时间(s):"); scanf("%lf",&REFRESH_TIME);
//printf("\n初始横坐标(m):"); scanf("%lf",&x);
//printf("\n初始纵坐标(m):"); scanf("%lf",&y);
//printf("\n初始水平速度(m/s):"); scanf("%lf",&vx);
//printf("\n初始竖直速度(m/s):"); scanf("%lf",&vy);
//printf("\n重力加速度(m/s^2):"); scanf("%lf",&g);
getchar();
hideCursor();
drawBackground();
simulateFreeFall(x,y,vx,vy,g);
return 0;
}