⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 deepsea.cpp

📁 用C++编写的屏幕保护程序源码源码
💻 CPP
字号:
//             _____________________________________
//            |                                     |
//            |               文件描述              |
// ___________|_____________________________________|___________
//
// 文件名:DeepSea.cpp
// 作者:阿卓
// 内容:深海生物屏幕保护程序源代码
// 声明:本文件及其相关文档内容可以自由使用、修改和传播,并可用
//       于任何商业和非商业目的。对于使用本文件及其相关文档内容
//       而产生的任何后果,作者概不负责。
//
// 技术要点之一:
//     展示了屏幕保护程序框架结构。
//     该程序使用了VC自带的屏幕保护程序开发库scrnsave.lib,它提供
//     了屏幕保护程序的基本支撑环境,设计者只需要实现这几个函数:
//
//     BOOL WINAPI ScreenSaverProc(
//                 HWND hWnd, 
//                 UINT message, 
//                 WPARAM wParam, 
//                 LPARAM lParam);
//
//     BOOL WINAPI ScreenSaverConfigureDialog(
//                 HWND hDlg, 
//                 UINT message, 
//                 WPARAM wParam, 
//                 LPARAM lParam);
//
//     BOOL WINAPI RegisterDialogClasses(
//                 HANDLE hInst);
//
//     和准备这些资源(ID是预先定义在scrnsave.h中的,必须在
//     resource.h中加入#include <scrnsave.h>和删除重复的ID):
//
//     DLG_SCRNSAVECONFIGURE  对话框资源
//     ID_APP                 程序图标资源
//     IDS_DESCRIPTION        程序描述字符串资源
//
// 技术要点之二:
//     深海生物图形的生成是在一个现成的艺术图形算法上修改而来,原
//     算法来自于一本很老的书叫《BASIC艺术图形程序设计》,在图书
//     馆找到的:-)
//
// 当前版本:v1.1
// 最后更新日期:11/10/2001
//
// 版本历史:
// v1.0
//     能产生一个生物,设置对话框是对生物的变色和形状进行控制。
// v1.1
//     能产生多个生物,设置对话框改为对生物的数量进行控制,取消了
//     对生物形状进行控制的属性。绘制改位逻辑坐标方式,修正了预览
//     屏保时显示比例失调的问题。修正了其它的一些BUG,增加了详细
//     注释。
//
// _______________________文件描述结束__________________________


// 这是程序需要的头文件
#include <windows.h>
#include <commctrl.h>
#include <scrnsave.h>
#include <math.h>

#include "resource.h"

#define PI				3.14159
// 缺省状态下只产生3个生物
#define	DEFAULT_NUM		3
// 对多能产生30个生物
#define MAX_CREATURES	30
#define MAX_LINES		300
#define TIMER_ID		1
// 帧速率控制在20FPS以下
#define TIMER_DELAY		50

// 存取注册表时要用到的一些存储缓冲区
CHAR	szTemp[20];
CHAR	szCreatureNum[] = "Creature Num";

// 初始化生物数量为缺省值
int		CreatureNum = DEFAULT_NUM;

// 描述屏幕区域
RECT	ScreenRect;

// 绘制时要使用的一些句柄
HDC		hDC;
HPEN	hPen, hOldPen, hBlackPen;

// 定义描述生物的数据结构
typedef struct _Creature
{
	COLORREF	Color;
	int			x, y;
	int			dx, dy;
	double		a1, a2, a3, a4;
	double		d1, d2, d3, d4;
	int			nLines;
	int			Lines[MAX_LINES][4];
} Creature;

// 创建生物实体数组
Creature	Creatures[MAX_CREATURES];

//      __________________
// ____|  DrawCreature()  |_____________________________________
// 功能:绘制一个生物
// 参数详解:
// Creature *ptr
//     指向一个生物实体的指针
// 返回值:无返回值
// _____________________________________________________________
void DrawCreature(Creature *ptr)
{
	double	a, d, e, l, m, o, p;
	double	x1, y1, x2, y2;

	d = 150.0;
	e = 50.0;

	// 参数变换
	ptr->a1 = ptr->a1 + ptr->d1;
	if(ptr->a1 > 20.0 * 1.0) {
		ptr->a1 = 20.0 * 1.0;
		ptr->d1 = -0.2;
		ptr->d2 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d3 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d4 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	if(ptr->a1 < 1.0 * 1.0) {
		ptr->a1 = 1.0 * 1.0;
		ptr->d1 = 0.2;
		ptr->d2 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d3 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d4 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	ptr->a2 = ptr->a2 + ptr->d2;
	if(ptr->a2 > 20.0 * 1.0) {
		ptr->a2 = 20.0 * 1.0;
		ptr->d2 = -0.2;
		ptr->d1 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d3 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d4 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	if(ptr->a2 < 1.0 * 1.0) {
		ptr->a2 = 1.0 * 1.0;
		ptr->d2 = 0.2;
		ptr->d1 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d3 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d4 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	ptr->a3 = ptr->a3 + ptr->d3;
	if(ptr->a3 > 20.0 * 1.0) {
		ptr->a3 = 20.0 * 1.0;
		ptr->d3 = -0.2;
		ptr->d2 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d1 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d4 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	if(ptr->a3 < 1.0 * 1.0) {
		ptr->a3 = 1.0 * 1.0;
		ptr->d3 = 0.2;
		ptr->d2 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d1 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d4 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	ptr->a4 = ptr->a4 + ptr->d4;
	if(ptr->a4 > 20.0 * 1.0) {
		ptr->a4 = 20.0 * 1.0;
		ptr->d4 = -0.2;
		ptr->d2 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d3 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d1 = ((rand() % 2) ? -1 : 1) * 0.2;
	}
	if(ptr->a4 < 1.0 * 1.0) {
		ptr->a4 = 1.0 * 1.0;
		ptr->d4 = 0.2;
		ptr->d2 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d3 = ((rand() % 2) ? -1 : 1) * 0.2;
		ptr->d1 = ((rand() % 2) ? -1 : 1) * 0.2;
	}

	// 反弹处理
	ptr->x += ptr->dx;
	if(ptr->x >= ScreenRect.right) {
		ptr->x = ScreenRect.right;
		do {
			ptr->dx = -1 * rand() % 5;
			ptr->dy = ((rand() % 2) ? -1 : 1) * (rand() % 5);
		} while(!ptr->dx && !ptr->dy);
	}
	if(ptr->x <= ScreenRect.left) {
		ptr->x = ScreenRect.left;
		do {
			ptr->dx = rand() % 5;
			ptr->dy = ((rand() % 2) ? -1 : 1) * (rand() % 5);
		} while(!ptr->dx && !ptr->dy);
	}

	ptr->y += ptr->dy;
	if(ptr->y >= ScreenRect.bottom) {
		ptr->y = ScreenRect.bottom;
		do {
			ptr->dy = -1 * rand() % 5;
			ptr->dx = ((rand() % 2) ? -1 : 1) * (rand() % 5);
		} while(!ptr->dx && !ptr->dy);
	}
	if(ptr->y <= ScreenRect.top) {
		ptr->y = ScreenRect.top;
		do {
			ptr->dy = rand() % 5;
			ptr->dx = ((rand() % 2) ? -1 : 1) * (rand() % 5);
		} while(!ptr->dx && !ptr->dy);
	}

	// 创建画笔
	hPen = CreatePen(PS_SOLID, 0, ptr->Color);
	hOldPen = (HPEN)SelectObject(hDC, hPen);

	ptr->nLines = 0;
	for(a = 0.0; a < 2.0 * PI; a = a + PI / 120.0) {
		// 计算每条线的两个端点
		l = d + d / 2.0 * (1.0 + 1.0 / 2.0 * cos(ptr->a1 * a)) * cos(a);
		x1 = ptr->x * 1.0 + l * cos(a);
		m = e + e / 3.0 * (1.0 + 1.0 / 2.0 * sin(ptr->a2 * a)) * cos(a);
		x2 = ptr->x * 1.0 + m * cos(a);

		o = d + d / 3.0 * (1.0 + 1.0 / 2.0 * cos(ptr->a3 * a)) * sin(a);
		y1 = ptr->y * 1.0 - o * sin(a) / 2.0;
		p = e + e / 2.0 * (1.0 + 1.0 / 2.0 * cos(ptr->a4 * a)) * sin(a);
		y2 = ptr->y * 1.0 - p * sin(a) / 2.0;

		if(!(!ptr->Lines[ptr->nLines][0] && !ptr->Lines[ptr->nLines][1] && 
			!ptr->Lines[ptr->nLines][2] && !ptr->Lines[ptr->nLines][3])) {
			// 擦去上次画的线
			SelectObject(hDC, hBlackPen);
			MoveToEx(hDC, ptr->Lines[ptr->nLines][0], ptr->Lines[ptr->nLines][1], NULL);
			LineTo(hDC, ptr->Lines[ptr->nLines][2], ptr->Lines[ptr->nLines][3]);
			SelectObject(hDC, hPen);
		}
		if(ptr->nLines > 0) {
			// 画上新的线
			MoveToEx(hDC, ptr->Lines[ptr->nLines - 1][0], ptr->Lines[ptr->nLines - 1][1], NULL);
			LineTo(hDC, ptr->Lines[ptr->nLines - 1][2], ptr->Lines[ptr->nLines - 1][3]);
		}
		// 记录刚才画的线的位置
		ptr->Lines[ptr->nLines][0] = (int)x1;
		ptr->Lines[ptr->nLines][1] = (int)y1;
		ptr->Lines[ptr->nLines][2] = (int)x2;
		ptr->Lines[ptr->nLines][3] = (int)y2;
		MoveToEx(hDC, ptr->Lines[ptr->nLines][0], ptr->Lines[ptr->nLines][1], NULL);
		LineTo(hDC, ptr->Lines[ptr->nLines][2], ptr->Lines[ptr->nLines][3]);
		ptr->nLines ++;
	}

	// 销毁画笔,释放GDI资源
	SelectObject(hDC, hOldPen);
	DeleteObject(hPen);
}
// _____End of DrawCreature()___________________________________

//      _____________________
// ____|  ScreenSaverProc()  |__________________________________
// 功能:屏幕保护的主体部分 - 屏幕保护窗口函数
// 参数详解:
// HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam
//     不用多说了吧?窗口函数典型的参数序列
// 返回值:
//     TRUE - 表明我已经处理了这个消息
//     FALSE - 表明我没有处理这个消息
//     其它 - 由缺省消息处理函数返回的值
// _____________________________________________________________
LRESULT CALLBACK ScreenSaverProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HKEY	hKey;
	DWORD	Type, Size;
	int		i;

	switch (message) {
	case WM_CREATE:
		srand(GetTickCount());

		// 从注册表中获取屏幕保护程序的设置信息
		RegCreateKey(HKEY_CURRENT_USER, "Software\\DeepSea", &hKey);
		Size = 3;
		RegQueryValueEx(hKey, szCreatureNum, NULL, &Type, (BYTE *)&szTemp, &Size);
		CreatureNum = atoi(szTemp);
		RegCloseKey(hKey);

		if(!CreatureNum) {
			CreatureNum = DEFAULT_NUM;
		}

		// 创建一个计时器
		SetTimer(hWnd, TIMER_ID, TIMER_DELAY, NULL);

		// 处理其它的初始化工作
		GetClientRect(hWnd, &ScreenRect);
		hDC = GetDC(hWnd);
		SetMapMode(hDC, MM_ANISOTROPIC);
		SetWindowExtEx(hDC, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL);
		SetViewportExtEx(hDC, ScreenRect.right, ScreenRect.bottom, NULL);
		ScreenRect.right = GetSystemMetrics(SM_CXSCREEN);
		ScreenRect.bottom = GetSystemMetrics(SM_CYSCREEN);

		hBlackPen = CreatePen(PS_SOLID, 0, RGB(0, 0, 0));

		for(i = 0; i < CreatureNum && i < MAX_CREATURES; i ++)
		{
			ZeroMemory(&Creatures[i], sizeof(Creatures[i]));

			Creatures[i].Color = RGB(rand() % 0xff, rand() % 0xff, rand() % 0xff);
			Creatures[i].x = ScreenRect.left + (ScreenRect.right - ScreenRect.left) / 2;
			Creatures[i].y = ScreenRect.top + (ScreenRect.bottom - ScreenRect.top) / 2;
			Creatures[i].a1 = Creatures[i].a2 = Creatures[i].a3 = Creatures[i].a4 = 10.0;
			Creatures[i].d1 = ((rand() % 2) ? -1 : 1) * 0.2;
			Creatures[i].d2 = ((rand() % 2) ? -1 : 1) * 0.2;
			Creatures[i].d3 = ((rand() % 2) ? -1 : 1) * 0.2;
			Creatures[i].d4 = ((rand() % 2) ? -1 : 1) * 0.2;

			do {
				Creatures[i].dx = ((rand() % 2) ? -1 : 1) * (rand() % 5);
				Creatures[i].dy = ((rand() % 2) ? -1 : 1) * (rand() % 5);
			} while(!Creatures[i].dx && !Creatures[i].dy);
		}

		return TRUE;

	case WM_TIMER:
		// 绘制
		for(i = 0; i < CreatureNum && i < MAX_CREATURES; i ++)
			DrawCreature(&Creatures[i]);

		return TRUE;

	case WM_DESTROY:
		// 处理其它销毁工作
		ReleaseDC(hWnd, hDC);

		// 销毁计时器
		KillTimer(hWnd, TIMER_ID);
		srand(1);

		return TRUE;

	default:
		// 不敢兴趣的消息留给缺省的消息处理函数处理
		return DefScreenSaverProc(hWnd,message,wParam,lParam);
	}

	return FALSE;
}
// _____End of ScreenSaverProc()________________________________

//      ________________________________
// ____|  ScreenSaverConfigureDialog()  |_______________________
// 功能:屏幕保护设置对话框的窗口函数。当在WINDOWS屏保选择面板里
//       点击这个屏保的“设置”按钮,或者鼠标右键单击这个屏保程
//       序,选择“配置”后,系统将显示你准备好的对话框,而这个函
//       数就是屏这个话框的窗口函数。
// 参数详解:
// HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam
//     不用多说了吧?窗口函数典型的参数序列
// 返回值:
//     TRUE - 表明我已经处理了这个消息
//     FALSE - 表明我没有处理这个消息,由缺省的对话框消息处理函数
//             处理
// _____________________________________________________________
BOOL WINAPI ScreenSaverConfigureDialog(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
	BOOL	bErr;
	HKEY	hKey;
	DWORD	Type, Size;

	switch (message) {
	case WM_INITDIALOG:
		// 创建设置对话框并初始化各控件值
		SendMessage(GetDlgItem(hDlg, IDC_CREATURE_NUM_SPIN), UDM_SETRANGE, 0, MAKELONG(30, 1));

		RegCreateKey(HKEY_CURRENT_USER, "Software\\DeepSea", &hKey);
		Size = 3;
		RegQueryValueEx(hKey, szCreatureNum, NULL, &Type, (BYTE *)&szTemp, &Size);
		CreatureNum = atoi(szTemp);
		RegCloseKey(hKey);

		if(!CreatureNum) {
			CreatureNum = DEFAULT_NUM;
			RegCreateKey(HKEY_CURRENT_USER, "Software\\DeepSea", &hKey);
			wsprintf(szTemp, "%ld", CreatureNum);
			RegSetValueEx(hKey,	szCreatureNum, 0, REG_SZ, (BYTE *)szTemp, strlen(szTemp) + 1);
			RegCloseKey(hKey);
		}

		SetDlgItemInt(hDlg, IDC_CREATURE_NUM, CreatureNum, TRUE);

		return TRUE;

	case WM_COMMAND:
		if (LOWORD(wParam) == IDOK) {
			// 将用户的输入保存到注册表中
			CreatureNum = GetDlgItemInt(hDlg, IDC_CREATURE_NUM, &bErr, TRUE);

			RegCreateKey(HKEY_CURRENT_USER, "Software\\DeepSea", &hKey);
			wsprintf(szTemp, "%ld", CreatureNum);
			RegSetValueEx(hKey,	szCreatureNum, 0, REG_SZ, (BYTE *)szTemp, strlen(szTemp) + 1);
			RegCloseKey(hKey);

			EndDialog(hDlg, LOWORD(wParam));
			return TRUE;
		}else if(LOWORD(wParam) == IDCANCEL) {
			EndDialog(hDlg, LOWORD(wParam));
			return TRUE;
		}

		break;
	}

	return FALSE;
}
// _____End of ScreenSaverConfigureDialog()_____________________

//      ___________________________
// ____|  RegisterDialogClasses()  |____________________________
// 功能:注册用于屏幕保护设置对话框的特殊窗口类或自定义窗口类。
//       如果设计的屏幕保护设置对话框需要注册特殊窗口类或自定义窗
//       口类,就在这里注册,在创建对话框之前,系统会先调用这个函
//       数。这里,我的程序需要comctl32公用控件的支持(Spin控件),
//       所以我在这里调用了InitCommonControls()函数来注册。
// 参数详解:
// HANDLE hInst
//     应用程序实例的句柄,系统调用时自己传递的,大可不必去管它。
// 返回值:
//     TRUE - 表明注册成功
//     FALSE - 表明注册失败
// _____________________________________________________________
BOOL WINAPI RegisterDialogClasses(HANDLE hInst)
{
	// 这里注册特殊窗口类或自定义窗口类
	// 这个程序需要注册comctl32控件
	InitCommonControls();

	return TRUE;
}
// _____End of RegisterDialogClasses()__________________________

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -