代码下载地址:
2015.8.11更新:
最近突然有一个想法:写一个程序,用来模拟太阳系的行星运动,甚至是任意星球的运动。感觉这个想法非常excited,所以就准备开始写。程序的名字就叫“星系模拟器”吧,或者也可以称作“拉普拉斯的长者?”,英文名Solar Simulator
为了避免写完后过一个月看不懂代码的悲剧重演,我准备把整个开发过程都记在这里。
工具:
①一只NOIP选手
②一台电脑
③稍有的物理学常识
2015.8.13更新:
首先说一下思路。
①每个物体都是一个质点,只考虑万有引力
②先假设所有物体都在二维平面上运动,三维的以后再说
③每个物体都用一个小点表示
④怎么模拟运动呢?最早想的是能不能用方程,然后我突然想到“三体问题没有解析解”这回事……果断大模拟
先解决“在屏幕上显示图形”这回事。毕竟作为一只NOIP选手,我以前写过的都是“黑白屏幕的傻X程序”。
先找了半天,找了两个备选方案:一是按着《C++图形与游戏编程基础》用Dark GDK,但它只兼容vs2008,而且功能非常受限。二是用DirectX,但找了找教程发现相当于学习windows编程,上来就给一堆乱码般的函数和类名跪了,写个显示亮点的小程序我至于吗我……
后来经光神指点,找到一个好东西:Easy Graphics Engine(EGE),主页http://tcgraphics.sourceforge.net/,在VS2015下的安装教程见http://www.jianshu.com/p/b12163e5a0b7
环境已备好(VS2015 Community+EGE),可以开始了。
EGE的函数名称啥的都很直白,我也不介绍了,主页里写的非常清楚。先写个“画东西”的小程序压压惊吧:
#include "stdafx.h" #include#include #include #include #include #include using namespace std; int main() { //初始化一个200*200的图像区域 initgraph(200, 200); //设置绘图颜色 setcolor(WHITE); //画空心圆 circle(100, 100, 3); //设置填充颜色 setfillcolor(WHITE); //填充圆 floodfill(100, 100,WHITE); //等待按任意键 getch(); //关闭图像 closegraph(); return 0; }
效果图:
我们将用这样的“亮点”表示物体,当然屏幕肯定比200*200大。
EGE中,坐标(x,y)代表距离左边x,距离上边y,不要搞反了
EGE还可以画像素。画一个抛物线作为练习:
#include "stdafx.h" #include#include #include #include #include #include using namespace std; #pragma warning(disable:4996)//无视掉freopen的警告 const int gsize = 600; int main() { //打开图像 initgraph(gsize, gsize); //绘图 for (float x = 0, y = 0 ; y < gsize ; x+=0.001, y = x*x/500) { putpixel(int(x+0.5), int(y+0.5), WHITE);//画像素 } //关闭图像 getch(); closegraph(); return 0; }
方程y=x^2/500
效果图:
接下来该画动图了。按照EGE官网上的教程,写了一个画动图的程序:
#include "stdafx.h" #include#include #include #include #include #include using namespace std; #pragma warning(disable:4996)//无视掉freopen的警告 void mainloop()//主循环 { //将线条和填充颜色设为白色 setcolor(WHITE); setfillcolor(WHITE); float x = 0, y = 0; for (; is_run(); delay_fps(60))//每秒60帧 { //cleardevice();//清屏 y = x*x / 500.0; fillellipsef(x, y, 3, 3);//画以(x,y)为中心,长短轴均为3的椭圆 x += 1.0;//更新x } } int main(void) { //设置初始化图形,差不多就是默认 setinitmode(INIT_DEFAULT | INIT_NOFORCEEXIT); //初始化窗口 initgraph(600, 600); //初始化随机种子 randomize(); //设置更新窗口模式,为手动模式 setrendermode(RENDER_MANUAL); //主循环 mainloop(); //关闭窗口 closegraph(); return 0; }
这是动态绘制上述抛物线的程序。
注意,每一帧绘制完成后我没有清屏,这意味着它将绘制出整条轨迹。
画到一半的效果图: