1
Programs / Re: Screensaver: Super Simple Snowfall (with accumulation)
« on: December 23, 2021, 01:16:54 am »
Wow! A lot of great feedback on my first post! I've taken a lot of the feedback to heart.
- Hairy Snow @bplus, great feedback! I added a "settle" function that gives spikey accumulation an increasingly likely chance to settle left or right when the delta is 2 pixels or more.
- Screen 9 @Richard Frost, great feedback! I've made this change!
- Timer Crossing Midnight @Richard Frost, great feedback, I had not considered midnight! I've made a similar change to the one you suggested (your exact suggestion didn't work for me... using MOD to get the remainder after seconds causes a 1 second delay every other second... the same problem you pointed out would occur after midnight, but every second now. So I just added another condition to the loop that sngStart had to be >= Timer for the loop to continue.
Code: QB64: [Select]
- 'SNOWFALL.BAS
- '============
- 'DESCRIPTION
- '-----------
- ' A holiday screensaver for QBasic.
- 'AUTHOR
- '------
- ' Dustinian Camburides
- 'PLATFORM
- '--------
- ' Written in QB64.
- ' But designed to be QBasic/QuickBasic compatible.
- ' Although, I haven't tested QBasic / QuickBasic compatability yet.
- 'VERSION
- '-------
- '1.0, 2021-12-18: First working version.
- '1.1, 2021-12-19: I was excited to keep working!
- ' Added page-flipping to reduce flicker!
- ' Added background snowflakes at a smaller speed and dimmer color!
- ' Set the formula to advance snowflakes to actually use the FALLSPEED constant.
- ' Also started the timer before calculating all the snowflakes to smooth out the animation.
- '1.2, 2021-12-23: Updates with encouragement from the great folks at qb64.org/forum!
- ' Added a "settle" function to let "spiky" snow accumulation settle. (Thank you for the suggestion bplus!)
- ' Updated the delay so it doesn't break when it starts before midnight and ends after midnight. (Thank you for the suggestion Richard Frost!)
- ' Shifted to screen 9 to keep page-flipping, but at a higher resolution. (Thank you for the suggestion Richard Frost!)
- 'PLANNED ENHANCEMENTS
- '--------------------
- 'Maybe next year I will add...
- ' - Actual, tested QBasic compatability (need to to a DosBox install and find a copy of QBasic).
- ' - A more complex data structure for snowflakes that can store both X and Y coordinates in a dynamic array of user-defined types... so it can support more than one snowflake per column... and mabe some drift back-and-forth in the X-axis.
- 'HOLIDAY MESSAGE
- '---------------
- 'But for now, I'm happy that I have my first QB64 program that has animation. Happy Holidays!
- 'SUBS
- 'CONSTANTS
- Const DELAY = 0.04 'The number of seconds between snowflake recalculation / re-draw... QBasic can't detect less than 0.04 seconds...
- Const ODDS = 0.7 'The % chance a snowflake will be added to a column that doesn't have a snowflake... anything over 1% will results in "waves" of snowflakes.
- 'VARIABLES
- 'INITIALIZE VARIABLES
- 'For each column...
- 'Set all snowflakes to -1, indicating there is no snowflake in this column.
- intSnowflakes(intColumn) = -1
- intBackgroundSnowflakes(intColumn) = -1
- 'Set all accumulation to 0, indicating there is no accumulation in this column.
- intAccumulation(intColumn) = 0
- intBackgroundAccumulation(intColumn) = 0
- Next intColumn
- intBackgroundFrame = 0
- 'INITIALIZE SCREEN
- 'Set the screen to mode 9 with an active page (where the cls, pset, and line commands occur) of 0 and a visible page (that the user sees) of 1.
- 'PROGRAM
- 'While no key has been pressed...
- 'Set the delay timer...
- sngStart = Timer
- 'Reset the number of full columns...
- intFullColumns = 0
- 'Flip whether the background snow will move on or off...
- intBackgroundFrame = Not intBackgroundFrame
- 'For each column... calculate the changes to the snowfall...
- 'Settle the accumulation...
- Call SettleAccumulation(intAccumulation(intColumn - 1), intAccumulation(intColumn), intAccumulation(intColumn + 1))
- Call SettleAccumulation(intBackgroundAccumulation(intColumn - 1), intBackgroundAccumulation(intColumn), intBackgroundAccumulation(intColumn + 1))
- 'If this is a background frame...
- 'Recalculate background snow...
- Call CalculateSnowflakeColumn(intBackgroundSnowflakes(intColumn), intBackgroundAccumulation(intColumn), ROWS, FALLSPEED, ODDS)
- 'Ensure background accumulation keeps up with foreground accumulation to smooth out the accumulation...
- 'Draw the background snow first...
- Call DrawSnowflakeColumn(intBackgroundSnowflakes(intColumn), intBackgroundAccumulation(intColumn), intColumn, ROWS, 7)
- 'Recalculate the foreground snow...
- Call CalculateSnowflakeColumn(intSnowflakes(intColumn), intAccumulation(intColumn), ROWS, FALLSPEED, ODDS)
- 'Draw the foreground snow next, on top of the background snow...
- 'Track whether or not this column is full of snow (program will terminate when all columns are full)...
- Next intColumn
- 'Copy the active page (where we just drew the snow) to the visible page...
- 'Clear the active page for the next frame...
- 'Wait for the delay to pass before starting over...
- 'If there is a snowflake in the column (i.e. any value > -1) then...
- 'If the snowflake has not fallen to the accumulation...
- 'Advance the snowflake...
- Snowflake = Snowflake + FallSpeed
- 'Eliminate the flake...
- Snowflake = -1
- 'Add to the accumulation...
- Accumulation = Accumulation + 1
- 'If accumulation hasn't filled up the column...
- 'Maybe add a flake...
- Snowflake = 0
- 'If there is a snowflake in this column...
- 'Draw the snowflake...
- 'If there is accumulation in this column...
- 'Draw the accumulation...
- 'If accumulation should settle left...
- 'Shift accumulation to the left
- LeftAccumulation = LeftAccumulation + 1
- Accumulation = Accumulation - 1
- 'If accumulation should settle right...
- 'Shift accumulation to the right
- RightAccumulation = RightAccumulation + 1
- Accumulation = Accumulation - 1