Skip to content

大一下学期C++大作业项目,自己写的2d游戏引擎

Notifications You must be signed in to change notification settings

jeanhua/JHMG-engine

Repository files navigation

项目背景:该项目是为了应付我大一下C++大作业而创建

  • 该项目作为我的C++大作业已经结束,但是未来可能无聊更一点东西
    • 画个大饼(可能不会做🤣)
      • 未来可能出一个场景编辑器
      • 用lua作为脚本语言填充
      • 更多物理模拟(bushi

本人为四川大学2023级大一本科生,初学C++,项目代码质量不高,欢迎各路大佬给予指正

✅JHMG 游戏引擎

Language author

JHMG 游戏引擎是我写的一个简单的2D游戏引擎,旨在帮助快速搭建和开发2D游戏。

源仓库地址 https://github.com/jeanhua/JHMG-engine

gitee镜像地址 https://gitee.com/jeanhua/JHMG-engine

代码案例仓库

特点

  • 提供了游戏场景管理、游戏对象管理、界面显示、音效播放、用户输入处理等核心功能。
  • 包含了一系列基础的自定义类,如字符串处理、数学计算和图形操作等。
  • 易于使用和扩展,适合开发小型的2D游戏或图形应用程序。

依赖

  • EasyX:图形库,用于图形界面的绘制和处理。

下载

你可以从GitHub仓库下载源代码:

git clone https://github.com/jeanhua/JHMG-engine.git

或者点此下载各版本

类图

类图

详细信息

类介绍

GameObject

  • 描述: 代表游戏中的各种对象,可以是圆形、矩形、菱形或三角形等形状。
  • 功能:
    • 管理对象的位置、大小、图像和可见性。
    • 处理对象之间的碰撞检测。
    • 允许设置游戏循环中对象的自定义行为。

GameUI

  • 描述: 管理游戏中的用户界面元素,例如图片等。
  • 功能:
    • 控制界面元素的位置、大小、图像和可见性。
    • 处理用户界面元素的鼠标交互,如点击事件。

GameUIText

  • 描述: 管理游戏用户界面中的文本元素。
  • 功能:
    • 设置文本的内容、位置和可见性。

GameSound

  • 描述: 处理游戏音效的播放和控制。
  • 功能:
    • 播放、停止、暂停和恢复音效。
    • 设置音效的音量和播放位置。
    • 获取音效的长度和状态。

GameInput

  • 描述: 处理游戏中的键盘输入。
  • 功能:
    • 捕获键盘按键事件。

GameScene

  • 描述: 表示游戏中的一个场景,包含游戏对象、用户界面元素和文本元素。
  • 功能:
    • 管理场景中的游戏对象、用户界面元素和文本元素。
    • 处理游戏循环中的场景逻辑。

MouseAction

  • 描述: 处理游戏对象和用户界面元素的鼠标交互。
  • 功能:
    • 处理鼠标点击事件,并触发相应的回调函数。

GameInputBox

  • 描述: 处理游戏中的输入框,允许用户输入文本。
  • 功能:
    • 显示输入框,并允许用户输入文本内容。

GameMessageBox

  • 描述: 管理游戏中的消息框,用于向用户显示消息。
  • 功能:
    • 显示消息框,并显示指定的消息内容。

Game

  • 描述: 表示游戏本身,管理游戏窗口、场景、帧率和声音等。
  • 功能:
    • 初始化游戏窗口并启动游戏循环。
    • 设置游戏窗口的大小和标题。
    • 控制游戏的帧率。
    • 管理游戏中的场景和声音。
    • 处理游戏中的输入事件。

String

  • 描述: 字符串类型,提供字符串操作的功能。
  • 功能:
    • 构造函数:可以从字符串、字符数组或另一个 String 对象构造。
    • 运算符重载:支持字符串的拼接、赋值、比较等操作。
    • 类型转换:可以将字符串转换为整型、浮点型等数据类型。
    • 字符串操作:包括索引、截取、查找等操作。

Fraction

  • 描述: 分数类型,用于处理分数的计算。
  • 功能:
    • 构造函数:可以从整型、浮点型或分子分母构造分数。
    • 运算符重载:支持分数的加减乘除等运算。
    • 分数化简:将分数进行化简操作。
    • 类型转换:可以将分数转换为浮点型。

Vector2

  • 描述: 二维向量,表示坐标或方向。
  • 功能:
    • 构造函数:可以从两个浮点数构造二维向量。
    • 运算符重载:支持向量的加减乘除等运算。
    • 向量操作:包括距离计算、叉乘、点乘等操作。

List 类模板

  • 描述: 链表模板类,用于管理元素的链表结构。
  • 功能:
    • 添加元素:在链表末尾添加元素。
    • 删除元素:删除链表中的节点。
    • 构造函数:初始化链表。
    • 析构函数:释放链表内存。

Matrix

  • 描述: 矩阵类,用于矩阵的运算和处理。
  • 功能:
    • 构造函数:可以从二维数组、其他矩阵对象或行列数构造矩阵。
    • 矩阵运算:支持矩阵的加减乘、转置、逆等运算。
    • 求解行列式:计算矩阵的行列式值。
    • 判断相等:判断两个矩阵是否相等。

Transform 基类(包含子类 Circle,Rectangle,Triangle,Diamond,Trapezium)

  • 描述: 二维物体类,包括圆形、矩形、三角形、菱形等。
  • 功能:
    • 各种形状的构造:可以构造圆形、矩形、三角形、菱形等物体。
    • 移动:可以移动物体的位置。
    • 面积计算:可以计算物体的面积。
    • 碰撞检测:可以检测物体之间的碰撞。

💡基础教程

·基本思路:模块化开发,创建对象,绑定事件,加入游戏
1.创建游戏对象

  //声明全局游戏对象
Game* mainGame;
int main()
{
//创建游戏对象
mainGame = new Game;
      ······

2.设置窗口大小和标题

mainGame->setWindowSize(Vector2(800, 600));
mainGame->setWindowTitle("Game demo");

3.设置游戏帧率

mainGame->setTargetFrame(165);

4.创建游戏场景

GameScene* scene = new GameScene;

5.添加场景到游戏中

mainGame->setScene(scene);

6.创建游戏对象

GameObject* player = new GameObject(new circle(25, Vector2(170, 70)), ".\\pkq.png", 50, 50, true);

7.添加游戏对象到场景中

scene->addGameObject("player", player);

8.创建游戏UI对象

GameUI* xiaoxin = new GameUI(Vector2(0, 0), Vector2(50, 50), ".\\xiaoxin.png", true);

9.添加UI对象到场景中

scene->addGameUI("xiaoxin", xiaoxin);

10.创建文本UI对象

GameUIText* text = new GameUIText(String("fps"), Vector2(100, 100));

11.添加文本UI到场景中

scene->addGameUIText("text", text);

12.初始化窗口开始游戏

mainGame->initWindow();

其他常用代码

1.获取游戏场景

auto scene = mainGame->getScene();

2.获取游戏对象

auto player = scene->getGameObject("player");

3.获取UI对象

auto xiaoxin = scene->getGameUI("xiaoxin");

4.获取UI文本对象

auto text = scene->getGameUIText("text");

5.从场景删除物体

scene->removeGameObject("player");

6.从场景删除UI对象

scene->removeGameUI("xiaoxin");

7.从场景删除UI文本对象

scene->removeGameUIText("text")

8.获取键盘输入

auto key = mainGame->Input.getKey();
//判断键盘输入
if (key == KeyMessage::a)
{
	//键盘按下 a 的操作
}
if (key == KeyMessage::d)
{
	//键盘按下 b 的操作
}
if (key == KeyMessage::w)
{
	//键盘按下 c 的操作
}
if (key == KeyMessage::s)
{
	//键盘按下 d 的操作
}
if (key == KeyMessage::space)
{
	//键盘按下 空格 的操作
}
if (key == KeyMessage::esc)
{
	//键盘按下 Esc退出键 的操作
}

进阶教程

1.绑定游戏对象碰撞事件(物体碰撞调用)

//声明碰撞事件函数
void trigger(GameObject* other)
{
  //other是与 绑定的的游戏对象 相碰撞的 ·游戏对象· 的指针
  //碰撞输出名字
  cout << mainGame->getScene()->getName(other) << endl;
}
//绑定碰撞事件
int main()
{
  ···
  player->setOnCollision(trigger);
}

2.绑定游戏对象循环事件(每帧调用一次)

//声明循环函数
void loop()
{
  //循环事件
}
//绑定循环函数
int main()
{
  ···
  player->setGameLoopFunc(loop);
}

3.绑定游戏对象点击事件(点击调用)

//声明点击事件
void onClick(int messageType, Vector2 position,GameObject* self)
{
  //输出被点击对象id名
  cout<<mainGame->getScene()->getName(self)<<endl;
  //点击输出
  if (messageType == MouseMessage::leftDown)
	cout << "左键按下" << endl;
  if (messageType == MouseMessage::leftUp)
	cout << "左键放开" << endl;
  if (messageType == MouseMessage::rightDown)
	cout << "右键按下" << endl;
  if (messageType == MouseMessage::rightUp)
	cout << "右键放开" << endl;
}
//绑定点击事件
int main()
{
  ···
  player->mouseAction->setClickFunc(onClick);
}

完整示例

#include "JHMG engine.h"
using namespace JHMG_ENGINE;

//声明全局游戏对象
Game* mainGame;

//声明函数
void loop(GameObject* self);
void trigger(GameObject* self, GameObject* other);
void onClick(int messageType, Vector2 position,GameObject* self);

int main()
{
	//创建游戏对象
	mainGame = new Game;
	//设置窗口大小和标题
	mainGame->setWindowSize(Vector2(800, 600));
	mainGame->setWindowTitle("Game demo");
	//设置游戏帧率
	mainGame->setTargetFrame(165);
	//创建游戏场景
	GameScene* scene = new GameScene;
	//添加场景到游戏中
	mainGame->setScene(scene);
	//创建UI对象
	GameUI* xiaoxin = new GameUI(Vector2(0, 0), Vector2(800, 600), ".\\background.jpg", true);
	//添加UI对象到场景中
	scene->addGameUI("xiaoxin", xiaoxin);
	//创建文本UI
	GameUIText* text = new GameUIText(String("fps"), Vector2(100, 100));
	//添加文本UI到场景中
	scene->addGameUIText("text", text);
	//创建游戏对象
	GameObject* player = new GameObject(new Circle(25, Vector2(170, 70)), ".\\pkq.png", 50, 50, true);
	//绑定游戏对象碰撞事件(物体碰撞调用)
	player->setOnCollision(trigger);
	//绑定游戏对象循环事件(每帧调用一次)
	player->setGameLoopFunc(loop);
	//添加游戏对象到场景中
	scene->addGameObject("player", player);
	//创建游戏对象
	GameObject* pikaqiu = new GameObject(new Circle(25, Vector2(270, 70)), ".\\pkq.png", 50, 50, true);
	//绑定游戏对象点击事件(点击调用)
	pikaqiu->mouseAction->setClickFunc(onClick);
	//添加游戏对象到场景中
	scene->addGameObject("pikaqiu", pikaqiu);
	//初始化窗口开始游戏
	mainGame->initWindow();
}

void loop(GameObject* self)
{
	//获取游戏场景
	auto scene = mainGame->getScene();
	//获取游戏对象
	auto player = scene->getGameObject("player");
	//获取UI文本对象
	auto text = scene->getGameUIText("text");
	//拼接显示fps
	text->text = "fps:" + std::to_string(int(1000 / mainGame->deltaTime));
	//获取键盘输入
	auto key = mainGame->input.getKey();
	//判断键盘输入
	if (key == KeyMessage::a)
	{
		Vector2 currentPosition = player->Transform.Circle->getPosition();
		//x = deltaX + X0 = V*t + X0
		currentPosition += Vector2(-250, 0) * ((float)mainGame->deltaTime / 1000);
		player->Transform.Circle->move(currentPosition);
	}
	if (key == KeyMessage::d)
	{
		Vector2 currentPosition = player->Transform.Circle->getPosition();
		currentPosition += Vector2(250, 0) * ((float)mainGame->deltaTime / 1000);
		player->Transform.Circle->move(currentPosition);
	}
	if (key == KeyMessage::w)
	{
		Vector2 currentPosition = player->Transform.Circle->getPosition();
		currentPosition += Vector2(0, -250) * ((float)mainGame->deltaTime / 1000);
		player->Transform.Circle->move(currentPosition);
	}
	if (key == KeyMessage::s)
	{
		Vector2 currentPosition = player->Transform.Circle->getPosition();
		currentPosition += Vector2(0, 250) * ((float)mainGame->deltaTime / 1000);
		player->Transform.Circle->move(currentPosition);
	}
	if (key == KeyMessage::space)
	{
		//删除物体
		std::cout << "delete pikaqiu" << std::endl;
		scene->removeGameObject("pikaqiu");
	}
	if (key == KeyMessage::esc)
	{
		//退出游戏
		exit(0);
	}
}

void trigger(GameObject* self,GameObject* other)
{
	//碰撞输出名字
	std::cout << mainGame->getScene()->getName(other) << std::endl;
}

void onClick(int messageType, Vector2 position,GameObject* self)
{
	std::cout<<mainGame->getScene()->getName(self)<< std::endl;
	//点击输出
	if (messageType == MouseMessage::leftDown)
		std::cout << "左键按下" << std::endl;
	if (messageType == MouseMessage::leftUp)
		std::cout << "左键放开" << std::endl;
	if (messageType == MouseMessage::rightDown)
		std::cout << "右键按下" << std::endl;
	if (messageType == MouseMessage::rightUp)
		std::cout << "右键放开" << std::endl;
}