Author Topic: Random Textured Rolling Hills  (Read 9211 times)

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
Random Textured Rolling Hills
« on: 2012-May-16 »
This will generate random, endless rolling hills.
It scrolls into/out of view at a specified speed.

Points that scroll off the screen (to the left) are removed from the array.
When a new hill is needed, it creates one (toggling the direction up or down).
It uses this new hill (really just a height value) and slices up the hill horizontally into segments.
It will scroll this new hill into view, then repeat endlessly.
In memory, the array should only have enough segment slices to fill the screen, plus a bit before, and the next hill yet to be shown.

Controls:
[<-] - Cursor Left - Decrease Speed (by 0.05)
[->] - Cursor Right - Increase Speed (by 0.05)
[1] - Change display mode to 'MODE_TEXTURE'
[2] - Change display mode to 'MODE_TEXTURE_WIRE'
[3] - Change display mode to 'MODE_WIRE'
[4] - Change display mode to 'MODE_POLYGON'
[5] - Change display mode to 'MODE_SOLID'
(The display modes are explained in the source code, nothing much really, just for debugging)

I'm not a graphics guy, so I just whipped up a sample texture to demo this.
If you notice the light brown bottom dirt border, and if you switch to 'MODE_TEXTURE_WIRE', the middle line follows this dirt border.
(This is configurable in code by a percentage - it is set to 25%)

While this may not affect the display too much, you can use the mid-line coordinates to wire up a physics engine and use that line for the colliders.
(It does affect the display a bit, kinda confusing, check out the code where ever I used that variable).

I tried commenting the code, but I ran out of time.  May update it later.
I attached the png texture I used.
And I zipped up the project too.
I hope it works, I'm in a rush!

Notes:
- a 'hill' is just the x/y coordinates of a peak or valley
- segments are how I slice up the hill and use a COSINE function to provide the rolling effect
- when the texture runs out, I just start it over again, but it may not have fully displayed the full texture, so when it joins with the next segment, it may not join up nicely - not sure how to get around this
- play with the hill settings, but if it is too much of a slope, the polygons will overlap, I could provide a work around, but it is simpler to just live with this constraint

RollingHills.gbas
Code: GLBasic [Select]
GLOBAL sx%, sy%
GLOBAL speed# = 4.0
GLOBAL draw_mode% = MODE_TEXTURE
GLOBAL sp_texture%

GLOBAL hills AS THillPoints
GLOBAL hills2 AS THillPoints
Main()
END

FUNCTION Main:
        SYSTEMPOINTER TRUE
        GETSCREENSIZE sx, sy
        SEEDRND MID$(PLATFORMINFO$("time"), 17, 2)
        LIMITFPS 60
        IF NOT SETCURRENTDIR("Media")
                DEBUG "Media Folder Not Found . . . Exiting!\n"
                END
        ENDIF


        // Initialize 'hill' TYPE
        sp_texture = GENSPRITE()
        LOADSPRITE "grass.png", sp_texture // Load texture
        hills.sp_texture = sp_texture
        hills.x_width = 15                                                                                                              // How wide each section strip is, the wider, the more 'chunky' looking hills
        GETSPRITESIZE sp_texture, hills.texture_width, hills.texture_height             // Sprite size of the ground texture
        hills.texture_ht_up = hills.texture_height * 0.75                                               // How tall to make the top portion
        hills.texture_ht_dn = hills.texture_height * 0.25                                               // How tall to make the bottom portion (together should add to 1.0)
        hills.x_change_min = 180                                                                                                // When creating a new hill peak, it must be at LEAST this distance from previous
        hills.x_change_max = 220                                                                                                // When creating a new hill peak, it must be at MOST this distance from previous
        hills.y_change_min = 50                                                                                                 // When creating a new hill peak, the peak must be at LEAST this much higher/lower
        hills.y_change_max = 190                                                                                                // When creating a new hill peak, the peak must be at MOST this much higher/lower
        hills.y_min = sy * 0.40                                                                                                 // Keep hills below top 20% of screen
        hills.y_max = sy * 0.95                                                                                                 // Keep hills above bottom 5% of screen
        hills.rgb_bottom = RGB(100,60,20)
        GenerateHills(hills)                                                                                                    // Initial seeding of hills to fill screen at start

        // Initialize 'hill2' TYPE
        sp_texture = GENSPRITE()
        LOADSPRITE "snow.png", sp_texture // Load texture
        hills2.sp_texture = sp_texture
        hills2.x_width = 25                                                                                                             // How wide each section strip is, the wider, the more 'chunky' looking hills
        GETSPRITESIZE sp_texture, hills2.texture_width, hills2.texture_height   // Sprite size of the ground texture
        hills2.texture_ht_up = hills2.texture_height * 0.25                                             // How tall to make the top portion
        hills2.texture_ht_dn = hills2.texture_height * 0.75                                             // How tall to make the bottom portion (together should add to 1.0)
        hills2.x_change_min = 220                                                                                               // When creating a new hill peak, it must be at LEAST this distance from previous
        hills2.x_change_max = 280                                                                                               // When creating a new hill peak, it must be at MOST this distance from previous
        hills2.y_change_min = 70                                                                                                // When creating a new hill peak, the peak must be at LEAST this much higher/lower
        hills2.y_change_max = 220                                                                                               // When creating a new hill peak, the peak must be at MOST this much higher/lower
        hills2.y_min = sy * 0.15                                                                                                // Keep hills below top 20% of screen
        hills2.y_max = sy * 0.60                                                                                                // Keep hills above bottom 5% of screen
        hills2.rgb_bottom = RGB(30,45,60)
        GenerateHills(hills2)                                                                                                   // Initial seeding of hills to fill screen at start

        // Main Loop
        WHILE TRUE
                // Speed: "<-" and "->" cursor to decrease / increase
                IF KEY(203)
                        DEC speed, 0.05
                        IF speed < 0.1 THEN speed = 0.1
                ELSEIF KEY(205)
                        INC speed, 0.05
                        IF speed > 20 THEN speed = 20
                ENDIF

                // Draw Mode: Good for see what is happening behind the scenes
                LOCAL key_hit$
                key_hit$ = INKEY$()
                SELECT key_hit$
                CASE "1"
                        draw_mode = MODE_TEXTURE
                CASE "2"
                        draw_mode = MODE_TEXTURE_WIRE
                CASE "3"
                        draw_mode = MODE_WIRE
                CASE "4"
                        draw_mode = MODE_POLYGON
                CASE "5"
                        draw_mode = MODE_SOLID
                ENDSELECT

                CLEARSCREEN RGB(0,100,220)                      // Blue background - azure
                ALPHAMODE -1.0                                          // In case your texture has alpha values
                SMOOTHSHADING FALSE                                     // Don't pixelate the graphics
                hills2.Draw(draw_mode)                          // Draw current hills using current draw mode
                hills2.Scroll(speed*0.3)                        // Scroll the hills left based on speed - if needed, a new hill will be generated
                hills.Draw(draw_mode)                           // Draw current hills using current draw mode
                hills.Scroll(speed)                                     // Scroll the hills left based on speed - if needed, a new hill will be generated
                SHOWSCREEN
        WEND
ENDFUNCTION

FUNCTION GenerateHills: hill AS THillPoints
        hill.Clear()

        WHILE hill.hill_next.x < (sx + hill.x_change_max)
                hill.GenerateNewHill()
        WEND
ENDFUNCTION

types.gbas
Code: GLBasic [Select]
CONSTANT MODE_TEXTURE% = 1                      // Normal textured display
CONSTANT MODE_TEXTURE_WIRE% = 2         // Wire outline overlayed on textured display
CONSTANT MODE_WIRE% = 3                         // Wire outine of all calculated vectors
CONSTANT MODE_SOLID% = 4                        // Fills in quads will solid colour - kinda neat when fast!
CONSTANT MODE_POLYGON% = 5                      // Same as 'SOLID', except shades each polygon to see each polygon

CONSTANT PI = 3.14159

// General vector routine, makes other code cleaner
TYPE TVector
        x#
        y#

        FUNCTION Set: x#, y#
                self.x = x
                self.y = y
        ENDFUNCTION

        FUNCTION Copy: v AS TVector
                self.x = v.x
                self.y = v.y
        ENDFUNCTION

        FUNCTION Scale: amount#
                self.x = self.x * amount
                self.y = self.y * amount
        ENDFUNCTION

        FUNCTION AverageWith AS TVector: v AS TVector
                LOCAL rv AS TVector
                rv.x = (self.x + v.x) / 2.0
                rv.y = (self.y + v.y) / 2.0
                RETURN rv
        ENDFUNCTION

        // Calc the magnitude / length of a vector
        FUNCTION Magnitude#:
           RETURN SQR((self.x * self.x) + (self.y * self.y))
        ENDFUNCTION
ENDTYPE

// A hill point is a point along the curved hill, a new one is generated every 'self.x_width' pixels
TYPE THillPoint
        pu AS TVector                                   // Higher point - used for top portion of texture (grass)
        pm AS TVector                                   // Base/mid point - good to use for physics engine as the 'contact' location
        pd AS TVector                                   // Lower point - used for the bottom portion of texture (dirt border)
        texture_x#                                              // How far along texture this point is
ENDTYPE

TYPE THillPoints
        points[] AS THillPoint                  // All of the points along all of the hills
        x_width%                                                // How far between curve segments (the more, the smoother the curve)
        texture_height#                                 // How tall the ground texture is
        texture_ht_up#                                  // How tall the ground texture is - above the base point
        texture_ht_dn#                                  // How tall the ground texture is - below the base point
        texture_width#                                  // How wide the ground texture is
        y_min%                                                  // How high up the screen a hill peak can reach
        y_max%                                                  // How low on the screen a hill valley can reach
        x_change_min%                                   // New hill peaks/valleys must be at least this 'x' distance from previous
        x_change_max%                                   // New hill peaks/valleys must be at most this 'x' distance from previous
        y_change_min%                                   // New hills must be at least this far above or below
        y_change_max%                                   // New hills must be at most this far above or below
        peak_valley_toggle%                             // Remember if previous hill was a peak or a valley, toggle each time
        sp_texture%                                             // Sprite ID of hill top texture
        rgb_bottom%                                             // Colour below the curve and texture (the bottom dirt colour)

        hill_prev AS TVector                    // Used when calculating new hills
        hill_next AS TVector                    // The current hill vector will be stored here

        // Used to clear / initialize the data
        FUNCTION Clear:
                LOCAL y_adjust% = 30            // Used to make sure we don't start too high or too low
                DIM self.points[0]                      // Clear previous points
                self.hill_next.Set(0, RND(self.y_max - self.y_min - (y_adjust * 2)) + self.y_min + y_adjust)    // Initialize 'hill_next' at a random valid 'y' pos
                self.hill_prev.Set(0, 0)                                                                                                                                                // Initialize 'hill_prev'
        ENDFUNCTION

        // Draw current hill points - various draw modes are available
        FUNCTION Draw: mode% = MODE_TEXTURE
                LOCAL hx%
                LOCAL xy[] AS TVector
                LOCAL uv[] AS TVector

                SELECT mode

                CASE MODE_WIRE
                        FOR hx = 1 TO LEN(self.points[]) - 1
                                DRAWLINE self.points[hx-1].pu.x, self.points[hx-1].pu.y, self.points[hx].pu.x, self.points[hx].pu.y, RGB(255,255,255)
                                DRAWLINE self.points[hx-1].pm.x, self.points[hx-1].pm.y, self.points[hx].pm.x, self.points[hx].pm.y, RGB(255,255,255)
                                DRAWLINE self.points[hx-1].pd.x, self.points[hx-1].pd.y, self.points[hx].pd.x, self.points[hx].pd.y, RGB(255,255,255)
                                DRAWLINE self.points[hx].pu.x,   self.points[hx].pu.y,   self.points[hx].pd.x, self.points[hx].pd.y, RGB(255,255,255)
                        NEXT

                CASE MODE_POLYGON
                        STARTPOLY -1, 2
                        FOR hx = 1 TO LEN(self.points[]) - 1
                                PolyQuick(self.points[hx-1].pu, self.points[hx].pu, self.points[hx-1].pd, self.points[hx].pd, RGB(250,175,0), RGB(175,120,0))
                        NEXT
                        ENDPOLY

                CASE MODE_SOLID
                        STARTPOLY -1, 2
                        FOR hx = 1 TO LEN(self.points[]) - 1
                                PolyQuick(self.points[hx-1].pu, self.points[hx].pu, self.points[hx-1].pd, self.points[hx].pd, RGB(250,180,0), RGB(250,180,0))
                        NEXT
                        ENDPOLY

                CASE MODE_TEXTURE
                        DIM xy[2]
                        DIM uv[4]
                        xy[0].y = sy
                        xy[1].y = sy

                        // Bottom area first (dirt?)
                        STARTPOLY -1, 2
                        FOR hx = 1 TO LEN(self.points[]) - 1
                                IF self.points[hx].pm.x < sx + (self.x_width*2)
                                        xy[0].x = self.points[hx-1].pd.x
                                        xy[1].x = self.points[hx].pd.x
                                        PolyQuick(self.points[hx-1].pm, self.points[hx].pm, xy[0], xy[1], self.rgb_bottom, self.rgb_bottom)
                                ENDIF
                        NEXT
                        ENDPOLY

                        // Now draw hills
                        uv[0].y = 0
                        uv[1].y = 0
                        uv[2].y = self.texture_height
                        uv[3].y = self.texture_height
                        STARTPOLY self.sp_texture, 2
                        FOR hx = 1 TO LEN(self.points[]) - 1
                                IF self.points[hx].pm.x < sx + (self.x_width*2)
                                        uv[0].x = self.points[hx-1].texture_x
                                        uv[1].x = self.points[hx].texture_x
                                        IF uv[0].x = self.texture_width THEN uv[0].x = 0
                                        IF uv[1].x < uv[0].x
                                                uv[1].x = uv[0].x + self.x_width
                                        ENDIF
                                        uv[2].x = uv[0].x
                                        uv[3].x = uv[1].x
                                        PolyDraw(self.points[hx-1].pu, self.points[hx].pu, self.points[hx-1].pd, self.points[hx].pd, uv[0], uv[1], uv[2], uv[3])
                                ENDIF
                        NEXT
                        ENDPOLY

                CASE MODE_TEXTURE_WIRE
                        self.Draw(MODE_TEXTURE)         // First draw in texture mode
                        self.Draw(MODE_WIRE)            // Then overlay with wire mode

                ENDSELECT
        ENDFUNCTION

        FUNCTION Scroll: x#
                FOREACH p IN self.points[]
                        DEC p.pu.x, x#
                        DEC p.pm.x, x#
                        DEC p.pd.x, x#
                        IF (p.pu.x < -(self.x_width*2)) AND (p.pd.x < -(self.x_width*2)) THEN DELETE p          // Delete point if too far to the left offscreen
                NEXT
                DEC self.hill_prev.x, x#
                DEC self.hill_next.x, x#

                // Generate new hill yet?
                IF self.hill_next.x < (sx + (self.x_width * 2)) THEN self.GenerateNewHill()
        ENDFUNCTION

        FUNCTION GenerateNewHill:
                LOCAL x_dist%
                ALIAS h0 AS self.hill_prev
                ALIAS h1 AS self.hill_next

                h0.Copy(h1)             // Move old 'next' to 'prev'

                // Random 'x' distance from previous peak
                x_dist = self.x_change_min + RND(self.x_change_max - self.x_change_min)
                x_dist = (x_dist / self.x_width) * self.x_width                                 // Snap to 'hillPoints.x_width'
                h1.x = h0.x + x_dist

                // Random 'y' distance from previous peak
                IF self.peak_valley_toggle = TRUE
                        // New point will be below previous (ie: a 'valley')
                        h1.y = h0.y + (self.y_change_min + RND(self.y_change_max - self.y_change_min))
                ELSE
                        // New point will be above previous (ie: a 'peak')
                        h1.y = h0.y - (self.y_change_min + RND(self.y_change_max - self.y_change_min))
                ENDIF

                // Adjust 'y' to keep in range
                IF h1.y < (self.y_min + self.texture_ht_up) THEN h1.y = (self.y_min + self.texture_ht_up)
                IF h1.y > (self.y_max - self.texture_ht_dn) THEN h1.y = (self.y_max - self.texture_ht_dn)

                // Toggle peak / valley bit for next entry
                self.peak_valley_toggle = NOT self.peak_valley_toggle

                self.FillCurve()
        ENDFUNCTION

        // Fill in curve between these two 'hillPeaks' entries
        FUNCTION FillCurve:
                LOCAL segments#, sx#
                LOCAL dx#, da#, ymid#, ampl#
                LOCAL hillPoint AS THillPoint
                LOCAL v_delta AS TVector
                LOCAL partial#, overage#
                LOCAL length#
                ALIAS h0 AS self.hill_prev
                ALIAS h1 AS self.hill_next
                segments = (h1.x - h0.x) / self.x_width

                dx = (h1.x - h0.x) / segments
                da =  PI / segments
                ymid = (h0.y + h1.y) / 2.0
                ampl = (h0.y - h1.y) / 2.0

                FOR sx = 0 TO segments-1
                        hillPoint.pm.x = h0.x + sx*dx
                        hillPoint.pm.y = ymid + ampl * COS(sx*da * 180.0/PI)
                        IF LEN(self.points[]) = 0
                                hillPoint.texture_x = 0
                        ELSE
                                v_delta.Set(hillPoint.pm.x - self.points[-1].pm.x, hillPoint.pm.y - self.points[-1].pm.y)
                                length = v_delta.Magnitude()
                                hillPoint.texture_x = self.points[-1].texture_x + length
                                // Are we at the end of the texture, time to start at the beginning again
                                IF hillPoint.texture_x > self.texture_width
                                        overage = hillPoint.texture_x - self.texture_width                      // How far over the end of the texture are we?
                                        partial = overage / length                                                                      // As a percentage (between 0 and 1)
                                        // If it's really small, just stretch it to tne end of the texture
                                        IF partial < 0.1
                                                hillPoint.texture_x = self.texture_width
                                        // If it's really large, snap the previous point to the end of the texture, and start this entry over
                                        ELSEIF partial > 0.9
                                                hillPoint.texture_x = length
                                                self.points[-1].texture_x = self.texture_width
                                        // Somewhere in between?  Then create a mid-point entry by splitting this polygon in two
                                        ELSE
                                                // Mid point entry
                                                hillPoint.texture_x = self.texture_width
                                                hillPoint.pm.x = h0.x + (sx-partial)*dx
                                                hillPoint.pm.y = ymid + ampl * COS((sx-partial)*da * 180.0/PI)
                                                self.AddPoint(hillPoint)
                                                // Regular entry
                                                hillPoint.texture_x = overage
                                                hillPoint.pm.x = h0.x + sx*dx
                                                hillPoint.pm.y = ymid + ampl * COS(sx*da * 180.0/PI)
                                        ENDIF
                                ENDIF
                        ENDIF
                        self.AddPoint(hillPoint)
        NEXT
        ENDFUNCTION

        FUNCTION AddPoint: h AS THillPoint
                DIMPUSH self.points[], h

                IF LEN(self.points[]) = 1
                        self.points[0].pu.Set(0, self.points[0].pm.y - self.texture_ht_up)
                        self.points[0].pd.Set(0, self.points[0].pm.y + self.texture_ht_dn)
                        RETURN
                ENDIF

                ALIAS h0 AS self.points[-2]
                ALIAS h1 AS self.points[-1]
                LOCAL angle#
                LOCAL v1 AS TVector
                LOCAL v0 AS TVector

                // Calculate 'p2' of HillPoint - form rectangle with previous point
                angle = ATAN(h1.pm.y - h0.pm.y, h1.pm.x - h0.pm.x)  -90// Angle of the two points

                v1.x = COS(angle) * self.texture_ht_up + h1.pm.x
                v1.y = SIN(angle) * self.texture_ht_up + h1.pm.y
                v0.x = COS(angle) * self.texture_ht_up + h0.pm.x
                v0.y = SIN(angle) * self.texture_ht_up + h0.pm.y
                h0.pu = h0.pu.AverageWith(v0)
                h1.pu.Copy(v1)

                v1.x = COS(angle) * -self.texture_ht_dn + h1.pm.x
                v1.y = SIN(angle) * -self.texture_ht_dn + h1.pm.y
                v0.x = COS(angle) * -self.texture_ht_dn + h0.pm.x
                v0.y = SIN(angle) * -self.texture_ht_dn + h0.pm.y
                h0.pd = h0.pd.AverageWith(v0)
                h1.pd.Copy(v1)
        ENDFUNCTION
ENDTYPE

FUNCTION PolyQuick: v1 AS TVector, v2 AS TVector, v3 AS TVector, v4 AS TVector, rgb1%, rgb2%
        POLYNEWSTRIP
        POLYVECTOR v1.x, v1.y, 0, 0, rgb1               // TL
        POLYVECTOR v3.x, v3.y, 0, 1, rgb1               // BL
        POLYVECTOR v2.x, v2.y, 1, 0, rgb2               // TR
        POLYVECTOR v4.x, v4.y, 1, 1, rgb2               // BR
ENDFUNCTION


FUNCTION PolyDraw: v1 AS TVector, v2 AS TVector, v3 AS TVector, v4 AS TVector,  uv1 AS TVector, uv2 AS TVector, uv3 AS TVector, uv4 AS TVector
        LOCAL rgb1% = RGB(255,255,255)
        POLYNEWSTRIP
        POLYVECTOR v1.x, v1.y, uv1.x, uv1.y, rgb1               // TL
        POLYVECTOR v3.x, v3.y, uv3.x, uv3.y, rgb1               // BL
        POLYVECTOR v2.x, v2.y, uv2.x, uv2.y, rgb1               // TR
        POLYVECTOR v4.x, v4.y, uv4.x, uv4.y, rgb1               // BR
ENDFUNCTION
 

[EDIT] Fixed most / all bugs.  Updated demo for parallax.  See post below for details.

[attachment deleted by admin]
« Last Edit: 2012-May-18 by Slydog »
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Offline kaotiklabs

  • Dr. Type
  • ****
  • Posts: 313
  • Spain is diferent
    • View Profile
Re: Random Textured Rolling Hills
« Reply #1 on: 2012-May-16 »
you god!!!

 :nw: :nw: :nw: :nw:
Vote Cthulhu! Because the stars are right!!!!
Ia Ia Cthulhu F' tang!

Offline Schranz0r

  • Premium User :)
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 5028
  • O Rly?
    • View Profile
Re: Random Textured Rolling Hills
« Reply #2 on: 2012-May-17 »
sick!  <3 it!
I <3 DGArray's :D

PC:
AMD Ryzen 7 1700 @3.9GHz, 16GB HyperX Fury 3000MHz Ram, ASUS ROG GTX 1060 STRIX 6GB, Windows 10 Pro 64Bit, MSi Tomahawk B350 Mainboard

Offline Ian Price

  • Administrator
  • Prof. Inline
  • *******
  • Posts: 4152
  • On the shoulders of giants.
    • View Profile
    • My Apps
Re: Random Textured Rolling Hills
« Reply #3 on: 2012-May-17 »
Nice one :)
I came. I saw. I played.

Offline Kitty Hello

  • code monkey
  • Administrator
  • Prof. Inline
  • *******
  • Posts: 10723
  • here on my island the sea says 'hello'
    • View Profile
    • http://www.glbasic.com
Random Textured Rolling Hills
« Reply #4 on: 2012-May-17 »
Screensaver?

Offline matchy

  • Prof. Inline
  • *****
  • Posts: 1543
    • View Profile
Re: Random Textured Rolling Hills
« Reply #5 on: 2012-May-17 »
Cool. Add some Box2D!

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
Re: Random Textured Rolling Hills
« Reply #6 on: 2012-May-17 »
Thanks everyone!

Quote
Cool. Add some Box2D!
I don't think that would be too hard, as the coordinates are ready to plug into Box2D.
I just never done any Box2D, plus I don't plan on using this code for anything specific yet.

It was more just to see if I could do it.  It took about 8 hours of programming.
I loved the challenge.

Dang, I could have used this for a base for a LD entry!
Throw in some Box2D, clouds, a 2nd or 3rd rolling hill (blurred / pastel) in the distance scrolling at different speeds, etc.
A Tiny Wings clone would be very easy.

Oh, if anybody is really considering that style game, here's a great blog I borrowed some ideas from:
How To Create A Game Like Tiny Wings (Part 1)

At least this all gave me a couple of ideas for future games though, if i ever finish my maze!

Anybody, feel free to use any / all of this to create a game.  That's why I did it!
« Last Edit: 2012-May-17 by Slydog »
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Offline matchy

  • Prof. Inline
  • *****
  • Posts: 1543
    • View Profile
Re: Random Textured Rolling Hills
« Reply #7 on: 2012-May-17 »
It's pretty hard to make a game more popular than Happy Wheels.

Offline erico

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 4240
    • View Profile
    • Portfolio
Re: Random Textured Rolling Hills
« Reply #8 on: 2012-May-18 »
That is really great what you did there Slydog!
Quite hypnotic and the code itself is great (to the points I understood :-[).

Imagination plays a role while looking at the terrain and I swear I can almost see a guy on a monocycle riding around... :good:

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
Re: Random Textured Rolling Hills
« Reply #9 on: 2012-May-18 »
I fixed most, if not all of the bugs.
See original post for the changes, and new screenshots!

I updated the demo to have a slow scrolling parallax snow-topped mountain.
Its speed is a factor of the faster normal hills.
This was fairly simple to add, after I fixed a few 'hard-coded' settings.

I think I also fixed the problem when the texture would repeat.
Before it would just cut off the overflowed texture and start at the beginning again.
Now I figure out exactly how far over the texture we are, and if it a small value (or large), I snap / stretch the texture to the edge, if the value is somewhere in between, I create a new hill point entry and split that polygon into two sections, each joining the end and the beginning of the texture, for a smooth continuous texture.  As long as your texture is tileable, you shouldn't see any join artifacts. 

That code got very confusing.  See the wire overlay mode to see what I'm talking about, every once in a while (when the texture ends) you will see one quad split into two to handle the transition.

Plus I sped up the scroll code by directly scrolling the x value, rather than calling a function to do that for every point.  To me it looks smoother, but still jerky once in a while.  If you plan on using any of this code, you may want to profile it and see where it is slowest.

I was just thinking this texture algorithm (take the hill code out) could be used to follow any dynamic path, such as a finger for drawing a textured line.  You would just have to smooth out the touch points, by eliminating lots and finding a curve algo between the main direction change points.  Or for drawing train tracks, etc.

[Edit] One final change, I updated to only draw visible polygons, should save some processing.  Before it was drawing all polygons, even the ones for the hills yet to be displayed.
« Last Edit: 2012-May-18 by Slydog »
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Offline Slydog

  • Prof. Inline
  • *****
  • Posts: 930
  • KodeSource
    • View Profile
    • KodeSource
Re: Random Textured Rolling Hills
« Reply #10 on: 2012-May-25 »
Somebody (Aybe) on StackExchange was asking for advice on creating a laser beam effect that moves around following a spline based pattern.

I suggested this thread as a start, to help figure out the polygon coordinates and texturing, as the code above would work to follow any path.

Here's the question:
http://gamedev.stackexchange.com/questions/29424/what-are-the-maths-behind-raiden-2-purple-laser/29469#29469

But, he is having trouble viewing this page (or even the main GLBasic homepage).

Quote
Great I will look at it. BTW, the link you gave is broken. – Aybe yesterday

The link doesn't appear to be broken for me... – Jonathan Hobbs yesterday

I just checked Random Textured Rolling Hills link right now, it brings me a 404 error. – Aybe 21 hours ago

Weird. It still works for me. But here's the underlying link: glbasic.com/forum/index.php?topic=8118 – Slydog 19 hours ago

Broken for me, I tried the home page, it shows 'It works !' and that's it ... weird. – Aybe 16 hours ago

Anybody know why?  I thought I read about the GLBasic site coming up as "It Works!" or something before, maybe on mobile devices or certain devices?

Gernot (or anybody), do you have a StackExchange account?  You could answer directly if you wish.
« Last Edit: 2012-May-25 by Slydog »
My current project (WIP) :: TwistedMaze <<  [Updated: 2015-11-25]

Offline kanonet

  • Administrator
  • Prof. Inline
  • *******
  • Posts: 1142
    • View Profile
    • My GLBasic code archiv
Re: Random Textured Rolling Hills
« Reply #11 on: 2012-May-25 »
If i remember right, IP6 only people have problems, especially some linux distros use IP6 only and no IP4. Maybe this is the problem?
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Offline erico

  • Community Developer
  • Prof. Inline
  • ******
  • Posts: 4240
    • View Profile
    • Portfolio
Re: Random Textured Rolling Hills
« Reply #12 on: 2012-May-25 »
Had some problems on it a few moons ago, it was my ISP blocking everything and it is fixed now.
Can he use a proxy or a dns to check?

Offline mentalthink

  • Prof. Inline
  • *****
  • Posts: 3366
  • Integrated Brain
    • View Profile
Re: Random Textured Rolling Hills
« Reply #13 on: 2012-May-26 »
Slydog you are a mosnter whit Glbasic!!!  :nw: :nw: :nw:

Offline theprotocol

  • Mc. Print
  • *
  • Posts: 22
    • View Profile
Re: Random Textured Rolling Hills
« Reply #14 on: 2012-May-31 »
Well done!

This forum's been a source of inspiration for me lately.