实现步骤:
- 一块板的上升
- 多块随机板的上升
- 小人随着板上升
- 小人的左右移动
- 小人的重力感下落
- 死亡的判断
- 记录分数
- 随着分数增加难度上升
程序中的难点:
(1)重力加速度的实现:
精髓就是把小人自由下落的运动单独分离出来处理。
首先看我第一次小人以固定速度下落的代码:
这时小人的下落很不自然,像是直接瞬间从一个高度掉落的另一个高度
#include <iostream>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
using namespace std;
#define High 25 // 游戏画面尺寸
#define Width 40
struct node{
int left;
int right;
int Pos_Y;
int center;
node(){
left=0;
right=0;
Pos_Y=High-1;
center=0;
}
};
// 全局变量
int canvas[High][Width]={0};
int ban_len;//第一块板的长度
int ban_posX,ban_posY;//第一块板的中心初始位置
int boy_posX,boy_posY;//小人的位置
int ban_speed;//第一块板子上升的速度
int boy_speed;//小人的重力加速度
node ban[3];//多块随机板(每行三个)
int timer;//板子出现的时间间隔
double score;//小人的分数(每跳到一个新的板子时分数加一)
void gotoxy(int a, int b) //光标移动到(x,y)位置
{
int xx=0x0b;
HANDLE hOutput;
COORD loc;
loc.X =a;
loc.Y=b;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, loc);
return;
}
void startup() // 数据初始化
{
srand(time(NULL));
int i,j;
ban_len=5;//板的长度
ban_posX=Width/2;
ban_posY=High-1;//板的中心位置
boy_posX=ban_posX;
boy_posY=ban_posY-1;//小人的初始位置
canvas[boy_posY][boy_posX]=1;//小人在第一块板子的正上方
int left=ban_posX-ban_len/2,right=ban_posX+ban_len/2;
ban_speed=1;
boy_speed=1;
timer=5;
score=0;
for(j=left;j<=right;j++){
canvas[ban_posY][j]=2;//第一块板子
}
for(i=0;i<High;i++){//周围的墙壁
canvas[i][0]=-1;
canvas[i][Width-1]=-1;
}
for(j=1;j<Width-1;j++){
canvas[0][j]=-2;//顶部的刺刀
}
}
void show() // 显示画面
{
gotoxy(0,0); // 光标移动到原点位置,以下重画清屏
int i,j;
for(i=0;i<High;i++){
for(j=0;j<Width;j++){
if(canvas[i][j]==0){
cout<<" ";
}else if(canvas[i][j]==-1){
cout<<"|";
}else if(canvas[i][j]==-2){
cout<<"T";
}else if(canvas[i][j]==2){
cout<<"_";
}else if(canvas[i][j]==1){
cout<<"O";
}
}
cout<<"\n";
}
cout<<"\n";
cout<<"score:"<<score<<"\n";
}
void updateWithoutInput() // 与用户输入无关的更新
{
int i=0,j=0;
srand(time(NULL));
for(i=0;i<High;i++){
for(j=0;j<Width;j++){
//板子向上移动
if(canvas[i][j]==2){
canvas[i][j]=0;
if(i>1){//板子触碰到顶部时消失
canvas[i-ban_speed][j]=2;
}
}
if(canvas[i][j]==1){//小人的运动
canvas[i][j]=0;
if(boy_posY>1&&boy_posY<High-1){//小人碰到刺刀或者掉入深渊游戏失败
if(canvas[i+1][j]!=2){//如果小人不站在板子上会随自身重力下降
boy_posY+=boy_speed;
score+=0.25;//在游戏中由于有speed和timer来控制板子出现的时间,所以相邻两层板子的间隔不止1个,故加的分数不是1
}else{//如果小人站在板子上会随板子上升
boy_posY-=ban_speed;
}
canvas[boy_posY][j]=1;
}else{//碰到刺刀或者掉入深渊游戏失败
cout<<"游戏失败"<<"\n";
Sleep(1000);
exit(0);
}
}
}
}
static int speed=0;
if(speed==timer){
for(j=0;j<3;j++){
ban[j].center=rand()%10+2+j*10;
ban[j].left=ban[j].center-rand()%4;
ban[j].right=ban[j].center+rand()%4;
for(i=ban[j].left;i<=ban[j].right;i++){
if(i>0&&i<Width-1)
canvas[ban[j].Pos_Y][i]=2;
}
}
speed=0;
}else{
speed++;
}
Sleep(150);
}
void updateWithInput() // 与用户输入有关的更新
{
char input;
if(kbhit()){
input=getch();
if(input=='a'){//小人左移
canvas[boy_posY][boy_posX]=0;
boy_posX-=1;
canvas[boy_posY][boy_posX]=1;
}else if(input=='d'){//小人右移
canvas[boy_posY][boy_posX]=0;
boy_posX+=1;
canvas[boy_posY][boy_posX]=1;
}
}
}
int main()
{
startup(); // 数据初始化
while (1) // 游戏循环执行
{
gotoxy(0,0);
show(); // 显示画面
updateWithoutInput(); // 与用户输入无关的更新
updateWithInput(); // 与用户输入有关的更新
}
return 0;
}
再看第二次实现的带有重力加速度的下落(这次只实现到了第五步,完整的在最下面):
这次不仅改良了下落的缺点,为了减少全局变量,很多精灵的属性都只用数组frame中的值代替了。
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#define high 30
#define wide 40
//1为人,2为板,3为边界,4为上边界的锯齿//
void starup();
void show();
void updateWithoutinput();
void updateWithinput();
void gotoxy(int a, int b); //清屏//
int frame[high][wide];
int i,j;
int radius;
int interval_static;
int interval_1,interval_2; //首先是可以用于调控新板生成的频率,其次可以让小球下落与整个画面的上升产生频率的落差感,造成重力的假象//
int board_1,board_2,board_3;
int ball;//小人的位置
int judge=0; //用于跳出两层循环的变量//
char ch;
int main()
{
starup();
while(1)
{
gotoxy(0,0);
show();
updateWithoutinput();
updateWithinput();
}
}
void starup()
{
//srand(time(NULL));
radius=2;
interval_static=20;
interval_1=0;
interval_2=0;
ball=wide/2;
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (j==wide-1)//右边的墙
{
frame[i][j]=3;
}
if (j==0)//左边的墙
{
frame[i][j]=3;
}
if (i==0&&j!=0&&j!=wide-1)//顶部的刺刀
{
frame[i][j]=4;
}
if (i==high-1&&j>(wide/2-3)&&j<(wide/2+3))//第一块板子
{
frame[i][j]=2;
}
if (i==high-2&&j==ball)//小人的初始位置
{
frame[i][j]=1;
}
}
}
}
void show()
{
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==2)
{
printf ("_");
}
else if (frame[i][j]==3)
{
printf ("|");
}
else if (frame[i][j]==4)
{
printf ("T");
}
else if (frame[i][j]==0)
{
printf (" ");
}
else if (frame[i][j]==1)
{
printf ("O");
}
}
printf ("\n");
}
}
void updateWithoutinput()
{
judge=0;
//srand(time(NULL));
if (interval_2==interval_static) //只要板球上升,和出现新板,小球下落的刷新频率不同,就能实现重力的落差感//
{
interval_2=0; //计时清零//
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1&&frame[i+1][j]==2)
{
frame[i][j]=0;
frame[i-1][j]=1;
}
else if (frame[i][j]==2&&i>1)
{
frame[i-1][j]=2;
frame[i][j]=0;
}
else if (frame[i][j]==2&&i==1)
{
frame[i][j]=0;
}
}
}
}
else
{
interval_2=interval_2+4;
}
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1&&frame[i+1][j]==0)
{
frame[i][j]=0;
frame[i+1][j]=1;
judge=1;
}
}
if (judge)
{
break;
}
}
if (interval_1==interval_static) //频率制造器//
{
interval_1=0; //计时清零//
board_1=rand()%13+1;
board_2=rand()%13+13;
board_3=rand()%13+24;
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (i==high-1&&((j>=board_1-radius)&&(j<=board_1+radius)&&j>0||(j>=board_2-radius)&&(j<=board_2+radius)||(j>=board_3-radius)&&(j<=board_3+radius)))
{
frame[i][j]=2;
}
}
}
}
else
{
interval_1=interval_1+1;
}
}
void updateWithinput()
{
if (kbhit())
{
ch=getch();
if (ch=='A')
{
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1)
{
frame[i][j]=0;
frame[i][j-1]=1;
break;
}
}
}
}
if (ch=='D')
{
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1)
{
frame[i][j]=0;
frame[i][j+1]=1;
break; //加入break的原因是不加入的话,循环会一直将1往后推导致这一排全为0了//
}
}
}
}
}
}
void gotoxy(int a, int b)
{
int xx=0x0b;
HANDLE hOutput;
COORD loc;
loc.X =a;
loc.Y=b;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, loc);
return;
}
(2)还有就是随分数增加难度提升
其实就是加一个分数的判断,随着指定分数到达后就增加板子更新的速率interval_1和上升的速率interval_2,其本质还是增加循环开启的频率,下面是最完整的代码
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <windows.h>
#include <time.h>
#define high 25
#define wide 40
void starup();
void show();
void updateWithoutinput();
void updateWithinput();
void gotoxy(int a, int b);
int frame[high][wide]; //1为人,2为板,3为边界,4为上边界的锯齿//
int i,j;
int radius;
int interval_static;
int interval_1,interval_2; //首先是可以用于调控新板生成的频率,其次可以让小球下落与整个画面的上升产生频率的落差感,造成重力的假象//
int board_1,board_2,board_3;
int ball;
int judge=0; //用于跳出两层循环的变量//
int score;
int turn_1,turn_2; //刷新木板上升的中间量
char ch;
char input;
int main()
{
starup();
printf ("温馨提示:\nA向左,D向右\n难度会不断增加\n按回车键继续");
scanf ("%c", &input);
while(1)
{
gotoxy(0,0);
show();
updateWithoutinput();
updateWithinput();
}
}
void starup()
{
srand(time(NULL));
radius=2;
score=0;
turn_1=1;
turn_2=4;
interval_static=64;
interval_1=0;
interval_2=0;
ball=wide/2;
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (j==wide-1)
frame[i][j]=3;
if (j==0)
frame[i][j]=3;
if (i==0&&j!=0&&j!=wide-1)
frame[i][j]=4;
if (i==high-1&&j>(wide/2-3)&&j<(wide/2+3))
frame[i][j]=2;
if (i==high-2&&j==ball)
frame[i][j]=1;
}
}
}
void show()
{
gotoxy(0,0);
for (i=0;i<high+1;i++)
{
for (j=0;j<wide;j++)
{
if (i==high)
{
printf ("score:%d", score);
break;
}
if (frame[i][j]==2)
printf ("_");
else if (frame[i][j]==3)
printf ("|");
else if (frame[i][j]==4)
printf ("T");
else if (frame[i][j]==0)
printf (" ");
else if (frame[i][j]==1)
printf ("O");
}
printf ("\n");
}
}
void updateWithoutinput()
{
judge=0;
srand(time(NULL));
if (score>=10&&turn_1==1&&turn_2==4)
{
interval_1=0;
interval_2=0;
turn_1=2;
turn_2=8;
}
if (score>=25&&turn_1==2&&turn_2==8)
{
interval_1=0;
interval_2=0;
turn_1=4;
turn_2=16;
}
if (score>=50&&turn_1==4&&turn_2==16) //增加一个难度系数//
{
interval_1=0;
interval_2=0;
turn_1=4;
turn_2=32;
}
for (i=0;i<high;i++) //判断游戏结束//
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1&&(i==1||i==high-1))
{
system("cls");
printf ("game over!\nscore:%d", score);
exit(0);
}
}
}
if (interval_2==interval_static) //木板上升部分以及小球上升部分//
{
interval_2=0; //计时清零//
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1&&frame[i+1][j]==2)
{
frame[i][j]=0;
frame[i-1][j]=1;
}
else if (frame[i][j]==2&&i>1)
{
frame[i-1][j]=2;
frame[i][j]=0;
}
else if (frame[i][j]==2&&i==1)
{
frame[i][j]=0;
}
}
}
}
else
interval_2=interval_2+turn_2;
for (i=0;i<high;i++) //小人下落部分//
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1&&frame[i+1][j]==0)
{
score++; //每下落一层分数加1//
frame[i][j]=0;
frame[i+1][j]=1;
judge=1;
}
}
if (judge)
break;
}
if (interval_1==interval_static) //刷新木板部分//
{
interval_1=0; //计时清零//
board_1=rand()%13+1;
board_2=rand()%13+13;
board_3=rand()%13+24;
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (i==high-1&&((j>=board_1-radius)&&(j<=board_1+radius)&&j>0||(j>=board_2-radius)&&(j<=board_2+radius)||(j>=board_3-radius)&&(j<=board_3+radius)))
{
frame[i][j]=2;
}
}
}
}
else
interval_1=interval_1+turn_1;
}
void updateWithinput()
{
if (kbhit())
{
ch=getch();
if (ch=='a')
{
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1)
{
frame[i][j]=0;
frame[i][j-1]=1;
break;
}
}
}
}
if (ch=='d')
{
for (i=0;i<high;i++)
{
for (j=0;j<wide;j++)
{
if (frame[i][j]==1)
{
frame[i][j]=0;
frame[i][j+1]=1;
break; //加入break的原因是不加入的话,循环会一直将1往后推导致这一排全为0了
}
}
}
}
}
}
void gotoxy(int a, int b)
{
int xx=0x0b;
HANDLE hOutput;
COORD loc;
loc.X =a;
loc.Y=b;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, loc);
return;
}