本項目已開源:https://github.com/wmpscc/AvoidBlankhtml
簡單示例git
#include <graphics.h> int main() { //初始化爲640*480大小 initgraph(640, 480); //等待用戶按鍵 getch(); //關閉圖形界面 closegraph(); return 0; }
開始以前先介紹一下相關點。github
本篇文章假定你已經準備好遊戲每一個按鍵對應的音頻文件和遊戲關卡的歌詞按鍵譜。windows
setinitmode(RENDER_MANUAL); //設置窗口模式api
功能:
這個函數用於設置初始化圖形的選項和模式。數組聲明:
void setinitmode(int mode, int x = CW_USEDEFAULT, int y = CW_USEDEFAULT);app參數:
mode
初始化模式,是二進制組合的值。若是爲INIT_DEFAULT 表示使用默認值。
可使用的值的組合:
INIT_NOBORDER 爲無邊框窗口
INIT_CHILD 爲子窗口(須要使用attachHWND指定要依附的父窗口,此函數不另說明)
INIT_TOPMOST 使窗口總在最前
INIT_RENDERMANUAL 手動更新標誌,即調用delay_fps/delay_ms等會等待操做的函數時會更新窗口,不然保持窗口內容
INIT_WITHLOGO 使initgraph的時候顯示開場動畫logo
INIT_NOFORCEEXIT 使關閉窗口的時候不強制退出程序,但窗口會消失,須要配合is_run函數
INIT_DEFAULT 默認參數,不調用本函數時即便用此參數
INIT_ANIMATION 是INIT_DEFAULT, INIT_RENDERMANUAL, INIT_NOFORCEEXIT的組合,用於動畫編寫domx, y
初始化時窗口左上角在屏幕的座標,默認爲系統分配。異步返回值:
(無)函數說明:
本函數只能在initgraph前調用。
initgraph(WINDOW_WIDTH, WINDOW_HIGHT, INIT_RENDERMANUAL); //初始化窗口
功能:
這個函數用於初始化繪圖環境。聲明:
void initgraph( int Width, int Height, int Flag = INIT_DEFAULT ); void initgraph( int* gdriver, int* gmode, char* path ); // 兼容 Borland C++ 3.1 的重載,不建議使用。
- 參數:
Width
繪圖環境的寬度。若是爲-1,則使用屏幕的寬度Height
繪圖環境的高度。若是爲-1,則使用屏幕的高度Style
請留空,爲保留參數- 返回值:
(無)
功能:
這個函數用於設置當前背景色。而且會把當前圖片上是原背景色的像素,轉變爲新的背景色。聲明:
void setbkcolor( color_t color, PIMAGE pimg = NULL );
參數:
color
指定要設置的背景顏色。注意,該設置會同時影響文字背景色。返回值:
(無)
setfillstyle(SOLID_FILL, Blank_COLOR); //設置方塊顏色
功能:
這個函數用於設置當前填充類型。該函數的自定義填充部分尚不支持。聲明:
void setfillstyle( int pattern, color_t color, PIMAGE pimg = NULL );
- 參數:
- pattern
填充類型,能夠是如下宏或值:NULL_FILL 不填充
SOLID_FILL 固實填充
pupattern
color
填充顏色。
- 返回值:
(無)
功能:
這個函數用於畫填充的多邊形。邊線顏色由setcolor函數決定,填充顏色由setfillstyle函數決定聲明:
void fillpoly( int numpoints, const int *polypoints, PIMAGE pimg = NULL );
- 參數:
numpoints
多邊形點的個數。polypoints
每一個點的座標,數組元素個數爲 numpoints * 2。
該函數會自動鏈接多邊形首尾。
- 返回值:
(無)
功能:
這個函數用於設置當前字體樣式。聲明:
void setfont( int nHeight, int nWidth, LPCSTR lpszFace, PIMAGE pimg = NULL ); void setfont( int nHeight, int nWidth, LPCSTR lpszFace, int nEscapement, int nOrientation, int nWeight, bool bItalic, bool bUnderline, bool bStrikeOut, PIMAGE pimg = NULL ); void setfont( int nHeight, int nWidth, LPCSTR lpszFace, int nEscapement, int nOrientation, int nWeight, bool bItalic, bool bUnderline, bool bStrikeOut, BYTE fbCharSet, BYTE fbOutPrecision, BYTE fbClipPrecision, BYTE fbQuality, BYTE fbPitchAndFamily, PIMAGE pimg = NULL ); void setfont( const LOGFONT *font, PIMAGE pimg = NULL );
outtextxy(WINDOW_WIDTH / 2, 0, mCharsScore); //在窗口輸出字體
功能:
這個函數用於在指定位置輸出字符串。聲明:
void outtextxy( int x, int y, LPCSTR textstring, PIMAGE pimg = NULL ); void outtextxy( int x, int y, CHAR c, PIMAGE pimg = NULL ); void outtextxy( int x, int y, LPCWSTR textstring, PIMAGE pimg = NULL ); void outtextxy( int x, int y, WCHAR c, PIMAGE pimg = NULL );
參數:
x
字符串輸出時頭字母的 x 軸的座標值
y
字符串輸出時頭字母的 y 軸的座標值。
textstring
要輸出的字符串的指針。
c
要輸出的字符。返回值:
(無)
random(max); //產生[0,max)的隨機數,注意不包括最大值
filename 爲要播放的文件的路徑名
mciSendString(filename, NULL, 0, NULL); //低效播放方式
//高效率無阻塞播放 ThreadParameter *tp = (ThreadParameter *)pParam; MCI_OPEN_PARMS open;//定義打開結構體變量 open.lpstrElementName = filename;//填充參數 mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, DWORD_PTR(&open));//打開 MCI_PLAY_PARMS play;//定義播放結構題變量 mciSendCommand(open.wDeviceID, MCI_PLAY, 0, DWORD_PTR(&play));//非阻塞式播放
舉個例子
typedef struct ThreadParameter { //音頻播放線程參數 char filename[200]; char key[30]; }; ThreadParameter tpp; //音頻播放線程傳參結構體<全局變量> DWORD WINAPI music_play(LPVOID pParam) //播放音樂 { //高效率無阻塞播放 ThreadParameter *tp = (ThreadParameter *)pParam; MCI_OPEN_PARMS open;//定義打開結構體變量 open.lpstrElementName = tp->filename;//填充參數 mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, DWORD_PTR(&open));//打開 MCI_PLAY_PARMS play;//定義播放結構題變量 mciSendCommand(open.wDeviceID, MCI_PLAY, 0, DWORD_PTR(&play));//非阻塞式播放 return 0; }
啓動線程
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tpp, 0, NULL); //啓動音樂播放線程
解釋以下:
結構體是用來傳參數的,線程函數返回值類型必須爲DWORD WINAPI,函數參數必須爲LPVOID 類型。形式以下:
啓動函數第四個參數傳入傳參結構體指針,此處爲&tpp。形式以下:
FILE *fp = NULL; fp = fopen(filename, "r"); //filename爲要打開的文件路徑
我已經準備好每一個按鍵的音頻文件和每一個關卡對應音樂的鍵譜了,相關定義以下
#define Path_Music_resPiano "..//resplus//piano" //載入鍵音 #define Path_Music_Fail "..//resplus//fail.mp3" #define Path_Music_Launch "..//resplus//chuanshao.mp3" #define Path_pre "..//resplus//piano//" //音頻路徑前綴 #define Path_end ".mp3" //音頻路徑後綴 //每一個關卡對應鍵譜 char Path_A_Breeze_From_Alabama[] = "..//resplus//A Breeze From Alabama.txt"; char Path_Happy_New_Year[] = "..//resplus//Happy New Year.txt"; char Path_Jasmine[] = "..//resplus//Jasmine.txt"; char Path_Little_Star[] = "..//resplus//Little Star.txt"; char Path_lyricwaltz[] = "..//resplus//lyricwaltz.txt"; char Path_Merry_Christmas[] = "..//resplus//Merry Christmas.txt";
int main() //主函數 { //--------播放啓動音樂----------begin ThreadParameter tp; strcpy(tp.filename, Path_Music_Launch); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); //--------播放啓動音樂----------end //------------初始化------------begin setinitmode(RENDER_MANUAL); initgraph(WINDOW_WIDTH, WINDOW_HIGHT, INIT_RENDERMANUAL); //初始化窗口 strcpy(Path_Music, Path_Jasmine); //默認關卡 //------------初始化------------end //----------選擇關卡------------begin setfont(20, 0, "宋體"); outtextxy(10, 10, "按下對應字母進入關卡"); outtextxy(10, 35, "A: A Breeze From Alabama"); outtextxy(10, 55, "B: 茉莉花"); outtextxy(10, 75, "C: Happy New Year"); outtextxy(10, 95, "D: Little Star"); outtextxy(10, 115, "E: lyricwaltz"); outtextxy(10, 135, "F: Merry Christmas"); switch (getch()) { case 'A': strcpy(Path_Music, Path_A_Breeze_From_Alabama); break; case 'B': strcpy(Path_Music, Path_Jasmine); break; case 'C': strcpy(Path_Music, Path_Happy_New_Year); break; case 'D': strcpy(Path_Music, Path_Little_Star); break; case 'E': strcpy(Path_Music, Path_lyricwaltz); break; case 'F': strcpy(Path_Music, Path_Merry_Christmas); break; default: break; } //----------選擇關卡------------end initFile(); //讀入相關文件 creatView(); //建立地圖 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GameControl, NULL, 0, NULL); //啓動鍵盤控制線程 GameView(); //繪圖 getch(); //防止遊戲結束後退出 return 0; }
鍵譜文件中的內容(片斷供參考)
d2 d2 #f2 e2 a1 #c2 e2 d2 d (#f.a) (#f.a) d (#f.a) (#f.a) d (#f.a) (#f.a) A-1 (e.g) (e.g)
對應的音頻文件名爲黃色部分
==d2== ==d== (==#f==.==a==) ==A-1==
char track[1024][12]; //曲譜 int mLength = 0; //鍵總數 void initFile() //初始化文件資源 { FILE *fp = NULL; fp = fopen(Path_Music, "r"); if (fp != NULL) { while (fscanf(fp, "%s", track[mLength]) != EOF) { //讀入全部鍵 mLength++; } } fclose(fp); }
從文件中讀入每一個按鍵的標識碼存到數組track中,並記錄有多少個鍵存到變量mLength中。
根據總按鍵數建立一個尺寸爲窗口寬度(按鍵數黑塊高度)的PIMAGE對象。生成1到4的隨機數,對應的數爲所在的軌道。按照所在軌道在總畫布上錯位繪製黑塊
PIMAGE totalimg; //總畫布存儲對象 <全局變量> int randtrack[3000] = { -1000 }; //存軌道的隨機數 void creatView() { int point[8]; //四邊形點集 int x = 0, y = 0; //基定點座標 randomize(); //初始化隨機數 totalimg = newimage(WINDOW_WIDTH, Blank_HIGHT*mLength); //初始化總畫布 setbkcolor(COLOR_WHITE, totalimg); //設置總畫布背景 cleardevice(totalimg); //清空總畫布 for (int i = 0; i < mLength; i++) { randtrack[i] = random(4) + 1; //參數0-3的隨機數,加一後爲軌道位置 y = inter_y; x = (randtrack[i] - 1) * Blank_WIDTH; point[0] = x; point[1] = y; point[2] = x + Blank_WIDTH; point[3] = y; point[4] = x + Blank_WIDTH; point[5] = y + Blank_HIGHT; point[6] = x; point[7] = y + Blank_HIGHT; setfillstyle(SOLID_FILL, Blank_COLOR); //設置方塊顏色 fillpoly(4, point, totalimg); //繪製方塊 inter_y += Blank_HIGHT; //設置滑塊公共高度 } }
根據按鍵以及以前的隨機數數組即答案來計分
因爲監聽按鍵和繪製動畫是異步操做的,全部咱們給按鍵控制單獨開一個線程來監聽。線程的使用在上面已經介紹過了,下面來看看代碼。
DWORD WINAPI GameControl() //控制 { int curr = 0; int k = 0, index = 0; ThreadParameter tp; strcpy(tp.filename, Path_Music_Fail); //給線程傳參結構體賦值失敗音樂路徑 for (; k != key_esc;) { if (kbhit()) { k = getch(); if (k == 'S') { if (randtrack[mLength - curr - 1] == 1) { music_play_control(track[index++]); //將鍵音傳入音樂處理函數 mScore++; //得分加一 drawCountText(); //刷新計分標籤 } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); //播放失敗音樂線程 failplay = true; //設定失敗標誌爲真 } } else if (k == 'D') { if (randtrack[mLength - curr - 1] == 2) { music_play_control(track[index++]); mScore++; drawCountText(); } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } } else if (k == '4') { if (randtrack[mLength - curr - 1] == 3) { music_play_control(track[index++]); mScore++; drawCountText(); } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } } else if (k == '5') { if (randtrack[mLength - curr - 1] == 4) { music_play_control(track[index++]); mScore++; drawCountText(); } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } } curr++; accelerate = mScore / 25; //設定滑塊每25分增長速度 } if (failplay) { api_sleep(500); //等待播放音樂線程啓動 return 0; } } return 0; }
代碼中用大寫字母S、D和數字鍵四、5分別控制四條軌道,可隨意修改。
failpaly爲遊戲失敗標誌,若爲真則播放失敗音樂,延遲500毫秒後結束線程。
void drawCountText() //繪製計數器 { sprintf(mCharsScore, "%d", mScore); //int轉char* setfont(40, 0, "宋體"); //設定字體樣式 setfontbkcolor(EGERGB(0xff, 0x00, 0x00)); //設置字體背景色 outtextxy(WINDOW_WIDTH / 2, 0, mCharsScore); //在窗口輸出字體 }
預處理(寫法比較暴力哈)
void music_play_control(char key[]) //控制音樂播放 { int flage = 0; char copy[30]; char buff[10][30]; //同時按下的鍵值 char temp[200]; memset(temp, '\0', sizeof(temp)); //按照特定格式讀入每一個鍵符 if (key[0] != '(') { strcat(temp, Path_pre); strcat(temp, key); strcat(temp, Path_end); strcpy(tpp.filename, temp); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tpp, 0, NULL); } else { memset(buff, '\0', sizeof(buff)); strcpy(copy, key); for (int i = 0; i < strlen(copy); i++) { if (copy[i] == '.') { flage++; copy[i] = ' '; } else if (copy[i] == '(' || copy[i] == ')') { copy[i] = ' '; } } if (flage == 0) { sscanf(copy, "%s", buff[0]); } else if (flage == 1) { sscanf(copy, "%s %s", buff[0], buff[1]); } else if (flage == 2) { sscanf(copy, "%s %s %s", buff[0], buff[1], buff[2]); } else if (flage == 3) { sscanf(copy, "%s %s %s %s", buff[0], buff[1], buff[2], buff[3]); } for (int i = 0; i < flage; i++) { strcat(temp, Path_pre); strcat(temp, buff[i]); strcat(temp, Path_end); strcpy(tpp.filename, temp); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tpp, 0, NULL); //啓動音樂播放線程 api_sleep(200); } } }
實際播放音樂的線程函數
DWORD WINAPI music_play(LPVOID pParam) //播放音樂 { //mciSendString(tp->filename, NULL, 0, NULL); //低效播放方式 //高效率無阻塞播放 ThreadParameter *tp = (ThreadParameter *)pParam; MCI_OPEN_PARMS open;//定義打開結構體變量 open.lpstrElementName = tp->filename;//填充參數 mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, DWORD_PTR(&open));//打開 MCI_PLAY_PARMS play;//定義播放結構題變量 mciSendCommand(open.wDeviceID, MCI_PLAY, 0, DWORD_PTR(&play));//非阻塞式播放 return 0; }
void GameView() // 繪圖 { randomize(); //初始化隨機數 cleardevice(); //清屏 setcaption("別踩白塊 - 1707004544"); //窗口標題 setbkcolor(EGERGB(0xff, 0xff, 0xff)); //背景色 ThreadDrawTrack(); }
遊戲啓動後,使總畫布左下角定點與窗口(0,0)頂點對齊
使總畫布在可見區域由底向上繪製,並記錄下移座標。
根據下移的座標除以黑塊的高度可肯定是哪一個方塊
DWORD WINAPI ThreadDrawTrack() { setrendermode(RENDER_MANUAL); int y = inter_y; int addh = 0; ThreadParameter tp; strcpy(tp.filename, Path_Music_Fail); for (; is_run(); delay_fps(FPS)) { if (failplay) { cleardevice(); sprintf(mCharsScore, "%d", mScore); setfont(100, 0, "宋體"); setfontbkcolor(EGERGB(0xff, 0x00, 0x00)); outtextxy(WINDOW_WIDTH / 2 + 20, WINDOW_HIGHT / 2, mCharsScore); outtextxy(0, WINDOW_HIGHT / 2, "得分:"); break; } if (-1 * y >= 0) { break; } putimage(0, -1 * y, totalimg); y -= 2 + accelerate; below = addh - mScore*Blank_HIGHT - 160; if (below >= WINDOW_HIGHT) { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } addh += 2; drawCountText(); //更新顯示得分 } return 1; }
我的感受EGE繪製效率確實有點低,這是我寫的五總方法中畫面最流暢,且最簡單的方法。缺點也很明顯,不能單獨控制每一個按鍵。
歡迎關注個人github。
我也是初學者,代碼上有不少不足歡迎提出指正,感謝閱覽。
完整實現代碼以下
#include <graphics.h> #include <math.h> #include<string.h> #include<stdio.h> #include <windows.h> #pragma comment(lib, "Winmm.lib") //For MCI(Media Control Interface,媒體控制接口) #define Path_Music_resPiano "..//resplus//piano" //載入鍵音 #define Path_Music_Fail "..//resplus//fail.mp3" #define Path_Music_Launch "..//resplus//chuanshao.mp3" #define Path_pre "..//resplus//piano//" //音頻路徑前綴 #define Path_end ".mp3" //音頻路徑後綴 #define WINDOW_HIGHT 800 //窗口高度 #define WINDOW_WIDTH 480 //窗口寬度 #define Blank_HIGHT 160 //方塊高度 #define Blank_WIDTH 120 //方塊寬度 #define Blank_COLOR EGERGB(00,00,00) //方塊顏色 #define COLOR_WHITE EGERGB(0xFF, 0xFF, 0xFF) //白色 #define FPS 100 #define SLEEP 10 //-------函數聲明-------- void drawCountText(); //繪製計數器 void initFile(); //初始化文件資源 DWORD WINAPI music_play(LPVOID pParam); //播放音樂 void music_play_control(char key[]); //控制音樂播放 DWORD WINAPI GameControl(); //控制 void GameView(); // 繪圖 void creatView(); //建立地圖 //-------全局變量-------- int mScore = 0; //分數 char mCharsScore[50]; //分數字符串 char track[1024][12]; //曲譜 int mLength = 0; //鍵總數 int below = 0; //最下面一個方塊定點的y軸 PIMAGE totalimg; int randtrack[3000] = { -1000 }; //存軌道的隨機數 int inter_y = 0; //生成圖片時用到的y bool failplay = false; int accelerate = 0; char Path_A_Breeze_From_Alabama[] = "..//resplus//A Breeze From Alabama.txt"; char Path_Happy_New_Year[] = "..//resplus//Happy New Year.txt"; char Path_Jasmine[] = "..//resplus//Jasmine.txt"; char Path_Little_Star[] = "..//resplus//Little Star.txt"; char Path_lyricwaltz[] = "..//resplus//lyricwaltz.txt"; char Path_Merry_Christmas[] = "..//resplus//Merry Christmas.txt"; char Path_Music[50]; typedef struct ThreadParameter { //音頻播放線程參數 char filename[200]; char key[30]; }; ThreadParameter tpp; //音頻播放線程傳參結構體 int main() //主函數 { //--------播放啓動音樂----------begin ThreadParameter tp; strcpy(tp.filename, Path_Music_Launch); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); //--------播放啓動音樂----------end //------------初始化------------begin setinitmode(RENDER_MANUAL); initgraph(WINDOW_WIDTH, WINDOW_HIGHT, INIT_RENDERMANUAL); //初始化窗口 strcpy(Path_Music, Path_Jasmine); //默認關卡 //------------初始化------------end //----------選擇關卡------------begin setfont(20, 0, "宋體"); outtextxy(10, 10, "按下對應字母進入關卡"); outtextxy(10, 35, "A: A Breeze From Alabama"); outtextxy(10, 55, "B: 茉莉花"); outtextxy(10, 75, "C: Happy New Year"); outtextxy(10, 95, "D: Little Star"); outtextxy(10, 115, "E: lyricwaltz"); outtextxy(10, 135, "F: Merry Christmas"); switch (getch()) { case 'A': strcpy(Path_Music, Path_A_Breeze_From_Alabama); break; case 'B': strcpy(Path_Music, Path_Jasmine); break; case 'C': strcpy(Path_Music, Path_Happy_New_Year); break; case 'D': strcpy(Path_Music, Path_Little_Star); break; case 'E': strcpy(Path_Music, Path_lyricwaltz); break; case 'F': strcpy(Path_Music, Path_Merry_Christmas); break; default: break; } //----------選擇關卡------------end initFile(); //讀入相關文件 creatView(); //建立地圖 CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)GameControl, NULL, 0, NULL); //啓動鍵盤控制線程 GameView(); //繪圖 getch(); //防止遊戲結束後退出 return 0; } void initFile() //初始化文件資源 { FILE *fp = NULL; fp = fopen(Path_Music, "r"); if (fp != NULL) { while (fscanf(fp, "%s", track[mLength]) != EOF) { //讀入全部鍵 mLength++; } } fclose(fp); } DWORD WINAPI ThreadDrawTrack() { setrendermode(RENDER_MANUAL); int y = inter_y; int addh = 0; ThreadParameter tp; strcpy(tp.filename, Path_Music_Fail); for (; is_run(); delay_fps(FPS)) { if (failplay) { cleardevice(); sprintf(mCharsScore, "%d", mScore); setfont(100, 0, "宋體"); setfontbkcolor(EGERGB(0xff, 0x00, 0x00)); outtextxy(WINDOW_WIDTH / 2 + 20, WINDOW_HIGHT / 2, mCharsScore); outtextxy(0, WINDOW_HIGHT / 2, "得分:"); break; } if (-1 * y >= 0) { break; } putimage(0, -1 * y, totalimg); y -= 2 + accelerate; below = addh - mScore*Blank_HIGHT - 160; if (below >= WINDOW_HIGHT) { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } addh += 2; drawCountText(); //更新顯示得分 } return 1; } void GameView() // 繪圖 { randomize(); //初始化隨機數 cleardevice(); //清屏 setcaption("別踩白塊 - 1707004544 李浩"); //窗口標題 setbkcolor(EGERGB(0xff, 0xff, 0xff)); //背景色 ThreadDrawTrack(); } DWORD WINAPI GameControl() //控制 { int curr = 0; int k = 0, index = 0; ThreadParameter tp; strcpy(tp.filename, Path_Music_Fail); //給線程傳參結構體賦值失敗音樂路徑 for (; k != key_esc;) { if (kbhit()) { k = getch(); if (k == 'S') { if (randtrack[mLength - curr - 1] == 1) { music_play_control(track[index++]); //將鍵音傳入音樂處理函數 mScore++; //得分加一 drawCountText(); //刷新計分標籤 } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); //播放失敗音樂線程 failplay = true; //設定失敗標誌爲真 } } else if (k == 'D') { if (randtrack[mLength - curr - 1] == 2) { music_play_control(track[index++]); mScore++; drawCountText(); } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } } else if (k == '4') { if (randtrack[mLength - curr - 1] == 3) { music_play_control(track[index++]); mScore++; drawCountText(); } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } } else if (k == '5') { if (randtrack[mLength - curr - 1] == 4) { music_play_control(track[index++]); mScore++; drawCountText(); } else { CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tp, 0, NULL); failplay = true; } } curr++; accelerate = mScore / 25; //設定滑塊每25分增長速度 } if (failplay) { api_sleep(500); //等待播放音樂線程啓動 return 0; } } return 0; } void drawCountText() //繪製計數器 { sprintf(mCharsScore, "%d", mScore); //int轉char* setfont(40, 0, "宋體"); //設定字體樣式 setfontbkcolor(EGERGB(0xff, 0x00, 0x00)); //設置字體背景色 outtextxy(WINDOW_WIDTH / 2, 0, mCharsScore); //在窗口輸出字體 } void creatView() { int point[8]; //四邊形點集 int x = 0, y = 0; //基定點座標 randomize(); //初始化隨機數 totalimg = newimage(WINDOW_WIDTH, Blank_HIGHT*mLength); //初始化總畫布 setbkcolor(COLOR_WHITE, totalimg); //設置總畫布背景 cleardevice(totalimg); //清空總畫布 for (int i = 0; i < mLength; i++) { randtrack[i] = random(4) + 1; //參數0-3的隨機數,加一後爲軌道位置 y = inter_y; x = (randtrack[i] - 1) * Blank_WIDTH; point[0] = x; point[1] = y; point[2] = x + Blank_WIDTH; point[3] = y; point[4] = x + Blank_WIDTH; point[5] = y + Blank_HIGHT; point[6] = x; point[7] = y + Blank_HIGHT; setfillstyle(SOLID_FILL, Blank_COLOR); //設置方塊顏色 fillpoly(4, point, totalimg); //繪製方塊 inter_y += Blank_HIGHT; //設置滑塊公共高度 } } void music_play_control(char key[]) //控制音樂播放 { int flage = 0; char copy[30]; char buff[10][30]; //同時按下的鍵值 char temp[200]; memset(temp, '\0', sizeof(temp)); //按照特定格式讀入每一個鍵符 if (key[0] != '(') { strcat(temp, Path_pre); strcat(temp, key); strcat(temp, Path_end); strcpy(tpp.filename, temp); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tpp, 0, NULL); } else { memset(buff, '\0', sizeof(buff)); strcpy(copy, key); for (int i = 0; i < strlen(copy); i++) { if (copy[i] == '.') { flage++; copy[i] = ' '; } else if (copy[i] == '(' || copy[i] == ')') { copy[i] = ' '; } } if (flage == 0) { sscanf(copy, "%s", buff[0]); } else if (flage == 1) { sscanf(copy, "%s %s", buff[0], buff[1]); } else if (flage == 2) { sscanf(copy, "%s %s %s", buff[0], buff[1], buff[2]); } else if (flage == 3) { sscanf(copy, "%s %s %s %s", buff[0], buff[1], buff[2], buff[3]); } for (int i = 0; i < flage; i++) { strcat(temp, Path_pre); strcat(temp, buff[i]); strcat(temp, Path_end); strcpy(tpp.filename, temp); CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)music_play, &tpp, 0, NULL); //啓動音樂播放線程 api_sleep(200); } } } DWORD WINAPI music_play(LPVOID pParam) //播放音樂 { //mciSendString(tp->filename, NULL, 0, NULL); //低效播放方式 //高效率無阻塞播放 ThreadParameter *tp = (ThreadParameter *)pParam; MCI_OPEN_PARMS open;//定義打開結構體變量 open.lpstrElementName = tp->filename;//填充參數 mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT, DWORD_PTR(&open));//打開 MCI_PLAY_PARMS play;//定義播放結構題變量 mciSendCommand(open.wDeviceID, MCI_PLAY, 0, DWORD_PTR(&play));//非阻塞式播放 return 0; }