ながみえ

一つ前のページではゲームクリアを設定する方法について学習しました。

今回は 追跡してくる敵を実装 し、いよいよゲームを完成させましょう。

Chapter1:pygame入門|画面を表示しよう
Chapter2:簡単なノベルゲームを作ろう
Chapter3:簡単なアクションゲームを作ろう
 ・Chapter3-1:衝突判定に基本を理解しよう
 ・Chapter3-2:画面に敵を配置しよう
 ・Chapter3-3:ゲームオーバーを設定しよう
 ・Chapter3-4:ゲームクリアを設定しよう
 ・Chapter3-5:追跡してくる敵を実装しよう ◁今回はここ
Chapter4:ブロック崩しを作ろう
Chapter5:シューティングゲームを作ろう
Chapter6:pygameのお役立ち情報

ここまでのレッスンでプレイヤーが操作する猫を自由に動かし、犬との衝突によるゲームオーバーや、ゴールに到達したときのゲームクリアといった基本的なゲームの流れを作ってきました。

今回は仕上げとして、「プレイヤーを追いかけてくる敵キャラクター(幽霊)」を新しく追加します。

この幽霊は、プレイヤーの動きを自動的に追跡してくる特徴的な敵です。

プレイヤーがどの方向に動いても、それを追いかけてくる敵がいることで、ゲームに緊張感が生まれ、より本格的なアクションゲームらしさが加わります。

新たに登場するこの敵は、簡単な「追跡アルゴリズム」によって実装します。アルゴリズムといっても難しいものではなく、座標を比較して少しずつ近づけるというシンプルな仕組みです。

今回のレッスンではその考え方を学びながら、ゲームへの実装方法を順を追って確認していきましょう。

注意点

Chapter3-1から3-5でまでを通して1つのゲームを作成しています。

直接このページに来た人は pygameのトップページ から基本セットを 無料 でダウンロードしてChapter3-1から学習を始めるか、以下のコードをコピーしてください。

Q
Chapter3-4の完成コード
# 初期化(ゲームの準備をする)
import pygame, sys, random
pygame.init()
screen = pygame.display.set_mode((800,600))
## 背景画像の設定
haikei_img = pygame.image.load("images/shibafu.png")
haikei_img = pygame.transform.scale(haikei_img, (800, 600))
## プレイヤーの猫の設定
neko_imgR = pygame.image.load("images/neko.png")
neko_imgR = pygame.transform.scale(neko_imgR, (50,50))
neko_imgL = pygame.transform.flip(neko_imgR, True, False)
neko_rect = pygame.Rect(50,50,50,50) # 猫のRect
## 敵の犬の設定
enemy_img = pygame.image.load("images/inu.png")
enemy_img = pygame.transform.scale(enemy_img,(50,50))
enemys = [] # 複数の犬のRectを格納する空のリスト
for i in range(13):
    wx = 100 + i * 50
    wy = random.randint(20,550)
    enemys.append(pygame.Rect(wx,wy,50,50)) # 犬のRect
## 敵の幽霊の設定

## ゴールの設定
sakana_img = pygame.image.load("images/sakana.png")
sakana_img = pygame.transform.scale(sakana_img,(100,100))
sakana_rect = pygame.Rect(680,480,100,100)
## 壁の設定
walls = [pygame.Rect(0,0,800,20),
         pygame.Rect(0,0,20,600),
         pygame.Rect(780,0,20,600),
         pygame.Rect(0,580,800,20)]
## リセットボタンの設定
replay_img = pygame.image.load("images/replaybtn.png")

## メインループ内で使う変数
rightFlag = True # 猫の向き
pushFlag = False # リセットボタンが押されたか
page = 1         # 表示するページ(1:ゲーム画面、2:ゲームオーバー画面、3、ゲームクリア画面)


# ここから関数の定義
## ゲームステージ
def gamestage():
    global rightFlag
    global page
    # 画面の初期化
	screen.blit(haikei_img, (0,0))
    vx = 0
    vy = 0
    #ユーザー入力
    key = pygame.key.get_pressed()
    if key[pygame.K_RIGHT]: # 右キーが押されたら右へ移動
        vx = 4
        rightFlag = True
    if key[pygame.K_LEFT]:  # 左キーが押されたら左へ移動
        vx = -4
        rightFlag = False
    if key[pygame.K_UP]:    # 上キーが押されたら上へ移動
        vy = -4
    if key[pygame.K_DOWN]:  # 下キーが押されたら下へ移動
        vy = 4

    ## 猫の処理
    neko_rect.x += vx
    neko_rect.y += vy
    if neko_rect.collidelist(walls) != -1: # 壁と衝突したらそれ以上動かない
        neko_rect.x -= vx
        neko_rect.y -= vy
    if rightFlag: # 猫の向きの指定
        screen.blit(neko_imgR, neko_rect)
    else:
        screen.blit(neko_imgL, neko_rect)
    ## 犬の処理
    for enemy in enemys: # enemysリストの全要素(敵のRect)
        screen.blit(enemy_img, enemy) 
    if neko_rect.collidelist(enemys) != -1: # 猫と犬との衝突判定
        page = 2
    ## 幽霊の処理

    ## ゴールの処理
    screen.blit(sakana_img,sakana_rect)
    if neko_rect.colliderect(sakana_rect): # 猫と魚の山との衝突判定
        page = 3
    ## 壁の処理
    for wall in walls:   # wallsリストの全要素(壁のRect)
        pygame.draw.rect(screen, pygame.Color("DARKGREEN"),wall)

## ジャンプ関数(ボタンが押されたらnewpageへジャンプする)
def button_to_jump(btn, newpage):
    global page, pushFlag
    #ユーザー入力
    mdown = pygame.mouse.get_pressed()
    (mx, my) = pygame.mouse.get_pos()
    if mdown[0]:
        if btn.collidepoint(mx, my) and pushFlag == False:
            page = newpage
            pushFlag = True
    else:
        pushFlag = False

## リセット関数(リセットボタンが押されたらゲームをリセットする)
def reset():
    # 猫を再配置
    neko_rect.x = 50
    neko_rect.y = 50
    # 犬を再配置
    for i in range(13):
        enemys[i].x = 100 + i * 50
        enemys[i].y = random.randint(20,550)
    # 幽霊を再配置


## ゲームオーバー関数
def gameover():
    reset() # リセット関数の呼び出し
    screen.fill(pygame.Color("NAVY"))
    font = pygame.font.Font(None, 150)
    text = font.render("GAMEOVER", True, pygame.Color("RED"))
    screen.blit(text, (100,200))
    btn1 = screen.blit(replay_img,(320,480))
    button_to_jump(btn1, 1) # ジャンプ関数の呼び出し

## ゲームクリア関数
def gameclear():
    reset() # リセット関数の呼び出し
    screen.fill(pygame.Color("GOLD"))
    font = pygame.font.Font(None, 150)
    text = font.render("GAMECLEAR", True, pygame.Color("RED"))
    screen.blit(text,(60,200))
    btn1 = screen.blit(replay_img,(320,480))
    button_to_jump(btn1,1) # ジャンプ関数の呼び出し


# メインループ
while True:
    if page == 1:
        gamestage()
    elif page == 2:
        gameover()
    elif page == 3:
        gameclear()
    #画面表示
    pygame.display.update()
    pygame.time.Clock().tick(60)
    # 終了処理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

Chapter3-4の記事の末尾にある完成コードをコピーしておいてください。

<<前のページ

pygameの記事一覧

Pythonのゲームライブラリ pygame を使ってゲームアプリを制作するページのアイキャッチ画像

次のページ>>

Pythonの学習の区切りを表し、記事一覧へ戻ることを促す画像

追跡アルゴリズムの基本を理解しよう

これまでのゲームでは、敵はあらかじめ配置された位置にじっとしており、プレイヤーが移動してぶつからなければゲームは進行していきました。

しかし現実のアクションゲームでは、プレイヤーの動きに反応する敵キャラクターが登場することが多く、そうした敵はゲームの緊張感や面白さを大きく引き上げてくれます。

【Python】勉強猫がノートパソコンを前にして学習を始める様子。記事内の学習スタート用イラスト

今回新たに追加する「幽霊」は、そのような動きのある敵キャラクターの第一歩です。

この幽霊はプレイヤーの動きに関係なく、常にプレイヤーの現在位置に向かって移動してきます。

こうした動きを実現するには、プレイヤーと敵の位置関係を計算し、敵をプレイヤーの方向へ少しずつ移動させるという処理が必要です。

この仕組みは「追跡アルゴリズム」と呼ばれ、ゲームAIの中でも基本的な考え方になります。

幽霊のような追跡型の敵を加えることで、プレイヤーに「動き続けなければ捕まってしまう」という新たなプレッシャーが生まれ、単純な回避だけではなく戦略的な操作も求められるようになります。

今回の実装を通じて、よりプレイしごたえのあるゲームづくりを体験していきましょう。

敵キャラ(幽霊)の画像と初期位置を設定

ゲームに新しいキャラクターを追加するには、まずそのキャラクターの「画像」と「初期位置」の設定を行う必要があります。

幽霊も同様で、ゲームに登場させるためには画像ファイルを読み込み、ゲーム画面上のどこに表示するかを指定します。

画像読み込みと編集方法

まずは、幽霊の画像ファイル yuurei.png を読み込みます。

さらにプレイヤーが左右に動くのに合わせて、幽霊の画像も左右反転できるように画像を2パターン用意しておきましょう。

コードを書いてみよう

action.py の「初期化(ゲームの準備をする)」の部分に、以下のコードを書き足しましょう。

## 敵の幽霊の設定
yuurei_imgR = pygame.image.load("images/yuurei.png")                # 右向きの画像
yuurei_imgR = pygame.transform.scale(yuurei_imgR, (50, 50))         # サイズを50x50に変更
yuurei_imgL = pygame.transform.flip(yuurei_imgR, True, False)       # 左右反転画像を作成

このコードでは、pygame.image.load()で画像を読み込み、pygame.transform.scale()で画像サイズを統一しています。

さらに、pygame.transform.flip()で左右反転した画像を作ることで、移動方向に応じて見た目を変えることができるようになります。

初期位置の座標指定

続いて、幽霊がゲーム開始時にどこに現れるかを指定します。

これは他のキャラクターと同じようにpygame.Rectを使って定義します。

コードを書いてみよう

action.py の「初期化(ゲームの準備をする)」の部分に、以下のコードを書き足しましょう。

先ほど書き足したコードの真下です。

yuurei_rect = pygame.Rect(50, 550, 50, 50)

このコードにより、幽霊はゲーム開始時に画面の左下(x=50, y=550)に現れます。

プレイヤーである猫は左上に出現するため、幽霊はそこからプレイヤーに向かってじわじわと近づいてくることになります。

プレイヤーを追いかける処理を実装

幽霊の画像と初期位置の設定が完了したら、次はプレイヤーを追いかけてくる動きを実装していきます。

このような処理を「追跡アルゴリズム」と呼びますが、今回は難しい計算は行わず、プレイヤーの位置と幽霊の位置を比較して少しずつ近づける というシンプルな方法を使います。

敵の移動方向を計算するロジック

まず、現在のプレイヤーの座標(neko_rect.x, neko_rect.y)と幽霊の座標(yuurei_rect.x, yuurei_rect.y)を比べて、どちらの方向に動けば近づけるかを判断します。

コードを書いてみよう

action.py の gamestage関数 の中に以下のコードを書き足しましょう。

    ## 幽霊の処理
	y_vx = 0  # 幽霊のx方向の移動量
	y_vy = 0  # 幽霊のy方向の移動量
	# 猫との位置を比較して移動方向を決定
	if yuurei_rect.x < neko_rect.x:
    	y_vx = 1  # プレイヤーより左にいる → 右に進む
	else:
    	y_vx = -1 # プレイヤーより右にいる → 左に進む
	if yuurei_rect.y > neko_rect.y:
    	y_vy = 1  # プレイヤーより下にいる → 上に進む
	else:
    	y_vy = -1 # プレイヤーより上にいる → 下に進む
	# 実際に幽霊を動かす
	yuurei_rect.x += y_vx
	yuurei_rect.y -= y_vy

このようにして、幽霊は毎フレーム1ピクセルずつプレイヤーの方向に向かって移動するようになります。

追跡スピードは「1」としてありますが、より速くしたい場合はこの数値を2や3に変更すれば対応できます。

方向に応じて画像を切り替える方法

幽霊の画像も、プレイヤーの右側にいるときは左向き画像、左側にいるときは右向き画像を表示するようにします。

コードを書いてみよう

action.py の gamestage関数 の中に以下のコードを書き足しましょう。

先ほど書き足したコードの真下です。

# 幽霊の向きに応じた画像の表示
if y_vx > 0:
    screen.blit(yuurei_imgR, yuurei_rect)  # 右向き画像を表示
else:
    screen.blit(yuurei_imgL, yuurei_rect)  # 左向き画像を表示

この処理をgamestage()関数の中に追加することで、幽霊がそれを追いかけてくる動きが実現します。

プレイヤーと敵の接触を判定しよう

幽霊がプレイヤーを追いかけてくる動きが完成したら、次に必要なのは「幽霊がプレイヤーにぶつかったかどうか」を判断する処理です。

これにより、プレイヤーが幽霊につかまった場合にゲームオーバーとすることができます。

衝突判定とは

衝突判定とは2つのオブジェクト(ここでは猫と幽霊)が同じ位置に重なっているかを調べる処理のことです。

Pygameではオブジェクトの位置と大きさを表すRect(矩形)に対して、colliderect()という便利な関数が用意されています。

この関数はあるRectが別のRectと重なっているかどうかを調べるもので、結果はTrueまたはFalseで返ってきます。

コードを書いてみよう

action.py の gamestage関数 の中に以下のコードを書き足しましょう。

先ほど書き足したコードの真下です。

# 幽霊とプレイヤーが衝突したか判定
if neko_rect.colliderect(yuurei_rect):
    page = 2  # 衝突したらゲームオーバー画面へ

このコードはneko_rectyuurei_rectが重なったときに変数page2に変更します。

pageの値が2になると、mainループgameover()関数が呼ばれるようになっており、自動的にゲームオーバー画面へと切り替わります。

幽霊の初期位置をリセットする

幽霊の動きと衝突判定が完成したことで、ゲームプレイ中にプレイヤーを追いかける敵としてしっかり機能するようになりました。

しかし、ゲームオーバー後にリセットボタンを押して再スタートしたときに、幽霊の位置がそのままになっていると、正しくゲームが始まりません。

そのため、他のキャラクター(猫や犬)と同じように、幽霊の初期位置もゲーム開始時の座標に戻す処理が必要です。

これを行うのが、ゲームの状態を初期化するreset()関数です。

コードを書いてみよう

action.py の reset()関数 の中に以下のコードを書き足しましょう。

# 幽霊を再配置
yuurei_rect.x = 50
yuurei_rect.y = 550

これでリセット時に幽霊もゲーム開始時の場所に戻るようになり、プレイヤーと同じタイミングで再スタートすることができます。

このようにプレイヤーだけでなく、ゲーム内のすべてのキャラクターや状態を初期化することは、ゲームの安定した動作にとって非常に重要です。

まとめ

Chapter3では簡単なアクションゲームを作りながら、実践的なゲームづくりの基本を一つ一つ積み重ねてきました。

以下の5つの記事を通して、プレイヤーの操作、敵キャラクターの設置、衝突によるゲームの状態遷移、ゴールの設定、そして動く敵の実装といった重要な技術を学びました。

  • 3-1 衝突判定の基本を理解しよう:プレイヤーと壁の衝突処理の方法
  • 3-2 画面に敵を表示しよう:敵キャラクター(犬)を表示し、画面上に配置
  • 3-3 ゲームオーバーを設定しよう:敵との接触でゲームオーバーになる仕組み
  • 3-4 ゲームクリアを設定しよう:ゴールに到達するとゲームクリアになる処理
  • 3-5 追跡してくる敵を実装しよう:追いかけてくる動的な敵を追加し、よりゲーム性を高めた

これらを通して、アクションゲームに必要な基本要素を一通り自分の手で作ることができるようになったはずです。

どの機能も一見シンプルに見えますが、組み合わせることでしっかりと遊べるゲームが完成しました。

ゲームづくりは創造力と工夫の連続です。今回学んだことを土台にして、さらに新しいアイデアを加えてみてください。後述の「チャレンジ!さらに面白いゲームに改造しよう!」に挑戦するのもお勧めです^^

ここまで学習を進めてきたあなたは、すでに立派なゲームクリエイターの仲間入りです。

ぜひ自分だけのオリジナルゲームづくりにチャレンジしてみてください。お疲れさまでした!

Q
Chapter3-5の完成コード

今回の記事での完成するコード全体は↓↓の通りです。

必要な方は開いて確認しましょう。

# 初期化(ゲームの準備をする)
import pygame, sys, random
pygame.init()
screen = pygame.display.set_mode((800,600))
## 背景画像の設定
haikei_img = pygame.image.load("images/shibafu.png")
haikei_img = pygame.transform.scale(haikei_img, (800, 600))
## プレイヤーの猫の設定
neko_imgR = pygame.image.load("images/neko.png")
neko_imgR = pygame.transform.scale(neko_imgR, (50,50))
neko_imgL = pygame.transform.flip(neko_imgR, True, False)
neko_rect = pygame.Rect(50,50,50,50) # 猫のRect
## 敵の犬の設定
enemy_img = pygame.image.load("images/inu.png")
enemy_img = pygame.transform.scale(enemy_img,(50,50))
enemys = [] # 複数の犬のRectを格納する空のリスト
for i in range(13):
    wx = 100 + i * 50
    wy = random.randint(20,550)
    enemys.append(pygame.Rect(wx,wy,50,50)) # 犬のRect
## 敵の幽霊の設定
yuurei_imgR = pygame.image.load("images/yuurei.png")
yuurei_imgR = pygame.transform.scale(yuurei_imgR,(50,50))
yuurei_imgL = pygame.transform.flip(yuurei_imgR,True, False)
yuurei_rect = pygame.Rect(50,550,50,50) # 幽霊のRect
## ゴールの設定
sakana_img = pygame.image.load("images/sakana.png")
sakana_img = pygame.transform.scale(sakana_img,(100,100))
sakana_rect = pygame.Rect(680,480,100,100)
## 壁の設定
walls = [pygame.Rect(0,0,800,20),
         pygame.Rect(0,0,20,600),
         pygame.Rect(780,0,20,600),
         pygame.Rect(0,580,800,20)]
## リセットボタンの設定
replay_img = pygame.image.load("images/replaybtn.png")

## メインループ内で使う変数
rightFlag = True # 猫の向き
pushFlag = False # リセットボタンが押されたか
page = 1         # 表示するページ(1:ゲーム画面、2:ゲームオーバー画面、3、ゲームクリア画面)


# ここから関数の定義
## ゲームステージ
def gamestage():
    global rightFlag
    global page
    # 画面の初期化
    screen.blit(haikei_img, (0,0))
    vx = 0
    vy = 0
    #ユーザー入力
    key = pygame.key.get_pressed()
    if key[pygame.K_RIGHT]: # 右キーが押されたら右へ移動
        vx = 4
        rightFlag = True
    if key[pygame.K_LEFT]:  # 左キーが押されたら左へ移動
        vx = -4
        rightFlag = False
    if key[pygame.K_UP]:    # 上キーが押されたら上へ移動
        vy = -4
    if key[pygame.K_DOWN]:  # 下キーが押されたら下へ移動
        vy = 4

    ## 猫の処理
    neko_rect.x += vx
    neko_rect.y += vy
    if neko_rect.collidelist(walls) != -1: # 壁と衝突したらそれ以上動かない
        neko_rect.x -= vx
        neko_rect.y -= vy
    if rightFlag: # 猫の向きの指定
        screen.blit(neko_imgR, neko_rect)
    else:
        screen.blit(neko_imgL, neko_rect)
    ## 犬の処理
    for enemy in enemys: # enemysリストの全要素(敵のRect)
        screen.blit(enemy_img, enemy) 
    if neko_rect.collidelist(enemys) != -1: # 猫と犬との衝突判定
        page = 2
    ## 幽霊の処理
    y_vx = 0 # 幽霊の移動量
    y_vy = 0
    if yuurei_rect.x < neko_rect.x: # ネコと幽霊の位置関係から移動方向を指定
        y_vx = 1
    else:
        y_vx = -1
    if yuurei_rect.y > neko_rect.y:
        y_vy = 1
    else:
        y_vy = -1
    yuurei_rect.x += y_vx
    yuurei_rect.y -= y_vy
    if y_vx > 0: # 幽霊の向きを指定
        screen.blit(yuurei_imgR,yuurei_rect)
    else:
        screen.blit(yuurei_imgL,yuurei_rect)
    if neko_rect.colliderect(yuurei_rect): # 猫と幽霊との衝突判定
        page = 2
    ## ゴールの処理
    screen.blit(sakana_img,sakana_rect)
    if neko_rect.colliderect(sakana_rect): # 猫と魚の山との衝突判定
        page = 3
    ## 壁の処理
    for wall in walls:   # wallsリストの全要素(壁のRect)
        pygame.draw.rect(screen, pygame.Color("DARKGREEN"),wall)

## ジャンプ関数(ボタンが押されたらnewpageへジャンプする)
def button_to_jump(btn, newpage):
    global page, pushFlag
    #ユーザー入力
    mdown = pygame.mouse.get_pressed()
    (mx, my) = pygame.mouse.get_pos()
    if mdown[0]:
        if btn.collidepoint(mx, my) and pushFlag == False:
            page = newpage
            pushFlag = True
    else:
        pushFlag = False

## リセット関数(リセットボタンが押されたらゲームをリセットする)
def reset():
    # 猫を再配置
    neko_rect.x = 50
    neko_rect.y = 50
    # 犬を再配置
    for i in range(13):
        enemys[i].x = 100 + i * 50
        enemys[i].y = random.randint(20,550)
    # 幽霊を再配置
    yuurei_rect.x = 50
    yuurei_rect.y = 550

## ゲームオーバー関数
def gameover():
    reset() # リセット関数の呼び出し
    screen.fill(pygame.Color("NAVY"))
    font = pygame.font.Font(None, 150)
    text = font.render("GAMEOVER", True, pygame.Color("RED"))
    screen.blit(text, (100,200))
    btn1 = screen.blit(replay_img,(320,480))
    button_to_jump(btn1, 1) # ジャンプ関数の呼び出し

## ゲームクリア関数
def gameclear():
    reset() # リセット関数の呼び出し
    screen.fill(pygame.Color("GOLD"))
    font = pygame.font.Font(None, 150)
    text = font.render("GAMECLEAR", True, pygame.Color("RED"))
    screen.blit(text,(60,200))
    btn1 = screen.blit(replay_img,(320,480))
    button_to_jump(btn1,1) # ジャンプ関数の呼び出し


# メインループ
while True:
    if page == 1:
        gamestage()
    elif page == 2:
        gameover()
    elif page == 3:
        gameclear()
    #画面表示
    pygame.display.update()
    pygame.time.Clock().tick(60)
    # 終了処理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

<<前のページ

pygameの記事一覧

Pythonのゲームライブラリ pygame を使ってゲームアプリを制作するページのアイキャッチ画像

次のページ>>

Pythonの学習の区切りを表し、記事一覧へ戻ることを促す画像

チャレンジ!さらに面白いゲームに改造しよう!

アクションゲームの製作講座はここで終了ですが、このゲームはまだまだ面白くできる余地があるとおもいませんか?

以下のアイディアをベースにして、あなたの手でより面白いゲームへ作り変えてみて下さい。

  • 犬の敵に動きをつける
  • 壁を作って迷路にし、犬を特定の場所に配置+動かす
  • 特定のRectに触れると別のRectの位置へワープする
  • 複数のステージを作り、クリア後に次のステージへ移動する

FAQ|敵の追跡アルゴリズム【pygame】

Q
Q1. 敵キャラがプレイヤーを追いかけるにはどんなロジックが必要?

プレイヤーと敵の座標を比較し、方向ごとに速度を加算・減算することで追跡の動きを作ることができます。

Q
Q2. 敵の動きが滑らかにならない場合の対処法は?

フレームごとの移動量が多すぎたり、座標の更新が整数単位で行われているとカクつきが出やすくなります。微調整を行いましょう。

Q
Q3. 敵の向きに応じて画像を切り替える方法は?

左右の移動方向を判定して、pygameのtransform.flip()などで画像を反転させることで、向きを変える表現が可能です。

質問用コンタクトフォーム

この記事を書くにあたりAIを活用しています。

人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。

pygame記事一覧へ戻る
Python記事一覧へ戻る

記事URLをコピーしました