- Stage 1: Eliminate fish-eye distortion with precomputed tangential ray offset table and fractional DDA depth - Stage 2: Full asset management in EblanStudio (stb_image/stb_image_write, 128x128 BGRA texture packaging, WAV sound manager) - Stage 3: Multi-level room streaming, LevelTransition/CELL_PORTAL trigger system, 16-frame screen fade to black - Stage 4: 60Hz cutscene engine in pure x86 ASM (v4 binary track, waypoint camera motion, shortest-arc pan, CP1251 Russian subtitles, letterbox overlay, audio) - Stage 5: EblanStudio cutscene timeline (F6) and windowless Live ASM Viewport over shared-memory IPC directly rendered into DX11 - Tooling & Tests: comprehensive regression test suite (94 editor + 107 engine tests), IPC tests, and cutscene demo
228 lines
5 KiB
PHP
228 lines
5 KiB
PHP
; ==============================================================================
|
|
; EBLAN ENGINE - Player Movement, Physics & Collision Handling
|
|
; ==============================================================================
|
|
|
|
.code
|
|
|
|
; ------------------------------------------------------------------------------
|
|
; UpdatePlayer: Updates rotation, computes movement vector & handles collisions
|
|
; ------------------------------------------------------------------------------
|
|
UpdatePlayer PROC uses ebx ecx edx esi edi
|
|
LOCAL moveX:DWORD, moveY:DWORD
|
|
LOCAL speed:DWORD
|
|
LOCAL nextX:DWORD, nextY:DWORD
|
|
LOCAL checkGridX:DWORD, checkGridY:DWORD
|
|
|
|
; Freeze player movement and inputs during level transitions
|
|
cmp fadeState, 0
|
|
jne update_player_done
|
|
|
|
cmp cutscenePending, 0
|
|
je scene_manual_start
|
|
call StartCutscene
|
|
scene_manual_start:
|
|
cmp keyCutscene, 0
|
|
je scene_check_active
|
|
cmp isCutsceneActive, 0
|
|
jne scene_check_active
|
|
call StartCutscene
|
|
scene_check_active:
|
|
cmp isCutsceneActive, 0
|
|
je normal_player_update
|
|
cmp keySkipScene, 0
|
|
je scene_update_tick
|
|
call StopCutscene
|
|
ret
|
|
scene_update_tick:
|
|
call UpdateCutscene
|
|
ret
|
|
normal_player_update:
|
|
mov moveX, 0
|
|
mov moveY, 0
|
|
|
|
; 1. Handle Camera Rotation
|
|
cmp keyTurnLeft, 0
|
|
je check_turn_right
|
|
mov eax, playerAngle
|
|
sub eax, playerTurnSpeed
|
|
and eax, ANGLE_MASK
|
|
mov playerAngle, eax
|
|
|
|
check_turn_right:
|
|
cmp keyTurnRight, 0
|
|
je check_action
|
|
mov eax, playerAngle
|
|
add eax, playerTurnSpeed
|
|
and eax, ANGLE_MASK
|
|
mov playerAngle, eax
|
|
|
|
check_action:
|
|
cmp keyAction, 0
|
|
je check_movement
|
|
call InteractDoor
|
|
cmp fadeState, 0
|
|
jne update_player_done
|
|
|
|
; 2. Determine Movement Speed
|
|
check_movement:
|
|
mov eax, playerMoveSpeed ; Base speed: raw units/frame
|
|
cmp keyRun, 0
|
|
je @F
|
|
mov eax, playerRunSpeed ; Sprint speed
|
|
@@:
|
|
mov speed, eax
|
|
|
|
; 3. Forward / Backward Vector
|
|
cmp keyForward, 0
|
|
je check_backward
|
|
|
|
mov eax, playerAngle
|
|
and eax, ANGLE_MASK
|
|
; dx += cos(angle) * speed
|
|
mov ebx, [tableCos + eax*4]
|
|
imul ebx, speed
|
|
sar ebx, 16
|
|
add moveX, ebx
|
|
|
|
; dy += sin(angle) * speed
|
|
mov ecx, [tableSin + eax*4]
|
|
imul ecx, speed
|
|
sar ecx, 16
|
|
add moveY, ecx
|
|
|
|
check_backward:
|
|
cmp keyBackward, 0
|
|
je check_strafe_left
|
|
|
|
mov eax, playerAngle
|
|
and eax, ANGLE_MASK
|
|
mov ebx, [tableCos + eax*4]
|
|
imul ebx, speed
|
|
sar ebx, 16
|
|
sub moveX, ebx
|
|
|
|
mov ecx, [tableSin + eax*4]
|
|
imul ecx, speed
|
|
sar ecx, 16
|
|
sub moveY, ecx
|
|
|
|
; 4. Strafe Left / Right Vector (Angle +/- 90 degrees)
|
|
check_strafe_left:
|
|
cmp keyStrafeLeft, 0
|
|
je check_strafe_right
|
|
|
|
; Left vector is (angle - 128)
|
|
mov eax, playerAngle
|
|
sub eax, ANGLE_90
|
|
and eax, ANGLE_MASK
|
|
|
|
mov ebx, [tableCos + eax*4]
|
|
imul ebx, speed
|
|
sar ebx, 16
|
|
add moveX, ebx
|
|
|
|
mov ecx, [tableSin + eax*4]
|
|
imul ecx, speed
|
|
sar ecx, 16
|
|
add moveY, ecx
|
|
|
|
check_strafe_right:
|
|
cmp keyStrafeRight, 0
|
|
je apply_physics
|
|
|
|
; Right vector is (angle + 128)
|
|
mov eax, playerAngle
|
|
add eax, ANGLE_90
|
|
and eax, ANGLE_MASK
|
|
|
|
mov ebx, [tableCos + eax*4]
|
|
imul ebx, speed
|
|
sar ebx, 16
|
|
add moveX, ebx
|
|
|
|
mov ecx, [tableSin + eax*4]
|
|
imul ecx, speed
|
|
sar ecx, 16
|
|
add moveY, ecx
|
|
|
|
; 5. Apply Movement with Wall-Sliding Collision Detection
|
|
apply_physics:
|
|
mov eax, moveX
|
|
or eax, moveY
|
|
jz update_player_done ; No movement input
|
|
|
|
; --- Test X Movement ---
|
|
mov eax, playerX
|
|
add eax, moveX
|
|
mov nextX, eax
|
|
|
|
; Buffer check (collision body radius)
|
|
mov ebx, nextX
|
|
cmp moveX, 0
|
|
jge @F
|
|
mov eax, playerRadius
|
|
sub ebx, eax ; Moving left: check left edge
|
|
jmp check_x_col
|
|
@@:
|
|
mov eax, playerRadius
|
|
add ebx, eax ; Moving right: check right edge
|
|
check_x_col:
|
|
sar ebx, 6 ; divide by CELL_SIZE (64)
|
|
mov checkGridX, ebx
|
|
|
|
mov ecx, playerY
|
|
sar ecx, 6
|
|
mov checkGridY, ecx
|
|
|
|
invoke GetMapCell, checkGridX, checkGridY
|
|
cmp eax, CELL_PORTAL
|
|
je allow_portal_x
|
|
invoke IsSolidCell, eax
|
|
test eax, eax
|
|
jnz skip_x_move ; Collision on X: slide along wall!
|
|
allow_portal_x:
|
|
|
|
mov eax, nextX
|
|
mov playerX, eax
|
|
|
|
skip_x_move:
|
|
; --- Test Y Movement ---
|
|
mov eax, playerY
|
|
add eax, moveY
|
|
mov nextY, eax
|
|
|
|
mov ecx, nextY
|
|
cmp moveY, 0
|
|
jge @F
|
|
mov eax, playerRadius
|
|
sub ecx, eax
|
|
jmp check_y_col
|
|
@@:
|
|
mov eax, playerRadius
|
|
add ecx, eax
|
|
check_y_col:
|
|
sar ecx, 6
|
|
mov checkGridY, ecx
|
|
|
|
mov ebx, playerX
|
|
sar ebx, 6
|
|
mov checkGridX, ebx
|
|
|
|
invoke GetMapCell, checkGridX, checkGridY
|
|
cmp eax, CELL_PORTAL
|
|
je allow_portal_y
|
|
invoke IsSolidCell, eax
|
|
test eax, eax
|
|
jnz update_player_done ; Collision on Y
|
|
allow_portal_y:
|
|
|
|
mov eax, nextY
|
|
mov playerY, eax
|
|
|
|
update_player_done:
|
|
cmp fadeState, 0
|
|
jne @F
|
|
call CheckPortalTriggers
|
|
@@:
|
|
ret
|
|
UpdatePlayer ENDP
|