QB64.org Forum

Active Forums => QB64 Discussion => Topic started by: xra7en on November 08, 2021, 05:44:06 pm

Title: ISO simple ASCII procedural terrain
Post by: xra7en on November 08, 2021, 05:44:06 pm
I tried this for a few years, but I just cannot grasp the concept of "noise" "Parlin noise" or at least how to implement it in qb64.
Everything I try comes out too random.

looking for something as simple as this.
https://i.imgur.com/NunOIhN.png

do not need anything more 7 tilesets

so if anyone has a starter sample, or a link that explains how this is done (in english LOL) - found lots of resources for 3d like Minecraft etc.. but 2d ascii does not seem to exist.
thansk

Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 08, 2021, 07:05:22 pm
When I think of 2D landscape I think of this:
Code: QB64: [Select]
  1. _Title "Drawlandscape Demo" ' b+ 2021-11-08
  2. Const Xmax = 800, Ymax = 600
  3. Screen _NewImage(Xmax, Ymax, 32)
  4. _ScreenMove 200, 50
  5.     drawLandscape
  6.     _Limit .5
  7.  
  8. Sub drawLandscape
  9.     'needs midInk, irnd
  10.  
  11.     Dim i As Long, startH As Single, rr As Long, gg As Long, bb As Long
  12.     Dim mountain As Long, Xright As Single, y As Single, upDown As Single, range As Single
  13.     Dim lastx As Single, X As Long
  14.     'the sky
  15.     For i = 0 To Ymax
  16.         midInk 0, 0, 128, 128, 128, 200, i / Ymax
  17.         Line (0, i)-(Xmax, i)
  18.     Next
  19.     'the land
  20.     startH = Ymax - 200
  21.     rr = 70: gg = 70: bb = 90
  22.     For mountain = 1 To 6
  23.         Xright = 0
  24.         y = startH
  25.         While Xright < Xmax
  26.             ' upDown = local up / down over range, change along Y
  27.             ' range = how far up / down, along X
  28.             upDown = (Rnd * .8 - .35) * (mountain * .5)
  29.             range = Xright + irnd&(15, 25) * 2.5 / mountain
  30.             lastx = Xright - 1
  31.             For X = Xright To range
  32.                 y = y + upDown
  33.                 Color _RGB(rr, gg, bb)
  34.                 Line (lastx, y)-(X, Ymax), , BF 'just lines weren't filling right
  35.                 lastx = X
  36.             Next
  37.             Xright = range
  38.         Wend
  39.         rr = irnd&(rr - 15, rr): gg = irnd&(gg - 15, gg): bb = irnd&(bb - 25, bb)
  40.         If rr < 0 Then rr = 0
  41.         If gg < 0 Then gg = 0
  42.         If bb < 0 Then bb = 0
  43.         startH = startH + irnd&(5, 20)
  44.     Next
  45.  
  46. Function irnd& (n1, n2) 'return an integer between 2 numbers
  47.     Dim l%, h%
  48.     If n1 > n2 Then l% = n2: h% = n1 Else l% = n1: h% = n2
  49.     irnd& = Int(Rnd * (h% - l% + 1)) + l%
  50.  
  51. Sub midInk (r1%, g1%, b1%, r2%, g2%, b2%, fr##)
  52.     Color _RGB32(r1% + (r2% - r1%) * fr##, g1% + (g2% - g1%) * fr##, b1% + (b2% - b1%) * fr##)
  53.  
  54.  

Then I thought of this:
Code: QB64: [Select]
  1. _Title "Drawlandscape Parallax test" 'started 2019-03-27
  2. 'test if can get end of landscape level to start for big looping background
  3. '2019-03-27 a more gentle adjustment back to Mountain starting height for
  4. 'more seamless connect of back end to front
  5. '2019-03-27 start this file with parallax drawing test
  6.  
  7.  
  8. Screen _NewImage(800, 600, 32)
  9. _ScreenMove 100, 20
  10. Type parallaxType
  11.     handle As Long
  12.     rate As Single 'number of pixels per frame added to le (leading edge)
  13.     le As Single
  14. nLevels = 6
  15. Dim Shared para(1 To nLevels) As parallaxType
  16.  
  17. Dim Shared scape&
  18. LoadLandscape
  19. scapeWidth = _Width(para(1).handle)
  20. scapeHeight = _Height(para(1).handle)
  21.  
  22. While t < 6000
  23.     Cls
  24.     For i = 1 To nLevels
  25.         If para(i).le + 800 > scapeWidth Then
  26.             te = scapeWidth - para(i).le
  27.             _PutImage (0, 0)-(te, scapeHeight), para(i).handle, 0, (scapeWidth - te, 0)-(scapeWidth, scapeHeight)
  28.             _PutImage (te, 0)-(800, scapeHeight), para(i).handle, 0, (0, 0)-(800 - te, scapeHeight)
  29.  
  30.         Else
  31.             _PutImage (0, 0)-(800, scapeHeight), para(i).handle, 0, (para(i).le, 0)-(para(i).le + 800, scapeHeight)
  32.         End If
  33.  
  34.         para(i).le = para(i).le - para(i).rate
  35.         If para(i).le < 0 Then para(i).le = scapeWidth
  36.     Next
  37.     t = t + 1
  38.     _Display
  39.     _Limit 120
  40.  
  41. Sub LoadLandscape
  42.     cur& = _Dest
  43.     xmax = 800 * 3.25: ymax = 600
  44.     hdl& = 1
  45.     para(hdl&).handle = _NewImage(xmax, ymax, 32)
  46.     _Dest para(hdl&).handle
  47.  
  48.     For i = 0 To ymax
  49.         midInk 0, 0, 128, 128, 128, 200, i / ymax
  50.         Line (0, i)-(xmax, i)
  51.     Next
  52.     'the land
  53.     startH = ymax - 200
  54.     rr = 70: gg = 70: bb = 90
  55.     For mountain = 1 To nLevels
  56.         If mountain > 1 Then
  57.             para(mountain).handle = _NewImage(xmax, ymax, 32)
  58.             _Dest para(mountain).handle
  59.         End If
  60.         Xright = 0
  61.         y = startH
  62.         Color _RGB(rr, gg, bb)
  63.         While Xright < xmax - 50
  64.             ' upDown = local up / down over range, change along Y
  65.             ' range = how far up / down, along X
  66.             upDown = (Rnd * .8 - .4) * (mountain * .5)
  67.             range = Xright + rand%(15, 25) * 2.5 / mountain
  68.             If range > xmax - 50 Then range = xmax - 50
  69.             lastx = Xright - 1
  70.             For x = Xright To range 'need less flat tops
  71.                 test = y + upDown
  72.                 test2 = y - upDown
  73.                 If Abs(test - startH) < .13 * startH Then y = test Else y = test2: upDown = -upDown
  74.                 Line (lastx, y)-(x, ymax), , BF 'just lines weren't filling right
  75.                 lastx = x
  76.             Next
  77.             Xright = range
  78.         Wend
  79.         x = lastx + 1
  80.         dy = (startH - y) / 50 'more gentle adjustment back to start of screen
  81.         While x <= xmax
  82.             y = y + dy
  83.             Line (lastx, y)-(x, ymax), , BF 'just lines weren't filling right
  84.             lastx = x
  85.             x = x + 1
  86.         Wend
  87.         rr = rand%(rr - 15, rr): gg = rand%(gg - 15, gg): bb = rand%(bb - 25, bb)
  88.         If rr < 0 Then rr = 0
  89.         If gg < 0 Then gg = 0
  90.         If bb < 0 Then bb = 0
  91.         startH = startH + mountain * rand%(2, 10)
  92.         para(mountain).le = xmax - 800
  93.         para(mountain).rate = mountain * .5
  94.     Next
  95.     _Dest cur&
  96.  
  97. Function rand% (lo%, hi%)
  98.     rand% = Int(Rnd * (hi% - lo% + 1)) + lo%
  99.  
  100. Sub midInk (r1%, g1%, b1%, r2%, g2%, b2%, fr##)
  101.     Color _RGB(r1% + (r2% - r1%) * fr##, g1% + (g2% - g1%) * fr##, b1% + (b2% - b1%) * fr##)
  102.  
  103.  

Sure that could be reduced to ASCII?
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 08, 2021, 08:04:17 pm
Love those
what I am trying to do (as in the image) is do a top down ascii style -
think dwarf fortress, but not that elaborate - just 5 or 6 tiles - I think DF has like 100 tiles LOL
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 06:09:43 pm
So I put this request up in 2012 in a game dev site, did not get many responses. I thought it was strange that a ascii top down terrain gen would be difficult (so at least I am not the only one LOL)
Many of the responses were like this - 3D models that were not land types.

So I'll take another stab at what I can do, post it here and see if someone can improve on it.

Team work
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 06:51:38 pm
@xra7en would you have images you would like converted, photos of something?
Title: Re: ISO simple ASCII procedural terrain
Post by: johnno56 on November 10, 2021, 08:26:48 pm
... like an ASCII rpg?

ASCII. Old school. But cool.
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 08:38:01 pm
Quote from: bbplus
@xra7en would you have images you would like converted, photos of something?


O I've done that before - looks cool, but what I want is a procedurally generated one.

The first style I used to do for small games - and it served its purpose
Code: QB64: [Select]
  1. Dim tile(5) As String
  2. tile(1) = "T"
  3. tile(2) = "."
  4. tile(3) = "="
  5. tile(4) = "~"
  6. tile(5) = " "
  7.  
  8.  
  9. For i = 1 To 10
  10.     For j = 1 To 10
  11.         Print " "; tile(Int(Rnd * 5) + 1); " ";
  12.     Next
  13.     Print

but as I started looking at modern indi games, their land "made sense"  - like Minecraft, everything worked. This is too random, no clumping of areas


Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 08:39:01 pm
... like an ASCII rpg?

ASCII. Old school. But cool.

yup, have a simple one in mind, but want to have a large map that displays only a small portion where the player is at live.

easy to make, just obsessing over the random generator
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 09:08:58 pm
I think you could paint a map with a mouse, click an ascii on one screen maybe pick a color too then on the map screen paint it with a mouse, mouse down paints until mouse up.
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 09:34:03 pm
Code: QB64: [Select]
  1. Dim tile(9) As String
  2. tile(0) = " "
  3. tile(1) = "T"
  4. tile(2) = "."
  5. tile(3) = "="
  6. tile(4) = "~"
  7. tile(5) = "b"
  8. tile(6) = "+"
  9. tile(7) = "M"
  10. tile(8) = Chr$(1)
  11. tile(9) = Chr$(3)
  12.  
  13.     k$ = InKey$
  14.     If k$ <> "" Then
  15.         If Asc(k$) >= 48 And Asc(k$) <= 57 Then kp = Asc(k$) - 48
  16.         Locate 1, 1: Print tile(kp);
  17.     End If
  18.     mx = _MouseX: my = _MouseY: mb1 = _MouseButton(1)
  19.     If my < 25 Then 'dang scrolling
  20.         If mb1 Then Locate my, mx: Print tile(kp);
  21.     End If
  22.  

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 09:49:56 pm
very clever!! lol
At first look I was like WOW, smaller script than mine, then I saw the inkey$.
but the END RESULT is what i am looking for as procedural

working on one right now - I think I am on to something :-)
I'll post it here later.
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 10:00:59 pm
I have added code to save to file with s keypress: (Had to start a Project Folder to save maps.)

Code: QB64: [Select]
  1. Dim tile(9) As String
  2. tile(0) = " "
  3. tile(1) = "T"
  4. tile(2) = "."
  5. tile(3) = "="
  6. tile(4) = "~"
  7. tile(5) = "b"
  8. tile(6) = "+"
  9. tile(7) = "M"
  10. tile(8) = Chr$(1)
  11. tile(9) = Chr$(3)
  12.  
  13.     k$ = InKey$
  14.     If k$ <> "" Then
  15.         If Asc(k$) >= 48 And Asc(k$) <= 57 Then
  16.             kp = Asc(k$) - 48: Locate 1, 1: Print tile(kp);
  17.         ElseIf k$ = "s" Then 'save pic
  18.             Open "Save Map.txt" For Output As #1
  19.             For y = 1 To 25
  20.                 b$ = ""
  21.                 For x = 1 To 80
  22.                     b$ = b$ + Chr$(Screen(y, x))
  23.                 Next
  24.                 Print #1, b$
  25.             Next
  26.             Close #1
  27.         End If
  28.     End If
  29.     mx = _MouseX: my = _MouseY: mb1 = _MouseButton(1)
  30.     If my < 25 Then 'dang scrolling
  31.         If mb1 Then Locate my, mx: Print tile(kp);
  32.     End If
  33.  

Here is sample of map (Save Map.txt) :
Code: QB64: [Select]
  1. +                                                                              
  2.                                                                                
  3.                                                              +++++              
  4.                                                             +++++++            
  5.                            bbbbb                            ++++++              
  6.                         b bb  bbbbbbbbbbbbbbb                ++ ++              
  7.                         bbbbbbb            bbb      ++++++++++++++++++++++      
  8.                           bbbbbbb          bbbb    ++++++++++++++++++++++++    
  9.                           b bbb             bbbb    +++++++++++++++++++++      
  10.                           b bb              bbbb             ++++              
  11.                           b bb              bb              +++++++            
  12.                           b bb            bbb               +++++++            
  13.                           bbb          bbbb                   +++              
  14.                           bbb          bbbbbbbb                                
  15.                           bb              bbbbbbbb                              
  16.                           bbb               bbbb b                              
  17.                           bbb                b bbb                              
  18.                           bbb              bbbbb                                
  19.                        bbbbbbbbbbbbbbbbbbbbbbb                                  
  20.                        bbbbbbbbbbbbbbbbbbbbbb                                  
  21.                           b   bbbbbbbbbbbbb                                    
  22.                              bb                                                
  23.                                                                                
  24.                                                                                
  25.                                                                              
  26.  

If you like it, save it under a new name otherwise it will just be written over with next drawing.
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 10:03:09 pm
ok try this-
closer to what im shooting for

yes yes yes. redundant code (easy to clean up later)

currently just using squares.. but may change this to diamonds mix
Code: QB64: [Select]
  1.  
  2. Dim tile(5) As String
  3. Dim area(75, 20) As Integer
  4.  
  5. tile(1) = "T"
  6. tile(2) = "."
  7. tile(3) = "="
  8. tile(4) = "~"
  9. tile(5) = " "
  10.  
  11. '// Clear the map
  12. For i = 1 To 75: For j = 1 To 20: area(i, j) = 0: Next: Next
  13.  
  14. '// lets try some random squares
  15. For i = 1 To 30 ' <-- bigger number more dense
  16.     x = r(72)
  17.     y = r(18)
  18.     For k = y - 1 To y + 1
  19.         For j = x - 5 To x + 5
  20.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  21.                 area(j, k) = 1
  22.             End If
  23.  
  24.         Next
  25.     Next
  26.  
  27. For i = 1 To 15 ' <-- bigger number more dense
  28.     x = r(72)
  29.     y = r(18)
  30.     For k = y - 1 To y + 1
  31.         For j = x - 5 To x + 5
  32.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  33.                 area(j, k) = 2
  34.             End If
  35.  
  36.         Next
  37.     Next
  38.  
  39. For i = 1 To 7 ' <-- bigger number more dense
  40.     x = r(72)
  41.     y = r(18)
  42.     For k = y - 1 To y + 1
  43.         For j = x - 5 To x + 5
  44.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  45.                 area(j, k) = 3
  46.             End If
  47.  
  48.         Next
  49.     Next
  50.  
  51. For i = 1 To 7 ' <-- bigger number more dense
  52.     x = r(72)
  53.     y = r(18)
  54.     For k = y - 1 To y + 1
  55.         For j = x - 5 To x + 5
  56.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  57.                 area(j, k) = 4
  58.             End If
  59.  
  60.         Next
  61.     Next
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69. For j = 1 To 20
  70.     For i = 1 To 75
  71.  
  72.         Select Case area(i, j)
  73.             Case 0: Print " ";
  74.             Case 1: Print "T";
  75.             Case 2: Print "#";
  76.             Case 3: Print ".";
  77.             Case 4: Print ".";
  78.  
  79.         End Select
  80.     Next
  81.  
  82.     Print
  83.  
  84.  
  85.     r = Int(Rnd * num) + 1
  86.  
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 10:06:28 pm
When you are ready to alter the look of the characters, I have a Character Editor.
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 10:12:25 pm
When you are ready to alter the look of the characters, I have a Character Editor.

thank you.. !!

for simplicity I'll keep it in the extended table for now..

is your editor similar to the DF characters?
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 10:15:08 pm
Don't know what DF characters are?

Char Editor is for 8 X16 Font and I was modifying for 8x8 font I think.
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 10:27:56 pm
Code: QB64: [Select]
  1. _Title "8X16 ASCII Character Editor"
  2. 'started 2018-08-27 by bplus
  3. 'QB64 X 64 version 1.2 20180228/86  from git b301f92
  4. ' 2020-09-18 modified to coexist with the 8X8 Character Editor in the same Folder
  5.  
  6. '========================== Instructions: =================================
  7. '
  8. ' Arrow keys move the highlighter around, spacebar toggles tile on/off
  9. ' or just click with mouse to do the same.
  10.  
  11. ' Click buttons to either
  12. ' 1. Enter an ascii by number to edit.
  13. ' 2. Enter a character by pressing the key(s) from which the ascii number is taken.
  14. ' 3. Save a modified character.
  15. ' 4. Save all edits made to file called "Character Set.DAT".
  16. ' Note: If want to work with more sets, just rename Character Set.DAT
  17. '       If that file isn't found, this app will start from scratch.
  18. '
  19. '==========================================================================
  20. Const cFile$ = "8X16 Character Set.DAT"
  21. Const CW = 8
  22. Const CH = 16
  23. Const SQ = 25
  24. Const XOFF = 60
  25. Const YOFF = 80
  26. Const WW = 800
  27. Const WH = 600
  28. Screen _NewImage(WW, WH, 32)
  29. _ScreenMove (1280 - WW) / 2 + 30, (760 - WH) / 2
  30. Dim Shared AN%, CX, CY, BLK As _Unsigned Long, WHT As _Unsigned Long, SAVED
  31. Dim Shared MAP(CW + 2, CH + 2) As String * 1
  32. Dim Shared CS(256) As String * 128
  33. WHT = _RGB32(255, 255, 255)
  34. BLK = _RGB32(0, 0, 0)
  35.  
  36. '==============================   main
  37.  
  38. 'see if there is a file in the works to load else start from scratch
  39.     Open cFile$ For Input As #1
  40.     For i = 1 To 256
  41.         Input #1, CS(i - 1)
  42.     Next
  43.     Close #1
  44.     SAVED = -1
  45.     For a = 0 To 255
  46.         Cls
  47.         _PrintString (0, 0), Chr$(a)
  48.         b$ = ""
  49.         For y = 0 To CH - 1
  50.             For x = 0 To CW - 1
  51.                 If Point(x, y) <> BLK Then b$ = b$ + "1" Else b$ = b$ + "0"
  52.             Next
  53.         Next
  54.         CS(a) = b$
  55.     Next
  56.     SAVED = 0
  57.  
  58. For i = 1 To 128
  59.     Print Mid$(CS(1), i, 1);
  60.     If i Mod CW = 0 Then Print
  61. 'END
  62. 'sample B for starters
  63. AN% = 66
  64. load AN%
  65. CX = 1: CY = 1
  66.         mx = _MouseX
  67.         my = _MouseY
  68.         _Delay .2
  69.         'ascii #  to edit
  70.         If mx > 500 And mx < 700 And my > 50 And my < 100 Then
  71.             Color WHT, 0
  72.             Line (500, 50)-(700, 100), BLK, BF
  73.             Locate 5, 67: Input "Ascii # "; a%
  74.             If a% >= 0 And a% <= 255 Then AN% = a%: load AN%
  75.         End If
  76.         'chr$  to edit
  77.         If mx > 500 And mx < 700 And my > 110 And my < 160 Then
  78.             Color WHT, 0
  79.             Line (500, 110)-(700, 160), BLK, BF
  80.             Locate 9, 67: Input "Enter Chr$ "; char$
  81.             a% = Asc(char$)
  82.             If a% >= 0 And a% <= 255 Then AN% = a%: load AN%
  83.         End If
  84.         'save character edit
  85.         If mx > 500 And mx < 700 And my > 170 And my < 220 Then
  86.             b$ = ""
  87.             For y = 1 To CH
  88.                 For x = 1 To CW
  89.                     b$ = b$ + MAP(x, y)
  90.                 Next
  91.             Next
  92.             CS(AN%) = b$
  93.             Color WHT, 0
  94.             Line (500, 170)-(700, 220), BLK, BF
  95.             Locate 13, 67: Print " Character recorded. "
  96.             SAVED = 0
  97.             _Display
  98.             _Delay 1.5
  99.         End If
  100.         'file character set
  101.         If mx > 500 And mx < 700 And my > 230 And my < 280 Then
  102.             Color WHT, 0
  103.             Line (500, 230)-(700, 280), BLK, BF
  104.             Open cFile$ For Output As #1
  105.             For a = 0 To 255
  106.                 Print #1, CS(a)
  107.             Next
  108.             Close #1
  109.             Locate 16, 65: Print cFile$
  110.             Locate 17, 71: Print "File Saved"
  111.             SAVED = -1
  112.             _Display
  113.             _Delay 1.5
  114.         End If
  115.  
  116.         'mouse over edit box, toggle tiles and update cursor
  117.         tx = (mx - XOFF) \ SQ: ty = (my - YOFF) \ SQ
  118.         If tx >= 1 And tx <= CW And ty >= 1 And ty <= CH Then
  119.             CX = tx: CY = ty
  120.             If MAP(CX, CY) = "1" Then MAP(CX, CY) = "0" Else MAP(CX, CY) = "1"
  121.         End If
  122.     End If
  123.     KH& = _KeyHit
  124.     Select Case KH&
  125.         Case 32 'space bar
  126.             If MAP(CX, CY) = "1" Then MAP(CX, CY) = "0" Else MAP(CX, CY) = "1"
  127.         Case 18432 'up
  128.             If CY - 1 >= 1 Then CY = CY - 1
  129.         Case 20480 'down
  130.             If CY + 1 <= CH Then CY = CY + 1
  131.         Case 19200 'left
  132.             If CX - 1 >= 1 Then CX = CX - 1
  133.         Case 19712 'right
  134.             If CX + 1 <= CW Then CX = CX + 1
  135.     End Select
  136.  
  137.     If _KeyDown(27) Then End
  138.     update
  139.     _Display
  140.     _Limit 60
  141.  
  142. Sub load (asci)
  143.     For i = 1 To 128
  144.         y = i \ CW + 1
  145.         x = i Mod CW: If x = 0 Then x = 8: y = y - 1
  146.         MAP(x, y) = Mid$(CS(asci), i, 1)
  147.     Next
  148.  
  149. Sub update
  150.     Color WHT, _RGB32(100, 110, 100): Cls
  151.     drwBtn 500, 50, "Load map with Ascii"
  152.     drwBtn 500, 110, "Load map with Chr$"
  153.     drwBtn 500, 170, "Save Character Edit"
  154.     drwBtn 500, 230, "File Character Set"
  155.     Color _RGB32(250, 225, 255), _RGB32(100, 110, 100)
  156.     _PrintString (398, 400), "Current Ascii% =" + Str$(AN%) + " or CHR$(" + LTrim$(Str$(AN%)) + ") = " + Chr$(AN%)
  157.     If SAVED Then s$ = " Saved." Else s$ = " not Saved yet."
  158.     _PrintString (398, 440), "File: " + cFile$ + s$
  159.     Line (XOFF - 1, YOFF - 1)-Step((CW + 2) * SQ + 2, (CH + 2) * SQ + 2), _RGB32(255, 255, 0), B
  160.     Line (XOFF + 1, YOFF + 1)-Step((CW + 2) * SQ, (CH + 2) * SQ), BLK, B
  161.     Line (XOFF, YOFF)-Step((CW + 2) * SQ, (CH + 2) * SQ), _RGB32(255, 80, 0), BF
  162.     For y = 1 To CH
  163.         For x = 1 To CW
  164.             If MAP(x, y) = "1" Then c& = _RGB32(200, 200, 200) Else c& = _RGB32(0, 0, 0)
  165.             Line ((x) * SQ + XOFF, (y) * SQ + YOFF)-Step(SQ - 2, SQ - 2), c&, BF
  166.         Next
  167.     Next
  168.     ' let's see actual size!
  169.     Color _RGB32(255, 255, 0), _RGB32(100, 110, 100)
  170.     For i = 1 To 4
  171.         drwChar XOFF + 16 * (i * 2), .5 * YOFF - (16 * i) / 2, AN%, i
  172.     Next
  173.     'highlight sqr
  174.     Line (CX * SQ - 1 + XOFF, CY * SQ - 1 + YOFF)-Step(SQ, SQ), WHT, B
  175.  
  176.  
  177. Sub drwBtn (x, y, s$)
  178.     th = 16: tw = 8 * Len(s$): gray& = _RGB32(190, 190, 190)
  179.     Line (x, y)-Step(200, 50), _RGB32(0, 0, 0), BF
  180.     Line (x, y)-Step(197, 47), _RGB32(255, 255, 255), BF
  181.     Line (x + 1, y + 1)-Step(197, 47), gray&, BF
  182.     Color _RGB32(0, 0, 0), gray&
  183.     _PrintString (x + 100 - 4 * Len(s$), y + 17), s$
  184.  
  185. Sub drwChar (x0, y0, ascn, size) 'what ever the present color is set at
  186.     For y = 0 To CH - 1
  187.         For x = 0 To CW - 1
  188.             i = i + 1
  189.             If Mid$(CS(ascn), i, 1) = "1" Then Line (x0 + x * size, y0 + y * size)-Step(size - 1, size - 1), , BF
  190.         Next
  191.     Next
  192.  

It will use custom charaacter set in this file: "8X16 Character Set.DAT"
if it finds it in the folder of the .exe otherwise it will start that file and when you slect save file it will make your character set with custom changes.

If you want several custom sets just change name of file, and change it back to "8X16 Character Set.DAT" to edit that one again.

Of course, you will need some routines for using these characters in you game file. I think I have a test demo somewhere.

Also looks like 8 x 8 editor is done too.
  [ This attachment cannot be displayed inline in 'Print Page' view ]  

Wow over 3 years ago!
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 10:50:04 pm
Don't know what DF characters are?

Char Editor is for 8 X16 Font and I was modifying for 8x8 font I think.

dwarf fortress (one of the hardest games ever created - even has an O'Reilly book on how to play - Im like seriously - ofc I bought it LOL)
https://i.pinimg.com/originals/96/3d/4f/963d4f5d54e5d0e90ee6d7b23d140bff.jpg
https://www.amazon.com/Getting-Started-Dwarf-Fortress-complex/dp/1449314945

Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 10:51:39 pm
Yes! I would be interested in that. It is almost like a modern THEDRAW program!
or more precisely TDFONTS program.
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 10, 2021, 10:53:13 pm
OK end result it actually accpetable. Obviously clean up the code.
will prob add a routine to add a river, maybe one or two lakes. and a range of hardcore mountains!

add color and poof
Code: QB64: [Select]
  1.  
  2.  
  3.  
  4. Dim tile(5) As String
  5. Dim area(75, 20) As Integer
  6.  
  7. tile(1) = "T"
  8. tile(2) = "."
  9. tile(3) = "="
  10. tile(4) = "~"
  11. tile(5) = " "
  12.  
  13. '// Clear the map
  14. For i = 1 To 75: For j = 1 To 20: area(i, j) = 0: Next: Next
  15.  
  16. '// lets try some random squares
  17. For i = 1 To 40 ' <-- bigger number more dense
  18.     x = r(75)
  19.     y = r(20)
  20.     For k = y - 1 To y + 1
  21.         For j = x - 5 To x + 5
  22.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  23.                 area(j, k) = 1
  24.             End If
  25.  
  26.         Next
  27.     Next
  28.  
  29. For i = 1 To 20 ' <-- bigger number more dense
  30.     x = r(72)
  31.     y = r(18)
  32.     For k = y - 1 To y + 1
  33.         For j = x - 5 To x + 5
  34.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  35.                 area(j, k) = 2
  36.             End If
  37.  
  38.         Next
  39.     Next
  40.  
  41. For i = 1 To 10 ' <-- bigger number more dense
  42.     x = r(72)
  43.     y = r(18)
  44.     For k = y - 1 To y + 1
  45.         For j = x - 5 To x + 5
  46.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  47.                 area(j, k) = 3
  48.             End If
  49.  
  50.         Next
  51.     Next
  52.  
  53. For i = 1 To 5 ' <-- bigger number more dense
  54.     x = r(72)
  55.     y = r(18)
  56.     For k = y - 1 To y + 1
  57.         For j = x - 5 To x + 5
  58.             If j > 0 And j < 76 And k > 0 And k < 21 Then
  59.                 area(j, k) = 4
  60.             End If
  61.  
  62.         Next
  63.     Next
  64.  
  65. For y = 1 To 20
  66.     For x = 1 To 75
  67.         If area(x, y) = 0 Then area(x, y) = 247
  68.     Next
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75. For j = 1 To 20
  76.     For i = 1 To 75
  77.  
  78.         Select Case area(i, j)
  79.             Case 0: Print " ";
  80.             Case 1: Print "T";
  81.             Case 2: Print "#";
  82.             Case 3: Print ".";
  83.             Case 4: Print ".";
  84.             Case 247: Print Chr$(area(i, j));
  85.  
  86.         End Select
  87.     Next
  88.  
  89.     Print
  90.  
  91.  
  92.     r = Int(Rnd * num) + 1
  93.  
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 11:32:06 pm
Oh hey, rndRect!
Code: QB64: [Select]
  1. _Title "RndRect - zzz... press any, esc to quit"
  2.     For i = 1 To 250
  3.         rndRect
  4.     Next
  5.     Sleep
  6.  
  7. Sub rndRect
  8.     c$ = Chr$(Int(Rnd * 200) + 32)
  9.     x = Int(Rnd * 80) + 1
  10.     y = Int(Rnd * 25) + 1
  11.     w = Int(Rnd * 30) + 1
  12.     h = Int(Rnd * 8) + 1
  13.     For row = y To y + h
  14.         For col = x To x + w
  15.             If row <= 25 And col <= 80 Then
  16.                 Locate row, col: Print c$;
  17.             End If
  18.         Next
  19.     Next
  20.  
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 11:37:16 pm
Colorized version
Code: QB64: [Select]
  1. _Title "RndRect - zzz... press any, esc to quit"
  2.     For i = 1 To 250
  3.         rndRect
  4.     Next
  5.     Sleep
  6.  
  7. Sub rndRect
  8.     c$ = Chr$(Int(Rnd * 200) + 32)
  9.     x = Int(Rnd * 80) + 1
  10.     y = Int(Rnd * 25) + 1
  11.     w = Int(Rnd * 30) + 1
  12.     h = Int(Rnd * 8) + 1
  13.     Color Int(Rnd * 15) + 1 '  Int(Rnd * 15) + 1
  14.     For row = y To y + h
  15.         For col = x To x + w
  16.             If row <= 25 And col <= 80 Then
  17.                 Locate row, col: Print c$;
  18.             End If
  19.         Next
  20.     Next
  21.  
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 10, 2021, 11:42:58 pm
With limited tile() set:
Code: QB64: [Select]
  1. _Title "RndRect - zzz... press any, esc to quit"
  2.  
  3. tile(1) = "T"
  4. tile(2) = "."
  5. tile(3) = "="
  6. tile(4) = "~"
  7. tile(5) = " "
  8.  
  9.     For i = 1 To 250
  10.         rndRect
  11.     Next
  12.     Sleep
  13.  
  14. Sub rndRect
  15.     c$ = tile(Int(Rnd * 5) + 1)
  16.     x = Int(Rnd * 80) + 1
  17.     y = Int(Rnd * 25) + 1
  18.     w = Int(Rnd * 30) + 1
  19.     h = Int(Rnd * 8) + 1
  20.     'Color Int(Rnd * 15) + 1 '  Int(Rnd * 15) + 1   ' Color or Not ?
  21.     For row = y To y + h
  22.         For col = x To x + w
  23.             If row <= 25 And col <= 80 Then
  24.                 Locate row, col: Print c$;
  25.             End If
  26.         Next
  27.     Next
  28.  
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 11, 2021, 12:12:53 am
nice - but grouping is off (something I am still struggling with)

trees should be surrounded by bushes, surrounded by maybe grass, and plains, and clearing near body of water.
so far we have random blocks, but not making sense LOL

cept now its late,,, will tackle tomorrow at work (i have my own hours hahhaaha)

Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 11, 2021, 12:28:42 am
Here is Font 8 so I can add round circles:
Code: QB64: [Select]
  1. _Title "RndRect - zzz... press any, esc to quit"
  2.  
  3. tile(1) = "T"
  4. tile(2) = "."
  5. tile(3) = "="
  6. tile(4) = "~"
  7. tile(5) = "#"
  8.  
  9. Width 80, 80
  10.     For i = 1 To 50
  11.         rndRect
  12.     Next
  13.     Sleep
  14.  
  15. Sub rndRect
  16.     c$ = tile(Int(Rnd * 5) + 1)
  17.     x = Int(Rnd * _Width) + 1
  18.     y = Int(Rnd * _Height) + 1
  19.     w = Int(Rnd * 15) + 1
  20.     h = Int(Rnd * 15) + 1
  21.     'Color Int(Rnd * 15) + 1 '  Int(Rnd * 15) + 1   ' Color or Not ?
  22.  
  23.     If Rnd < .5 Then
  24.         For row = y To y + h
  25.             For col = x To x + w
  26.                 If row <= _Height And col <= _Width Then
  27.                     Locate row, col: Print c$;
  28.                 End If
  29.             Next
  30.         Next
  31.     Else
  32.         For row = y - h To y + h
  33.             For col = x - h To x + h
  34.                 If row >= 1 And row <= _Height Then
  35.                     If col > 1 And col <= _Width Then
  36.                         If Sqr(((col - x) ^ 2) + (row - y) ^ 2) <= h Then
  37.                             Locate row, col: Print c$;
  38.                         End If
  39.                     End If
  40.                 End If
  41.             Next
  42.         Next
  43.  
  44.     End If

Circles look more natural but what we really need is plasma!
Title: Re: ISO simple ASCII procedural terrain
Post by: SMcNeill on November 11, 2021, 12:49:21 am
Here's my first shot at this:

Code: QB64: [Select]
  1. Const XSize = 200, YSize = 200
  2. Dim Shared As Long Grid(XSize, YSize)
  3.  
  4. DisplayScreen = MaxScreen
  5. Screen MaxScreen
  6.  
  7.  
  8.     InitializeMap
  9.     Rivers Int(Rnd * 10) + 1, Int(Rnd * 100) - 100, -3
  10.     GenerateTerrain
  11.  
  12.     DrawMap
  13.     Sleep
  14.  
  15. Sub InitializeMap
  16.     For x = 0 To XSize
  17.         For y = 0 To YSize
  18.             Grid(x, y) = -999 'default blank part of map
  19.         Next
  20.     Next
  21.  
  22.  
  23. Sub DrawMap
  24.     Dim kolor As _Unsigned Long
  25.     xscale = _Width / XSize
  26.     yscale = _Height / YSize
  27.     For x = 0 To XSize
  28.         For y = 0 To YSize
  29.             Select Case Grid(x, y)
  30.                 Case -3: kolor = DarkBlue 'Deep Water
  31.                 Case -2: kolor = Blue 'Water
  32.                 Case -1: kolor = SkyBlue 'Shallow Water
  33.                 Case 0: kolor = Tann 'beach/sand
  34.                 Case 1: kolor = Green 'grassland
  35.                 Case 2: kolor = DarkGreen 'forest
  36.                 Case 3: kolor = Pink 'hills
  37.                 Case 4: kolor = Purple 'mountains
  38.                 Case 5 TO 99: kolor = Red
  39.                 Case Else: kolor = Black
  40.             End Select
  41.             Line (x * xscale, y * yscale)-Step(xscale, yscale), kolor, BF
  42.     Next y, x
  43.  
  44.  
  45. Sub GenerateTerrain
  46.     Height = -3
  47.     Do Until finished
  48.         finished = -1
  49.         For x = 0 To XSize
  50.             For y = 0 To YSize
  51.                 If Grid(x, y) = Height Then Fill x, y, Height + 1: finished = 0
  52.             Next
  53.         Next
  54.         Height = Height + 1
  55.     Loop
  56.  
  57.  
  58. Sub Fill (x, y, height)
  59.     Select Case height
  60.         Case Is < 0: RepeatChance = 33 'water repeat
  61.         Case Is = 0: RepeatChance = 25 'beach repeat
  62.         Case Is = 1: RepeatChance = 55 'grassland
  63.         Case Is = 2: RepeatChance = 55 'forest
  64.         Case Is = 3: RepeatChance = 40 ' hills
  65.         Case Is = 4: RepeatChance = 33 'mountains
  66.         Case Else
  67.             RepeatChance = 50 - 3 * height
  68.             If RepeatChance < 10 Then RepeatChance = 10
  69.     End Select
  70.     CurrentX = x
  71.     If CurrentX > 0 Then
  72.         If Grid(CurrentX - 1, y) = -999 Then
  73.             Grid(CurrentX - 1, y) = height
  74.             If Int(Rnd * 100) < RepeatChance Then Fill CurrentX - 1, y, height
  75.         End If
  76.     End If
  77.     CurrentX = x
  78.     If CurrentX < XSize Then
  79.         If Grid(CurrentX + 1, y) = -999 Then
  80.             Grid(CurrentX + 1, y) = height
  81.             If Int(Rnd * 100) < RepeatChance Then Fill CurrentX + 1, y, height
  82.         End If
  83.     End If
  84.     CurrentY = y
  85.     If CurrentY > 0 Then
  86.         If Grid(x, CurrentY - 1) = -999 Then
  87.             Grid(x, CurrentY - 1) = height
  88.             If Int(Rnd * 100) < RepeatChance Then Fill x, CurrentY - 1, height
  89.         End If
  90.     End If
  91.     CurrentY = y
  92.     If CurrentY < YSize Then
  93.         If Grid(x, CurrentY + 1) = -999 Then
  94.             Grid(x, y + 1) = height
  95.             If Int(Rnd * 100) < RepeatChance Then Fill x, CurrentY + 1, height
  96.         End If
  97.     End If
  98.  
  99. Sub Rivers (Number, Meander, Deep)
  100.     For i = 1 To Number
  101.         flip1 = Int(Rnd * 2): flip2 = Int(Rnd * 2)
  102.         If flip1 Then 'entry point is on top
  103.             x1 = Int(Rnd * XSize): y1 = 0
  104.         Else 'entry point is on left
  105.             x1 = 0: y1 = Int(Rnd * YSize)
  106.         End If
  107.         If flip2 Then 'exit point is on bottom
  108.             x2 = Int(Rnd * XSize): y2 = YSize
  109.         Else 'exit point is on right
  110.             x2 = XSize: y2 = Int(Rnd * YSize)
  111.         End If
  112.  
  113.         Grid(x1, y1) = Deep: Grid(x2, y2) = Deep
  114.         StartX = x1: StartY = y1: EndX = x2: EndY = y2 'just to preserve our original values, if needed.
  115.         Do Until StartX = EndX And StartY = EndY
  116.             CoinToss = Int(Rnd * 100) 'Coin toss to move left/right or up/down, to go towards exit, or wander a bit.
  117.             Meander = 10
  118.             If CoinToss Mod 2 Then 'even or odd, so we only walk vertical or hortizontal and not diagional
  119.                 If CoinToss < 100 - Meander Then 'Lower values meander less and go directly to the target.
  120.                     XChange = Sgn(EndX - StartX) '-1,0,1, drawn always towards the mouse
  121.                     Ychange = 0
  122.                 Else
  123.                     XChange = Int(Rnd * 3) - 1 '-1, 0, or 1, drawn in a random direction to let the lightning wander
  124.                     Ychange = 0
  125.                 End If
  126.             Else
  127.                 If CoinToss < 100 - Meander Then 'Lower values meander less and go directly to the target.
  128.                     Ychange = Sgn(EndY - StartY)
  129.                     XChange = 0
  130.                 Else
  131.                     Ychange = Int(Rnd * 3) - 1
  132.                     XChange = 0
  133.                 End If
  134.             End If
  135.             StartX = StartX + XChange
  136.             StartY = StartY + Ychange
  137.             If StartX < 0 Then StartX = 0 'Make certain we move inside the bounds of our map dimensions
  138.             If StartY < 0 Then StartY = 0
  139.             If StartX > XSize Then StartX = XSize
  140.             If StartY > YSize Then StartY = YSize
  141.             Grid(StartX, StartY) = Deep 'place a river where we moved to
  142.         Loop
  143.     Next
  144.  
  145.  
  146.  
  147.  
  148.  
  149. Function MaxScreen
  150.     DH = _DesktopHeight: DW = _DesktopWidth
  151.     TBH = TaskbarHeight: TBW = TaskbarWidth
  152.     TH = TitleBarHeight: BW = BorderWidth
  153.     If TBH = DH Then TBH = 0 'Users taskbar is configured vertical, not hortizonal.
  154.     If TBW = DW Then TBW = 0
  155.     MaxScreen = _NewImage(DW - TBW - 2 * BW, DH - TBH - TH - BW * 2, 32)
  156.  
  157. Sub ScreenMove (x, y)
  158.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  159.     _ScreenMove x - BorderWidth, y - BorderWidth - TitleBarHeight
  160.  
  161. Sub ScreenMove_Middle
  162.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  163.     _ScreenMove (_DesktopWidth - _Width - BorderWidth) / 2 + 1, (_DesktopHeight - _Height - BorderWidth) / 2 - TitleBarHeight + 1
  164.  
  165. Function TaskbarHeight
  166.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  167.  
  168.     $If WIN Then
  169.         $If TASKBARDEC = UNDEFINED Then
  170.             $Let TASKBARDEC = TRUE
  171.             Declare Library "taskbar"
  172.                 Function taskbar_height& ()
  173.                 Function taskbar_width& ()
  174.             End Declare
  175.         $End If
  176.         TaskbarHeight = taskbar_height&
  177.     $Else
  178.         TaskbarHeight = 0 'no function to get the value for Linux/Mac, so return 0 instead of an error
  179.     $End If
  180.  
  181. Function TaskbarWidth
  182.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  183.     $If WIN Then
  184.         $If TASKBARDEC = UNDEFINED Then
  185.             $Let TASKBARDEC = TRUE
  186.  
  187.             Declare Library "taskbar"
  188.             Function taskbar_height& ()
  189.             Function taskbar_width& ()
  190.             End Declare
  191.         $End If
  192.         TaskbarWidth = taskbar_width&
  193.     $Else
  194.         TaskbarWidth = 0 'no function to get the value for Linux/Mac, so return 0 instead of an error
  195.     $End If
  196.  
  197.  
  198. Function TitleBarHeight
  199.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  200.     $If BORDERDEC = UNDEFINED Then
  201.         $Let BORDERDEC = TRUE
  202.         Declare Library
  203.             Function glutGet& (ByVal what&)
  204.         End Declare
  205.     $End If
  206.     TitleBarHeight = glutGet(507)
  207.  
  208. Function BorderWidth
  209.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  210.     $If BORDERDEC = UNDEFINED Then
  211.         $Let BORDERDEC = TRUE
  212.         Declare Library
  213.         Function glutGet& (ByVal what&)
  214.         End Declare
  215.     $End If
  216.     BorderWidth = glutGet(506)

We start by building some rivers across the screen, which would be the lowest point on the map, and then we rise up to build terrain from that point outwards...    beach, plain, forest, hill, mountain, impassable mountains!

Some things to play around with here:

Rivers Int(Rnd * 10) + 1, Int(Rnd * 100) - 100, -3   -- First value is the number of rivers, second is how much they meander across the map, and the third is their starting depth.  Note that I haven't set any colors for a depth < -3.

In the fill sub, there's a section which you can play around with to increase density of various features:

    Select Case height
        Case Is < 0: RepeatChance = 33 'water repeat
        Case Is = 0: RepeatChance = 25 'beach repeat
        Case Is = 1: RepeatChance = 55 'grassland
        Case Is = 2: RepeatChance = 55 'forest
        Case Is = 3: RepeatChance = 40 ' hills
        Case Is = 4: RepeatChance = 33 'mountains
        Case Else
            RepeatChance = 50 - 3 * height
            If RepeatChance < 10 Then RepeatChance = 10
    End Select

The higher the numbers here, the more of the feature your map is going to have...

There's no Ocean on these maps, nor is there any lakes (I think lakes would be a nice addition, rather than just forcing multiple rivers to define the low points of the map), but I think this goes to show how I'd work on generating a map like this.   I'd start at the lowest point and then just expand outwards and upwards to my mountains.  ;)

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

NOTE: Grab the taskbar header file for proper sizing from here: https://www.qb64.org/forum/index.php?topic=1020.msg138058#msg138058
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 11, 2021, 01:27:44 am
Here I am building Contours about Random Points:
Code: QB64: [Select]
  1. _Title "Build Contours about Rnd Pts - zzz... press any, esc to quit"
  2. _ScreenMove 400, 60
  3. tile(1) = "."
  4. tile(2) = "~"
  5. tile(3) = "="
  6. tile(4) = "o"
  7. tile(5) = "#"
  8.  
  9. Width 80, 80
  10.  
  11.     Cls
  12.     nP = Rnd * 7 + 3
  13.     ReDim pX(1 To nP), pY(1 To nP)
  14.     For i = 1 To nP
  15.         pX(i) = Rnd * _Width * .9 + .05 * _Width
  16.         pY(i) = Rnd * _Height * .9 + .05 * _Height
  17.     Next
  18.  
  19.     For level = 1 To 5
  20.         For i = 1 To nP
  21.             If Rnd < .5 Then dir = -1 Else dir = 1
  22.             x = pX(i) + dir * (Rnd * (6 - level) * 2)
  23.             If Rnd < .5 Then dir = -1 Else dir = 1
  24.             y = pY(i) + dir * (Rnd * (6 - level) * 2)
  25.             r = (Rnd * (6 - level) * 3) + 5 * (6 - level)
  26.             For row = y - r To y + r
  27.                 For col = x - r To x + r
  28.                     If row >= 1 And row <= _Height Then
  29.                         If col > 1 And col <= _Width Then
  30.                             If Sqr(((col - x) ^ 2) + (row - y) ^ 2) <= r Then
  31.                                 Locate row, col: Print tile(level);
  32.                             End If
  33.                         End If
  34.                     End If
  35.                 Next
  36.             Next
  37.  
  38.         Next
  39.     Next
  40.     Sleep
  41.  
  42.  
  43.  

  [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 11, 2021, 01:31:53 am
Nice job Steve! but where is the Ascii? ;-))
Title: Re: ISO simple ASCII procedural terrain
Post by: bplus on November 11, 2021, 01:57:57 am
@SMcNeill

Here's feedback on where your screen ended up in my screen, the left side under my taskbar and the right side showing what's underneath about the width of the taskbar, beautiful image, your farm?

Title: Re: ISO simple ASCII procedural terrain
Post by: SMcNeill on November 11, 2021, 02:37:40 am
Nice job Steve! but where is the Ascii? ;-))

It's just a grid of a few various heights.  Map it to whatever ASCII colors/characters you want.  I used graphics so I could display it all.  ;)
Title: Re: ISO simple ASCII procedural terrain
Post by: SMcNeill on November 11, 2021, 02:40:10 am
@SMcNeill

Here's feedback on where your screen ended up in my screen, the left side under my taskbar and the right side showing what's underneath about the width of the taskbar, beautiful image, your farm?

I don't detect which border you have your taskbar snapped to, so just drag the screen right a bit for your display.  At least it seems properly sized right for everything.  ;)
Title: Re: ISO simple ASCII procedural terrain
Post by: SMcNeill on November 11, 2021, 07:21:07 am
Added Lakes into the mix.

Code: QB64: [Select]
  1. Const XSize = 200, YSize = 200
  2. Dim Shared As Long Grid(XSize, YSize)
  3.  
  4. DisplayScreen = MaxScreen
  5. Screen MaxScreen
  6.  
  7.  
  8.     InitializeMap
  9.     Lakecount = Int(Rnd * 4)
  10.     Lakes Lakecount, 400 - Lakecount * 100, 1000 - Lakecount * 300
  11.     Rivers Int(Rnd * 5) + 1, Int(Rnd * 100) - 100, -3
  12.  
  13.     GenerateTerrain
  14.  
  15.     DrawMap
  16.     Sleep
  17.  
  18. Sub InitializeMap
  19.     For x = 0 To XSize
  20.         For y = 0 To YSize
  21.             Grid(x, y) = -999 'default blank part of map
  22.         Next
  23.     Next
  24.  
  25.  
  26. Sub DrawMap
  27.     Dim kolor As _Unsigned Long
  28.     xscale = _Width / XSize
  29.     yscale = _Height / YSize
  30.     For x = 0 To XSize
  31.         For y = 0 To YSize
  32.             Select Case Grid(x, y)
  33.                 Case -3: kolor = DarkBlue 'Deep Water
  34.                 Case -2: kolor = Blue 'Water
  35.                 Case -1: kolor = SkyBlue 'Shallow Water
  36.                 Case 0: kolor = Tann 'beach/sand
  37.                 Case 1: kolor = Green 'grassland
  38.                 Case 2: kolor = DarkGreen 'forest
  39.                 Case 3: kolor = Gold 'hills
  40.                 Case 4: kolor = Purple 'mountains
  41.                 Case 5 TO 99: kolor = Red
  42.                 Case Else: kolor = Black
  43.             End Select
  44.             Line (x * xscale, y * yscale)-Step(xscale, yscale), kolor, BF
  45.     Next y, x
  46.  
  47.  
  48. Sub GenerateTerrain
  49.     Height = -3
  50.     Do Until finished
  51.         finished = -1
  52.         For x = 0 To XSize
  53.             For y = 0 To YSize
  54.                 If Grid(x, y) = Height Then Fill x, y, Height + 1: finished = 0
  55.             Next
  56.         Next
  57.         Height = Height + 1
  58.     Loop
  59.  
  60.  
  61. Sub Fill (x, y, height)
  62.     Select Case height
  63.         Case Is = -2: RepeatChance = 50 'water repeat
  64.         Case Is = -1: RepeatChance = 30 'shallow water repeat
  65.         Case Is = 0: RepeatChance = 25 'beach repeat
  66.         Case Is = 1: RepeatChance = 55 'grassland
  67.         Case Is = 2: RepeatChance = 55 'forest
  68.         Case Is = 3: RepeatChance = 50 ' hills
  69.         Case Is = 4: RepeatChance = 50 'mountains
  70.         Case Else
  71.             RepeatChance = 50 - 3 * height
  72.             If RepeatChance < 10 Then RepeatChance = 10
  73.     End Select
  74.     CurrentX = x
  75.     If CurrentX > 0 Then
  76.         If Grid(CurrentX - 1, y) = -999 Then
  77.             Grid(CurrentX - 1, y) = height
  78.             If Int(Rnd * 100) < RepeatChance Then Fill CurrentX - 1, y, height
  79.         End If
  80.     End If
  81.     CurrentX = x
  82.     If CurrentX < XSize Then
  83.         If Grid(CurrentX + 1, y) = -999 Then
  84.             Grid(CurrentX + 1, y) = height
  85.             If Int(Rnd * 100) < RepeatChance Then Fill CurrentX + 1, y, height
  86.         End If
  87.     End If
  88.     CurrentY = y
  89.     If CurrentY > 0 Then
  90.         If Grid(x, CurrentY - 1) = -999 Then
  91.             Grid(x, CurrentY - 1) = height
  92.             If Int(Rnd * 100) < RepeatChance Then Fill x, CurrentY - 1, height
  93.         End If
  94.     End If
  95.     CurrentY = y
  96.     If CurrentY < YSize Then
  97.         If Grid(x, CurrentY + 1) = -999 Then
  98.             Grid(x, y + 1) = height
  99.             If Int(Rnd * 100) < RepeatChance Then Fill x, CurrentY + 1, height
  100.         End If
  101.     End If
  102.  
  103. Sub Lakes (Number, MinSize, MaxSize)
  104.     For i = 1 To Number
  105.         x = Int(Rnd * XSize): y = Int(Rnd * YSize)
  106.         LakeSize = Int(Rnd * (MaxSize - MinSize)) + MinSize
  107.         LakeBuilt = 0
  108.         Do Until LakeBuilt >= LakeSize
  109.             xchange = 0: ychange = 0
  110.             Do
  111.                 Do
  112.                     xchange = Int(Rnd * 3) - 1
  113.                 Loop Until x + xchange > 0 And x + xchange < XSize
  114.                 Do
  115.                     ychange = Int(Rnd * 3) - 1
  116.                 Loop Until y + ychange > 0 And y + ychange < YSize
  117.             Loop Until xchange <> 0 And ychange <> 0
  118.             repeat:
  119.             If x + xchange < 0 Or x + xchange > XSize Then xchange = -xchange
  120.             If y + ychange < 0 Or y + ychange > YSize Then ychange = -ychange
  121.             If Grid(x + xchange, y + ychange) = -999 Then
  122.                 Grid(x + xchange, y + ychange) = -3
  123.                 LakeBuilt = LakeBuilt + 1
  124.                 x = x + xchange: y = y + ychange
  125.             Else
  126.                 flip = Int(Rnd * 2)
  127.                 If flip Then xchange = xchange * 2 Else ychange = ychange * 2
  128.                 GoTo repeat
  129.             End If
  130.         Loop
  131.     Next
  132.  
  133. Sub Rivers (Number, Meander, Deep)
  134.     For i = 1 To Number
  135.         flip1 = Int(Rnd * 2): flip2 = Int(Rnd * 2)
  136.         If flip1 Then 'entry point is on top
  137.             x1 = Int(Rnd * XSize): y1 = 0
  138.         Else 'entry point is on left
  139.             x1 = 0: y1 = Int(Rnd * YSize)
  140.         End If
  141.         If flip2 Then 'exit point is on bottom
  142.             x2 = Int(Rnd * XSize): y2 = YSize
  143.         Else 'exit point is on right
  144.             x2 = XSize: y2 = Int(Rnd * YSize)
  145.         End If
  146.  
  147.         Grid(x1, y1) = Deep: Grid(x2, y2) = Deep
  148.         StartX = x1: StartY = y1: EndX = x2: EndY = y2 'just to preserve our original values, if needed.
  149.         Do Until StartX = EndX And StartY = EndY
  150.             CoinToss = Int(Rnd * 100) 'Coin toss to move left/right or up/down, to go towards exit, or wander a bit.
  151.             Meander = 10
  152.             If CoinToss Mod 2 Then 'even or odd, so we only walk vertical or hortizontal and not diagional
  153.                 If CoinToss < 100 - Meander Then 'Lower values meander less and go directly to the target.
  154.                     XChange = Sgn(EndX - StartX) '-1,0,1, drawn always towards the mouse
  155.                     Ychange = 0
  156.                 Else
  157.                     XChange = Int(Rnd * 3) - 1 '-1, 0, or 1, drawn in a random direction to let the lightning wander
  158.                     Ychange = 0
  159.                 End If
  160.             Else
  161.                 If CoinToss < 100 - Meander Then 'Lower values meander less and go directly to the target.
  162.                     Ychange = Sgn(EndY - StartY)
  163.                     XChange = 0
  164.                 Else
  165.                     Ychange = Int(Rnd * 3) - 1
  166.                     XChange = 0
  167.                 End If
  168.             End If
  169.             StartX = StartX + XChange
  170.             StartY = StartY + Ychange
  171.             If StartX < 0 Then StartX = 0 'Make certain we move inside the bounds of our map dimensions
  172.             If StartY < 0 Then StartY = 0
  173.             If StartX > XSize Then StartX = XSize
  174.             If StartY > YSize Then StartY = YSize
  175.             Grid(StartX, StartY) = Deep 'place a river where we moved to
  176.         Loop
  177.     Next
  178.  
  179.  
  180.  
  181.  
  182.  
  183. Function MaxScreen
  184.     DH = _DesktopHeight: DW = _DesktopWidth
  185.     TBH = TaskbarHeight: TBW = TaskbarWidth
  186.     TH = TitleBarHeight: BW = BorderWidth
  187.     If TBH = DH Then TBH = 0 'Users taskbar is configured vertical, not hortizonal.
  188.     If TBW = DW Then TBW = 0
  189.     MaxScreen = _NewImage(DW - TBW - 2 * BW, DH - TBH - TH - BW * 2, 32)
  190.  
  191. Sub ScreenMove (x, y)
  192.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  193.     _ScreenMove x - BorderWidth, y - BorderWidth - TitleBarHeight
  194.  
  195. Sub ScreenMove_Middle
  196.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  197.     _ScreenMove (_DesktopWidth - _Width - BorderWidth) / 2 + 1, (_DesktopHeight - _Height - BorderWidth) / 2 - TitleBarHeight + 1
  198.  
  199. Function TaskbarHeight
  200.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  201.  
  202.     $If WIN Then
  203.         $If TASKBARDEC = UNDEFINED Then
  204.             $Let TASKBARDEC = TRUE
  205.             Declare Library "taskbar"
  206.                 Function taskbar_height& ()
  207.                 Function taskbar_width& ()
  208.             End Declare
  209.         $End If
  210.         TaskbarHeight = taskbar_height&
  211.     $Else
  212.         TaskbarHeight = 0 'no function to get the value for Linux/Mac, so return 0 instead of an error
  213.     $End If
  214.  
  215. Function TaskbarWidth
  216.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  217.     $If WIN Then
  218.         $If TASKBARDEC = UNDEFINED Then
  219.             $Let TASKBARDEC = TRUE
  220.  
  221.             Declare Library "taskbar"
  222.             Function taskbar_height& ()
  223.             Function taskbar_width& ()
  224.             End Declare
  225.         $End If
  226.         TaskbarWidth = taskbar_width&
  227.     $Else
  228.         TaskbarWidth = 0 'no function to get the value for Linux/Mac, so return 0 instead of an error
  229.     $End If
  230.  
  231.  
  232. Function TitleBarHeight
  233.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  234.     $If BORDERDEC = UNDEFINED Then
  235.         $Let BORDERDEC = TRUE
  236.         Declare Library
  237.             Function glutGet& (ByVal what&)
  238.         End Declare
  239.     $End If
  240.     TitleBarHeight = glutGet(507)
  241.  
  242. Function BorderWidth
  243.     Do Until _Width <> 0 And _ScreenExists = -1: Loop
  244.     $If BORDERDEC = UNDEFINED Then
  245.         $Let BORDERDEC = TRUE
  246.         Declare Library
  247.         Function glutGet& (ByVal what&)
  248.         End Declare
  249.     $End If
  250.     BorderWidth = glutGet(506)

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

  [ This attachment cannot be displayed inline in 'Print Page' view ]  

I've got to admit, I think some of these end up looking rather nice.  (Of course, since almost everything is random here, some of these end up looking like complete garbage to me as well.)

Keep in mind, I'm creating massive 200 x 200 world maps with the settings the way I currently have them.  Also note, the actual game would probably be at a much larger scale with only small portions of it viewable by the player at a time.   I also don't know if I'd bother to use so many colors for water... Probably just shallow water (where you can wade in it) and deep water (where a boat travels) would be good enough.  My thinking behind 3 levels of water here was basically ocean ship, canoe/raft/shallow drag boat, and then wading/shallow water.

Anywho...   I'd call this a decent shot at a random terrain generator.  It doesn't follow any basic rules of logic, but it's decent enough I'm not ashamed to share it.  :P

If I was serious about this thing, I'd probably start at my mountains and then flow down to my oceans and not backwards like I did in this attempt, as that seems like it'd generate a more natural water flow from high to low.  I'd also try to work in things like temperature zones for the polar regions, and deserts for places which are too far away from any major source of water and would normally be plains instead.

Enough to showcase the basic idea behind things here, but it can definitely be expanded on if someone was wanting to.  ;D
Title: Re: ISO simple ASCII procedural terrain
Post by: xra7en on November 11, 2021, 11:07:49 pm
still....

you have something there.

gonna tinker with it, and post a couple of images. I think this might work for what I am looking for. Will have to do a little converting to ASCII (piece o cake :P)

wonder how Nox got MC almost perfect generating land! ??