Featured image of post 第3回-clone()で色違いモンスターを量産しよう - mass-producing-monsters

第3回-clone()で色違いモンスターを量産しよう - mass-producing-monsters

clone()したモンスターの色だけ変えて、赤スライム・青スライム・金スライムを量産!テンプレートからバリエーションを作る楽しさを味わおう。

@nqounetです。

「PerlとMooでモンスター軍団を量産してみよう」シリーズの第3回です。

前回の振り返り

前回は、MooX::Cloneを導入してclone()メソッドでスライムを量産する方法を学びました。

10体のスライムが1行で作れるようになりましたね。今回は、clone()で作ったオブジェクトの属性を変更して、バリエーションを作る方法を学びます。

シリーズ全体の目次は以下をご覧ください。

色違いスライムを作りたい!

通常の緑スライムだけでなく、赤スライム、青スライム、金スライムなど、色違いバージョンを作りたいとしましょう。

それぞれをnew()で作ると、こうなります。

1
2
3
4
my $green  = Monster->new(name => 'スライム', hp => 10, attack => 3, defense => 2, color => '緑');
my $red    = Monster->new(name => 'スライム', hp => 10, attack => 3, defense => 2, color => '赤');
my $blue   = Monster->new(name => 'スライム', hp => 10, attack => 3, defense => 2, color => '青');
my $gold   = Monster->new(name => 'スライム', hp => 10, attack => 3, defense => 2, color => '金');

ほとんど同じコードの繰り返しです。もっと楽にできないでしょうか?

clone()後に属性を変更する

clone()で作ったオブジェクトは、元のオブジェクトとは独立した別のオブジェクトです。だから、コピー後に属性を変更しても、元のオブジェクトには影響しません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, MooX::Clone(cpanmでインストール)

use v5.36;

package Monster {
    use Moo;
    use MooX::Clone;

    has name    => (is => 'ro', required => 1);
    has hp      => (is => 'rw', required => 1);
    has attack  => (is => 'rw', required => 1);
    has defense => (is => 'rw', required => 1);
    has color   => (is => 'rw', default => '緑');

    sub show_status ($self) {
        say "【" . $self->name . "】HP:" . $self->hp
            . " 攻撃:" . $self->attack
            . " 防御:" . $self->defense
            . " 色:" . $self->color;
    }
}

# ベーススライムを1体作成
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 10,
    attack  => 3,
    defense => 2,
);

# clone()してから色を変更
my $red_slime = $base_slime->clone;
$red_slime->color('赤');  # 色を赤に変更

my $blue_slime = $base_slime->clone;
$blue_slime->color('青');  # 色を青に変更

my $gold_slime = $base_slime->clone;
$gold_slime->color('金');  # 色を金に変更

# 元のスライムは緑のまま
say "=== 色違いスライム軍団 ===";
$base_slime->show_status;   # 色: 緑(元のまま)
$red_slime->show_status;    # 色: 赤
$blue_slime->show_status;   # 色: 青
$gold_slime->show_status;   # 色: 金

$base_slime->cloneでコピーを作り、その後->color('赤')で色を変更しています。元の$base_slimeは緑のままです。

5色のスライム軍団を一気に作成

配列とmapを組み合わせて、一気に作ってみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, MooX::Clone(cpanmでインストール)

use v5.36;

package Monster {
    use Moo;
    use MooX::Clone;

    has name    => (is => 'ro', required => 1);
    has hp      => (is => 'rw', required => 1);
    has attack  => (is => 'rw', required => 1);
    has defense => (is => 'rw', required => 1);
    has color   => (is => 'rw', default => '緑');

    sub show_status ($self) {
        say "【" . $self->name . "】HP:" . $self->hp
            . " 攻撃:" . $self->attack
            . " 防御:" . $self->defense
            . " 色:" . $self->color;
    }
}

# ベーススライムを1体作成
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 10,
    attack  => 3,
    defense => 2,
);

# 5色のスライムを一気に作成
my @colors = qw(緑 赤 青 金 銀);
my @color_slimes = map {
    my $slime = $base_slime->clone;
    $slime->color($_);
    $slime;
} @colors;

say "=== 5色スライム軍団 ===";
for my $slime (@color_slimes) {
    $slime->show_status;
}

出力結果:

1
2
3
4
5
6
=== 5色スライム軍団 ===
【スライム】HP:10 攻撃:3 防御:2 色:緑
【スライム】HP:10 攻撃:3 防御:2 色:赤
【スライム】HP:10 攻撃:3 防御:2 色:青
【スライム】HP:10 攻撃:3 防御:2 色:金
【スライム】HP:10 攻撃:3 防御:2 色:銀

色の配列を@colorsとして定義し、mapで各色のスライムを作成しています。ベースを1体作って、あとは色だけ変えるという発想です。

強化版バリエーションも作れる

色だけでなく、ステータスを少しずつ変えたバリエーションも作れます。

1
2
3
4
5
6
7
8
9
# 強化版スライムを作成(HP、攻撃力、防御力を少し上げる)
my $strong_slime = $base_slime->clone;
$strong_slime->hp(15);
$strong_slime->attack(5);
$strong_slime->defense(3);
$strong_slime->color('金');

$strong_slime->show_status;
# 【スライム】HP:15 攻撃:5 防御:3 色:金

ベースから少しずつパラメータを変えて、強化版モンスターを作れます。これが「テンプレートからのバリエーション生成」です。

今回の完成コード

今回の最終的なコードです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, MooX::Clone(cpanmでインストール)
#
# clone()でベースを複製し、属性を変更してバリエーションを作成

use v5.36;

package Monster {
    use Moo;
    use MooX::Clone;

    has name    => (is => 'ro', required => 1);
    has hp      => (is => 'rw', required => 1);
    has attack  => (is => 'rw', required => 1);
    has defense => (is => 'rw', required => 1);
    has color   => (is => 'rw', default => '緑');

    sub show_status ($self) {
        say "【" . $self->name . "】HP:" . $self->hp
            . " 攻撃:" . $self->attack
            . " 防御:" . $self->defense
            . " 色:" . $self->color;
    }
}

# ベーススライムを1体作成
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 10,
    attack  => 3,
    defense => 2,
);

# 5色のスライム軍団を作成
my @colors = qw(緑 赤 青 金 銀);
my @color_slimes = map {
    my $slime = $base_slime->clone;
    $slime->color($_);
    $slime;
} @colors;

say "=== 5色スライム軍団 ===";
for my $slime (@color_slimes) {
    $slime->show_status;
}

# 強化版スライムも作成
say "\n=== 強化版スライム ===";
my $strong_slime = $base_slime->clone;
$strong_slime->hp(15);
$strong_slime->attack(5);
$strong_slime->defense(3);
$strong_slime->color('虹');
$strong_slime->show_status;

まとめ

  • clone()で作ったオブジェクトは、元のオブジェクトとは独立している
  • コピー後に属性を変更しても、元のオブジェクトには影響しない
  • 「ベースを複製→一部を変更」という手順で、バリエーションを効率的に作れる
  • 色違いや強化版など、テンプレートからの派生モンスターを量産できる

次回予告

次回は、装備(武器オブジェクト)を持つモンスターをclone()してみます。すると、思わぬ問題が発覚……。「浅いコピー」の罠にハマります。お楽しみに。

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。