Foreword: The full-text code imitates the game code idea developed by programmer rock. If you want to make step-by-step production according to the video, you can directly go to station b to search. The full-text code is mainly divided into two parts, one is the complete version of the development code (the blogger made it step by step according to the video, and the materials are all from the programmer rock); the other is the reason why the blogger considers his own level. The weakening modification is carried out on the basis of the source code, and the blogger will mention the places that can be modified later, and the material is manually deducted by the blogger ps, which will be described in detail in the following article.
Table of contents
1. Library and macro compilation and some variable settings
2. The init() function is used as the game initialization
3. The creatobstacle() function creates obstacles
4. checkhit() function detects player collision
Five. The fly() function realizes the data update of the picture
6. The updata() function renders the game background
7. The updataren() function performs character image rendering
10. The anjian() function handles user keystroke reading
11. The updateEnemy() function handles mob rendering
12. The updatablood() function renders blood bars
Thirteen.updatascore() function handles score rendering
Fourteen. checkover() function to determine the end
15. checkscore() function for score update
16. checkwin() function detects success
Seventeen.drawblood() function is used to draw blood bars
Next enter the text
full version
1. Library and macro compilation and some variable settings
#include<stdio.h> #include<graphics.h> #include<conio.h> #include"tools.h" #include<vector> using namespace std; #define WHIDE 1012 #define HEIGHT 396 #define OBSTACLE_COUNT 10 #define win 20 //win score //triple loop IMAGE imgbgs[3]; int bgx[3];//The x coordinate of the background image int bgspeed[3] = { 1,2,4 }; IMAGE imgbgsren[12]; int renx;//Character abscissa int reny;//Character ordinate int renindex;//The picture frame of the player running int jumpmax;//character jump height bool renjump;//Determine whether the character has jumped int rendownspeed;//decline bool updata;//Picture Refresh Switch int blood;//Character HP int score;//Fraction //IMAGE imgTortoise;//mob 1 //int torToiseX;//x coordinate of mob 1 //int torToiseY; //bool torToiseXExist;//Whether there is mob 1 in the current window typedef enum { //enumerated type guai1, guai2, zhu1, zhu2, zhu3, zhu4, //Blame 1 is 0, blame 2 is 1 sum //sum to indicate how many monsters there are in total }obstacle_type; vector<vector<IMAGE>>obstacleimgs;//Define a variable two-dimensional array, the row represents which kind of obstacle, and the column represents the image of the obstacle typedef struct obstacle {//Obstacle Encapsulation obstacle_type type;//Obstacle type int imgindex;//current picture number int x, y; //The x,y coordinates of the obstacle int speed;//speed int power;//Obstacle lethality (commonly known as how much blood is deducted) bool exist;//Determine whether an obstacle exists bool hit;//Judging whether to collide bool passed;//Indicate whether to pass }obstacle_t; obstacle_t obstacles[OBSTACLE_COUNT];//Build a pool directly to see how many obstacles there are int lastobindex; //The sequence number of the last obstacle //people squatting IMAGE imgrendown[2]; bool rendown;//Character squat judgment //digital material IMAGE imgsz[10];
2. The init() function is used as the game initialization
//game initialization void init() { //Create game window initgraph(WHIDE, HEIGHT, EX_SHOWCONSOLE);//show console //Load background resources char name[64]; for (int i = 0; i < 3; i++) { sprintf(name, "res/bg%03d.png", i + 1); loadimage(&imgbgs[i], name); } //Load character frame picture (running) for (int i = 0; i < 12; i++) { sprintf(name, "res/hero%d.png", i + 1); loadimage(&imgbgsren[i], name); } //Set the player's initial position, it should not change afterwards renx = WHIDE / 2 - imgbgsren[0].getwidth() / 2; reny = 345 - imgbgsren[0].getheight(); renindex = 0; renjump = false;//The character does not jump at the beginning jumpmax = reny - 120; rendownspeed = -4;//The rate of decline blood = 100; //Load mobs 1 //loadimage(&imgTortoise, "res/t2.png"); //torToiseXExist = false;//mob 1 initialization //torToiseY = 345 - imgTortoise.getheight()+5; IMAGE imgguai1; loadimage(&imgguai1, "res/t2.png"); vector<IMAGE>boxguai1;//A container is an array boxguai1.push_back(imgguai1);//Then put the one-dimensional array into the two-dimensional array obstacleimgs.push_back(boxguai1); //Next load mobs 2 IMAGE imagguai2; vector<IMAGE> boxguai2; for (int i = 0; i < 6; i++) { sprintf(name, "res/p%d.png", i + 1); loadimage(&imagguai2, name); boxguai2.push_back(imagguai2); } obstacleimgs.push_back(boxguai2); //Initialize the obstacle pool for (int i = 0; i < OBSTACLE_COUNT; i++) { obstacles[i].exist = false; } //Load squat material loadimage(&imgrendown[0], "res/d1.png"); loadimage(&imgrendown[1], "res/d2.png"); rendown = false; //Obstacles (column animation) IMAGE imgH; for (int i = 0; i < 4; i++) { vector<IMAGE>imgzhu; sprintf(name, "res/h%d.png", i + 1); loadimage(&imgH, name, 63, 260, true); //Zoom while recording imgzhu.push_back(imgH); obstacleimgs.push_back(imgzhu); } //Preload sound effects preLoadSound("res/hit.mp3"); //This thing is the external interface mciSendString("play res/bg.mp3 repeat", 0, 0, 0); //Background music lastobindex = -1; score = 0; //Load digital pictures for (int i = 0; i < 10; i++) { sprintf(name, "res/sz/%d.png", i); loadimage(&imgsz[i], name); } }
3. The creatobstacle() function creates obstacles
void creatobstacle() { int i; for (i = 0; i < OBSTACLE_COUNT; i++) { if (!obstacles[i].exist) { break; } } if (i >= OBSTACLE_COUNT) { return; } obstacles[i].exist = true; obstacles[i].hit = false; obstacles[i].imgindex = 0; obstacles[i].type = (obstacle_type)(rand() % 3);//forced conversion if (lastobindex >= 0 && obstacles[lastobindex].type >= zhu1 && obstacles[lastobindex].type <= zhu4 && obstacles[i].type == guai2 && obstacles[lastobindex].x > (WHIDE - 500)) { obstacles[i].type = guai1; } lastobindex = i; if (obstacles[i].type == zhu1) { //Optimize the appearance of obstacles obstacles[i].type = (obstacle_type)(zhu1 + rand() % 4); } obstacles[i].x = WHIDE; obstacles[i].y = 350 - obstacleimgs[obstacles[i].type][0].getheight(); if (obstacles[i].type == guai1) { obstacles[i].speed = 0; obstacles[i].power = 5; //Mob 1 damage } else if (obstacles[i].type == guai2) { obstacles[i].speed = 4; obstacles[i].power = 20; } else if (obstacles[i].type >= zhu1 && obstacles[i].type <= zhu4) { obstacles[i].speed = 0; obstacles[i].power = 20; obstacles[i].y = 0; } obstacles[i].passed = false; }
4. checkhit() function detects player collision
//Player Collision Detection void checkhit() { for (int i = 0; i < OBSTACLE_COUNT; i++) { //For a rectangle, you only need to know two opposite corners to determine if (obstacles[i].exist && obstacles[i].hit == false) { //Use open source code to detect whether two rectangles intersect int alx, aly, a2x, a2y; int off = 30; if (!rendown) { //If people are not squatting, they are running or jumping alx = renx + off; aly = reny + off; a2x = renx + imgbgsren[renindex].getwidth() - off; a2y = reny + imgbgsren[renindex].getheight(); } else { alx = renx + off; aly = 345 - imgrendown[renindex].getheight(); a2x = renx + imgrendown[renindex].getwidth() - off; a2y = 345; } IMAGE img = obstacleimgs[obstacles[i].type][obstacles[i].imgindex];//The first picture of the first obstacle int blx = obstacles[i].x + off; int bly = obstacles[i].y + off; int b2x = obstacles[i].x + img.getwidth() - off; int b2y = obstacles[i].y + img.getheight() - 10; if (rectIntersect(alx, aly, a2x, a2y, blx, bly, b2x, b2y)) {//Collision blood -= obstacles[i].power; printf("remaining blood %d\n", blood); playSound("res/hit.mp3"); obstacles[i].hit = true; } } } }
Five. The fly() function realizes the data update of the picture
//picture mobile void fly() { for (int i = 0; i < 3; i++) { bgx[i] -= bgspeed[i]; if (bgx[i] < -WHIDE) bgx[i] = 0; } //Character Jump Realization if (renjump) { //What the hell are you changing, the y coordinates, why can’t you know anything, are you a baby? if (reny < jumpmax) {//The first time is to take off, so it starts to be negative, and the next step must be to fall, so it can be positive rendownspeed = 4; } reny += rendownspeed; if (reny > 345 - imgbgsren[0].getheight()) {//has fallen to the ground renjump = false; rendownspeed = -4; } } else if (rendown) { static int count = 0; int delays[2] = { 4,32 }; //Want to control the station time of the two pictures separately count++; if (count >= delays[renindex]) { //The station time is different count = 0; renindex++; if (renindex >= 2) { renindex = 0; rendown = false; } } } else {//neither jump nor squat renindex = (renindex + 1) % 12; } //create obstacles static int frameCount = 0;//Static variables are permanently valid //static int torToiseFre = 100; static int enemyFre = 50; frameCount++; if (frameCount > enemyFre) { frameCount = 0; //if (!torToiseXExist) { //torToiseXExist = true; //torToiseX = WHIDE; //enemyFre = 200 + rand() % 301; //} enemyFre = 50 + rand() % 50; creatobstacle(); } //update coordinates for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist) { obstacles[i].x -= obstacles[i].speed + bgspeed[2]; if (obstacles[i].x < -obstacleimgs[obstacles[i].type][0].getheight() * 2) { obstacles[i].exist = false; } int len = obstacleimgs[obstacles[i].type].size(); obstacles[i].imgindex = (obstacles[i].imgindex + 1) % len; } } //if (torToiseXExist) { //Set the movement of mob 1 //torToiseX -= bgspeed[2]; //if (torToiseX < -imgTortoise.getwidth()) { //torToiseXExist = false; //} //} checkhit(); }
The above creatobstacle function and checkhit function are applied here
6. The updata() function renders the game background
//Render the game background void updatabg() { putimagePNG2(bgx[0], 0, &imgbgs[0]); putimagePNG2(bgx[1], 119, &imgbgs[1]); putimagePNG2(bgx[2], 330, &imgbgs[2]); }
7. The updataren() function performs character image rendering
//character image rendering void updataren() { if (!rendown) { putimagePNG2(renx, reny, &imgbgsren[renindex]); } else { int y = 345 - imgrendown[renindex].getheight(); putimagePNG2(renx, y, &imgrendown[renindex]); } }
8. Character jump switch
//character jump switch void jump() { renjump = true; updata = true; //Character frame waiting (just don't wait for 30ms, just refresh directly) }
Nine. Character squat switch
//Character squat switch void down() { rendown = true; updata = true; renindex = 0; }
10. The anjian() function handles user keystroke reading
//Handle user keystroke input void anjian() { char ch; if (kbhit()) { //Determine whether there is input ch = getch();//getch reads characters directly, there is no buffer if (ch == ' ') { jump(); } else if (ch == 'b') { down(); } } }
11. The updateEnemy() function handles mob rendering
void updateEnemy() { //render mobs 1 //if (torToiseXExist) { // putimagePNG2(torToiseX, torToiseY, WHIDE, &imgTortoise); //} for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist) { putimagePNG2(obstacles[i].x, obstacles[i].y, WHIDE, &obstacleimgs[obstacles[i].type][obstacles[i].imgindex]); } } }
12. The updatablood() function renders blood bars
//render health bar void updatablood() { drawblood(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, blood / 100.0); }
Thirteen.updatascore() function handles score rendering
void updatascore() { char str[3]; sprintf(str, "%d", score); int x = 20; int y = 25; for (int i = 0; str[i] != '\0'; i++) { int sz = str[i] - '0'; putimagePNG(x, y, &imgsz[sz]); x = x + imgsz[sz].getwidth() + 5; } }
Fourteen. checkover() function to determine the end
void checkover() { if (blood <= 0) { loadimage(0, "res/over.png"); FlushBatchDraw(); mciSendString("stop res/bg.mp3", 0, 0, 0); system("pause"); //Ready to set a button to start the next set if (getch() == 'w') { blood = 100; score = 0; mciSendString("play res/bg.mp3 repeat", 0, 0, 0); //Background music } } }
15. checkscore() function for score update
void checkscore() { for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist && obstacles[i].passed == false && obstacles[i].x + obstacleimgs[obstacles[i].type][0].getwidth() < renx && obstacles[i].hit == false) { score++; obstacles[i].passed = true; printf("score=%d\n", score); } } }
16. checkwin() function detects success
void checkwin() { if (score >= win) { FlushBatchDraw(); mciSendString("play res/win.mp3", 0, 0, 0); Sleep(2000); loadimage(0, "res/win.png"); FlushBatchDraw(); system("pause"); if (getch() == 'w') { //Restart mciSendString("stop res/win.mp3", 0, 0, 0); blood = 100; score = 0; ("play res/bg.mp3 repeat", 0, 0, 0); //Background music } } }
Seventeen.drawblood() function is used to draw blood bars
//draw blood void drawblood(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) { LINESTYLE lineStyle; getlinestyle(&lineStyle); int lineColor = getlinecolor(); int fileColor = getfillcolor(); if (percent < 0) { percent = 0; } setlinecolor(BLUE); setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth); setfillcolor(emptyColor); fillrectangle(x, y, x + width, y + height); setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0); setfillcolor(fillColor); setlinecolor(fillColor); if (percent > 0) { fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth); } setlinecolor(lineColor); setfillcolor(fillColor); setlinestyle(&lineStyle); }
Eighteen.main() main program
int main() { init(); int time = 0; loadimage(0, "res/over.png"); if (getch() == ' ') { while (1) { anjian(); time += getDelay();//background frame wait if (time > 30) { //Frame waiting can be optimized time = 0; updata = true; } if (updata) { updata = false; BeginBatchDraw(); updatabg(); //putimagePNG2(renx, reny, &imgbgsren[renindex]); updataren(); updateEnemy(); updatablood(); updatascore(); checkwin(); EndBatchDraw(); checkover(); checkscore(); fly(); } } } system("pause"); return 0; }
I know that many people will not read one by one, and put the full version of the code directly.
complete program
#define _CRT_SECURE_NO_WARNINGS /*development log * 1.Create game window * 2.import material * 3.Create game page * (1)how to make pictures move * (2)Render the background to make the background transparent (delete the black background of the png image) * 4.protagonist debut * character running * The character jumps (space means jump) * 5.frame wait * 6.mobs show * 7.Struct Encapsulation * 1.Define the obstacle structure * 2.Use c++ variable array to load pictures of different obstacles * 3.Create an obstacle pool (that is, an array of structures) * 8.Character squat operation * At this point, the character rendering function is encapsulated * 9.Set up hanging obstacles * Optimize the frequency of obstacles * 10.Core Algorithm ==== Collision Algorithm--No sound for the first collision, solution, external interface * 11.add health bar * 12.Solve some bug s: mobs appear too frequently and cannot be avoided * Simple solution: when the pillar is detected, we don't generate mobs 2 * 13.final packaging */ #include<stdio.h> #include<graphics.h> #include<conio.h> #include"tools.h" #include<vector> using namespace std; #define WHIDE 1012 #define HEIGHT 396 #define OBSTACLE_COUNT 10 #define win 20 //win score //triple loop IMAGE imgbgs[3]; int bgx[3];//The x coordinate of the background image int bgspeed[3] = { 1,2,4 }; IMAGE imgbgsren[12]; int renx;//Character abscissa int reny;//Character ordinate int renindex;//The picture frame of the player running int jumpmax;//character jump height bool renjump;//Determine whether the character has jumped int rendownspeed;//decline bool updata;//Picture Refresh Switch int blood;//Character HP int score;//Fraction //IMAGE imgTortoise;//mob 1 //int torToiseX;//x coordinate of mob 1 //int torToiseY; //bool torToiseXExist;//Whether there is mob 1 in the current window typedef enum { //enumerated type guai1, guai2, zhu1, zhu2, zhu3, zhu4, //Blame 1 is 0, blame 2 is 1 sum //sum to indicate how many monsters there are in total }obstacle_type; vector<vector<IMAGE>>obstacleimgs;//Define a variable two-dimensional array, the row represents which kind of obstacle, and the column represents the image of the obstacle typedef struct obstacle {//Obstacle Encapsulation obstacle_type type;//Obstacle type int imgindex;//current picture number int x, y; //The x,y coordinates of the obstacle int speed;//speed int power;//Obstacle lethality (commonly known as how much blood is deducted) bool exist;//Determine whether an obstacle exists bool hit;//Judging whether to collide bool passed;//Indicate whether to pass }obstacle_t; obstacle_t obstacles[OBSTACLE_COUNT];//Build a pool directly to see how many obstacles there are int lastobindex; //The sequence number of the last obstacle //people squatting IMAGE imgrendown[2]; bool rendown;//Character squat judgment //digital material IMAGE imgsz[10]; //game initialization void init() { //Create game window initgraph(WHIDE, HEIGHT, EX_SHOWCONSOLE);//show console //Load background resources char name[64]; for (int i = 0; i < 3; i++) { sprintf(name, "res/bg%03d.png", i + 1); loadimage(&imgbgs[i], name); } //Load character frame picture (running) for (int i = 0; i < 12; i++) { sprintf(name, "res/hero%d.png", i + 1); loadimage(&imgbgsren[i], name); } //Set the player's initial position, it should not change afterwards renx = WHIDE / 2 - imgbgsren[0].getwidth() / 2; reny = 345 - imgbgsren[0].getheight(); renindex = 0; renjump = false;//The character does not jump at the beginning jumpmax = reny - 120; rendownspeed = -4;//The rate of decline blood = 100; //Load mobs 1 //loadimage(&imgTortoise, "res/t2.png"); //torToiseXExist = false;//mob 1 initialization //torToiseY = 345 - imgTortoise.getheight()+5; IMAGE imgguai1; loadimage(&imgguai1, "res/t2.png"); vector<IMAGE>boxguai1;//A container is an array boxguai1.push_back(imgguai1);//Then put the one-dimensional array into the two-dimensional array obstacleimgs.push_back(boxguai1); //Next load mobs 2 IMAGE imagguai2; vector<IMAGE> boxguai2; for (int i = 0; i < 6; i++) { sprintf(name, "res/p%d.png", i + 1); loadimage(&imagguai2, name); boxguai2.push_back(imagguai2); } obstacleimgs.push_back(boxguai2); //Initialize the obstacle pool for (int i = 0; i < OBSTACLE_COUNT; i++) { obstacles[i].exist = false; } //Load squat material loadimage(&imgrendown[0], "res/d1.png"); loadimage(&imgrendown[1], "res/d2.png"); rendown = false; //Obstacles (column animation) IMAGE imgH; for (int i = 0; i < 4; i++) { vector<IMAGE>imgzhu; sprintf(name, "res/h%d.png", i + 1); loadimage(&imgH, name, 63, 260, true); //Zoom while recording imgzhu.push_back(imgH); obstacleimgs.push_back(imgzhu); } //Preload sound effects preLoadSound("res/hit.mp3"); //This thing is the external interface mciSendString("play res/bg.mp3 repeat", 0, 0, 0); //Background music lastobindex = -1; score = 0; //Load digital pictures for (int i = 0; i < 10; i++) { sprintf(name, "res/sz/%d.png", i); loadimage(&imgsz[i], name); } } //draw blood void drawblood(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) { LINESTYLE lineStyle; getlinestyle(&lineStyle); int lineColor = getlinecolor(); int fileColor = getfillcolor(); if (percent < 0) { percent = 0; } setlinecolor(BLUE); setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth); setfillcolor(emptyColor); fillrectangle(x, y, x + width, y + height); setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0); setfillcolor(fillColor); setlinecolor(fillColor); if (percent > 0) { fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth); } setlinecolor(lineColor); setfillcolor(fillColor); setlinestyle(&lineStyle); } void creatobstacle() { int i; for (i = 0; i < OBSTACLE_COUNT; i++) { if (!obstacles[i].exist) { break; } } if (i >= OBSTACLE_COUNT) { return; } obstacles[i].exist = true; obstacles[i].hit = false; obstacles[i].imgindex = 0; obstacles[i].type = (obstacle_type)(rand() % 3);//forced conversion if (lastobindex >= 0 && obstacles[lastobindex].type >= zhu1 && obstacles[lastobindex].type <= zhu4 && obstacles[i].type == guai2 && obstacles[lastobindex].x > (WHIDE - 500)) { obstacles[i].type = guai1; } lastobindex = i; if (obstacles[i].type == zhu1) { //Optimize the appearance of obstacles obstacles[i].type = (obstacle_type)(zhu1 + rand() % 4); } obstacles[i].x = WHIDE; obstacles[i].y = 350 - obstacleimgs[obstacles[i].type][0].getheight(); if (obstacles[i].type == guai1) { obstacles[i].speed = 0; obstacles[i].power = 5; //Mob 1 damage } else if (obstacles[i].type == guai2) { obstacles[i].speed = 4; obstacles[i].power = 20; } else if (obstacles[i].type >= zhu1 && obstacles[i].type <= zhu4) { obstacles[i].speed = 0; obstacles[i].power = 20; obstacles[i].y = 0; } obstacles[i].passed = false; } //Player Collision Detection void checkhit() { for (int i = 0; i < OBSTACLE_COUNT; i++) { //For a rectangle, you only need to know two opposite corners to determine if (obstacles[i].exist && obstacles[i].hit == false) { //Use open source code to detect whether two rectangles intersect int alx, aly, a2x, a2y; int off = 30; if (!rendown) { //If people are not squatting, they are running or jumping alx = renx + off; aly = reny + off; a2x = renx + imgbgsren[renindex].getwidth() - off; a2y = reny + imgbgsren[renindex].getheight(); } else { alx = renx + off; aly = 345 - imgrendown[renindex].getheight(); a2x = renx + imgrendown[renindex].getwidth() - off; a2y = 345; } IMAGE img = obstacleimgs[obstacles[i].type][obstacles[i].imgindex];//The first picture of the first obstacle int blx = obstacles[i].x + off; int bly = obstacles[i].y + off; int b2x = obstacles[i].x + img.getwidth() - off; int b2y = obstacles[i].y + img.getheight() - 10; if (rectIntersect(alx, aly, a2x, a2y, blx, bly, b2x, b2y)) {//Collision blood -= obstacles[i].power; printf("remaining blood %d\n", blood); playSound("res/hit.mp3"); obstacles[i].hit = true; } } } } //picture mobile void fly() { for (int i = 0; i < 3; i++) { bgx[i] -= bgspeed[i]; if (bgx[i] < -WHIDE) bgx[i] = 0; } //Character Jump Realization if (renjump) { //What the hell are you changing, the y coordinates, why can’t you know anything, are you a baby? if (reny < jumpmax) {//The first time is to take off, so it starts to be negative, and the next step must be to fall, so it can be positive rendownspeed = 4; } reny += rendownspeed; if (reny > 345 - imgbgsren[0].getheight()) {//has fallen to the ground renjump = false; rendownspeed = -4; } } else if (rendown) { static int count = 0; int delays[2] = { 4,32 }; //Want to control the station time of the two pictures separately count++; if (count >= delays[renindex]) { //The station time is different count = 0; renindex++; if (renindex >= 2) { renindex = 0; rendown = false; } } } else {//neither jump nor squat renindex = (renindex + 1) % 12; } //create obstacles static int frameCount = 0;//Static variables are permanently valid //static int torToiseFre = 100; static int enemyFre = 50; frameCount++; if (frameCount > enemyFre) { frameCount = 0; //if (!torToiseXExist) { //torToiseXExist = true; //torToiseX = WHIDE; //enemyFre = 200 + rand() % 301; //} enemyFre = 50 + rand() % 50; creatobstacle(); } //update coordinates for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist) { obstacles[i].x -= obstacles[i].speed + bgspeed[2]; if (obstacles[i].x < -obstacleimgs[obstacles[i].type][0].getheight() * 2) { obstacles[i].exist = false; } int len = obstacleimgs[obstacles[i].type].size(); obstacles[i].imgindex = (obstacles[i].imgindex + 1) % len; } } //if (torToiseXExist) { //Set the movement of mob 1 //torToiseX -= bgspeed[2]; //if (torToiseX < -imgTortoise.getwidth()) { //torToiseXExist = false; //} //} checkhit(); } //Render the game background void updatabg() { putimagePNG2(bgx[0], 0, &imgbgs[0]); putimagePNG2(bgx[1], 119, &imgbgs[1]); putimagePNG2(bgx[2], 330, &imgbgs[2]); } //character image rendering void updataren() { if (!rendown) { putimagePNG2(renx, reny, &imgbgsren[renindex]); } else { int y = 345 - imgrendown[renindex].getheight(); putimagePNG2(renx, y, &imgrendown[renindex]); } } //character jump switch void jump() { renjump = true; updata = true; //Character frame waiting (just don't wait for 30ms, just refresh directly) } //Character squat switch void down() { rendown = true; updata = true; renindex = 0; } //Handle user keystroke input void anjian() { char ch; if (kbhit()) { //Determine whether there is input ch = getch();//getch reads characters directly, there is no buffer if (ch == ' ') { jump(); } else if (ch == 'b') { down(); } } } void updateEnemy() { //render mobs 1 //if (torToiseXExist) { // putimagePNG2(torToiseX, torToiseY, WHIDE, &imgTortoise); //} for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist) { putimagePNG2(obstacles[i].x, obstacles[i].y, WHIDE, &obstacleimgs[obstacles[i].type][obstacles[i].imgindex]); } } } //render health bar void updatablood() { drawblood(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, blood / 100.0); } void updatascore() { char str[3]; sprintf(str, "%d", score); int x = 20; int y = 25; for (int i = 0; str[i] != '\0'; i++) { int sz = str[i] - '0'; putimagePNG(x, y, &imgsz[sz]); x = x + imgsz[sz].getwidth() + 5; } } void checkover() { if (blood <= 0) { loadimage(0, "res/over.png"); FlushBatchDraw(); mciSendString("stop res/bg.mp3", 0, 0, 0); system("pause"); //Ready to set a button to start the next set if (getch() == 'w') { blood = 100; score = 0; mciSendString("play res/bg.mp3 repeat", 0, 0, 0); //Background music } } } void checkscore() { for (int i = 0; i < OBSTACLE_COUNT; i++) { if (obstacles[i].exist && obstacles[i].passed == false && obstacles[i].x + obstacleimgs[obstacles[i].type][0].getwidth() < renx && obstacles[i].hit == false) { score++; obstacles[i].passed = true; printf("score=%d\n", score); } } } void checkwin() { if (score >= win) { FlushBatchDraw(); mciSendString("play res/win.mp3", 0, 0, 0); Sleep(2000); loadimage(0, "res/win.png"); FlushBatchDraw(); system("pause"); if (getch() == 'w') { //Restart mciSendString("stop res/win.mp3", 0, 0, 0); blood = 100; score = 0; ("play res/bg.mp3 repeat", 0, 0, 0); //Background music } } } int main() { init(); int time = 0; loadimage(0, "res/over.png"); if (getch() == ' ') { while (1) { anjian(); time += getDelay();//background frame wait if (time > 30) { //Frame waiting can be optimized time = 0; updata = true; } if (updata) { updata = false; BeginBatchDraw(); updatabg(); //putimagePNG2(renx, reny, &imgbgsren[renindex]); updataren(); updateEnemy(); updatablood(); updatascore(); checkwin(); EndBatchDraw(); checkover(); checkscore(); fly(); } } } system("pause"); return 0; }
Show results:
Weakened version
Next is the weakened version of the code:
#include<stdio.h> #include<graphics.h> #include<conio.h> #include"tools.h" #define WHIDE 1012 #define HEIGHT 396 #define win 10 //win score IMAGE guai1;//Mob 1 int guai1x;//The x coordinate of mob 1 int guai1y; bool guai1exist;//Is there any mobs in the current window 1 bool hit1; bool pass1; IMAGE guai2; int guai2x; int guai2y; bool guai2exist; bool hit2; bool pass2; IMAGE guai3; int guai3x; int guai3y; bool guai3exist; bool hit3; bool pass3; IMAGE guai4; int guai4x; int guai4y; bool guai4exist; bool hit4; bool pass4; //Double cycle IMAGE imgbgs[2]; int bgx[2];//The x coordinate of the background image int bgspeed[2] = { 0,4 }; IMAGE imgbgsren[12]; int renx;//Character abscissa int reny;//Character ordinate int renindex;//The picture frame of the player running int jumpmax;//character jump height bool renjump;//Determine whether the character has jumped int rendownspeed;//decline int score;//Fraction //people squatting IMAGE imgrendown[2]; bool rendown;//Character squat judgment //digital material IMAGE imgsz[10]; void init() { //Create game window initgraph(WHIDE, HEIGHT);//show console //Load background resources char name[64]; for (int i = 0; i < 2; i++) { sprintf(name, "res/bg%03d.png", i + 1); loadimage(&imgbgs[i], name); } //Load character frame picture (running) for (int i = 0; i < 12; i++) { sprintf(name, "res/hero%d.png", i + 1); loadimage(&imgbgsren[i], name); } //Set the player's initial position, it should not change afterwards renx = WHIDE / 2 - imgbgsren[0].getwidth() / 2; reny = 345 - imgbgsren[0].getheight(); renindex = 0; renjump = false;//The character does not jump at the beginning jumpmax = reny - 130; rendownspeed = -3;//The rate of decline //Load mobs 1 loadimage(&guai1, "res/t2.png"); guai1exist = false;//mob 1 initialization guai1y = 355 - guai1.getheight(); //load mobs 2 loadimage(&guai2, "res/t1.png"); guai2exist = false; guai2y = 355 - guai2.getheight(); //load mobs 3 loadimage(&guai3, "res/h1.png",63,260); guai3exist = false; guai3y = -10; //load mobs 4 loadimage(&guai4, "res/h4.png",63,260); guai4exist = false; guai4y = -10; //Load squat material loadimage(&imgrendown[0], "res/d1.png"); loadimage(&imgrendown[1], "res/d2.png"); rendown = false; //Preload sound effects preLoadSound("res/hit.mp3"); //This thing is the external interface mciSendString("play res/bg.mp3 repeat", 0, 0, 0); //Background music score = 0; //Load digital pictures for (int i = 0; i < 10; i++) { sprintf(name, "res/sz/%d.png", i); loadimage(&imgsz[i], name); } } //Player Collision Detection void checkhit() { int alx, aly, a2x, a2y, b1x, b2x, b1y, b2y; int off = 30; if (guai1exist == true && hit1 == false) { if (!rendown) { //If people are not squatting, they are running or jumping alx = renx + off; aly = reny + off; a2x = renx + imgbgsren[renindex].getwidth() - off; a2y = reny + imgbgsren[renindex].getheight(); } else { alx = renx + off; aly = 345 - imgrendown[renindex].getheight(); a2x = renx + imgrendown[renindex].getwidth() - off; a2y = 345; } b1x = guai1x + off+10; b1y = guai1y + off+10; b2x = guai1x + guai1.getwidth() - off; b2y = guai1y + guai1.getheight() - 10; if (rectIntersect(alx, aly, a2x, a2y, b1x, b1y, b2x, b2y)) {//Collision hit1 = true; mciSendString("play res/hit.mp3",0,0,0); if (score > 0) { score--; } } } if (guai2exist == true && hit2 == false) { if (!rendown) { //If people are not squatting, they are running or jumping alx = renx + off; aly = reny + off; a2x = renx + imgbgsren[renindex].getwidth() - off; a2y = reny + imgbgsren[renindex].getheight(); } else { alx = renx + off; aly = 345 - imgrendown[renindex].getheight(); a2x = renx + imgrendown[renindex].getwidth() - off; a2y = 345; } b1x = guai2x + off+10; b1y = guai2y + off+10; b2x = guai2x + guai2.getwidth() - off; b2y = guai2y + guai2.getheight() - 10; if (rectIntersect(alx, aly, a2x, a2y, b1x, b1y, b2x, b2y)) {//Collision hit2 = true; mciSendString("play res/hit.mp3", 0, 0, 0); if (score > 0) { score--; } } } if (guai3exist == true && hit3 == false) { if (!rendown) { //If people are not squatting, they are running or jumping alx = renx + off; aly = reny + off; a2x = renx + imgbgsren[renindex].getwidth() - off; a2y = reny + imgbgsren[renindex].getheight(); } else { alx = renx + off; aly = 345 - imgrendown[renindex].getheight(); a2x = renx + imgrendown[renindex].getwidth() - off; a2y = 345; } b1x = guai3x + off; b1y = guai3y + off; b2x = guai3x + guai3.getwidth() - off; b2y = guai3y + guai3.getheight() - 10; if (rectIntersect(alx, aly, a2x, a2y, b1x, b1y, b2x, b2y)) {//Collision hit3 = true; mciSendString("play res/hit.mp3", 0, 0, 0); if (score > 0) { score--; } } } if (guai4exist == true && hit4 == false) { if (!rendown) { //If people are not squatting, they are running or jumping alx = renx + off; aly = reny + off; a2x = renx + imgbgsren[renindex].getwidth() - off; a2y = reny + imgbgsren[renindex].getheight(); } else { alx = renx + off; aly = 345 - imgrendown[renindex].getheight(); a2x = renx + imgrendown[renindex].getwidth() - off; a2y = 345; } b1x = guai4x + off; b1y = guai4y + off; b2x = guai4x + guai4.getwidth() - off; b2y = guai4y + guai4.getheight() - 10; if (rectIntersect(alx, aly, a2x, a2y, b1x, b1y, b2x, b2y)) {//Collision hit4 = true; mciSendString("play res/hit.mp3", 0, 0, 0); if (score > 0) { score--; } } } } //picture mobile void fly() { for (int i = 0; i < 2; i++) { bgx[i] -= bgspeed[i]; if (bgx[i] < -WHIDE) bgx[i] = 0; } //Character Jump Realization if (renjump) { if (reny < jumpmax) {//The first time is to take off, so it starts to be negative, and the next step must be to fall, so it can be positive rendownspeed = 4; } reny += rendownspeed; if (reny > 345 - imgbgsren[0].getheight()) {//has fallen to the ground renjump = false; rendownspeed = -4; } } else if (rendown) { static int count = 0; int delays[2] = { 4,32 }; //Want to control the station time of the two pictures separately count++; if (count >= delays[renindex]) { //The station time is different count = 0; renindex++; if (renindex >= 2) { renindex = 0; rendown = false; } } } else {//neither jump nor squat renindex = (renindex + 1) % 12; } //create obstacles static int frameCount = 0;//Static variables are permanently valid static int guai1count = 0; static int guai2count = 1; static int guai3count = 2; static int guai4count = 3; static int enemyFre = 50; frameCount++; if (frameCount > enemyFre) { frameCount = 0; int count = rand() % 4; if (!guai1exist && count == guai1count) { guai1exist = true; hit1 = false; pass1=false; guai1x = WHIDE; enemyFre = 50 + rand() % 50; } if (!guai2exist && count == guai2count) { guai2exist = true; hit2 = false; pass2 = false; guai2x = WHIDE; enemyFre = 50+ rand() % 50; } if (!guai3exist && count == guai3count) { guai3exist = true; hit3 = false; pass3 = false; guai3x = WHIDE; enemyFre = 50 + rand() % 50; } if(!guai4exist && count == guai4count){ guai4exist = true; hit4 = false; pass4 = false; guai4x = WHIDE; enemyFre = 50 + rand() % 50; } } //update coordinates //Set the movement of mob 1 if (guai1exist) { guai1x -= bgspeed[1]; if (guai1x < -guai1.getwidth()) { guai1exist = false; } } //Set the movement of mobs 2 if (guai2exist) { guai2x -= bgspeed[1]; if (guai2x < -guai2.getwidth()) { guai2exist = false; } } //Set the movement of mobs 3 if (guai3exist) { guai3x -= bgspeed[1]; if (guai3x < -guai3.getwidth()) { guai3exist = false; } } //Set the movement of mobs 4 if (guai4exist) { guai4x -= bgspeed[1]; if (guai4x < -guai4.getwidth()) { guai4exist = false; } } checkhit(); } void updatabg() { putimagePNG2(-100, 0, &imgbgs[0]); putimagePNG2(bgx[1], 330, &imgbgs[1]); } //character image rendering void updataren() { if (!rendown) { putimagePNG(renx, reny, &imgbgsren[renindex]); } else { int y = 345 - imgrendown[renindex].getheight(); putimagePNG(renx, y, &imgrendown[renindex]); } } //character jump switch void jump() { renjump = true; } //Character squat switch void down() { rendown = true; renindex = 0; } //rendering score void updatascore() { char str[3]; sprintf(str, "%d", score); int x = 512; int y = 25; for (int i = 0; str[i] != '\0'; i++) { int sz = str[i] - '0'; putimagePNG(x, y, &imgsz[sz]); x = x + imgsz[sz].getwidth() + 5; } } void updateEnemy() { //render mobs 1 if (guai1exist) { putimagePNG2(guai1x, guai1y, WHIDE, &guai1); } if (guai2exist) { putimagePNG2(guai2x, guai2y, WHIDE, &guai2); } if (guai3exist) { putimagePNG2(guai3x, guai3y, WHIDE, &guai3); } if (guai4exist) { putimagePNG2(guai4x, guai4y, WHIDE, &guai4); } } void checkwin() { if (score >= win) { updatascore(); FlushBatchDraw(); mciSendString("play res/win.mp3", 0, 0, 0); Sleep(2000); loadimage(0, "res/win.png"); FlushBatchDraw(); system("pause"); //Continue the game mciSendString("stop res/win.mp3", 0, 0, 0); score = 0; } } void checkscore() { if (guai1exist && pass1 == false && guai1x + guai1.getwidth() < renx && hit1 == false) { score++; pass1 = true; } if (guai2exist && pass2 == false && guai2x + guai2.getwidth() < renx && hit2 == false) { score++; pass2 = true; } if (guai3exist && pass3 == false && guai3x + guai3.getwidth() < renx && hit3 == false) { score++; pass3 = true; } if (guai4exist && pass4 == false && guai4x + guai4.getwidth() < renx && hit4 == false) { score++; pass4 = true; } } int main() { while (1) { init(); loadimage(0, "res/over.png"); if (getch() == 'o') { //start the game while (1) { char ch; if (kbhit()) { //Determine whether there is input ch = getch();//getch reads characters directly, there is no buffer if (ch == 'w') { jump(); } else if (ch == 's') { down(); } else if (ch == 'p') { break; } } BeginBatchDraw(); updatabg(); updataren(); updateEnemy(); updatascore(); checkscore(); checkwin(); EndBatchDraw(); fly(); Sleep(20); } } } system("pause"); return 0; }
The code here is composed of the most basic code, even a very novice can easily understand it.
Let me show you the effect:
Since the frame animation of the characters is really hard to find and difficult to make (mainly because the blogger is a ps novice and not particularly good at it), I just use the materials in the rock directly, haha. The sound effects and background music are also edited by the blogger himself.
Explain in detail
It is a detailed explanation, just to tell you about the difficulties I encountered in the process of writing code and the tips I have summed up, which can reduce the time for everyone to take detours.
1. You will find that there is a tools.h header file in the game code. This is actually a header file written by the rock programmer himself. I will not post the details here. I will put the material extraction address at the end of the article . It needs to be added to the program when writing the game. It is recommended that you use vs to write and add it directly.
2. Many small partners find that vs will report an error when copying the code directly. Here are some adjustments to the settings.
Open the property interface as shown in the figure (right-click "Cool Running in the Picture"), open "Advanced", find "Character Set", drop down and select "Use Multi-Byte Character Set"; then open "c/c++ ", open "General", select "SDL Check", the option is "No". This should work.
3. When beginners modify the code, they can add an array to the obstacle, or use a structure to encapsulate and then add an array, which can greatly reduce the running space and code length; of course, if you are too lazy to use your brain, just copy my weakened version Just keep adding variables.
4. When writing a program, it is recommended to put the code, header files, and materials in the same folder, so that it is not easy to make mistakes.
5. When you are writing a small game, if you want to use the if--else if--else statement multiple times, it is recommended not to use the else if multiple times, you can directly use the if judgment multiple times, the blogger has tried to use it in the weakened version Else if, as a result, a certain segment of else if will fail to run, the program will not report an error, and there is no problem with the grammar, so let’s take it as an experience.
6. When writing small games, it is recommended to define more global variables, but it is not suitable for large-scale games. Encapsulate more functions so that it is not easy to confuse.
Ok. . . . So be it.
Next, provide the material address:
Link: https://pan.baidu.com/s/1sgm2xraVIhFAfzeIvHdIgA?pwd=n3pe Extraction code: n3pe (weakened version material)
Link: https://pan.baidu.com/s/12u29t1FbXj8WRiY6o_DYKQ?pwd=v8iv Extraction code: v8iv (full version material)