using System.Collections.Generic; using UnityEngine; // Sci-Fi Ship Controller. Copyright (c) 2018-2023 SCSM Pty Ltd. All rights reserved. namespace SciFiShipController { /// /// This sample shows how you can: /// 1. Run radar queries for a player ship to find nearby enemy /// 2. Use DisplayTargets on a HUD to track enemy on the screen /// 3. Assign targets to weapons that use Guided Projectiles /// 4. Get notified when an enemy is hit /// This is only sample to demonstrate how API calls could be used in /// your own code. You should write your own version of this in your own /// namespace. /// SETUP: /// 1. Add Prefabs\Visuals\HUD1 prefab to the scene /// 2. Add player ship from Prefabs\Ships to the scene (ones that don't have NPC in the name) /// 3. Remove or disable the default Main Camera /// 4. Add Prefabs\Environment\PlayerCamera prefab to the scene /// 5. Hook up the player ship to the PlayerCamera /// 6. Add this script to the player ship /// 7. Hook up the HUD to the slot on this script /// 8. Make sure you player ship has at least one weapon with a guided Projectile /// 9. Ensure the weapon has Auto Targeting enabled. /// NOTE: Most of the time you can simply add the AutoTargetingModule /// to your player ship. /// [AddComponentMenu("Sci-Fi Ship Controller/Samples/HUD Targets")] [HelpURL("http://scsmmedia.com/ssc-documentation")] public class SampleHUDTargets : MonoBehaviour { #region Public Variables and Properties public ShipDisplayModule shipDisplayModule; #endregion #region Private Variables private ShipControlModule playerShip = null; private bool isInitialised = false; private SSCRadar sscRadar = null; private SSCRadarQuery radarQuery = null; private List sscRadarBlipsList = null; private int numDisplayTargets = 0; #endregion #region Initialisation Methods // Start is called before the first frame update void Start() { #region Initialise Player Ship playerShip = GetComponent(); if (playerShip != null) { // If Initialise On Awake is not ticking on the ship, initialise the ship now. if (!playerShip.IsInitialised) { playerShip.InitialiseShip(); } } #if UNITY_EDITOR else { Debug.LogWarning("[ERROR] SampleHUDTargets.Start() could not find the ship! Did you attach this script to you Player ship (ShipControlModule)?"); } #endif #endregion #region Initialise HUD if (shipDisplayModule != null) { // If Initialise on Start is not ticked on the HUD, do it now. if (!shipDisplayModule.IsInitialised) { shipDisplayModule.Initialise(); } if (shipDisplayModule.IsInitialised) { // Typically you can let the HUD update DisplayTarget positions on the screen // automatically. However, in this sample we want to do things ourselves. shipDisplayModule.autoUpdateTargetPositions = false; numDisplayTargets = shipDisplayModule.GetNumberDisplayTargets; // If no Display Targets are pre-configured, let's add some // Typically, you will configure them in the HUD before runtime. if (numDisplayTargets < 1) { int numAvailableReticles = shipDisplayModule.GetNumberDisplayReticles; int numAdded = 0; // Use the last 3 available reticles as Display Target reticles for (int rIdx = numAvailableReticles - 1; rIdx >= 0; rIdx--) { int guidHash = shipDisplayModule.GetDisplayReticleGuidHash(rIdx); shipDisplayModule.AddTarget(guidHash); if (++numAdded == 3) { break; } } numDisplayTargets = shipDisplayModule.GetNumberDisplayTargets; } } } #if UNITY_EDITOR else { Debug.LogWarning("[ERROR] SampleHUDTargets.Start() the ShipDisplayModule is not set. Add the Prefabs/Visuals/HUD1 prefab to the scene, then drag it on to this script which should be attached to your player ship."); } #endif #endregion #region Create some "enemy" and added them to radar sscRadar = SSCRadar.GetOrCreateRadar(); if (sscRadar != null && playerShip != null && playerShip.IsInitialised) { // Create a position 100m in front of the ship Vector3 locationWS = playerShip.shipInstance.TransformPosition + (playerShip.shipInstance.TransformForward * 100f); // Create some "enemy" for (int eIdx = 0; eIdx < 4; eIdx++) { GameObject enemyGO = GameObject.CreatePrimitive(PrimitiveType.Sphere); if (enemyGO != null) { enemyGO.name = "Enemy " + (eIdx + 1).ToString(); enemyGO.transform.position = locationWS + (playerShip.shipInstance.TransformRight * 25 * (eIdx+1)); enemyGO.transform.localScale = Vector3.one * 3f; enemyGO.GetComponent().material.color = new Color(1f, 1f / (eIdx + 2), 1f / (eIdx + 2)); // Let's get notified when our "enemy" is hit DamageReceiver damageReceiver = enemyGO.AddComponent(); damageReceiver.callbackOnHit = TakeDamage; // Tell the radar system about this enemy gameobject sscRadar.EnableRadar(enemyGO, enemyGO.transform.position, playerShip.shipInstance.factionId + 1, -1, 0, 5); } } // Create a radar query with some default settings radarQuery = new SSCRadarQuery() { range = 1000, querySortOrder = SSCRadarQuery.QuerySortOrder.DistanceAsc3D, factionsToExclude = new int[] { playerShip.shipInstance.factionId } }; // Create an empty list to store the radar results sscRadarBlipsList = new List(10); isInitialised = shipDisplayModule != null && sscRadarBlipsList != null && radarQuery != null; } #endregion } #endregion #region Update Methods // Update is called once per frame void Update() { if (isInitialised) { // Test code to allow you to move it around in the scene view at runtime //GameObject enGO = GameObject.Find("Enemy 1"); //if (enGO != null) //{ // sscRadar.SetItemPosition(sscRadar.GetRadarItemIndexByHash(enGO.GetHashCode()), enGO.transform.position); //} sscRadar.GetRadarResults(radarQuery, sscRadarBlipsList); int numEnemy = sscRadarBlipsList.Count; Vector2 screenResolution = shipDisplayModule.ScreenResolution; int nextBlipIndex = 0; int nextWeaponIndex = 0; for (int dtIdx = 0; dtIdx < numDisplayTargets; dtIdx++) { DisplayTarget displayTarget = shipDisplayModule.GetDisplayTargetByIndex(dtIdx); // Are there any more enemies that could be in view? if (dtIdx < numEnemy && nextBlipIndex >= 0) { // Find the next enemy in view nextBlipIndex = sscRadar.GetNextBlipInView(sscRadarBlipsList, nextBlipIndex, shipDisplayModule.mainCamera, screenResolution); // Is the enemy in view? if (nextBlipIndex >= 0) { SSCRadarBlip blip = sscRadarBlipsList[nextBlipIndex]; // Move the DisplayTarget slot to the correct position on the screen // For this sample we're just using 1 DisplayTarget slot (or 1 copy of each DT in the DT list in the HUD) // We are ignoring the Max Number of Targets setting for each DisplayTarget. shipDisplayModule.SetDisplayTargetPosition(displayTarget, 0, blip.wsPosition); // Find a weapon to assign to the target if (nextWeaponIndex >= 0) { nextWeaponIndex = playerShip.shipInstance.GetNextAutoTargetingWeaponIndex(nextWeaponIndex); // Found an available weapon with a guided projectile if (nextWeaponIndex >= 0) { // This just one possible way you could do things. You could also investigate using other methods like // shipDisplayModule.AssignDisplayTargetSlot(..) like is used in the AutoTargetingModule. if (sscRadar.IsShipBlip(blip)) { playerShip.shipInstance.SetWeaponTargetShip(nextWeaponIndex, blip.shipControlModule); } else if (sscRadar.IsGameObjectBlip(blip)) { playerShip.shipInstance.SetWeaponTarget(nextWeaponIndex, blip.itemGameObject); } else if (nextBlipIndex >= numEnemy - 1) { // No more Ship or GameObject enemy so unassign remaining auto targeting weapons UnassignWeapons(ref nextWeaponIndex); // Go to the next DisplayTarget which will be turned off continue; } else { // find another enemy target nextBlipIndex++; continue; } // Advance to the next weapon nextWeaponIndex++; } } // If the DisplayTarget is not already visible, show it if (!displayTarget.showTarget) { shipDisplayModule.ShowDisplayTarget(displayTarget); } // Advance to the next enemy target nextBlipIndex++; } else { // If there are no more enemy, the remaining weapons (if any) should not have targets. UnassignWeapons(ref nextWeaponIndex); // If the DisplayTarget is visible, turn it off if (displayTarget.showTarget) { shipDisplayModule.HideDisplayTarget(displayTarget); } } } else { // If there are no more enemy, the remaining weapons (if any) should not have targets. UnassignWeapons(ref nextWeaponIndex); // If the DisplayTarget is visible, turn it off if (displayTarget.showTarget) { shipDisplayModule.HideDisplayTarget(displayTarget); } } } } } #endregion #region Private Methods /// /// Unassign any remaining Auto Targeting weapons that could not be allocated a target. /// /// private void UnassignWeapons(ref int nextWeaponIndex) { int numWeapons = playerShip.NumberOfWeapons; while (nextWeaponIndex >= 0 && nextWeaponIndex < numWeapons) { playerShip.shipInstance.ClearWeaponTarget(nextWeaponIndex); nextWeaponIndex++; nextWeaponIndex = playerShip.shipInstance.GetNextAutoTargetingWeaponIndex(nextWeaponIndex); } } #endregion #region Public Member Methods /// /// This routine is called by Sci-Fi Ship Controller when a projectile or beam hits our enemy /// /// public void TakeDamage(CallbackOnObjectHitParameters callbackOnObjectHitParameters) { // Rather than taking damage, immediately our "enemy" is hit, we will destroy it. if (callbackOnObjectHitParameters.hitInfo.transform != null) { // Get the radar item by using the hashcode of the GameObject // Then tell the radar system to stop tracking this item. sscRadar.RemoveItem(sscRadar.GetRadarItemIndexByHash(callbackOnObjectHitParameters.hitInfo.transform.gameObject.GetHashCode())); // Now we can destroy the actual gameobject Destroy(callbackOnObjectHitParameters.hitInfo.transform.gameObject); } } #endregion } }