You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在汇编中实现VGA模式双人Tron游戏?寄存器使用困惑求解

问题:汇编语言实现双人VGA Tron游戏的寄存器冲突问题

我想在汇编语言中制作一款VGA模式的双人Tron游戏:玩家1通过方向键控制,绘制橙色轨迹;玩家2通过W/A/S/D键控制,绘制蓝色轨迹。我已有单人游戏代码,但不清楚如何实现双人模式——我知道不宜为两名玩家使用相同寄存器,却不确定该改用哪些寄存器。我尝试用BX替代DX作为玩家2的寄存器,但似乎无效。

以下是完整代码:

Code    Segment
    assume CS:Code, DS:Data, SS:Stack

Start:
    mov ax, Code
    mov DS, AX


Menu:
;Screen clear
    mov ax, 03h
    int 10h
    
;Kurzor position
    mov ah, 02h
    mov bh, 0
    mov dh, 10          ;row
    mov dl, 30          ;column
    int 10h

;Menu
    mov dx, offset gamestart
    mov ah, 09
    int 21h

    mov dx, offset empty
    mov ah, 09
    int 21h

    mov dx, offset exit
    mov ah, 09
    int 21h

;Wait for button press
    xor ax, ax
    int 16h

;Examine pressed button
    cmp al, '1'
    jz Startgame

    cmp al, '2'
    jz Program_End_Helper

Startgame:
;First player pos
    mov dl, 100
    mov dh, 100
    push dx

;Second player pos
    mov dl, 200
    mov dh, 100
    push dx

    mov ax, 13h             ;Change mode (VGA)
    int 10h
    mov ax, 0a000h          ;Video 
    mov es, ax              ;Extra segment

Draw:
    pop dx                  ;dx contains Y(dh) and X(dl)
    xor ah, ah
    mov al, dh              ;ax-ben Y koordináta
    push dx                 ;dx mentése, mul utasítás felülírja
    mov bx, 128     ;320
    mul bx                  ;Y koordináta * 320
    pop dx                  ;dx-ben Y(dh), X(dl) koordináta
    add al, dl              ;X koordináta hozzáadása
    jnc Pixel
    inc ah                  ;van átvitel

Pixel:
    push dx
    mov di, ax

    mov al, 1       ;blue
    shl al, 2  
    or al, 20       ;green
    shl al, 2    
    or al, 50       ;red

    mov es:[di], al         ;video

    

Draw2:
    pop dx
    xor ah, ah
    mov al, dh
    push dx
    mov bx, 320
    mul bx
    pop dx
    add al, dl
    jnc Pixel2
    inc ah

Pixel2:
    push dx
    mov di, ax
    mov bl, 128
    mov es:[di], bl

Var:
    xor ah, ah
    int 16h
    cmp al, 27
    jz Program_End_Helper2
    cmp ah, 75
    jz Left
    cmp ah, 77
    jz Right
    cmp ah, 72
    jz Up
    cmp ah, 80
    jz Down
    jmp Var

Program_End_Helper:
    jmp Program_End 

Var2:                   ;Second player control: w,a,s,d
    xor ah, ah
    int 16h
    cmp al, 27
    jz Program_End_Helper2
    cmp al, 'a'
    jz Left2
    cmp al, 'd'
    jz Right2
    cmp al, 'w'
    jz Up2
    cmp al, 's'
    jz Down2
    jmp Var2



Left:
    pop dx
    dec dl
    cmp dl, 1
    jnc Store
    inc dl
    jmp Store
    
Right:
    pop dx
    inc dl
    cmp dl, 250
    jc Store
    dec dl
    jmp Store

Up:
    pop dx
    dec dh
    cmp dh, 1
    jnc Store
    inc dh
    jmp Store

Down:
    pop dx
    inc dh
    cmp dh, 200
    jc Store
    dec dh
    jmp Store

Store:
    push dx
    jmp Draw

Program_End_Helper2:
    jmp Program_End 

Left2:
    pop dx
    dec dl
    cmp dl, 1
    jnc Store2
    inc dl
    jmp Store2
    
Right2:
    pop dx
    inc dl
    cmp dl, 250
    jc Store2
    dec dl
    jmp Store2

Up2:
    pop dx
    dec dh
    cmp dh, 1
    jnc Store2
    inc dh
    jmp Store2

Down2:
    pop dx
    inc dh
    cmp dh, 200
    jc Store2
    dec dh
    jmp Store2

Store2:
    push dx
    jmp Draw2

Program_End:
    mov ax, 03h
    int 10h
    pop dx
    mov ax, 4c00h
    int 21h

gamestart: db '1. Start game$'
empty: db '                                                                   $'
exit: db '2. Exit$'


Code    Ends

Data    Segment

Data    Ends

Stack   Segment

Stack   Ends
    End Start
解决方案

你的核心问题在于没有为两名玩家独立存储位置数据,而是复用了DX寄存器和栈空间,导致两个玩家的坐标互相覆盖。另外,当前代码的输入处理是阻塞式的(int 16h等待按键),无法同时响应两名玩家的操作,这也是双人模式的关键障碍。下面分步骤修正:

1. 为两名玩家分配独立的存储位置

不要用栈临时存坐标,直接在Data段定义两个变量分别存储玩家1和玩家2的(X,Y)坐标:

Data    Segment
    Player1X db 100   ; 玩家1X坐标
    Player1Y db 100   ; 玩家1Y坐标
    Player2X db 200   ; 玩家2X坐标
    Player2Y db 100   ; 玩家2Y坐标
Data    Ends

这样就彻底避免了寄存器冲突,每个玩家的位置都有独立的存储单元。

2. 重构绘制逻辑,分别处理两名玩家

修改绘制代码,直接从数据段读取对应玩家的坐标,而非从栈中弹出:

玩家1绘制代码:

DrawPlayer1:
    ; 计算显存地址: Y*320 + X
    xor ax, ax
    mov al, [Player1Y]
    mov bx, 320
    mul bx
    mov cl, [Player1X]
    add ax, cx
    mov di, ax

    ; 设置橙色(保留你原代码的颜色计算)
    mov al, 1       ; blue
    shl al, 2  
    or al, 20       ; green
    shl al, 2    
    or al, 50       ; red
    mov es:[di], al
    ret

玩家2绘制代码:

DrawPlayer2:
    xor ax, ax
    mov al, [Player2Y]
    mov bx, 320
    mul bx
    mov cl, [Player2X]
    add ax, cx
    mov di, ax

    ; 设置蓝色(VGA模式下128对应蓝色)
    mov al, 128
    mov es:[di], al
    ret

3. 非阻塞式输入处理,同时响应两名玩家

原来的int 16h是阻塞调用,必须改成非阻塞检查(使用ah=01h的int 16h),这样可以在没有按键时继续执行游戏逻辑,同时检测两名玩家的输入:

GameLoop:
    ; 先绘制两名玩家的当前位置
    call DrawPlayer1
    call DrawPlayer2

    ; 非阻塞检查键盘输入
    mov ah, 01h
    int 16h
    jz NoKeyPressed  ; 无按键则跳过处理

    ; 读取按键
    xor ah, ah
    int 16h

    ; 处理玩家1的方向键
    cmp ah, 75       ; 左箭头
    jz Player1Left
    cmp ah, 77       ; 右箭头
    jz Player1Right
    cmp ah, 72       ; 上箭头
    jz Player1Up
    cmp ah, 80       ; 下箭头
    jz Player1Down

    ; 处理玩家2的WASD
    cmp al, 'a'
    jz Player2Left
    cmp al, 'd'
    jz Player2Right
    cmp al, 'w'
    jz Player2Up
    cmp al, 's'
    jz Player2Down

    ; 处理ESC退出
    cmp al, 27
    jz Program_End

NoKeyPressed:
    ; 加延时防止游戏速度过快
    mov cx, 0001h
    mov dx, 8000h
    mov ah, 86h
    int 15h

    jmp GameLoop

4. 重构移动逻辑,操作对应玩家的坐标

以玩家1左移为例,直接修改数据段变量:

Player1Left:
    dec [Player1X]
    cmp [Player1X], 0
    jge Player1MoveDone
    mov [Player1X], 319  ; 边界循环,也可改成禁止越界
Player1MoveDone:
    jmp GameLoop

其他方向和玩家2的移动逻辑以此类推,无需再依赖栈和DX寄存器。

5. 修复原代码中的错误

  • 原Draw段中mov bx,128是笔误,应该是320(VGA 320x200模式每行像素数),否则显存地址计算完全错误。
  • 栈的使用逻辑混乱,两名玩家的坐标入栈后弹出会互相覆盖,使用数据段变量是更可靠的方案。

将这些修改整合到代码中,即可实现正常的双人Tron游戏模式。

内容的提问来源于stack exchange,提问作者tomiwind

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 05:08:15