おかしなところなどあればTwitterで教えて欲しいです。(ブログにコメントを書いてもらえると嬉しいですがハードルが高いのといつでも反応できるわけではないので)
Teitter:@ritz_prgrm
Raycastを使ったもので作った。
Raycastを使わなくてもいいとは思う。
使ったのはPlayer(Cube),PlayerCamera(camera),Anker,AnkerLine
コードが必要なのはPlayerとPlayerCameraのみ。AnkerとAnkerLineはPrefabでなんでもいいが今回はCubeを使った。AnkerLineにいろをつけたかったらMaterialつける。インデントがゴミ。
PlayerCameraはPlayerの子オブジェクト
Cubeでしかまだ使っていないので注意。
アタッチしてAnkerPrefab,AnkerLinePrefabにはオブジェクトをいれる。
Player(RigidBody付でAngular drag,Dragは0。ConstraintsでFreezeRotation yにチェック)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public float inputHorizontal;
public float inputVertical;
public Rigidbody rigidBody;
//インスペクタでAnkerPrefabとAnkerLinePrefabになにかオブジェクトをいれる。自分の場合はCube
public GameObject Anker,AnkerPrefab;
public GameObject AnkerLine, AnkerLinePrefab;
public Camera PlayerCamera;
public bool IsUsingAnker;
public bool IsUsingInput;
public bool IsMovingByAnker;
//歩くはやさ
float moveSpeed = 3f;
//0.7秒くらいでアンカーの移動を終わらせたい
float AnkerMoveSpeed = 50f;
float AnkerDistance = 35f;
private void Awake()
{
if(rigidBody == null)
{
rigidBody = GetComponent<Rigidbody>();
}
if(PlayerCamera == null)
{
PlayerCamera = GetComponentInChildren<Camera>();
}
}
void Start()
{
IsUsingAnker = false;
Anker = Instantiate(AnkerPrefab);
Anker.SetActive(false);
AnkerLine = Instantiate(AnkerLinePrefab);
AnkerLine.SetActive(false);
}
void Update()
{
inputHorizontal = Input.GetAxisRaw("Horizontal");
inputVertical = Input.GetAxisRaw("Vertical");
if(inputVertical == 0 && inputHorizontal == 0)
{
IsUsingInput = false;
}
else
{
IsUsingInput = true;
}
if(Input.GetMouseButtonDown(0))
{
float distance = 100;
float duration = 10;
Ray ray = new Ray(transform.position,PlayerCamera.transform.forward.normalized);
//インスペクタでRayを確認したい場合はしたのやつのコメントアウトをやめる
//Debug.DrawRay(ray.origin, ray.direction * distance, Color.red, duration, false);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, distance))
{
if (IsUsingAnker == false)
{
//始点がray.originじゃないとずれる
StartCoroutine(AnkerCoroutine(ray.origin,hit.point));
}
}
else
{
if (IsUsingAnker == false)
{
//始点がray.originじゃないとずれる
// ray.origin足さないとずれる
StartCoroutine(AnkerCoroutine(ray.origin,ray.direction * distance + ray.origin));
}
}
}
}
void FixedUpdate()
{
// カメラの方向から、XZ平面の単位ベクトルをもとめる
Vector3 cameraForward = Vector3.Scale(PlayerCamera.transform.forward, new Vector3(1, 0, 1)).normalized;
Vector3 cameraSide = Vector3.Scale(PlayerCamera.transform.right, new Vector3(1, 0, 1)).normalized;
// Inputとカメラの向きから移動方向と大きさをきめる
Vector3 moveForward = cameraForward * inputVertical;
Vector3 moveSide = cameraSide * inputHorizontal;
// 移動方向にスピードを掛ける。落ちるときにふわふわしないために分岐している
if(!IsMovingByAnker)
{
rigidBody.velocity = rigidBody.velocity = (moveForward + moveSide) * moveSpeed + new Vector3(0, rigidBody.velocity.y, 0);
}
else
{
rigidBody.velocity = rigidBody.velocity = (moveForward + moveSide) * moveSpeed;
}
// キャラクターの向きを進行方向に
if (moveForward != Vector3.zero && inputVertical > 0)
{
transform.rotation = Quaternion.LookRotation(moveForward);
}
else if(moveForward != Vector3.zero && inputVertical < 0)
{
transform.rotation = Quaternion.LookRotation(-moveForward);
}
if(moveSide != Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(cameraForward);
}
if(moveForward == Vector3.zero && moveSide == Vector3.zero)
{
transform.rotation = Quaternion.LookRotation(cameraForward);
}
}
private IEnumerator AnkerCoroutine(Vector3 firstPos,Vector3 target)
{
Anker.transform.position = firstPos;
Anker.SetActive(true);
AnkerLine.SetActive(true);
float distance = 0f;
while (distance < AnkerDistance && Anker.transform.position != target)
{
IsUsingAnker = true;
float speed = Time.deltaTime * AnkerMoveSpeed; Anker.transform.position = Vector3.MoveTowards(Anker.transform.position,target,speed);
AnkerLine.transform.localScale = new Vector3(0.1f, 0.1f, distance);
AnkerLine.transform.LookAt(target);
//アンカーとプレイヤーの中点を座標にのびていく
AnkerLine.transform.position = (Anker.transform.position + transform.position) * 0.5f;
distance += speed;
ield return null;
}
Anker.SetActive(false);
AnkerLine.SetActive(false);
StartCoroutine(AnkerMoveCoroutine());
IsUsingAnker = false;
}
private IEnumerator AnkerMoveCoroutine()
{
//重力等の関係でtransform.position != Anker.transform.positionにするとめっちゃぶれる
while ((transform.position - Anker.transform.position).magnitude >= 0.5f && !IsUsingInput)
{
IsMovingByAnker = true;
var heading = Anker.transform.position - transform.position;
var distance = heading.magnitude;
var direction = heading / distance;
if(Anker.transform.position.y <= transform.position.y)
{
direction = Vector3.Scale(direction, new Vector3(1, 0, 1));
}
float speed = Time.deltaTime * (AnkerMoveSpeed * 2f / moveSpeed);
transform.position += direction * speed;
yield return null;
}
IsMovingByAnker = false;
}
}PlayerCameraクラス
Playerの子オブジェクトにCameraと一緒につける。
AnkerLinePrefabを見たいのでカメラのtransformはyを2ぐらいにする。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCamera : MonoBehaviour
{
public Transform VerticalRotation;
public Transform HorizontalRotation;
public float XRotation;
public float YRotation;
// Start is called before the first frame update
private void Awake()
{
if(VerticalRotation == null)
{
VerticalRotation = transform.parent;
}
if(HorizontalRotation == null)
{
HorizontalRotation = GetComponent<Transform>();
}
}
void Start()
{
}
// Update is called once per frame
void Update()
{
XRotation = Input.GetAxis("Mouse X");
YRotation = Input.GetAxis("Mouse Y");
//ここをマイナスにするとマウスの上下と逆にカメラワークが動く
VerticalRotation.transform.Rotate(0, XRotation, 0);
//ここをプラスにするとマウスの左右と逆にカメラワークが動く
HorizontalRotation.transform.Rotate(-YRotation, 0, 0);
}
}
インデントがゴミ