添加bgm

This commit is contained in:
2026-04-26 11:39:50 +08:00
parent e80dd15ebf
commit 295dba8bd7
6 changed files with 295 additions and 0 deletions
Binary file not shown.
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 573 KiB

+1
View File
@@ -171,6 +171,7 @@ extern int tScore;
extern bool gameOverFlag;
extern bool suspendFlag;
extern bool targetFlag;
extern bool bgmEnabled;
extern int workRegion[20][10];
extern Point point;
extern Point target;
+244
View File
@@ -1,5 +1,6 @@
#include "stdafx.h"
#include "Tetris.h"
#include <string>
#define MAX_LOADSTRING 100
#define GAME_TIMER_ID 1
@@ -8,6 +9,11 @@
HINSTANCE hInst;
TCHAR szTitle[MAX_LOADSTRING];
TCHAR szWindowClass[MAX_LOADSTRING];
bool bgmEnabled = true;
static bool bgmPlaying = false;
static bool bgmUsingMci = false;
static constexpr const wchar_t* kBgmAlias = L"TereisBgm";
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
@@ -20,6 +26,229 @@ static void ResetGameTimer(HWND hWnd)
SetTimer(hWnd, GAME_TIMER_ID, currentFallInterval > 0 ? currentFallInterval : GAME_TIMER_INTERVAL, nullptr);
}
static std::wstring BuildAssetPath(const wchar_t* relativePath)
{
wchar_t modulePath[MAX_PATH] = {};
GetModuleFileNameW(nullptr, modulePath, MAX_PATH);
std::wstring basePath(modulePath);
size_t lastSlash = basePath.find_last_of(L"\\/");
if (lastSlash != std::wstring::npos)
{
basePath.resize(lastSlash);
}
std::wstring projectRelative = basePath + L"\\..\\..\\" + relativePath;
wchar_t fullPath[MAX_PATH] = {};
DWORD result = GetFullPathNameW(projectRelative.c_str(), MAX_PATH, fullPath, nullptr);
if (result > 0 && result < MAX_PATH)
{
return fullPath;
}
return projectRelative;
}
static std::wstring BuildWorkingDirAssetPath(const wchar_t* relativePath)
{
wchar_t currentDirectory[MAX_PATH] = {};
DWORD length = GetCurrentDirectoryW(MAX_PATH, currentDirectory);
if (length == 0 || length >= MAX_PATH)
{
return L"";
}
std::wstring candidate = std::wstring(currentDirectory) + L"\\" + relativePath;
wchar_t fullPath[MAX_PATH] = {};
DWORD result = GetFullPathNameW(candidate.c_str(), MAX_PATH, fullPath, nullptr);
if (result > 0 && result < MAX_PATH)
{
return fullPath;
}
return candidate;
}
static bool FileExists(const std::wstring& path)
{
DWORD attributes = GetFileAttributesW(path.c_str());
return attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
}
static RECT GetMusicButtonRect(HWND hWnd)
{
RECT clientRect;
GetClientRect(hWnd, &clientRect);
int clientWidth = clientRect.right - clientRect.left;
int clientHeight = clientRect.bottom - clientRect.top;
int scaleX = MulDiv(clientWidth, 1000, WINDOW_CLIENT_WIDTH);
int scaleY = MulDiv(clientHeight, 1000, WINDOW_CLIENT_HEIGHT);
int scale = (scaleX < scaleY) ? scaleX : scaleY;
if (scale < 500)
{
scale = 500;
}
int layoutWidth = MulDiv(WINDOW_CLIENT_WIDTH, scale, 1000);
int offsetX = (clientWidth - layoutWidth) / 2;
int offsetY = 0;
int size = MulDiv(28, scale, 1000);
if (size < 22)
{
size = 22;
}
int marginRight = MulDiv(12, scale, 1000);
if (marginRight < 6)
{
marginRight = 6;
}
int marginBottom = MulDiv(12, scale, 1000);
if (marginBottom < 6)
{
marginBottom = 6;
}
RECT buttonRect =
{
offsetX + layoutWidth - marginRight - size,
offsetY + MulDiv(WINDOW_CLIENT_HEIGHT, scale, 1000) - marginBottom - size,
offsetX + layoutWidth - marginRight,
offsetY + MulDiv(WINDOW_CLIENT_HEIGHT, scale, 1000) - marginBottom
};
return buttonRect;
}
static bool IsPointInRect(const RECT& rect, int x, int y)
{
return x >= rect.left && x < rect.right && y >= rect.top && y < rect.bottom;
}
static bool TryPlayMciLoop(const std::wstring& path, bool forceMpegVideo)
{
if (!FileExists(path))
{
return false;
}
mciSendStringW((std::wstring(L"close ") + kBgmAlias).c_str(), nullptr, 0, nullptr);
std::wstring openCommand = L"open \"" + path + L"\" ";
if (forceMpegVideo)
{
openCommand += L"type mpegvideo ";
}
openCommand += L"alias ";
openCommand += kBgmAlias;
if (mciSendStringW(openCommand.c_str(), nullptr, 0, nullptr) != 0)
{
return false;
}
std::wstring playCommand = std::wstring(L"play ") + kBgmAlias + L" repeat";
if (mciSendStringW(playCommand.c_str(), nullptr, 0, nullptr) != 0)
{
mciSendStringW((std::wstring(L"close ") + kBgmAlias).c_str(), nullptr, 0, nullptr);
return false;
}
bgmPlaying = true;
bgmUsingMci = true;
return true;
}
static void StopBackgroundMusic()
{
if (bgmUsingMci)
{
mciSendStringW((std::wstring(L"stop ") + kBgmAlias).c_str(), nullptr, 0, nullptr);
mciSendStringW((std::wstring(L"close ") + kBgmAlias).c_str(), nullptr, 0, nullptr);
}
else
{
PlaySoundW(nullptr, nullptr, 0);
}
bgmPlaying = false;
bgmUsingMci = false;
}
static void StartBackgroundMusic()
{
if (!bgmEnabled || bgmPlaying)
{
return;
}
const wchar_t* bgmWavRelativePath = L"assets\\audio\\bgm.wav";
const std::wstring bgmWavCandidates[] =
{
BuildAssetPath(bgmWavRelativePath),
BuildWorkingDirAssetPath(bgmWavRelativePath)
};
for (const std::wstring& candidate : bgmWavCandidates)
{
if (FileExists(candidate) &&
PlaySoundW(candidate.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_LOOP))
{
bgmPlaying = true;
bgmUsingMci = false;
return;
}
}
const wchar_t* oggRelativePath = L"assets\\audio\\bgm.ogg";
const std::wstring oggCandidates[] =
{
BuildAssetPath(oggRelativePath),
BuildWorkingDirAssetPath(oggRelativePath)
};
for (const std::wstring& candidate : oggCandidates)
{
if (TryPlayMciLoop(candidate, false) || TryPlayMciLoop(candidate, true))
{
return;
}
}
const wchar_t* fallbackWavRelativePath = L"assets\\audio\\background.wav";
const std::wstring fallbackWavCandidates[] =
{
BuildAssetPath(fallbackWavRelativePath),
BuildWorkingDirAssetPath(fallbackWavRelativePath)
};
for (const std::wstring& candidate : fallbackWavCandidates)
{
if (FileExists(candidate) &&
PlaySoundW(candidate.c_str(), nullptr, SND_FILENAME | SND_ASYNC | SND_LOOP))
{
bgmPlaying = true;
bgmUsingMci = false;
return;
}
}
bgmEnabled = false;
}
static void ToggleBackgroundMusic(HWND hWnd)
{
bgmEnabled = !bgmEnabled;
if (bgmEnabled)
{
StartBackgroundMusic();
}
else
{
StopBackgroundMusic();
}
InvalidateRect(hWnd, nullptr, FALSE);
}
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
@@ -124,6 +353,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_CREATE:
srand((unsigned int)time(nullptr));
ReturnToMainMenu();
StartBackgroundMusic();
ResetGameTimer(hWnd);
InvalidateRect(hWnd, nullptr, FALSE);
break;
@@ -295,6 +525,19 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
case WM_SIZE:
InvalidateRect(hWnd, nullptr, FALSE);
break;
case WM_LBUTTONUP:
{
int mouseX = static_cast<short>(LOWORD(lParam));
int mouseY = static_cast<short>(HIWORD(lParam));
RECT musicButtonRect = GetMusicButtonRect(hWnd);
if (IsPointInRect(musicButtonRect, mouseX, mouseY))
{
ToggleBackgroundMusic(hWnd);
break;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
case WM_KEYDOWN:
if (currentScreen == SCREEN_MENU)
{
@@ -580,6 +823,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
break;
case WM_DESTROY:
KillTimer(hWnd, GAME_TIMER_ID);
StopBackgroundMusic();
PostQuitMessage(0);
break;
default:
+50
View File
@@ -302,6 +302,52 @@ void TDrawScreen(HDC hdc, HWND hWnd)
DeleteObject(localAccentPen);
};
auto DrawMusicButton = [&]()
{
RECT musicButtonRect =
{
SX(WINDOW_CLIENT_WIDTH - 40),
SY(WINDOW_CLIENT_HEIGHT - 40),
SX(WINDOW_CLIENT_WIDTH - 12),
SY(WINDOW_CLIENT_HEIGHT - 12)
};
DrawPanelCardAlpha(
musicButtonRect,
bgmEnabled ? RGB(255, 238, 246) : RGB(244, 236, 240),
bgmEnabled ? RGB(222, 130, 166) : RGB(170, 148, 158),
12,
bgmEnabled ? 218 : 190);
HPEN musicPen = CreatePen(PS_SOLID, SS(3), bgmEnabled ? RGB(128, 70, 100) : RGB(128, 112, 120));
HPEN oldMusicPen = (HPEN)SelectObject(hdc, musicPen);
HBRUSH oldMusicBrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
int noteStemX = musicButtonRect.left + SS(17);
int noteTop = musicButtonRect.top + SS(7);
int noteBottom = musicButtonRect.bottom - SS(9);
MoveToEx(hdc, noteStemX, noteTop, nullptr);
LineTo(hdc, noteStemX, noteBottom);
MoveToEx(hdc, noteStemX, noteTop, nullptr);
LineTo(hdc, musicButtonRect.right - SS(7), noteTop + SS(4));
LineTo(hdc, musicButtonRect.right - SS(7), noteTop + SS(10));
Ellipse(
hdc,
musicButtonRect.left + SS(7),
musicButtonRect.bottom - SS(13),
musicButtonRect.left + SS(19),
musicButtonRect.bottom - SS(4));
if (!bgmEnabled)
{
MoveToEx(hdc, musicButtonRect.left + SS(7), musicButtonRect.bottom - SS(7), nullptr);
LineTo(hdc, musicButtonRect.right - SS(6), musicButtonRect.top + SS(6));
}
SelectObject(hdc, oldMusicBrush);
SelectObject(hdc, oldMusicPen);
DeleteObject(musicPen);
};
if (currentScreen == SCREEN_MENU)
{
RECT menuCard =
@@ -418,6 +464,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
SetTextColor(hdc, RGB(128, 104, 118));
DrawText(hdc, _T("\u65b9\u5411\u952e / WASD \u5207\u6362\uff0cEnter \u6216 Space \u786e\u8ba4\uff0cEsc \u9000\u51fa"), -1, &hintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawMusicButton();
SelectObject(hdc, oldFont);
DeleteObject(titleFont);
DeleteObject(sectionFont);
@@ -557,6 +604,7 @@ void TDrawScreen(HDC hdc, HWND hWnd)
};
DrawText(hdc, _T("Esc / Backspace / M \u8fd4\u56de\u4e3b\u83dc\u5355"), -1, &backHintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
DrawMusicButton();
SelectObject(hdc, oldFont);
DeleteObject(titleFont);
DeleteObject(sectionFont);
@@ -1765,6 +1813,8 @@ void TDrawScreen(HDC hdc, HWND hWnd)
DrawText(hdc, _T("W/A/S/D \u6216\u65b9\u5411\u952e\u5207\u6362\uff0cEnter \u6216 Space \u786e\u8ba4"), -1, &hintRect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
DrawMusicButton();
SelectObject(hdc, oldFont);
DeleteObject(titleFont);
DeleteObject(sectionFont);