皆さん、こんにちはイデアルアーキテクツ ゲーム事業部の塚本です。
私は昔プログラムも組むクリエイターでしたが、もう10年ほど本格的な開発から遠ざかっています。そんなロートルプログラマな私がChatGPTを使用してコーディングをしてみようと思います。そのやり取りを今回記事にしますので良かったら参考にしてみてください。
今回はカジュアルゲームに使えるようなゲームの基幹部分として弾を放物線上に射出する部分とその放物線を射出前に事前に表示する部分をChatGPTに組んでもらおうと思います。
まず最初にChatGPTに指示したプロンプトは以下の様にしました。
「Unityでマウスを使って上下左右の方向を指定して離すとオブジェクトを射出し放物線を描いて地面に落ちるスクリプトを教えてください。
また射出する前はオブジェクトを射出する方向を点線で示すようにしてください。」
これに対してChatGPTが出力したのが以下のソースコードになります。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileShooter : MonoBehaviour
{
public GameObject projectilePrefab; // 射出するオブジェクト
public Transform shootPoint; // 射出位置
public float shootForce = 10f; // 射出の強さ
public int lineSegmentCount = 20; // 点線のセグメント数
public LineRenderer lineRenderer; // 点線描画用
private Vector3 startMousePosition;
private Vector3 endMousePosition;
private bool isDragging = false;
void Update()
{
if (Input.GetMouseButtonDown(0)) // マウスの左ボタンを押したらドラッグ開始
{
isDragging = true;
startMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0) && isDragging) // マウスを押し続けている間
{
Vector3 currentMousePosition = Input.mousePosition;
DrawTrajectory(currentMousePosition);
}
if (Input.GetMouseButtonUp(0) && isDragging) // マウスを離したら射出
{
isDragging = false;
endMousePosition = Input.mousePosition;
ShootProjectile();
lineRenderer.positionCount = 0; // 点線を消去
}
}
void DrawTrajectory(Vector3 currentMousePosition)
{
// マウスのドラッグ量を計算して射出方向を決定
Vector3 dragDirection = (currentMousePosition - startMousePosition);
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
// 射出方向を基に点線を描画
Vector3 velocity = worldDragDirection * shootForce;
Vector3[] points = new Vector3[lineSegmentCount];
Vector3 currentPoint = shootPoint.position;
for (int i = 0; i < lineSegmentCount; i++)
{
float time = i * 0.1f;
points[i] = currentPoint + velocity * time + 0.5f * Physics.gravity * time * time;
}
lineRenderer.positionCount = lineSegmentCount;
lineRenderer.SetPositions(points);
}
void ShootProjectile()
{
// マウスのドラッグ量を計算して射出方向を決定
Vector3 dragDirection = (endMousePosition - startMousePosition);
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
// 射出するオブジェクトを生成
GameObject projectile = Instantiate(projectilePrefab, shootPoint.position, Quaternion.identity);
Rigidbody rb = projectile.GetComponent<Rigidbody>();
if (rb != null)
{
rb.velocity = worldDragDirection * shootForce; // 射出力を適用
}
}
}
教えてもらった通りオブジェクトを配置してインスペクタから各プロパティなどを設定します。
そうして実行した所以下の様な状態になりました。
マウス移動で放物線を描き弾を発射する挙動は合っていますが
「左右上下」と日本語?で書いたのがいけなかったのか、カメラから見て
右側に弾を発射するスクリプトになっています。
それを修正するために次はプロンプトを以下の様にしてみました。
「射出するのは画面に対して奥(z軸の₊正の方向)になります。スクリプトを修正して下さい。」
そのプロンプトに対してChatGPTが出力したスクリプトが以下です。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileShooter : MonoBehaviour
{
[Header("射出設定")]
[Tooltip("Hierarchy上の射出するオブジェクトを指定してください")]
public GameObject projectileObject; // 射出するオブジェクト(Hierarchy上)
[Tooltip("射出開始位置を指定してください")]
public Transform shootPoint; // 射出位置
[Tooltip("射出時の速度を調整します")]
public float shootForce = 10f; // 射出の強さ
[Header("点線設定")]
[Tooltip("点線で放物線を描画するためのLineRenderer")]
public LineRenderer lineRenderer; // 点線描画用
[Tooltip("点線の分割数を調整します")]
public int lineSegmentCount = 20; // 点線のセグメント数
private Vector3 startMousePosition;
private Vector3 endMousePosition;
private bool isDragging = false;
void Update()
{
if (Input.GetMouseButtonDown(0)) // マウス左クリックを押したとき
{
isDragging = true;
startMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0) && isDragging) // マウスドラッグ中
{
Vector3 currentMousePosition = Input.mousePosition;
DrawTrajectory(currentMousePosition);
}
if (Input.GetMouseButtonUp(0) && isDragging) // マウスを離したとき
{
isDragging = false;
endMousePosition = Input.mousePosition;
ShootProjectile();
lineRenderer.positionCount = 0; // 点線を消去
}
}
void DrawTrajectory(Vector3 currentMousePosition)
{
// マウスのドラッグ量を計算して射出方向を決定
Vector3 dragDirection = (currentMousePosition - startMousePosition);
float dragStrength = dragDirection.magnitude; // ドラッグの強さ(速さに影響)
// マウスのスクリーン座標をワールド座標の方向に変換
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
// カメラの前方向(z軸)を基準に射出方向を決定
Vector3 shootDirection = Camera.main.transform.TransformDirection(new Vector3(worldDragDirection.x, worldDragDirection.y, 1)).normalized;
// 射出速度ベクトル
Vector3 velocity = shootDirection * dragStrength * shootForce * 0.01f; // スケール調整
// 点線を描画
Vector3[] points = new Vector3[lineSegmentCount];
Vector3 currentPoint = shootPoint.position;
for (int i = 0; i < lineSegmentCount; i++)
{
float time = i * 0.1f;
points[i] = currentPoint + velocity * time + 0.5f * Physics.gravity * time * time;
}
lineRenderer.positionCount = lineSegmentCount;
lineRenderer.SetPositions(points);
}
void ShootProjectile()
{
if (projectileObject != null)
{
// 射出するオブジェクトを射出位置に移動
projectileObject.transform.position = shootPoint.position;
// Rigidbodyを取得し、射出方向に力を加える
Rigidbody rb = projectileObject.GetComponent<Rigidbody>();
if (rb != null)
{
// マウスのドラッグ方向を取得
Vector3 dragDirection = (endMousePosition - startMousePosition);
float dragStrength = dragDirection.magnitude;
// マウスのスクリーン座標をワールド座標の方向に変換
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
// カメラの前方向(z軸)を基準に射出方向を決定
Vector3 shootDirection = Camera.main.transform.TransformDirection(new Vector3(worldDragDirection.x, worldDragDirection.y, 1)).normalized;
// 射出速度を計算して適用
rb.velocity = shootDirection * dragStrength * shootForce * 0.01f;
}
}
else
{
Debug.LogWarning("Projectile Object が指定されていません");
}
}
}
スクリプトを上書きして実行すると今度は問題無く画面奥に対して
放物線を描き弾も発射するようになりました。
次に気になったのは弾を発射する前に描く放物線の太さです。
かっこ悪い上に目標が見えません。
早速ChatGPTに相談です。
「放物線を細くしてください」
またまたChatGPTは甲斐甲斐しくスクリプトを出力してくれます。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileShooter : MonoBehaviour
{
[Header("射出設定")]
public GameObject projectileObject; // 射出するオブジェクト(Hierarchy上)
public Transform shootPoint; // 射出位置
public float shootForce = 10f; // 射出の強さ
[Header("点線設定")]
public LineRenderer lineRenderer; // 点線描画用
public int lineSegmentCount = 20; // 点線のセグメント数
public float lineWidth = 0.05f; // 放物線の線の幅
private Vector3 startMousePosition;
private Vector3 endMousePosition;
private bool isDragging = false;
void Start()
{
// LineRendererの幅を設定
if (lineRenderer != null)
{
lineRenderer.startWidth = lineWidth;
lineRenderer.endWidth = lineWidth;
}
}
void Update()
{
if (Input.GetMouseButtonDown(0)) // マウス左クリックを押したとき
{
isDragging = true;
startMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0) && isDragging) // マウスドラッグ中
{
Vector3 currentMousePosition = Input.mousePosition;
DrawTrajectory(currentMousePosition);
}
if (Input.GetMouseButtonUp(0) && isDragging) // マウスを離したとき
{
isDragging = false;
endMousePosition = Input.mousePosition;
ShootProjectile();
lineRenderer.positionCount = 0; // 点線を消去
}
}
void DrawTrajectory(Vector3 currentMousePosition)
{
Vector3 dragDirection = (currentMousePosition - startMousePosition);
float dragStrength = dragDirection.magnitude;
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
Vector3 shootDirection = Camera.main.transform.TransformDirection(new Vector3(worldDragDirection.x, worldDragDirection.y, 1)).normalized;
Vector3 velocity = shootDirection * dragStrength * shootForce * 0.01f;
Vector3[] points = new Vector3[lineSegmentCount];
Vector3 currentPoint = shootPoint.position;
for (int i = 0; i < lineSegmentCount; i++)
{
float time = i * 0.1f;
points[i] = currentPoint + velocity * time + 0.5f * Physics.gravity * time * time;
}
lineRenderer.positionCount = lineSegmentCount;
lineRenderer.SetPositions(points);
}
void ShootProjectile()
{
if (projectileObject != null)
{
projectileObject.transform.position = shootPoint.position;
Rigidbody rb = projectileObject.GetComponent<Rigidbody>();
if (rb != null)
{
Vector3 dragDirection = (endMousePosition - startMousePosition);
float dragStrength = dragDirection.magnitude;
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
Vector3 shootDirection = Camera.main.transform.TransformDirection(new Vector3(worldDragDirection.x, worldDragDirection.y, 1)).normalized;
rb.velocity = shootDirection * dragStrength * shootForce * 0.01f;
}
}
else
{
Debug.LogWarning("Projectile Object が指定されていません");
}
}
}
これで線が調整できるようになりました。
インスペクタから線を調度良い感じになるようにパラメータを変更してあげます。
次にお願いしたのは放物線を点線に変える事です。
「放物線を点線にするにはどうしたらいいですか?」
プロンプトを打つとChatGPTは2つの答えを出力してくれました。
一つ目の方法はマテリアルで表現する方法
二つ目の方法はスクリプトで表現する方法です。
マテリアルを用意するのが面倒だったのまずはスクリプトで実装したいと思います。
そのスクリプトが以下です。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ProjectileShooter : MonoBehaviour
{
[Header("射出設定")]
public GameObject projectileObject; // 射出するオブジェクト(Hierarchy上)
public Transform shootPoint; // 射出位置
public float shootForce = 10f; // 射出の強さ
[Header("点線設定")]
public LineRenderer lineRenderer; // 点線描画用
public int lineSegmentCount = 20; // 点線のセグメント数
public float lineWidth = 0.05f; // 放物線の線の幅
public float dashSpacing = 0.5f; // 点線の間隔
private Vector3 startMousePosition;
private Vector3 endMousePosition;
private bool isDragging = false;
void Start()
{
// LineRendererの幅を設定
if (lineRenderer != null)
{
lineRenderer.startWidth = lineWidth;
lineRenderer.endWidth = lineWidth;
}
}
void Update()
{
if (Input.GetMouseButtonDown(0)) // マウス左クリックを押したとき
{
isDragging = true;
startMousePosition = Input.mousePosition;
}
if (Input.GetMouseButton(0) && isDragging) // マウスドラッグ中
{
Vector3 currentMousePosition = Input.mousePosition;
DrawTrajectory(currentMousePosition);
}
if (Input.GetMouseButtonUp(0) && isDragging) // マウスを離したとき
{
isDragging = false;
endMousePosition = Input.mousePosition;
ShootProjectile();
lineRenderer.positionCount = 0; // 点線を消去
}
}
void DrawTrajectory(Vector3 currentMousePosition)
{
Vector3 dragDirection = (currentMousePosition - startMousePosition);
float dragStrength = dragDirection.magnitude;
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
Vector3 shootDirection = Camera.main.transform.TransformDirection(new Vector3(worldDragDirection.x, worldDragDirection.y, 1)).normalized;
Vector3 velocity = shootDirection * dragStrength * shootForce * 0.01f;
List<Vector3> points = new List<Vector3>();
Vector3 currentPoint = shootPoint.position;
// 点線を計算
for (int i = 0; i < lineSegmentCount; i++)
{
float time = i * dashSpacing; // 点線の間隔を適用
Vector3 point = currentPoint + velocity * time + 0.5f * Physics.gravity * time * time;
points.Add(point);
}
lineRenderer.positionCount = points.Count;
lineRenderer.SetPositions(points.ToArray());
}
void ShootProjectile()
{
if (projectileObject != null)
{
projectileObject.transform.position = shootPoint.position;
Rigidbody rb = projectileObject.GetComponent<Rigidbody>();
if (rb != null)
{
Vector3 dragDirection = (endMousePosition - startMousePosition);
float dragStrength = dragDirection.magnitude;
Vector3 worldDragDirection = new Vector3(dragDirection.x, dragDirection.y, 0).normalized;
Vector3 shootDirection = Camera.main.transform.TransformDirection(new Vector3(worldDragDirection.x, worldDragDirection.y, 1)).normalized;
rb.velocity = shootDirection * dragStrength * shootForce * 0.01f;
}
}
else
{
Debug.LogWarning("Projectile Object が指定されていません");
}
}
}
実行してみましたが、どうにもカクカクです…。
ここは大人しくマテリアルを用意してあげる方が良さそうです。
仕方が無いのでマテリアルを用意しました。
というわけで、作ったマテリアルを放物線のオブジェクトに適用したのが
以下の状態です。
なんとなく様になったんでは無いでしょうか?
ここまでの作業の所用時間は30分程度でした。
こんな感じである程度のプログラムの知識があれば
ChatGPTを使って簡単に時短でプログラムすることが可能です。
興味が湧いたら、是非皆さんもChatGPTと会話しながら是非プログラミングしてみてください。
それでは、皆さん次の記事でお会いしましょう!
/assets/images/543744/original/698edbe5-db67-4c0e-8fa0-447b6b87153c.jpeg?1472709375)