前言
程序,作为人类智慧的结晶,其根源在于我们的学习和创造。当我们深入探索编程的世界,不断学习新的知识和技能,我们的思维会逐渐拓宽,创新的火花也会随之点燃。许多程序,一旦我们理解了它们的运行逻辑和内在机制,就能够模仿并改进,甚至创造出属于自己的新版本。
按钮
近期,《黑神话:悟空》这款游戏以其独特的魅力和深度的游戏性赢得了众多玩家的喜爱。在体验其测试工具的过程中,我被游戏中那些充满设计感的操作按钮深深吸引。与以往我在项目中简单地在窗口中央绘制方块并附上菜单文字的方式相比,这些按钮无疑更加生动、富有吸引力。
因此,我萌生了一个念头:将《黑神话:悟空》中的按钮设计融入到我的项目中。我计划深入研究这些按钮的视觉风格和交互方式,从形状、颜色、动画效果到文字排版,力求在保留原作精髓的基础上,加入自己的创意和理解。
设计
在编程的世界里,我们就像是在撰写一篇关于虚拟世界的作文。每个对象、每个元素都需要我们精心描绘,赋予它们生命和灵魂。就像写作文时,我们会详细描述人物的脸形、眼睛、嘴巴、鼻子等特征,以便读者能够在脑海中清晰地勾勒出这个人物的形象一样,在编程中,我们也需要使用结构体来精确地描述程序中的每一个具体对象。
这里我写了三个按钮,通过鼠标的位置,来确定它的颜色和背景方块,当鼠标在按钮上时,按钮背景为白色渐变色,字体为黑色,否则字体为白色。
源码
///////////////////////////////////////////////////
// 程序名称:按钮
// 编译环境:Mictosoft Visual Studio 2022, EasyX_20200315(beta)
// 作 者:luoyh <2864292458@qq.com>
// 公 众 号:C语言研究
// 最后修改:2024-11-14
//
struct Button
{
int X1; // 左上角
int Y1;
int X2; // 右下角
int Y2;
int size; // 字体大小
LPCTSTR str; // 对应文本
};
Button button1 = { 40, 300, 545, 380, 35, TEXT("开始游戏") };
Button button2 = { 40, 380, 545, 460, 35, TEXT("游戏说明") };
Button button3 = { 40, 460, 545, 540, 35, TEXT("退出") };
void DrawButton(Button button, COLORREF color);
void GradientFill(int left, int top, int right, int bottom, COLORREF startColor, COLORREF endColor);
int RETURN();
int main()
{
initgraph(800, 600);
setbkcolor(BLACK);
cleardevice();
// 绘制三个按钮
DrawButton(button1, WHITE);
DrawButton(button2, WHITE);
DrawButton(button3, WHITE); // 绘制按钮
int NUM = RETURN(); // 鼠标操作
_getch();
}
void DrawButton(Button button, COLORREF color)
{
setbkmode(TRANSPARENT);
if (color == WHITE)
{
settextcolor(color);
}
else
{
GradientFill(button.X1, button.Y1, button.X2, button.Y2, WHITE, BLACK);
settextcolor(color);
}
settextstyle(button.size, 0, _T("楷体"));
outtextxy(button.X1, button.Y1 + 22, button.str);
}
int RETURN()
{
int NUM = 0;
// 定义变量,保存鼠标消息
ExMessage msg;
BeginBatchDraw();
// 游戏的主循环
while (true)
{
while (peekmessage(&msg, EX_MOUSE)) // 如果获取到了消息就执行
{
switch (msg.message)
{
case WM_MOUSEMOVE:
if (msg.x > button1.X1 && msg.x<button1.X2 && msg.y>button1.Y1 && msg.y < button1.Y2)
{
NUM = 1;
}
if (msg.x > button2.X1 && msg.x<button2.X2 && msg.y>button2.Y1 && msg.y < button2.Y2)
{
NUM = 2;
}
if (msg.x > button3.X1 && msg.x<button3.X2 && msg.y>button3.Y1 && msg.y < button3.Y2)
{
NUM = 3;
}
break;
case WM_LBUTTONDOWN:
if (msg.x > button1.X1 && msg.x<button1.X2 && msg.y>button1.X2 && msg.y < button1.Y2)
{
NUM = 4;
}
if (msg.x > button2.X1 && msg.x<button2.X2 && msg.y>button2.X2 && msg.y < button2.Y2)
{
NUM = 5;
}
if (msg.x > button3.X1 && msg.x<button3.X2 && msg.y>button3.X2 && msg.y < button3.Y2)
{
NUM = 6;
}
break;
}
}
FlushBatchDraw();
cleardevice();
switch (NUM)
{
case 0:break;
case 1:
DrawButton(button1, BLACK);
DrawButton(button2, WHITE);
DrawButton(button3, WHITE);
break;
case 2:
DrawButton(button1, WHITE);
DrawButton(button2, BLACK);
DrawButton(button3, WHITE);
break;
case 3:
DrawButton(button1, WHITE);
DrawButton(button2, WHITE);
DrawButton(button3, BLACK);
break;
case 4:return 1; break;
case 5:return 2; break;
case 6:return 3; break;
}
//Sleep(10); // 延时,降低 CPU 占用率
}
EndBatchDraw();
return 0;
}
void GradientFill(int left, int top, int right, int bottom, COLORREF startColor, COLORREF endColor)
{ // 计算水平和垂直方向上的颜色变化量
double dx = right - left;
double dy = bottom - top;
double redStep = (GetRValue(endColor) - GetRValue(startColor)) / dx;
double greenStep = (GetGValue(endColor) - GetGValue(startColor)) / dx;
double blueStep = (GetBValue(endColor) - GetBValue(startColor)) / dx; // 遍历每个像素点,并设置其颜色
for (int x = left; x <= right; x++)
{
COLORREF currentColor = RGB(GetRValue(startColor) + (x - left) * redStep, GetGValue(startColor) + (x - left) * greenStep, GetBValue(startColor) + (x - left) * blueStep);
setfillcolor(currentColor); solidrectangle(x, top, x, bottom); // 填充当前列的颜色
}
}
动态效果