View difference between Paste ID: 4B3LHdCi and KA26DFXu
SHOW: | | - or go back to the newest paste.
1
#if HAVE_SLATE
2
3
using System;
4
using System.Collections.Generic;
5
6
using UnityEngine;
7
8
using Slate;
9
10
using Framework.Camera;
11
using Framework.Support;
12
13
namespace Framework.Cinematics {
14
15
  /// <summary>Helper methods for dealing with cutscenes</summary>
16
  public static class CutsceneHelper {
17
18
    #region class CameraParenter
19
20
    /// <summary>Temporarily changes the parent of a game object</summary>
21
    private class CameraParenter : IDisposable {
22
23
      /// <summary>Initializes a new instance that does nothing</summary>
24
      public CameraParenter() {
25
        this.onCutsceneStoppedDelegate = new Action<Cutscene>(onCutsceneStopped);
26
      }
27
28
      /// <summary>
29
      ///   Assigns a new parent to the camera and remembers the previous one
30
      /// </summary>
31
      /// <param name="newParentGameObject">New parent for the camera</param>
32
      /// <param name="cameraGameObject">Camera that will be reparented</param>
33
      public CameraParenter(
34
        GameObject newParentGameObject, GameObject cameraGameObject
35
      ) : this() {
36
        Initialize(newParentGameObject, cameraGameObject);
37
      }
38
39
      /// <summary>
40
      ///   Assigns a new parent to the camera and remembers the previous one
41
      /// </summary>
42
      /// <param name="newParentGameObject">New parent for the camera</param>
43
      /// <param name="cameraGameObject">Camera that will be reparented</param>
44
      public void Initialize(
45
        GameObject newParentGameObject, GameObject cameraGameObject
46
      ) {
47
        this.cameraGameObject = cameraGameObject;
48
49
        Transform cameraTransform = cameraGameObject.transform;
50
        this.previousPosition = cameraTransform.localPosition;
51
        this.previousOrientation = cameraTransform.localRotation;
52
53
        Transform parentTransform = cameraTransform.parent;
54
        if(parentTransform == null) {
55
          this.previousParentGameObject = null;
56
        } else {
57
          this.previousParentGameObject = parentTransform.gameObject;
58
        }
59
60
        GameObjectHelper.SetAsChild(newParentGameObject, cameraGameObject);
61
        cameraTransform.localPosition = Vector3.zero;
62
        cameraTransform.localRotation = Quaternion.identity;
63
      }
64
65
      /// <summary>Restores the original parent of the camera</summary>
66
      public void Dispose() {
67
        WatchCutsceneForRecycling(null);
68
69
        if(this.cameraGameObject != null) {
70
          GameObjectHelper.SetAsChild(this.previousParentGameObject, this.cameraGameObject);
71
72
          Transform cameraTransform = this.cameraGameObject.transform;
73
          cameraTransform.localPosition = this.previousPosition;
74
          cameraTransform.localRotation = this.previousOrientation;
75
76
          this.cameraGameObject = null;
77
        }
78
      }
79
80
      /// <summary>Sets the parenter up for recycling after a cutscene finishes</summary>
81
      /// <param name="cutscene">Cutscene that will be watched for completion</param>
82
      public void WatchCutsceneForRecycling(Cutscene cutscene) {
83
        if(this.cutsceneForUnsubscribe != null) {
84
          Cutscene.OnCutsceneStopped -= this.onCutsceneStoppedDelegate;
85
          this.cutsceneForUnsubscribe = null;
86
        }
87
        if(cutscene != null) {
88
          Cutscene.OnCutsceneStopped += this.onCutsceneStoppedDelegate;
89
          this.cutsceneForUnsubscribe = cutscene;
90
        }
91
      }
92
93
      /// <summary>Recycles the parenter when the cutscene stops playing</summary>
94
      /// <param name="cutscene">Cutscene that has stopped playing</param>
95
      private void onCutsceneStopped(Cutscene cutscene) {
96
        if(ReferenceEquals(this.cutsceneForUnsubscribe, cutscene)) {
97
          Dispose();
98
99
          CutsceneHelper.recyclableCameraParenters.Add(this);
100
        }
101
      }
102
103
      /// <summary>Game object that will be reparented</summary>
104
      private GameObject cameraGameObject;
105
      /// <summary>Game object that was the camera's previous parent</summary>
106
      private GameObject previousParentGameObject;
107
      /// <summary>Previous position of the camera</summary>
108
      private Vector3 previousPosition;
109
      /// <summary>Previous orientation of the camera</summary>
110
      private Quaternion previousOrientation;
111
112
      /// <summary>Cutscene this camera parenter is watching for completion</summary>
113
      private Cutscene cutsceneForUnsubscribe;
114
      /// <summary>Delegate for the onCutsceneStopped() method</summary>
115
      private Action<Cutscene> onCutsceneStoppedDelegate;
116
117
    }
118
119
    #endregion // class CameraParenter
120
121
    /// <summary>Starts playing a cutscene using the specified camera</summary>
122
    /// <param name="cutscene">Cutscene that will be played</param>
123
    /// <param name="camera">Camera on which the cutscene will be played</param>
124
    /// <param name="callback">Callback to invoke when the cutscene ends</param>
125
    public static void PlayCutsceneOnCamera(
126
      Cutscene cutscene, UnityEngine.Camera camera, System.Action callback = null
127
    ) {
128
129
      // Stop the DirectorCamera from messing with our camera settings
130
      DirectorCamera.setMainWhenActive = false;
131
      DirectorCamera.matchMainCamera = False;
132
      DirectorCamera.autoHandleActiveState = false;
133
      DirectorCamera.dontDestroyOnLoad = false;
134
135
      // Start the cutscene. This will disable the active camera, but we'll undo
136
      // that little mishap right away
137
      cutscene.Play(0.0f, callback);
138
139
      // Switch to our own render camera
140
      CameraHelper.ActivateCamera(camera);
141
142
      // Parent our render camera to the director camera root
143
      CameraParenter parenter = recycleOrCreateCameraParenter();
144
      parenter.Initialize(DirectorCamera.current.gameObject, camera.gameObject);
145
146
      // Set up the parenter to recycle (and unparent) when the cutscene ends,
147
      // then play the cutscene (in this order in case of a zero-length cutscene)
148
      parenter.WatchCutsceneForRecycling(cutscene);
149
150
    }
151
152
    /// <summary>Starts playing a cutscene using the director camera</summary>
153
    /// <param name="cutscene">Cutscene that will be played</param>
154
    /// <param name="camera">Camera that will be active when the cutscene starts</param>
155
    /// <param name="callback">Callback to invoke when the cutscene ends</param>
156
    public static void PlayCutsceneOnDirectorCamera(
157
      Cutscene cutscene, UnityEngine.Camera camera, System.Action callback = null
158
    ) {
159
160
      // In this case, we want the director camera to take over all camera settings
161
      DirectorCamera.setMainWhenActive = true;
162
      DirectorCamera.matchMainCamera = true;
163
      DirectorCamera.autoHandleActiveState = true;
164
      DirectorCamera.dontDestroyOnLoad = false;
165
166
      // Switch to our own render camera
167
      CameraHelper.ActivateCamera(camera);
168
169
      // Start the cutscene
170
      cutscene.Play(0.0f, callback);
171
172
    }
173
174
    /// <summary>
175
    ///   Returns a recycled instance of a camera parenter or creates a new one
176
    /// </summary>
177
    /// <returns>An unused instance of a camera parenter</returns>
178
    private static CameraParenter recycleOrCreateCameraParenter() {
179
      if(recyclableCameraParenters == null) {
180
        recyclableCameraParenters = new List<CameraParenter>();
181
        return new CameraParenter();
182
      }
183
184
      int parenterCount = recyclableCameraParenters.Count;
185
      if(parenterCount == 0) {
186
        return new CameraParenter();
187
      }
188
189
      CameraParenter parenter = recyclableCameraParenters[parenterCount - 1];
190
      recyclableCameraParenters.RemoveAt(parenterCount - 1);
191
      return parenter;
192
    }
193
194
    /// <summary>Camera parenters that are ready for reuse</summary>
195
    private static IList<CameraParenter> recyclableCameraParenters;
196
197
  }
198
199
} // namespace Framework.Cinematics
200
201
#endif // HAVE_SLATE