>Terrain-CE on GitHub<

>>Download v1.0 From The Archives!<<

So I've started gradually programming a bit more lately and here's my latest bored experiment.

I don't know if you'd call this perlin noise or not, but I made some code last night that randomly generates smooth(ish) terrain, or perhaps you might just call it a height map, using a matrix and height values in each element.

The main idea for the code is that it will generate a map where each block that is next to each other will be no more than 1 block higher or lower than the block next to it. After getting that to work, I implemented a smoothing algorithm that looks for single block dips or spikes and flattens them so they are the same height as the blocks around them.

I also limited it to only 6 height values bc of the ti-basic colors, I used white thru black but replaced the white with light blue, or you might imagine it as water. Black areas are high, blue is low.

Here's the (unoptimized) code, if you would like to optimize it be my guest:

Code:
//Initialize
ClrHome
Float
0->Xmin:264->Xmax
~164->Ymin:0->Ymax
Input N //Input map size
DelVar [A]{N,N->dim([A]
randInt(20,25->[A](1,1 //Generate random height for first element
~1->C //flag variable used for start of program only

//Progress Bar Variables
100/(2N-2->G
Ans->P

//Generate Map
For(A,1,N
   Output(2,1,toString(int(P))+"%" //Display progress
   P+G->P
   For(B,1,N
      If C=~1
      DelVar C2->B
      If A=1
      [A](A,B-1)+randInt(~1,1->R
      If A>1 and B=1
      [A](A-1,B)+randInt(~1,1->R
      If A>1 and B>1
      Then
         If [A](A,B-1)!=[A](A-1,B
         Then
            int(median({[A](A,B-1),[A](A-1,B->R
         Else
            [A](A,B-1)+randInt(~1,1->R
         End
      End
      If R<20:20->R
      If R>25:25->R
      R->[A](A,B
   End
End

//Smoothing Code
//Smooth Corners
If [A](1,1)!=[A](2,1) and [A](2,1)=[A](1,2
[A](2,1)->[A](1,1
If [A](1,N)!=[A](2,N) and [A](2,N)=[A](1,N-1
[A](2,N)->[A](1,N
If [A](N,1)!=[A](N,2) and [A](N,2)=[A](N-1,1
[A](N,2)->[A](N,1
If [A](N,N)!=[A](N-1,N) and [A](N-1,N)=[A](N,N-1
[A](N-1,N)->[A](N,N

//Smooth Edges
For(C,2,N-1
   If [A](1,C)!=[A](1,C-1) and not(variance({[A](1,C-1),[A](2,C),[A](1,C+1
   [A](1,C-1)->[A](1,C
End
For(C,2,N-1
   If [A](C,1)!=[A](C-1,1) and not(variance({[A](C-1,1),[A](C,2),[A](C+1,1
   [A](C-1,1)->[A](C,1
End
For(C,2,N-1
   If [A](C,N)!=[A](C-1,N) and not(variance({[A](C-1,N),[A](C,N-1),[A](C+1,N
   [A](C-1,N)->[A](C,N
End
For(C,2,N-1
   If [A](N,C)!=[A](N,C-1) and not(variance({[A](N,C-1),[A](N-1,C),[A](N,C+1
   [A](N,C-1)->[A](N,C
End

//Smooth everything else on the inside
For(A,2,N-1
   Output(2,1,toString(int(P))+"%"
   P+G->P
   For(B,2,N-1
      If [A](A,B)!=[A](A-1,B) and not(variance({[A](A-1,B),[A](A+1,B),[A](A,B-1),[A](A,B+1)
      [A](A-1,B)->[A](A,B
   End
End

//Draw Map
ClrHome
ClrDraw
For(B,0,N-1
   For(A,0,N-1
      [A](A+1,B+1
      Ans-13(Ans=25)-2(Ans=20
      Pt-On(7A+3,~7B-3,1,Ans
      Pt-On(7A+3,~7B-3,2,Ans
   End
End


With that said, here's an example with a 20x20 map:



The limitations with this code is that of course the matrix can be no larger than 20x20, so perhaps converting storage to a string or list might work better. There's also no way to implement caves or anything else at the moment. It would be cool to represent this in a 3d space (like an isometric view perhaps) but for the moment this is just a demo/experiment.

It's not the best of course, I definitely think I could optimize the smoothing code. But I hope you like it!
It looks pretty good so far. Would you mind if I ported this code?
beckadamtheinventor wrote:
It looks pretty good so far. Would you mind if I ported this code?

Thanks! What are you porting it for?
Hey this is pretty neat.
Cool stuff! AKSHUALLY (pushes glasses up nose), if you're interpolating the dot products of a grid of gradient vectors, it is indeed Perlin Noise; otherwise it's a general noise-based heightmap algorithm.

Planning to do anything specific with it?
Michael2_3B wrote:
beckadamtheinventor wrote:
It looks pretty good so far. Would you mind if I ported this code?

Thanks! What are you porting it for?

ez80 assembly. I ended up going with a similar algorithm to yours, but a tad easier to create in assembly.
Randomizes a 2d map, then smooths each map unit with every other adjacent map unit with the equation A = (A+((A+B)>>1))>>1, which is equivalent to (A*3+B)>>2, according to my math.
KermMartian wrote:
Cool stuff! AKSHUALLY (pushes glasses up nose), if you're interpolating the dot products of a grid of gradient vectors, it is indeed Perlin Noise; otherwise it's a general noise-based heightmap algorithm.

Planning to do anything specific with it?

Good to know. I don't plan on much at the moment, but I will continue to experiment with it more and perhaps add a simple terrain/matrix editor.

beckadamtheinventor wrote:
Michael2_3B wrote:
beckadamtheinventor wrote:
It looks pretty good so far. Would you mind if I ported this code?

Thanks! What are you porting it for?

ez80 assembly. I ended up going with a similar algorithm to yours, but a tad easier to create in assembly.
Randomizes a 2d map, then smooths each map unit with every other adjacent map unit with the equation A = (A+((A+B)>>1))>>1, which is equivalent to (A*3+B)>>2, according to my math.

Sounds cool! I look forward to seeing what you are creating.
Ok, so I spent today working on the isometric view, and here's what I came up with:



It's not the clearest image you'll ever see, but you can see how I've drawn the individual cubes at different heights for each matrix value.

Here is that same terrain from top down:


And a full run-through of the programs (Note: I added a rand seeder to the original code btw)


And here's the isometric display code I came up with:

Code:
ClrDraw
15/8->R
For(A,1,16
   ~80-R(A-1->S
   132-6A->T
   For(B,1,16
      [A](B,A)-19->V
      18+Ans-(Ans=1)+(Ans>1)-13(Ans=6->C
      T+6B->X
      S-BR->Z
      V-1->W
      Line(X+6,Z+6W-R,X,Z+6W-2R,C
      Line(X-6,Z+6W-R,X,Z+6W-2R,C
      Line(X-6,Z+6V-R,X-6,Z+6W-R,C
      Line(X+6,Z+6V-R,X+6,Z+6W-R,C
      Line(X,Z+6V-2R,X,Z+6W-2R,C
      Line(X,Z+6V,X-6,Z+6V-R,C
      Line(X,Z+6V,X+6,Z+6V-R,C
      Line(X-6,Z+6V-R,X,Z+6V-2R,C
      Line(X+6,Z+6V-R,X,Z+6V-2R,C
   End
End

A small note, but you'll also notice that I'm not drawing 3 of the lines that would supposedly be on the back side of the cubes.

Once again, this is still just a fun side experiment of mine, but make sure to download the program from the repository if you want to try it out:
https://github.com/Michael2-3B/Terrain-CE/tree/master
Michael2_3B wrote:

And here's the isometric display code I came up with:

Code:
ClrDraw
15/8->R
For(A,1,16
   ~80-R(A-1->S
   132-6A->T
   For(B,1,16
      [A](B,A)-19->V
      18+Ans-(Ans=1)+(Ans>1)-13(Ans=6->C
      T+6B->X
      S-BR->Z
      V-1->W
      Line(X+6,Z+6W-R,X,Z+6W-2R,C
      Line(X-6,Z+6W-R,X,Z+6W-2R,C
      Line(X-6,Z+6V-R,X-6,Z+6W-R,C
      Line(X+6,Z+6V-R,X+6,Z+6W-R,C
      Line(X,Z+6V-2R,X,Z+6W-2R,C
      Line(X,Z+6V,X-6,Z+6V-R,C
      Line(X,Z+6V,X+6,Z+6V-R,C
      Line(X-6,Z+6V-R,X,Z+6V-2R,C
      Line(X+6,Z+6V-R,X,Z+6V-2R,C
   End
End

These small optimizations would be approximately 42% faster.

Code:
ClrDraw
1.875->PMT
For(A,1,Brown
   ~80-PMT(A-1->Tmin
   132-6A->Tmax
   For([recursiven],1,Brown
      [A]([recursiven],A)-Yellow->|P/Y
      Navy+|P/Y+2(|P/Y>1)-Magenta(|P/Y=6->PV
      Tmax+[recursiven]6->|N
      Tmin-PMT[recursiven]-PMT+6(|P/Y-1->I%
      Tmin-PMT[recursiven]+|P/Y6-PMT->FV
      |N+6
      Line(Ans,I%,|N,I%-PMT,PV
      Line(|N-6,I%,|N,I%-PMT,PV
      Line(|N-6,FV,|N-6,I%,PV
      Line(Ans,FV,Ans,I%,PV
      Line(|N,FV-PMT,|N,I%-PMT,PV
      Line(|N,FV+PMT,|N-6,FV,PV
      Line(|N,FV+PMT,Ans,FV,PV
      Line(|N-6,FV,|N,FV-PMT,PV
      Line(Ans,FV,|N,FV-PMT,PV
   End
End

I don't usually throw in those system variable optimizations because its only about 0.5ms per use and it bloats the program, but since the inner loop gets called 256 times, it makes a difference.
Also, using the colors makes almost no difference at all, but all together, it saves about 83ms. And makes the code considerably less readable
Could you combine both codes, so a top-down view is in the top left corner, and a iso is in the center?
mr womp womp wrote:
This small optimization would save some bytes and be approximately 25% faster.

Thanks, that works great!

KosmicCyclone wrote:
Could you combine both codes, so a top-down view is in the top left corner, and a iso is in the center?

I sure can, I'd have to see how small I have to make the top-down view though. I'll update you on that later
Okay cool. Also, if you had used both iPart( and fPart( and had a second set of values as a decimal, you could double how much you could do with a single matrix. might be hard to figure out how to do that though...
KosmicCyclone wrote:
Okay cool. Also, if you had used both iPart( and fPart( and had a second set of values as a decimal, you could double how much you could do with a single matrix. might be hard to figure out how to do that though...

That’s pretty simple actually, however for the way I’m currently displaying the map I’d either not have enough room or the blocks would be quite small if I were to double the size.

I could easily have a much much larger map though if I were to store height values in a string. A string is 1 dimensional, but if you have the map dimensions you can just split it up to get your different rows
The isometric view looks awesome!

Also for BASIC this runs really nicely too Smile.
mr womp womp wrote:
I don't usually throw in those system variable optimizations because its only about 0.5ms per use and it bloats the program, but since the inner loop gets called 256 times, it makes a difference. And makes the code considerably less readable

Haha, I just noticed you used all those finance variables and such. Indeed it does make the code quite unreadable which is why I've chosen not to use them currently, but I'll have to test those optimizations out for myself in a bit.

I've made quite a few changes in the last 12 hours, some tiny tweaks in the generator program (read: you can generate a random map by putting 0 for the seed, and each seed can be seen in theta), but also a bunch of graphics improvements in the rendering program. I haven't combined them yet, but I'll get to that eventually. I've updated and organized the GitHub so you can check out the code and program there.

The previous graphics were so 12 hours ago.

Check out this beach:


And this pyramid of sorts with openings on each side and the top:


And here you can watch it render in real-time (about 1m34s):


You'll notice I added the minimap in the corner Smile I like how the pyramid looks on that.

Render code:

Code:
ClrDraw
2->R
16->N
BackgroundOn DARKGRAY

//Draw MiniMap
RED
Line(3,~3,3,~52,Ans,1
Line(3,~3,52,~3,Ans,1
Line(3,~52,52,~52,Ans,1
Line(52,~3,52,~52,Ans,1
For(B,0,N-1
   For(A,0,N-1
      [A](A+1,B+1
      Ans-13(Ans=25)-2(Ans=20
      Pt-On(3A+5,~3B-5,1,Ans
   End
End

//Draw Isometric Terrain
For(A,1,BROWN //substituting values in For loops with colors
   ~80-R(A-1->S
   132-6A->T
   For(B,1,BROWN
      [A](B,A)-19->V
      BROWN+2(Ans<2)+3(Ans=2->C
      BLACK-2(Ans=LTBLUE->O
      If randInt(0,1) and V>2
      MEDGRAY->C
      T+6B->X
      S-BR-R+6(V-1->Z
      S-BR+6V-R
      
      //Fill Box
      For(I,Z-R+1,Ans+R-2
         Line(X-5,I,X+5,I,C,1
      End
      
      //Complete rest of fill at top
      Line(X-2R,Ans+R-2,X+2R,Ans+R-2,C,1
      Line(X-R,Ans+R-1,X+R,Ans+R-1,C,1
      
      //Draw grass
      If V>2 and C!=MEDGRAY
      Then
         For(I,0,3,.2
            Line(X-6+2I,Ans-I,X+2I,Ans+R-I,GREEN,1
         End
      End
      
      //Draw main vertical edge facing camera
      Line(X,Z-R,X,Ans-R,O,1
      
      //Other edges
      For(I,~6,6,BLACK
         Line(X+I,Z,X,Z-R,O,1
         Line(X+I,Ans,X+I,Z,O,1
         Line(X,Ans+R,X+I,Ans,O,1
         Line(X+I,Ans,X,Ans-R,O,1
      End
   End
End


The only noticeably slower part of this now is drawing the grass, but I hope you like the developments! I've also kind of found a way to rotate the map up and down by changing the value in R, but I'd have to fix some of the graphics with that.
That's pretty dang cool Smile Can't wait to see what you do next with this. Smile
We have stumbled upon a complete madman Very Happy
Fantastic work! Just for the record with a seed of 1337:
    My revision Pre-A CE finished in 1:35
    My revision Pre-A CE with reduced wait states took 1:26 (10% faster)
    My revision M CE took 46 seconds (52% faster)
    EDIT: My revision M CE with your optimization took 44 seconds! (54% faster)
    EDIT 2: My revison M CE with womp's optimizations only took 31 seconds! (67% faster)

That's pretty quick for a BASIC program. I'd love to see this written in C!
TheLastMillennial wrote:
Fantastic work! Just for the record with a seed of 1337:
    My revision Pre-A CE finished in 1:35
    My revision Pre-A CE with reduced wait states took 1:26 (10% faster)
    My revision M CE only took 46 seconds! (48% faster)

Nice work! There will be some variance in the render times because grass takes a tiny bit longer and I'm alternating the generation with stone and stuff.

TheLastMillennial wrote:
I'd love to see this written in C!

But CE C is pointless now isn't it? Razz

EDIT:
You can get a speed boost on the grass if you change the .2 in "For(I,0,3,.2" to .249

EDIT 2:
I timed things on my "normal" CE (clearly yours is better than mine):
1:25 for a matrix filled with 20s or any other map that doesn't have grass
2:23 for a map that is only grass
I'll do some optimizations and stuff with finance variables now and see what I get
I think it would be cool to have a render option that turns off the rendering of lines between blocks that are both on the same level and are the same type, so you only have lines between block types and at vertices.

Edit: Oh my goodness, I just had an idea. This is a great opportunity to use my TI-BASIC RTX code I made a few months ago and never finished! I'm gonna try to throw together a raytraced rendering engine for this program.
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 2
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement