Unity

今は、マウスで押された場合になっているので、次はコントローラーで動くようにします

ElevatorSwitchForControllerスクリプトを追加

using UnityEngine;

public class ElevatorSwitchForController : MonoBehaviour
{
[Header("検出設定")]
[SerializeField] private float detectionRange = 5f; // 検出範囲
[SerializeField] private bool showGizmo = true; // 範囲を可視化するか
[SerializeField] public Elevator[] elevators; // 連携設定

[Header("表示するオブジェクト")]
[SerializeField] private GameObject targetObject; // 表示/非表示するオブジェクト
[SerializeField] private bool useThisObject = false; // このオブジェクト自体を表示/非表示するか

[Header("回転設定")]
[SerializeField] private bool smoothRotation = true; // なめらかな回転にするか
[SerializeField] private float rotationSpeed = 5f; // 回転速度
[SerializeField] private bool lockYAxis = false; // Y軸回転のみにするか(水平回転のみ)
[SerializeField] private Vector3 rotationOffset = Vector3.zero; // 回転のオフセット

private Transform player; // プレイヤーのTransform
private bool playerInRange = false; // プレイヤーが範囲内にいるか
private GameObject objectToControl; // 制御するオブジェクト
private bool button = false; // ボタンを反応させるようにする

void Start()
{
// プレイヤーを検索
FindPlayer();

// 制御するオブジェクトを決定
if (useThisObject)
{
objectToControl = gameObject;
}
else if (targetObject != null)
{
objectToControl = targetObject;
}
else
{
Debug.LogWarning("表示するオブジェクトが設定されていません。");
return;
}

// 初期状態では非表示
objectToControl.SetActive(false);
}

void Update()
{
if (player == null)
{
FindPlayer();
return;
}

CheckPlayerDistance();

if (playerInRange && objectToControl.activeInHierarchy)
{
LookAtPlayer();
}

if (button == true)
{
if ((Input.GetKeyDown(KeyCode.Joystick1Button2)))
{
foreach (var elevator in elevators)
{
elevator.MoveUp();
}
}
}
}

private void FindPlayer()
{
GameObject playerObject = GameObject.FindGameObjectWithTag("Player");
if (playerObject != null)
{
player = playerObject.transform;
Debug.Log("プレイヤーを見つけました: " + playerObject.name);
}
else
{
Debug.LogWarning("'Player'タグの付いたオブジェクトが見つかりません。");
}
}

private void CheckPlayerDistance()
{
if (player == null || objectToControl == null) return;

float distance = Vector3.Distance(transform.position, player.position);
bool shouldBeActive = distance <= detectionRange;

if (shouldBeActive && !playerInRange)
{
// プレイヤーが範囲内に入った
playerInRange = true;
objectToControl.SetActive(true);
Debug.Log("プレイヤーが範囲内に入りました。オブジェクトを表示します。");
button = true;
}
else if (!shouldBeActive && playerInRange)
{
// プレイヤーが範囲外に出た
playerInRange = false;
objectToControl.SetActive(false);
Debug.Log("プレイヤーが範囲外に出ました。オブジェクトを非表示にします。");
}
}

private void LookAtPlayer()
{
if (player == null) return;

// プレイヤーへの方向ベクトルを計算
Vector3 direction = player.position - objectToControl.transform.position;

// Y軸をロックする場合
if (lockYAxis)
{
direction.y = 0;
}

// 方向ベクトルが0の場合は処理しない
if (direction.magnitude < 0.01f) return;

// 目標の回転を計算
Quaternion targetRotation = Quaternion.LookRotation(direction);

// オフセットを適用
if (rotationOffset != Vector3.zero)
{
targetRotation *= Quaternion.Euler(rotationOffset);
}

// なめらかな回転 or 即座に回転
if (smoothRotation)
{
objectToControl.transform.rotation = Quaternion.Slerp(
objectToControl.transform.rotation,
targetRotation,
rotationSpeed * Time.deltaTime
);
}
else
{
objectToControl.transform.rotation = targetRotation;
}
}

// 検出範囲を変更する外部メソッド
public void SetDetectionRange(float newRange)
{
detectionRange = newRange;
}

// プレイヤーが範囲内にいるかを取得
public bool IsPlayerInRange()
{
return playerInRange;
}

// Gizmoで検出範囲を表示(エディタ上でのデバッグ用)
void OnDrawGizmosSelected()
{
if (!showGizmo) return;

// 検出範囲を表示
Gizmos.color = playerInRange ? Color.green : Color.yellow;
Gizmos.DrawWireSphere(transform.position, detectionRange);

// プレイヤーとの接続線を表示
if (player != null && playerInRange)
{
Gizmos.color = Color.red;
Gizmos.DrawLine(transform.position, player.position);

if (objectToControl != null && objectToControl.activeInHierarchy)
{
Gizmos.color = Color.blue;
Gizmos.DrawRay(objectToControl.transform.position, objectToControl.transform.forward * 2f);
}
}
}

void OnDrawGizmos()
{
if (!showGizmo) return;

// 常に検出範囲を薄く表示
Gizmos.color = new Color(1f, 1f, 0f, 0.1f);
Gizmos.DrawSphere(transform.position, detectionRange);
}
}

DetactionRange 検出範囲の半径

ShowGizmo エディタ上で検出範囲を見えるようにする

TargetObject 動かしたいオブジェクトを入れる

UseThisObject 自分自身を制御する

SmoothRotation なめらかに回転させる

RotationSpeed 回転速度を設定

LockYAxis 水平回転のみ(Y軸固定)

RotationOffset 回転のオフセット

現在の様子

このように、いろいろ作れました!

これからもどんどん作っていきます

エレベーターの目的地をGameObjectを設定するのがめんどくさかったので数字に変更!

エレベータープログラム

using System.Collections;
using UnityEngine;

public class Elevator : MonoBehaviour
{
[Header("移動設定")]
[SerializeField] private float moveSpeed = 2f; // 移動速度
[SerializeField] private float arrivalThreshold = 0.01f; // 到着とみなす距離
[SerializeField] private float waitTime = 5f; // 待機時間
[SerializeField] private float moveDistance = 5f; // Y座標移動距離

[Header("連携設定")]
[SerializeField] public ElevatorSwitch[] elevators; // スイッチと連携する場合用

private bool isMoving = false; // 移動中フラグ
private bool isAtTop = false; // 上にいるかどうか
private Vector3 startPosition; // 初期位置
private Vector3 topPosition; // 上の位置

void Start()
{
startPosition = transform.position; // 初期位置を記録
topPosition = startPosition + Vector3.up * moveDistance; // 上の位置を計算
isMoving = false; // 最初は停止状態
isAtTop = false; // 下にいる状態からスタート
}

void Update()
{
if (isMoving)
{
Vector3 destination = isAtTop ? startPosition : topPosition;

// 目的地に向かって移動
transform.position = Vector3.MoveTowards(
transform.position,
destination,
moveSpeed * Time.deltaTime
);

// 到着判定(距離が十分に近ければ到着とみなす)
if (Vector3.Distance(transform.position, destination) < arrivalThreshold)
{
transform.position = destination; // ぴったり位置を合わせる
isMoving = false;

if (!isAtTop)
{
isAtTop = true;
StartCoroutine(WaitAndMoveDown()); // 上に着いたら待ってから戻る
}
else
{
isAtTop = false;
EnableSwitches(); // 下に着いたらスイッチを再有効化
}
}
}
}

private IEnumerator WaitAndMoveDown()
{
yield return new WaitForSeconds(waitTime); // 一時停止
isMoving = true; // 下への移動を再開
}

private void EnableSwitches()
{
// スイッチを再びクリック可能にする
foreach (var elevatorSwitch in elevators)
{
elevatorSwitch.EnableClick();
}
}

// 外部から呼び出すことでエレベーターを上昇させる
public void MoveUp()
{
if (!isMoving && !isAtTop)
{
isMoving = true;
}
}
}

次は、GameObjectを設定するのではなく、MoveDistanceのところで動き幅を設定するようにした!

カメラを回転できるようにする

Playerのスクリプトを書き換える!

using UnityEngine;

public class Player : MonoBehaviour
{
[Header("移動設定")]
[SerializeField] private float moveSpeed; // 移動速度
[SerializeField] private float jumpForce; // ジャンプ力
[SerializeField] private float deadZone = 0.1f; // コントローラーのデッドゾーン

[Header("カメラ設定")]
[SerializeField] private float mouseSensitivity = 2f; // マウス感度
[SerializeField] private float controllerSensitivity = 100f; // コントローラー感度
[SerializeField] private float maxLookUpAngle = 80f; // 上を向く最大角度
[SerializeField] private float maxLookDownAngle = -80f; // 下を向く最大角度
[SerializeField] private Camera playerCamera; // プレイヤーカメラの参照
[SerializeField] private float cameraHeight = -0.5f; // カメラの高さオフセット

private Rigidbody rb; // プレイヤーのRigidbody
private bool isGrounded; // 地面に接しているかどうか
private float verticalRotation = 0f; // カメラの縦回転

void Start()
{
rb = GetComponent<Rigidbody>();

// カメラが設定されていない場合、子オブジェクトから探す
if (playerCamera == null)
{
playerCamera = GetComponentInChildren<Camera>();
}

// カメラの位置を調整(視点を下げる)
if (playerCamera != null)
{
Vector3 cameraPos = playerCamera.transform.localPosition;
cameraPos.y = cameraHeight;
playerCamera.transform.localPosition = cameraPos;
}

// カーソルをロック(任意)
Cursor.lockState = CursorLockMode.Locked;
}

void Update()
{
Move();
Jump();
CameraLook();
}

void Move()
{
Vector3 moveDirection = Vector3.zero;

// キーボード入力
if (Input.GetKey(KeyCode.UpArrow) || Input.GetKey(KeyCode.W))
{
moveDirection += transform.forward;
}
if (Input.GetKey(KeyCode.DownArrow) || Input.GetKey(KeyCode.S))
{
moveDirection -= transform.forward;
}
if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.A))
{
moveDirection -= transform.right;
}
if (Input.GetKey(KeyCode.RightArrow) || Input.GetKey(KeyCode.D))
{
moveDirection += transform.right;
}

// コントローラー入力(左スティック)
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");

// デッドゾーン処理
if (Mathf.Abs(horizontal) > deadZone)
{
moveDirection += transform.right * horizontal;
}
if (Mathf.Abs(vertical) > deadZone)
{
moveDirection += transform.forward * vertical;
}

Vector3 move = moveDirection.normalized * moveSpeed;
Vector3 velocity = rb.linearVelocity;
rb.linearVelocity = new Vector3(move.x, velocity.y, move.z);
}

void Jump()
{
// キーボード(スペースキー)またはコントローラー(×ボタン)でジャンプ
if ((Input.GetKeyDown(KeyCode.Space) || Input.GetKeyDown(KeyCode.Joystick1Button1)) && isGrounded)
{
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
isGrounded = false;
}
}

void CameraLook()
{
// マウス入力
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;

// コントローラー入力(右スティック)
float rightStickX = 0f;
float rightStickY = 0f;

// 複数の軸名を試行(お好みの軸名を追加/変更可能)
string[] rightStickXNames = { "Right Stick X", "Joy1 Axis 4", "RightStickX", "Mouse X" };
string[] rightStickYNames = { "Right Stick Y", "Joy1 Axis 5", "RightStickY", "Mouse Y" };

foreach (string axisName in rightStickXNames)
{
try
{
rightStickX = Input.GetAxis(axisName);
break;
}
catch (System.ArgumentException) { }
}

foreach (string axisName in rightStickYNames)
{
try
{
rightStickY = Input.GetAxis(axisName);
break;
}
catch (System.ArgumentException) { }
}

// デッドゾーン処理とコントローラー入力の適用
if (Mathf.Abs(rightStickX) > deadZone)
{
// 右スティック横軸 → 水平回転(左右)
mouseX += rightStickX * controllerSensitivity * Time.deltaTime;
}
if (Mathf.Abs(rightStickY) > deadZone)
{
// 右スティック縦軸 → 垂直回転(上下)
mouseY += rightStickY * controllerSensitivity * Time.deltaTime; // 反転を削除
}

// 水平回転(プレイヤー全体を回転)
transform.Rotate(Vector3.up * mouseX);

// 垂直回転(カメラのみ回転)
verticalRotation -= mouseY;
verticalRotation = Mathf.Clamp(verticalRotation, maxLookDownAngle, maxLookUpAngle);

if (playerCamera != null)
{
playerCamera.transform.localRotation = Quaternion.Euler(verticalRotation, 0f, 0f);
}
}

void OnCollisionEnter(Collision collision)
{
// 地面に着いたらジャンプ可能にする
if (collision.gameObject.CompareTag("Ground") || collision.gameObject.CompareTag("Block"))
{
isGrounded = true;
}
}

public void Ground()
{
isGrounded = true;
}
}