Skip to content

Sharpiless/Gold-Miner

Repository files navigation

汇编小游戏——黄金矿工

小组成员及分工

叶语霄:负责定义全局变量和项目架构

袁沛文:编写view模块

李子昂:编写model模块

梁瑛平:编写controller模块

玩家使用指南

项目地址:https://github.com/Insomnia-y/Gold-Miner

若要开始游戏,请运行./Release/GAME.exe。

若上述方法无法开始游戏,可以在visual studio中切换到Debug模式下手动编译运行。编译前请先修改链接器中的附加库目录和属性页最下方MS Assembly中的IncludePath。分别添加masm32的目录和项目的目录。

1.项目结构

项目文件夹的结构如下:

Gold-Miner
├─Release
│  ├─GAME.exe
├─Gold-Miner
│  ├─include
│  ├─main.asm
│  ├─vars.asm
│  ├─controller.asm
│  ├─model.asm
│  ├─view.asm
├─lib
└─resource
    ├─icon
    └─music

./Release/GAME.exe:生成的可执行文件,点击即可直接开始游戏

./Gold-Miner/main.asm:程序入口,包含main子函数,即程序开始运行的地方。

./Gold-Miner/vars.asm:定义的全局变量

./Gold-Miner/controller.asm:控制器模块,负责捕获用户的鼠标和键盘事件

./Gold-Miner/model.asm:以不同方式响应用户的不同事件,根据游戏逻辑调用函数,修改全局变量

./Gold-Miner/view.asm:根据当前的全局变量,绘制游戏界面

./Gold-Miner/include:包含所有.inc文件

./lib 包含图形库acllib,以及自己手写的c语言库

./resource:游戏的图片和音乐素材

2.游戏操作

鼠标左键点击:

  • 在欢迎界面点击任意位置,开始游戏
  • 在游戏界面点击地下部分区域,释放钩索
  • 在游戏界面点击menu,回到欢迎界面并重新开始游戏
  • 在商店界面点击道具,购买道具

键盘:

  • 空格,释放鞭炮
  • 键和,操作电动勾

3.游戏描述

不同物体的半径、重量、价值:

类别 半径 重量 价值
0(石头) 20像素 80像素/秒 10
0(石头) 35像素 40像素/秒 20
1(金块) 20像素 120像素/秒 50
1(金块) 35像素 80像素/秒 100
1(金块) 50像素 30像素/秒 500
2(钻石) 20像素 120像素/秒 600
3(福袋) 20像素 30~120像素/秒 10~1200
4(TNT) 35像素(爆炸半径200)

不同物体在各关的出现概率:

类别 出现概率(12关\34关\5关及以后)
石头 0.1\0.2\0.2
金块 0.4\0.4\0.3
钻石 0.2\0.1\0.1
福袋 0.2\0.1\0.1
TNT 0.1\0.2\0.3

道具功能介绍:

道具 效果
石头收藏书 提高石头价值(石头价值*2)
鞭炮 不必多说,空格释放
神水 提高拉回速度(拉回速度*2)
幸运草 提高福袋出现概率(由10%提升为33%)
磁铁 可以吸住金子(金子的判定半径增加30)
电动勾 可以控制钩子下降角度(使用←、→控制方向)

程序设计描述

这部分玩家不用看,只是为了向老师证明我们是自己做的

1.概述

采用MVC架构,model负责根据游戏逻辑维护游戏的全局变量,view负责根据全局变量绘制界面,controller负责响应用户事件。

2.全局变量

窗口

当前窗口curWindow:DD,指示当前所在的游戏界面。0为欢迎界面,1为游戏界面,2为过关界面,3为失败界面。

窗体

游戏有效区域的高度和宽度gameX gameY:DD。

时间

本关卡剩余时间restTime:DD。以s为单位。

定时器timer:每10ms为一个时间片,为游戏的最小时间单元。在每个时间片开始或结束时触发定时器,model维护全局变量,且view根据维护后的全局变量重绘界面。

得分

目标得分goalScore:DD,本局游戏的目标得分。

当前得分playerScore:DD,当前得分。在各关卡累加。仅当用户主动返回菜单或游戏未过关被动结束时清零。

矿工

minerPosX:DD,矿工位置X坐标。 minerPosY:DD,矿工位置Y坐标。

物体

lastHit DD,上一次命中的物体的下标。(注意是28的倍数)

itemNum DD,物体数量。

为方便起见,认为物体的逻辑形状是圆心位置固定的圆,视觉形状是不规则的图形(加载素材)。

描述一个物体的结构体Item定义如下:

  • 存在exist:DD,1存在,0不存在。
  • 类型type:DD,枚举值,{石头,金块,钻石,福袋,TNT}。
  • X位置posX:DD,物体的圆心位置X坐标。
  • Y位置posY:DD,物体的圆心位置Y坐标。
  • 半径radius:DD,物体的半径。
  • 重量weight:DD。
  • 价值value:DD。

钩索

当前钩索状态hookStat:DD,当前钩索是否被释放。1时释放,表现为下一次触发时间片时钩索位置变化,钩索角度不变;0时不释放,表现为下一次触发时间片时钩索角度变化,钩索位置不变。

当前钩索角度移动方向hookODir:DD,**仅当hookStat为false时有意义。**为0时向右转,为1时向左转。

当前钩索位置移动方向hookDir: DD,**仅当hookStat为true时有意义。**为0时向下移动(回收),为1时向上移动(下放)。

钩索角速度hookOmega,DD,常量。

钩索线速度hookV,DD,有一基础值(下放和未命中回收时),命中回收时依赖于抓到的物体类型。


钩索角度hookDeg:DD,取值范围为180~360度。

钩索位置hookPosX hookPosY:DD。

不同hookStat和hookDir(或hookODir)组合的含义如下:

hookStat hook(O)Dir 含义
0 0(ODir) 向右转
0 1(ODir) 向左转
1 0 向下移动
1 1 向上移动

3.控制器

用户事件回调函数:释放钩索

; @brief: 鼠标点击游戏区域时,释放钩索。 ; @read: 无 ; @write: 写hookStat为1,写hookDir为0,写hookV为默认值(120),写lastHit为-1。

4. 模型

触发定时器时,依次调用以下函数。

函数:钩索移动

根据hookStat,计算并更新hookPoshookDeg

函数:判断钩索是否命中物体

; @brief: 判断钩索是否命中物体。遍历items中所有物体的位置(posX、posY),判断钩索位置与物体位置的距离是否小于物体半径。 ; @read: hookPosX,hookPosY,Items ; @write: lastHit,hookDir,hookV。若命中,写lastHit为命中物体的下标,写hookDir为1,写hookV为f(Items[lastHit].weight)。

函数:判断钩索是否出界

; @brief: 判断钩索是否出界或回到矿工手中。 ; @read: hookPosX,hookPosY,lastHit ; @write: hootDir,hookStat,Items,playerScore。若出界,写hookDir为1;若回到矿工手中,写hookStat为0,写Items[lastHit].exist为0,写playerScore+=Items[lastHit].value

5.问题与解决方法

  1. 离散刷新问题。在刷新间隔长且物体半径小的情况下可能“掠过”物体,即未响应应该响应的isHit。解决方法:缩短刷新间隔,增大物体的半径。
  2. 计算机坐标系与常规坐标系不一致。计算机坐标系$(x,y)$ = 常规坐标系$(-y',x')$。hookDeg在常规坐标系上定义,取值范围$[180,360]$。故当调用moovHook改变钩索位置时,移动增量$(Δx,Δy) = (-ρsinθ, ρcosθ)$,其中 $θ$hookDeg$ρ$hookV
  3. 计算精度问题。最初计算三角函数时,由于疏忽采用(int)取整,但这种方式只能截断取整数部分,没有四舍五入的效果,因此导致误差,体现为计算结果与期望值不一致。解决方法:改为采用round()函数取整,达到了期望的四舍五入的效果。
  4. 取整误差问题。抓取大物体时速度过慢,当ρ很小sinθ也很小的时候容易出现Δx为0的情况,导致相乘后的偏移量四舍五入后变为0,表现为钩子水平移动无法回到矿工手中。解决方法:移动过程中,如果检测到hookX的偏移量等于0时,根据钩子目前下落将其设置为+1或-1。
  5. 使用的acllib图形库有导入图形的格式限制,无法导入无底色的png图片作为贴图。解决方法:采用更高级的图形库

6.C语言库

用C语言处理一些计算,避免汇编中的浮点数运算。

计算两点间距离:

// 计算两点间距离
// @params: (x1,y1)第一个点坐标 (x2,y2)第二个点坐标
// @return: ans,int型距离。
extern "C" int calDistance(int x1, int y1, int x2, int y2) {
    int ans = round(sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
    return ans;
}

计算psinθ:

// 计算ρsinθ
// @params: theta,角度制,实际取值范围[180, 360];ρ,极径
// @return: ans
extern "C" int calPSin(int deg, int r) {
    int ans = round(r*sin(deg * 2 * PI / 360));
    return ans;
}

计算pcosθ:

// 计算ρcosθ
// @params: 同上
// @return: ans
extern "C" int calPCos(int deg, int r) {
    int ans = round(r*cos(deg * 2 * PI / 360));
    return ans;
}

About

汇编大作业,黄金矿工

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Languages