《Pong》是什么?
《Pong》是一款游戏,内容简单,只有一个拍子和球
游戏循环和Game类
游戏循环
游戏是需要不断更新界面的,这种更新叫做游戏循环,把游戏封装成一个类就是Game类
Game类
源码奉上:
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<fstream>
#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<wallwindy;i++){
gotoxy(0,wally+i);
cerr<<"■ ";
}
}
输出球和拍子
代码
预命令和变量
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<fstream>
#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<wallwindy;i++){
gotoxy(0,wally+i);
cerr<<"■ ";
}
}
};
Game是一个very very good的封装类,我们将在第二章好好讲讲Game类
主函数
int main(){
HideCursor();
noedit();
Gwin=GetConsoleWindow();
Game game;
game.GameLoop();
}
虽然Game是一个very very good的封装类,但程序的入口一定是main/WinMain函数
全部代码
#include<windows.h>
#include<stdlib.h>
#include<stdio.h>
#include<unistd.h>
#include<math.h>
#include<string.h>
#include<iostream>
#include<fstream>
#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<wallwindy;i++){
gotoxy(0,wally+i);
cerr<<"■ ";
}
}
};
int main(){
HideCursor();
noedit();
Gwin=GetConsoleWindow();
Game game;
game.GameLoop();
}
后文
本章内我们做了《Pong》这个游戏但仍不完善,我也不会完善,我们将会在之后讲讲这里面的Bug
我是杨某一辰,期待你的关注!