好的,这是我的真实代码。它似乎有效,但我认为某处存在竞争条件。这是一些典型的(尽管很短)输出。
A monster hatched.
A monster hatched.
A hero was born.
The Monster is at 2,3
The Monster is at 3,2
The Player is at 0,0
The Monster (2) attacks the Player (3)
The Monster rolls 14
The Player rolls 4
The Monster inflicts 4 damage
The Player (3) attacks the Monster (2)
The Player rolls 11
The Monster rolls 8
The Player inflicts 45 damage
The Monster is dead
The Monster is at -3,-3
The Player is at 4,-3
The Monster (1) attacks the Player (3)
The Monster rolls 8
The Player rolls 5
The Monster inflicts 11 damage
The Player has 32 hitpoints left
The Monster is at -4,1
The Player is at -1,4
The Player (3) attacks the Monster (1)
The Player rolls 12
The Monster rolls 11
The Player inflicts 46 damage
The Monster is dead
Stopping
Game over. The Player has won
现在奇怪的是,有时,在 20% 的运行中,输出的最后一行是
Game over. The GameObject has won
好像物体已经部分解构时被抓住了?或者其他的东西?无论如何,这是代码。
class GameObject
{
has Int $.id;
has Int $.x is rw;
has Int $.y is rw;
has $.game;
has Int $.speed; #the higher the faster
has Bool $.stopped is rw;
multi method start( &action )
{
start {
loop {
&action();
last if self.stopped;
await Promise.in( 1 / self.speed );
}
$.game.remove-object( self );
}
}
method speed {
$!speed +
# 33% variation from the base speed in either direction
( -($!speed / 3).Int .. ($!speed / 3).Int ).pick
;
}
}
role UnnecessaryViolence
{
has $.damage;
has $.hitpoints is rw;
has $.offense;
has $.defense;
method attack ( GameObject $target )
{
say "The {self.WHAT.perl} ({self.id}) attacks the {$target.WHAT.perl} ({$target.id})";
my $attacker = roll( $.offense, 1 .. 6 ).sum;
say "The {self.WHAT.perl} rolls $attacker";
my $defender = roll( $target.defense, 1 .. 6 ).sum;
say "The {$target.WHAT.perl} rolls $defender";
if $attacker > $defender
{
my $damage = ( 1 .. $.damage ).pick;
say "The {self.WHAT.perl} inflicts {$damage} damage";
$target.hitpoints -= $damage ;
}
if $target.hitpoints < 0
{
say "The {$target.WHAT.perl} is dead";
$target.stopped = True;
}
else
{
say "The {$target.WHAT.perl} has { $target.hitpoints } hitpoints left";
}
}
}
class Player is GameObject does UnnecessaryViolence
{
has $.name;
multi method start
{
say "A hero was born.";
self.start({
# say "The hero is moving";
# keyboard logic here, in the meantime random movement
$.game.channel.send( { object => self, x => (-1 .. 1).pick, y => (-1 .. 1).pick } );
});
}
}
class Monster is GameObject does UnnecessaryViolence
{
has $.species;
multi method start
{
say "A monster hatched.";
self.start({
# say "The monster {self.id} is moving";
# AI logic here, in the meantime random movement
$.game.channel.send( { object => self, x => (-1 .. 1).pick, y => (-1 .. 1).pick } );
});
}
}
class Game
{
my $idc = 0;
has GameObject @.objects is rw;
has Channel $.channel = .new;
method run{
self.setup;
self.mainloop;
}
method setup
{
self.add-object( Monster.new( :id(++$idc), :species("Troll"), :hitpoints(20), :damage(14), :offense(3), :speed(300), :defense(3), :x(3), :y(2), :game(self) ) );
self.add-object( Monster.new( :id(++$idc), :species("Troll"), :hitpoints(10), :damage(16), :offense(3), :speed(400), :defense(3), :x(3), :y(2), :game(self) ) );
self.add-object( Player.new( :id(++$idc), :name("Holli"), :hitpoints(50), :damage(60), :offense(3), :speed(200) :defense(2), :x(0), :y(0), :game(self) ) );
}
method add-object( GameObject $object )
{
@!objects.push( $object );
$object.start;
}
method remove-object( GameObject $object )
{
@!objects = @!objects.grep({ !($_ === $object) });
}
method mainloop
{
react {
whenever $.channel.Supply -> $event
{
self.stop-game
if self.all-objects-stopped;
self.process-movement( $event );
self.stop-objects
if self.game-is-over;
};
whenever Supply.interval(1) {
self.render;
}
}
}
method process-movement( $event )
{
#say "The {$event<object>.WHAT.perl} moves.";
given $event<object>
{
my $to-x = .x + $event<x>;
my $to-y = .y + $event<y>;
for @!objects -> $object
{
# we don't care abour ourselves
next
if $_ === $object;
# see if anything is where we want to be
if ( $to-x == $object.x && $to-y == $object.y )
{
# can't move, blocked by friendly
return
if $object.WHAT eqv .WHAT;
# we found a monster
.attack( $object );
last;
}
}
# -5 -1 5
# we won the fight or the place is empty
# so let's move
.x = $to-x == 5 ?? -4 !!
$to-x == -5 ?? 4 !!
$to-x;
.y = $to-y == 5 ?? -4 !!
$to-y == -5 ?? 4 !!
$to-y;
}
}
method render
{
for @!objects -> $object {
"The {$object.WHAT.perl} is at {$object.x},{$object.y}".say;
}
}
method stop-objects
{
say "Stopping";
for @!objects -> $object {
$object.stopped = True;
}
}
method stop-game {
"Game over. The {@!objects[0].WHAT.perl} has won".say;
$.channel.close;
done;
}
method game-is-over {
return (@!objects.map({.WHAT})).unique.elems == 1;
}
method all-objects-stopped {
(@!objects.grep({!.stopped})).elems == 0;
}
}
Game.new.run;