Batch Games

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Posts: 117
Joined: 06 May 2020 10:14

Re: Batch Games

#31 Post by T3RRY » 08 Dec 2020 08:39

dbenham wrote:
08 Dec 2020 08:00
T3RRY wrote:
07 Dec 2020 21:41
Unfortunately I've not found a means to standardise delays that isn't impacted by the specs of a PC
That is actually fairly simple. Treat your game as a movie, consisting of a series of static frames with incremental changes displayed sequentially to simulate motion. You want the frame rate to be constant, regardless of the speed of the PC.

Dave Benham
Thanks for the tips, I'll have to find a bit of time to look over it and adapt my current approach.
As you say, it should be simple enough provided the execution of the codeblock can be completed within the desired framerate. Lowsuns version which occasionaly fails to catch input between frames has me thinking it might take a bit of testing still to ensure all necessary tasks are completed between one frame and the next.

Posts: 117
Joined: 06 May 2020 10:14

Re: Batch Games

#32 Post by T3RRY » 16 Dec 2020 10:47

Been at it again. This time around it's more about the system I've developed than it is the game { The game is only to show how to use the system }

Again, this one requires Antonio's getkey.exe for input, which is included in the below games archive link:
Games Archive: ... sp=sharing

Spites.bat uses macro's to convert ASCII art within the batch script to a list containing Y;X cell coordinates and character information for each cell. The approach used to convert the ASCII art limits each sprite to a single color.

Additional macro's are used to display and move sprites; Iterating over the Variables associated with each sprite and performing collision testing against a list of characters supplied as the Move.Sprite macro is expanded.
A sprite that will be moved CANNOT contain any characters that will be used in it's Collision Detection testing ( It will detect it's own cells colliding with each other, as testing is performed against current cell definitions ).


Code: Select all

@Echo off & CD "%~dp0"
CHCP 65001 > nul
:::::::::: Version 1.5
::: Games_by_T3RRY:
::: Header: Game building tool + tutorial for Batch Arcade Games
::: Dev Notes:
::: Purpose: Create a system to convert ASCII Art into sprites that can be moved and interacted with.
::: Move.Sprite macro Performance Decreases as Sprite size increases.
::: Creation Date 16/12/2020
::: [ * Author: T3RRY * ]
::: Additional Accreditation
::: Getkey.Exe by Antonio {} for Extended key controls.
::: Version Changes:
::: Removed Response handling of collision from Move.Sprite macro
::: Upgraded move.sprite macro to accept arguments for Collision or Capture Characters
::: - return Vars [Collision is True: Valid=0] [Capture is True: Captured=1]
rem /* Establish and verify required resources. Clearly separate script elements */
rem /* Test Environment is suitable for definition of Macro's */
 If "!![" == "[" (Echo/Delayed expansion Must not be enabled prior to starting %~n0.bat & Pause & Exit /B 0)
 Set "MSG=Title ?"
 %MSG:?= Verifying Resources ...%
rem /* use wmic output with find to test if system is windows 10. Exit with notice if not */
 wmic OS get OSArchitecture,caption | FIND "10" > nul || (ECHO/Windows 10 required for ascii escape codes & Exit /B)
rem /* Define Escape character used for console virtual terminal sequences */
rem -
 for /F "delims=#" %%a in ('"prompt #$E# & for %%a in (1) do rem"') do set "\E=%%a"
rem /* Define Getkey path wit /n no wait parameter */
 For /F "Delims=" %%C in ('dir "%~dp0*GetKey.exe" /B /S') Do If not defined GetKey Set "GetKey="%%C" /n"
rem /* Test getkey var is defined with valid exe path. Exit with notice if not. */
 Echo/%GetKey%|findstr.exe /LIC:"GetKey.exe" > nul || (Echo/GetKey.Exe not found in Directory. Game cannot be played without GetKey.exe &Pause &Exit /B 0)
 (For /F "Tokens=1,2 Delims==" %%G in ('Set "}" 2^> Nul ')Do Set "%%~G=") 2> nul
 If not exist "%TEMP%" (Set "Save.Dir=%~dp0")Else Set "Save.Dir=%TEMP%\"
rem /* Test write permission in the assigned directory. Exit with notice if no write permission */
 break >"" || (
  Echo/Write permission required in %Save.Dir% to continue
  Exit /B
 Set Background="%Save.Dir%%~n0_background.~tmp"
 Set Foreground="%Save.Dir%%~n0_foreground.~tmp"
 DEL %Foreground% 2> Nul
rem /* Ensure array used to display screen elements is undefined. */
 (For /F "Tokens=1,2 Delims==" %%G in ('Set "}"')Do Set "%%~G=") 2> nul
 %= --------------------------------------------------------- =%
(Set \n=^^^

%= Macro newline var =%)
(Set COMMENT=rem {i} ^^^

%= Macro Comment var =%)
rem /* On win loss action */
 Set "G.O=Call :End & Endlocal & Goto start"
 %MSG:?= Crafting Animation tools ...%
 Set ".Left=Right"&Set ".Right=Left"&Set ".Up=Down"&Set ".Down=Up"
rem /* Background.Border macro USAGE: %Background.Border%{VTcolorcode}{.Xmin}{.Xmax}{.Ymin}{.Ymax}{BorderCharacter} */
 Set Background.Border=Set "Border=" ^& For %%n in (1 2)Do If %%n==2 ( %\n%
  %COMMENT:{i}= Ensure Args 1-6 captured \n%
  For /F "Tokens=1,2,3,4,5,6 Delims={}" %%G in ("!Border!")Do If not "%%L" == "" ( %\n%
  %COMMENT:{i}= Assign Y;X min max values as border constraints for use within other macros {Args 2 -5} \n%
   Set /A ".Xmin=%%H,.Xmax=%%I,.Ymin=%%J,.Ymax=%%K"%\n%
  %COMMENT:{i}= Assign Border Char {Arg 6} \n%
   Set ".Char=%%L"%\n%
  %COMMENT:{i}= {SIDES} For each in xmin AND xmax do for each in Ymin TO Ymax Do \n%
   For %%w in (%%H %%I)Do for /L %%h in (%%J,1,%%K)Do ( %\n%
  %COMMENT:{i}= Define Cell of Border for Collision testing and display \n%
    Set "}%%h;%%w=%\E%[%%h;%%wH%\E%[%%~Gm%%~L" %\n%
  %COMMENT:{i}= {TOP + BASE} For each in Ymin AND Ymax do for each in Xmin TO Xmax Do \n%
    For %%i in (%%J %%K)Do If %%h Equ %%i ( %\n%
     For /L %%W in (%%H 1 %%I)Do ( %\n%
  %COMMENT:{i}= Define Cell of Border for Collision testing and display {with VT Color Arg 1} \n%
      Set "}%%h;%%W=%\E%[%%h;%%WH%\E%[%%~Gm%%~L" %\n%
  ))))Else ( Echo/Missing Args for %%Background.Border%% ^& Pause ^> nul ) %\n%
  %COMMENT:{i}= Define Console Size Lines Cols and Control Panel X Position based on Y X max values \n%
  Set /A "CNTRL=!.Xmax!+5,cols=!.Xmax!+25,lines=!.Ymax!+2" %\n%
 )Else Set Border=

 Set "UPDATE.Background=Set /A ".End=!.Ymax! + 1" & ((For /F "Tokens=2* Delims==" %%G in ('Set "}"')Do (< nul Set /P "=%%~G") & < nul Set /P "=%\E%[!.END!;1H%\E%[0m%\E%[?25l")) >%Background% & Type %Background%"
 Set "Def.Key=Set "input="&For %%n in (1 2)Do if %%n==2 (For %%I in (!input!)Do Set "k%%~I")Else Set input="
 Set "?Key#=For %%E in (!Errorlevel!) Do If not "!k%%E!" == "" (Set "Key=!k%%E!" & (If /I "!Key!" == "space" ( Pause > nul )) & (For %%d in (left right up down)Do If /I "!Key!" == "%%d" (Set "Dir=%%d")))Else If not "%%E" == "0" (If "mode" == "dev" TITLE Key Errorcode - %%E)"
::: DEF.SPRITE : Converts Ascii art to objects [ as a list ] with Defined Cordinates }Y;H=}Y;XHcharacter
rem /* Def.Sprite Macro. USAGE: %Def.Sprite:#=lineYpos%{SPRITEVARNAME}{VTCOLORCODE}{string defining characters for x positions of substituted Y line} */
 Set Def.Sprite=For %%n in (1 2)Do if %%n==2 ( %\n%
  %COMMENT:{i}= get Y coordinate value of current line from value supplied during macro expansion \n%
  Set /A "{y}=#" %\n%
  Set /A "{y}+=1" %\n%
  For /F "Tokens=1,2,3 Delims={}" %%G in ("!Cells!")Do If not "%%~H" == "" ( %\n%
   %COMMENT:{i}= Split Arg 2 cell data from Arg 1 Sprite name \n%
   Set "cell=%%I" %\n%
   Set "%%G.Color=%%H" %\n%
   %COMMENT:{i}= Constrain sprite definition to Playfield X dimensions \n%
   For /L %%i in (2 1 !.Xmin!)Do Set "cell= !cell!" %\n%
   %COMMENT:{i}= Get x coordinate of non whitespace elements in Cell string \n%
   For /L %%x in (0 1 !.Xmax!)Do If not "!cell:~%%x,1!" == "" ( %\n%
    If not "!cell:~%%x,1!" == " " ( %\n%
    %COMMENT:{i}= Shift {x} value from 0 index used by substring modification to 1 index of Virtual Terminal Sequences \n%
     FOR /F "Delims=" %%X in ('Set /A "{x}=%%x+!.Xmin!+1"')Do ( %\n%
      %COMMENT:{i}= Define Cell cordinate for collision testing \n%
      For %%C in ("H" ";" "[")Do If /I "!cell:~%%x,1!" == "%%~C" ( %\n%
       Echo/ Delim character %%C cannot be defined to a sprite. ^& Endlocal %\n%
       Pause  %\n%
       Exit /B 0 %\n%
      ) %\n%
      Set "}!{y}!;%%X=!{y}!;%%XH!cell:~%%x,1!" %\n%
      %COMMENT:{i}= Define Sprite variable Arg 1 with converted Coordinates for non whitespace cells from Arg 2 \n%
      Set "%%G=!%%G!"!{y}!;%%XH!cell:~%%x,1!"," %\n%
 )))))Else Set Cells=
::: SHOW : Iterates over the list value of a substituted sprite variable and outputs value.
rem /* USAGE: %Show:obj=SpriteVARNAME% */ [ Displays spritenames cells ]
 Set "Show=For %%n in (1 2)Do If %%n==2 (For %%g in (!obj!)Do ((Set "oStr=%%~g") & < nul Set /P "=%\E%[!Obj.Color!m%\E%[!oStr!%\E%[0m"))"
rem /* Variables used to convert Direction to Vector in Move.Sprite Macro*/
 Set "Left={x}{-}"& Set "Right={x}{+}"& Set "Up={y}{-}"& Set "Down={y}{+}"
::: rem /* Move.Sprite macro. Usage:
::: %Move.Sprite:obj=SPRITEVARNAME%{x|y}{+|-}{collision characters}{capture characters} */
::: Args 3 and 4 are optional. To ensure correct results; Characters for testing should  be unique to a
::: single test; Characters MUST NOT match the current object or characters in the other test.
 Set Move.Sprite=For %%n in (1 2) Do if %%n==2 ( %\n%
  %COMMENT:{i}= reset sprite clone SUB and VALID move flag variable \n%
  Set "Sub=" %\n%
  Set /A "valid=1,captured=0" %\n%
  %COMMENT:{i}= Catch Move Vector and Collision objects \n%
  For /F "Tokens=1,2,3,4 Delims={}" %%G in ("!Move.Dir!")Do ( %\n%
   Set "axis=%%G" %\n%
   Set "vector=%%H" %\n%
   If not "%%~I" == "" (Set "Collide=%%I")Else (Set "Collide=") %\n%
   If not "%%~J" == "" (Set "Flag=%%J")Else ( %\n%
    Set "Flag=" %\n%
  )) %\n%
  %COMMENT:{i}= For X or Y axis \n%
  If /I "!axis!" == "X" ( %\n%
   %COMMENT:{i}= iterate over sprite cells \n%
   For %%g in (!obj!) Do ( %\n%
    %COMMENT:{i}= Seperate Y;X coords and Cell character from cell string \n%
    For /F "Tokens=1,2,3 Delims=;H" %%t in ("%%~g")Do ( %\n%
     %COMMENT:{i}= Adjust cells vector \n%
     Set /A "cx=%%u!vector!1" %\n%
     Set "cTkn=%%v" %\n%
     %COMMENT:{i}= get value of new y/x coord for substring modification \n%
     For /F "Delims=" %%c in ("!cx!")Do ( %\n%
      %COMMENT:{i}= Test cell against each collision character Flag move invalid on collision \n%
      For %%K in (!Collide!)Do If Not "!}%%t;%%c!" == "" ( %\n%
       Set "KO=!}%%t;%%c:%%~K=!" %\n%
       If Not "!}%%t;%%c!" == "!KO!" ( Set "valid=0" ) %\n%
      ) %\n%
      For %%Q in (!Flag!)Do If Not "!}%%t;%%c!" == "" ( %\n%
       Set "flag.C=!}%%t;%%c:%%~Q=!" %\n%
       Set "flag.Cell=!}%%t;%%c!" %\n%
       If not "!flag.Cell!" == "!flag.C!" ( Set "Captured=1" ) %\n%
      ) %\n%
      %COMMENT:{i}= On valid move for cell build sprite clone string \n%
      If "!Valid!" == "1" (Set "Sub=!Sub!"%%t;%%cH!cTKN!",") %\n%
   )))) ELSE ( %\n%
   For %%g in (!obj!) Do ( %\n%
    For /F "Tokens=1,2,3 Delims=;H" %%i in ("%%~g") Do ( %\n%
     Set /A "cy=%%i!vector!1" %\n%
     Set "cTkn=%%k" %\n%
     For /F "Delims=" %%o in ("!cy!") Do ( %\n%
      For %%K in (!Collide!)Do If not "!}%%o;%%j!" == "" ( %\n%
       Set "KO=!}%%o;%%j:%%~K=!" %\n%
       If Not "!}%%o;%%j!" == "!KO!" ( Set "valid=0" ) %\n%
      ) %\n%
      For %%P in (!Flag!)Do If Not "!}%%o;%%j!" == "" ( %\n%
       Set "flag.C=!}%%o;%%j:%%~P=!" %\n%
       Set "flag.Cell=!}%%o;%%j!" %\n%
       If Not "!flag.Cell!" == "!flag.C!" ( Set "Captured=1" ) %\n%
      ) %\n%
      If "!valid!" == "1" (Set "Sub=!Sub!"%%o;%%jH!cTKN!",") %\n%
  %Comment:{i}= If "valid" EQU "0" (Goto End) \n%
  %COMMENT:{i}= On all moves being valid \n%
  If "!valid!" == "1" (%\n%
   %COMMENT:{i}= iterate over sprites previous y;x cells \n%
   (For %%Q in (!obj!)Do ( %\n%
    %COMMENT:{i}= Seperate Y/X values \n%
    For /F "tokens=1,2 Delims=;H" %%1 in ("%%~Q") Do (%\n%
     %COMMENT:{i}= undefine Cell from collision detection array and clear from display \n%
     Set "}%%~1;%%~2=" %\n%
     Echo/%\E%[%%1;%%2H %\n%
     %COMMENT:{i}= redirect to foreground output file for display when new cell values are appended with SHOW macro \n%
   )))^>%Foreground% %\n%
   %COMMENT:{i}= Define new Cell Location with new value \n%
   (For %%S in (!Sub!)Do ( %\n%
    For /F "tokens=1,2,3 Delims=;H" %%3 in ("%%~S") Do (%\n%
     Set "cTKN=%%5" %\n%
     Set "}%%~3;%%~4=%%~3%;%~4H!cTKN!" %\n%
   ))) ^>^>%Foreground% %\n%
   TYPE %Foreground% %\n%
   %COMMENT:{i}= replace sprite with moved clone \n%
   Set "obj=!Sub!" %\n%
  %COMMENT:{i}= End the game on collision \n%
  ) %\n%
 )Else Set Move.Dir=
::: Commence Game. Define BORDER and SPRITE properties
 Setlocal EnableDelayedExpansion
 %MSG:?= Generating Border ...%
 Set "}2;!CNTRL!=%\E%[2;!CNTRL!H%\E%[33mControls:"
 Set "}3;!CNTRL!=%\E%[3;!CNTRL!H  ▲    - Up"
 Set "}4;!CNTRL!=%\E%[4;!CNTRL!H  ◄    - Left"
 Set "}5;!CNTRL!=%\E%[5;!CNTRL!H  ▼    - Down"
 Set "}6;!CNTRL!=%\E%[6;!CNTRL!H  ►    - Right"
 Set "}7;!CNTRL!=%\E%[7;!CNTRL!HSpace  - Pause"
 Set "}8;!CNTRL!=%\E%[8;!CNTRL!HEscape - Quit"
 mode %Cols%,%lines%
rem /* Y coordinate for each line of a sprite to be supplied during Def.Sprite Expansion */
 %MSG:?= Generating Sprites ...%
       %Def.Sprite:#=1%{player}{32}{ O }
   %Def.Sprite:#=!{y}!%{player}{32}{ ^^ }
        %Def.Sprite:#=3%{rocks}{90}{            @                             }
    %Def.Sprite:#=!{y}!%{rocks}{90}{            @                             }
    %Def.Sprite:#=!{y}!%{rocks}{90}{             #                         #@ }
    %Def.Sprite:#=!{y}!%{rocks}{90}{                                      @@  }
       %Def.Sprite:#=17%{rocks}{90}{                 @       @                }
    %Def.Sprite:#=!{y}!%{rocks}{90}{                @         @               }
    %Def.Sprite:#=!{y}!%{rocks}{90}{                #                         }
    %Def.Sprite:#=!{y}!%{rocks}{90}{                 @                        }
        %Def.Sprite:#=1%{river}{36}{                        .ll           }
        %Def.Sprite:#=2%{river}{36}{                          ^l.         }
    %Def.Sprite:#=!{y}!%{river}{36}{                           .l         }
    %Def.Sprite:#=!{y}!%{river}{36}{                             .l_      }
    %Def.Sprite:#=!{y}!%{river}{36}{                             r^)._    }
    %Def.Sprite:#=!{y}!%{river}{36}{                             .l`  ^). }
    %Def.Sprite:#=!{y}!%{river}{36}{                             l`     . }
    %Def.Sprite:#=!{y}!%{river}{36}{                           _l.        }
    %Def.Sprite:#=!{y}!%{river}{36}{                          .           }
    %Def.Sprite:#=9%{mountains}{37}{        x X   xXx }
%Def.Sprite:#=!{y}!%{mountains}{37}{       XxXx  Xx X }
%Def.Sprite:#=!{y}!%{mountains}{37}{      Xx  xXxxX  x}
     %Def.Sprite:#=8%{money}{33}{                                       $}
    %Def.Sprite:#=12%{money}{33}{                          $}
rem /* varname[index#] naming convention can be used to define multiple sprites of a given type - allowing for random selection from an array of sprites */
    %Def.Sprite:#=21%{enemy[1]}{31}{                                           /+\}
 %Def.Sprite:#=!{y}!%{enemy[1]}{31}{                                            + }
 %Def.Sprite:#=!{y}!%{enemy[1]}{31}{                                           \+/}
rem /* Show initial sprite positions */
rem /* Display order: Collectable;Background - Static or Collidable;Player;Foreground Collidable [enemys]*/
 TYPE %Foreground%
rem /* Define valid keys */
 %Def.Key%"-72=up" "-80=down" "-75=left" "-77=right" "27=escape" "32=space" "13=enter"
 %Def.Key%"48=0" "49=1" "50=2" "51=3" "52=4" "53=5" "54=6" "55=7" "56=8" "57=9"
 %MSG:?= Sprite Demo by T3RRY. Collect Both $ Coins%
 For %%G in (start)Do < Nul Set /P "=%\E%[10;!CNTRL!H%\E%[32mPlayer: %%G%\E%[0m   %\E%[11;!CNTRL!H    %\E%[31mAI: waiting%\E%[0m   "
:level[1]                /* DEMO of Sprite movement and Display only. Not intended as an Actual Game. */
rem /* input is taken and assessed within the loop ; all game actions repeat with each loop until a specified end condition is met */
rem /* clear previous key; catch new input */
  Set "Key="& %GetKey%
rem /* ::: ?Key# insert/remove substring modification ':mode=dev' for/after debugging. Dev mode allows testing of key inputs to identify errorcode values returned */
rem /* Expand ?Key# macro; test if captured errorlevel corresponds to a valid key */
rem /* Static Sprite Objects NOT collision tested should be refreshed each cycle PRIOR to movement */
rem /* Test move in the current Direction for declared SPRITE OBJect valid against list of collision characters; Call :End on Collision */
rem /* Previous sprite position overwritten with whitespace during Move.Sprite macro execution */
 For %%G in (!Dir!)Do < Nul Set /P "=%\E%[10;!CNTRL!H%\E%[32mPlayer: %%G%\E%[0m   %\E%[11;!CNTRL!H    %\E%[31mAI: !.%%G!%\E%[0m     "
 For %%M in (!Dir!)Do %Move.Sprite:obj=player%!%%M!{"#" "@" "x" "+" "/" "\"}{"$"}
::: Objective - Player must capture both $ coin to win.
::: Loss - player or AI experiences any collision
::: AI Captures any $ coin
 If "!captured!" == "1" Set /A "Playercoin+=1 + 0"
 If "!valid!" == "0" ( Set "Win=Lost" & set ".Win=Won" & %G.O%)
 If "!Playercoin!" == "2" (Set "Win=Won" & set ".Win=Lost" & %G.O%)
rem /* Simple AI sprite motion. AI moves in opposite direction to player */
 For %%. in (!Dir!)Do For %%M in (!.%%.!)Do %Move.Sprite:obj=enemy[1]%!%%M!{"#" "@" "x" "O" "M" "^^"}{"$"}
 If "!captured!" == "1" (Set "Win=Lost" & set ".Win=Won" & %G.O%)
 If "!valid!" == "0" (Set "Win=Lost" & set ".Win=Lost" & %G.O%)
 If /I "!Key!" == "escape" (
  <nul Set /P "=%\E%[!.End!;1H%\E%[?25h%\E%[0m"
  DEL "%Save.Dir%%~n0*.~tmp" 2> Nul
  Exit /B 0
::: Implement levels by using conditional tests that flag winning the current level jump to
::: a new label to define new sprites.
::: Before implementing a new level loop:
:::   - endlocal environment to remove previous sprites and renew Setlocal EnableDelayedExpansion
:::     prior to defining the next batch of sprites - MUST be done to remove }Y;X definitions used
:::     for collision testing.
Goto :level[1]
rem /* Display order: Background;Player;Collidable */
 TYPE %Foreground%
 %MSG:?= Game over%
 For %%G in ("Win")Do < Nul Set /P "=%\E%[10;!CNTRL!H%\E%[32mPlayer: !%%~G!%\E%[0m   %\E%[11;!CNTRL!H    %\E%[31mAI: !.%%~G!%\E%[0m   "
<nul Set /P "=%\E%[!.End!;1H%\E%[?25h%\E%[31m"
 DEL "%Save.Dir%%~n0*.~tmp" 2> Nul
 Timeout /T 2 /Nobreak > Nul
<nul Set /P "=%\E%[0m"
Exit /B 0

Post Reply