#!/usr/bin/perl #Starfield in console # # Copyright (c) 2006, Rob Bloom # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the nor the # names of its contributors may be used to endorse or promote products # derived from this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY ROB BLOOM ''AS IS'' AND ANY # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE # DISCLAIMED. IN NO EVENT SHALL ROB BLOOM BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # ## Console info # Wait so each redraw is this far apart from the next. #colors for ncurses init_pair(1, COLOR_BLACK, COLOR_BLACK); ## Starfield info # Number of stars to draw. $numstars = 500; # Min speed of stars. $minspeed = .05; # Max $maxspeed = 2; #Star origination point (1 = right/top, 0 = left/bottom, .5 = center) $width_center = .5; $height_center = .5; # Probablility of superspeed (rand % $prob == 0) $prob = 25; # Super speed $superspeed = 5; ############################# ### DON'T EDIT BELOW HERE ### ############################# use Time::HiRes qw (usleep gettimeofday tv_interval); use Curses; $buf = new Curses; start_color; noecho; curs_set(0); #constants $width = $COLS; $height = $LINES; $PI = 3.14159265358979323846; $r = ($width + $height)/4; # Randomly place ~$numstars stars. Change around to be divisible by three # (we want an even amount of stars) #center $cx = $width * $width_center; $cy = $height * (1 - $height_center); for ($i = 0; $i < $numstars ; $i++) { # Distance from center @stard[$i] = rand($r)/20; # Velocity if (int(rand($prob)) == 0) { $s = $superspeed; } else { $s = $maxspeed; } @starv[$i] = $minspeed + rand ($s - $minspeed); # Direction (angle) @stara[$i] = rand(2 * $PI); } # Okay, now we do a main program loop. #bootstrap the clock :O $last = [gettimeofday]; $t = 0; #Time of last frame while (1) { ## Draw the stars #Clear the screen (and buffer), since everything is in motion anyway. $buf->clear; ## For loop through the stars, drawing and updating them. for ($i = 0; $i < $numstars; $i++) { #Which way does it point? $dy = sin($stara[$i]); $dx = cos($stara[$i]); #Where is it at now? (y is 2x tall so 1/2 as strong) $y = $cy + ( $dy * $stard[$i] )/2; $x = $cx + ( $dx * $stard[$i] ); $m = $stard[$i] * ($starv[$i]/2) * $maxspeed; if ($m < $r / 3) { $buf->attrset(A_BOLD | COLOR_PAIR(1)); } elsif ($m < $r * 2 / 3) { $buf->attrset(A_NORMAL); } else { $buf->attrset(A_BOLD); } if ($y - int $y < .5) { $buf->addch($y,$x, "`"); } else { $buf->addch($y,$x, "."); } #Move the star now, by increasing distance, resetting if it's out. #Multiply by time of last frame. This'll make it run at all FPS $stard[$i] += $starv[$i]*$t*($stard[$i]+.1); if ($y > $height || $y < 0 || $x > $width || $x < 0) { $stard[$i] = 0; $stara[$i] = rand(2 * $PI); if (int(rand($prob)) == 0) { $s = $superspeed; } else { $s = $maxspeed; } $starv[$i] = $minspeed + rand($maxspeed - $minspeed); } } #Move cursor to bottomleft for consistency #Wait until it's time to print. usleep 5000; # Give the CPU/network a break, this is a screensaver $t = tv_interval($last); $last = [gettimeofday]; # Get this done as soon as possible. $buf->refresh; } sub moveto { my ($x, $y) = @_; #Round to nearest whole. $x = sprintf("%.0f", $x); $y = sprintf("%.0f", $y); $x = 0 if ($x < 0); $x = $width if ($x > $width); $y = 0 if ($y < 0); $y = $width if ($y > $height); return (chr(27) . '[' . ($y+1) . ';' . ($x+1) . 'H'); }