1、程序设计大赛答辩演讲稿尊敬的各位评委,各位老师: 你们好,我叫,来自140406班的LZ组合。我们组的题目是连连看辅助工具。 在作品演讲之前,请允许我代表我们小组感谢黑马IT学院和计算机学院能够提供给我这样一个展示自我的平台,谢谢(行礼) 下面,开始我们组的品演示,首先,打开我们的连连看辅助工具,因为在制作之前,我们小组考虑到不同系统的用户需求,所以制作了三个版本的“连连看辅助工具”,并分别对应W7 32位操作系统,W7 64位操作系统和W8 64位操作系统,由于我的电脑是W8 64位操作系统,所以就只演示W8 64位版本的。 接下来,让我们进入游戏,考虑到时间问题,所以只用练习模式来演示,首
2、先尝试“单消”功能,所谓单消,顾名思义,便是只消除一对棋子的意思,它是本游戏的基础,接下来的一些中重要的功能都是围绕着它展开;然后,让我们尝试一下“秒杀”功能,“秒杀”就是全屏清除,我们可以多尝试几个图(演示); 接下来,让我们尝试一下“自动挂机”功能,勾选“自动挂机”我们会发现游戏开始自动以一个一个的消除,同时我们也可以通过移动下面的滑块来调节自动挂机的速度,这就是我们的“挂机速度调节”功能(演示); 至于“去游戏倒计时”功能,是取消游戏倒计时,让游戏无比流畅;而“无限道具”功能,则是让游戏的道具增加,下面我给大家试一下(演示) 接下来“自动开局”功能为了让游戏自动开始;“窗口置顶”功能是将
3、游戏页面放在桌面最上方,便于对游戏的操作,并使游戏辅助工具更加稳定再加上先前“去游戏倒计时”功能都是为了给游戏的自动挂机做铺垫,让挂机变得流畅,下面让我们来试一下这两个功能(演示) 讲解完了本工具的大体功能,让我们来和别人正式的玩一局。 (游戏时间 需自由发挥 带上所有的功能 并突出功能特色) 这真是完美的一次胜利,那它到底是怎样实现的哪?下面开始进行PPT的讲解。 这个辅助工具是由我们计算机科学与工程学院 140406班的LZ组合制作,我们的口号是“理智成就自我”(全组齐声), “LZ”是“理智”的缩写,所以我们会用我们的理性和智慧去处理每一件事,这虽然是我们小组第一次参加比赛,但我相信这绝
4、不会是最后一次。 OK,下面让我们进入正题。 我们的连连看辅助工具共有8项功能,包括:单消、秒杀、无限道具、自动开局、自动挂机、挂机速度调节、去游戏倒计时、游戏窗口置顶(翻页)下面开始“单消”功能的详细介绍首先让我们看看程序的流程图首先,我们读取棋盘的内存数据然后判断是否有相同的棋子接下来模拟鼠标点击判断棋子的数量是否减少如果减少了就更新棋盘数据最后结束单消现在让我们来看看具体的代码这是一段用来打开进程读取进程并将棋盘的内存数据存放到数组中的程序首先,我们定义一个字节型的数组因为棋盘是11行19列,所以定义为chessdata【11】*【19】然后定义一个hWnd gameh 用来表示窗口句柄
5、FindWindow,是用来寻找窗口ID的函数/FindWindow,LPCTSTR lpClassName, / pointer to class nameLPCTSTR lpWindowName / pointer to window name);这个函数拥有两个参数其中lpClassName参数指向类名,lpWindowName指向窗口名在本程序中不需要指向类名的参数,所以第一个参数为空,而第二个参数指向窗口名,也就是之前定义过的gameCaption然后下一步我们需要定义一个Double Word类型的变量 processid 由于每个word为2个字节的长度,所以processid双
6、字节为4个字节接下来我们要使用GetWindowThreadProcessId这个函数来找到窗口的进程,这个函数同样拥有两个参数DWORD GetWindowThreadProcessId(HWND hWnd,LPDWORD lpdwProcessId);其中第一个参数指向被查找的句柄 也就是Findwindow的返回值gameh第二个参数是进程号的存放地址,我们可以指向刚刚定义的processid hWndin (向函数提供的)被查找窗口的句柄.lpdwProcessIdout 进程号的存放地址(变量地址)接下来我们需要用OpenProcess这个函数获取进程的句柄并且将句柄保存在proce
7、ssH中OpenProcess 函数用来打开一个已存在的进程对象,并返回进程的句柄。HANDLE OpenProcess(DWORD dwDesiredAccess, /渴望得到的访问权限(标志)BOOL bInheritHandle, / 是否继承句柄DWORD dwProcessId/ 进程标示符这个函数拥有三个参数,第一个参数是访问权限,我们定义为 PROCESS_ALL_ACCESS也就是对进程内存的全部操作权限 第二个是是否继承句柄,我们选择否,也就是false 第三个进程标示符,也就是进程号,我们已经通过GetWindowThreadProcessId得到了,也就是processi
8、d因此我们得到了进程的句柄processH然后我们需要定义一个同样是Double Word类型的变量 byread, 再定义一个没有类型的指针LPCVOID pbase(基础) 这个指针存放的是棋盘数据的首地址 其中这个C代表不能修改变量的意思这个首地址是通过CE(CheatEngine61_cn)这个工具找到的 这个基址是一个十六进制数字0x00189F74然后再次定义一个没有类型的指针LPVOID nbuffer(缓冲)用来存放棋盘的数据最后我们使用ReadProcessMemory这个函数,这个函数拥有5个参数,第一个是参数是进程的句柄,也就是processH;第二个参数是要读取内存的首
9、地址,也就是我们之前定义的pbase;第三个参数是我们存入内存数据的地址,我们将其存在nuffer中;第四个参数是要传送的字节数,因为棋盘是11*19,所以我们就传送11*19个数据;第五个参数是实际传送的字节数. 函数返回时报告实际写入多少,我们将其存在byread之中BOOL ReadProcessMemory(HANDLE hProcess,PVOID pvAddressRemote,PVOIDpvBufferLocal,DWORD dwSize,PDWORDpdwNumBytesRead);实际应用hProcess in远程进程句柄。 被读取者pvAddressRemote in远程进
10、程中内存地址。 从具体何处读取pvBufferLocal out本地进程中内存地址. 函数将读取的内容写入此处dwSize in要传送的字节数。要写入多少pdwNumBytesRead out实际传送的字节数. 函数返回时报告实际写入多少这样我们就完成读取棋盘数据的功能了然后我们开始寻找棋盘中相同的棋子,通过查找内存中相同的数据我们找出相同的棋子程序中的for循环是用来不断改变棋子的位子,其中x1,y1是棋子1的位子,x2,y2是棋子二的位子x1=1,y1=1代表第一行第一列的棋子,x1=2,y1=2代表第二行,第二列的棋子,以此类推如果棋子1与棋子2的内存数据相等,那么我们就模拟鼠标点击,然
11、后通过鼠标的模拟点击和棋子数量是否减少来决定单消的程序是否结束。下面我们开始介绍模拟鼠标点击的程序,首先我们通过之前的ReadProcessMemory函数,将棋盘中剩余棋子的数量保存在chessnum中然后将它的值赋给l,通过Findwindow获得窗口句柄,并且将其保存在hwnd中然后定义一个整型变量lparam根据棋子1与棋子2的位子来给lparam赋值,因为第一行第一列的鼠标坐标为(192.21)相邻棋子之间的间隔为35并且由于我们要用到的是32位的鼠标地址,我们我们将x左移16位,所以给lparam赋值为lparam=(p1.y*35+192)16)+(p1.x*31+21);接下来
12、我们开始使用这个SendMassage函数,该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回而我们就需要这个函数发送一个鼠标消息,这个函数拥有四个参数,第一个是我们通过Findwindow找到的窗口的句柄hwnd;第二个是消息的标识(志)符,我们模拟的是鼠标点击所以就是WM_LBUTTONDOWN和WM_LBUTTONUP,对应的是鼠标的按下和抬起;第三个和第四个参数都是32位的特定附加信息,我们使用第四个,也就是将第三个参数设为零,第四个参数设为鼠标地址也就是我们之前定义的lparamsendmessagehWnd 是接收消息的窗口的句柄M
13、sg 是消息标识符wParam 是32位的特定附加信息。lParam 是32位特定附加信息这样我们就可以模拟点击棋子1了,然后我们再次按照上面的方法点击棋子二,通过下面if语句,判断如果棋子减少了,就返回大于一的数;终止循环。如果棋子不变,就返回0,让上面的循环继续,知道棋子数发生变化为止这样,我们的单消功能就完成了下面我们开始讲解秒杀的程序先看看流程图,首先我们需要执行单消这个程序,然后我们需要判断棋子数是否为零,如果为零就退出循环结束程序,如果不为零,就继续执行单消程序下面开始讲解代码的实现我们先将单消的函数进行封装,定义成clearpair()函数然后我们经行while循环,直到棋子数为
14、零,才终止循环;此时,我们也就完成了秒杀功能下面我们开始介绍无限道具的程序对于无限道具,我们只需要找到游戏道具的内存地址,并且将其改写就OK了下面开始讲解程序程序前面我们已经讲解过,定义窗口名,获取窗口句柄,获取进程句柄,唯一不同的是我们要用到writeprocessmemory函数来写入进程WriteProcessMemory此函数能写入某一进程的内存区域(直接写入会出Access Violation错误,故需此函数)。VC+声明BOOL WriteProcessMemory(HANDLE hProcess,LPVOID lpBaseAddress,LPVOID lpBuffer,DWORD
15、 nSize,LPDWORD lpNumberOfBytesWritten);参数:hProcess由OpenProcess返回的进程句柄。如参数传数据为 INVALID_HANDLE_VALUE 【即-1】目标进程为自身进程lpBaseAddress要写的内存首地址再写入之前,此函数将先检查目标地址是否可用,并能容纳待写入的数据。lpBuffer指向要写的数据的指针。nSize要写入的字节数。返回值非零值代表成功。该函数一共拥有5个参数,第一个参数是由openprocess返回的进程句柄;第二个是要写入的首地址,也就是我们游戏道具的首地址;要写入数据的指针,也就是我在上面定义的数组a,b,c
16、,d,e,;第四个是要写入的字节数,我们都定义为1个字节;第五个是返回值,我们把上面定义的bywritesize放到这里,存储返回值;由于道具是有两个内存地址控制,一个地址控制道具种类,一个地址控制道具数量,例如第一个函数控制的是道具的数量,第二个控制的就是“重列”这个道具是否出现这样我们就完成游戏道具内存的写入了下面开始讲解自动挂机的功能这个功能很简单,只需要在单消的基础上加入一个定时器函数就行了,流程图也很简单,就是更新数据,然后定时器函数重复单消,然后再次更新数据下面开始讲解代码的实现,首先我们先定义两个常量,一个变量,然后更新棋盘数据,通过if语句来判断此项功能是否被勾选,如果被勾选,
17、就再次更新棋盘数据,然后使用settimer这个定时器函数UINT_PTR SetTimer(HWND hWnd, / 窗口句柄UINT_PTR nIDEvent, / 定时器ID,多个定时器时,可以通过该ID判断是哪个定时器UINT nElapse, / 时间间隔,单位为毫秒TIMERPROC lpTimerFunc / 回调函数);在MFC程序中SetTimer被封装在CWnd类中,调用就不用指定窗口句柄了,所以这个函数就只有三个参数,第一个参数是定时器的ID,我们把它指向之前定义的playID;第二个是时间间隔q的值为1000,所以时间间隔为1s;第三个参数是回调函数,我们这回调函数中放
18、入单消的函数,在下面这个程序里面了;这样就是每间隔1s就执行一次单消函数,所以就实现了自动挂机的功能下面开始介绍自动开局功能首先,让我们看看流程图,我们需要先更新数据,然后判断棋子的数量,如果棋子数量为零,那么我们就模拟鼠标点击“开始游戏”,如果不为零的话就重新更新棋盘数据,直到它为0为止下面让我们看看程序的实现首先通过IF语句来判断棋子数是否为零,如果为0就延时1s,并获取窗口的句柄,并且模拟鼠标的点击“开始游戏”这样就完成自动开局的功能下面开始介绍挂机速度调节功能让我们看看流程图首先,我们需要创建一个滑块然后定义一个变量并且将变量传给 自动挂机里的时间标识,然后更新数据下面让我们看看那代码
19、的实现首先,我们需要更新一下数据,然后将滑块的值赋给m_num,其中this是关键字,属于实体(entity),是一个指针右值,而后面的m_ctl_slider.GetPos();是滑块当前的位子的值至于这个*pResult = 0;是为了防止对未知的位子进行操作,增加程序的稳定性然后我们将滑块的值传递给Q,通过滑块改变Q的值,就能改变下面自动挂机函数的时间间隔,进而改变自动挂机的速度下面是去游戏倒计时功能这个功能和无限道具功能的代码类似,都是读取进程,然后写入进程就行了这里就不过多的解释了下面是游戏窗口置顶功能首先,我们要更新一下游戏数据然后获取游戏窗口名,最后使用一下窗口置顶函数让我们看看
20、代码的实现用FINDWINDOW找到窗口的句柄然后使用SetWindowPos函数,这个函数一共有7个参数,第一个参数是窗口的句柄,也就是我们之前定义的gameh;第二个参数是我们要把这个窗口放到哪,我们选择 HWND_NOTOPMOST:将窗口置于所有非顶层窗口之上;第三个参数到第六个参数设定窗口的位子和大小,我们将其都设为0;第七个窗口是窗口尺寸和定位的标志,我们使用这三个参数,组合成一个参数,分别是SWP_NOMOVE:维持当前位置(忽略X和Y参数)。SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)SWP_SHOWWINDOW:显示窗口。BOOL SetWindowPos(HWN
21、D hWnd, const CWnd* pWndInsertAfter, int x, int y,int cx, int cy, UINT nFlags);这样我们就完成了窗口置顶的设置HWND_NOTOPMOST:将窗口置于所有非顶层窗口之上(即在所有顶层窗口之后)。如果窗口已经是非顶层窗口则该标志不起作用。x以客户坐标指定窗口新位置的左边界。Y以客户坐标指定窗口新位置的顶边界。cx以像素指定窗口的新的宽度。cy以像素指定窗口的新的高度。SWP_NOMOVE:维持当前位置(忽略X和Y参数)。SWP_NOSIZE:维持当前尺寸(忽略cx和Cy参数)SWP_SHOWWINDOW:显示窗口。下面
22、开始对我们作品的优点进行总结首先我们对大量的函数进行了封装,例如单消函数,模拟鼠标点击函数等等,尽量简洁了函数其次,我们添加了自动使用重列的函数,因为我们在游戏的时候,很可能会遇到这种情况(提示请使用重列道具),此时,我们不得不手动的去使用重列道具因此我们在单消函数中添加了自动使用重列,这样就能在无解的情况下自动使用重列下面让我们来看看自动使用重列的代码,使用自动重列的条件是棋子的数量在经过一次完整的单消循环后还没有变化,此时就会模拟鼠标点击重列道具但是经过我们几百次的实验,发现有的时候,使用重列道具之后依然会发生无解的情况,因此在我们小组不断的摸索,不断的尝试的情况下发现,使用重列道具之后会
23、有0.1s的动画延迟这个延迟就导致了我们的IF的条件一直是成立的状态,所以就一瞬间将所有的重列道具使用完,进而会再次出现无解的情况所以,我们在模拟鼠标点击后面加了0.1s的延时函数,这样就不会发生上述的情况了。这个功能的实现使我们小组实验上百次的成果,也是最令我们骄傲的成果第三个优点是秒杀功能的防卡死,因为while函数本身的特性,可能会因为各种各样的情况陷入死循环,因此我们在while的里面加入了几个计数的函数如果棋子数长时间未变化的话,那么就自动调出while的循环,这样就会大大提高程序的稳定性至于缺点,就是改变自动挂机速度的时候需要重新点击自动挂机。相信这个缺点大家已经看到了。这个我们一
24、直想改进,却一直都没有成功还有代码繁杂的问题,虽然尽量封装了一些函数,但是还是存在着一些繁杂的代码,包括一些不能删除的测试程序还有一个不算缺点的缺点,就是不能实现防踢的功能,这个我有一些简单的构想。踢人,指的是将人踢出房间,是腾讯蓝钻特有的权利,如果想拥有防踢功能就必须也办理腾讯蓝钻。但是我们不想办蓝钻还想拥有防踢的功能,因此我想绕过这个特权,用别的方法来模拟这个防踢的功能,方法如下当我们进入房间的时候,游戏进程的某个内存地址会记录下我们的房间号与座位号,而当别人把我们踢出后,我们只要在第一时间回到之前我们记录的房间和座位就相当于我们没被踢出去。虽然我能够找到房间号和座位号的内存地址,然而由于时间的问题和我所学的知识有限,无法实现在游戏大厅回到固定房间和固定座位的功能,因为这个功能无法实现。以上,就是我们作品的详细情况,谢谢。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1