コンテンツにスキップ

第4週:オブジェクトを動かそう - Unityスクリプト入門

前回はPythonとC#の違いを学び、Visual Studioの使い方を練習しました。 今日はいよいよUnityでC#スクリプトを作成し、実際にオブジェクトを動かします!

  • UnityでC#スクリプトを作成する
  • スクリプトをGameObjectにアタッチする
  • Start()とUpdate()メソッドを理解する
  • Transformを使ってオブジェクトを動かす

第3週でもFirstScriptを1つ作りましたが、これから何度も作るので、 あらためて手順と名前の付け方を確認します。

方法1:Projectウィンドウから作成

Section titled “方法1:Projectウィンドウから作成”
  1. Projectウィンドウで右クリック
  2. Create → MonoBehaviour Script を選択
  3. 名前を入力できる状態になるので、そのままMyFirstScriptと入力
  4. Enterキーで確定
スクリプト作成メニュー
スクリプト作成メニュー
  1. メニューバーのAssets → Create → MonoBehaviour Script
  2. スクリプト名を入力

スクリプトの中身を見てみよう

Section titled “スクリプトの中身を見てみよう”

新しく作成したスクリプトをダブルクリックすると、Visual Studioが開きます:

using UnityEngine;
public class MyFirstScript : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
スクリプトの基本構造
スクリプトの基本構造
コード 説明
using UnityEngine; Unityの機能を使うための宣言
public class MyFirstScript クラスの定義(スクリプト名と同じ)
: MonoBehaviour Unityのスクリプトの基本クラスを継承
void Start() ゲーム開始時に1回だけ実行される
void Update() 毎フレーム実行される(1秒間に約60回)

Pythonとの違い - 関数からクラスへ

Section titled “Pythonとの違い - 関数からクラスへ”

Pythonではこれまで関数を中心に学んできましたが、C#では「クラス」という仕組みを使います。

クラスは「設計図」のようなものです。ゲームのキャラクターで例えると:

  • クラス:「プレイヤー」の設計図
    • HP、攻撃力、スピードなどのデータ(変数)
    • 歩く、ジャンプする、攻撃するなどの動作(メソッド)
  • オブジェクト:実際のキャラクター
    • 設計図から作られた実体
    • 同じ設計図から複数作れる(敵キャラ1、敵キャラ2…)
クラスとオブジェクトの関係
クラスとオブジェクトの関係

Unityでは:

  • GameObject:ゲーム内のオブジェクト(円、四角、キャラクターなど)
  • スクリプト(クラス):そのオブジェクトの動きを定義
  • アタッチ:スクリプトをGameObjectに付ける = 設計図を適用
クラス宣言部分の説明
public class MyFirstScript : MonoBehaviour // ← これ
{
// MonoBehaviourを継承すると使える機能:
// - Start():開始時に1回実行
// - Update():毎フレーム実行
// - transform:位置・回転・大きさ
// - gameObject:自分自身のGameObject
}

MonoBehaviourは、Unityが用意している「基本クラス」です。これを継承(受け継ぐ)することで:

  • Start()やUpdate()が自動的に呼ばれる
  • transformで位置を変更できる
  • GameObjectとして動作する

まず、きれいな状態から始めるために新しいシーンを作成します:

  1. File → New Scene(または Ctrl + N)
  2. Lit 2D (URP)を選択
    • 一覧の左上にあり、ピン留めのマークが付いています
    • 2D用に設定されたカメラと、2D用のライトが入っています
  3. 右下の「Create」をクリック
  4. まだ保存していないので、Ctrl + Sで名前を付けて保存
    (例:ScriptPractice
New Sceneダイアログ
New Sceneダイアログ

スクリプトをテストするためのオブジェクトを作りましょう:

  1. Hierarchy で右クリック
  2. 2D Object → Sprites → Circle を選択
  3. 名前を「Player」に変更(F2キー)
  4. Position を (0, 0, 0) に設定(Inspectorで確認)
練習用オブジェクト作成
練習用オブジェクト作成

スクリプトをGameObjectにアタッチ

Section titled “スクリプトをGameObjectにアタッチ”

スクリプトを作っただけでは動きません。先ほど作った「Player」オブジェクトに「アタッチ(取り付ける)」する必要があります。

アタッチの概念図
アタッチの概念図
  1. Hierarchyで「Player」を選択
  2. Projectウィンドウから「MyFirstScript」をInspectorにドラッグ
  3. Inspectorの一番下にスクリプトが追加される
ドラッグでアタッチ
ドラッグでアタッチ
  1. Hierarchyで「Player」を選択
  2. Inspectorの一番下の「Add Component」ボタンをクリック
  3. Scripts → MyFirstScript を選択
Add Componentメニュー
Add Componentメニュー
  • Inspectorにスクリプト名が表示される
  • チェックボックスで有効/無効を切り替えられる
  • 歯車アイコンからRemove Componentで削除できる

フレームって何? - ゲームの仕組み

Section titled “フレームって何? - ゲームの仕組み”

映画やアニメと同じように、ゲームも実は「静止画」を高速で切り替えて動いているように見せています。

  • フレーム:1枚の静止画のこと
  • FPS(Frames Per Second):1秒間に表示するフレーム数
  • 60FPS:1秒間に60枚の画像を表示(なめらか)
  • 30FPS:1秒間に30枚の画像を表示(普通)
フレームの概念
フレームの概念

対戦ゲームをしている人は聞いたことがあるかもしれません:

FPS 特徴
30FPS 普通に動く Nintendo Switch(携帯モード)の多くのゲーム
60FPS なめらかに動く PlayStation、PC、Switchドックモード
120FPS とてもなめらか ゲーミングPC、一部のスマホゲーム
144FPS以上 プロゲーマー向け 高性能ゲーミングPC
Update()メソッドの実行頻度
void Update()
{
// この中のコードが「毎フレーム」実行される
// 60FPSなら → 1秒間に60回実行
// 30FPSなら → 1秒間に30回実行
}

つまり:

  • Update()は画面が更新されるたびに呼ばれる
  • 60FPSのゲームなら、Update()は1秒間に60回実行
  • だからUpdate()の中で少しずつ動かすと、なめらかに動く
Update()の実行タイミング
Update()の実行タイミング
メソッド部分のみ(クラス宣言は省略)
void Start()
{
// 初期設定を書く場所
Debug.Log("このオブジェクトが作られました");
// 変数の初期化
int hp = 100;
string playerName = "勇者";
// 初期位置の設定
transform.position = new Vector3(0, 0, 0);
}

Update()メソッド - 毎フレーム実行

Section titled “Update()メソッド - 毎フレーム実行”
メソッド部分のみ(クラス宣言は省略)
void Update()
{
// 毎フレーム実行したいことを書く
// 例:常に右に動く
transform.position += new Vector3(0.01f, 0, 0);
// 注意:Debug.Logは大量に出力される
// Debug.Log("動いています"); // これは避ける
}
Start vs Update実行タイミング
Start vs Update実行タイミング
メソッド 実行回数 使用例
Start() 1回だけ 初期設定、開始メッセージ、初期位置設定
Update() 毎フレーム 移動、回転、入力チェック、アニメーション

Transformでオブジェクトを動かそう

Section titled “Transformでオブジェクトを動かそう”

すべてのGameObjectが持っている位置・回転・大きさの情報です。

transformプロパティの例
// transformの3つの要素
transform.position // 位置(Vector3)
transform.rotation // 回転(Quaternion)
transform.localScale // 大きさ(Vector3)
Start()とUpdate()メソッドの実装例
void Start()
{
// 位置を直接設定
transform.position = new Vector3(2, 1, 0);
// X=2, Y=1, Z=0の位置に移動
}
void Update()
{
// 少しずつ移動(右に動く)
transform.position += new Vector3(0.01f, 0, 0);
// 変数を使った移動
float speed = 0.05f;
transform.position += new Vector3(speed, 0, 0);
}
位置の変更例
位置の変更例
Update()メソッド内での回転処理
void Update()
{
// Z軸回りに回転(2Dでよく使う)
transform.Rotate(0, 0, 1); // 毎フレーム1度回転
// 回転速度を調整
float rotateSpeed = 2.0f;
transform.Rotate(0, 0, rotateSpeed);
}
Start()とUpdate()メソッドでのスケール変更
void Start()
{
// 2倍の大きさにする
transform.localScale = new Vector3(2, 2, 1);
// X方向だけ伸ばす
transform.localScale = new Vector3(3, 1, 1);
}
void Update()
{
// 少しずつ大きくなる
transform.localScale += new Vector3(0.01f, 0.01f, 0);
}
スケール変更例
スケール変更例

3次元の座標や方向を表すデータ型です。2Dゲームでも使います(Zは0にする)。

Vector3の使用例
// Vector3の作り方
Vector3 pos = new Vector3(1, 2, 0);
// X=1, Y=2, Z=0
// 個別にアクセス
float x = pos.x; // 1
float y = pos.y; // 2
float z = pos.z; // 0
// よく使う定数
Vector3.zero // (0, 0, 0)
Vector3.one // (1, 1, 1)
Vector3.right // (1, 0, 0)
Vector3.up // (0, 1, 0)
Vector3.forward // (0, 0, 1)
Vector3の演算例
// 足し算・引き算
Vector3 a = new Vector3(1, 2, 0);
Vector3 b = new Vector3(3, 1, 0);
Vector3 c = a + b; // (4, 3, 0)
Vector3 d = a - b; // (-2, 1, 0)
// スカラー倍
Vector3 e = a * 2; // (2, 4, 0)
Vector3 f = a / 2; // (0.5, 1, 0)

実践:簡単な動きを作ってみよう

Section titled “実践:簡単な動きを作ってみよう”
public class MoveBackAndForth : MonoBehaviour
{
float speed = 2.0f;
float range = 3.0f;
float startX;
void Start()
{
// 開始位置を記憶
startX = transform.position.x;
}
void Update()
{
// Sin波を使った往復運動
float newX = startX + Mathf.Sin(Time.time * speed) * range;
transform.position = new Vector3(newX, transform.position.y, 0);
}
}
往復運動の例
往復運動の例
public class CircleMove : MonoBehaviour
{
float radius = 2.0f; // 半径
float speed = 1.0f; // 速度
void Update()
{
float x = Mathf.Cos(Time.time * speed) * radius;
float y = Mathf.Sin(Time.time * speed) * radius;
transform.position = new Vector3(x, y, 0);
}
}
public class PulseScale : MonoBehaviour
{
float minScale = 0.5f;
float maxScale = 1.5f;
float speed = 2.0f;
void Update()
{
float scale = Mathf.Lerp(minScale, maxScale,
(Mathf.Sin(Time.time * speed) + 1) / 2);
transform.localScale = new Vector3(scale, scale, 1);
}
}

ゲーム開始からの経過時間(秒)です。

Time.timeの使用例
void Update()
{
// ゲーム開始から3秒後に実行
if (Time.time > 3.0f)
{
Debug.Log("3秒経ちました");
}
}

前のフレームからの経過時間です。フレームレートに依存しない動きを作るのに使います。

Time.deltaTimeの使用例
void Update()
{
// フレームレートに関係なく、1秒で1移動
float speed = 1.0f;
transform.position += Vector3.right * speed * Time.deltaTime;
}
deltaTimeの重要性
deltaTimeの重要性
エラーメッセージ 原因と対処法
The script don’t inherit a native class MonoBehaviourのスペルミス → 修正する
Can’t add script クラス名とファイル名が違う → 一致させる
NullReferenceException オブジェクトが設定されていない → 確認する
エラー表示例
エラー表示例
  • エラーをダブルクリック:該当行にジャンプ
  • Debug.Logを活用:変数の値を確認
  • 一時停止ボタン:ゲームを止めて確認
  • ステップ実行:1行ずつ実行して確認

基礎課題全員必須

基本的な動きのスクリプト作成:

  • 新しいシーンを作成
  • Circleを配置
  • MoveRightスクリプトを作成
  • Update()で右に動くようにする
  • Debug.Logで位置を表示

標準課題時間があれば

複数の動きを組み合わせる:

  • 3つのオブジェクトを作成
  • それぞれ違う動き(横移動、回転、拡大縮小)
  • Time.deltaTimeを使って速度調整
  • Start()で初期メッセージ表示

発展課題チャレンジ

インタラクティブな動き:

  • マウスの位置に追従するオブジェクト
  • クリックで色が変わる機能
  • 画面端で跳ね返る動き
  • 複数のスクリプトを1つのオブジェクトに
条件付きデバッグの実装
void Update()
{
// 特定の条件でのみログ出力
if (transform.position.x > 5)
{
Debug.LogWarning("画面外に出そうです!");
}
// 一定間隔でログ出力
if (Time.frameCount % 60 == 0) // 60フレームごと
{
Debug.Log("1秒経過:" + Time.time);
}
}

次回からは、いよいよパズルゲームの制作に入ります。 まずは玉の画像を取り込んで、Unityの物理エンジンで落としてみます。 今日のようにスクリプトを書かなくても、物が落ちて床に乗るところまで作れます。