Game-Entities
view release on metacpan or search on metacpan
lib/Game/Entities.pm view on Meta::CPAN
$index | ( $self->{entities}[$index]->$version << ENTITY_SHIFT )
};
my $generate_guid = sub ($self) {
Carp::croak 'Exceeded maximum number of entities'
if @{ $self->{entities} } >= ENTITY_MASK;
my $guid = @{ $self->{entities} };
push @{ $self->{entities} }, $guid;
return $guid;
};
my $recycle_guid = sub ($self) {
my $next = $self->{available};
Carp::croak 'Cannot recycle GUID if none has been released'
if $next->$is_null;
my $ver = $self->{entities}[$next]->$version;
$self->{available} = $self->{entities}[$next]->$entity;
return $self->{entities}[$next] = $next | ( $ver << ENTITY_SHIFT );
};
my $maybe_prefix = sub ( $self, $name ) {
$$name =~ s/^:([^:])/$self->{prefix}::$1/ if $self->{prefix};
};
my $get = sub ( $self, $unsafe, $guid, @types ) {
my $index = $guid->$entity;
if ( $self->{prefix} ) {
s/^:([^:])/$self->{prefix}::$1/ for @types;
}
my @got = map {
my $set = $self->{components}{"$_"};
my $sparse = $set->[SPARSE][$index];
defined($sparse) && ( $unsafe || $self->check( $guid, $_ ) )
? $set->[COMPONENTS][$sparse] : undef
} @types;
return $got[0] if @types == 1;
return @got;
};
## Public methods
sub new ( $class, %args ) {
my $self = bless { %args{prefix} }, $class;
$self->clear;
}
sub created ($self) { scalar @{ $self->{entities} } - 1 }
# Get the number of created entities that are still valid; that is, that have
# not been deleted.
sub alive ($self) {
my $size = @{ $self->{entities} } - 1;
my $current = $self->{available};
until ( $current->$is_null ) {
$size--;
$current = $self->{entities}[ $current->$entity ];
}
return $size;
}
# Reset the registry internal storage. All entities will be deleted, and all
# entity IDs will be made available.
sub clear ($self) {
delete $self->{view_cache};
# Keys in this hash are component type names (ie. the result of ref),
# and values are sparse sets of entities that "have" that component.
delete $self->{components};
# Parameters used for recycling entity GUIDs
# See https://skypjack.github.io/2019-05-06-ecs-baf-part-3
$self->{entities} = [ undef ];
$self->{available} = NULL_ENTITY;
return $self;
}
# Create a new entity
sub create ( $self, @components ) {
Carp::croak 'Component must be a reference'
if List::Util::any { !ref } @components;
my $guid = $self->{available}->$is_null
? $self->$generate_guid : $self->$recycle_guid;
$self->add( $guid, @components );
return $guid;
}
sub check ( $self, $guid, $type ) {
Carp::croak 'GUID must be defined' unless defined $guid;
Carp::croak 'Component name must be defined and not a reference'
if ! defined $type || ref $type;
$self->$maybe_prefix(\$type);
$self->{components}{$type}->$contains( $guid->$entity );
}
# Add or replace a component for an entity
sub add ( $self, $guid, @components ) {
Carp::croak 'GUID must be defined' unless defined $guid;
my $index = $guid->$entity;
for my $component (@components) {
my $name = ref($component) || Carp::croak 'Component must be a reference';
# SPARSE DENSE COMPONENTS
( run in 3.420 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )