2, PersistentObjectsプレハブにSavingGameObjectを作成する
3, SavingにSavingSystemスクリプトをコンポーネントする
5, SavingにSavingWrapperをコンポーネントする
6, SavingWrapper.csに下記スクリプトを記述する
SavingWrapper
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Saving;
namespace RPG.SceneManagement
{
public class SavingWrapper : MonoBehaviour
{
const string defaultSaveFile = "Save";
void Update()
{
if (Input.GetKeyDown(KeyCode.L))
{
Load();
}
if (Input.GetKeyDown(KeyCode.S))
{
Save();
}
}
private void Save()
{
GetComponent<SavingSystem>().Save(defaultSaveFile);
}
private void Load()
{
GetComponent<SavingSystem>().Load(defaultSaveFile);
}
}
}
7, PlayerにSaveableEntityスクリプトをつける
8, Moverスクリプトに下記コードを追加する
Mover
using System.Collections;
using System.Collections.Generic;
using RPG.Core;
using UnityEngine;
using UnityEngine.AI;
using RPG.Saving; //追加
namespace RPG.Movement
{
public class Mover : MonoBehaviour, IAction, ISaveable //ISaveableを追加
{
[SerializeField] Transform target;
[SerializeField] float maxSpeed = 6f;
NavMeshAgent navMeshAgent;
Health health;
private void Start()
{
navMeshAgent = GetComponent<NavMeshAgent>();
health = GetComponent<Health>();
}
void Update()
{
navMeshAgent.enabled = !health.IsDead();
UpdateAnimator();
}
public void StartMoveAction(Vector3 destination, float speedFraction)
{
GetComponent<ActionScheduler>().StartAction(this);
MoveTo(destination, speedFraction);
}
public void MoveTo(Vector3 destination, float speedFraction)
{
navMeshAgent.destination = destination;
navMeshAgent.speed = maxSpeed * Mathf.Clamp01(speedFraction);
navMeshAgent.isStopped = false;
}
public void Cancel()
{
navMeshAgent.isStopped = true;
}
private void UpdateAnimator()
{
Vector3 velocity = navMeshAgent.velocity;
Vector3 localVelocity = transform.InverseTransformDirection(velocity);
float speed = localVelocity.z;
GetComponent<Animator>().SetFloat("fowardSpeed", speed);
}
//追加
public object CaptureState()
{
return new SerializableVector3(transform.position);
}
//追加
public void RestoreState(object state)
{
SerializableVector3 position = (SerializableVector3)state;
GetComponent<NavMeshAgent>().enabled = false;
transform.position = position.ToVector();
GetComponent<NavMeshAgent>().enabled = true;
}
}
}
体力ポイントのセーブ
1, 各スクリプトに下記コードを追加
Health
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Saving; //追加
namespace RPG.Core
{
public class Health : MonoBehaviour, ISaveable //追加
{
[SerializeField] float healthPoints = 100f;
bool isDead = false;
public bool IsDead()
{
return isDead;
}
public void TakeDamage(float damage)
{
healthPoints = Mathf.Max(healthPoints - damage, 0);
if (healthPoints == 0)
{
Die();
}
}
private void Die()
{
if (isDead) return;
isDead = true;
GetComponent<Animator>().SetTrigger("die");
GetComponent<ActionScheduler>().CancelCurrentAction();
}
// 追加
public object CaptureState()
{
return healthPoints;
}
// 追加
public void RestoreState(object state)
{
healthPoints = (float)state;
if (healthPoints == 0)
{
Die();
}
}
}
}
SavingWrapper
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Saving;
namespace RPG.SceneManagement
{
public class SavingWrapper : MonoBehaviour
{
const string defaultSaveFile = "save";
void Update()
{
if (Input.GetKeyDown(KeyCode.L))
{
Load();
}
if (Input.GetKeyDown(KeyCode.S))
{
Save();
}
}
public void Save() //publicに変更
{
GetComponent<SavingSystem>().Save(defaultSaveFile);
}
public void Load() //publicに変更
{
GetComponent<SavingSystem>().Load(defaultSaveFile);
}
}
}
Portal
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
namespace RPG.SceneManagement
{
public class Portal : MonoBehaviour
{
enum DestinationIdentifier
{
A, B, C, D, E
}
[SerializeField] int sceneToLoad = -1;
[SerializeField] Transform spawnPoint;
[SerializeField] DestinationIdentifier destination;
[SerializeField] float fadeOutTime = 1f;
[SerializeField] float fadeInTime = 2f;
[SerializeField] float fadeWaitTime = 0.5f;
//private void Start()
//{
// transform.parent = null;
// DontDestroyOnLoad(gameObject);
//}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
StartCoroutine(Transition());
}
}
private IEnumerator Transition()
{
if (sceneToLoad < 0)
{
Debug.LogError("Scene to load not set.");
yield break;
}
transform.parent = null;
DontDestroyOnLoad(gameObject);
Fader fader = FindObjectOfType<Fader>();
yield return fader.FadeOut(fadeOutTime);
SavingWrapper wrapper = FindObjectOfType<SavingWrapper>(); //追加
wrapper.Save(); //追加
yield return SceneManager.LoadSceneAsync(sceneToLoad);
wrapper.Load(); //追加
Portal otherPortal = GetOtherPortal();
UpdatePlayer(otherPortal);
yield return new WaitForSeconds(fadeWaitTime);
yield return fader.FadeIn(fadeInTime);
Destroy(gameObject);
}
private void UpdatePlayer(Portal otherPortal)
{
GameObject player = GameObject.FindWithTag("Player");
player.GetComponent<NavMeshAgent>().enabled = false; //追加
player.GetComponent<NavMeshAgent>().Warp(otherPortal.spawnPoint.position);
player.transform.rotation = otherPortal.spawnPoint.rotation;
player.GetComponent<NavMeshAgent>().enabled = true; //追加
}
private Portal GetOtherPortal()
{
foreach (Portal portal in FindObjectsOfType<Portal>())
{
if (portal == this) continue;
if (portal.destination != destination) continue;
return portal;
}
return null;
}
}
}
2, PlayerプレハブのUniqueIdentifierをplayerにする
3, PlayerのUniqueIdentifierをRevertして設定する。他のSceneのplayerも同じく設定する。
最後のセーブ地点からスタートさせる
1, 各スクリプトに下記のコードを追加
SavingWrapper
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using RPG.Saving;
namespace RPG.SceneManagement
{
public class SavingWrapper : MonoBehaviour
{
const string defaultSaveFile = "save";
[SerializeField] float fadeInTime = 0.2f;
//追加
IEnumerator Start()
{
Fader fader = FindObjectOfType<Fader>();
fader.FadeOutImmediate();
yield return GetComponent<SavingSystem>().LoadLastScene(defaultSaveFile);
yield return fader.FadeIn(fadeInTime);
}
void Update()
{
if (Input.GetKeyDown(KeyCode.L))
{
Load();
}
if (Input.GetKeyDown(KeyCode.S))
{
Save();
}
}
public void Save()
{
GetComponent<SavingSystem>().Save(defaultSaveFile);
}
public void Load()
{
GetComponent<SavingSystem>().Load(defaultSaveFile);
}
}
}
Portal
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.SceneManagement;
namespace RPG.SceneManagement
{
public class Portal : MonoBehaviour
{
enum DestinationIdentifier
{
A, B, C, D, E
}
[SerializeField] int sceneToLoad = -1;
[SerializeField] Transform spawnPoint;
[SerializeField] DestinationIdentifier destination;
[SerializeField] float fadeOutTime = 1f;
[SerializeField] float fadeInTime = 2f;
[SerializeField] float fadeWaitTime = 0.5f;
//private void Start()
//{
// transform.parent = null;
// DontDestroyOnLoad(gameObject);
//}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
StartCoroutine(Transition());
}
}
private IEnumerator Transition()
{
if (sceneToLoad < 0)
{
Debug.LogError("Scene to load not set.");
yield break;
}
transform.parent = null;
DontDestroyOnLoad(gameObject);
Fader fader = FindObjectOfType<Fader>();
yield return fader.FadeOut(fadeOutTime);
SavingWrapper wrapper = FindObjectOfType<SavingWrapper>();
wrapper.Save();
yield return SceneManager.LoadSceneAsync(sceneToLoad);
wrapper.Load();
Portal otherPortal = GetOtherPortal();
UpdatePlayer(otherPortal);
wrapper.Save(); //追加
yield return new WaitForSeconds(fadeWaitTime);
yield return fader.FadeIn(fadeInTime);
Destroy(gameObject);
}
private void UpdatePlayer(Portal otherPortal)
{
GameObject player = GameObject.FindWithTag("Player");
player.GetComponent<NavMeshAgent>().enabled = false;
player.GetComponent<NavMeshAgent>().Warp(otherPortal.spawnPoint.position);
player.transform.rotation = otherPortal.spawnPoint.rotation;
player.GetComponent<NavMeshAgent>().enabled = true;
}
private Portal GetOtherPortal()
{
foreach (Portal portal in FindObjectsOfType<Portal>())
{
if (portal == this) continue;
if (portal.destination != destination) continue;
return portal;
}
return null;
}
}
}
Fader
using System.Collections;
using UnityEngine;
namespace RPG.SceneManagement
{
public class Fader : MonoBehaviour
{
CanvasGroup canvasGroup;
private void Start()
{
canvasGroup = GetComponent<CanvasGroup>();
}
//追加
public void FadeOutImmediate()
{
canvasGroup.alpha = 1;
}
public IEnumerator FadeOut(float time)
{
while (canvasGroup.alpha < 1)
{
canvasGroup.alpha += Time.deltaTime / time;
yield return null;
}
}
public IEnumerator FadeIn(float time)
{
while (canvasGroup.alpha > 0)
{
canvasGroup.alpha -= Time.deltaTime / time;
yield return null;
}
}
}
}