📄 deepsea.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 + -