Games-GUI-Battleship

 view release on metacpan or  search on metacpan

lib/Games/GUI/Battleship/Renderer.pm  view on Meta::CPAN

package Games::GUI::Battleship::Renderer;

use v5.38;
use experimental 'signatures';
use feature 'try';
no warnings 'experimental::try';
use Cairo;
use List::Util qw(min max);

# Math constant
my $PI = 3.14159265358979323846;

sub new ( $class, %args ) {
    my $self = {
        cell_size       => 32,
        player_origin   => [ 50,  80 ],
        opponent_origin => [ 460, 80 ],
        header_height   => 60,
        label_margin    => 26,
    };
    return bless $self, $class;
}

sub cell_size ($self) {
    return $self->{cell_size};
}

sub player_origin ($self) {
    return @{ $self->{player_origin} };
}

sub opponent_origin ($self) {
    return @{ $self->{opponent_origin} };
}

sub update_layout ( $self, $vp_w, $vp_h ) {
    $self->{vp_w} = $vp_w;
    $self->{vp_h} = $vp_h;

    my $w_factor = $vp_w / 940;

    # Header height scales smoothly with window height and width
    my $header_h = int( 72 + ( $vp_h - 600 ) * 0.05 + ( $vp_w - 900 ) * 0.035 );
    $header_h = max( 74, min( 170, $header_h ) );

    # Footer height scales with height and width
    my $footer_h = int( 40 + ( $vp_h - 600 ) * 0.03 + ( $vp_w - 900 ) * 0.015 );
    $footer_h = max( 42, min( 75, $footer_h ) );

    # Dynamic label margin around each board for larger titles and labels
    my $avail_h_est = $vp_h - $header_h - $footer_h - 40;
    my $avail_w_est = ( $vp_w - 60 - 80 ) / 2;
    my $cs_est      = min( int( $avail_h_est / 10 ), int( $avail_w_est / 10 ) );
    $cs_est = max( 24, min( 140, $cs_est ) );

    my $label_m = int( 28 + ( $cs_est * 0.28 ) + ( $vp_w * 0.012 ) );
    $label_m = max( 32, min( 80, $label_m ) );
    $self->{label_margin} = $label_m;

    my $avail_h = $vp_h - $header_h - $footer_h - $label_m;
    my $avail_w = ( $vp_w - 60 - ( 2 * $label_m ) ) / 2;

    my $cs_h = int( $avail_h / 10 );
    my $cs_w = int( $avail_w / 10 );

    my $cs = min( $cs_h, $cs_w );
    $cs = max( 24, min( 140, $cs ) );
    $self->{cell_size} = $cs;

    my $board_px = 10 * $cs;
    my $gap =
      max( 24, int( ( $vp_w - ( 2 * $board_px ) - ( 2 * $label_m ) ) / 3 ) );
    $gap = min( 120, $gap );

    my $total_w = ( 2 * $board_px ) + ( 2 * $label_m ) + $gap;
    my $start_x = max( 15, int( ( $vp_w - $total_w ) / 2 ) );
    my $start_y = $header_h + $label_m;

    $self->{player_origin} = [ $start_x + $label_m, $start_y ];
    $self->{opponent_origin} =
      [ $start_x + $board_px + $label_m + $gap + $label_m, $start_y ];

    return $cs;
}

sub point_to_cell ( $self, $px, $py, $board_type ) {
    my ( $ox, $oy ) =
      ( $board_type eq 'player' )
      ? $self->player_origin
      : $self->opponent_origin;

    my $cs = $self->{cell_size};
    if (   $px >= $ox
        && $px < $ox + ( 10 * $cs )
        && $py >= $oy
        && $py < $oy + ( 10 * $cs ) )



( run in 0.517 second using v1.01-cache-2.11-cpan-f1796dc4e6b )