http://qs321.pair.com?node_id=11101830

Hello community!

who knows me is aware I'm writing a game (engine?) and I asked here for the precious monks wisdom about circular area in a coordinates grid (AoA).

But now I'm progressing and I discovererd that the above illuminate function is not enough. I found a big resource of Roguelike_Vision_Algorithms and I choosed the simplest one (second example) and I ported it to Perl ( field_of_view sub in the below code ).

Impressed by this shiny exemple I wrapped into an interactive program to show my proof of concept:

use strict; use warnings; use Term::ReadKey; ReadMode 'cbreak'; # debug my $debug = 0; # Point of View coordinates my $pov_coords = [15,15]; # sight range my $pov_radius = 5; # used to cast rays trough 360 degrees (default to 1) my @stepping_radius = (1,2,4,8,16,32); # the map is an ArrayOfArrays taken from DATA my @aoa; my $row = 0; while(<DATA>){ chomp; $aoa[$row] = [ map{ /\s/ ? '.' : $_} split // ]; $row++; } # first print of the map local $aoa[$pov_coords->[0]][$pov_coords->[1]]='X'; system ( $^O =~ /mswin32/i ? 'cls' : 'clear') unless $debug; print "move the point of view X with wasd keys\n". "+ or - to modify sight radius (now $pov_radius)\nr to cycle stepp +ing radius (now $stepping_radius[ 0 ])\n"; field_of_view(); print_map(); # proof of concept loop while ( my $key = ReadKey(0) ){ system ( $^O =~ /mswin32/i ? 'cls' : 'clear') unless $debug; # reinitialize the map foreach my $row (0..$#aoa){ foreach my $col( 0..$#{$aoa[$row]} ){ $aoa[$row][$col] = '.' unless $aoa[$row][$col] eq 'O'; } } # movements and controls if ($key eq 'w'){ $pov_coords->[0]-- } elsif ($key eq 's'){ $pov_coords->[0]++ } elsif ($key eq 'a'){ $pov_coords->[1]-- } elsif ($key eq 'd'){ $pov_coords->[1]++ } elsif ($key eq '+'){ $pov_radius++ } elsif ($key eq '-'){ $pov_radius-- } elsif ($key eq 'r'){ push @stepping_radius, shift @stepping_radius + } else { 0 } print "move the point of view X with wasd keys\n". "+ or - to modify sight radius (now $pov_radius)\nr to cycle stepp +ing radius (now $stepping_radius[ 0 ])\n"; field_of_view(); local $aoa[$pov_coords->[0]][$pov_coords->[1]]='X'; print_map(); } # translated from: # http://www.roguebasin.com/index.php?title=Eligloscode sub field_of_view{ my $i = 0; my ($x,$y); while ( $i < 360 ){ $x = cos( $i * 0.01745); $y = sin( $i * 0.01745); my $ox = $pov_coords->[0] + 0.5; my $oy = $pov_coords->[1] + 0.5; # DEBUG print "DEG $i X $x Y $y OX $ox OY $oy\n" if $debug; for ( 0..$pov_radius ){ # DEBUG print "\t$_ : intOX ".int($ox)." intOY ".int($oy)."\n" if +$debug; next unless int($ox) >= 0 and int($ox) <= $#{$aoa[ 0 ]} and int($oy) >= 0 and int($oy) <= $#aoa; $aoa[ int($ox) ][ int($oy) ] = ' ' if $aoa[ int($ox) ][ int($oy) ] ne 'O' and $aoa[ int($ox) ][ int($oy) ] ne 'X'; last if $aoa[ int($ox) ][ int($oy) ] eq 'O'; $ox+=$x; $oy+=$y; } $i+= $stepping_radius[ 0 ]; } } sub print_map{ foreach my $row (0..$#aoa){ foreach my $col( 0..$#{$aoa[$row]} ){ print $aoa[$row][$col]; } print "\n"; } } __DATA__ OOO OOOOOOOOOOOO OOOO O OO O O O O O O O O O O O O O OOOOOOO O O OOOO OOOOOO O O OOOOOOO OOOOO O O O O OOOO O O O O OOOO OOOO O O OOOO O O O O O OOOOOO OOO OOOOO O O OOOO O OOOOO O O O OOO O O OOO OOO OOO OOOO O OOO OOO OO OOOOO O OOO OOO O O O O OOO O O O O O O O O O O O O O OOOOOO O O O OOO O OOO O OOOOOO OOO OOOO

Chatting in the perl irc channel daxim also implemented a semi-transparency feature I'd like to add to my game. Here daxim's patch (and a big thank to him):

diff --git a/scpaste-585123.pl b/scpaste-585123.pl index a23cf20..8fe0613 100644 --- a/scpaste-585123.pl +++ b/scpaste-585123.pl @@ -39 +39 @@ while ( my $key = ReadKey(0) ){ - $aoa[$row][$col] = '.' unless $aoa[$row][$col] eq 'O'; + $aoa[$row][$col] = '.' unless $aoa[$row][$col] eq 'O' or +$aoa[$row][$col] eq '#'; @@ -66 +66 @@ sub field_of_view{ - + my $radius = $pov_radius; # reinit from global @@ -75 +75 @@ sub field_of_view{ - for ( 0..$pov_radius ){ + for (my $r = 0; $r < $radius; $r++){ @@ -77 +77 @@ sub field_of_view{ - print "\t$_ : intOX ".int($ox)." intOY ".int($oy)."\n" if + $debug; + print "\t$r : r $r radius $radius intOX ".int($ox)." intO +Y ".int($oy)."\n" if $debug; @@ -85,2 +85,6 @@ sub field_of_view{ - $aoa[ int($ox) ][ int($oy) ] ne 'X'; - + $aoa[ int($ox) ][ int($oy) ] ne 'X' and + $aoa[ int($ox) ][ int($oy) ] ne '#'; + if ($aoa[ int($ox) ][ int($oy) ] eq '#') { + print "semi\n"; + $radius /= 2; + } @@ -119 +123 @@ __DATA__ - O OOOOOO OOO + # OOOOOO OOO

have fun!

L*

There are no rules, there are no thumbs..
Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.

Replies are listed 'Best First'.
Re: 2d field of view, vision algorithm in grid (ray casting)
by Don Coyote (Friar) on Jun 29, 2019 at 08:39 UTC

    The '-' ReadKey conditional goes into negative territory. That may cause some metaphysical disturbances for our X. I'd suggest limiting the lower end of visibility.

    elsif ($key eq '-'){ ! $pov_radius < 1 and $pov_radius-- }

    The ReadKey function can take octal values for timings so the program will self close after some time without a keypress.

    while ( my $key = ReadKey(010) ){