C++横板格斗小游戏(基于Easyx图形库)

  • 一、项目概览
  • 1.1、游戏流程一览
  • 1.2、使用技术及开发环境
  • 1.3 游戏预览
  • 二、具体功能设计
    • 2.1、窗口架构设计
    • 2.2 UI设计
    • 2.3 游戏类设计
    • 2.4 英雄类设计
    • 2.5 NPC类及BOSS设计
    • 2.6 总体类一览
  • 三、辅助判定设计
    • 3.1 按键事件函数
    • 3.2 玩家/boss行为函数
    • 3.3 位置判定函数
  • 四、技术难点

前言:本项目所有图片素材均来自网络,如有侵权,请及时联系;由于项目代码量较多,仅展示部分代码,需要源文件私信留下邮箱。

一、项目概览

1.1、游戏流程一览

本项目是一个2.5D横板格斗游戏,游戏流程简图如下所示:

游戏共设计了4个主界面以及多个次级界面,4个主界面分别为:开始游戏界面、主城镇界面、武斗场界面、夜市界面;次级界面包括:暂停界面、物品栏界面、各级UI界面等。
实现的功能:八方向移动、待机动画、场景切换、智能NPC、对战系统、背包系统、技能释放、朝向判定、动态UI。

1.2、使用技术及开发环境

开发环境:Visual studio 2022、Easyx图形库、C++。
本项目使用技术:Easyx图形库相关、类(抽象类)、继承、多态、封装、vector容器、window api、gdi函数、双缓冲绘图、inline、虚函数重写等。

1.3 游戏预览

C++小游戏预览

二、具体功能设计

2.1、窗口架构设计

设计游戏面临的第一个问题就是如何打开窗口并绘制图片,选择Easyx图形库进行游戏设计的基底,利用其中的库函数进行窗口的绘制;加载、输出透明位图以实现游戏图像;在此处设计了基本的windows类,以进行基本的创建窗口,获取鼠标信息的功能。
但是游戏是一个动态的画面,如何将静态的画面转变为动态?这里使用了双缓冲绘图函数,它会在每一次调用flushdraw函数的时候输出缓冲区中的所有图片,我们设定一个刷新时间,将不同次序的图片依次进行刷新,就可以实现动态的效果,考虑到整个游戏都需要持续使用双缓冲输出,将他设计在windows类中,并赋为static以方便调用。

class window  //窗口界面
{
public:window(int w, int h, int flag);void setwindowtitle(const std::string& title);int exec();static int width();static int height();static void clear();static void beginDraw();static void flushDraw();static void endDraw();//按键与鼠标inline static bool hasMsg() //有无鼠标/键盘信息{return ::peekmessage(&m_msg, EX_MOUSE | EX_KEY);}inline static const ExMessage& getMsg() //获得信息{return m_msg;}
private:HWND m_handle; //窗口句柄inline static ExMessage m_msg; //鼠标和键盘消息

Windows类:行为:打开窗口、获取窗口的长度、宽度、peek鼠标操作信息并返回给调用者、双缓冲绘图。
私有属性:打开窗口获得的句柄、保存鼠标消息的类型为Exmessage的变量。

2.2 UI设计

在初始进入游戏时,一般会有选择开始游戏等功能的菜单,实现菜单,即实现鼠标点击不同地方造成不同结果的功能,为了实现这个功能,需要设计一个按钮类,以及一个GUI类来配合按钮进行跳转;考虑到控件类型较多,直接设计一个控件抽象类作为基类:

class Basicwidget //窗口/按钮控件抽象类
{
public:Basicwidget(int x, int y, int w, int h); //初始化坐标 宽 高int width(); //获取宽 高int height();void setfixedsize(int w, int h); //设置宽高int x();//获取坐标int y();void move(int x, int y); //设置x y坐标virtual void show() = 0; //纯虚
protected:int m_x, m_y, m_w, m_h; //坐标和宽高 属性
};

Basicwidget基类:行为: 获取控件宽、高、坐标、设置宽、高、坐标、以及显示控件的纯虚函数。
私有属性:坐标和宽高。

class pushbutton :public Basicwidget  //按钮类
{
public:pushbutton(const std::string& text = "button", int x = 0, int y = 0, int w = 100, int h = 30);//按钮初始化默认值和按钮内容void show() override; //虚函数重写void showhp(); //绘制hpvoid showmp(); //绘制mpbool isin();//判断鼠标是否在当前按钮上bool isclicked(); // 判断鼠标是否点击了按钮void evenloop(const ExMessage& msg); //事件循环
private:std::string m_text;  //按钮中的文字ExMessage m_msg; //鼠标信息COLORREF cur_c = RGB(225, 215, 222);COLORREF normal_c = RGB(225,215,222); //正常颜色COLORREF hover_c = GREEN; //检测到指针的颜色
};

Pushbutton子类:继承自控件基类,行为:重写过的用于显示按钮的show函数,判断鼠标位置和是否点击、以及改变按钮表现形式的事件循环。
私有属性:接收鼠标信息的类型为Exmessage的变量、按钮中的文字、按钮各种情况下的表现形式。

class GUI //ui类
{
public:GUI(); //初始化uivoid run(); //功能菜单int menu();void startgame(game* k,hero* player,boss* lin);void drawbackground(); void evenloop();
private:IMAGE m_bk; //图片变量ExMessage m_msg; //鼠标和键盘消息std::vector<IMAGEp*>menu_btns; //创建一个向量menu_btns 元素类型为IMAGEp*
};

GUI类:行为:提供界面的跳转切换、进行UI的初始化。
私有属性:用作背景的图片类型的变量、接收鼠标信息的类型为Exmessage的变量,以及一个vector向量组,用于单独控制按钮。
在后期的优化中,设计了IMAGEp类,以图片按钮代替简单的绘制按钮,只是更改了vector向量的类型,基本实现方法是一致的。

class IMAGEp //用作ui的图片
{
public:IMAGEp(int x, int y, int w, int h);int width(); //获取宽 高int height();void setfixedsize(int w, int h); //设置宽高int x();//获取坐标int y();void show();void move(int x, int y); //设置x y坐标bool isin();//判断鼠标是否在当前按钮上bool isclicked(); // 判断鼠标是否点击了按钮IMAGE UI;void evenloop(const ExMessage& msg,int i); //事件循环
private:IMAGE ui_bk[5];ExMessage g_msg; //ui消息判定int m_x, m_y, m_w, m_h; //坐标和宽高 属性
};

实现功能:动态UI:当鼠标移动到UI上时,UI图片会放大显示。

2.3 游戏类设计

在主界面。即GUI控制的界面选择开始游戏后,即进入正式的游戏流程,我们首先需要设计一个游戏类,以支持游戏运作的基础条件,主要功能即为背景的绘制、loading动画加载、各个场景间的切换,实际上,所有的动作判断都在场景子函数中进行,它是游戏运行的基础。
Game类:行为:进入各个场景的子函数、绘制各类背景、以及部分ui的绘制
私有属性:接收鼠标信息的类型为Exmessage的变量,用作UI的图片变量组、以及vector向量组。
实现功能:三个主界面的挑战,各类判定,包括坐标判定、行为判定、按键判定、伤害判定、以及各类杂项判定

2.4 英雄类设计

在搭建好基本的游戏架构后,需要设计玩家可以操作的角色,即设计一个hero类;首先对hero的基本行为进行抽取,即攻击、行走、待机、受击、死亡;同样使用双缓冲绘图以实现动态动画,同时考虑玩家具有的属性,即HP、MP、防御、攻击力、坐标。这就是基本的4个属性和行为;在实际实现时,给hero赋予了各种各样的bool类型的变量,如向上、向下、向左、向右、攻击、受击、倒地等,制作了判断按键的子函数keyevent,使用GetAsyncKeyState()函数控制各个bool类型的变量,同时改变坐标以控制英雄的动作。

class hero
{
public:hero(); //初始化int width(); //获取玩家图片宽 高int height();void setfixedsize(int w, int h); //设置hero图片宽高int x(); //获取坐标int y();void setheroxy(int x, int y);//设置玩家坐标int gethp(); //获取血量int getmp(); //蓝量int getattack(); //攻击int getdefn(); //防御void setgame(int a, int b, int c = 1000, int d = 1000);//设置玩家属性void drawhero(int heroindex); //绘制herovoid heroright(int heroindex);//hero 8 方向绘制void heroleft(int heroindex);void heroup(int heroindex);void herodown(int heroindex);void heroyx(int heroindex); //右下void heroys(int heroindex); //右上void herozs(int heroindex); //左上void herozx(int heroindex); //左下void drawattribute(); //绘制状态栏void drawherobackage(); //绘制背包void drawherobackagepicture(int heroindex); //绘制背包界面人物void drawskill(bool a,int heroindex); //hero技能void drawskill2(bool a,int heroindex); //hero技能2void drawskill3(int heroindex);void drawattack (bool a, int heroindex);//hero攻击动作void drawdeath(bool a,int heroindex); //hero击倒特效void drawlight(int heroindex);int herolocal = 0;int heroxp = 0;int herolp = 0;
private:int herox, heroy, herow, heroh, hp, mp, attack, defn;IMAGE heropicture[65], heropictureright[6], heropictureleft[6], heropictureup[6], heropicturedown[6], heropictureyx[6], heropictureys[6], heropicturezx[6], heropicturezs[6]; //人物动作IMAGE herobackage, herobackagepicture[65],herolight[16];IMAGE attackpicturel[10], attackpicturer[10]; //攻击动作IMAGE skillpicture[10],skillpicture1[10],skillpicture2[10],skillpicture3[10];//技能动作IMAGE deadpicturer[4], deadpicturel[4]; //击倒/死亡std::vector<pushbutton*>attribute; //创建一个向量attribute 元素类型为pushbutton* 用于界面绘制std::vector<IMAGEp*>skill_btns;

Hero类:行为:获取坐标、设置坐标、图片宽高、hp、mp等属性、绘制各个状态下的动画
私有属性:4个基本属性、坐标、图片类型的数组,以及一个用于实时绘制血条和蓝条的vector向量。
实际实现中的判定比较复杂,共支持8个方向的自由移动,如在控制上和控制右的bool量激活后,英雄会斜向移动。攻击、受击的同时无法进行移动。在绘制英雄的状态时,使用了上面的pushbutton子类,重叠绘制两个按钮,上层的按钮上色,并且大小跟随hero的hp进行改变,以实现动态血条效果。
实现功能:可被玩家控制的角色(八个方向的移动、传送、释放技能、状态栏绘制)。

2.5 NPC类及BOSS设计

游戏中的npc和boss同样是可以移动的人物,区别在于没有玩家去进行控制,而且普通的npc仅用于交互,但boss的动作更加丰富,所以将npc设计为基类,将boss设计为子类,行为与属性与英雄类相似;npc的设计较为简单,只需要提供一个固定的坐标,并循环播放待机动画即可实现他的功能;但是boss的设计比较复杂,由于没有玩家控制,需要设计一套足以自洽的行动逻辑用于boss的行动控制。
具体实现中,同样对boss赋予一系列的bool量来实现较为真实的交互,为了使boss自行动作,通过种子每隔一段时间生成一个随机数,以随机数的范围进行判定来实现不同的动作,通过改变判定的区间来改变各种动作的概率。考虑到boss撞墙,在判定到达极限xy坐标后,立即生成控制相反范围的随机数,以实现较为无序的控制,避免boss卡在角落。
实现功能:系统自动控制的boss,可以与玩家进行对战与交互。

2.6 总体类一览

用于实现游戏窗口的windows类、用于进行初始化界面和跳转的GUI类、用做按钮、属性绘制等功能的控件抽象类basicwidget和子类pushbutton,以及优化后的图片UI类IMAGEp,承载游戏运行的game类、以及人物类hero、npc、boss。

三、辅助判定设计

3.1 按键事件函数

自定义按键事件函数keyevent,用于判断用户的键盘输入,使用GetAsyncKeyState()函数判断用户按键是否按下,以此控制hero相对于的bool类型的变量以控制移动或释放技能。使用多段if结构同时判断各个按键。
同时boss也拥有单独的keyevent函数,用户时根据键盘输入进行判定,而boss的key是根据种子生成的随机数进行判定,基本原理都是更改对应类型的bool量。
此函数位于game类的各个场景行为中,所有辅助判定函数为一个单独的cpp,不包含在类中。

3.2 玩家/boss行为函数

自定义玩家行为函数heroactioncheck(),根据hero的各个类型的bool量判断应该播出什么动画,控制hero进行动作,通过hero类中的设置坐标、绘制动作行为实现。

3.3 位置判定函数

自定义位置判定函数herolocationcheck(),实时判定hero的坐标,以实现定点传送、范围受击等功能。具体实现是判断了hero的坐标与目标坐标的相对距离,若在范围内,则将相应的bool量置为true并执行相应动作。

四、技术难点

首先是透明底色png图片的输出,若直接使用Easyx库函数putimage,会导致输出的图片底色为黑,开始使用了基于window api函数的transparentblt进行透明化底色,但效果相当不好,会有大幅度的黑边,观感很差。然后尝试了使用RGB像素与操作,对每个像素点进行与操作,屏蔽掉不需要的颜色,此方法效果很好,但在图片超出屏幕范围时,及其容易导致像素数组越界,导致栈冲突,最终使用了window api函数alphablend,根据图片的alpha属性以进行透明底色的输出,此方法效果较好,但只支持在window下底色就为透明的png图片。
然后是对于各个类行为的抽象,对于各个基类的抽象可能比较模糊,如GUI类和game类,在初次抽象时,感觉有很多功能相似,如加载背景和跳转的UI,但根本上,实际的动作判定都是在game类的动作中实现的,GUI仅仅只是提供基本的进入游戏的初始载入、跳转和基本UI。
对于人物的抽象则比较灵活,其实玩家类在本质上也是一个NPC类,将其抽象为npc的子类也是可以实现的,但考虑到后续数据的冗杂度,最终还是将其拆分。
其次就是对各类状态bool量的判定,各个子函数都对bool量有影响,比如受击的范围判定、受击时不能移动或释放技能,这需要在构架判定时互相自洽,同时要考虑到如何恢复到动作前的状态,由于动作一直由双缓冲输出实现,也要考虑到判定的时间先后关系等。

C++横板格斗小游戏(基于Easyx图形库)相关推荐

  1. QT横板格斗小游戏——基于网编的重构

    QT横板格斗小游戏--基于网编的重构 一.项目概览 二.具体功能设计 2.1 Npc基类 2.2 Boss子类 2.3 Hero类 2.4 Widget类 2.5 GameContral基类 2.6 ...

  2. 贪吃蛇小游戏 c++ easyx图形库实现

    贪吃蛇小游戏 c++ easyx图形库实现 实施思路 1.用上下左右键来控制方向 2.按enter键开始 暂停 3.通过随机函数来实现食物的随机出现 4.通过单链表来构造蛇 5.蛇撞墙    咬到自己 ...

  3. 源码篇-2048小游戏(需要EasyX图形库)

    本项目需要EasyX图形库,若没有可在www.easyx.cn网上下载哦 ! 可以选择一个游戏音乐哦! mciSendString函数 Parameters lpszCommand 指向一个以空结束的 ...

  4. 用easyx画电子钟_基于EasyX图形库的多线程绘图应用

    本文<基于EasyX图形库的多线程绘图应用>由手机部落整理,仅供参考.如果觉得很不错,欢迎点评和分享-感谢你的阅读与支持! 张煜昕 摘要:EasyX 是C++语言进行图形化编程和游戏编程的 ...

  5. C++写的是男人就下一百层小游戏,基于EasyX图形库(本人菜鸟)

    是男人就下一百层 小游戏 游戏整体源代码已打包,在最下面 首先建立一个board类: #pragma once #ifndef BOARD_H_ #define BOARD_H_ const int ...

  6. c语言/c++大作业基于easyx图形库自制RPG类型小游戏代码(附源码)

    目录 一.游戏玩法 二.完整代码 三.部分细节 透明化人物背景 关于easyx库中怎样贴出透明图片 地图的链表实现 移动检测 碰撞检测 总结 前言: 花两天边看easyx文档边学边写的期末小作业. 学 ...

  7. c语言基于easyX樱花特效,C++基于easyx图形库实现推箱子游戏

    本文实例为大家分享了C++实现推箱子游戏的具体代码,供大家参考,具体内容如下 头文件: #include #include //#include #include #include #include ...

  8. C/C++语言扫雷小游戏(eaxyX图形库的应用)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一.扫雷的玩法,以及实现功能介绍 二.代码实现 1.引入库 2.宏定义部分 3.初始化游戏界面 4.加载图片 5.绘制 ...

  9. Python编写的猜数字小游戏~~~基于Tkinter库

    Python编写猜数字小游戏 编写猜数字小游戏 一.界面 1.PyQt5 2. wxPython 3. PyGTK 二.Tkinter功能 ① 15种核心组件 ② 组件的放置和排版(pack,grid ...

  10. 大一c语言期末小游戏(easyx)--生老病死(粗糙模仿4399小游戏)

    这个游戏小项目上手很简单,在改动方面有很大的操控性,由于自身技术的不足和惰性,小游戏其实可以变得更好,但是作为第一个我上手的小游戏,还是把基础的分享给大家,把更多的可能性留给愿意上手这款游戏的朋友们. ...

最新文章

  1. 如何查看crontab的日志记录
  2. DataGridView数据控件演示
  3. java rpm_Java JDK rpm安装与配置
  4. HTTP 500 服务器内部错误的解决方法
  5. salt-api timeout 执行超时问题解决
  6. C#的多线程机制探索4
  7. bootstrap 点击加号 表格_bootstrap中的输入组按钮,点击加号加1,减1子
  8. Qt QGraphics体系及刷新机制介绍
  9. vue中mixin的一点理解
  10. B树、B+树、B*树谈到R 树
  11. python 日志内容提取
  12. android 连接指定wifi
  13. 程序员面试金典 - 面试题 16.14. 最佳直线(哈希map+set)
  14. procyon java8_java jdk 8反编译工具JD-GUI、procyon-decompiler、luyten、crf下载使用简介
  15. php 数组 构造为树,从PHP中的平面数组构建树
  16. 欢乐大作战服务器维护,欢乐大作战
  17. Curl 方式实现POST提交数据
  18. 管理感悟:软件公司不加班还搞什么软件
  19. 高数——八种求极限方法总结
  20. matlab 2010 win10,win10系统运行matlab2010找不到指定的程序的教程介绍

热门文章

  1. 天才在左,疯子在右读书笔记 -- 高铭著
  2. 赴日java常问问题_赴日软件工程师java笔试题
  3. 新型电话诈骗手法“明天到我办公室来一下”全揭秘
  4. Key(Windows Android),申请 android google 地图 API key(转)
  5. python粒子特效_初试PyOpenGL四 (Python+OpenGL)GPU粒子系统与基本碰撞
  6. CC(标准)版D碟收藏指南(三)
  7. linux ntfs 安装教程,Linux NTFS文件系统安装教程
  8. mp3转为pcm工具
  9. 微信接口开发,config提示OK,但分享不成功
  10. 华裔天才数学家-陶哲轩