330 lines
13 KiB
C#
330 lines
13 KiB
C#
|
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
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 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.
|
|||
|
/// </summary>
|
|||
|
[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<ShipAIInputModule> 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
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Take action when a ship finished it's current action
|
|||
|
/// </summary>
|
|||
|
/// <param name="shipAIInputModule"></param>
|
|||
|
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);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Gets called automatically when a ship's docking state changes.
|
|||
|
/// (Docking, Docked, Undocking, Undocked)
|
|||
|
/// </summary>
|
|||
|
/// <param name="shipDocking"></param>
|
|||
|
/// <param name="shipControlModule"></param>
|
|||
|
/// <param name="shipAIInputModule"></param>
|
|||
|
/// <param name="previousDockingState"></param>
|
|||
|
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
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// If the ship is waiting (docked) at a station, attempt to get it
|
|||
|
/// to travel to the other station.
|
|||
|
/// </summary>
|
|||
|
/// <param name="dockingPointNumber"></param>
|
|||
|
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);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 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.
|
|||
|
/// </summary>
|
|||
|
/// <param name="dockingPointNumber"></param>
|
|||
|
public void DepartStation1 (int dockingPointNumber)
|
|||
|
{
|
|||
|
if (isInitialised)
|
|||
|
{
|
|||
|
shipDockingStation1.UnDockShip(dockingPointNumber - 1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 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.
|
|||
|
/// </summary>
|
|||
|
/// <param name="dockingPointNumber"></param>
|
|||
|
public void DepartStation2 (int dockingPointNumber)
|
|||
|
{
|
|||
|
if (isInitialised)
|
|||
|
{
|
|||
|
shipDockingStation2.UnDockShip(dockingPointNumber - 1);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Initialise this demo component.
|
|||
|
/// </summary>
|
|||
|
public void Initialise()
|
|||
|
{
|
|||
|
if (isInitialised) { return; }
|
|||
|
|
|||
|
sscManager = SSCManager.GetOrCreateManager();
|
|||
|
|
|||
|
departTransitPath = sscManager.GetPath(departTransitPathName);
|
|||
|
returnTransitPath = sscManager.GetPath(returnTransitPathName);
|
|||
|
|
|||
|
aiShips = new List<ShipAIInputModule>(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
|
|||
|
|
|||
|
}
|
|||
|
}
|