实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类
devc++ 5.11编译环境
dll编译环境设置参考
Dev c++ C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客
插件 DLL代码和主程序代码如下
注意 dll 代码中的class 类名需要 和主程序 相同
其中使用了函数指针和强制类型转换
函数指针教程参考
以动态库链接库 .dll 探索结构体参数-CSDN博客
注意,退出游戏后需等30-50秒,让dll自行销毁,然后重开时才能正常运行。否则进入后不显示地图。
有dll时:
无DLL插件读取到时,即dll不在同程序目录下
dll.h
#ifndef _DLL_H_
#define _DLL_H_
#include <iostream>
using namespace std;
// 游戏背景操作板,可以通过坐标直接改
class Bkmap
{public:Bkmap(int height,int wide){this->wide=wide;this->height=height;this->bkmap=new char*[this->height];for(int i=0; i<height; i++){this->bkmap[i]=new char[this->wide];for(int j=0; j<wide; j++){this->bkmap[i][j]='\0';}}}public:char** bkmap;int wide;int height;};// 玩家类,移动,攻击,地图修改
class Player
{public:Player(int x,int y,int limitx,int limity){this->playerx=x;this->playery=y;is_atk=0;is_buff=0;flag_x=0;flag_y=0;this->limitx=limitx;this->limity=limity;}~Player();public:char player='1';int playerx;int playery;int flag_x;int flag_y;int limitx;int limity;int is_atk;int is_buff;public:
};// 攻击类,这里直线攻击做测试
class Aking
{public:Aking(int height,int wide,int atk_time,int number){this->height=height;this->wide=wide;this->number=number;this->atk_time=atk_time;atk_count=0;}public:int height; // 攻击范围长宽int wide;int number; // 攻击序号,因为有多个攻击技能,所以编号,可以查找攻击int atk_time; // 攻击时长int atk_count; // 当前攻击持续时间public:// 攻击中void atking(Bkmap* bkmap,Player* player){if (atk_count != atk_time) // 攻击{atk_count++;cout<<"DLL"<<atk_count<<endl; cout<<"DLL:playerx player y:"<<player->playerx<<","<<player->playery<<endl;cout<<"DLL: player is_atk:"<<player->is_atk<<endl;for(int j=0; j<10; j++){bkmap->bkmap[player->playery][player->playerx+1+j]='P';}}else{atk_count=0;player->is_atk=0; // 玩家状态复位}}
};static Aking* akv3=new Aking(20,50,20,3); // 静态类,在调用时,保存被调用的值,调用结束后数值不清空 extern "C"{void mainDll(Bkmap* bkmap,Player* player);
}#endif
插件 dll.cpp
/* Replace "dll.h" with the name of your header */
#include "dll.h"
#include <windows.h>void mainDll(Bkmap* bkmap,Player* player)
{
// cout<<"DLL: atking class start"<<endl;akv3->atking(bkmap,player);
}
主程序,注意和dll放在同一个目录下
#include <iostream>
#include <string.h>
#include <windows.h>#define KEY_DOWN(vKey) ((GetAsyncKeyState(vKey) & 0x8000) ? 1:0) // 判断是否按下按键,按下之后,最高位变成 1,所以需要位运算去除其他位,只检测最高位
#define KEY_DOWN_FOREGROUND(hWnd, vk) (KEY_DOWN(vk) && GetForegroundWindow() == hWnd) // 前景窗口判断
#pragma warning(disable : 4996)
using namespace std;// 加入的游戏背景数据,通常不修改,放到 Bkmap 进行修改
class Gamemap
{public:Gamemap(int height,int wide){this->wide=wide;this->height=height;this->gamemap=new int*[this->height];for(int i=0; i<height; i++){this->gamemap[i]=new int[this->wide];for(int j=0; j<this->wide; j++){this->gamemap[i][j]=0;}}}~Gamemap();public:int** gamemap;int wide;int height;
};
// 游戏背景操作板,可以通过坐标直接改
class Bkmap
{public:Bkmap(int height,int wide){this->wide=wide;this->height=height;this->bkmap=new char*[this->height];for(int i=0; i<height; i++){this->bkmap[i]=new char[this->wide];for(int j=0; j<wide; j++){this->bkmap[i][j]='\0';}}}public:char** bkmap;int wide;int height;public:void adddata(){for(int i=0; i<this->height; i++) // 地图数据写入{for(int j=0; j<this->wide-1; j++){this->bkmap[i][j]='*';}this->bkmap[i][this->wide-1]='\0';cout<<this->bkmap[i]<<"ok"<<endl;}}void fresh(Gamemap* gamemap){for(int i=0; i<gamemap->height; i++) // 地图复印到选区{for(int j=0; j<gamemap->wide; j++){if(gamemap->gamemap[i][j]==0)this->bkmap[i][j]=' '; // 这里决定地图打印在屏幕的样子}}}};
// 字符串缓冲类
class Showmap
{public:Showmap(int height,int wide){this->showmap=new char[wide*height+1000];strcpy(showmap,"");
// showmap={}; // 不能这样写,否则报错,指针重新变空}public:char* showmap;public:void adddata(Bkmap* bkmap){cout<<"test"<<endl;if(showmap==NULL){cout<<"NULL";cout<<"函数因空指针结束"<<endl;return;}strcpy(showmap,"");for(int i=0; i<bkmap->height; i++) // 选区加入到打印缓冲区{strcat(showmap,bkmap->bkmap[i]);strcat(this->showmap,"\n");}}void show(){cout<<this->showmap;}
};// 玩家类,移动,攻击,地图修改
class Player
{public:Player(int x,int y,int limitx,int limity){this->playerx=x;this->playery=y;is_atk=0;is_buff=0;flag_x=0;flag_y=0;this->limitx=limitx;this->limity=limity;}~Player();public:char player='1';int playerx;int playery;int flag_x;int flag_y;int limitx;int limity;int is_atk;int is_buff;public://玩家移动检测void checkmove(HWND hwnd){flag_x=0;flag_y=0;if (KEY_DOWN_FOREGROUND(hwnd, 0x41)) // A{flag_x -= 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x57)) // W{flag_y -= 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x44)) // D{flag_x += 1;}if (KEY_DOWN_FOREGROUND(hwnd, 0x53)) // S{flag_y += 1;}}// 打包速度检测void checkspeed(){if (flag_x > 1) // 速度限制flag_x = 1;else if (flag_x < -1)flag_x = -1;if (flag_y > 1)flag_y = 1;else if (flag_y < -1)flag_y = -1;}// 改变玩家位置void move(){if (flag_x) // 位移改变playerx += flag_x;if (flag_y)playery += flag_y;}
// 边界检测void checkboundary(){if (playerx >= limitx) // 角色位置限制playerx = limitx - 1;else if (playerx < 0)playerx = 0;if (playery >= limity)playery = limity - 1;else if (playery < 0)playery = 0;}void putinmap(Bkmap* bkmap){bkmap->bkmap[playery][playerx]=player;}
// 检测攻击void checkatk(HWND hwnd){if (is_atk == 0 && KEY_DOWN_FOREGROUND(hwnd, 0x4A)) // j 键攻击{is_atk = 1;}}
// 检测buffvoid checkbuff(HWND hwnd){if (is_buff == 0 && KEY_DOWN_FOREGROUND(hwnd, 0x4B)) // k 键增加范围 buff{is_buff = 1;}}// 绘制地图void drawmap(HWND hwnd,Gamemap* gamemap){if (KEY_DOWN_FOREGROUND(hwnd, 0x30)) // 0 键绘制地图gamemap->gamemap[playery][playerx] = 0;if (KEY_DOWN_FOREGROUND(hwnd, 0x36)) // 6 键绘制地图gamemap->gamemap[playery][playerx] = 6;if (KEY_DOWN_FOREGROUND(hwnd, 0x37)) // 7 键绘制地图gamemap->gamemap[playery][playerx] = 7;if (KEY_DOWN_FOREGROUND(hwnd, 0x38)) // 8 键绘制地图gamemap->gamemap[playery][playerx] = 8;if (KEY_DOWN_FOREGROUND(hwnd, 0x39)) // 9 键绘制地图gamemap->gamemap[playery][playerx] = 9;}
};class Dlling
{typedef void(*Menu)(Bkmap* bkmap,Player* player); // 定义函数指针,函数返回值是 void, 指针类型名是 Menu, 参数是Bkmap*public:Dlling(char* name,int number){mainDll="mainDll";HINSTANCE hDLL = LoadLibrary(name); // 加载dll库if(hDLL==NULL){cout<<"没有在本目录里找到 dllv3.dll"<<endl;atk=NULL;Sleep(300);}else{void(*atkv2)(Bkmap* bkmap,Player*)= (void (*)(Bkmap*,Player*))GetProcAddress(hDLL,mainDll); // 加载dll 的入口主函数 强制类型转换后,加载的dll主函数成为atkv2的替身if(atkv2==NULL){cout<<"dllv3 插件没有读取"<<endl;atk=NULL;Sleep(300);}else{cout<<"dllv3 读取成功"<<endl;Sleep(300);atk = atkv2;}}count=0;}public:char* mainDll;Menu atk;int count; // 成员是一个指针,目前没有函数替身,所以没有编译报错public:void aking(Bkmap* bkmap,Player* player){cout<<"class_atkv3"<<endl;if(player->is_atk&&atk!=NULL){cout<<"class_atkv3 is going"<<endl;atk(bkmap,player); // 函数指针在初始化过程在有了替身函数,所以可以加入变量}else if(player->is_atk&&atk==NULL){cout<<"dll是空的,跳过执行函数"<<endl;count++;if(count>10){player->is_atk=0;count=0;}}}
};int main()
{Gamemap* gamemap = new Gamemap(20,50);Bkmap* bkmap=new Bkmap(20,50);Showmap* showmap= new Showmap(20,80);Dlling* dll = new Dlling("dllv3.dll",3);bkmap->fresh(gamemap);
// bkmap->adddata();showmap->adddata(bkmap);showmap->show();HWND hwnd = GetForegroundWindow(); // 获取前端窗口句柄,由于程序刚运行时是在前端,所以这就是本程序的窗口句柄Player* player = new Player(0,0,50,20);while(1){if (KEY_DOWN_FOREGROUND(hwnd, VK_ESCAPE)){printf("游戏退出\n");break;}if(KEY_DOWN_FOREGROUND(hwnd,0x31)){player->is_atk=1;}player->checkmove(hwnd);player->checkspeed();player->move();player->checkboundary();bkmap->fresh(gamemap);dll->aking(bkmap,player);player->putinmap(bkmap);showmap->adddata(bkmap);cout<<"玩家位置:"<<player->playerx<<","<<player->playery<<endl;showmap->show();Sleep(100);system("cls");}return 0;}
相关文章:
实现第一个动态链接库 游戏插件 成功在主程序中运行 dll 中定义的类
devc 5.11编译环境 dll编译环境设置参考 Dev c C语言实现第一个 dll 动态链接库 创建与调用-CSDN博客 插件 DLL代码和主程序代码如下 注意 dll 代码中的class 类名需要 和主程序 相同 其中使用了函数指针和强制类型转换 函数指针教程参考 以动态库链接库 .dll 探索结构体…...
算法第三十九天-验证二叉树的前序序列化
验证二叉树的前序序列化 题目要求 解题思路 方法一:栈 栈的思路是「自底向上」的想法。下面要结合本题是「前序遍历」这个重要特点。 我们知道「前序遍历」是按照「根节点-左子树-右子树」的顺序遍历的,只有当根节点的所有左子树遍历完成之后…...
Rust---复合数据类型之字符串与切片(2)
目录 字符串操作删除 (Delete)连接 (Concatenate)字符串转义前情回顾: Rust—复合数据类型之字符串(1) 字符串操作 删除 (Delete) 删除方法仅适用于 String 类型,分别是: pop(),remove(),truncate(),clear(),此外还有drain() 方法。 pop 方法:pop() 方法返回一个 O…...
iOS 应用内网络请求设置代理
主要通过URLSessionConfiguration 的connectionProxyDictionary 属性 为了方便其他同学使用,我们可以通过界面来进行设定(是否开启代理、服务端、端口),从而达到类似系统上的设定 具体链接参考:为 iOS 网络请求设置代理…...
什么是MariaDB
2024年4月6日,周六晚上 今晚在Debian12上安装mysql时,运行后却发现是MariaDB MariaDB是一个开源的关系型数据库管理系统(RDBMS),它是MySQL的一个分支和替代品。MariaDB由MySQL的原始开发者之一Michael "Monty&qu…...
【面试八股总结】传输控制协议TCP(三)
参考资料 :小林Coding、阿秀、代码随想录 一、TCP拥塞控制⭐ 1. 慢启动 – Slow Start 慢启动是指TCP连接刚建立,一点一点地提速,试探一下网络的承受能力,以免直接扰乱了网络通道的秩序。 慢启动算法: 初始拥塞窗口…...
今年过去了多少天?(switch)
//今年已经过去了几天? #include <stdio.h> int monthday(int year,int month){switch(month){case 1:return 31;case 2:if ((year % 4 0 && year % 100 ! 0)||year % 400 0){return 29;}else{return 28;}break;case 3:return 31;case 4:return 30;…...
提升团队工程交付能力,从“看见”工程活动和研发模式开始
作者:张裕、雅纯 理想中的研发团队应当具有以下特征: 总是工作在最高优先级的事项上 理想的研发团队能够识别并始终集中精力在当前最紧迫和最有价值的任务上。这需要团队具备出色的项目管理能力和决策能力,以便能够正确评估优先级࿰…...
前端学习之DOM编程案例:全选反选案例
代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>全选反选</title> </head> <body><input type"checkbox" id"all">全选<ul><li><…...
golang map
1.底层实现 2.如何解决hash冲突 3.扩容机制 4.无序 5.非线程安全 6.不可寻址 runtime/map.go 1.底层实现 底层基于hash表实现,实现有2个结构体hmap,bmap,map由若干个桶存储,每个桶存8个元素,使用链地址解决hash冲突 …...
设计模式:享元模式案例
让我们以游戏开发中的棋类游戏(例如国际象棋)为例来展示享元模式的代码实现。在这个例子中,棋子的类型是内部状态,而棋子的位置是外部状态。 Java 代码示例 import java.util.HashMap; import java.util.Map;// 享元接口 interf…...
pandas(day5)
一. 检测重复值 1.1 检测 data pd.read_csv("./teacher/订单数据.csv")检测行与行之前是否有重复值 data.drop_duplicates()检测 列是否有重复值出现, keep first 从前往后判定 , last是从后往前判定data.drop_duplicates(subset["产…...
如何注册midjourney账号
注册Midjourney账号比较简单,准备好上网工具,进入官网 Midjourney访问地址: https://www.midjourney.com/ 目前没有免费使用额度了,会员最低 10 美元/月,一般建议使用30美元/月的订阅方案。了解如何订阅可以查看订阅…...
探索数据结构:特殊的双向队列
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:数据结构与算法 贝蒂的主页:Betty’s blog 1. 双向队列的定义 **双向队列(double‑ended queue)**是一种特殊的队列…...
16_I2C库函数
I2C库函数 1.void I2C_DeInit(I2C_TypeDef* I2Cx);2.void I2C_Init(I2C_TypeDef* I2Cx, I2C_InitTypeDef* I2C_InitStruct);3.void I2C_StructInit(I2C_InitTypeDef* I2C_InitStruct);4.void I2C_Cmd(I2C_TypeDef* I2Cx, FunctionalState NewState);5.void I2C_DMACmd(I2C_Type…...
十八、Rust gRPC 多 proto 演示
十八、Rust gRPC 多 proto 演示 网上及各官方资料,基本是一个 proto 文件,而实际项目,大多是有层级结构的多 proto 文件形式,本篇文章 基于此诉求,构建一个使用多 proto 文件的 rust grpc 使用示例。 关于 grpc 的实现…...
【Linux】Linux64位环境下编译32位报错skipping incompatible的解决办法
本文首发于 ❄️慕雪的寒舍 问题 如题,当我尝试在wsl2的ubuntu中使用-m32选项编译32位程序的时候,出现了下面的两种报错 ❯ g -m32 test.cpp -o test1 && ./test1 In file included from test.cpp:1: /usr/include/stdio.h:27:10: fatal error…...
vue指令v-model
<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>vue指令v-model</title> </head>…...
CentOS安装MySQL数据库
一、更新yum源 #下载对应repo文件 wget -O CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-8.repo #清除缓存 yum clean all #生成新缓存 yum makecache #更新 yum update -y 二、安装MySQL #获取源 wget http://repo.mysql.com/mysql80-community-release-el7-3.…...
从B2B转向B2B2C模式:工业品牌史丹利百得的转型历程
图片来源:Twitter 在当今数据驱动的营销环境中,企业努力更好了解客户,并在整个客户旅程中提供个性化体验。史丹利百得(Stanley Black & Decker)是一家领先的工具和工业设备供应商,近年来开始重大转型。…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
XCTF-web-easyupload
试了试php,php7,pht,phtml等,都没有用 尝试.user.ini 抓包修改将.user.ini修改为jpg图片 在上传一个123.jpg 用蚁剑连接,得到flag...
基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...
vue3 字体颜色设置的多种方式
在Vue 3中设置字体颜色可以通过多种方式实现,这取决于你是想在组件内部直接设置,还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法: 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
k8s业务程序联调工具-KtConnect
概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析
Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问(基础概念问题) 1. 请解释Spring框架的核心容器是什么?它在Spring中起到什么作用? Spring框架的核心容器是IoC容器&#…...
保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek
文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama(有网络的电脑)2.2.3 安装Ollama(无网络的电脑)2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
