using System.Collections; using System.Collections.Generic; using UnityEngine; // Sci-Fi Ship Controller. Copyright (c) 2018-2023 SCSM Pty Ltd. All rights reserved. namespace SciFiShipController { /// /// Demo script that uses your pre-configured Docking Station for an AI Ship to undock, /// fly along a path, then dock with another Docking Station. /// This is designed to work with TechDemo4scene2 but a similar script could be adapted /// to work with your scenario. /// 1. Add this component to a gameobject in the scene /// 2. Add two Docking Stations to your scene /// 3. Configure a Ship Docking Point on each Ship Docking Station /// 4. Drag each of the Ship Docking Stations from the scene into the slots provided on this component /// 5. Add a NPC ship with ShipDocking and ShipAIInputModules attached /// 6. On one of the Docking Stations, drag the NPC ship into the Ship Docking Station Point (Assign Ship) /// 7. In the scene, ensure there is a SSCManager. /// 8. Create a path between station 1 and station 2 (leave a gap between the start/end of the path and the stations) /// 9. Click (I)nsert button on path to create a duplicate of the first path and rename it /// 10. Reverse the direction of the new path using the reverse (<->) button /// 11. Add the names of the paths to this component in the inspector /// 12. On the ShipDocking component (on the NPC ship), set the Initial Docking State to Docked. /// 13. On the ShipDocking component (on the NPC ship), optionally set the Auto Undock Time. /// WARNING: This is a DEMO script and is subject to change without notice during /// upgrades. This is just to show you how to do things in your own code and namespace. /// [HelpURL("http://scsmmedia.com/ssc-documentation")] public class DemoDockingTransit : MonoBehaviour { #region Public Variables public bool initialiseOnStart = false; public ShipDockingStation shipDockingStation1 = null; public ShipDockingStation shipDockingStation2 = null; public string departTransitPathName = "Depart Transit Path"; public string returnTransitPathName = "Return Transit Path"; public ShipAIInputModule.AIObstacleAvoidanceQuality obsAvoidWhenDocking = ShipAIInputModule.AIObstacleAvoidanceQuality.Off; public ShipAIInputModule.AIObstacleAvoidanceQuality obsAvoidWhenNoDocking = ShipAIInputModule.AIObstacleAvoidanceQuality.Medium; #endregion #region Public Properties public bool IsInitialised { get { return isInitialised; } } #endregion #region Public Static Variables #endregion #region Private Variables - General private bool isInitialised = false; private SSCManager sscManager = null; private PathData departTransitPath = null; private PathData returnTransitPath = null; private List aiShips = null; #endregion #region Public Delegates #endregion #region Private Initialise Methods void Start() { if (initialiseOnStart) { Initialise(); } } #endregion #region Update Methods #endregion // Create additional regions for specific Private method groups #region Private and Internal Methods - General private void ConfigureAssignedShips (ShipDockingStation shipDockingStation) { int numDockingPoints = shipDockingStation.NumberOfDockingPoints; for (int dpIdx = 0; dpIdx < numDockingPoints; dpIdx++) { ShipControlModule shipControlModule = shipDockingStation.GetAssignedShip(dpIdx); if (shipControlModule != null) { // Tell the AI ship to take action when it has finished following a path ShipAIInputModule shipAIInputModule = shipControlModule.GetShipAIInputModule(true); if (shipAIInputModule != null && shipAIInputModule.IsInitialised) { shipAIInputModule.callbackCompletedStateAction = CompletedStateActionCallback; // Remember this ship aiShips.Add(shipAIInputModule); } // The ship should already know about it's docking point component, as it was discovered // when the ship was assigned to the docking point in ShipDockingStation.Initialise(). ShipDocking shipDocking = shipControlModule.GetShipDocking(false); // Get notified when a ship changes it's docking state (Docking, Docked, Undocking, Undocked) if (shipDocking != null) { shipDocking.callbackOnStateChange = OnDockingStateChanged; } } } } #endregion #region Events #endregion #region Call back notifications /// /// Take action when a ship finished it's current action /// /// public void CompletedStateActionCallback (ShipAIInputModule shipAIInputModule) { if (shipAIInputModule != null) { // Ww are only interested in knowing when the ship is not docking, undocking or docked. // i.e. Has just finished undocking OR has reached the end of the depart or return path. ShipControlModule shipControlModule = shipAIInputModule.GetShipControlModule; if (shipControlModule.ShipIsNotDocked()) { PathData pathToFollow = shipAIInputModule.GetTargetPath(); // Was the ship following the depart path? if (pathToFollow != null && pathToFollow.Equals(departTransitPath)) { shipDockingStation2.AssignShipToDockingPoint(shipControlModule, shipControlModule.GetShipDocking(false)); shipDockingStation2.DockShip(shipControlModule); } // Was the ship following the return path? else if (pathToFollow != null && pathToFollow.Equals(returnTransitPath)) { shipDockingStation1.AssignShipToDockingPoint(shipControlModule, shipControlModule.GetShipDocking(false)); shipDockingStation1.DockShip(shipControlModule); } else { // Which station was it assigned to? if (shipDockingStation1.IsShipAssigned(shipControlModule.GetShipId)) { pathToFollow = departTransitPath; shipDockingStation1.UnassignShip(shipControlModule.GetShipId); } else { // Assume assigned to second station pathToFollow = returnTransitPath; shipDockingStation2.UnassignShip(shipControlModule.GetShipId); } // Tell the ship to follow the appropriate path shipAIInputModule.AssignTargetPath(pathToFollow); shipAIInputModule.SetState(AIState.moveToStateID); } } } } /// /// Gets called automatically when a ship's docking state changes. /// (Docking, Docked, Undocking, Undocked) /// /// /// /// /// public void OnDockingStateChanged (ShipDocking shipDocking, ShipControlModule shipControlModule, ShipAIInputModule shipAIInputModule, ShipDocking.DockingState previousDockingState) { int dockingStateInt = shipDocking.GetStateInt(); // Set the obstacle avoidance quality based on the docking state. if (shipAIInputModule != null) { if (dockingStateInt == ShipDocking.notDockedInt) { shipAIInputModule.obstacleAvoidanceQuality = obsAvoidWhenNoDocking; } else { shipAIInputModule.obstacleAvoidanceQuality = obsAvoidWhenDocking; } } } #endregion #region Public API Methods - General /// /// If the ship is waiting (docked) at a station, attempt to get it /// to travel to the other station. /// /// public void DepartStation (ShipControlModule shipControlModule) { // Is ship docked? if (isInitialised && shipControlModule != null && shipControlModule.ShipIsDocked()) { // Now determine if it is docked with one of our stations int dockingPointIdx = shipDockingStation1.GetDockingPointIndex(shipControlModule.GetShipId); if (dockingPointIdx != ShipDockingStation.NoDockingPoint) { // Ship is assigned to Station 1. DepartStation1(dockingPointIdx+1); } else { // Ship is not docked with Station 1, so check station 2. dockingPointIdx = shipDockingStation2.GetDockingPointIndex(shipControlModule.GetShipId); // Is ship assigned to Station 2? if (dockingPointIdx != ShipDockingStation.NoDockingPoint) { // Ship is assigned to Station 2. DepartStation2(dockingPointIdx+1); } } } } /// /// Attempt to get the ship (if any) to undock and begin travelling to Station 2. /// Assume the ship is an AI or AI-assisted ship. /// /// public void DepartStation1 (int dockingPointNumber) { if (isInitialised) { shipDockingStation1.UnDockShip(dockingPointNumber - 1); } } /// /// Attempt to get the ship (if any) to undock and begin travelling to Station 1. /// Assume the ship is an AI or AI-assisted ship. /// /// public void DepartStation2 (int dockingPointNumber) { if (isInitialised) { shipDockingStation2.UnDockShip(dockingPointNumber - 1); } } /// /// Initialise this demo component. /// public void Initialise() { if (isInitialised) { return; } sscManager = SSCManager.GetOrCreateManager(); departTransitPath = sscManager.GetPath(departTransitPathName); returnTransitPath = sscManager.GetPath(returnTransitPathName); aiShips = new List(5); if (shipDockingStation1 == null) { #if UNITY_EDITOR Debug.LogWarning("DemoDockingTransit - could not find ShipDockingStation1 - did you add it as a reference from the scene in the slot provided?"); #endif } else if (shipDockingStation2 == null) { #if UNITY_EDITOR Debug.LogWarning("DemoDockingTransit - could not find ShipDockingStation2 - did you add it as a reference from the scene in the slot provided?"); #endif } else if (!shipDockingStation1.IsInitialised) { #if UNITY_EDITOR Debug.LogWarning("ERROR: DemoDockingTransit " + shipDockingStation1.name + " should have Initialise On Awake enabled for this demo"); #endif } else if (!shipDockingStation2.IsInitialised) { #if UNITY_EDITOR Debug.LogWarning("ERROR: DemoDockingTransit " + shipDockingStation2.name + " should have Initialise On Awake enabled for this demo"); #endif } else if (departTransitPath == null) { #if UNITY_EDITOR Debug.LogWarning("DemoDockingTransit - could not find departTransitPath (" + departTransitPathName + ")" ); #endif } else if (returnTransitPath == null) { #if UNITY_EDITOR Debug.LogWarning("DemoDockingTransit - could not find returnTransitPath (" + returnTransitPathName + ")" ); #endif } else { ConfigureAssignedShips(shipDockingStation1); ConfigureAssignedShips(shipDockingStation2); isInitialised = true; } } #endregion } }