C++基于EasyX框架實(shí)現(xiàn)飛機(jī)大戰(zhàn)小游戲
正式使用Easyx之前,你需要先安裝他??!
EasyX 2022 版 (2022-9-1 更新) - EasyX
選擇合適的版本安裝

安裝結(jié)束后就可以開始敲代碼啦!
這里作者使用的是Visual Studio 2022所以安裝EasyX_20220901版本
啟動(dòng)Visual Studio 2022,新建一個(gè)空項(xiàng)目

這是工程目錄:

首先來看看Bullet(子彈)類
頭文件:
#pragma once
class Bullet
{
public:
Bullet(int x, int y, int owner);
int owner; // 0 means player, 1 means enemy
int x;
int y;
int speed;
int pic_w = 5;
int pic_h = 11;
bool dead = false;
void move();
void checkBound();
};
源文件:
#include "Bullet.h"
#include "constants.h"
Bullet::Bullet(int x, int y, int owner) {
this->x = x;
this->y = y;
this->owner = owner;
speed = 12;
}
void Bullet::move() {
if (owner == 0) {
y -= speed;
}
else {
y += speed;
}
}
void Bullet::checkBound() {
if (owner == 0) {
if (y + pic_h <= 0) {
dead = true;
}
}
else {
if (y >= HEIGHT) {
dead = true;
}
}
}這里簡(jiǎn)單地實(shí)現(xiàn)了子彈的移動(dòng)和檢測(cè)超出邊界,不難理解
Enemy類頭文件:
#pragma once
class Enemy
{
public:
Enemy(int type);
int x;
int y;
int speed;
int pic_w;
int pic_h;
int type;
int health;
int static_health;
bool dead = false;
void move();
void checkBound();
};
源文件:
#include "Enemy.h"
#include "constants.h"
Enemy::Enemy(int type) {
this->type = type;
switch (type) {
case 1:
pic_w = 60;
pic_h = 44;
health = random(1, 2);
break;
case 2:
pic_w = 70;
pic_h = 100;
health = random(3, 4);
break;
case 3:
pic_w = 160;
pic_h = 250;
health = random(5, 6);
break;
default:
pic_w = 60;
pic_h = 44;
health = 1;
break;
}
x = random(0, WIDTH - pic_w);
y = 0 - pic_h;
speed = random(5,8);
static_health = health;
}
void Enemy::move() {
y += speed;
}
void Enemy::checkBound() {
if (y >= HEIGHT || health <= 0) {
dead = true;
}
}這里的類成員變量type表示敵機(jī)大小,3最大,同時(shí)血量最多,也實(shí)現(xiàn)了移動(dòng)和檢測(cè)超出邊界功能
有的人會(huì)發(fā)現(xiàn)random方法以及WIDTH常量等,這里是因?yàn)槲覀儗⑦@些常量寫在一個(gè)頭文件下:
constants.h:
#pragma once #ifndef WIDTH #define WIDTH 800 #endif #ifndef HEIGHT #define HEIGHT 1000 #endif #include <cstdlib> #include <string> using namespace std; #ifndef random(a,x) #define random(a,x) a+rand()%x #endif const string PATH = "./resources/";
接下來是Player.h
#pragma once
#include <string>
#include "constants.h"
using namespace std;
class Player
{
public:
Player();
int speed;
int y;
int x;
int pic_w;
int pic_h;
void move(int a);
void checkBound();
};
Player.cpp:
#include "Player.h"
#include "constants.h"
Player::Player() {
speed = 12;
y = HEIGHT - 170;
x = 300;
pic_w = 100;
pic_h = 126;
}
void Player::move(int a) {
if (a == 0) { // left
x -= speed;
}
else { // right
x += speed;
}
}
void Player::checkBound() {
if (x < 0) {
x = 0;
}
else if (x + pic_w > WIDTH) {
x = WIDTH - pic_w;
}
}代碼都很短,也實(shí)現(xiàn)了移動(dòng)和限制活動(dòng)區(qū)域(checkBound)操作,不難理解
接下來是作者自己寫了一個(gè)實(shí)用的頭文件,用于判斷2者是否碰撞,CheckCollide.h:
#pragma once
bool collide(
int l,
int r,
int t,
int d,
int el,
int er,
int et,
int ed) {
if ((l <= er && t <= ed && l >= el && t >= et) ||
(r >= el && t <= ed && r <= er && t >= et) ||
(l <= er && d >= et && l >= el && d <= ed) ||
(r >= el && d >= et && r <= er && d <= ed)) {
return true;
}
return false;
}其中,l、r、t、d分別為第一個(gè)物體的左邊x坐標(biāo)、右邊x坐標(biāo)、上邊y坐標(biāo)、下邊y坐標(biāo),el、er、et、ed是第二個(gè)物體的,然后進(jìn)行判斷,返回bool值,這個(gè)待會(huì)在main.cpp會(huì)用到
接下來也是一個(gè)常用的頭文件,因?yàn)閑asyx渲染透明圖片很麻煩,所以這個(gè)方法通過計(jì)算來繪制,這個(gè)是借用了EasyX 繪制透明背景圖這篇文章的代碼,PhotoTransparent.h
#pragma once
#include <graphics.h>
#include "constants.h"
void drawAlpha(IMAGE* image, int x, int y, int width, int height, int pic_x = 0, int pic_y = 0, double AA = 1)
{
// 變量初始化
DWORD* dst = GetImageBuffer(); // GetImageBuffer() 函數(shù),用于獲取繪圖設(shè)備的顯存指針, EasyX 自帶
DWORD* draw = GetImageBuffer();
DWORD* src = GetImageBuffer(image); // 獲取 picture 的顯存指針
int imageWidth = image->getwidth(); // 獲取圖片寬度
int imageHeight = image->getheight(); // 獲取圖片寬度
int dstX = 0; // 在 繪圖區(qū)域 顯存里像素的角標(biāo)
int srcX = 0; // 在 image 顯存里像素的角標(biāo)
// 實(shí)現(xiàn)透明貼圖 公式: Cp=αp*FP+(1-αp)*BP , 貝葉斯定理來進(jìn)行點(diǎn)顏色的概率計(jì)算
for (int iy = 0; iy < height; iy++)
{
for (int ix = 0; ix < width; ix++)
{
// 防止越界
if (ix + pic_x >= 0 && ix + pic_x < imageWidth && iy + pic_y >= 0 && iy + pic_y < imageHeight &&
ix + x >= 0 && ix + x < WIDTH && iy + y >= 0 && iy + y < HEIGHT)
{
// 獲取像素角標(biāo)
int srcX = (ix + pic_x) + (iy + pic_y) * imageWidth;
dstX = (ix + x) + (iy + y) * WIDTH;
int sa = ((src[srcX] & 0xff000000) >> 24) * AA; // 0xAArrggbb; AA 是透明度
int sr = ((src[srcX] & 0xff0000) >> 16); // 獲取 RGB 里的 R
int sg = ((src[srcX] & 0xff00) >> 8); // G
int sb = src[srcX] & 0xff; // B
// 設(shè)置對(duì)應(yīng)的繪圖區(qū)域像素信息
int dr = ((dst[dstX] & 0xff0000) >> 16);
int dg = ((dst[dstX] & 0xff00) >> 8);
int db = dst[dstX] & 0xff;
draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr
| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg
| (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db
}
}
}
}接下來這一個(gè)是作者自己寫的一個(gè)常用的頭文件StringCharExchange.h:
#pragma once
#include <graphics.h>
#define BUFFERSIZE 1024
TCHAR* Transform(char c[BUFFERSIZE]) {
TCHAR result[BUFFERSIZE];
MultiByteToWideChar(CP_ACP, 0, c, -1, result, BUFFERSIZE);
return result;
}
TCHAR* Transform(string s) {
TCHAR result[BUFFERSIZE];
char c[BUFFERSIZE];
strcpy_s(c, s.c_str());
MultiByteToWideChar(CP_ACP, 0, c, -1, result, BUFFERSIZE);
return result;
}上面實(shí)現(xiàn)了char*轉(zhuǎn)TCHAR*以及string轉(zhuǎn)TCHAR*
最后是main.cpp
#include <graphics.h>
#include "constants.h"
#include "Player.h"
#include "PhotoTransparent.h"
#include <time.h>
#include <vector>
#include "Bullet.h"
#include "Enemy.h"
#include "CheckCollide.h"
#include "StringCharExchange.h"
Player* player = new Player();
vector<Bullet>* bullets = new vector<Bullet>;
vector<Enemy>* enemies = new vector<Enemy>;
int startTime[5] = { 0 };
int durations[5] = { 200,1000,0,0,0 };
int health = 5;
int score = 0;
bool lose = false;
void DrawBackGroundImage() {
IMAGE img;
loadimage(&img, Transform(PATH+"background2.png"), WIDTH, HEIGHT);
putimage(0, 0, &img);
}
void DrawPlayer() {
IMAGE img;
loadimage(&img, Transform(PATH + "myplane1.png"), player->pic_w, player->pic_h);
drawAlpha(&img, player->x, player->y, player->pic_w, player->pic_h);
}
void DrawBullets() {
for (int i = 0;i < bullets->size();i++) {
Bullet* bullet = &(bullets->at(i));
IMAGE img;
loadimage(&img, Transform(PATH + "bullet1.png"));
drawAlpha(&img, bullet->x, bullet->y, bullet->pic_w, bullet->pic_h);
}
}
void DrawEnemies() {
for (int i = 0;i < enemies->size();i++) {
Enemy* enemy = &(enemies->at(i));
IMAGE img;
switch (enemy->type) {
case 1:
loadimage(&img, Transform(PATH + "small_enemy.png"));
break;
case 2:
loadimage(&img, Transform(PATH + "mid_enemy.png"));
break;
case 3:
loadimage(&img, Transform(PATH + "big_enemy.png"));
break;
default:
break;
}
drawAlpha(&img, enemy->x, enemy->y, enemy->pic_w, enemy->pic_h);
}
}
void UpdateBullets() {
for (int i = 0;i < bullets->size();i++) {
Bullet* bullet = &(bullets->at(i));
bullet->move();
bullet->checkBound();
if (bullet->dead) {
swap(bullets->at(i), bullets->at(bullets->size() - 1));
bullets->pop_back();
i--;
}
}
}
void UpdateEnemies() {
for (int i = 0;i < enemies->size();i++) {
Enemy* enemy = &(enemies->at(i));
enemy->move();
enemy->checkBound();
if (enemy->dead) {
swap(enemies->at(i), enemies->at(enemies->size() - 1));
enemies->pop_back();
i--;
}
}
}
void CheckPlayerHit() {
for (int i = 0;i < enemies->size();i++) {
Enemy* enemy = &(enemies->at(i));
int l, r, t, d;
int el, er, et, ed;
l = player->x;
r = player->x + player->pic_w;
t = player->y;
d = player->y + player->pic_h;
el = enemy->x;
er = enemy->x + enemy->pic_w;
et = enemy->y;
ed = enemy->y + enemy->pic_h;
if (collide(l, r, t, d, el, er, et, ed)) {
health--;
swap(enemies->at(i), enemies->at(enemies->size() - 1));
enemies->pop_back();
i--;
}
}
}
void CheckBulletHit() {
for (int i = 0;i < bullets->size();i++) {
Bullet* bullet = &(bullets->at(i));
int l, r, t, d;
l = bullet->x;
r = bullet->x + bullet->pic_w;
t = bullet->y;
d = bullet->y + bullet->pic_h;
for (int j = 0;j < enemies->size();j++) {
Enemy* enemy = &(enemies->at(j));
int el, er, et, ed;
el = enemy->x;
er = enemy->x + enemy->pic_w;
et = enemy->y;
ed = enemy->y + enemy->pic_h;
if (collide(l, r, t, d, el, er, et, ed)) {
enemy->health--;
if (enemy->health <= 0 || enemy->dead) {
score += enemy->static_health;
swap(enemies->at(j), enemies->at(enemies->size() - 1));
enemies->pop_back();
}
j--;
swap(bullets->at(i), bullets->at(bullets->size() - 1));
bullets->pop_back();
i--;
break;
}
}
}
}
void _DrawText() {
settextcolor(RGB(0, 0, 255));
settextstyle(26, 0, _T("simhei"));
char c[BUFFERSIZE];
snprintf(c, 64, "Health: %d", health);
TCHAR* c2 = Transform(c);
outtextxy(10, 10, c2);
settextcolor(RGB(255, 0, 0));
settextstyle(26, 0, _T("simhei"));
char c3[BUFFERSIZE];
snprintf(c3, 64, "Score: %d", score);
TCHAR* c4 = Transform(c3);
outtextxy(10, 44, c4);
}
void CheckLose() {
if (health <= 0) {
lose = true;
}
}
void Draw() {
CheckLose();
DrawBackGroundImage();
_DrawText();
if (!lose) {
UpdateBullets();
UpdateEnemies();
CheckPlayerHit();
CheckBulletHit();
DrawPlayer();
DrawEnemies();
DrawBullets();
}
}
void Timer() {
int endTime = clock();
if (endTime - startTime[0] >= durations[0]) { // Create bullet event
bullets->push_back(Bullet(player->x + player->pic_w / 2, player->y, 0));
startTime[0] = endTime;
}
if (endTime - startTime[1] >= durations[1]) { // Create enemy event
enemies->push_back(Enemy(random(1,3)));
startTime[1] = endTime;
}
}
int Listen() {
if (GetAsyncKeyState(VK_ESCAPE)) {
return 1;
}
if (GetAsyncKeyState(VK_LEFT)) {
player->move(0);
player->checkBound();
}
if (GetAsyncKeyState(VK_RIGHT)) {
player->move(1);
player->checkBound();
}
return 0;
}
int main() {
initgraph(WIDTH, HEIGHT);
setbkmode(TRANSPARENT);
BeginBatchDraw();
while (true) {
Draw();
if (Listen()) {
break;
}
Timer();
FlushBatchDraw();
}
EndBatchDraw();
closegraph();
return 0;
}實(shí)現(xiàn)了程序的主流程
到此這篇關(guān)于C++基于EasyX框架實(shí)現(xiàn)飛機(jī)大戰(zhàn)小游戲的文章就介紹到這了,更多相關(guān)C++ EasyX飛機(jī)大戰(zhàn)游戲內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Matlab實(shí)現(xiàn)同步子圖視角的方法詳解
這篇文章主要和大家分享三個(gè)可以Matlab中更簡(jiǎn)便實(shí)現(xiàn)同步子圖視角的技巧,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下2022-06-06
JS調(diào)用C++函數(shù)拋出異常及捕捉異常詳解
這篇文章主要介紹了js調(diào)用C++函數(shù)的方法示例,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2021-08-08
C++?中如何結(jié)束?while?(cin>>str)?的輸入
這篇文章主要介紹了C++?中如何結(jié)束?while?(cin>>str)?的輸入,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-07-07
Recommended C Style and Coding Standards中文翻譯版
本文翻譯自Recommended C Style and Coding Standards(C語(yǔ)言編碼風(fēng)格和標(biāo)準(zhǔn)),需要的朋友可以參考下2014-04-04
Eclipse對(duì)printf()不能輸出到控制臺(tái)的快速解決方法
Eclipse對(duì)printf()不能輸出到控制臺(tái)的快速解決方法。需要的朋友可以過來參考下,希望對(duì)大家有所幫助2013-10-10

