├── README.md ├── gfx ├── sprites.png ├── sprites.xpm2 ├── textures.png ├── textures.xpm2 └── xpm3toxpm2.sh ├── lib ├── 2d.gawk ├── draw.gawk └── xpm2.gawk ├── main.gawk ├── maps ├── jail.w3d ├── objects.w3d └── wolf.w3d └── screenshot01.jpg /README.md: -------------------------------------------------------------------------------- 1 | # First Person Shooter in gawk 2 | 3 | After seeing TheMozg's awkaster project I thought to myself (yet again) "I could make that better, right?". 4 | So during easter of 2020 I started programming and came up with this first result. 5 | 6 | ## Controls 7 | key | action 8 | --- | ------------------- 9 | **w**/**s** | forward/backward 10 | **a**/**d** | strafe left/right 11 | **j**/**l** | turn left/right 12 | **TAB** | move minimap 13 | **~** | toggle shading 14 | **ESC** | quit 15 | 16 | ## Showcase 17 | Here's a static image of the result: 18 | ![awk-fps image](/screenshot01.jpg) 19 | 20 | For a moving version see: 21 | * [first attempt](https://youtu.be/8AJ9Kx_XycE) 22 | * [sprite test](https://youtu.be/I6sLFo72dSo) 23 | 24 | -------------------------------------------------------------------------------- /gfx/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patsie75/awk-fps/782ff26eef63d9c80d380a8f8341e7663a5aea3c/gfx/sprites.png -------------------------------------------------------------------------------- /gfx/textures.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patsie75/awk-fps/782ff26eef63d9c80d380a8f8341e7663a5aea3c/gfx/textures.png -------------------------------------------------------------------------------- /gfx/xpm3toxpm2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | [ -w "$1" ] || { echo "Usage: $0 " >&2; exit 1; } 4 | 5 | # awk converts human readable colors back to #RRGGBB values 6 | # sed converts xpm3 format to xpm2 7 | awk 'BEGIN { 8 | # get list of color names and their srgb() values 9 | cmd = "convert -list color" 10 | while ((cmd | getline) > 0) 11 | color[$1] = $2 12 | close(cmd) 13 | } 14 | (($2 == "c") && (c=substr($3, 1, length($3)-2)) && (c in color)) { 15 | # color line and color is in the color[] array, extract srgb values 16 | match(color[c], /srgb\(([0-9]*),([0-9]*),([0-9]*)\)/, arr) 17 | 18 | printf("\"%-*s c #%02X%02X%02X\", # %s\n", 2, substr($1,2), arr[1], arr[2], arr[3], color[c] ) 19 | next 20 | } 1' "$1" | \ 21 | sed 's/^static char.*/! XPM2/;/^\/\*/d;s/^"//;s/",\?//;/^};/d' >"$(basename "$1" .xpm).xpm2" 22 | 23 | -------------------------------------------------------------------------------- /lib/2d.gawk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gawk -f 2 | 3 | @include "lib/draw.gawk" 4 | 5 | function abs(i) { return( (i<0) ? -i : i ) } 6 | function max(a,b) { return( (a>b) ? a : b ) } 7 | function min(a,b) { return( (a= abs(y1-y2)) { 43 | # horizontal line 44 | direction = 1 45 | a1=x1; a2=x2; b1=y1; b2=y2 46 | } else { 47 | # vertical line 48 | direction = 0 49 | a1=y1; a2=y2; b1=x1; b2=x2 50 | } 51 | 52 | # swap points if a1 > a2 53 | if (a1 > a2) { 54 | tmp=a1; a1=a2; a2=tmp 55 | tmp=b1; b1=b2; b2=tmp 56 | } 57 | 58 | # calculate slope/delta 59 | m = (a2-a1) ? (b2-b1) / (a2-a1) : 0 60 | 61 | j = b1 62 | # draw either a "horizontal" or "vertical" line 63 | for (i=a1; i<=a2; i++) { 64 | pixel(scr, direction ? i : j, direction ? j : i, col) 65 | j += m 66 | } 67 | } 68 | 69 | ## Draw a triangle (x1,y1), (x2,y2), (x3,y3) 70 | function triangle(src, x1,y1, x2,y2, x3,y3, col) { 71 | line(scr, x1,y1, x2,y2, col) 72 | line(scr, x2,y2, x3,y3, col) 73 | line(scr, x3,y3, x1,y1, col) 74 | } 75 | 76 | function fillTriangle(scr, x1,y1, x2,y2, x3,y3, col, type, i, d1,d2,d3, sx,ex) { 77 | if ((x1 < 0) && (x2 < 0) && (x3 < 0)) return 78 | if ((y1 < 0) && (y2 < 0) && (y3 < 0)) return 79 | if ((x1 > scr["width"]) && (x2 > scr["width"]) && (x3 > scr["width"])) return 80 | if ((y1 > scr["height"]) && (y2 > scr["height"]) && (y3 > scr["height"])) return 81 | 82 | # y1 < y2 < y3 83 | if (y2 < y1) { i=y1; y1=y2; y2=i; i=x1; x1=x2; x2=i } 84 | if (y3 < y2) { i=y2; y2=y3; y3=i; i=x2; x2=x3; x3=i } 85 | if (y2 < y1) { i=y1; y1=y2; y2=i; i=x1; x1=x2; x2=i } 86 | 87 | # get delta/slopes 88 | i = y2-y1; d1 = i ? (x2-x1) / i : 0 89 | i = y3-y2; d2 = i ? (x3-x2) / i : 0 90 | i = y1-y3; d3 = i ? (x1-x3) / i : 0 91 | 92 | # upper triangle 93 | for (i=y1; i x2) { 121 | tmp=x1; x1=x2; x2=tmp 122 | } 123 | if (y1 > y2) { 124 | tmp=y1; y1=y2; y2=tmp 125 | } 126 | 127 | for (i=x1; i<=x2; i++) { 128 | pixel(scr, i,y1, col) 129 | pixel(scr, i,y2, col) 130 | } 131 | for (i=y1+1; i x2) { 139 | tmp=x1; x1=x2; x2=tmp 140 | } 141 | if (y1 > y2) { 142 | tmp=y1; y1=y2; y2=tmp 143 | } 144 | 145 | for (i=y1; i<=y2; i++) 146 | hline(scr, x1,i, (x2-x1)+1, col) 147 | } 148 | -------------------------------------------------------------------------------- /lib/draw.gawk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gawk -f 2 | 3 | BEGIN { 4 | "tput cols" | getline terminal["width"] 5 | "tput lines" | getline terminal["height"] 6 | close("tput cols") 7 | close("tput lines") 8 | } 9 | 10 | ## initialize and clear canvas 11 | function init(scr, width, height) { 12 | 13 | ## autodetect width/height if not supplied 14 | if (!width) { 15 | if ("COLUMNS" in ENVIRON) width = ENVIRON["COLUMNS"] 16 | else { "tput cols" | getline width; close("tput cols") } 17 | } 18 | 19 | if (!height) { 20 | if (ENVIRON["LINES"]) height = (ENVIRON["LINES"] - 1) * 2 21 | else { "tput lines" | getline height; height = (height-1) * 2; close("tput lines") } 22 | } 23 | 24 | # fallback width/height if autodetect fails 25 | if (!width) width = 80 26 | if (!height) height = 48 27 | 28 | # two pixels per lines 29 | # height = (height-1) * 2 30 | 31 | scr["width"] = width 32 | scr["height"] = height 33 | 34 | clear(scr) 35 | } 36 | 37 | # turn cursor on or off 38 | function cursor(state) { 39 | if (state == "off") printf("\033[?25l") 40 | else if (state == "on") printf("\033[?25h") 41 | } 42 | 43 | ## clean the canvas (black) 44 | function clear(scr) { 45 | #fill(scr, color["black"]) 46 | fill(scr, colors["0"]["1"]) 47 | } 48 | 49 | ## fill the canvas with a color 50 | function fill(scr, col, i, size) { 51 | size = scr["height"] * scr["width"] 52 | for (i=0; i 0) { 106 | close("/proc/uptime") 107 | return($1) 108 | } else return(systime()) 109 | } 110 | 111 | # return number of frames in time interval 112 | function fps(f) { 113 | f["frame"]++ 114 | f["now"] = myTime() 115 | 116 | if (f["interval"] == 0) 117 | f["interval"] = 1 118 | 119 | if ( (f["now"] - f["prev"]) >= f["interval"] ) { 120 | f["fps"] = f["frame"] / (f["now"] - f["prev"]) 121 | f["prev"] = f["now"] 122 | f["frame"] = 0 123 | } 124 | 125 | return( f["fps"] ) 126 | } 127 | 128 | 129 | # copy graphic buffer to another graphic buffer (with transparency, and edge clipping) 130 | # usage: dst, src, [dstx, dsty, [srcx, srcy, [srcw, srch, [transparent] ] ] ] 131 | function copy(dst, src, dstx, dsty, srcx, srcy, srcw, srch, transp, dx,dy, dw,dh, sx,sy, sw,sh, x,y, w,h, t, pix, sw_mul_y, ydy_mul_dw, xdx) { 132 | # src/dst default values 133 | dw = dst["width"] 134 | dh = dst["height"] 135 | sw = src["width"] 136 | sh = src["height"] 137 | 138 | dx = int(src["x"]) 139 | dy = int(src["y"]) 140 | sx = 0 141 | sy = 0 142 | w = src["width"] 143 | h = src["height"] 144 | 145 | # arguments override 146 | if (length(dstx)) dx = dstx 147 | if (length(dsty)) dy = dsty 148 | if (length(srcx)) sx = srcx 149 | if (length(srcy)) sy = srcy 150 | if (length(srcw)) w = ((srcw > 0) && (srcw < src["width"])) ? srcw : w 151 | if (length(srch)) h = ((srch > 0) && (srch < src["height"])) ? srch : h 152 | 153 | # transparancy 154 | if (sprintf("%s", transp)) t = transp 155 | else if ("transparent" in src) t = src["transparent"] 156 | else if ("transparent" in glib) t = glib["transparent"] 157 | 158 | for (y=sy; y<(sy+h); y++) { 159 | # clip image off top/bottom 160 | if ((y - sy + dy) >= dh) break 161 | if ((y - sy + dh) < 0) continue 162 | sw_mul_y = sw * y 163 | ydy_mul_dw = (y - sy + dy) * dw 164 | 165 | for (x=sx; x<(sx+w); x++) { 166 | xdx = x - sx + dx 167 | 168 | # clip image on left/right 169 | if (xdx >= dw) break 170 | if (xdx < 0) continue 171 | 172 | # draw non-transparent pixel or else background 173 | pix = src[sw_mul_y + x] 174 | dst[ydy_mul_dw + xdx] = ((pix == t) || (pix == "None")) ? dst[ydy_mul_dw + xdx] : pix 175 | #if ((pix == t) || (pix == "None")) 176 | # dst[ydy_mul_dw + xdx] = dst[ydy_mul_dw + xdx] 177 | #else 178 | # dst[ydy_mul_dw + xdx] = pix 179 | } 180 | } 181 | } 182 | 183 | -------------------------------------------------------------------------------- /lib/xpm2.gawk: -------------------------------------------------------------------------------- 1 | #!/usr/bin/gawk -f 2 | 3 | BEGIN { 4 | hex = "0123456789ABCDEF" 5 | } 6 | 7 | function hex2dec(h, result, l) { 8 | result = 0 9 | l = length(h) 10 | 11 | for (i=1; i<=l; i++) { 12 | result *= 16 13 | result += index(hex, toupper(substr(h,i,1)) ) - 1 14 | } 15 | 16 | return(result) 17 | } 18 | 19 | 20 | function loadxpm2(dst, fname, w,h, nrcolors,charsppx, col,color,data, i,pix) { 21 | # read header "! XPM2" 22 | if ( ((getline < fname) < 1) || ($0 != "! XPM2") ) { close(fname); return(0); } 23 | 24 | # read picture meta info " " 25 | if ( ((getline < fname) < 1) || (NF != 4) ) { close(fname); return(0); } 26 | w = int($1) 27 | h = int($2) 28 | nrcolors = int($3) 29 | charsppx = int($4) 30 | 31 | # read colormap " c #" 32 | for (i=0; i 1) ? val : 1 13 | if (split(col, arr, ";") == 3) 14 | return sprintf("%d;%d;%d", min(255,arr[1]/val), min(255,arr[2]/val), min(255,arr[3]/val)) 15 | } 16 | return col 17 | } 18 | 19 | function floor(n, x) { x=int(n); return(x==n || n>0) ? x : x-1 } 20 | 21 | function miniMap(scr, map, posX,posY, offsetX, offsetY, x,y) { 22 | if (offsetX < 0) offsetX = scr["width"] + offsetX - 1 23 | if (offsetY < 0) offsetY = scr["height"] + offsetY - 1 24 | 25 | for (y=-5; y<=5; y++) { 26 | for (x=-5; x<=5; x++) { 27 | if ( (int(posX+x) > map["width"]) || (int(posX+x) < 0) || (int(posY+y) > map["height"]) || (int(posY+y) < 0) ) 28 | pixel(scr, offsetX+x, offsetY+y, COL_BLACK) 29 | else { 30 | c = map[int(posY+y)*map["width"]+int(posX+x)] 31 | pixel(scr, offsetX+x, offsetY+y, (c == " ") ? COL_BLACK : COL_GRAY) 32 | } 33 | } 34 | } 35 | pixel(scr, offsetX,offsetY, COL_LMAGENTA) 36 | } 37 | 38 | function input() { 39 | system("stty -echo") 40 | cmd = "saved=$(stty -g); stty raw; var=$(dd bs=1 count=1 2>/dev/null); stty \"$saved\"; echo \"$var\"" 41 | cmd | getline key 42 | close(cmd) 43 | system("stty echo") 44 | 45 | return(key) 46 | } 47 | 48 | function loadMap(map, object, fname, linenr, x,y, c, obj, str) { 49 | map["width"] = 0 50 | map["height"] = 0 51 | y = 0 52 | obj = 0 53 | 54 | while ((getline < fname) > 0) { 55 | linenr++ 56 | #printf("loadMap(): linenr: %d, line: \"%s\" (len: %d) NR == %d\n", linenr, $0, length($0), NF) 57 | 58 | # skip empty and comment lines 59 | if ((NF == 0) || ($1 ~ /^#/)) continue 60 | 61 | switch ($1) { 62 | case "map": 63 | match($0, /^ *map "([^"]+)" *$/, str) 64 | 65 | # check line length (map width) 66 | if (!map["width"]) map["width"] = length(str[1]) 67 | else if (map["width"] != length(str[1])) { 68 | printf("loadMap(): Error on line #%d, file \"%s\": invalid line length (%d != %d)\n", linenr, fname, length(str[1]), map["width"]) 69 | exit 1 70 | } 71 | 72 | for (x=0; x=0 && mapX=0 && mapY= scr["height"]) drawEnd = scr["height"] - 1 299 | 300 | 301 | ## 302 | ## start texture mapping 303 | ## 304 | 305 | # texture to draw 306 | texNum = worldMap[mapY*worldMap["width"]+mapX] 307 | 308 | # calculate value of wallX 309 | if (side == 0) wallX = posY + perpWallDist * rayDirY 310 | else wallX = posX + perpWallDist * rayDirX 311 | wallX -= floor(wallX) 312 | 313 | # x coordinate on the texture 314 | texX = int(wallX * texWidth) 315 | if (side == 0 && rayDirX > 0) texX = texWidth - texX - 1; 316 | if (side == 1 && rayDirY < 0) texX = texWidth - texX - 1; 317 | 318 | # How much to increase the texture coordinate per screen pixel 319 | step = 1.0 * texHeight / lineHeight 320 | # Starting texture coordinate 321 | texPos = (drawStart - scr["height"] / 2 + lineHeight / 2) * step 322 | 323 | for (y=drawStart; y<=drawEnd; y++) { 324 | # Cast the texture coordinate to integer, and mask with (texHeight - 1) in case of overflow 325 | texY = int(and(texPos, texHeight - 1)) 326 | texPos += step 327 | color = wallTex[texNum][texHeight * texY + texX] 328 | 329 | 330 | # make color darker for y-sides: R, G and B byte each divided through two with a "shift" and an "and" 331 | tmp = (perpWallDist > 1) ? perpWallDist : 1 332 | 333 | if (side == 1) color = darken(color, (tmp+2)/2) 334 | else color = darken(color, tmp/2) 335 | 336 | ## draw final pixel to buffer 337 | pixel(scr, x,y, color) 338 | } 339 | 340 | ZBuffer[x] = perpWallDist; 341 | } 342 | 343 | ## 344 | ## Sprites 345 | ## 346 | 347 | # calculate distance from player 348 | for (i in object) 349 | object[i]["dist"] = ( (posX - object[i]["x"]) * (posX - object[i]["x"]) + (posY - object[i]["y"]) * (posY - object[i]["y"]) ) 350 | 351 | # sort objects by distance from player (far -> near) 352 | asort(object, object, "sortDist") 353 | 354 | # loop through objects (far -> near) 355 | for (i in object) { 356 | #printf("object[%s][sprite] = [%s]\n", i, object[i]["sprite"]) 357 | spriteX = object[i]["x"] - posX 358 | spriteY = object[i]["y"] - posY 359 | 360 | invDet = 1.0 / (planeX * dirY - dirX * planeY); # required for correct matrix multiplication 361 | 362 | transformX = invDet * (dirY * spriteX - dirX * spriteY); 363 | transformY = invDet * (-planeY * spriteX + planeX * spriteY); # this is actually the depth inside the screen, that what Z is in 3D 364 | 365 | spriteScreenX = int((scr["width"] / 2) * (1 + transformX / transformY)); 366 | 367 | # calculate height of the sprite on screen 368 | spriteHeight = abs(int(scr["height"] / transformY)); # using 'transformY' instead of the real distance prevents fisheye 369 | # calculate lowest and highest pixel to fill in current stripe 370 | drawStartY = (-spriteHeight / 2) + (scr["height"] / 2) 371 | if (drawStartY < 0) drawStartY = 0 372 | drawEndY = (spriteHeight / 2) + (scr["height"] / 2) - 1 373 | if (drawEndY > scr["height"]) drawEndY = scr["height"] 374 | 375 | # calculate width of the sprite 376 | spriteWidth = abs( int(scr["height"] / transformY)) 377 | drawStartX = int( (-spriteWidth / 2) + spriteScreenX) 378 | if (drawStartX < 0) drawStartX = 0 379 | drawEndX = (spriteWidth / 2) + spriteScreenX 380 | if (drawEndX > scr["width"]) drawEndX = scr["width"] 381 | 382 | 383 | # loop through every vertical stripe of the sprite on screen 384 | for (stripe = drawStartX; stripe < drawEndX; stripe++) { 385 | #texX = int(256 * (stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth / spriteWidth) / 256; 386 | texX = int((stripe - (-spriteWidth / 2 + spriteScreenX)) * texWidth / spriteWidth) 387 | # the conditions in the if are: 388 | # 1) it's in front of camera plane so you don't see things behind you 389 | # 2) it's on the screen (left) 390 | # 3) it's on the screen (right) 391 | # 4) ZBuffer, with perpendicular distance 392 | #if (object[i]["sprite"] == 3) printf("transformY == %s, stripe == %s, ZBuffer == %s, width == %s\n", transformY, stripe, ZBuffer[stripe], scr["width"]) 393 | if (transformY > 0 && stripe > 0 && stripe < scr["width"] && transformY < ZBuffer[stripe]) { 394 | for (y = drawStartY; y < drawEndY; y++) # for every pixel of the current stripe 395 | { 396 | d = y * 256 - scr["height"] * 128 + spriteHeight * 128; # 256 and 128 factors to avoid floats 397 | texY = ((d * texHeight) / spriteHeight) / 256 + 1; 398 | 399 | c = sprite[object[i]["sprite"]][int(texY) * texWidth + int(texX)]; # get current color from the texture 400 | if (c != sprite[object[i]["sprite"]]["transparent"]) { 401 | tmp = (object[i]["dist"] > 1) ? object[i]["dist"] : 1 402 | c = darken(c, tmp/5) 403 | 404 | pixel(scr, stripe, y, c) 405 | } 406 | } 407 | } 408 | } 409 | 410 | } 411 | 412 | # layer minimap on top of screenbuffer 413 | miniMap(scr, worldMap, posX, posY, mmPosX, mmPosY) 414 | 415 | # draw screenbuffer to terminal 416 | draw(scr, -1,1) 417 | 418 | ## handle user input 419 | key = input() 420 | 421 | # quit key exits game 422 | if (key == KEY_QUIT) { 423 | cursor("on") 424 | exit 0 425 | } 426 | 427 | # rotate left 428 | if (key == KEY_ROTL) { 429 | oldDirX = dirX; 430 | dirX = dirX * cos(rotSpeed) - dirY * sin(rotSpeed); 431 | dirY = oldDirX * sin(rotSpeed) + dirY * cos(rotSpeed); 432 | 433 | oldPlaneX = planeX; 434 | planeX = planeX * cos(rotSpeed) - planeY * sin(rotSpeed); 435 | planeY = oldPlaneX * sin(rotSpeed) + planeY * cos(rotSpeed); 436 | } 437 | 438 | # rotate left fast 439 | if (key == KEY_ROTLF) { 440 | oldDirX = dirX 441 | dirX = dirX * cos(rotSpeed*2) - dirY * sin(rotSpeed*2) 442 | dirY = oldDirX * sin(rotSpeed*2) + dirY * cos(rotSpeed*2) 443 | 444 | oldPlaneX = planeX 445 | planeX = planeX * cos(rotSpeed*2) - planeY * sin(rotSpeed*2) 446 | planeY = oldPlaneX * sin(rotSpeed*2) + planeY * cos(rotSpeed*2) 447 | } 448 | 449 | # rotate right 450 | if (key == KEY_ROTR) { 451 | oldDirX = dirX 452 | dirX = dirX * cos(-rotSpeed) - dirY * sin(-rotSpeed) 453 | dirY = oldDirX * sin(-rotSpeed) + dirY * cos(-rotSpeed) 454 | 455 | oldPlaneX = planeX 456 | planeX = planeX * cos(-rotSpeed) - planeY * sin(-rotSpeed) 457 | planeY = oldPlaneX * sin(-rotSpeed) + planeY * cos(-rotSpeed) 458 | } 459 | 460 | # rotate right fast 461 | if (key == KEY_ROTRF) { 462 | oldDirX = dirX 463 | dirX = dirX * cos(-rotSpeed*2) - dirY * sin(-rotSpeed*2) 464 | dirY = oldDirX * sin(-rotSpeed*2) + dirY * cos(-rotSpeed*2) 465 | 466 | oldPlaneX = planeX 467 | planeX = planeX * cos(-rotSpeed*2) - planeY * sin(-rotSpeed*2) 468 | planeY = oldPlaneX * sin(-rotSpeed*2) + planeY * cos(-rotSpeed*2) 469 | } 470 | 471 | # move forward 472 | if (key == KEY_MOVF) { 473 | newPosX = posX + dirX * moveSpeed 474 | newPosY = posY + dirY * moveSpeed 475 | } 476 | 477 | # move back 478 | if (key == KEY_MOVB) { 479 | newPosX = posX - dirX * moveSpeed 480 | newPosY = posY - dirY * moveSpeed 481 | } 482 | 483 | # move left (strafe) 484 | if (key == KEY_MOVL) { 485 | newPosX = posX - dirY * moveSpeed 486 | newPosY = posY + dirX * moveSpeed 487 | } 488 | 489 | # move right (strafe) 490 | if (key == KEY_MOVR) { 491 | newPosX = posX + dirY * moveSpeed 492 | newPosY = posY - dirX * moveSpeed 493 | } 494 | 495 | # minimap location 496 | if (key == KEY_MMAP) { 497 | switch (mmPosX "," mmPosY) { 498 | case "7,7": mmPosX = -7; mmPosY = 7; break 499 | case "-7,7": mmPosX = -7; mmPosY = -7; break 500 | case "-7,-7": mmPosX = 7; mmPosY = -7; break 501 | default: mmPosX = 7; mmPosY = 7 502 | } 503 | } 504 | if (key == KEY_SHADE) { 505 | cfg["shade"] = cfg["shade"] ? 0 : 1 506 | } 507 | 508 | # TODO colision detection 509 | #if (worldMap[int(posY * worldMap["width"] + newPosX)] == " ") posX = newPosX 510 | #if (worldMap[int(newPosY * worldMap["width"] + PosX)] == " ") posY = newPosY 511 | if ( (int(newPosX) > 0) && (int(newPosX) < worldMap["width"]-1) ) 512 | posX = newPosX 513 | if ( (int(newPosY) > 0) && (int(newPosY) < worldMap["height"]-1) ) 514 | posY = newPosY 515 | } 516 | } 517 | -------------------------------------------------------------------------------- /maps/jail.w3d: -------------------------------------------------------------------------------- 1 | hh hh 2 | h h 3 | h h 4 | h h 5 | h h 6 | h h 7 | h h 8 | h h 9 | h h 10 | h h 11 | h h 12 | hhhhhhh hhhhhhh 13 | hhhhhhhh hhhhhhhh 14 | hh h h hh 15 | hh hh 16 | hh h h hh 17 | hh h h hh 18 | hhhhhhh hhhhhhh 19 | hh h h hh 20 | hh s a hh 21 | hh h h hh 22 | hhhhhhh hhhhhhh 23 | hh hh 24 | hh hh 25 | hh hh 26 | hhhhhhhhhhhhhhhhh 27 | -------------------------------------------------------------------------------- /maps/objects.w3d: -------------------------------------------------------------------------------- 1 | map "aaaaaaaaaaaaaaaaaaaaaa" 2 | map "as a" 3 | map "a a" 4 | map "a a" 5 | map "a a" 6 | map "a a" 7 | map "a a" 8 | map "a a" 9 | map "a a" 10 | map "a a" 11 | map "aaaaaaaaaaaaaaaaaaaaaa" 12 | 13 | obj 2 1 1 14 | obj 4 1 2 15 | obj 6 1 3 16 | obj 8 1 4 17 | obj 10 1 5 18 | obj 12 1 6 19 | obj 14 1 7 20 | obj 16 1 8 21 | obj 18 1 9 22 | obj 20 1 10 23 | 24 | 25 | obj 2 3 11 26 | obj 4 3 12 27 | obj 6 3 13 28 | obj 8 3 14 29 | obj 10 3 15 30 | obj 12 3 16 31 | obj 14 3 17 32 | obj 16 3 18 33 | obj 18 3 19 34 | obj 20 3 20 35 | 36 | obj 2 5 21 37 | obj 4 5 22 38 | obj 6 5 23 39 | obj 8 5 24 40 | obj 10 5 25 41 | obj 12 5 26 42 | obj 14 5 27 43 | obj 16 5 28 44 | obj 18 5 29 45 | obj 20 5 30 46 | 47 | obj 2 7 31 48 | obj 4 7 32 49 | obj 6 7 33 50 | obj 8 7 34 51 | obj 10 7 35 52 | obj 12 7 36 53 | obj 14 7 37 54 | obj 16 7 38 55 | obj 18 7 39 56 | obj 20 7 40 57 | 58 | obj 2 9 41 59 | obj 4 9 42 60 | obj 6 9 43 61 | obj 8 9 44 62 | obj 10 9 45 63 | obj 12 9 46 64 | obj 14 9 47 65 | obj 16 9 48 66 | obj 18 9 49 67 | obj 20 9 50 68 | 69 | -------------------------------------------------------------------------------- /maps/wolf.w3d: -------------------------------------------------------------------------------- 1 | # test map 2 | map "abababa hihihih" 3 | map "b z e g" 4 | map "a s zxxiih h" 5 | map "b B O i" 6 | map "a zx ih h" 7 | map "b z g e" 8 | map "azz zzz hih hih" 9 | map " x x i i " 10 | map " x i " 11 | map " l q " 12 | map " l l q q " 13 | map "lll lll qqq qqq" 14 | map "l l q q" 15 | map "l ll qq r" 16 | map "k j L q" 17 | map "l lllqqq r" 18 | map "l l q q" 19 | map "lllklll qqtqtqq" 20 | 21 | # obj 22 | obj 5 1 3 23 | obj 8 8 9 24 | obj 9 8 10 25 | obj 8 9 10 26 | obj 9 9 9 27 | -------------------------------------------------------------------------------- /screenshot01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/patsie75/awk-fps/782ff26eef63d9c80d380a8f8341e7663a5aea3c/screenshot01.jpg --------------------------------------------------------------------------------