今天給大家分享使用C語言配合easy-x圖形庫開發的一款控制檯桌面小遊戲。(IDE:請使用vs2010或者vs2019)
資源下載鏈接:
百度網盤
鏈接:https://pan.baidu.com/s/1KYtZDYwbR_X62k_Swl3anQ
提取碼:8qa4
或者點擊這裏!!!
相信不管是80後還是90後,更或者是00後,應該都玩過“09坦克大戰”這款經典的FP遊戲吧,現在,給大家分享這款遊戲的運行代碼。(個人觀點)
程序還有許多地方需要去優化的,有興趣的小夥伴可以下載回去自己琢磨琢磨,修改完善。
當然,地圖也是隻有一份,有興趣的小夥伴,可以自行下載資源回去,對地圖進行增加。
由於代碼量有點大,在這裏就不一一講解了。
當然本款小遊戲也是在騰訊課堂騎牛學院martin老師的指點下完成的,有興趣學習C/C++語言的小夥伴可以去騰訊課堂官網搜索騎牛學院!
廢話不多說,先上游戲截圖:
好了,遊戲的效果圖已經展現給大家看了,那麼下面請看代碼:
#include <graphics.h>
#include <conio.h>
#include <Windows.h>
#include <time.h>
#include <MMSystem.h>
#pragma comment (lib, "winmm.lib") // 導入聲音庫
#define ENEMY_NUM 10
enum DIRECTION {
UP,
DOWN,
LEFT,
RIGHT
};
// 坦克結構體
struct tank_s {
int x; // 坦克在地圖數組中所在的列
int y; // 坦克在地圖數組中所在的行
DIRECTION direction; // 坦克的方向,上、下、左、右
int live; // 坦克是否生存 1 -- 活着 0 -- 死了
};
// 子彈結構體
struct bullet_s {
int pos_x; // 子彈再窗口上的橫座標
int pos_y; // 子彈再窗口上的縱座標
DIRECTION direction; // 子彈方向
int status; // 子彈的狀態
};
// 定義地圖數組
int map[26][26] = {
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1 },
{ 2, 2, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 2, 2 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
void set_prop_map(int x, int y, int value) {
map[y][x] = value;
map[y][x + 1] = value;
map[y + 1][x] = value;
map[y + 1][x + 1] = value;
}
void menu() {
// 顯示logo
IMAGE logo_img;
loadimage(&logo_img, _T("logo.bmp"), 433, 174); // 將圖片加載進logo_img變量中
putimage(110, 20, &logo_img);
// 實現導航按鈕
setlinecolor(WHITE);
setfillcolor(BLACK);
fillrectangle(230, 200, 310, 240);
settextstyle(25, 0, _T("宋體"));
outtextxy(240, 210, _T("說 明"));
fillrectangle(350, 200, 430, 240);
outtextxy(360, 210, _T("開 始"));
MOUSEMSG mouse; // 定義鼠標
IMAGE illustrate_img;
loadimage(&illustrate_img, _T("illustrate.jpg"), 300, 300);
while (1) {
mouse = GetMouseMsg(); // 獲取鼠標消息
switch (mouse.uMsg) {
case WM_MOUSEMOVE: // 鼠標移動事件
if ((mouse.x > 230 && mouse.x < 310) && (mouse.y > 200 && mouse.y < 240)) {
putimage(150, 250, &illustrate_img);
}
else {
solidrectangle(150, 250, 450, 550); // 繪製一個無邊框的矩形
}
break;
case WM_LBUTTONDOWN: // 鼠標左鍵點擊事件
if ((mouse.x > 350 && mouse.x < 430) && (mouse.y > 200 && mouse.y < 240)) {
cleardevice();
return;
}
}
}
}
// 初始化地圖
// 可消除的牆1;不可消除的牆2;碉堡(3,4)
void initMap(int *map, int rows, int cols) {
IMAGE img_home, img_wall_1, img_wall_2;
loadimage(&img_home, _T("home.jpg"), 50, 50); // 碉堡
loadimage(&img_wall_1, _T("wall1.jpg"), 25, 25); // 不可消除的牆
loadimage(&img_wall_2, _T("wall2.jpg"), 25, 25); // 可消除的牆
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (*(map + cols * i + j) == 1) {
putimage(25 * j, 25 * i, &img_wall_2);
} else if (*(map + cols * i + j) == 2) {
putimage(25 * j, 25 * i, &img_wall_1);
} else if (*(map + cols * i + j) == 3) {
putimage(25 * j, 25 * i, &img_home);
set_prop_map(j, i, 4);
}
}
}
}
// 控制坦克按相應的位置前進一步
// 成功返回1;失敗返回0
int do_tank_walk(tank_s *tank, DIRECTION direction, IMAGE *img, int step) {
int new_x = tank->x;
int new_y = tank->y;
int old_prop = map[tank->y][tank->x];
if (step) {
if (direction == UP) {
new_y -= 1;
} else if (direction == DOWN) {
new_y += 1;
} else if (direction == LEFT) {
new_x -= 1;
} else if (direction == RIGHT) {
new_x += 1;
} else {
return 0; // 無效方向
}
set_prop_map(tank->x, tank->y, 0);
}
setfillcolor(BLACK);
solidrectangle(tank->x * 25, tank->y * 25, tank->x * 25 + 50, tank->y * 25 + 50);
if (step) {
set_prop_map(new_x, new_y, old_prop);
tank->x = new_x;
tank->y = new_y;
}
putimage(tank->x * 25, tank->y * 25, img);
return 1;
}
// 實現子彈運行和碰撞檢測,並反饋遊戲結果
// 返回:1 - 表示遊戲失敗 0 - 繼續遊戲
int bullet_ation(bullet_s *bullet, tank_s *enemy_tank) {
int x, y, x1, y1; // 子彈目前所在的二維數組的座標
x = bullet->pos_x / 25;
y = bullet->pos_y / 25;
// 1.擦除上一次繪製的子彈
setfillcolor(BLACK);
solidrectangle(bullet->pos_x, bullet->pos_y, bullet->pos_x + 3, bullet->pos_y + 3);
// 2.根據方向計算子彈在地圖上的座標
if (bullet->direction == UP) {
bullet->pos_y -= 2;
x1 = x + 1;
y1 = y;
} else if (bullet->direction == DOWN) {
bullet->pos_y += 2;
x1 = x + 1;
y1 = y;
} else if (bullet->direction == LEFT) {
bullet->pos_x -= 2;
x1 = x;
y1 = y + 1;
} else if (bullet->direction == RIGHT) {
bullet->pos_x += 2;
x1 = x;
y1 = y + 1;
} else {
return 0;
}
if (bullet->pos_x < 0 || bullet->pos_x > 650 || bullet->pos_y < 0 || bullet->pos_y > 650) {
bullet->status = 0;
return 0;
}
// 碰撞檢查
if (map[y][x] == 4 || map[y1][x1] == 4) { // 子彈擊中碉堡
//bullet->status = 0;
return 1;
}
if (map[y][x] == 200 || map[y1][x1] == 200) { // 擊中我方坦克
return 1;
}
if ((map[y][x] >= 100 && map[y][x] <= 109) || (map[y1][x1] >= 100 && map[y1][x1] <= 109)) {
tank_s *tank = NULL;
bullet->status = 0;
if (map[y][x] >= 100 && map[y][x] <= 109) {
tank = enemy_tank + (map[y][x] - 100);
} else {
tank = enemy_tank + (map[y1][x1] - 100);
}
tank->live = 0;
set_prop_map(tank->x, tank->y, 0);
setfillcolor(BLACK);
solidrectangle(tank->x * 25, tank->y * 25, tank->x * 25 + 50, tank->y * 25 + 50);
}
if (map[y][x] == 1) { // 子彈擊中可消除的牆
map[y][x] = 0;
bullet->status = 0;
setfillcolor(BLACK);
solidrectangle(x * 25, y * 25, x * 25 + 25, y * 25 + 25);
} else if (map[y][x] == 2) { // 不可消除的牆
//PlaySound(_T("hit.wav"), NULL, SND_FILENAME | SND_ASYNC);
bullet->status = 0;
}
if (map[y1][x1] == 1) { // 子彈擊中可消除的牆
map[y1][x1] = 0;
bullet->status = 0;
setfillcolor(BLACK);
solidrectangle(x1 * 25, y1 * 25, x1 * 25 + 25, y1 * 25 + 25);
} else if (map[y1][x1] == 2) { // 不可消除的牆
bullet->status = 0;
}
// 3.重新繪製子彈
if (bullet->status == 1) {
setfillcolor(WHITE);
solidrectangle(bullet->pos_x, bullet->pos_y, bullet->pos_x + 3, bullet->pos_y + 3);
}
return 0;
}
// 坦克前進一步
void tank_walk(tank_s *tank, DIRECTION direction, IMAGE *img) {
switch (direction) {
case UP: // 上
if (tank->direction == UP && (tank->y - 1) >= 0 && map[tank->y - 1][tank->x] == 0 && map[tank->y - 1][tank->x + 1] == 0) {
do_tank_walk(tank, UP, img, 1);
}
else if (tank->direction != UP) {
tank->direction = UP;
do_tank_walk(tank, UP, img, 0);
}
break;
case DOWN: // 下
if (tank->direction == DOWN && (tank->y + 2) <= 25 && map[tank->y + 2][tank->x] == 0 && map[tank->y + 2][tank->x + 1] == 0) {
do_tank_walk(tank, DOWN, img, 1);
}
else if (tank->direction != DOWN) {
tank->direction = DOWN;
do_tank_walk(tank, DOWN, img, 0);
}
break;
case LEFT: // 左
if (tank->direction == LEFT && (tank->x - 1) >= 0 && map[tank->y][tank->x - 1] == 0 && map[tank->y + 1][tank->x - 1] == 0) {
do_tank_walk(tank, LEFT, img, 1);
}
else if (tank->direction != LEFT) {
tank->direction = LEFT;
do_tank_walk(tank, LEFT, img, 0);
}
break;
case RIGHT: // 右
if (tank->direction == RIGHT && (tank->x + 2) <= 25 && map[tank->y][tank->x + 2] == 0 && map[tank->y + 1][tank->x + 2] == 0) {
do_tank_walk(tank, RIGHT, img, 1);
}
else if (tank->direction != RIGHT) {
tank->direction = RIGHT;
do_tank_walk(tank, RIGHT, img, 0);
}
break;
default: // 其他鍵無需操作
break;
}
}
// 根據目標位置,調整敵方坦克的方向
DIRECTION enemy_direction(tank_s *tank, int x, int y) {
int r = rand() % 100;
if (tank->x > x) { // 目標再左邊
if (tank->y > y) { // 目標在左上方
if (r <= 50) return UP;
return LEFT;
} else { // 目標在左下方
if (r <= 50) return DOWN;
return LEFT;
}
} else { // 目標再右邊
if (tank->y > y) { // 目標在右上方
if (r <= 50) return UP;
return RIGHT;
} else { // 目標在右下方
if (r <= 50) return DOWN;
return RIGHT;
}
}
}
// 坦克開火
void tank_fire(tank_s *tank, bullet_s *bullet, int need_sound) {
if (bullet->status == 0) {
if (need_sound) {
PlaySound(_T("fire.wav"), NULL, SND_FILENAME | SND_ASYNC);
}
if (tank->direction == UP) {
bullet->pos_x = tank->x * 25 + 23;
bullet->pos_y = tank->y * 25 - 3;
}
else if (tank->direction == DOWN) {
bullet->pos_x = tank->x * 25 + 23;
bullet->pos_y = tank->y * 25 + 53;
}
else if (tank->direction == LEFT) {
bullet->pos_x = tank->x * 25 - 3;
bullet->pos_y = tank->y * 25 + 23;
}
else if (tank->direction == RIGHT) {
bullet->pos_x = tank->x * 25 + 53;
bullet->pos_y = tank->y * 25 + 23;
}
bullet->direction = tank->direction;
bullet->status = 1;
}
}
/****************************************
* 實現遊戲場景
*****************************************/
int play() {
tank_s my_tank; // 我方坦克
bullet_s my_bullet; // 我方坦克發射的子彈
tank_s enemy_tank[ENEMY_NUM]; // 敵方坦克
bullet_s enemy_bullet[ENEMY_NUM]; // 敵方坦克發射的子彈
IMAGE my_tank_img[4]; // 我方坦克的顯示圖片
IMAGE enemy_tank_img[4];// 地方坦克的顯示圖片
int key;
int times = 0; // 記錄當前程序的休眠次數,每次10ms
int enemy_total = 0;
// 初始化隨機種子
srand(time(NULL));
// 遊戲背景音樂
mciSendString(_T("play background.wav"), 0, 0, 0);
// 加載我方坦克的圖片
loadimage(&my_tank_img[UP], _T("tank_up.jpg"), 50, 50);
loadimage(&my_tank_img[DOWN], _T("tank_down.jpg"), 50, 50);
loadimage(&my_tank_img[LEFT], _T("tank_left.jpg"), 50, 50);
loadimage(&my_tank_img[RIGHT], _T("tank_right.jpg"), 50, 50);
// 加載地方坦克的圖片
loadimage(&enemy_tank_img[UP], _T("enemy_tank_up.jpg"), 50, 50);
loadimage(&enemy_tank_img[DOWN], _T("enemy_tank_down.jpg"), 50, 50);
loadimage(&enemy_tank_img[LEFT], _T("enemy_tank_left.jpg"), 50, 50);
loadimage(&enemy_tank_img[RIGHT], _T("enemy_tank_right.jpg"), 50, 50);
// 1 :子彈存在 0 : 子彈不存在
my_bullet.status = 0;
// 我方坦克出現的位置
my_tank.x = 8;
my_tank.y = 24;
my_tank.live = 1;
my_tank.direction = UP;
// 敵方坦克出現的位置
for (int i = 0; i < ENEMY_NUM; i++) {
if (i % 3 == 0) {
enemy_tank[i].x = 0;
}
else if (i % 3 == 1) {
enemy_tank[i].x = 12;
}
else if (i % 3 == 2) {
enemy_tank[i].x = 24;
}
enemy_tank[i].direction = DOWN;
enemy_tank[i].y = 0;
enemy_tank[i].live = 1;
//set_prop_map(enemy_tank[i].x, enemy_tank[i].y, 100 + i);
enemy_bullet[i].status = 0;
}
// 前三輛坦克出現
do_tank_walk(&enemy_tank[0], DOWN, &enemy_tank_img[DOWN], 0);
set_prop_map(enemy_tank[0].x, enemy_tank[0].y, 100);
do_tank_walk(&enemy_tank[1], DOWN, &enemy_tank_img[DOWN], 0);
set_prop_map(enemy_tank[1].x, enemy_tank[1].y, 101);
do_tank_walk(&enemy_tank[2], DOWN, &enemy_tank_img[DOWN], 0);
set_prop_map(enemy_tank[2].x, enemy_tank[2].y, 102);
enemy_total = 3;
set_prop_map(my_tank.x, my_tank.y, 200);
// 顯示我方坦克
putimage(25 * my_tank.x, 25 * my_tank.y, &my_tank_img[my_tank.direction]);
while (1) {
if (times > 0 && times % 1000 == 0 && enemy_total < ENEMY_NUM) {
set_prop_map(enemy_tank[enemy_total].x, enemy_tank[enemy_total].y, 100 + enemy_total);
enemy_total++;
}
if (times % 100 == 0) {
for (int i = 0; i < enemy_total; i++) {
if (enemy_tank[i].live == 0) continue;
if (i % 2 == 0) { // 雙數攻擊我方老鷹
DIRECTION d = enemy_direction(&enemy_tank[i], 12, 24);
tank_walk(&enemy_tank[i], d, &enemy_tank_img[d]);
} else { // 單數攻擊我方坦克
DIRECTION d = enemy_direction(&enemy_tank[i], my_tank.x, my_tank.y);
tank_walk(&enemy_tank[i], d, &enemy_tank_img[d]);
}
tank_fire(&enemy_tank[i], &enemy_bullet[i], 0);
}
} else if (times % 100 == 0) { // 敵方坦克還生存
for (int i = 0; i < enemy_total; i++) {
if (enemy_tank[i].live) {
tank_walk(&enemy_tank[i], enemy_tank[i].direction, &enemy_tank_img[enemy_tank->direction]);
}
}
}
if (_kbhit()) {
key = _getch();
switch (key) {
case 'w': // 上
tank_walk(&my_tank, UP, &my_tank_img[UP]);
break;
case 's': // 下
tank_walk(&my_tank, DOWN, &my_tank_img[DOWN]);
break;
case 'a': // 左
tank_walk(&my_tank, LEFT, &my_tank_img[LEFT]);
break;
case 'd': // 右
tank_walk(&my_tank, RIGHT, &my_tank_img[RIGHT]);
break;
case 'j': // 開火
tank_fire(&my_tank, &my_bullet, 1);
break;
case 'p': // 暫停
system("pause");
break;
default: // 其他鍵無需操作
break;
}
}
if (my_bullet.status == 1) {
if (bullet_ation(&my_bullet, enemy_tank)) {
return 1;
}
}
for (int i = 0; i < ENEMY_NUM; i++) {
if (enemy_bullet[i].status == 1) {
if (bullet_ation(&enemy_bullet[i], enemy_tank)) {
return 1;
}
}
}
// 判斷敵方坦克是否全部被消滅
int isWin = 1;
for (int i = 0; i < ENEMY_NUM; i++) {
if (enemy_tank[i].live == 1) {
isWin = 0;
break;
}
}
if (isWin) return 0;
Sleep(5);
times++;
}
}
void game_voer(int result) {
IMAGE img;
if (result == 1) { // 等於1表示失敗
loadimage(&img, _T("failure.jpg"), 500, 250);
putimage(80, 200, &img);
} else if (result == 0) { // 等於0表示成功
loadimage(&img, _T("success.jpg"), 500, 250);
putimage(80, 200, &img);
}
_getch();
}
int main(void) {
int result = 0;
initgraph(650, 650);
// 開始場景,顯示菜單
menu();
// 初始化地圖
initMap(*map, 26, 26);
result = play();
// 顯示遊戲結果
game_voer(result);
system("pause");
closegraph();
return 0;
}
最後祝csdn的各位,五一快樂!