Pull to refresh

Comments 15

программируем, как будто сейчас 1992 год

Осталось запустить этот код на Intel 286 с полумегабайтом памяти.

в Rust под DOS? ?

Xотя на Rust делают Forth (Форт) для запуска в рамках контроллеров для встроенного оборудования, а это где то уже близко DOS использованию.

P.S. Немногие современные инструменты программирования ещё поддерживают возможность создания программ для DOS.
Один из таких инструментов FPC (Free Pascal Compiller)

1992г уже «эра» 386-х, 486-х ПК.

Не сделана коррекция fish eye, что довольно заметно даже на таких небольших участках стен. В black book на это несколько страниц было потрачено

Ну так они и делали все в спешке, судя по статье.

Rustenstein 3D: программируем, как будто сейчас 1992 год

Используем язык высокого уровня

А потом появляется люди, которые не понимают, как раньше так долго делали простенькие по нынешным меркам игры

Если вспомнить, какой интерес вызывал геймплей тех игр и нынешних, то не очень понятно, как можно так долго делать простенькие нынешние игры....

И при этом выпускать киберпанк

Ожидание: полноценная (почти полноценная) реализация Wold3D на RUST, с азартными играми и женщинами с пониженной социальной ответственностью.
Реальность: мы смогли реализовать raycasting на RUST и «благодаря нескольким хакам и куче уродливого кода нам удалось» хоть что-то показать людям.
Программист на QBASIC, скептически хмыкает, стряхивает пыль с тридцатилетней IDE и пишет свой raycasting полностью на Qbasic

Source code re-write from video by Bernhard Slawik 2020-10-01
' Shown by Carl Mahnke, but now offline
' www.youtube.com/watch?v=3Qpht8dSps8
' rws.sebus.de/misc/raycast.rar
' Re-write by Bernhard Slawik 2020-10-01

' But there is stuill a bug in normaly% i think…
' See "***"

DEF SEG = 0
pl.x = 66: pl.xtmp = 66
pl.y = 220: pl.ytmp = 220
pl.ld = 5
angf% = 1440
angtol% = 20
cols% = 320
colstep% = 1 ' Set to >1 to decrease horizontal resolution
notexture% = 0 ' Set to 1 for fast no-texture mode
colsh% = cols% / 2
DIM map(15, 15) AS INTEGER
DIM costable#(angf% — 1)
DIM sintable#(angf% — 1)
pi# = 3.14159265#
DIM buffer%(63, 448)

angh% = angf% / 2
angq% = angf% / 4
angtq% = 3 * angf% / 4

' Pre-calc sine table
PRINT «Calculating sine table...»
FOR x = 0 TO angf% — 1
PRINT (x):
y# = x / (angf% — 1)
costable#(x) = COS(y# * pi# * 2)
sintable#(x) = SIN(y# * pi# * 2)
NEXT x

' Read map data
FOR y = 0 TO 15
FOR x = 0 TO 15
READ map(x, y)
NEXT x
NEXT y

' graphic stuff
SCREEN 13

PRINT «Loading textures...»
'GOTO fake ' Do not load texture, use pattern

' Read from BMP file
OPEN «MAH_TEX2.BMP» FOR BINARY AS #1
'SEEK #1, 1079
SEEK #1, 55 + (4 * 256) + (64 * 32)
FOR y% = 447 TO 0 STEP -1
FOR x% = 0 TO 63
c% = ASC(INPUT$(1, #1))
buffer%(x%, y%) = c%
NEXT x%
NEXT y%

SEEK #1, 55
FOR x% = 0 TO 255
b% = ASC(INPUT$(1, #1)) \ 4
g% = ASC(INPUT$(1, #1)) \ 4
r% = ASC(INPUT$(1, #1)) \ 4
q% = ASC(INPUT$(1, #1))
PALETTE x%, r% + g% * 256 + b% * 256 ^ 2
NEXT x%
CLOSE #1
GOTO main


fake: ' Create procedural textures
PRINT «Generating textures...»
FOR y% = 447 TO 0 STEP -1
FOR x% = 0 TO 63
c = (x% * y%) MOD 256 ' Random
buffer%(x%, y%) = c
NEXT x%
NEXT y%


main:
' Main loop
DO
lookdir% = pl.ld
FOR ray% = 0 TO cols% STEP colstep%
pl.ld = ((lookdir% + angf% — colsh%) + ray%) MOD angf%

' horizontal detection
dis1% = -1
IF pl.ld MOD angh% > angtol% AND pl.ld MOD angh% < (angh% — angtol%) THEN
dir% = (ABS(pl.ld — angh%) / (pl.ld — angh%)) * -1
pl.xb = pl.x \ 64
pl.yb = pl.y \ 64
rest% = ABS(((pl.y MOD 64) + (64 * (dir% * -1)) + ((1 + dir%) / 2)) MOD 64)
shortx% = rest% * costable#(pl.ld) / sintable#(pl.ld) * dir%
actdef% = shortx%
nblockx% = (shortx% + pl.x) \ 64
nblocky% = pl.yb + dir%
IF nblockx% > -1 AND nblockx% < 16 THEN
'dir1% = ABS(rest% / sintable#(pl.ld))
dis1% = ABS(rest% / sintable#(pl.ld))
fblock% = map(nblockx%, nblocky%)
IF fblock% = 0 THEN
count% = 1
dis1% = -1
normalx% = 64 * (costable#(pl.ld) / sintable#(pl.ld)) * dir%
'normalx% = 64 * costable#(pl.ld) / sintable#(pl.ld) * dir%
'normalx% = 64 / costable#(pl.ld) * sintable#(pl.ld) * dir%
DO
actdef% = shortx% + (count% * normalx%)
nblockx% = (actdef% + pl.x) \ 64
nblocky% = pl.yb + (dir% * (count% + 1))
'IF nblockx% < 16 AND nblockx% > -1 THEN fblock% = map(nblockx%, nblocky%)
IF nblockx% > -1 AND nblockx% < 16 AND nblocky% > -1 AND nblocky% < 16 THEN fblock% = map(nblockx%, nblocky%)
IF fblock% > 0 THEN dis1% = ABS(rest% / sintable#(pl.ld) + (64 / sintable#(pl.ld) * count%)): count% = 11
count% = count% + 1
LOOP UNTIL count% > 10
END IF
END IF
IF dis1% <> -1 THEN dis1% = dis1% * costable#(ABS(ray% — colsh%))
texoffh% = ABS((pl.x + actdef%) MOD 64)
tex1% = fblock%
END IF

' vertical detection
dis2% = -1
IF ((pl.ld + angq%) MOD angh% > angtol%) AND ((pl.ld + angq%) MOD angh% < (angh% — angtol%)) THEN
dir% = (ABS((pl.ld MOD angtq%) — angq%) / ((pl.ld MOD angtq%) — angq%)) * -1
pl.xb = pl.x \ 64
pl.yb = pl.y \ 64
rest% = ABS(((pl.x MOD 64) + (64 * (dir% * -1)) + ((1 + dir%) / 2)) MOD 64)
'shorty% = rest% * costable#(pl.ld) / sintable#(pl.ld) * dir%
shorty% = rest% / costable#(pl.ld) * sintable#(pl.ld) * dir%
actdef% = shorty%
nblocky% = (shorty% + pl.y) \ 64
nblockx% = pl.xb + dir%
IF nblocky% > -1 AND nblocky% < 16 THEN
dis2% = ABS(rest% / costable#(pl.ld))
's# = sintable#(pl.ld)
'' IF ABS(s#) < .01 THEN s# = .01 * SGN(s#)
'IF s# >= 0# AND s# < .0001 THEN s# = .0001
'ELSE IF s# < 0# AND s# > -.0001 THEN s# = -.0001
'dis2% = ABS(rest% / s#)

fblock% = map(nblockx%, nblocky%)
IF fblock% = 0 THEN
count% = 1
dis2% = -1
normaly% = 64 / costable#(pl.ld) * sintable#(pl.ld) * dir%
DO
actdef% = shorty% + (count% * normaly%)
nblocky% = (actdef% + pl.y) \ 64
nblockx% = pl.xb + (dir% * (count% + 1))
IF nblocky% < 16 AND nblocky% > -1 THEN fblock% = map(nblockx%, nblocky%)
IF fblock% > 0 THEN dis2% = ABS(rest% / costable#(pl.ld) + (64 / costable#(pl.ld) * count%)): count% = 11
count% = count% + 1
LOOP UNTIL count% > 10
END IF
END IF
IF dis2% <> -1 THEN dis2% = dis2% * costable#(ABS(ray% — colsh%))
texoffv% = ABS((pl.y + actdef%) MOD 64)
tex2% = fblock%
END IF

vertical = 0
IF dis2% <> -1 AND dis1% = -1 THEN dis1% = dis2%: vertical = 1
IF dis2% <> -1 AND dis1% <> -1 AND dis2% < dis1% THEN dis1% = dis2%: vertical = 1
IF dis1% = -1 THEN dis1% = 0
IF vertical = 1 THEN texoffh% = texoffv%: tex1% = tex2%

IF dis1% <> 0 THEN lineh% = 200 * (65 / dis1%)
scaler# = lineh% / 64

IF tex1% <> 0 THEN
linehh% = lineh% / 2
' Draw simple color
IF notexture% > 0 THEN LINE (ray%, 100 — linehh%)-(ray%, 100 + linehh%), tex1%: GOTO skiptexture

' Draw texture
FOR pixel% = 0 TO 63
col% = buffer%(texoffh%, pixel% + ((tex1% — 1) * 64))
IF scaler# > 1 THEN
LINE (ray%, 100 — linehh% + pixel% * scaler#)-(ray%, 100 — linehh% + (pixel% + 1) * scaler#), col%
ELSE 'IF scaler# <= 1 THEN
PSET (ray%, 100 — linehh% + pixel% * scaler#), col%
END IF
NEXT pixel%
skiptexture:
END IF

IF lineh% < 200 AND lineh% > 0 THEN
LINE (ray%, 100 — linehh%)-(ray%, 0), 1 ' Sky
LINE (ray%, 100 + linehh%)-(ray%, 200), 17 ' Floor
END IF
NEXT ray%

pl.ld = lookdir%

' Keyboard

'POKE &H41A, PEEK(&H41C)
'k% = INP(&H60)
k$ = INKEY$
'LOCATE 1, 1: PRINT k$
'IF k% = 30 THEN pl.ld = pl.ld — 20
'IF k% = 32 THEN pl.ld = pl.ld + 20
IF k$ = CHR$(0) + «M» THEN pl.ld = pl.ld + 20
IF k$ = CHR$(0) + «K» THEN pl.ld = pl.ld — 20

walkdir% = (pl.ld + angq%) MOD angf%
'speed# = speed# / 2
speed# = 0
'IF k% = 17 THEN speed# = 10
'IF k% = 31 THEN speed# = -10
IF k$ = CHR$(0) + «H» THEN speed# = 10
IF k$ = CHR$(0) + «P» THEN speed# = -10

pl.ytmp = (pl.ytmp — speed# * costable#(walkdir%))
pl.xtmp = (pl.xtmp + speed# * sintable#(walkdir%))
pl.y = INT(pl.ytmp)
pl.x = INT(pl.xtmp)

pl.ld = ABS((pl.ld + angf%) MOD angf%)
LOOP UNTIL k$ = CHR$(27) 'k% = 16


' Insert Map
DATA 7,2,1,2,1,1,1,2,1,1,1,1,1,1,1,1
DATA 7,0,0,0,2,2,2,2,2,6,0,0,0,0,0,3
DATA 7,0,0,0,0,5,0,0,3,6,0,0,0,0,0,3
DATA 7,0,0,0,0,0,0,0,3,6,0,3,0,3,0,3
DATA 7,0,0,0,0,5,0,0,3,6,0,0,0,0,0,3
DATA 7,2,2,2,2,3,0,0,3,6,0,0,0,0,0,3
DATA 1,4,1,1,1,1,7,0,7,6,0,0,0,0,7,3
DATA 3,4,7,0,0,0,7,0,7,6,0,0,0,0,0,3
DATA 3,0,3,5,0,5,7,0,7,7,0,0,0,0,0,3
DATA 3,0,0,5,0,0,0,0,0,0,0,0,0,0,0,3
DATA 3,0,0,5,5,5,5,1,5,7,0,0,0,0,0,3
DATA 5,0,5,5,2,2,2,2,2,6,0,0,0,0,0,3
DATA 5,0,0,0,7,0,0,0,0,0,0,3,0,3,0,3
DATA 5,0,0,0,0,0,0,0,0,6,0,0,0,0,0,3
DATA 5,0,0,0,7,0,0,0,0,6,0,0,0,0,0,3
DATA 5,5,5,5,2,2,2,2,2,1,1,1,1,1,1,6

download source textures упорно требует логин и пароль

Сайт ушел в даун, не оплата хостинга и т.д.
Но в комментах к видео, один добрый самаритянин Bernhard Slawik год назад, расшифровал листинг показанный в видео. Таким образом утерян только файл текстур (обычный BMP файл).
Bernhard Slawik 1 год назад
Since the file is offline, I re-constructed the code from the video here: pastebin.com/64MYbJjY

Ниже под катом исходник raycaster'а
Source code re-write from video by Bernhard Slawik 2020-10-01
' Shown by Carl Mahnke, but now offline
' www.youtube.com/watch?v=3Qpht8dSps8
' rws.sebus.de/misc/raycast.rar
' Re-write by Bernhard Slawik 2020-10-01

' But there is stuill a bug in normaly% i think…
' See "***"

DEF SEG = 0
pl.x = 66: pl.xtmp = 66
pl.y = 220: pl.ytmp = 220
pl.ld = 5
angf% = 1440
angtol% = 20
cols% = 320
colstep% = 1 ' Set to >1 to decrease horizontal resolution
notexture% = 0 ' Set to 1 for fast no-texture mode
colsh% = cols% / 2
DIM map(15, 15) AS INTEGER
DIM costable#(angf% — 1)
DIM sintable#(angf% — 1)
pi# = 3.14159265#
DIM buffer%(63, 448)

angh% = angf% / 2
angq% = angf% / 4
angtq% = 3 * angf% / 4

' Pre-calc sine table
PRINT «Calculating sine table...»
FOR x = 0 TO angf% — 1
PRINT (x):
y# = x / (angf% — 1)
costable#(x) = COS(y# * pi# * 2)
sintable#(x) = SIN(y# * pi# * 2)
NEXT x

' Read map data
FOR y = 0 TO 15
FOR x = 0 TO 15
READ map(x, y)
NEXT x
NEXT y

' graphic stuff
SCREEN 13

PRINT «Loading textures...»
'GOTO fake ' Do not load texture, use pattern

' Read from BMP file
OPEN «MAH_TEX2.BMP» FOR BINARY AS #1
'SEEK #1, 1079
SEEK #1, 55 + (4 * 256) + (64 * 32)
FOR y% = 447 TO 0 STEP -1
FOR x% = 0 TO 63
c% = ASC(INPUT$(1, #1))
buffer%(x%, y%) = c%
NEXT x%
NEXT y%

SEEK #1, 55
FOR x% = 0 TO 255
b% = ASC(INPUT$(1, #1)) \ 4
g% = ASC(INPUT$(1, #1)) \ 4
r% = ASC(INPUT$(1, #1)) \ 4
q% = ASC(INPUT$(1, #1))
PALETTE x%, r% + g% * 256 + b% * 256 ^ 2
NEXT x%
CLOSE #1
GOTO main

fake: ' Create procedural textures
PRINT «Generating textures...»
FOR y% = 447 TO 0 STEP -1
FOR x% = 0 TO 63
c = (x% * y%) MOD 256 ' Random
buffer%(x%, y%) = c
NEXT x%
NEXT y%

main:
' Main loop
DO
lookdir% = pl.ld
FOR ray% = 0 TO cols% STEP colstep%
pl.ld = ((lookdir% + angf% — colsh%) + ray%) MOD angf%

' horizontal detection
dis1% = -1
IF pl.ld MOD angh% > angtol% AND pl.ld MOD angh% < (angh% — angtol%) THEN
dir% = (ABS(pl.ld — angh%) / (pl.ld — angh%)) * -1
pl.xb = pl.x \ 64
pl.yb = pl.y \ 64
rest% = ABS(((pl.y MOD 64) + (64 * (dir% * -1)) + ((1 + dir%) / 2)) MOD 64)
shortx% = rest% * costable#(pl.ld) / sintable#(pl.ld) * dir%
actdef% = shortx%
nblockx% = (shortx% + pl.x) \ 64
nblocky% = pl.yb + dir%
IF nblockx% > -1 AND nblockx% < 16 THEN
'dir1% = ABS(rest% / sintable#(pl.ld))
dis1% = ABS(rest% / sintable#(pl.ld))
fblock% = map(nblockx%, nblocky%)
IF fblock% = 0 THEN
count% = 1
dis1% = -1
normalx% = 64 * (costable#(pl.ld) / sintable#(pl.ld)) * dir%
'normalx% = 64 * costable#(pl.ld) / sintable#(pl.ld) * dir%
'normalx% = 64 / costable#(pl.ld) * sintable#(pl.ld) * dir%
DO
actdef% = shortx% + (count% * normalx%)
nblockx% = (actdef% + pl.x) \ 64
nblocky% = pl.yb + (dir% * (count% + 1))
'IF nblockx% < 16 AND nblockx% > -1 THEN fblock% = map(nblockx%, nblocky%)
IF nblockx% > -1 AND nblockx% < 16 AND nblocky% > -1 AND nblocky% < 16 THEN fblock% = map(nblockx%, nblocky%)
IF fblock% > 0 THEN dis1% = ABS(rest% / sintable#(pl.ld) + (64 / sintable#(pl.ld) * count%)): count% = 11
count% = count% + 1
LOOP UNTIL count% > 10
END IF
END IF
IF dis1% <> -1 THEN dis1% = dis1% * costable#(ABS(ray% — colsh%))
texoffh% = ABS((pl.x + actdef%) MOD 64)
tex1% = fblock%
END IF

' vertical detection
dis2% = -1
IF ((pl.ld + angq%) MOD angh% > angtol%) AND ((pl.ld + angq%) MOD angh% < (angh% — angtol%)) THEN
dir% = (ABS((pl.ld MOD angtq%) — angq%) / ((pl.ld MOD angtq%) — angq%)) * -1
pl.xb = pl.x \ 64
pl.yb = pl.y \ 64
rest% = ABS(((pl.x MOD 64) + (64 * (dir% * -1)) + ((1 + dir%) / 2)) MOD 64)
'shorty% = rest% * costable#(pl.ld) / sintable#(pl.ld) * dir%
shorty% = rest% / costable#(pl.ld) * sintable#(pl.ld) * dir%
actdef% = shorty%
nblocky% = (shorty% + pl.y) \ 64
nblockx% = pl.xb + dir%
IF nblocky% > -1 AND nblocky% < 16 THEN
dis2% = ABS(rest% / costable#(pl.ld))
's# = sintable#(pl.ld)
'' IF ABS(s#) < .01 THEN s# = .01 * SGN(s#)
'IF s# >= 0# AND s# < .0001 THEN s# = .0001
'ELSE IF s# < 0# AND s# > -.0001 THEN s# = -.0001
'dis2% = ABS(rest% / s#)

fblock% = map(nblockx%, nblocky%)
IF fblock% = 0 THEN
count% = 1
dis2% = -1
normaly% = 64 / costable#(pl.ld) * sintable#(pl.ld) * dir%
DO
actdef% = shorty% + (count% * normaly%)
nblocky% = (actdef% + pl.y) \ 64
nblockx% = pl.xb + (dir% * (count% + 1))
IF nblocky% < 16 AND nblocky% > -1 THEN fblock% = map(nblockx%, nblocky%)
IF fblock% > 0 THEN dis2% = ABS(rest% / costable#(pl.ld) + (64 / costable#(pl.ld) * count%)): count% = 11
count% = count% + 1
LOOP UNTIL count% > 10
END IF
END IF
IF dis2% <> -1 THEN dis2% = dis2% * costable#(ABS(ray% — colsh%))
texoffv% = ABS((pl.y + actdef%) MOD 64)
tex2% = fblock%
END IF

vertical = 0
IF dis2% <> -1 AND dis1% = -1 THEN dis1% = dis2%: vertical = 1
IF dis2% <> -1 AND dis1% <> -1 AND dis2% < dis1% THEN dis1% = dis2%: vertical = 1
IF dis1% = -1 THEN dis1% = 0
IF vertical = 1 THEN texoffh% = texoffv%: tex1% = tex2%

IF dis1% <> 0 THEN lineh% = 200 * (65 / dis1%)
scaler# = lineh% / 64

IF tex1% <> 0 THEN
linehh% = lineh% / 2
' Draw simple color
IF notexture% > 0 THEN LINE (ray%, 100 — linehh%)-(ray%, 100 + linehh%), tex1%: GOTO skiptexture

' Draw texture
FOR pixel% = 0 TO 63
col% = buffer%(texoffh%, pixel% + ((tex1% — 1) * 64))
IF scaler# > 1 THEN
LINE (ray%, 100 — linehh% + pixel% * scaler#)-(ray%, 100 — linehh% + (pixel% + 1) * scaler#), col%
ELSE 'IF scaler# <= 1 THEN
PSET (ray%, 100 — linehh% + pixel% * scaler#), col%
END IF
NEXT pixel%
skiptexture:
END IF

IF lineh% < 200 AND lineh% > 0 THEN
LINE (ray%, 100 — linehh%)-(ray%, 0), 1 ' Sky
LINE (ray%, 100 + linehh%)-(ray%, 200), 17 ' Floor
END IF
NEXT ray%

pl.ld = lookdir%

' Keyboard

'POKE &H41A, PEEK(&H41C)
'k% = INP(&H60)
k$ = INKEY$
'LOCATE 1, 1: PRINT k$
'IF k% = 30 THEN pl.ld = pl.ld — 20
'IF k% = 32 THEN pl.ld = pl.ld + 20
IF k$ = CHR$(0) + «M» THEN pl.ld = pl.ld + 20
IF k$ = CHR$(0) + «K» THEN pl.ld = pl.ld — 20

walkdir% = (pl.ld + angq%) MOD angf%
'speed# = speed# / 2
speed# = 0
'IF k% = 17 THEN speed# = 10
'IF k% = 31 THEN speed# = -10
IF k$ = CHR$(0) + «H» THEN speed# = 10
IF k$ = CHR$(0) + «P» THEN speed# = -10

pl.ytmp = (pl.ytmp — speed# * costable#(walkdir%))
pl.xtmp = (pl.xtmp + speed# * sintable#(walkdir%))
pl.y = INT(pl.ytmp)
pl.x = INT(pl.xtmp)

pl.ld = ABS((pl.ld + angf%) MOD angf%)
LOOP UNTIL k$ = CHR$(27) 'k% = 16

' Insert Map
DATA 7,2,1,2,1,1,1,2,1,1,1,1,1,1,1,1
DATA 7,0,0,0,2,2,2,2,2,6,0,0,0,0,0,3
DATA 7,0,0,0,0,5,0,0,3,6,0,0,0,0,0,3
DATA 7,0,0,0,0,0,0,0,3,6,0,3,0,3,0,3
DATA 7,0,0,0,0,5,0,0,3,6,0,0,0,0,0,3
DATA 7,2,2,2,2,3,0,0,3,6,0,0,0,0,0,3
DATA 1,4,1,1,1,1,7,0,7,6,0,0,0,0,7,3
DATA 3,4,7,0,0,0,7,0,7,6,0,0,0,0,0,3
DATA 3,0,3,5,0,5,7,0,7,7,0,0,0,0,0,3
DATA 3,0,0,5,0,0,0,0,0,0,0,0,0,0,0,3
DATA 3,0,0,5,5,5,5,1,5,7,0,0,0,0,0,3
DATA 5,0,5,5,2,2,2,2,2,6,0,0,0,0,0,3
DATA 5,0,0,0,7,0,0,0,0,0,0,3,0,3,0,3
DATA 5,0,0,0,0,0,0,0,0,6,0,0,0,0,0,3
DATA 5,0,0,0,7,0,0,0,0,6,0,0,0,0,0,3
DATA 5,5,5,5,2,2,2,2,2,1,1,1,1,1,1,6
Но если вам этот raycaster все ещё нужен, то держите его:
raycast.rar
Чего только не найдешь в своём каталоге Downloads...

Если из текста статьи убрать слово RUST, то ничгео не изменится. А все же интересно, как именно Rust помог/улучши/ускорил/снизил кол-во циклов правки багов в разработке этого проекта.

Мне очнеь интеренсен Rust, т.к. дает на выходе относительно более безопасные сборки, но я нигде не могу найти инфу относительно того, а дает ли раст качественный скачек в процессе непосредсвенно самой разработки (скорость, кол-во багов и прочее). Страы ерпоекты для этого очень хороши, можно сравнить лоб в лоб.

Есть у меня опасение, что клоны паскаля могут оказаться по совокупности критериев более "производительными", но я не уверен.

Несколько человек потратили неделю, на то, что можно собрать одному за вечер? Серьезно?

И это имея книгу и туториалы...

Ну ладно, еще загрузку карт и ассетов сделали. Два вечера.

Sign up to leave a comment.

Articles