【c++游戏编程】第一站!Game模板和《Pong》

《Pong》是什么?

《Pong》是一款游戏,内容简单,只有一个拍子和球

游戏循环和Game类

游戏循环

游戏是需要不断更新界面的,这种更新叫做游戏循环,把游戏封装成一个类就是Game类

Game类

源码奉上:

#include
#include
#include
#include
#include
#include
#include
#include
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
using namespace std;
const char *gamename="";
int GameHz=30;
HWND Gwin;

//s:淡 b:亮
#define BLACK 0
#define BLUE 1
#define GREEN 2
#define SBULE 3
#define RED 4
#define PURPLE 5
#define YELLO 6
#define WHILE 7
#define ASH 8
#define S_EBULE 9
#define BGREEN 10
#define BBULE 11
#define SRED 12
#define SPURPLE 13
#define BYELLO 14
#define BWHILE 15

#define PIX_VOID ' '

struct pixel{
	int q=BLACK,h=BWHILE;
	char z=PIX_VOID;
}pix[59][119];

pixel out(int x,int y){
	return pix[y][x];
}

#define ISRUN 1//...

void gotoxy(int x, int y){
	COORD pos={(short)x,(short)y};
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut,pos);
}

void color(int ForgC,int BackC){
	WORD wColor=((BackC&0x0F)<<4)+(ForgC&0x0F);
	SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),wColor);
}

void noedit(){
	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);
}

void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

class Player{
	//...
	public:
		bool isdie=0;
		Player();//...
		bool Out();//0成功,1失败,...
		void Die(){
			if(isdie)return;
			isdie=1;
			//...
		}
		bool Act();//0成功,1失败,...
		class Game;
		friend class Game;
};

class Game{
	public:
		bool Running;
		Game(){
			Running=1;
		}
		void GameLoop(){
			int i=0;
			while(Running&&ISRUN){
				if(i++%100==0)system("cls");
				Input();
				Output();
				Sleep(1000.0/GameHz);
				gotoxy(0,0);
			}
		}
	private:
		void GameEnd(){//Close
			if(MessageBox(Gwin,"确定要退出吗?",gamename,MB_YESNO)==IDYES){exit(0);}
		}
		void Input(){//检测键盘
			if(GetConsoleWindow()==Gwin){
				//...
				if(kd(VK_ESCAPE)){
					GameEnd();
				}
			}
		}
		void Output(){//输出
			//默认
			for(int i=0;i<59;i++){
				for(int j=0;j<119;j++){
					color(out(j,i).q,out(j,i).h);
					printf("%c",out(j,i).z);
				}
			}
		}
};
int main(){
	HideCursor();
	noedit();
	Gwin=GetConsoleWindow();
	Game game;
	game.GameLoop();
}

这是一个项目模板,至于详细内容,下期再讲,你只需知道GameHz是1秒内游戏刷新的次数,gamename是游戏的名字。

警告:运行过程不要修改gamename

我们将在第二章好好讲讲Game类

实现游戏的过程

思考

《Pong》需要什么?

拍子,球,界面

如何封装?

拍子不用封装,一个int就够了

球得用两个int,和一个enum,把它封装成一个class ball

警告:不要习惯用struct封装,不要习惯定义一个变量来代表一个对象

实践

封装

拍子:

int wally=0,wallwindy=4;

class Ball:

class Ball{
	public:
		int x,y;
		enum{
			up=1,donw=-1,left=2,right=-2,
			ul=3,ur=-3,dl=4,dr=-4
		}status;
		void out(){
			gotoxy(x,y);
			cerr<<"○";
		}
}ball;

警告:不要把所有成员变量设成公用,我这是为了方便......

Input

void Input(){//检测
	if(GetConsoleWindow()==Gwin){
		//...
		if(kd(VK_ESCAPE)){
			GameEnd();
		}
		if(kd(VK_UP)){
			wally--;
			wally=abs(wally);
		}
		if(kd(VK_DOWN)){
			wally++;
			if(wally>=60){
				wally=59;
			}
		}
		if(kd(107)){
			GameHz++;
		}
		if(kd(109)){
			GameHz--;
		}
	}
	int &bx=ball.x,&by=ball.y;
	switch(ball.status){
		case Ball::up:
			by--;
			break;
		case Ball::donw:
			by++;
			break;
		case Ball::left:
			bx--;
			break;
		case Ball::right:
			bx++;
			break;
		case Ball::ul:
			by--;bx--;
			break;
		case Ball::ur:
			by--;bx++;
			break;
		case Ball::dl:
			by++;bx--;
			break;
		case Ball::dr:
			by++;bx++;
			break;
	}
	if(bx<0){
		bx=0;
		if(ball.status!=Ball::right&&ball.status!=Ball::ur&&ball.status!=Ball::dr)
		ball.status=(Ball::enums)-ball.status;
	}
	if(bx>=120){
		bx=119;
		if(ball.status!=Ball::left&&ball.status!=Ball::ul&&ball.status!=Ball::dl)
		ball.status=(Ball::enums)-ball.status;
	}
	if(by<0){
		by=0;
		if(ball.status!=Ball::up&&ball.status!=Ball::ur&&ball.status!=Ball::ul)
		ball.status=(Ball::enums)-ball.status;
	}
	if(by>=60){
		bx=59;
		if(ball.status!=Ball::donw&&ball.status!=Ball::dr&&ball.status!=Ball::dl)
		ball.status=(Ball::enums)-ball.status;
	}
	if(by-wally>=0&&by-wally<=4&&bx<=2){
		ball.status=(Ball::enums)-ball.status;
		if(by-wally==0){
			switch(ball.status){
				case Ball::up:break;
				case Ball::donw:
					ball.status=(Ball::enums)-ball.status;
					break;
				case Ball::left:
					ball.status=Ball::ul;
					break;
				case Ball::right:
					ball.status=Ball::ur;
					break;
				case Ball::ul:break;
				case Ball::ur:break;
				case Ball::dl:
					ball.status=Ball::ul;
					break;
				case Ball::dr:
					ball.status=Ball::ur;
					break;
			}
		}
		if(by-wally==4){
			//..
		}
	}
}

这些代码是检测发生的事件,其中有一部分未完成,为了方便

Output

void Output(){//输出
	ball.out();
	for(int i=0;i

输出球和拍子

代码 

预命令和变量

#include
#include
#include
#include
#include
#include
#include
#include
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
using namespace std;
const char *gamename="Pong";
int GameHz=60;
HWND Gwin;

#define ISRUN 1//...

功能性函数

void gotoxy(int x, int y){
	COORD pos={(short)x,(short)y};
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut,pos);
}

void noedit(){
	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);
}

void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

gotoxy是一个很好的函数,特有用

noedit是禁止快速编译插入模式

另外2个是影藏/显示光标

游戏对象实现

int wally=0,wallwindy=4;

class Ball{
	public:
		int x,y;
		enum enums{
			up=1,donw=-1,left=2,right=-2,
			ul=3,ur=-3,dl=4,dr=-4
		}status;
		void out(){
			gotoxy(x,y);
			cerr<<"○";
		}
		Ball(){
			x=rand()%60;
			y=rand()%30;
			status=left;
		}
}ball;

定义了一个Ball类,一个Ball类对象ball,int变量wally,和宽度

Game类

class Game{
	public:
		bool Running;
		Game(){
			Running=1;
		}
		void GameLoop(){
			while(Running&&ISRUN){
				Input();
				Output();
				Sleep(1000.0/GameHz);
				system("cls");
			}
		}
	private:
		void GameEnd(){//Close
			if(MessageBox(Gwin,"确定要退出吗?",gamename,MB_YESNO)==IDYES){exit(0);}
		}
		void Input(){//检测
			if(GetConsoleWindow()==Gwin){
				//...
				if(kd(VK_ESCAPE)){
					GameEnd();
				}
				if(kd(VK_UP)){
					wally--;
					wally=abs(wally);
				}
				if(kd(VK_DOWN)){
					wally++;
					if(wally>=60){
						wally=59;
					}
				}
				if(kd(107)){
					GameHz++;
				}
				if(kd(109)){
					GameHz--;
				}
			}
			int &bx=ball.x,&by=ball.y;
			switch(ball.status){
				case Ball::up:
					by--;
					break;
				case Ball::donw:
					by++;
					break;
				case Ball::left:
					bx--;
					break;
				case Ball::right:
					bx++;
					break;
				case Ball::ul:
					by--;bx--;
					break;
				case Ball::ur:
					by--;bx++;
					break;
				case Ball::dl:
					by++;bx--;
					break;
				case Ball::dr:
					by++;bx++;
					break;
			}
			if(bx<0){
				bx=0;
				if(ball.status!=Ball::right&&ball.status!=Ball::ur&&ball.status!=Ball::dr)
				ball.status=(Ball::enums)-ball.status;
			}
			if(bx>=120){
				bx=119;
				if(ball.status!=Ball::left&&ball.status!=Ball::ul&&ball.status!=Ball::dl)
				ball.status=(Ball::enums)-ball.status;
			}
			if(by<0){
				by=0;
				if(ball.status!=Ball::up&&ball.status!=Ball::ur&&ball.status!=Ball::ul)
				ball.status=(Ball::enums)-ball.status;
			}
			if(by>=60){
				bx=59;
				if(ball.status!=Ball::donw&&ball.status!=Ball::dr&&ball.status!=Ball::dl)
				ball.status=(Ball::enums)-ball.status;
			}
			if(by-wally>=0&&by-wally<=4&&bx<=2){
				ball.status=(Ball::enums)-ball.status;
				if(by-wally==0){
					switch(ball.status){
						case Ball::up:break;
						case Ball::donw:
							ball.status=(Ball::enums)-ball.status;
							break;
						case Ball::left:
							ball.status=Ball::ul;
							break;
						case Ball::right:
							ball.status=Ball::ur;
							break;
						case Ball::ul:break;
						case Ball::ur:break;
						case Ball::dl:
							ball.status=Ball::ul;
							break;
						case Ball::dr:
							ball.status=Ball::ur;
							break;
					}
				}
				if(by-wally==4){
					//..
				}
			}
		}
		void Output(){//输出
			ball.out();
			for(int i=0;i

Game是一个very very good的封装类,我们将在第二章好好讲讲Game类

主函数

int main(){
	HideCursor();
	noedit();
	Gwin=GetConsoleWindow();
	Game game;
	game.GameLoop();
}

虽然Game是一个very very good的封装类,但程序的入口一定是main/WinMain函数

全部代码

#include
#include
#include
#include
#include
#include
#include
#include
#define kd(VK_NONAME) ((GetAsyncKeyState(VK_NONAME) & 0x8000) ? 1:0)
using namespace std;
const char *gamename="Pong";
int GameHz=60;
HWND Gwin;

#define ISRUN 1//...

void gotoxy(int x, int y){
	COORD pos={(short)x,(short)y};
	HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE);
	SetConsoleCursorPosition(hOut,pos);
}

void noedit(){
	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);
}

void HideCursor(){
	CONSOLE_CURSOR_INFO cur={1,0};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

void ShowCursor(){
	CONSOLE_CURSOR_INFO cur={1,1};
	SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cur);
}

int wally=0,wallwindy=4;

class Ball{
	public:
		int x,y;
		enum enums{
			up=1,donw=-1,left=2,right=-2,
			ul=3,ur=-3,dl=4,dr=-4
		}status;
		void out(){
			gotoxy(x,y);
			cerr<<"○";
		}
		Ball(){
			x=rand()%60;
			y=rand()%30;
			status=left;
		}
}ball;

class Game{
	public:
		bool Running;
		Game(){
			Running=1;
		}
		void GameLoop(){
			while(Running&&ISRUN){
				Input();
				Output();
				Sleep(1000.0/GameHz);
				system("cls");
			}
		}
	private:
		void GameEnd(){//Close
			if(MessageBox(Gwin,"确定要退出吗?",gamename,MB_YESNO)==IDYES){exit(0);}
		}
		void Input(){//检测
			if(GetConsoleWindow()==Gwin){
				//...
				if(kd(VK_ESCAPE)){
					GameEnd();
				}
				if(kd(VK_UP)){
					wally--;
					wally=abs(wally);
				}
				if(kd(VK_DOWN)){
					wally++;
					if(wally>=60){
						wally=59;
					}
				}
				if(kd(107)){
					GameHz++;
				}
				if(kd(109)){
					GameHz--;
				}
			}
			int &bx=ball.x,&by=ball.y;
			switch(ball.status){
				case Ball::up:
					by--;
					break;
				case Ball::donw:
					by++;
					break;
				case Ball::left:
					bx--;
					break;
				case Ball::right:
					bx++;
					break;
				case Ball::ul:
					by--;bx--;
					break;
				case Ball::ur:
					by--;bx++;
					break;
				case Ball::dl:
					by++;bx--;
					break;
				case Ball::dr:
					by++;bx++;
					break;
			}
			if(bx<0){
				bx=0;
				if(ball.status!=Ball::right&&ball.status!=Ball::ur&&ball.status!=Ball::dr)
				ball.status=(Ball::enums)-ball.status;
			}
			if(bx>=120){
				bx=119;
				if(ball.status!=Ball::left&&ball.status!=Ball::ul&&ball.status!=Ball::dl)
				ball.status=(Ball::enums)-ball.status;
			}
			if(by<0){
				by=0;
				if(ball.status!=Ball::up&&ball.status!=Ball::ur&&ball.status!=Ball::ul)
				ball.status=(Ball::enums)-ball.status;
			}
			if(by>=60){
				bx=59;
				if(ball.status!=Ball::donw&&ball.status!=Ball::dr&&ball.status!=Ball::dl)
				ball.status=(Ball::enums)-ball.status;
			}
			if(by-wally>=0&&by-wally<=4&&bx<=2){
				ball.status=(Ball::enums)-ball.status;
				if(by-wally==0){
					switch(ball.status){
						case Ball::up:break;
						case Ball::donw:
							ball.status=(Ball::enums)-ball.status;
							break;
						case Ball::left:
							ball.status=Ball::ul;
							break;
						case Ball::right:
							ball.status=Ball::ur;
							break;
						case Ball::ul:break;
						case Ball::ur:break;
						case Ball::dl:
							ball.status=Ball::ul;
							break;
						case Ball::dr:
							ball.status=Ball::ur;
							break;
					}
				}
				if(by-wally==4){
					//..
				}
			}
		}
		void Output(){//输出
			ball.out();
			for(int i=0;i

后文

本章内我们做了《Pong》这个游戏但仍不完善,我也不会完善,我们将会在之后讲讲这里面的Bug

我是杨某一辰,期待你的关注!

你可能感兴趣的:(c++游戏编程,c++,游戏,c++)