There's a variety of approaches available for doing this.
The one I favor is suited only for windows 10 as it uses Virtual terminal sequences to control cursor position, color and display properties such as wether the cusor is visible or hidden. It also allows you to switch seemlessly between the main screen buffer and an alternate screen buffer. It is the method that offers the smoothest animation available, however, being limited to windows 10 only means there will be a lot of users out there who won't be able to use it.
Here is a basic collision detection engine using the principle, that describes the process:
As it is basic, it is limited to the choice comma for user input. The game engine in the link further below uses an external exe developed by Antonio, a long time member of this forum, to take user input, allowing for much faster gameplay.
Code: Select all
::: AUTHOR : T3RRY Created : 20/03/2021 Version : 1.0.0
::: PURPOSE : Demonstrate how to implement a system of Character movement against a background
::: with collision detection against specific background characters
::: LIMITATION : Windows 10
=================================================================================================
::: DEMONSTRATION SCRIPT:
=================================================================================================
@Echo off
:# Execute from directory script located in
CD /D "%~dp0"
If "!" == "" (Echo(Delayed Expansion Not Permitted prior to macro definiton& Pause & Exit /b 1)
Ver | findstr /LC:"Version 10." > nul || (Echo(Your Version of Windows does not Support Virtual Terminal Sequences)
:# Ensure Virtual Terminal sequences Enabled for VT codes. Effective after restart.
:# No test exists to determine if VT support is already enabled.
(reg add HKCU\Console /f /v VirtualTerminalLevel /t REG_DWORD /d 1 ) > Nul || (
Echo(Virtual Terminal codes Required by %~n0 not supported on your system.
Pause
Exit
)
:# Define Escape Control Character for Virtual Terminal Code usage
For /F %%a in ('Echo prompt $E^|cmd')Do Set "\E=%%a"
CLS & Mode 100,30
=================:# MODIFICATION OF MACRO'S NOT RECOMMENDED [ Closed System with Dependencies ]
:# Movement Macros. MODIFICATIONS SHOULD ONLY BE ATTEMPTED BY ADVANCED BATCH SCRIPTERS
:#
:# Dependencies:
:# - Variable: Sprite
:# - Variable: Collision.Characters
:# - Array Variables: LineINTEGER
:#
:# Mode of operation:
:#
:# Tests Sprite cells at new Y/X Position along axis of intended travel against list of
:# collision characters in the Defined LineY using substring modification to Determine if a move at cell Y;X
:# is to be considered Out Of Bounds due to collision.
:# On Collision Sets 'OOB' variable Flag as 1 [True] and Returns the Character collided with in Var: Collide.Type
:# At the end of Move_Loop ; Sprite Definition is replaced with New cell values only when OOB flag is not set.
:# Components common to Move Direction macro's defined to For.Cells and Test.CollisionAXIS
Set "For.Cells=Set "OOB="&(Set "nSprite="& For %%G in (!Sprite!)Do For /F "Tokens=1,2 Delims=;" %%Y in ("%%~G")Do For /F "Delims=" %%v in"
:# Seperate Y and X Test Collision macros required as Meta variable usage during collision testing differs for Y and X axis.
:# Vertical Movement Macros output the lineY definition prior to movement to clear previous sprite cells from Display
:# before sprite cell Y values are updated; as the loop uses current Sprite Y values to clear previous cell locations.
:# To account for string substition being 1 indexed ; X axis offsets %%Z+0 [Right] and %%Z-2 [Left] are used.
:# %%Z-2 [Left] also accounts for cmd.exe Y;X cell coordinates being 1 indexed.
Set "Test.CollisionX=For %%K in (!Collision.Characters!)Do if "!Line%%Y:~%%v,1!" == "%%~K" (Set "OOB=1"& Set "Collide.Type=%%~K")) & Set "nSprite=!nSprite! "%%Y;!nX!"")"
Set "Test.CollisionY=For %%K in (!Collision.Characters!)Do if "!Line%%v:~%%c,1!" == "%%~K" (Set "OOB=1"& Set "Collide.Type=%%~K")) & Set "nSprite=!nSprite! "!nY!;%%Z"" & <Nul Set /P "=%\E%[%%Y;1H!Line%%Y!")"
:# Directional Macros - Right Left Up Down
Set "Right=%For.Cells% ('Set /A %%Z+0')Do ( Set /A "nX=%%Z+1"&( %Test.CollisionX% )"
Set "Left= %For.Cells% ('set /A %%Z-2')Do ( Set /A "nX=%%Z-1"&( %Test.CollisionX% )"
Set "Up= %For.Cells% ('set /A %%Y-1')Do For /F "Delims=" %%c in ('set /A %%Z-1')Do (Set /A "nY=%%Y-1"&( %Test.CollisionY% )"
Set "Down= %For.Cells% ('set /A %%Y+1')Do For /F "Delims=" %%c in ('set /A %%Z-1')Do (Set /A "nY=%%Y+1"&( %Test.CollisionY% )"
:# Undefine shared Macro's after incorperration in the Directional Macros
Set "For.Cells="
Set "Test.CollisionX="
Set "Test.CollisionY="
=================================================================================================
Setlocal EnableExtensions EnableDelayedExpansion
:# Disable Cursor Display for smooth animation
Echo(%\E%[?25l
Cls
:# Define screen Line# Array [ Example ]
:# Characters in each line are passable unless defined in the Collision.Characters variable
:#
For %%G in (^
"Line1=+-----------------------------------------------------------------------------------------+"^
"Line2=| |"^
"Line3=| |"^
"Line4=| .. |"^
"Line5=| .. |"^
"Line6=| OO OO |"^
"Line7=| O OOc |"^
"Line8=| OO OO |"^
"Line9=| |"^
"Line10=| |"^
"Line11=| . ___ |"^
"Line12=| ... |"^
"Line13=| ..... |"^
"Line14=| ....... [ ] |"^
"Line15=| [ ] |"^
"Line16=| Z |"^
"Line17=| Z |"^
"Line18=| rZ ___ |"^
"Line19=| ZZ |"^
"Line20=| |"^
"Line21=| |"^
"Line22=| |"^
"Line23=| |"^
"Line24=| |"^
"Line25=+-----------------------------------------------------------------------------------------+"^
) Do Set %%G
:# Output Screen Lines
For /L %%i in (1 1 25)Do Echo(!Line%%i!
:# Define Collison Characters. On Collision, Character collided with is returned to !Collide.Type!
:# Out of bounds flagged using boundary characters in Collision.Characters list
:# Characters in any Line not defined as a collision character are passable; and are not returned to !Collide.Type!
:# Each Character in the list should be Doublequoted:
Set Collision.Characters="-" "|" "O" "_" "[" "]" "Z"
:# Specify Fatal Characters by Definition; Each Character Doublequoted in list form as above:
Set Fatal="Z"
:# Define Individual Sprite cell properties - VTCOLORmCHARACTER
Set "sC1=31mU"
Set "sC2=31mU"
Set "sC3=35m#"
Set "sC4=36m@"
Set "sC5=35m#"
:# Define Sprite cell coordinates
:# sC1 sC2 sC3 sC4 sC5
Set Sprite="2;2" "2;4" "3;2" "3;3" "3;4"
:# Move_Loop Choice Controller Key Definition
:# Change controller Keys by redifining the below four kDirection or kQuit Values
Set "kLeft=A"
Set "kRight=D"
Set "kUp=W"
Set "kDown=S"
Set "kQuit=0"
:# Populate choice keylist using kDirection values.
Set "MoveKeys=!kUp!!kDown!!kLeft!!kRight!"
:# kDirection variables are used to test inverse inverse of !last! if Locking out movement in opposing direction.
Set "!kUp!=!kDown!"
Set "!kDown!=!kUp!"
Set "!kLeft!=!kRight!"
Set "!kRight!=!kLeft!"
Title Move: !MoveKeys! Exit: 0
:Move_Loop
:# Reset Collision Flag
Set "Collide.Type="
:# Overwite Lines currently occupied by Sprite Cells with Original Line%%Y definition
:# Redirected to Sprite.dat to append sprite cells in next step
For %%G in (!Sprite!)Do For /F "Tokens=1 Delims=;" %%Y in ("%%~G") Do (
<Nul Set /P "=%\E%[%%Y;1H!Line%%Y!"
)
:# Append Current sprite cell locations and values to Output file
:# Notifies undefined Sprite Cell 'sC' color and character and exits
:# Output New Cell values
Set cCol=0
For %%G in (!Sprite!)Do For /F "Tokens=1,2 Delims=;" %%Y in ("%%~G") Do (
Set /A "cCol+=1"
For %%# in (!cCol!) Do (
If "!sC%%#!" == "" (
CLS
Echo(Sprite Cell sC%%# Undefined
Timeout /T 3 /Nobreak
Endlocal
Exit /B 1
)
<nul Set /P "=%\E%[%%Y;%%ZH%\E%[!sC%%#!%\E%[0m"
)
)
:# Select Move Axis and enact Relevent Macro
:# Choice command for input may be substuted with other Control Systems.
:# To 'Lock out' Movement in the Opposing Direction currently being travelled:
:#
:# For /F "Delims=" %%C in ('Choice /N /C:!MoveKeys!!kQuit!')Do If not "!%%C!" == "!Last!" (
For /F "Delims=" %%C in ('Choice /N /C:!MoveKeys!!kQuit! ')Do (
Set "Last=%%C"
If %%C==!kQuit! (
Echo(%\E%[26;1H%\E%[?25h
Endlocal & Exit /B
)
If %%C==!kUp! (%Up%)
If %%C==!kLeft! (%Left%)
If %%C==!kDown! (%Down%)
If %%C==!kRight! (%Right%)
)
:# Update Sprite Definiton if the executed Movement macro did not flag move as Out Of Bounds
If "!OOB!" == "" (Set "Sprite=!nSprite!")
:# Example of Flagging a fatal collision.
For %%x in (!Fatal!)Do If "!Collide.Type!" == "%%~x" (
Cls & Echo(Oh No - %%~x is Deadly^^!
Timeout /T 3 /NoBreak
Endlocal & Goto :Eof
)
Goto :Move_Loop
A more verbose game engine is available in my games archive here:
https://drive.google.com/file/d/1cAQLd- ... sp=sharing