<>C++ Implementation of matrix meteor shower effect

The source code is here
#include <windows.h> #define ID_TIMER 1 #define STRMAXLEN 25 // The maximum length of a display column #
define STRMINLEN 8 // The minimum length of a display column LRESULT CALLBACK WndProc(HWND, UINT, WPARAM,
LPARAM); // // typedef struct tagCharChain // The whole screen is treated as a display column , This is a two-way list { struct
tagCharChain*prev; // The first element of a linked list TCHAR ch; // A character in a display column struct tagCharChain *next;
// The last element of the linked list }CharChain, *pCharChain; typedef struct tagCharColumn { CharChain *
head, *current, *point; int x, y, iStrLen; // Displays the beginning of the column x,y coordinate ,iStrLen Is the length of this column int
iStopTimes, iMustStopTimes; // The number of times it has stopped and the number of times it has to stop , The number of times that must stop is random }CharColumn, *
pCharColumn; int main(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR
szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT("matrix"); HWND hwnd;
MSG msg; WNDCLASS wndclass; wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.
lpfnWndProc= WndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass
.hInstance = hInstance; wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH
)GetStockObject(BLACK_BRUSH); wndclass.lpszMenuName = NULL; wndclass.
lpszClassName= szAppName; if (!RegisterClass(&wndclass)) { MessageBox(NULL, TEXT
(" This program must run on NT lower !"), szAppName, MB_ICONERROR); return 0; } hwnd = CreateWindow(
szAppName, NULL, WS_DLGFRAME | WS_THICKFRAME | WS_POPUP, 0, 0, GetSystemMetrics(
SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, SW_SHOWMAXIMIZED); // Maximize display UpdateWindow(hwnd); ShowCursor(FALSE
); // Hide mouse cursor srand((int)GetCurrentTime()); // Initialize random number generator while (GetMessage(&msg,
NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } ShowCursor(TRUE)
; // Show mouse cursor return msg.wParam; } TCHAR randomChar() // Random character generating function { return (TCHAR)(
rand() % (126 - 33) + 33); //33 reach 126 between } int init(CharColumn *cc, int cyScreen,
int x) // initialization { int j; cc->iStrLen = rand() % (STRMAXLEN - STRMINLEN) + STRMINLEN
; // Displays the length of the column cc->x = x + 3; // Displays the beginning of the column x coordinate cc->y = rand() % 3 ? rand() % cyScreen
: 0; // Displays the beginning of the column y coordinate cc->iMustStopTimes = rand() % 6; cc->iStopTimes = 0; cc->
head= cc->current = (pCharChain)calloc(cc->iStrLen, sizeof(CharChain)); // Generate display columns
for (j = 0; j < cc->iStrLen - 1; j++) { cc->current->prev = cc->point;
//cc->point The first element of a display column cc->current->ch = '/0'; cc->current->next = cc->current +
1; //cc->current+1 The last element of a display column cc->point = cc->current++; //cc->point =
cc->current; cc->current++; } cc->current->prev = cc->point; // Last node cc->
current->ch = '/0'; cc->current->next = cc->head; cc->head->prev = cc->current;
// The first element of the head node is the last element of the chain cc->current = cc->point = cc->head; //free How much memory do you need current When parameter
cc->head->ch = randomChar(); // Check the chain header Element fill return 0; } LRESULT CALLBACK WndProc
(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { HDC hdc; //ctn
Used to determine whether a display chain is active Go down , If the number of waits exceeds the number of times you have to wait ,ctn It means going down int i, j, temp, ctn;
//j For a display chain in addition to the chain header displayed on the screen y coordinate ,temp Green to black static HDC hdcMem; HFONT hFont; static
HBITMAP hBitmap; static int cxScreen, cyScreen; // The width of the screen height . static int
iFontWidth= 10, iFontHeight = 15, iColumnCount; // The width of the font height , Number of columns static CharColumn
*ccChain; switch (message) { case WM_CREATE: cxScreen = GetSystemMetrics(
SM_CXSCREEN); // Screen width cyScreen = GetSystemMetrics(SM_CYSCREEN); SetTimer(hwnd,
ID_TIMER, 10, NULL); hdc = GetDC(hwnd); hdcMem = CreateCompatibleDC(hdc);
hBitmap= CreateCompatibleBitmap(hdc, cxScreen, cyScreen); SelectObject(hdcMem,
hBitmap); ReleaseDC(hwnd, hdc); // Create font hFont = CreateFont(iFontHeight,
iFontWidth- 5, 0, 0, FW_BOLD, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, DRAFT_QUALITY, FIXED_PITCH | FF_SWISS, TEXT("Fixedsys"));
SelectObject(hdcMem, hFont); DeleteObject(hFont); SetBkMode(hdcMem, TRANSPARENT)
; // Set background mode to transparent iColumnCount = cxScreen / (iFontWidth * 3 / 2); // The number of columns of letters displayed on the screen
ccChain= (pCharColumn)calloc(iColumnCount, sizeof(CharColumn)); for (i = 0; i <
iColumnCount; i++) { init(ccChain + i, cyScreen, (iFontWidth * 3 / 2)*i); }
return 0; case WM_TIMER: hdc = GetDC(hwnd); PatBlt(hdcMem, 0, 0, cxScreen,
cyScreen, BLACKNESS); // Paint the memory device image black for (i = 0; i < iColumnCount; i++) { ctn = (
ccChain+ i)->iStopTimes++ > (ccChain + i)->iMustStopTimes; // (ccChain + i)->
point= (ccChain + i)->head; //point Used to traverse the entire display column // The first character is displayed as white SetTextColor(hdcMem,
RGB(255, 255, 255)); TextOut(hdcMem, (ccChain + i)->x, (ccChain + i)->y, &((
ccChain+ i)->point->ch), 1); j = (ccChain + i)->y; (ccChain + i)->point = (
ccChain+ i)->point->next; // Traverses the entire display column , Display the characters in the display column from bottom to top temp = 0; //temp Green to black
while ((ccChain + i)->point != (ccChain + i)->head && (ccChain + i)->point->ch)
{ SetTextColor(hdcMem, RGB(0, 255 - (255 * (temp++) / (ccChain + i)->iStrLen), 0
)); TextOut(hdcMem, (ccChain + i)->x, j -= iFontHeight, &((ccChain + i)->point->
ch), 1); (ccChain + i)->point = (ccChain + i)->point->next; } if (ctn) (ccChain
+ i)->iStopTimes = 0; else continue; (ccChain + i)->y += iFontHeight;
// Next time it starts to show y coordinate For the current y Coordinates plus The height of a character // If the y Coordinate subtraction The length of the entire display column exceeds the height of the screen if ((ccChain + i)
->y - (ccChain + i)->iStrLen*iFontHeight > cyScreen) { free((ccChain + i)->
current); init(ccChain + i, cyScreen, (iFontWidth * 3 / 2)*i); } // The head of a linked list
This is the first element of the linked list , Because the next time it starts to show It is equivalent to adding an element at the beginning of the entire display column , Then start to show up at the beginning (ccChain + i)->head = (
ccChain+ i)->head->prev; (ccChain + i)->head->ch = randomChar(); } BitBlt(hdc, 0
, 0, cxScreen, cyScreen, hdcMem, 0, 0, SRCCOPY); ReleaseDC(hwnd, hdc); return 0;
case WM_RBUTTONDOWN: KillTimer(hwnd, ID_TIMER); return 0; case WM_RBUTTONUP:
SetTimer(hwnd, ID_TIMER, 10, NULL); return 0; // Dealing with the aftermath case WM_KEYDOWN: case
WM_LBUTTONDOWN: case WM_DESTROY: KillTimer(hwnd, ID_TIMER); DeleteObject(hBitmap
); DeleteDC(hdcMem); for (i = 0; i < iColumnCount; i++) { free((ccChain + i)->
current); } free(ccChain); PostQuitMessage(0); return 0; } return DefWindowProc(
hwnd, message, wParam, lParam); }

Technology