Air combat game (console application) c/c++ implementation

I also learned c++ for half a year, and I used to stay in the console to do some exercises. Recently, I think this is really a near sense of accomplishment, so I want to try to write a simple game, using the brick, flappyAfter training in mini-games such as bird, after consulting books, looking for some network information, I wrote a console application of air combat mini-games with relatively high completion, hoping to provide some direction for other c++ novices who feel confused

Completion of the game:
First look at the main framework of the game:

#include<iostream>
#include<cstdlib>
#include<conio.h>
#include<windows.h>
using namespace std;
//Macro Definition
#define High 15  //Game interface height
#define Width 25 //Game interface width
#define EnemyNum 6 //Enemy number
//global variable
int pos_x,pos_y; //Airplane coordinates
int canvas[High][Width]={0}; //Background canvas, represented by a two-dimensional array
int enemy_x[EnemyNum],enemy_y[EnemyNum]; //The coordinates of the enemy aircraft, because there are multiple enemy aircraft, expressed in a one-dimensional array
int BulletWidth; //Bullet Width for Bullet Function
int EnemySpeed; //Enemy speed for dynamic difficulty
int score; //Score

//Copy Code
//Copy Code

int main(){
    HideCursor();//hide cursor
    startup();//Game Parameter Initialization
    while(1){//Cycle keeps the game going
        show();//Output Game Screen
        UpdateWithoutInput();//Data updates irrelevant to user input
        UpdateWithInput();//Data updates related to user input
    }
    return 0;
}

Most simple game implementations rely on these frameworks. You can also add a function to judge if the game is playing or not, a function to restart the game, and so on. These are left to the reader to implement.

Let's look at the principles and implementation of these functions in sequence.

The first is to hide the cursor function. As a console application, having a cursor blinking on the screen is bound to destroy the game experience, so you need to hide it.Let's see what this function looks like:


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


I don't know the principle of this function. It was copied online. The detailed parsing of windows.h header file can't be found on the internet. It would be great if readers could know something about it.

Then there is the initialization of the game parameters, and the function has no difficulty to understand:

void startup(){
    pos_x=High-1; //x is the ordinate coordinate
    pos_y=Width/2;   //y is a transverse coordinate
    canvas[pos_x][pos_y]=1;  //The corresponding position of the aircraft in the canvas is set to 1, indicating that this position is an aircraft
    for(int i=0;i<EnemyNum;i++){ //Set a random position for each enemy aircraft to appear
        enemy_y[i]=rand()%Width;
        enemy_x[i]=rand()%2;
        canvas[enemy_x[i]][enemy_y[i]]=3; //The corresponding position of the enemy aircraft in the canvas is set to 3, indicating that this position is the enemy aircraft
    }
    score=0;
    BulletWidth=0;
    EnemySpeed=13; //Speed is the refresh interval, so the smaller the speed, the faster
}

Next is the function to output the game picture, which is a big game:

void show(){
    gotoxy(0,0);  //Return cursor of output to upper left corner
    for(int i=0;i<High;i++){      //These two lines are canvas element values
        for(int j=0;j<Width;j++){ //Scan one by one
            if(canvas[i][j]==0) //If the value is 0
                printf(" ");  //Output blank space
            else if(canvas[i][j]==1) //If the value is 1
                printf("*"); //Output*, representing aircraft
            else if(canvas[i][j]==2) //If the value is 2
                printf("|"); //Output |, for bullets
            else if(canvas[i][j]==3) //If the value is 3
                printf("@"); //Output @, indicating enemy aircraft
        }
        printf("\n"); //Scan one line and wrap to start the next
    }
    printf("Score:%3d\n",score); //Output fraction
    Sleep(20); //Stay for 2 milliseconds as refresh frequency
}

Explain the idea of output picture roughly.First, the two-dimensional array is used as the canvas background, where the element value represents the game object on the screen. If the value is 0, it means blank; if it is 1, it means airplane; if it is 2, it means bullet launched by airplane; if it is 3, it means enemy aircraft.The output is then determined by traversing the canvas's two-dimensional array with its values.Then how to achieve the animation effect? When this function is called again, the first line of gotoxy(0,0) will move the output cursor to the upper left corner of the window, and then output the picture again, which will achieve the effect of the elements in it. Gotoxy is not a standard library function, it also needs window.h to write by itself, the specific principle is not concerned, just use copy directly:

void gotoxy(int x,int y){
    HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X=x;
    pos.Y=y;
    SetConsoleCursorPosition(handle,pos);
}

Of course, the animation effect of the game cannot be achieved by the picture output function alone, and data updates in the canvas are needed, so UpdateWithoutInput (); (data updates not related to user input) UpdateWithInput(); (data updates related to user input).First look at the implementation of UpdateWithoutInput():

void UpdateWithoutInput(){
    for(int i=0;i<High;i++){     //These two loops
        for(int j=0;j<Width;j++){//Is Scanning Canvas Elements One by One
            if(canvas[i][j]==2){ //If the element value is 2 (i.e. a bullet), the following data changes occur
                for(int k=0;k<EnemyNum;k++){ //Traverse data about each enemy aircraft
                    if(i==enemy_x[k]&&j==enemy_y[k]){ //If the bullet's horizontal and vertical coordinates are equal to the enemy's
                        score++;  //Bonus
                        if(score<7&&EnemySpeed>2) EnemySpeed=13;//Difficulties in achieving different fractions
                        else if(score>=7&&score<14) EnemySpeed=11;
                        else if(score>=14&&score<21) EnemySpeed=9;
                        else if(score>=21&&score<40) EnemySpeed=7;
                        else if(score>=40&&score<60) EnemySpeed=5;
                        else if(score>=60) EnemySpeed=3;
                        if(score<15) BulletWidth=0; //If the score is less than 15 and the bullet width is 0, then only one bullet
                        else if(score<30&&score>=15) BulletWidth=1;//With a score greater than 15 and less than 30 and a width of 1, there are three bullets
                        else if(score<45&&score>=30) BulletWidth=2;//If the score is greater than 30 and less than 45 and the width is 2, then there are 5 bullets
                        canvas[enemy_x[k]][enemy_y[k]]=0; //Since the coordinates of the bullet and the enemy aircraft coincide, the enemy aircraft is destroyed and the corresponding position becomes blank.
                        enemy_x[k]=rand()%2; //Randomly generate new enemy aircraft's ordinates
                        enemy_y[k]=rand()%Width; //Randomly generate new enemy plane's x-coordinates
                        canvas[enemy_x[k]][enemy_y[k]]=3; //Generate new enemy aircraft
                        canvas[i][j]=0; //Bullets disappear (in fact, they don't disappear, and I don't know why)
                    }
                }
                canvas[i][j]=0;//Blank the bullet's original position
                if(i>0)
                    canvas[i-1][j]=2;//Generate new position data for bullets and animate with output picture function
            }
        }
    }
    static int speed=0;             //These two sentences may be difficult to understand and are set to static variables to prevent speed s from disappearing directly beyond the scope and from updating the data
    if(speed<EnemySpeed) speed++;   //The purpose of setting speed is to update the position data of the enemy aircraft moving in the canvas only when speed is added equal to EnemySpeed, so as to animate the enemy aircraft moving slowly.
    for(int k=0;k<EnemyNum;k++){ //Handle each enemy aircraft
        if(pos_x==enemy_x[k]&&pos_y==enemy_y[k]){ //The game failed because the enemy plane coincided with the plane's position
            printf("You Lose!\n");
            Sleep(3000);
            system("pause");
            exit(0);    
        }
        if(enemy_x[k]>High){ //The enemy plane flew out of range
            canvas[enemy_x[k]][enemy_y[k]]=0; //Leave the original position blank
            enemy_y[k]=rand()%Width; //Generate new enemy coordinates
            enemy_x[k]=rand()%2;
            canvas[enemy_x[k]][enemy_y[k]]=3; //Generate new enemy aircraft
            score--; //Deductions
        }
        if(speed==EnemySpeed){  //speed equals EnemySpeed, so you can update the position data of the enemy aircraft
            for(int i=0;i<EnemyNum;i++){
                canvas[enemy_x[i]][enemy_y[i]]=0;
                enemy_x[i]++; //Vertical coordinates plus 1, move forward
                speed=0;
                canvas[enemy_x[i]][enemy_y[i]]=3;
            }
        }
    }
}

This function can be said to be the main body, the output picture function with data updates can achieve simple animation effect, many small games can be achieved in this way, if you can understand this system then with the notes should be able to understand, or suggest that you tap once to deepen your understanding

Then it's about the user:

void UpdateWithInput(){
    char input;//Enter Characters
    if(_kbhit()){ //If you press the keyboard
        input=_getch();//Read characters entered by keyboard
        if(input=='a'){ //If the character entered is a, move to the left. The following branch classes are the same
            canvas[pos_x][pos_y]=0;
            pos_y--;
            canvas[pos_x][pos_y]=1;
        }
        else if(input=='w'){
            canvas[pos_x][pos_y]=0;
            pos_x--;
            canvas[pos_x][pos_y]=1;
        }
        else if(input=='s'){
            canvas[pos_x][pos_y]=0;
            pos_x++;
            canvas[pos_x][pos_y]=1;
        }
        else if(input=='d'){
            canvas[pos_x][pos_y]=0;
            pos_y++;
            canvas[pos_x][pos_y]=1;
        }
        else if(input==' '){  //If the Spacebar is read in
            int l=pos_y-BulletWidth; //Left end of bullet flow
            int r=pos_y+BulletWidth; //Right end of bullet flow for (int k=l; k<=r; k++)//Output a row of bullets
                canvas[pos_x-1][k]=2;
        }
    }
}

It's a very simple passage that doesn't explain much

The following is the complete code:

#include<iostream>
#include<cstdlib>
#include<conio.h>
#include<windows.h>
using namespace std;

#define High 15  
#define Width 25
#define EnemyNum 6

int pos_x,pos_y;
int canvas[High][Width]={0};
int enemy_x[EnemyNum],enemy_y[EnemyNum];
int BulletWidth;
int EnemySpeed;
int score;

void gotoxy(int x,int y){
    HANDLE handle=GetStdHandle(STD_OUTPUT_HANDLE);
    COORD pos;
    pos.X=x;
    pos.Y=y;
    SetConsoleCursorPosition(handle,pos);
}
void HideCursor(){
    CONSOLE_CURSOR_INFO cursor_info={1,0};
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
void startup(){
    pos_x=High-1;
    pos_y=Width/2;
    canvas[pos_x][pos_y]=1;
    for(int i=0;i<EnemyNum;i++){
        enemy_y[i]=rand()%Width;
        enemy_x[i]=rand()%2;
        canvas[enemy_x[i]][enemy_y[i]]=3;
    }
    score=0;
    BulletWidth=0;
    EnemySpeed=13;
}
void show(){
    gotoxy(0,0);
    for(int i=0;i<High;i++){
        for(int j=0;j<Width;j++){
            if(canvas[i][j]==0)
                printf(" ");
            else if(canvas[i][j]==1)
                printf("*");
            else if(canvas[i][j]==2)
                printf("|");
            else if(canvas[i][j]==3)
                printf("@");
        }
        printf("\n");
    }
    printf("Score:%3d\n",score);
    Sleep(20);
}
void UpdateWithoutInput(){
    for(int i=0;i<High;i++){
        for(int j=0;j<Width;j++){
            if(canvas[i][j]==2){
                for(int k=0;k<EnemyNum;k++){
                    if(i==enemy_x[k]&&j==enemy_y[k]){
                        score++;
                        if(score<7&&EnemySpeed>2) EnemySpeed=13;
                        else if(score>=7&&score<14) EnemySpeed=11;
                        else if(score>=14&&score<21) EnemySpeed=9;
                        else if(score>=21&&score<40) EnemySpeed=7;
                        else if(score>=40&&score<60) EnemySpeed=5;
                        else if(score>=60) EnemySpeed=3;
                        if(score<15) BulletWidth=0;
                        else if(score<30&&score>=15) BulletWidth=1;
                        else if(score<45&&score>=30) BulletWidth=2;
                        canvas[enemy_x[k]][enemy_y[k]]=0;
                        enemy_x[k]=rand()%2;
                        enemy_y[k]=rand()%Width;
                        canvas[enemy_x[k]][enemy_y[k]]=3;
                        canvas[i][j]=0;
                    }
                }
                canvas[i][j]=0;
                if(i>0)
                    canvas[i-1][j]=2;
            }
        }
    }
    static int speed=0;
    if(speed<EnemySpeed) speed++;
    for(int k=0;k<EnemyNum;k++){
        if(pos_x==enemy_x[k]&&pos_y==enemy_y[k]){
            printf("You Lose!\n");
            Sleep(3000);
            system("pause");
            exit(0);    
        }
        if(enemy_x[k]>High){
            canvas[enemy_x[k]][enemy_y[k]]=0;
            enemy_y[k]=rand()%Width;
            enemy_x[k]=rand()%2;
            canvas[enemy_x[k]][enemy_y[k]]=3;
            score--;
        }
        if(speed==EnemySpeed){
            for(int i=0;i<EnemyNum;i++){
                canvas[enemy_x[i]][enemy_y[i]]=0;
                enemy_x[i]++;
                speed=0;
                canvas[enemy_x[i]][enemy_y[i]]=3;
            }
        }
    }
}
void UpdateWithInput(){
    char input;
    if(_kbhit()){
        input=_getch();
        if(input=='a'){
            canvas[pos_x][pos_y]=0;
            pos_y--;
            canvas[pos_x][pos_y]=1;
        }
        else if(input=='w'){
            canvas[pos_x][pos_y]=0;
            pos_x--;
            canvas[pos_x][pos_y]=1;
        }
        else if(input=='s'){
            canvas[pos_x][pos_y]=0;
            pos_x++;
            canvas[pos_x][pos_y]=1;
        }
        else if(input=='d'){
            canvas[pos_x][pos_y]=0;
            pos_y++;
            canvas[pos_x][pos_y]=1;
        }
        else if(input==' '){
            int l=pos_y-BulletWidth;
            int r=pos_y+BulletWidth;
            for(int k=l;k<=r;k++)
                canvas[pos_x-1][k]=2;
        }
    }
}

int main(){
    HideCursor();
    startup();
    while(1){
        show();
        UpdateWithoutInput();
        UpdateWithInput();
    }
    return 0;
}

There should be other updates to the game in the future, and perhaps the game will be updated with the graphics library

PS: Recommended to read "C Language Course Design and Game Development Practice Tutorial", if you do not know what C Language can do, read this book!

0 original articles published, 0 praised, 32 visits
Private letter follow

Tags: less Windows C network

Posted on Wed, 11 Mar 2020 23:40:32 -0400 by GreenMarch