⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snoke.asm

📁 贪食蛇汇编源代码
💻 ASM
📖 第 1 页 / 共 2 页
字号:
;********************************************************************************
;编译模式="WND"
;********************************************************************************
	.386
	.model flat, stdcall
	option casemap:none

;********************************************************************************
;头文件
;********************************************************************************
include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc
include comctl32.inc

includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib
includelib comctl32.lib

SNOKENODE struct
	x dd ?
	y dd ?
	pPrev dd ?
	pNext dd ?
SNOKENODE ends

;********************************************************************************
;全局变量
;********************************************************************************
IDM_MAINMENU equ 100
IDM_FILE_NEW equ 1000
IDM_FILE_CLOSE equ 1001
IDM_FILE_STOP equ 1002
IDM_FILE_EXIT equ 1003
IDM_SPEED_SLOWEST equ 1010
IDM_SPEED_SLOW equ 1011
IDM_SPEED_NORMAL equ 1012
IDM_SPEED_FAST equ 1013
IDM_SPEED_FASTEST equ 1014
IDM_SPEED_USER equ 1015
IDM_FOOD_ONE equ 1016
IDM_FOOD_TWO equ 1017
IDM_FOOD_FOUR equ 1018
IDM_FOOD_16 equ 1019
IDM_FOOD_32 equ 1020
IDM_FOOD_USER equ 1021
IDM_OPTION_ENVIRONMENT equ 1022
IDM_HELP_ABOUT equ 1023
IDD_INPUT equ 200
IDC_INPUT_OK equ 2000
IDC_INPUT_CANCEL equ 2001
IDC_INPUT_EDT1 equ 2002
IDC_INPUT_STC1 equ 2003
IDI_ICON1 equ 100

WNDCX equ 400
WNDCY equ 400
SNKSIZE equ 8
INITCOUNT equ 10
ID_TIMER1 equ 1000
IS_SPEED equ 0
IS_FOOD equ 1

	.const

	.data
szClassName db "STANDARDCLASS", 0
szWindowsName db "贪食蛇", 0
szPause db "贪食蛇 - 暂停中", 0
szGameOver db "游戏结束 (GAME OVER)", 0
szPlaying db "游戏进行中, 请先结束游戏", 0
szSpeed db "输入数度值(1~1000)毫秒/格, 1秒=1000毫秒", 0
szFood db "输入食物值(1~256)个", 0
bPause db 0
pHead dd 0
pEnd dd 0
dwTimeStop dd 100
dwFoodCount dd 4
dwKeyPrev dd VK_DOWN
dwKeyFlag dd VK_DOWN

	.data?
hInstance dd ?
hWndMain dd ?
hMenu dd ?
hBrushSnoke dd ?
hBrushFood dd ?
dwCurrentCount dd ?
nrandom_seed dd ?
stFood POINT 256 dup(<>)

;********************************************************************************
	.code
nrandom proc uses ebx edx base
    mov eax, nrandom_seed
    xor edx, edx
    mov ebx, 127773
    div ebx
    mov ebx, eax
    mov eax, 16807
    mul edx
    mov edx, ebx
    mov ebx, eax
    mov eax, 2836
    mul edx
    sub ebx, eax
    xor edx, edx
    mov eax, ebx
    mov nrandom_seed, ebx
    div base
    mov eax, edx
    ret
nrandom endp

nseed proc TheSeed
    mov eax, TheSeed
    mov nrandom_seed, eax
    ret
nseed endp

;********************************************************************************
;释放所有节点
;********************************************************************************
_FreeNodes proc uses esi
	mov eax, pHead
	assume eax:ptr SNOKENODE
	.while eax
		mov esi, [eax].pNext
		invoke GlobalFree, eax
		mov eax, esi
	.endw
	mov pHead, NULL
	mov pEnd, NULL
	mov dwKeyFlag, VK_DOWN
	ret
_FreeNodes endp

;********************************************************************************
;添加节点
;********************************************************************************
_AddHead proc uses esi @dwX, @dwY
	invoke GlobalAlloc, GMEM_FIXED or GMEM_ZEROINIT, sizeof SNOKENODE
	mov esi, eax
	assume esi:ptr SNOKENODE
	assume eax:ptr SNOKENODE
	.if pHead
		xchg eax, pHead
		mov [esi].pNext, eax
		mov [eax].pPrev, esi
	.else
		mov pHead, eax
		mov pEnd, eax
	.endif
	mov eax, @dwX
	mov [esi].x, eax
	mov eax, @dwY
	mov [esi].y, eax
	ret
_AddHead endp

;********************************************************************************
;产生食物
;********************************************************************************
_NewFoods proc uses esi @dwCount
	lea esi, stFood
	assume esi:ptr POINT
	mov ecx, @dwCount
	mov dwCurrentCount, ecx
@@:
	invoke nrandom, WNDCX/SNKSIZE
	shl eax, 3
	add eax, SNKSIZE
	mov [esi].x, eax
	invoke nrandom, WNDCY/SNKSIZE
	shl eax, 3
	add eax, SNKSIZE
	mov [esi].y, eax
	add esi, 8
	loop @B
	ret
_NewFoods endp

;********************************************************************************
;游戏结束
;********************************************************************************
_GameOver proc
	invoke KillTimer, hWndMain, ID_TIMER1
	invoke _FreeNodes
	invoke MessageBox, hWndMain, addr szGameOver, addr szWindowsName, MB_OK
	invoke InvalidateRect, hWndMain, NULL, TRUE
	invoke CheckMenuItem, hMenu, IDM_FILE_STOP, MF_UNCHECKED
	invoke SetWindowText, hWndMain, addr szWindowsName
	mov bPause, 0
	ret
_GameOver endp

;********************************************************************************
;定时器消息处理函数
;********************************************************************************
_TimerProc proc uses ebx ecx esi hWnd, uMsg, idEvent, dwTime
	local @stRectHead:RECT, @stRectEnd:RECT
	local @hrgn

	;取得头节点数据
	mov esi, pHead
	assume esi:ptr SNOKENODE
	mov eax, [esi].x
	mov @stRectHead.left, eax
	mov eax, [esi].y
	mov @stRectHead.top, eax
	;由键盘按键记录, 设置新节点数据
	mov eax, dwKeyFlag
	.if eax == VK_LEFT
		sub @stRectHead.left, SNKSIZE
	.elseif eax == VK_RIGHT
		add @stRectHead.left, SNKSIZE
	.elseif eax == VK_UP
		sub @stRectHead.top, SNKSIZE
	.elseif eax == VK_DOWN
		add @stRectHead.top, SNKSIZE
	.endif
	mov dwKeyPrev, eax
	;判断横坐标
	mov eax, @stRectHead.left
	.if eax < SNKSIZE || eax > WNDCX
		invoke _GameOver
		ret
	.endif
	;设置新值
	mov @stRectHead.right, eax
	add @stRectHead.right, SNKSIZE-1
	;取得尾节点数据
	mov esi, pEnd
	xchg [esi].x, eax
	mov @stRectEnd.left, eax
	add eax, SNKSIZE-1
	mov @stRectEnd.right, eax
	;判断纵坐标
	mov eax, @stRectHead.top
	.if eax < SNKSIZE || eax > WNDCY
		invoke _GameOver
		ret
	.endif
	;设置新值
	mov @stRectHead.bottom, eax
	add @stRectHead.bottom, SNKSIZE-1
	;取尾节点数据
	xchg [esi].y, eax
	mov @stRectEnd.top, eax
	add eax, SNKSIZE-1
	mov @stRectEnd.bottom, eax
	;设置节点链路, [倒二].pNext=NULL, [倒一].pNext=第一, [倒一].pPrev=NULL, [第一].pPrev=倒一
	mov esi, [esi].pPrev
	mov [esi].pNext, NULL
	xchg esi, pEnd
	mov eax, pHead
	mov [esi].pNext, eax
	mov [esi].pPrev, NULL
	xchg esi, eax
	mov [esi].pPrev, eax
	mov pHead, eax
	;判断是否撞倒自身
	mov eax, @stRectHead.left
	mov ebx, @stRectHead.top
	.while esi
		.if eax == [esi].x && ebx == [esi].y
			invoke _GameOver
			ret
		.endif
		mov esi, [esi].pNext
	.endw
	;判断是否吃到食物
	lea esi, stFood
	assume esi:ptr POINT
	sub esi, 8
	mov ecx, dwFoodCount
LOP1:
	add esi, 8
	cmp eax, [esi].x
	je LOP2
	loop LOP1
	jmp LOP3
LOP2:
	cmp ebx, [esi].y
	je LOP3
	loop LOP1
LOP3:
	;ecx != 0, 则吃到食物, 食物位置标记清 0, 蛇长度 +1, 食物数量 -1
	.if ecx
		mov [esi].x, 0
		mov [esi].y, 0
		invoke _AddHead, @stRectHead.left, @stRectHead.top
		dec dwCurrentCount
	.endif
	;食物数量为 0, 重新产生 dwFoodCount 个食物, 否则, 绘制蛇下一形态
	.if !dwCurrentCount
		invoke _NewFoods, dwFoodCount
		invoke InvalidateRect, hWndMain, NULL, TRUE
	.else
		invoke CreateRectRgnIndirect, addr @stRectHead
		mov @hrgn, eax
		invoke CreateRectRgnIndirect, addr @stRectEnd
		push eax
		invoke CombineRgn, @hrgn, @hrgn, eax, RGN_OR
		pop eax
		invoke DeleteObject, eax
		invoke InvalidateRgn, hWndMain, @hrgn, TRUE
		invoke DeleteObject, @hrgn
	.endif
	ret
_TimerProc endp

;********************************************************************************
;对话框消息处理函数
;********************************************************************************
_InputDlgProc proc hWnd, uMsg, wParam, lParam
	.if uMsg == WM_COMMAND
		mov eax, wParam
		.if ax == IDC_INPUT_OK
			invoke GetDlgItemInt, hWnd, IDC_INPUT_EDT1, NULL, FALSE
			invoke EndDialog, hWnd, eax
		.elseif ax == IDC_INPUT_CANCEL
			invoke EndDialog, hWnd, NULL
		.endif
	.elseif uMsg == WM_CLOSE
		invoke EndDialog, hWnd, NULL

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -