C++實現鼠標控制的黑框象棋
本文實例為大傢分享瞭C++實現鼠標控制的黑框象棋的具體代碼,供大傢參考,具體內容如下
該象棋小遊戲的特色
有顏色標註出 紅方和綠方
可以用鼠標控制
顏色原理
直接調用用Windows自帶的顏色API
用到瞭 顏色頭文件.h
代碼.
//consolecolor.hpp這是著色的實現頭文件 #pragma once #include<Windows.h>//調用win32API函數 #include<iostream>//調用flush成員函數,首先刷新緩沖區 namespace color//命名空間為color,防止名字沖突 { //顏色常量定義,分為掩碼,前景色,背景色 static const WORD bgMask(BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY); static const WORD fgMask(FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY); static const WORD fgBlack(0); static const WORD fgLoRed(FOREGROUND_RED); static const WORD fgLoGreen(FOREGROUND_GREEN); static const WORD fgLoBlue(FOREGROUND_BLUE); static const WORD fgLoCyan(fgLoGreen | fgLoBlue); static const WORD fgLoMagenta(fgLoRed | fgLoBlue); static const WORD fgLoYellow(fgLoRed | fgLoGreen); static const WORD fgLoWhite(fgLoRed | fgLoGreen | fgLoBlue); static const WORD fgGray(fgBlack | FOREGROUND_INTENSITY); static const WORD fgHiWhite(fgLoWhite | FOREGROUND_INTENSITY); static const WORD fgHiBlue(fgLoBlue | FOREGROUND_INTENSITY); static const WORD fgHiGreen(fgLoGreen | FOREGROUND_INTENSITY); static const WORD fgHiRed(fgLoRed | FOREGROUND_INTENSITY); static const WORD fgHiCyan(fgLoCyan | FOREGROUND_INTENSITY); static const WORD fgHiMagenta(fgLoMagenta | FOREGROUND_INTENSITY); static const WORD fgHiYellow(fgLoYellow | FOREGROUND_INTENSITY); static const WORD bgBlack(0); static const WORD bgLoRed(BACKGROUND_RED); static const WORD bgLoGreen(BACKGROUND_GREEN); static const WORD bgLoBlue(BACKGROUND_BLUE); static const WORD bgLoCyan(bgLoGreen | bgLoBlue); static const WORD bgLoMagenta(bgLoRed | bgLoBlue); static const WORD bgLoYellow(bgLoRed | bgLoGreen); static const WORD bgLoWhite(bgLoRed | bgLoGreen | bgLoBlue); static const WORD bgGray(bgBlack | BACKGROUND_INTENSITY); static const WORD bgHiWhite(bgLoWhite | BACKGROUND_INTENSITY); static const WORD bgHiBlue(bgLoBlue | BACKGROUND_INTENSITY); static const WORD bgHiGreen(bgLoGreen | BACKGROUND_INTENSITY); static const WORD bgHiRed(bgLoRed | BACKGROUND_INTENSITY); static const WORD bgHiCyan(bgLoCyan | BACKGROUND_INTENSITY); static const WORD bgHiMagenta(bgLoMagenta | BACKGROUND_INTENSITY); static const WORD bgHiYellow(bgLoYellow | BACKGROUND_INTENSITY); //設置顏色的實現函數,主要是調用win32的API和一些位運算。 void setConsoleColor(WORD mask, WORD c) { static HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE); if(hStdout==NULL)return; CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(hStdout, &csbi); csbi.wAttributes &= ~mask; csbi.wAttributes |= c; SetConsoleTextAttribute(hStdout, csbi.wAttributes); } //用到模板是為瞭通用,不僅cout,cerr可以染色,wcout,wcerr等也可以著色,自己定義的流隻要滿足模板都可以。 template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_white(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgLoWhite); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_blue(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgHiBlue); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_green(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgHiGreen); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_red(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgHiRed); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_cyan(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgHiCyan); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_magenta(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgHiMagenta); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_yellow(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgHiYellow); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& fg_black(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(fgMask, fgBlack); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_white(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgLoWhite); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_blue(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgHiBlue); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_green(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgHiGreen); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_red(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgHiRed); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_cyan(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgHiCyan); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_magenta(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgHiMagenta); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_yellow(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgHiYellow); return os; } template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& bg_black(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgBlack); return os; } //清空屏幕,還原本色 template<typename charT, typename traits> inline std::basic_ostream<charT, traits>& clr(std::basic_ostream<charT, traits>& os) { os.flush(); setConsoleColor(bgMask, bgBlack); setConsoleColor(fgMask, fgLoWhite); system("cls"); return os; } }
鼠標控制原理
直接調用windows自帶的鼠標控制函數
註意,如果直接使用清屏函數 system(“clr”)會導致鼠標輸入阻塞所以要自己重新編譯一個清屏函數
鼠標代碼.
void MyCls(HANDLE hConsole) { COORD coordScreen={0,0};//設置清屏後光標返回的屏幕左上角坐標 BOOL bSuccess; DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi;//保存緩沖區信息 DWORD dwConSize;//當前緩沖區可容納的字符數 bSuccess=GetConsoleScreenBufferInfo(hConsole,&csbi);//獲得緩沖區信息 PERR(bSuccess,"GetConsoleScreenBufferInfo"); dwConSize=csbi.dwSize.X * csbi.dwSize.Y;//緩沖區容納字符數目 //用空格填充緩沖區 bSuccess=FillConsoleOutputCharacter(hConsole,(TCHAR)' ',dwConSize,coordScreen,&cCharsWritten); PERR(bSuccess,"FillConsoleOutputCharacter"); bSuccess=GetConsoleScreenBufferInfo(hConsole,&csbi);//獲得緩沖區信息 PERR(bSuccess,"ConsoleScreenBufferInfo"); //填充緩沖區屬性 bSuccess=FillConsoleOutputAttribute(hConsole,csbi.wAttributes,dwConSize,coordScreen,&cCharsWritten); PERR(bSuccess,"FillConsoleOutputAttribute"); //光標返回屏幕左上角坐標 bSuccess=SetConsoleCursorPosition(hConsole,coordScreen); PERR(bSuccess,"SetConsoleCursorPosition"); return; }
自定義清屏函數.
void clrscr(void) { HANDLE hStdOut=GetStdHandle(STD_OUTPUT_HANDLE); MyCls(hStdOut); return; }
象棋的具體實現細節
定義瞭一個棋盤chessboard,和一個棋子控制的類chess,對不同的棋子有自己的類,定義有特定的ID和每個棋子特定的走法規則。還有對棋盤控制的move()函數。
總體代碼.
#include <iostream> #include <memory.h> #include <math.h> #include<windows.h> #include<winuser.h> #include"顏色頭文件.h" #include<conio.h> #include <stdlib.h> #include <stdio.h> #define PERR(bSuccess, api){if(!(bSuccess)) printf("%s:Error %d from %s on line %d\n", __FILE__, GetLastError(), api, __LINE__);} void MyCls(HANDLE) ; void clrscr(void) { HANDLE hStdOut=GetStdHandle(STD_OUTPUT_HANDLE); MyCls(hStdOut); return; } void MyCls(HANDLE hConsole) { COORD coordScreen={0,0};//設置清屏後光標返回的屏幕左上角坐標 BOOL bSuccess; DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi;//保存緩沖區信息 DWORD dwConSize;//當前緩沖區可容納的字符數 bSuccess=GetConsoleScreenBufferInfo(hConsole,&csbi);//獲得緩沖區信息 PERR(bSuccess,"GetConsoleScreenBufferInfo"); dwConSize=csbi.dwSize.X * csbi.dwSize.Y;//緩沖區容納字符數目 //用空格填充緩沖區 bSuccess=FillConsoleOutputCharacter(hConsole,(TCHAR)' ',dwConSize,coordScreen,&cCharsWritten); PERR(bSuccess,"FillConsoleOutputCharacter"); bSuccess=GetConsoleScreenBufferInfo(hConsole,&csbi);//獲得緩沖區信息 PERR(bSuccess,"ConsoleScreenBufferInfo"); //填充緩沖區屬性 bSuccess=FillConsoleOutputAttribute(hConsole,csbi.wAttributes,dwConSize,coordScreen,&cCharsWritten); PERR(bSuccess,"FillConsoleOutputAttribute"); //光標返回屏幕左上角坐標 bSuccess=SetConsoleCursorPosition(hConsole,coordScreen); PERR(bSuccess,"SetConsoleCursorPosition"); return; } using namespace color; using namespace std;//存儲結構:chess類是基類,派生類是各種棋子,在chessboard類中用chess的指針調用各個棋子 class chessboard; //鼠標控制參數 // bool turn=0; class chess{ private: int id;//等級 public: chess(int i):id(i){} int get(){return id;} virtual bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy)=0; virtual ~chess(){};//虛析構 }; class chessboard{ private: chess *c[10][9];//用指針調用各個棋子,實現多態 char chessword[15][4]={"帥","相","炮","士","車","馬","兵","","卒","馬","車","士","炮","象","將"};//名字 public: chessboard(){memset(c, NULL, sizeof(c));};//把指針初始化為零指針 void init(); chess* get(int x,int y){return c[x][y];} int getid(int x,int y){ if(c[x][y]!=NULL) return c[x][y]->get();return 0;} void show(); void play(); bool move(int startx,int starty,int aimx,int aimy); ~chessboard();//析構函數 static bool end;//判斷結束 static int player; }; bool chessboard::end=true; int chessboard::player=-1; bool chessboard::move(int startx,int starty,int aimx,int aimy){ if(startx>=0&&startx<10&&starty>=0&&starty<9//初步判斷傳入的點是否符合規則 &&aimx>=0&&aimx<10&&aimy>=0&&aimy<9 &&getid(startx,starty)&&getid(startx,starty)*player>0 &&c[startx][starty]->judge_move(*this,startx,starty,aimx,aimy)){ if(c[aimx][aimy]!=NULL) delete c[aimx][aimy];//吃子 c[aimx][aimy]=c[startx][starty]; c[startx][starty]=NULL; player*=-1; if(turn==0) turn=1; else turn=0; return true; } //cout<<"走法錯誤,不符合規則"<<endl; return false; } class horse : public chess{//馬的實現 public: horse(int i) : chess((i==0?-2:2)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&(tempx*tempx+tempy*tempy==5)&&!cb.get(startx+tempx/2,starty+tempy/2)) return true; return false; } }; class soldier : public chess{//兵(卒)的實現 public: soldier(int c) : chess((c==0?-1:1)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&sid*tempx<=0){ if(abs(tempx)==1&&tempy==0) return true; if(abs(tempy)==1&&tempx==0) if((startx/5==0&&sid>0)||(startx/5==1&&sid<0)) return true; return false; } return false; } }; class general : public chess{//帥(將)的實現 public: general(int c) : chess((c==0?-7:7)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&tempy*tempy+tempx*tempx==1&&aimx%7>=0&&aimx%7<=2&&aimy>=3&&aimy<=5) return true; return false; } ~general(){chessboard::end=false;} }; class elephant : public chess{//象(相)的實現 public: elephant(int c) : chess((c==0?-6:6)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&tempy*tempy+tempx*tempx==8&&startx/5==aimx/5&&!cb.get(startx+tempx/2,starty+tempy/2)) return true; return false; } }; class cannon : public chess{//炮的實現 public: cannon(int c) : chess((c==0?-5:5)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&!(tempx&&tempy)&&(tempx+tempy)){ int tot=0; if(tempx!=0){ int sign=tempx>0?1:-1; for(int i=1;i<abs(tempx);i++) if(cb.get(startx+sign*i,starty)) tot++; } else{ int sign=tempy>0?1:-1; for(int i=1;i<abs(tempy);i++) if(cb.get(startx,starty+sign*i)) tot++; } if(!aid) {if(!tot) return true;} else {if(tot==1) return true;} } return false; } }; class guard: public chess{//士(仕)的實現 public: guard(int c) : chess((c==0?-4:4)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&tempy*tempy+tempx*tempx==2&&aimx%7>=0&&aimx%7<=2&&aimy>=3&&aimy<=5) return true; return false; } }; class rook : public chess{//車的實現 public: rook(int c) : chess((c==0?-3:3)){} bool judge_move(chessboard &cb,int startx,int starty,int aimx,int aimy){ int tempx=aimx-startx,tempy=aimy-starty; int sid=cb.getid(startx, starty),aid=cb.getid(aimx, aimy); if(sid*aid<=0&&!(tempx&&tempy)&&(tempx+tempy)){ if(tempx!=0){ int sign=tempx>0?1:-1; for(int i=1;i<abs(tempx);i++) if(cb.get(startx+sign*i,starty)) return false; } else{ int sign=tempy>0?1:-1; for(int i=1;i<abs(tempy);i++) if(cb.get(startx,starty+sign*i)) return false; } return true; } return false; } }; chessboard :: ~chessboard(){ for(int i=0;i<10;i++) for(int j=0;j<9;j++) if(c[i][j]!=NULL){ delete c[i][j]; c[i][j]=NULL; } } void chessboard :: init(){//初始化,棋子的生成 c[0][0]=new rook(0); c[0][8]=new rook(0); c[0][1]=new horse(0); c[0][7]=new horse(0); c[0][2]=new elephant(0); c[0][6]=new elephant(0); c[0][3]=new guard(0); c[0][5]=new guard(0); c[0][4]=new general(0); c[9][4]=new general(1); c[2][1]=new cannon(0); c[2][7]=new cannon(0); c[3][0]=new soldier(0); c[3][2]=new soldier(0); c[3][4]=new soldier(0); c[3][6]=new soldier(0); c[3][8]=new soldier(0); c[6][8]=new soldier(1); c[6][0]=new soldier(1); c[6][2]=new soldier(1); c[6][4]=new soldier(1); c[6][6]=new soldier(1); c[7][1]=new cannon(1); c[7][7]=new cannon(1); c[9][0]=new rook(1); c[9][8]=new rook(1); c[9][1]=new horse(1); c[9][7]=new horse(1); c[9][2]=new elephant(1); c[9][6]=new elephant(1); c[9][3]=new guard(1); c[9][5]=new guard(1); } void chessboard :: show(){ cout<<fg_yellow<<" 零一二三四五六七八"<<endl<<endl; char num[10][4]={"零","一","二","三","四","五","六","七","八","九"}; for(int i=0;i<6/*10*/;i++){ if(i==5) cout<<fg_white<<" ——楚 河 漢 界——"<<endl; cout<<fg_yellow<<num[i]<<" "; for(int j=0;j<9;j++){ if(c[i][j]!=NULL) { if(c[i][j]->get()>0) cout<<fg_red<<chessword[c[i][j]->get()+7]; else cout<<fg_green<<chessword[c[i][j]->get()+7]; } else if((i==1&&j==4)||(i==8&&j==4)) cout<<fg_yellow<<"米"; else cout<<fg_yellow<<"十"; } cout<<endl; } for(int i=6;i<10/*10*/;i++){ cout<<fg_yellow<<num[i]<<" "; for(int j=0;j<9;j++){ if(c[i][j]!=NULL) { if(c[i][j]->get()>0) cout<<fg_red<<chessword[c[i][j]->get()+7]; else cout<<fg_green<<chessword[c[i][j]->get()+7]; } else if((i==1&&j==4)||(i==8&&j==4)) cout<<fg_yellow<<"米"; else cout<<fg_yellow<<"十"; } cout<<endl; } } void chessboard::play(){ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE); CONSOLE_SCREEN_BUFFER_INFO bInfo; INPUT_RECORD mouseRec; DWORD res; this->init(); this->show(); do{ int startx,starty,aimx,aimy; int sid,aid; do{ sid=aid=0; if(turn==0) { clrscr(); this->show(); cout<<fg_blue<<"請綠方行動" <<endl; //turn=1; } else { clrscr(); this->show(); cout<<fg_blue<<"請紅方行動"<<endl; //turn=0; } repeat: while(1){ Sleep(110); //this->show(); ReadConsoleInput(hIn, &mouseRec, 1, &res); if(mouseRec.Event.MouseEvent.dwButtonState==FROM_LEFT_1ST_BUTTON_PRESSED){ //system("cls"); //this->show(); if(mouseRec.Event.MouseEvent.dwMousePosition.X%2==1) starty=(mouseRec.Event.MouseEvent.dwMousePosition.X-5)/2; else starty=(mouseRec.Event.MouseEvent.dwMousePosition.X-4)/2; if(mouseRec.Event.MouseEvent.dwMousePosition.Y<7) startx=mouseRec.Event.MouseEvent.dwMousePosition.Y-2; else startx=mouseRec.Event.MouseEvent.dwMousePosition.Y-3; if(c[startx][starty]==NULL) goto repeat; //cout<<"startx:"<<startx<<endl; //cout<<"starty:"<<starty<<endl; break; } } cout<<"please give me next position"<<endl; while(1){ Sleep(110); //this->show(); ReadConsoleInput(hIn, &mouseRec, 1, &res); if(mouseRec.Event.MouseEvent.dwButtonState==FROM_LEFT_1ST_BUTTON_PRESSED){ //system("cls"); //this->show(); if(mouseRec.Event.MouseEvent.dwMousePosition.X%2==1) aimy=(mouseRec.Event.MouseEvent.dwMousePosition.X-5)/2; else aimy=(mouseRec.Event.MouseEvent.dwMousePosition.X-4)/2; if(mouseRec.Event.MouseEvent.dwMousePosition.Y<7) aimx=mouseRec.Event.MouseEvent.dwMousePosition.Y-2; else aimx=mouseRec.Event.MouseEvent.dwMousePosition.Y-3; //cout<<"aimx:"<<aimx<<endl; //cout<<"aimy:"<<aimy<<endl; break; } } //cin>>startx>>starty>>aimx>>aimy; }while(!this->move(startx,starty,aimx,aimy)); //clrscr(); //this->show(); }while(chessboard::end); if(chessboard::player==1) cout<<"結束,贏傢是綠方"<<endl; else cout<<"結束,贏傢是紅方" <<endl; } int main(){ HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode; GetConsoleMode(hStdin, &mode); mode &= ~ENABLE_QUICK_EDIT_MODE; //移除快速編輯模式 //mode &= ~ENABLE_INSERT_MODE; //移除插入模式 //mode &= ~ENABLE_MOUSE_INPUT; SetConsoleMode(hStdin, mode); chessboard C; C.play(); }
運行圖片
居中的圖片:
總結
本質類似與鍵盤輸入的象棋小遊戲和鼠標控制的五子棋小遊戲的綜合。其中碰到一個小問題,就是黑窗要把快速便捷模式取消瞭才可以利用鼠標點擊,為瞭解決這個問題,我在主函數插入瞭自動取消快速編輯的函數。
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); DWORD mode; GetConsoleMode(hStdin, &mode); mode &= ~ENABLE_QUICK_EDIT_MODE; //移除快速編輯模式 SetConsoleMode(hStdin, mode);
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- 從c++標準庫指針萃取器談一下traits技法(推薦)
- C++ 命名空間 using聲明使用示例詳解
- 深入淺析C++ traits技術
- 詳解c++中的trait與policy模板技術
- C++元編程語言初步入門詳解