TASM asm 中的碰撞检测

问题描述 投票:0回答:1

我尝试实现的算法是https://gbdev.io/gb-asm-tutorial/part3/collision.html

这是获取苹果和蛇的中心的代码

    shr bx,1
    mov [CenterSquare_X], bx
    

    mov bx, [Y]
    shr bx,1
    mov [CenterSquare_Y], bx
    
    
    mov bx, [Xapple]
    shr bx,1
    mov [CenterApple_X], bx
    
    
    mov bx, [Yapple]
    shr bx,1
    mov [CenterApple_Y], bx
    

call check_collision

这是碰撞测试之前的代码:

 
    
    
    mov  ax, [CenterSquare_X]
    sub  ax, [CenterApple_X]
    jns  DeltaX
    neg  ax
    DeltaX:
    
    cmp  ax, [SnakeBody]
    jnb  NoCollision

    mov  ax, [CenterSquare_Y]
    sub  ax, [CenterApple_Y]
    jns  DeltaY ; Jump short if not sign (SF=0)
    neg  ax
DeltaY:
  cmp  ax, [SnakeBody]
  jnb  NoCollision ; Jump short if not below

    
    
    Collision:
    CALL rnd_y
    call rnd_x 
    
    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
    
    
    
    
    
   
    

NoCollision:
    RET
    
ENDP check_collision ; hitbox code

出于某种原因,此代码仅在苹果的 x 可被 5 整除并且苹果的 y 可被 5 整除时才有效,尽管该算法应该适用于不在这些轴上的情况。

通过调试器查看后,我找不到原因,碰撞正在工作,rnds正在工作,中心正在工作。

我的完整代码:

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 80 ; my rnds
Random_y dw 80 ; 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 its RND_y we can use any y value times 5 if its 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 displayx
    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 Key Stroke
    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' '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 collison 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 collison 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


 

    mov bx, [X]
    shr bx,1
    mov [CenterSquare_X], bx
    

    mov bx, [Y]
    shr bx,1
    mov [CenterSquare_Y], bx
    
    
    mov bx, [Xapple]
    shr bx,1
    mov [CenterApple_X], bx
    
    
    mov bx, [Yapple]
    shr bx,1
    mov [CenterApple_Y], bx
    

call check_collision

        

    RET
ENDP draw



 PROC check_collision ; checks for collison with snake
 
    
    
    mov  ax, [CenterSquare_X]
    sub  ax, [CenterApple_X]
    jns  DeltaX
    neg  ax
    DeltaX:
    
    cmp  ax, [SnakeBody]
    jnb  NoCollision

    mov  ax, [CenterSquare_Y]
    sub  ax, [CenterApple_Y]
    jns  DeltaY ; Jump short if not sign (SF=0)
    neg  ax
DeltaY:
  cmp  ax, [SnakeBody]
  jnb  NoCollision ; Jump short if not below

    
    
    Collision:
    CALL rnd_y
    call rnd_x 
    
    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
    
    
    
    
    
   
    

NoCollision:
    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], ax
    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 [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 [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```


assembly collision-detection game-development x86-16 tasm
1个回答
0
投票
mov bx, [X]
shr bx,1
mov [CenterSquare_X], bx

mov bx, [Y]
shr bx,1
mov [CenterSquare_Y], bx

mov bx, [Xapple]
shr bx,1
mov [CenterApple_X], bx

mov bx, [Yapple]
shr bx,1
mov [CenterApple_Y], bx

您的代码“获取苹果和蛇的中心”是错误,因为您仍然将坐标减半而不是尺寸!我已经在我的之前的回答中报告了这一点。不过,您确实纠正了 X 和 Y 的混合。

您的 Square 和 Apple 的尺寸相同。您已将其设置为 5。
接下来是你的正方形和苹果的样子。我用“S”标记了正方形的中心,用“A”标记了苹果的中心:

          Xsquare                 Xapple
          |                       |
          v                       v
Ysquare ->.*****         Yapple ->.*****
           *****                   *****
           **S** <- Ysquare + 2    **A** <- Yapple + 2
           *****                   *****
           *****                   *****
             ^                       ^
             |                       |
             Xsquare + 3             Xapple + 3

这就是计算中心的方法:

mov  si, [SnakeBody]      ; 5 (best to keep this an odd number: 3, 5, 7, ...
shr  si, 1                ; 2

mov  bx, [X]
lea  ax, [bx + si + 1]    ; X + 3
mov  [CenterSquare_X], ax

mov  bx, [Y]
lea  ax, [bx + si]        ; Y + 2
mov  [CenterSquare_Y], ax

mov  bx, [Xapple]
lea  ax, [bx + si + 1]    ; Xapple + 3
mov  [CenterApple_X], ax

mov  bx, [Yapple]
lea  ax, [bx + si]        ; Yapple + 2
mov  [CenterApple_Y], ax

为了在 X 方向上发生碰撞,X 坐标之间的差必须小于 5。 Y方向的差值也是如此。并且这两个条件必须同时成立。

Xsqr  Xapp    DifferenceX is 6 -> No collision
|     |
v     v
.*****.*****
 ***** *****
 **S** **A**
 ***** *****
 ***** *****

Xsqr Xapp    DifferenceX is 5 -> No collision
|    |
v    v
.****.*****
 **********
 **S****A**
 **********
 **********

XsqrXapp    DifferenceX is 4 -> Collision (only if DifferenceY is < 5)
|   |
v   v
.***.@****
 ****@****
 **S*@*A**
 ****@****
 ****@****
PROC check_collision
  mov  ax, [CenterSquare_X]
  sub  ax, [CenterApple_X]
  jns  DeltaX
  neg  ax
DeltaX:
  cmp  ax, [SnakeBody]
  jnb  NoCollision

  mov  ax, [CenterSquare_Y]
  sub  ax, [CenterApple_Y]
  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
© www.soinside.com 2019 - 2024. All rights reserved.