#!/usr/local/bin/perl
use strict;
use warnings;
use Player;
my $player = Player->new('vx' => -1);
for (keys %$player) {
print "$_: ", $player->{$_}, $/;
}
####
package Player;
use Mover;
@Player::ISA = qw(Mover);
use strict;
sub defaults {
my $defaults = {
'symbol' => '_',
'score' => 0,
}
}
1;
####
package Mover;
use Object;
@Mover::ISA = qw(Object);
use strict;
sub defaults {
my $defaults = {
'symbol' => '?', # override this in subclasses
'x' => 0, # x-coordinate
'y' => 0, # y-coordinate
'vx' => 0, # velocity in x-direction
'vy' => 0, # velocity in y-direction
'shown' => 1, # still alive?
}
}
1;
####
package Object;
use strict;
sub new {
my ($caller, %args) = @_;
my ($self, $class);
$class = ref $caller;
$class ||= $caller;
$self = bless {}, $class;
$self->init(\%args);
return $self;
}
sub init {
my ($self, $args) = @_;
my ($defaults);
# See if superclass has defaults
if ($self->can('SUPER::defaults')) {
$defaults = $self->SUPER::defaults();
}
# Let current class override superclass
if ($self->can('defaults')) {
my $current_defaults = $self->defaults();
for my $attr (keys %$current_defaults) {
$defaults->{$attr}
= $current_defaults->{$attr};
}
}
# Set default values
if (ref($defaults) eq 'HASH') {
for my $attr (keys %$defaults) {
$self->{$attr} = $defaults->{$attr};
}
}
# If %args are given to new(), use those instead
for my $attr (keys %$args) {
$self->{$attr} = $args->{$attr};
}
}
1;
####
$ ./test.pl
score: 0
vx: -1
symbol: _