おかしなところなどあれば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); } }
インデントがゴミ