C++基于EasyX框架实现飞机大战小游戏

正式使用Easyx之前,你需要先安装他!!

EasyX 2022 版 (2022-9-1 更新) - EasyX

选择合适的版本安装

安装结束后就可以开始敲代码啦!

这里作者使用的是Visual Studio 2022所以安装EasyX_20220901版本

启动Visual Studio 2022,新建一个空项目

这是工程目录:

首先来看看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;
        }
    }
}

这里简单地实现了子弹的移动和检测超出边界,不难理解

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表示敌机大小,3最大,同时血量最多,也实现了移动和检测超出边界功能

有的人会发现random方法以及WIDTH常量等,这里是因为我们将这些常量写在一个头文件下:

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;
    }
}

代码都很短,也实现了移动和限制活动区域(checkBound)操作,不难理解

接下来是作者自己写了一个实用的头文件,用于判断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分别为第一个物体的左边x坐标、右边x坐标、上边y坐标、下边y坐标,el、er、et、ed是第二个物体的,然后进行判断,返回bool值,这个待会在main.cpp会用到

接下来也是一个常用的头文件,因为easyx渲染透明图片很麻烦,所以这个方法通过计算来绘制,这个是借用了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() 函数,用于获取绘图设备的显存指针, EasyX 自带
    DWORD* draw = GetImageBuffer();
    DWORD* src = GetImageBuffer(image);        // 获取 picture 的显存指针
    int imageWidth = image->getwidth();        // 获取图片宽度
    int imageHeight = image->getheight();    // 获取图片宽度
    int dstX = 0;                            // 在 绘图区域 显存里像素的角标
    int srcX = 0;                            // 在 image 显存里像素的角标

    // 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
    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)
            {
                // 获取像素角标
                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

                // 设置对应的绘图区域像素信息
                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
            }
        }
    }
}

接下来这一个是作者自己写的一个常用的头文件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;
}

上面实现了char*转TCHAR*以及string转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;
}

实现了程序的主流程

到此这篇关于C++基于EasyX框架实现飞机大战小游戏的文章就介绍到这了,更多相关C++ EasyX飞机大战游戏内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++实现基于EASYX库扫描线算法

    本文实例为大家分享了C++实现基于EASYX库扫描线算法的具体代码,供大家参考,具体内容如下 扫描线算法的基本原理 * 作者在扫描线算法的基础上自己设计的更易于理解的地物填充绘制算法 流程图 代码 #include<graphics.h> //#include<conio.h> #include<iostream> using namespace std; //-----------------------------草图形-----------------------

  • c++使用Easyx图形库实现飞机大战

    公共的头文件        common.h #pragma once #include <graphics.h> #include <iostream> #include <string> #include <map> #include <list> #include <thread> #include <vector> #include <ctime> #include <mmsystem.h>

  • C++基于easyx图形库实现打砖块游戏

    本文实例为大家分享了C++基于easyx实现打砖块的具体代码,供大家参考,具体内容如下 代码: #include <graphics.h> #include <ctime> #include <iostream> #include <cassert> using namespace std;   class Board { public:     int x;     int y;     int w;     int h;     COLORREF col

  • c++游戏教程使用easyx做出大飞机

    效果图 这个打飞机小游戏素材都很一般,直接网上抠图下来的. 但我们应该学习一下怎么入门这一款经典小游戏. 游戏对象 首先游戏对象就这几个东西 // 全局画板 IMAGE bk; IMAGE BK; IMAGE Plane; IMAGE Diren; IMAGE Zidan; 这个游戏用到游戏插件easyX,我们想载入这几个图片. //预加载资源,需要加载了之后才能用 void loadRes() { loadimage(&bk, _T("res\\bg.png")); load

  • C++用easyx图形库实现障碍跑酷小游戏

    用easyx图形库做一个简单的c++小游戏-障碍跑酷 开发环境:visual c++6.0 库:easyx图形库 下载地址 EasyX(c++图形库) v20200806 官方安装免费版 当时我原本是想模仿做一个Flappy Bird的小游戏,在想如何写的时候突然有了新的想法,就有了这个障碍跑酷的小游戏.(这是我之前写的代码,没有很注重规范,看上去有点乱,但我很尽力的都标上了注释.) 游戏介绍: 1.操控小球,小球一开始只具有左a,右d与跳跃w的功能 2.可根据按1,2,3,4调节小球的跳跃高度

  • C++基于EasyX图形库实现2048小游戏

    C++ 和 EasyX 图形库,实现2048小游戏,供大家参考,具体内容如下 MainGame2048.cpp /** Name: Game2048CoreClass*/ #include<iostream> #include<graphics.h> #include<stdio.h> #include<windows.h> #include<conio.h> #include<stdio.h> #include"Game2

  • C++基于EasyX框架实现飞机大战小游戏

    正式使用Easyx之前,你需要先安装他!! EasyX 2022 版 (2022-9-1 更新) - EasyX 选择合适的版本安装 安装结束后就可以开始敲代码啦! 这里作者使用的是Visual Studio 2022所以安装EasyX_20220901版本 启动Visual Studio 2022,新建一个空项目 这是工程目录: 首先来看看Bullet(子弹)类 头文件: #pragma once class Bullet { public: Bullet(int x, int y, int

  • 基于Java语言在窗体上实现飞机大战小游戏的完整步骤

    目录 小组项目 模块需求描述 总体开发思想 功能实现 1.登录与结束界面 2.播放音乐 3.子弹 运行测试 登陆界面 发射子弹 总结 小组项目 飞机大战:用 Java 语言在窗体上实现飞机大战小游戏,运行程序后,出现一个窗体,在窗体上用鼠标控制英雄机的移动,通过子弹打击敌机进行分数的计算,以及英雄机血量的计算等. 主要模块:登陆界面.音乐.子弹.敌机.英雄机.背景图.结束界面.BOSS 机.分数计算.血量计算. 负责模块:登陆界面.音乐.子弹.结束界面. 模块需求描述 登陆界面:运行程序后,弹出

  • java实战之飞机大战小游戏(源码加注释)

    一.工程文件 二.Main.java 主函数,实现类 package ui; //主函数实现 public class Main { public static void main(String[] args) { //创建窗体 GameFrame frame = new GameFrame(); //创建面板 GamePanel panel = new GamePanel(frame); //调用开始游戏的方法启动游戏 panel.action(); //将面板加入到窗体中 frame.add

  • 用JS实现飞机大战小游戏

    本文实例为大家分享了JS实现飞机大战小游戏的具体代码,供大家参考,具体内容如下 小的时候玩的飞机大战感觉还蛮神奇,今天自己就学着做了一个 先制作好要做好的几步以及背景样式 var canvas = document.getElementById("canvas"); var ctx = canvas.getContext("2d"); var start = 0; // 开始阶段 var starting = 1; // 开始的加载阶段 var running =

  • 原生JS实现飞机大战小游戏

    本文实例为大家分享了JS实现飞机大战小游戏的具体代码,供大家参考,具体内容如下 <html> <head> <title> 飞机大战 </title> <style type="text/css"> *{margin:0;padding:0;font-family:"Microsoft yahei"} body{overflow:hidden;;} </style> </head>

  • C语言实现飞机大战小游戏完整代码

    大一课设做的飞机大战,可以进行登入和注册,这个是利用单链表做的,源代码已经给出,这个是最基本的飞机大战模式,我设置了几个功能,比如排行榜之类的.排行榜是用结构体数组做的,已及冒泡排序,并且在文件里保存信息.比较简单. 这个是注册页面规范: 这个是登入页面: 游戏菜单:  飞机大战页面:  话不多说,直接上代码 以下是源代码  #include"stdio.h" #include"windows.h" //用于获取窗口的句柄与屏幕控制 #include"co

  • javascript实现简单飞机大战小游戏

    本文实例为大家分享了javascript实现飞机大战小游戏的具体代码,供大家参考,具体内容如下 效果图 html文件 <!DOCTYPE html><html lang='zh'><head>    <meta charset='UTF-8'>    <title>mm</title>    <link rel="stylesheet" href="./css/index.css">

  • Vue实现飞机大战小游戏

    目录 使用 Vue 开发一个简略版的飞机大战小游戏 一.实现思路 二.所需知识点 三.实现步骤 使用 Vue 开发一个简略版的飞机大战小游戏 如题,假设你为了向更多访问你博客的人展示你的技术,你决定小试身手开发一个飞机大战小游戏.功能: 开始游戏前用户名必填,玩家可以发射子弹,敌军与行星随机出现,鼠标可操控玩家移动,敌军可发射子弹 一.实现思路 如题所述: 玩家可操控玩家飞机可发射子弹,敌军与行星随机生成: 这意味着我们需要一个单独的玩家飞机dom,以及敌军.行星与子弹 用 vue 循环生成的3

  • C语言实现飞机大战小游戏

    本文实例为大家分享了C语言实现飞机大战小游戏的具体代码,供大家参考,具体内容如下 技术原型 1.void gotoxy(int x, int y) 函数,该函数可以使光标去到(x,y)的位置进行打印:2.链表,用于存储状态:3.windows.h中有非阻塞输入,_kbhit():4.随机生成数:5.视觉暂留:6.碰撞检测:7.清屏函数:8.设置边界: 技术路线 1.设置一个边界:2.维护一个子弹的列表:3.维护一个敌机的列表:4.初始化飞机的位置:5.每隔一秒钟生成一架敌机,生成位置x坐标随机,

  • python实现飞机大战小游戏

    本文实例为大家分享了python实现飞机大战的具体代码,供大家参考,具体内容如下 初学Python,写了一个简单的Python小游戏. 师出bilibili某前辈 pycharm自带了第三方库pygame,安装一下就好了,很方便. 虽然很多大佬已经给出了步骤,我这里还是啰嗦一下,也为了自己巩固一下. 上图: 这里再给出代码的逻辑架构 plane_main.py import pygame from plane_sprites import * class PlaneGame(object): "

随机推荐