到现在为止,我们已经将疯狂坦克外挂所需相关的功能点及解决方案完成。

先说说常规的使用方法:

1、编译发布程序后,先运行程序(默认不可见),然后进入美服疯狂坦克。

2、在游戏中按(Pause)键启动各种辅助线。

3、在游戏中按(Scroll Lock)键切换你当前所用的坦克。

4、在游戏中鼠标放到你坦克所在的位置(小地图上圆点中心),按下(PrScrn SysRq)键确定曲线起点。

5、通过(Insert)和(Delete)键调节角度标识与游戏中坦克实际角度线端点重合。

6、通过(Home)和(End)键调节风力标识与游戏中风力线边缘重合。

7、通过(PgUp)和(PgDn)建调节力度,直到小地图上的抛物线穿过你要命中的目标。

8、按一下键盘上的左边的(Control)键,将会按照预先设定的抛物线发射炮弹命中目标。

PS:所有调节按键,同时按下(Shift)键为粗调,放开(Shift)键后为精调。

由于游戏中不同的坦克的风力系统、推力系数、重力系数、满力时间不一样,所以请使用各种坦克经过多次测试得出系数。

具体测试各种坦克的相关系数方法:

1、选中某一款坦克,然后多次测试,根据炮弹的落点与小地图上曲线落点的误差调节该坦克的风力系统、推力系数、重力系数,直到精确。

2、多次测试根据推力标识与实际力度边缘线的误差调节该坦克的满力时间这一系数。

3、将各种测量后的系数写入配置文件中保存。

截止到目前为止,一个疯狂坦克辅助瞄准外挂的基本功能就完成了。但是这样的外挂其实是存在一些功能缺陷的,如下:

1、不能够直接读取游戏内存中的数据,来获取当前的角度、风力和力度等值,而是通过绘制和调节辅助线来获取。

2、不能够直接识别出当前正在使用的坦克的名称和加载相关参数,需要通过手动切换坦克。

3、未将各种坦克的四个系数都预设好,因为我真的没有这个时间和耐性。

以上的功能缺陷,最大的一个技术障碍就是不能够在游戏运行过程中从内存中获取相关的数据。

这也是为什么美服没有瞄准外挂而且当初国服的外挂在美服用不了的原因把。

个人推测是因为在某一次游戏更新过程中,将原来直接写到动态内存中的这些相关数据改为加密后再写入内存。

所以不管用FPE或者金山游侠等内存查询工具,均不能够在内存中发现任何的相关数据明文。

如果有朋友对其加密方式有研究,或者能够提供获取这些数据的解决方法,请与我联系指正。

如果能够获取到这些数据,这个外挂功能就算比较完整了,使用起来也没这么麻烦,如国服当年的坦克猎手4.1。

下面是程序的所有源码,稍后我会放到CSDN下载中心一份完整的源码,不知道是否能通过审核。

本程序仅限用于学习研究,请不要破坏游戏平衡,谢谢。

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Text;
  7. using System.Xml;
  8. using System.Windows.Forms;
  9. using System.Runtime.InteropServices;
  10. using System.Diagnostics;
  11. using GlobalMouseKeyBoardHook;
  12. namespace BBTankAssistant
  13. {
  14. public partial class Form1:Form
  15. {
  16. #region ====变量定义====
  17. //全局鼠标钩子
  18. private KeyboardHook KH;
  19. //全局键盘钩子
  20. private MouseHook MH;
  21. //炮弹初始位置(坦克所在位置坐标)
  22. private Point PrimaryCoordinate;
  23. //炮弹运行位置(某一时刻炮弹所在位置坐标)
  24. private Point MovementCoordinate;
  25. //炮弹运行轨迹(炮弹可能出现的所有位置坐标)
  26. private IList<Point> MoveKeyCoordinates;
  27. //风力大小
  28. private float WindPower;
  29. //推力大小
  30. private float PushPower;
  31. //推力角度
  32. private double PushAngle;
  33. //当前坦克编号
  34. private int TankNumberNowPlay;
  35. //当前坦克
  36. private Tank TankNowPlay;
  37. //计时器
  38. private Stopwatch SW;
  39. #endregion
  40. #region ====外部方法====
  41. //外部方法:获取DC
  42. [DllImport("User32.dll")]
  43. public extern static System.IntPtr GetDC(System.IntPtr hWnd);
  44. //外部方法:释放DC
  45. [DllImport("User32.dll")]
  46. static extern int ReleaseDC(IntPtr hWnd,IntPtr hDC);
  47. //外部方法:刷新区域
  48. [DllImport("user32.dll",CharSet = CharSet.Auto)]
  49. public static extern bool InvalidateRect(IntPtr hWnd,IntPtr lpRect,bool bErase);
  50. #endregion
  51. public Form1()
  52. {
  53. InitializeComponent();
  54. }
  55. private void Form1_Shown(object sender,EventArgs e)
  56. {
  57. this.Hide();
  58. }
  59. private void Form1_Load(object sender,EventArgs e)
  60. {
  61. #region ====变量初始化====
  62. KH = new KeyboardHook();
  63. MH = new MouseHook();
  64. KH.Start();
  65. MH.Start();
  66. KH.KeyDown += new KeyEventHandler(KeyBoardHook_KeyDown);
  67. KH.KeyUp += new KeyEventHandler(KeyBoardHook_KeyUp);
  68. KH.KeyPress += new KeyPressEventHandler(KeyBoardHook_KeyPress);
  69. MH.MouseDown += new MouseEventHandler(MouseHook_MouseDown);
  70. MH.MouseUp += new MouseEventHandler(MouseHook_MouseUp);
  71. PrimaryCoordinate = new Point(487,56);
  72. WindPower = 0;
  73. PushPower = 0;
  74. PushAngle = 30;
  75. TankNumberNowPlay = 0;
  76. TankNowPlay = Common.GetAllTanks()[0];
  77. SW = new Stopwatch();
  78. #endregion
  79. }
  80. private void timer1_Tick(object sender,EventArgs e)
  81. {
  82. DrawAssistantLine();
  83. }
  84. private void timer2_Tick(object sender,EventArgs e)
  85. {
  86. if(SW.ElapsedMilliseconds <  TankNowPlay.MaxPowerTime * PushPower / 322)
  87. {
  88. KeyboardSimulator.KeyDown(Keys.Space);
  89. }
  90. else
  91. {
  92. KeyboardSimulator.KeyUp(Keys.Space);
  93. SW.Reset();
  94. timer2.Enabled = false;
  95. }
  96. }
  97. public void KeyBoardHook_KeyDown(object sender,KeyEventArgs e)
  98. {
  99. #region ====按键绑定====
  100. switch(e.KeyCode)
  101. {
  102. case Keys.Pause:
  103. timer1.Enabled = true;
  104. break;
  105. case Keys.Scroll:
  106. ChangeNextTank();
  107. break;
  108. case Keys.Insert:
  109. PushAngle += e.Shift ? 10 : 1;
  110. break;
  111. case Keys.Delete:
  112. PushAngle -= e.Shift ? 10 : 1;
  113. break;
  114. case Keys.Home:
  115. if(WindPower < 36)
  116. {
  117. WindPower += e.Shift ? 10 : 1;
  118. }
  119. break;
  120. case Keys.End:
  121. if(WindPower > -36)
  122. {
  123. WindPower -= e.Shift ? 10 : 1;
  124. }
  125. break;
  126. case Keys.PageUp:
  127. if(PushPower < 322)
  128. {
  129. PushPower += e.Shift ? 10 : 1;
  130. }
  131. break;
  132. case Keys.PageDown:
  133. if(PushPower > 0)
  134. {
  135. PushPower -= e.Shift ? 10 : 1;
  136. }
  137. break;
  138. case Keys.PrintScreen:
  139. PrimaryCoordinate = MouseSimulator.Position;
  140. break;
  141. case Keys.LControlKey:
  142. SW.Start();
  143. timer2.Enabled = true;
  144. break;
  145. default:
  146. break;
  147. }
  148. #endregion
  149. }
  150. public void KeyBoardHook_KeyUp(object sender,KeyEventArgs e)
  151. {
  152. }
  153. public void KeyBoardHook_KeyPress(object sender,KeyPressEventArgs e)
  154. {
  155. }
  156. public void MouseHook_MouseDown(object sender,MouseEventArgs e)
  157. {
  158. }
  159. public void MouseHook_MouseUp(object sender,MouseEventArgs e)
  160. {
  161. }
  162. //切换下一坦克
  163. public void ChangeNextTank()
  164. {
  165. IList<Tank> ILT = new List<Tank>();
  166. ILT = Common.GetAllTanks();
  167. if((ILT !=null)&&(ILT.Count > 0))
  168. {
  169. if(TankNumberNowPlay < ILT.Count -1 )
  170. {
  171. TankNumberNowPlay += 1;
  172. }
  173. else
  174. {
  175. TankNumberNowPlay = 0;
  176. }
  177. TankNowPlay = ILT[TankNumberNowPlay];
  178. }
  179. else
  180. {
  181. TankNowPlay = null;
  182. }
  183. }
  184. //绘图
  185. public void DrawAssistantLine()
  186. {
  187. #region ====绘图准备====
  188. Pen Pe = new Pen(Color.Red,1);
  189. SolidBrush SB = new SolidBrush(Color.Green);
  190. IntPtr ScreenHandle = GetDC(IntPtr.Zero);
  191. Graphics G = Graphics.FromHdc(ScreenHandle);
  192. #endregion
  193. #region ====绘制坦克名称====
  194. G.DrawString(TankNowPlay.Name,new Font("宋体",12),SB,PrimaryCoordinate);
  195. #endregion
  196. #region ====绘制参考线====
  197. //绘制角度线条
  198. G.DrawLine(Pe,74,427,74 + float.Parse((37 * Math.Cos(PushAngle * Math.PI / 180)).ToString()),427 - float.Parse((37 * Math.Sin(PushAngle * Math.PI / 180)).ToString()));
  199. //绘制角度端点
  200. G.FillEllipse(SB,72 + float.Parse((37 * Math.Cos(PushAngle * Math.PI / 180)).ToString()),425 - float.Parse((37 * Math.Sin(PushAngle * Math.PI / 180)).ToString()),4,4);
  201. //绘制风力线
  202. G.DrawLine(Pe,74 + WindPower,469,74 + WindPower,477);
  203. //绘制推力线
  204. G.DrawLine(Pe,224 + PushPower,438,224 + PushPower,454);
  205. #endregion
  206. #region ====绘制辅助线====
  207. 绘制角度边框
  208. //G.DrawEllipse(Pe,35,388,74,74);
  209. 绘制推力边框
  210. //G.DrawRectangle(Pe,224,438,322,16);
  211. 绘制风力边框
  212. //G.DrawRectangle(Pe,38,469,72,8);
  213. 绘制地图边框
  214. //G.DrawRectangle(Pe,482,5,153,95);
  215. #endregion
  216. #region ====计算运行轨迹====
  217. MovementCoordinate = PrimaryCoordinate;
  218. MoveKeyCoordinates = new List<Point>();
  219. double MoveTime = 0;
  220. while(((MovementCoordinate.X > Parabola.GraphRangeXmin) && (MovementCoordinate.X < Parabola.GraphRangeXmax)) && ((MovementCoordinate.Y > Parabola.GraphRangeYmin) && (MovementCoordinate.Y < Parabola.GraphRangeYmax)))
  221. {
  222. MovementCoordinate = new Point();
  223. MovementCoordinate.X = int.Parse(Math.Round(PrimaryCoordinate.X + TankNowPlay.PushCoefficient * PushPower * Math.Cos(PushAngle * Math.PI / 180) * MoveTime + (TankNowPlay.WindCoefficient * WindPower * MoveTime * MoveTime) / 2,0).ToString());
  224. MovementCoordinate.Y = int.Parse(Math.Round(PrimaryCoordinate.Y - TankNowPlay.PushCoefficient * PushPower * Math.Sin(PushAngle * Math.PI / 180) * MoveTime + (TankNowPlay.GravityCoefficient * MoveTime * MoveTime) / 2,0).ToString());
  225. MoveKeyCoordinates.Add(MovementCoordinate);
  226. MoveTime += Parabola.GraphFreq;
  227. }
  228. #endregion
  229. #region ====绘制弹道曲线====
  230. Point[] Ps = new Point[MoveKeyCoordinates.Count];
  231. MoveKeyCoordinates.CopyTo(Ps,0);
  232. //绘制弹道曲线
  233. G.DrawLines(Pe,Ps);
  234. #endregion
  235. #region ====释放所有资源====
  236. //InvalidateRect(System.IntPtr.Zero,System.IntPtr.Zero,false);
  237. Pe.Dispose();
  238. SB.Dispose();
  239. G.Dispose();
  240. ReleaseDC(IntPtr.Zero,ScreenHandle);
  241. #endregion
  242. }
  243. }
  244. #region ====通用函数====
  245. public static class Common
  246. {
  247. //读取配置文件内容
  248. public static string GetConfigValue(string XmlPath)
  249. {
  250. XmlDocument XD = new XmlDocument();
  251. XD.Load(AppDomain.CurrentDomain.BaseDirectory + "../..../../BBTankAssistant.config");
  252. XmlNode XN = XD.SelectSingleNode(XmlPath);
  253. if(XN != null)
  254. {
  255. return XN.InnerText;
  256. }
  257. else
  258. {
  259. return null;
  260. }
  261. }
  262. //更新配置文件内容
  263. public static void SetConfigValue(string XmlPath,string ConfigValue)
  264. {
  265. XmlDocument XD = new XmlDocument();
  266. XD.Load(AppDomain.CurrentDomain.BaseDirectory + "../../BBTankAssistant.config");
  267. XmlNode XN = XD.SelectSingleNode(XmlPath);
  268. if(XN != null)
  269. {
  270. XN.InnerText = ConfigValue;
  271. XD.Save(AppDomain.CurrentDomain.BaseDirectory + "../../BBTankAssistant.config");
  272. }
  273. }
  274. //获取所有坦克对象
  275. public static IList<Tank> GetAllTanks()
  276. {
  277. XmlDocument XD = new XmlDocument();
  278. XD.Load(AppDomain.CurrentDomain.BaseDirectory + "../../BBTankAssistant.config");
  279. XmlNodeList XNL = XD.SelectNodes("//Tank");
  280. if(XNL.Count > 0 )
  281. {
  282. IList<Tank> ILT = new List<Tank>();
  283. foreach(XmlNode XN in XNL)
  284. {
  285. Tank T = new Tank(XN.FirstChild.InnerText);
  286. ILT.Add(T);
  287. }
  288. return ILT;
  289. }
  290. else
  291. {
  292. return null;
  293. }
  294. }
  295. }
  296. #endregion
  297. #region ====弹道模型====
  298. public static class Parabola
  299. {
  300. //Xmin
  301. public static int GraphRangeXmin
  302. {
  303. get
  304. {
  305. return int.Parse(Common.GetConfigValue("//ParabolaGraphRange").Split(',')[0]);
  306. }
  307. }
  308. //Xmax
  309. public static int GraphRangeXmax
  310. {
  311. get
  312. {
  313. return int.Parse(Common.GetConfigValue("//ParabolaGraphRange").Split(',')[1]);
  314. }
  315. }
  316. //Ymin
  317. public static int GraphRangeYmin
  318. {
  319. get
  320. {
  321. return int.Parse(Common.GetConfigValue("//ParabolaGraphRange").Split(',')[2]);
  322. }
  323. }
  324. //Ymax
  325. public static int GraphRangeYmax
  326. {
  327. get
  328. {
  329. return int.Parse(Common.GetConfigValue("//ParabolaGraphRange").Split(',')[3]);
  330. }
  331. }
  332. //Freq
  333. public static double GraphFreq
  334. {
  335. get
  336. {
  337. return double.Parse(Common.GetConfigValue("//ParabolaGraphFreq"));
  338. }
  339. set
  340. {
  341. Common.SetConfigValue("//ParabolaGraphFreq",value.ToString());
  342. }
  343. }
  344. }
  345. #endregion
  346. #region ====坦克模型====
  347. public class Tank
  348. {
  349. #region ====字段====
  350. //名称
  351. private string m_Name;
  352. #endregion
  353. #region ====属性====
  354. //名称
  355. public string Name
  356. {
  357. get
  358. {
  359. return m_Name;
  360. }
  361. set
  362. {
  363. m_Name = value;
  364. }
  365. }
  366. //风力系数
  367. public double WindCoefficient
  368. {
  369. get
  370. {
  371. return double.Parse(Common.GetConfigValue("//Tank[@Name='"+m_Name+"']/WindCoefficient"));
  372. }
  373. set
  374. {
  375. Common.SetConfigValue("//Tank[@Name='" + m_Name + "']/WindCoefficient",value.ToString());
  376. }
  377. }
  378. //推力系数
  379. public double PushCoefficient
  380. {
  381. get
  382. {
  383. return double.Parse(Common.GetConfigValue("//Tank[@Name='" + m_Name + "']/PushCoefficient"));
  384. }
  385. set
  386. {
  387. Common.SetConfigValue("//Tank[@Name='" + m_Name + "']/PushCoefficient",value.ToString());
  388. }
  389. }
  390. //重力系数
  391. public double GravityCoefficient
  392. {
  393. get
  394. {
  395. return double.Parse(Common.GetConfigValue("//Tank[@Name='" + m_Name + "']/GravityCoefficient"));
  396. }
  397. set
  398. {
  399. Common.SetConfigValue("//Tank[@Name='" + m_Name + "']/GravityCoefficient",value.ToString());
  400. }
  401. }
  402. //满力时间
  403. public double MaxPowerTime
  404. {
  405. get
  406. {
  407. return double.Parse(Common.GetConfigValue("//Tank[@Name='" + m_Name + "']/MaxPowerTime"));
  408. }
  409. set
  410. {
  411. Common.SetConfigValue("//Tank[@Name='" + m_Name + "']/MaxPowerTime",value.ToString());
  412. }
  413. }
  414. #endregion
  415. #region ====构造函数====
  416. public Tank(string Name)
  417. {
  418. m_Name = Name;
  419. }
  420. #endregion
  421. }
  422. #endregion
  423. }

美服疯狂坦克辅助瞄准外挂C#版开发(四)程序使用说明和完成源代码及其下载相关推荐

  1. 美服疯狂坦克辅助瞄准外挂C#版开发(一)物理模型及弹道曲线方程

    疯狂坦克弹道曲线方程式: 由上面的图表,根据初中物理知识,我们可以推导以下弹道曲线方程式: 以上物理模型和公式就已经完成了,当然这只是一个近似的公式,由于疯狂坦克游戏算法中存在同角和力点不均匀分布,所 ...

  2. 美服疯狂坦克辅助瞄准外挂C#版开发(二)全局鼠标键盘HOOK

    大家都知道,Windows操作系统内部通讯是基于消息机制的.为了实现我们的功能,必须要能够截和处理获游戏中鼠标键盘事件的消息,常规做法是获取游戏窗体的句柄,然后加入HOOK,这样的好处是不会影响到其它 ...

  3. 美服疯狂坦克辅助瞄准外挂C#版开发(三)在全屏游戏屏幕上绘制弹道曲线

    要在游戏全屏模式下屏幕绘制弹道曲线,需要用到以下三个API: //获取DC [DllImport("User32.dll")] public extern static Syste ...

  4. ASP版微信小程序支付(包含源代码)

    asp版本的微信小程序支付里面代码的解说和各代码用途 微信小程序交流群:111733917 | 微信小程序从0基础到就业的课程:https://edu.csdn.net/topic/huangjuhu ...

  5. 疯狂python讲义视频 百度云-疯狂Python讲义 PDF高清版附源码

    内容简介 本书全面,深入地介绍了Python编程的相关内容,大致可分为四个部分.*系统部分介绍了Python的基本语法结构,函数编程,类和对象,模块和包,异常处理等: 第二部分主要介绍Python常用 ...

  6. java怎么给坦克上图片_Java坦克大战 (七) 之图片版

    在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学完J2SE的小伙伴们一点启示! 坦克大战效果图: 坦克大战V0.7图片版实现功能: 1.将方向定义为一个E ...

  7. 疯狂Android讲义(第2版)重印10次的超级畅销书

    查看书籍详细信息: 疯狂Android讲义(第2版)(重印10次的超级畅销书-- 编辑推荐 本书第一版荣获"电子工业出版社最畅销图书奖":累计印刷10次,销售码洋二百余万,是And ...

  8. Java坦克大战 (七) 之图片版

    本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...

  9. 金蝶KIS商贸版开发往来对账单明细表[无辅助属性批号]

    金蝶KIS商贸版开发往来对账单明细表[无辅助属性批号] 客户需求: 金蝶商品资料如果勾选了'辅助属性',原有往来对账表中会显示出过多的销售明细行在客户对账时极为不方便,经过开发后,带有批号及辅助属性的 ...

最新文章

  1. matrix_multiply代码解析
  2. 深入理解 JavaScript 中的 replace 方法
  3. Java基础教程(3)--回顾HelloWorld
  4. 设计模式复习-适配器模式
  5. python 美化输出 错误 警告等信息_OpenCV抑制、隐藏或禁用输出到屏幕的错误或警告消息...
  6. SAP系统和微信集成的系列教程之六:如何通过OAuth2获取微信用户信息并显示在SAP UI5应用中
  7. 使用txt文件导入数据库内容
  8. Java 面向对象:super关键字的理解
  9. Python 报错TypeError: expected string or bytes-like object
  10. JavaScript:对象都是这样生成的!
  11. C语言第12轮:指针
  12. Linux 命令(27)—— echo 命令
  13. linux小技巧--vim下多行注释和取消多行注释
  14. c语言void结尾,c语言中的void和void*
  15. python 幅度和相位求复数_皮质运动兴奋性不受中央区mu节律相位的调节
  16. PostgreSQL 数据库查询
  17. CollaNote - 完全免费无广告的 iPad / iPhone 手写笔记应用(Notability / GoodNotes 的免费替代品)
  18. 其他笔记 - Scum和KANBAN
  19. 数字货币期货现货交易技巧,把握关键进场的买入点!(纯干货)
  20. 安全狗防护引擎安装失败

热门文章

  1. 大林算法计算机控制实验报告,计算机控制工程实验报告.docx
  2. durbin watson检验表_DW检验表精选文档
  3. [13][02][10] QQ 拼音自定义时间戳
  4. ubuntu桌面图标管理(以pycharm图标为例)
  5. 国内的房地产ERP系统能够上线吗,实施效益如何
  6. doophp 常用篇
  7. php支持中文字符串分割的函数
  8. c++实现分水岭算法
  9. 社会化评论系统 php,HashOver评论系统,弃坑畅言,致敬多说!
  10. Spring动态代理使用