星系模拟器开发日志(一) 如何科学地用C++画图

代码下载地址:

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;
}


这是动态绘制上述抛物线的程序。

注意,每一帧绘制完成后我没有清屏,这意味着它将绘制出整条轨迹。

画到一半的效果图:



发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注