算法由GB-ASM制定:
您检查 2 个物体的 2 个中心之间的差异,如果两个差异的绝对值都小于它们的半宽度的总和,则存在碰撞。
我的 TASM 代码:
PROC check_collision ; checks for collision with snake
mov bx, [X]
shr bx,1
mov [CenterSquare_Y], bx
mov bx, [Y]
shr bx,1
mov [CenterSquare_X], bx
; Find middle point of apple
mov bx, [Xapple]
shr bx,1
mov [CenterApple_X], bx
mov bx, [Yapple]
shr bx,1
mov [CenterApple_Y], bx
mov cx , [CenterSquare_Y]
mov bx , [CenterApple_Y]
SUB bx , cx
mov [Diffrence_Y] , bx
cmp bx , 0
jg check_Diffrence
Neg bx
mov cx , [CenterSquare_X]
mov bx , [CenterApple_X]
SUB bx , cx
mov [Diffrence_X] , bx
cmp bx , 0
jg check_Diffrence
Neg bx
check_Diffrence:
mov ax, [SnakeBody]
shr ax ,1
cmp [Diffrence_Y] , ax
jne skip_draw_apple
cmp [Diffrence_X] , ax
jne skip_draw_apple
CALL rnd_y
call rnd_x
skip_draw_apple:
RET
ENDP check_collision
完整代码:
IDEAL
MODEL small
STACK 100h
DATASEG
; --------------------------
Y dw 100 ; of charchter
X dw 100 ; of charchter
TIME_AUX DB 0 ; for waiting in between frames
PressFlag db 0 ; press flag
SnakeBody dw 5 ; body of charcter
Xapple dw 80 ; y of apple
yapple dw 80 ; x of apple
Random_x dw 50 ; my rnds
Random_y dw 50 ; my rnds
Speed dw 5 ; speed of snake
Player_Score DB 48 ; ascii value of 0
level dw 1
SEED dw 11
FlagForRnd dw 1 ; if it's RND_y we can use any y value times 5 if it's x it can be any value from 150,1
CenterSquare_Y dw 0
CenterSquare_X dw 0
CenterApple_Y dw 0
CenterApple_X dw 0
Diffrence_Y dw 0
Diffrence_X dw 0
; --------------------------
CODESEG
proc set_cursor
MOV AH, 02h
MOV BH, 0
MOV DH, 1 ; Adjust row for the score display
MOV DL, 1 ; Adjust column for the score display
INT 10h
RET
ENDP set_cursor
PROC Score
mov ah, 09h ; Display character function
mov bh, 0 ; Page number
mov cx, 1 ; Number of times to display character
mov al, [byte ptr Random_x] ; Character to display
ADD AL, '0' ; Convert to ASCII
mov bl, [byte ptr level] ; Attribute (text color)
int 10h
MOV AH, 02h
MOV BH, 0
MOV DH, 1 ; Adjust row for the score display
MOV DL, 1 ; Adjust column for the score display
INT 10h
MOV AH, 02h
MOV BH, 0
MOV DH, 1 ; Adjust row for the score display x
MOV DL, 20 ; Adjust column for the score display y
int 10h
ENDP Score
PROC moves
MOV AH, 01h ; Function 01h - Check for Key Press
INT 16h
JZ exit_moves ; Jump if ZF is set (no key pressed)
MOV AH, 00h ; Function 00h - Read Keystroke
INT 16h
; Check if AH contains 'W' (ASCII value 87)
CMP AL, 'w'
je w_pressed
; Check if AH contains 'D' (ASCII value 68)
CMP AL, 'd'
je d_pressed
; Check if AH contains 'A' (ASCII value 65)
CMP AL, 'a'
je a_pressed
; Check if AH contains 'S'
CMP AL, 's'
JMP s_pressed
exit_moves:
RET
ENDP moves
PROC w_pressed
mov [PressFlag], 1
mov cx , [Speed]
SUB [Y], cx
CHECK_TIME1: ;time checking loop
MOV AH,2Ch ;get the system time
INT 21h ;is the current time equal to the previous one(TIME_AUX)?
CMP DL,[TIME_AUX] ;is the current time equal to the previous one(TIME_AUX)?
JE CHECK_TIME1
MOV [TIME_AUX],DL
CALL draw
call moves
CMP [PressFlag],1
je w_pressed
RET
ENDP w_pressed
PROC d_pressed
mov [PressFlag], 2
mov cx , [Speed]
ADD [X], cx
CHECK_TIME2: ;time checking loop
MOV AH,2Ch ;get the system time
INT 21h ;is the current time equal to the previous one(TIME_AUX)?
CMP DL,[TIME_AUX] ;is the current time equal to the previous one(TIME_AUX)?
JE CHECK_TIME2
MOV [TIME_AUX],DL
CALL draw
call moves
cmp [PressFlag],2
je d_pressed
ret
ENDP d_pressed
PROC a_pressed
mov [PressFlag], 3
mov cx , [Speed]
SUB [X], cx
CHECK_TIME3: ;time checking loop
MOV AH,2Ch ;get the system time
INT 21h ;is the current time equal to the previous one(TIME_AUX)?
CMP DL,[TIME_AUX] ;is the current time equal to the previous one(TIME_AUX)?
JE CHECK_TIME3
MOV [TIME_AUX],DL
CALL draw
call moves
CMP [PressFlag],3
je a_pressed
ret
ENDP a_pressed
PROC s_pressed
mov [PressFlag], 4
mov cx , [Speed]
ADD [Y], cx
CHECK_TIME4: ;time checking loop
MOV AH,2Ch ;get the system time
INT 21h ;is the current time equal to the previous one(TIME_AUX)?
CMP DL,[TIME_AUX] ;is the current time equal to the previous one(TIME_AUX)?
JE CHECK_TIME4
MOV [TIME_AUX],DL
CALL draw
call moves
CMP [PressFlag],4
je s_pressed
RET
ENDP s_pressed
PROC draw
MOV AX, 0C07h ; Function 0Ch, Set Pixel Color
MOV BH, 0 ; Page number (usually 0 in mode 13h)
; Draw the gray border
MOV CX, 40 ; X-coordinate of the left border
MOV DX, 49 ; Y-coordinate of the top border
MOV SI, 0
MOV DI, 0
MOV AL, 8 ; Color for gray pixels
draw_row_loop_border:
draw_pixel_loop_border:
INC CX
INC DI
INT 10h
CMP DI, 240 ; Width of the border
JNE draw_pixel_loop_border
SUB CX, 240 ; Reset X-coordinate to start
MOV DI, 0
INC DX
INC SI
CMP SI, 150 ; Height of the border
JNE draw_row_loop_border
MOV AX, 0C07h ; Function 0Ch, Set Pixel Color
MOV BH, 0 ; Page number (usually 0 in mode 13h)
; Draw the apple
MOV CX, [Xapple] ; X-coordinate of the apple
MOV DX, [yapple] ; Y-coordinate of the apple
MOV SI, 0
MOV DI, 0
MOV AL, 4 ; Color (choose a color different from the snake)
draw_row_loop_apple:
draw_pixel_loop_apple:
INC CX
INC DI
INT 10h
CMP DI, [SnakeBody] ; size of the apple must be the same size of the snake for collision to work
JNE draw_pixel_loop_apple
SUB CX, [SnakeBody] ; without this, the apple is not drawing up; it's drawing to the side
MOV DI, 0
INC DX
INC SI
CMP SI, [SnakeBody]; size of the apple must be the same size of the snake for collision to work
JNE draw_row_loop_apple
; Draw the snake
MOV CX, [X] ; X-coordinate of the snake head
MOV DX, [Y] ; Y-coordinate of the snake head
MOV SI, 0
MOV DI, 0
MOV AL, 2 ; Color green (you can choose a different color)
draw_row_loop:
draw_pixel_loop:
INC CX
INC DI
INT 10h
CMP DI, [SnakeBody]
JNE draw_pixel_loop
SUB CX, [SnakeBody]
MOV DI, 0
INC DX
INC SI
CMP SI, [SnakeBody]
JNE draw_row_loop
; after moving snake find center square and center apple
; Find middle point of SNAKE
CALL check_collision
RET
ENDP draw
PROC check_collision ; checks for collision with snake
mov bx, [X]
shr bx,1
mov [CenterSquare_Y], bx
mov bx, [Y]
shr bx,1
mov [CenterSquare_X], bx
; Find middle point of apple
mov bx, [Xapple]
shr bx,1
mov [CenterApple_X], bx
mov bx, [Yapple]
shr bx,1
mov [CenterApple_Y], bx
mov cx , [CenterSquare_Y]
mov bx , [CenterApple_Y]
SUB bx , cx
mov [Diffrence_Y] , bx
cmp bx , 0
jg check_Diffrence
Neg bx
mov cx , [CenterSquare_X]
mov bx , [CenterApple_X]
SUB bx , cx
mov [Diffrence_X] , bx
cmp bx , 0
jg check_Diffrence
Neg bx
check_Diffrence:
mov ax, [SnakeBody]
shr ax ,1
cmp [Diffrence_Y] , ax
jne skip_draw_apple
cmp [Diffrence_X] , ax
jne skip_draw_apple
CALL rnd_y
call rnd_x ; moves snake to x coords
;mov dx, [Random_x]
;ADD DX , 40 ; CURRENTLY BROKEN FIX BY GETTING ACTUAL TRUE RANDOMS ALSO NUMBER THAT IS ADDED MUST BE DIVISIBLE BY THE SPEED OF BODY OF SNAKE!!!
;mov [Xapple], dx
Inc [Player_Score]
cmp [Player_Score], 59
jne score_Show
inc [level]
mov [Player_Score], 49
mov cx, [level]
ADD [SnakeBody], cx
ADD [Speed], cx
score_Show:
call set_cursor
call Score
skip_draw_apple:
RET
ENDP check_collision ; hitbox code
;Randoms
PROC rand2num1toValue_Y
push dx
push bx
xor dx, dx ; Compute randval(DX) mod 10 to get num
mov bx, 26 ; between 1 and given value
div bx
inc dx ; DX = modulo from division
mov [Random_y], dx
pop bx
pop dx
RET
ENDP rand2num1toValue_Y
PROC rand2num1toValue_X
push dx
push bx
xor dx, dx ; Compute randval(DX) mod 10 to get num
mov bx, 26 ; between 1 and given value
div bx
inc dx ; DX = modulo from division
mov [Random_x], dx
pop bx
pop dx
ret
ENDP rand2num1toValue_X
; Set LCG PRNG seed to system timer ticks
; Inputs: AX = seed
; Modifies: AX
; Return: nothing
Proc srandsystime
xor ax, ax ; Int 1Ah/AH=0 to get system timer in CX:DX
int 1Ah
mov [seed], dx ; seed = 16-bit value from DX
ret
ENDP srandsystime
PROC rand
push dx
mov ax, 25173 ; LCG Multiplier
mul [word ptr seed] ; DX:AX = LCG multiplier * seed
add ax, 13849 ; Add LCG increment value
mov [seed], ax ; Update seed
; AX = (multiplier * seed + increment) mod 65536
pop dx
ret
ENDP rand
Proc rnd_x
call srandsystime ; Seed PRNG with system time, call once only
call rand ; Get a random number in AX
call rand2num1toValue_X
mov cx, AX ; save AX in register
mov AX, [Random_x]
mov [Xapple], ax
ret
ENDP rnd_x
Proc rnd_y
call srandsystime ; Seed PRNG with system time, call once only
call rand ; Get a random number in AX
call rand2num1toValue_Y
mov cx, AX ; save AX in register
mov AX , 0
mov al, 5 ; CHANGE LATER TO FIT GRID
mul cx
mov [yapple], ax
RET
ENDP rnd_y
PROC game_logic
CHECK_TIME: ;time checking loop
MOV AH, 2Ch ;get the system time
INT 21h ;is the current time equal to the previous one(TIME_AUX)?
CMP DL, [TIME_AUX] ;is the current time equal to the previous one(TIME_AUX)?
JE CHECK_TIME ; if it is the same, skip updating the game state
; If it reaches this point, it's because the time has passed
MOV [TIME_AUX], DL ;update time
CALL moves
call draw
cmp [level] , 1
RET
ENDP game_logic
start:
MOV AX, @data
MOV DS, AX
MOV AX, 13h
INT 10h ; Set video mode 13h (320x200 pixels, 256 colors)
game_loop:
CALL game_logic
JMP game_loop
exit:
MOV AX, 4C00h
INT 21h
END start
碰撞不起作用我知道,因为当你应该碰撞时苹果没有移动。
算法由GB-ASM制定:
您检查 2 个物体的 2 个中心之间的差异,如果两个差异的绝对值都小于它们的半宽度的总和,则存在碰撞。
您的 check_collision 过程是 so 没有实现上述描述!这完全是无稽之谈,因为它是将坐标而不是大小减半,它混合了 X 和 Y,而且它做了很多根本无法工作的事情。
忘记上面的算法,看看它是如何工作的。
您的 Square 和 Apple 的尺寸相同。您已将其设置为 5。
你绘制它们的方式很特别,但是嘿,它可以工作。这就是它的样子:
Xsquare Xapple
| |
v v
Ysquare ->.***** Yapple ->.*****
***** *****
***** *****
***** *****
***** *****
为了在 X 方向上发生碰撞,X 坐标之间的差必须小于 5。 Y方向的差值也是如此。并且这两个条件必须同时成立。
Xsqr Xapp DifferenceX is 6 -> No collision
| |
v v
.*****.*****
***** *****
***** *****
***** *****
***** *****
Xsqr Xapp DifferenceX is 5 -> No collision
| |
v v
.****.*****
**********
**********
**********
**********
XsqrXapp DifferenceX is 4 -> Collision (only if DifferenceY is < 5)
| |
v v
.***.@****
****@****
****@****
****@****
****@****
PROC check_collision
mov ax, [Xsquare]
sub ax, [Xapple]
jns DeltaX
neg ax
DeltaX:
cmp ax, [SnakeBody]
jnb NoCollision
mov ax, [Ysquare]
sub ax, [Yapple]
jns DeltaY
neg ax
DeltaY:
cmp ax, [SnakeBody]
jnb NoCollision
Collision:
... Here you do whatever it is that you need to do
NoCollision:
ret
ENDP check_collision