zoukankan      html  css  js  c++  java
  • Win32汇编项目总结——猎杀潜航

    必须得承认,这个项目的名字《猎杀潜航》起得大了点,一开始设想的挺好的,想用刚学到的win32汇编做点有意义的项目,都说名字是成功的一半,所以想了老半天,看了很多小游戏,觉得这种“打飞机”的比较容易实现,再加上想起之前看的电影,就使用这个名字了。

    废话不多说了,先说一下做这个项目的总体感想。然后再谈一些技术上的东西。

    首先是说为什么会学习win32汇编。到目前为止,我还是一个学生。我刚本科毕业,从院长手里拿到了需要的文凭。但是研究生路途漫长啊,仅靠本科的计算机基础,c/c++功底和在Microsoft学到的SQL Server技术总是会吃完的。再加上很久以前就想到黑客的牛逼之处,和在MS有个mentor指点我看看调试和汇编,所以俺就决定学习win32汇编了。至于为什么会那么臭屁的把自己的习作放到网上来,光明正大地说是因为和大家一起学习进步,往暗错错里说,为了方便以后在简历里写上我有过win32汇编编程经验,给老板一个地址看看我的作品。

    说我在这次的项目里学到了什么,我觉得主要是对以前x86汇编的回顾——对ds, ss等段寄存器的使用的回顾,对call, ret等指令的原理的解析,对各种标志寄存器和各种转移指令的重新认识,以及——最关键的,是使用了ollydb调试器。想做黑客就必须得会用ollydb。通过在看雪论坛的几个相关帖子的研究,我从一只不明方向的精子,遇到了饥渴的卵子,终于成为了一只——蛋。通过这次项目的错误调试,研究ollydb的使用等,我想我可以成为一只正真的鸟蛋了。

    下面谈一下整个项目吧。项目是关于潜艇打飞机的故事,画面很简单,如图1.

     

    “黑怪”来回的飞,我们控制那个“阿黄”。“黑怪”会向各方发射“睡不醒”,我们发出“亲嘴”,当有碰撞时扣血,直到血没有为止。

    技术难点和解决方案概括如下,由于我的编程能力有限,可能使用的设计模式和数据结构以及解决方案不是最优的,但是毕竟是我一步步前进的脚印,所以记录下来。望各位高手能够指点,让我们共同进步。

    1.       总体架构

    我使用了3个线程来勾画整个项目的。

    主线程除了常规的初始化和建立其他两个线程的功能外主要负责消息循环。关键的消息是WM_TIMERWM_KEYUPWM_KEYDOWNWM_TIMER是处理两个计时器消息,一个是每50ms(其实记得根本不可能达到每50ms触发一次的,但是具体的秒数忘记了)解禁一个负责画画的线程并检查游戏结束条件是否被满足,另外一个是每500ms增加“黑怪”一颗子弹并触发垃圾清理线程。

    画画的线程主要功能就是画出背景,敌人,子弹,“阿黄”。具体的放在绘图那部分讲。

    还有一个相对独立的线程,用于清理垃圾。这个线程的作用是检查子弹是否已经超过了屏幕显示范围,如果超过了,就进行回收。

     

    2.       关于绘画

    在这里我使用了双缓冲技术。先将所有需要的对象(比如说阿黄,黑怪的图像,背景之类的)读入相应的hDC,然后在初始化的时候初始化hDcForground,使他拥有背景,阿黄和黑怪,再创建两个线程,然后马上触发WM_PAINT,将hDcForground传送给屏幕DC。画画线程的作用主要是将背景,阿黄,黑怪画在hDcForgroundCopy上,在该线程没有全部画完前,如果WM_PAINT被触发就将原来的hDcForground画上去,如果此次WM_PAINT被触发前,已经画完,那么将hDcForgroundCopy拷贝至hDcForground。这个整个机制使用的是WaitForMultipleObjects是否WM_TIMEOUT来决定。

    忘记说了,二级缓冲画图,必须得准备compatibledc, compatiblebitmap,然后当装进去之后才能够画。一开始因为结构稍有混乱再加上有短时间没有编写gdi程序了,就忘记做有些操作了。

     

    3.       关于子弹

    首先我先定义一个32位变量记录,它的每一位代表着该序号的子弹是否被使用。当然,前提是我假定屏幕上能够出现的子弹的最大值(CONNAN_BALL_MAX_ENEMY)小于等于32个。当500ms的计时器被触发时,就通过将1h进行CONNAN_BALL_MAX_ENEMYshl,与相应的记录的对应位比较,如果该序号的子弹没有使用,就填充由VirtualAlloc提交过的相应段,主要填充当前位置,和走向角度。当然这里就要涉及到汇编里的浮点运算,等会讲述。

    垃圾回收机制只要是刚才操作的逆操作,这里就不再累述。

     

    4.       关于移动

    不得不承认,这个习作我最不满意的地方就在于移动。我使用的方法是使用WM_KEYDOWNWM_KEYUP,但是实际证明下来不够理想。主要体现在当我一直按下左,突然又按下了上(此时左继续按着),阿黄会有一个停顿。这个问题我咨询过在SD工作的便友,他说这是没有办法的,因为走了windows的消息机制,所以慢也没办法。唯一的解决办法是跳过windows消息机制,让硬件直接向我发消息。于是我改用了WM_INPUT,但是当我通过查看MSDN编了一系列函数后,发现ml编译器根本就不忍WM_INPUT的系列函数,可能是我那个版本的windows.inc中没有收录这些函数。(顺便说一句,我的IDERadasm 2.2.1.9)最后无奈,也实在懒得去找原型,就只能够对不起观众了。

     

     

    5.       关于汇编浮点数操作

    很无奈,终于还是避不开浮点数操作,最后参考了《windows32位汇编语言程序设计》的相关代码才搞定。主要方法是使用FPU堆栈,flid,fadd(p), fmul(p)等类似操作完成。具体可以参见程序源代码或者http://blog.163.com/wm1301@126/blog/static/37163258200941184348965/

     

    6.       关于编译

    这次居然碰到一个实在是搞不定的编译问题,以至于在画画线程中有两段非常类似且冗长的代码,我已经写好了函数,但是怎么也编译通不过。如果读者愿意,可以帮我查看一下为什么,方法是将submarine.asmcode段的那个被我注释掉的include还原,然后再编译。我的编译错误处在结尾的.endw中,报错是操作不正确,莫名啊~%@#$!

     

    7.       有符号数的比较

    这次有符号数的比较不多,但是也挺头痛的。最后是参考了王爽的《汇编语言》才搞定的。关键是看OF标志的值。太关键了。当OF0时,SF1,则比较结果小于0,反之则大于0.OF1时,SF1,则比较结果大于0,反之则小于0.等于零可以用zf推断。

     

    8.       碰撞判定

    应该不是第一次遇到碰撞判定,但是也还是挺麻烦的。看来我还需要多编程啊,老本总有一天会被吃完的。

    这次使用的是两个长方形的判定。假设(x1,y1)在(x2,y2)的左上角。那么就有

    x1 < x2 < x1 + w1y1 < y2 < y1 + h1时撞到。

     

    写了好长一堆了呀,感谢大家可以和我一起交流经验。通过这次项目,我感到自己在总体涉及方面还是有一定问题的。所以接下去会在下个星期重新阅读《大话设计模式》,顺便复习一下C#

     

    这个习作是我win32汇编的开始,希望各位口下留情。

     

    可以在网盘中下载到所有源代码,如果看得起我需要引用代码,请随意,并在这里感谢您的引用。不过我非常希望您能够在我这里留意下言,给我增加点人气。

    网盘地址为http://www.163pan.com/files/700000x0j.html

  • 相关阅读:
    1017 A除以B (20分)**
    剑指 Offer 11. 旋转数组的最小数字(简单)
    剑指 Offer 04. 二维数组中的查找(中等)
    剑指 Offer 53
    剑指 Offer 53
    剑指 Offer 03. 数组中重复的数字(简单)
    剑指 Offer 58
    剑指 Offer 05. 替换空格(简单)
    执行npm install命令出错问题
    剑指 Offer 35. 复杂链表的复制(中等)
  • 原文地址:https://www.cnblogs.com/aicro/p/1792708.html
Copyright © 2011-2022 走看看