/// <summary> /// Function to select a target for the tank. /// It requires at least 2 buildings from a neighbourhood to be eligible. /// </summary> /// <returns></returns> private IVisualizedObject SelectTarget() { List <NeighbourhoodModel> randomNeighbourhoodQuery = CityManager.Instance.GameModel.Neighbourhoods .Where(neighbourhoodModel => neighbourhoodModel.VisualizedObjects.Count(visualizedObject => visualizedObject is VisualizedBuildingModel) >= _minimumBuildings).ToList(); if (TeamManager.Instance.SelectedTeam != null) { randomNeighbourhoodQuery = randomNeighbourhoodQuery.Where(x => x.Team == TeamManager.Instance.SelectedTeam).ToList(); } // No target found. Tank is probably going in standby mode now. if (randomNeighbourhoodQuery.Count == 0) { _foundTargets = false; return(null); } // Pick a random neighbourhood from the list NeighbourhoodModel randomNeighbourhoodModel = randomNeighbourhoodQuery.PickRandom(); // We found a target and it's a building. Return the target. IVisualizedObject obj = randomNeighbourhoodModel.VisualizedObjects .First(visualizedObject => visualizedObject.GameObject != null && visualizedObject is VisualizedBuildingModel); _foundTargets = true; return(obj); }
/// <summary> /// Function to add a new visualized object to the game. /// </summary> /// <param name="neighbourhoodName"></param> /// <param name="newVisualizedObject"></param> private void AddBuilding(string neighbourhoodName, IVisualizedObject newVisualizedObject) { // We only care about buildings in this manager if (!(newVisualizedObject is IVisualizedBuilding)) { return; } NeighbourhoodModel neighbourhood = GameModel.Neighbourhoods.SingleOrDefault(x => x.Name == neighbourhoodName); if (neighbourhood == null) { Debug.LogWarning($"Adding object went wrong! Neighbourhood {neighbourhoodName} does not exists!"); return; } // Check if there are buildings with the same identifier. List <IVisualizedBuilding> existingVisualizedObjects = neighbourhood.VisualizedObjects .OfType <IVisualizedBuilding>().Where(x => x.Identifier == newVisualizedObject.Identifier) .ToList(); // Destroy every building that has the same identifier. foreach (IVisualizedBuilding visualizedObject in existingVisualizedObjects) { GridManager.Instance.DestroyBuilding(visualizedObject); neighbourhood.VisualizedObjects.Remove(visualizedObject); } // TODO: We actually need to check if there are destroyed grass tiles, but haven't found a solution for it yet. neighbourhood.VisualizedObjects.Add(newVisualizedObject); GridManager.Instance.DestroyBlock(neighbourhood, false); GridManager.Instance.SpawnNeighbourhood(neighbourhood); }
/// <summary> /// Function to highlight a neighbourhood when clicked. /// </summary> /// <param name="clickedObject"></param> /// <param name="showInfoPanel"></param> public void HighlightNeighbourhood(GameObject clickedObject, bool showInfoPanel = true) { if (showInfoPanel) { string neighbourhoodName = clickedObject.name.Replace("neighbourhood-", ""); string infoText = $"Neighbourhood: {neighbourhoodName}"; try { if (clickedObject.CompareTag("Building")) { NeighbourhoodModel neighboorhoud = CityManager.Instance.GameModel.Neighbourhoods.SingleOrDefault( (x => x.Name == neighbourhoodName)); if (neighboorhoud != null) { IVisualizedObject visualizedObject = neighboorhoud.VisualizedObjects.SingleOrDefault(x => x.GameObject == clickedObject); _selectedObject = visualizedObject; string days = neighboorhoud.Age == 1 ? "day" : "days"; infoText = $"Neighbourhood: {neighbourhoodName}\r\nAge: {neighboorhoud.Age} {days}"; VisualLayerModel selectedLayer = LayerManager.Instance.SelectedLayer; if (visualizedObject is IVisualizedBuilding visualizedBuilding) { DestroyButton.SetActive(true); OpenButton.SetActive(true); if (selectedLayer != null) { // Only enable destroy button for buildings infoText = $"Neighbourhood: {neighbourhoodName}\r\n{selectedLayer.Name.Replace("Layer", "")}: {visualizedBuilding.LayerValues[selectedLayer.Name]} / {neighboorhoud.LayerValues.Single(x => x.LayerType == selectedLayer.Name).MaxValue} "; } } } } } catch (Exception e) { Debug.LogError($"[OnObjectClickManager] {e.Message}"); } finally { InfoPanel.GetComponentInChildren <TMP_Text>().text = infoText; InfoPanel.gameObject.SetActive(true); } } Renderer[] renderComponents = clickedObject.GetComponentsInChildren <Renderer>(); foreach (Renderer renderComponent in renderComponents) { _clickedObjects.Add(renderComponent, renderComponent.material.color); renderComponent.material.color = Color.green; } }
/// <summary> /// Function to set the target of the tank /// </summary> /// <param name="target">The GameObject of the target should not be null</param> public void SetTarget(IVisualizedObject target) { IsStandby = false; Target = target; _agent.enabled = true; if (_agent.isActiveAndEnabled && target.GameObject != null) { _agent.isStopped = false; _agent.SetDestination(target.GameObject.transform.position); HasTarget = true; ChaosManager.Instance.TankTargetChanged.Invoke(target.GameObject.name.Replace("neighbourhood-", "")); } }
/// <summary> /// Function to search for a neighbourhood. /// </summary> /// <param name="serviceName"></param> public void SearchNeighbourhood(string serviceName) { NeighbourhoodModel search = CityManager.Instance.GameModel.Neighbourhoods .FirstOrDefault(x => x.Name.Contains(serviceName)); IVisualizedObject randomContainer = search?.VisualizedObjects.FirstOrDefault(x => x.GameObject != null); if (randomContainer == null || randomContainer.GameObject == null) { return; } CameraController.Instance.FocusOnTarget(randomContainer.GameObject.transform.position); OnObjectClickManager.Instance.ResetHighlighting(); OnObjectClickManager.Instance.HighlightNeighbourhood(randomContainer.GameObject); }
// Update is called once per frame void Update() { // Check if left mouse button is pressed and if there has not been clicked on an UI element if (!Input.GetMouseButtonDown(0) || UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject()) { return; } // Check if we have a hit on a prefab with the active camera bool hit = Physics.Raycast(CameraManager.Instance.ActiveCamera.ScreenPointToRay(Input.mousePosition), out RaycastHit hitInfo, _maxDistance, _defaultLayer); // We reset the highlighting ResetHighlighting(); _selectedObject = null; if (hit) { DestroyButton.SetActive(false); OpenButton.SetActive(false); GameObject targetObject = hitInfo.transform.gameObject; // Check if the object we hit has a parent, since buildings, vehicle etc don't have parents but they do have children if (hitInfo.transform.parent != null) { targetObject = hitInfo.transform.parent.gameObject; } if ((targetObject.CompareTag("Building") || targetObject.CompareTag("DestroyedBuilding")) && targetObject.name.StartsWith("neighbourhood-")) { HighlightNeighbourhood(targetObject); } else if (targetObject.CompareTag("Tank") || targetObject.CompareTag("Vehicle")) { HighlightVehicle(targetObject); } else { InfoPanel.gameObject.SetActive(false); } } else { InfoPanel.gameObject.SetActive(false); } }
/// <summary> /// Function that is executed when a button is pressed. /// The player will focus with the camera on the first building of a neighbourhood /// </summary> /// <param name="neighbourhoodModel"></param> private static void OnButtonClick(NeighbourhoodModel neighbourhoodModel) { IVisualizedObject visualizedBuilding = neighbourhoodModel.VisualizedObjects.FirstOrDefault(x => x is IVisualizedBuilding && x.GameObject != null); if (visualizedBuilding == null) { return; } CameraController.Instance.FocusOnTarget(visualizedBuilding.GameObject.transform.position); OnObjectClickManager.Instance.ResetHighlighting(); OnObjectClickManager.Instance.HighlightNeighbourhood(visualizedBuilding.GameObject); }
/// <summary> /// Check if the tank still has a target. Otherwise pick a new target. /// It won't check for a new target is the tank is in stand-by. /// </summary> void LateUpdate() { // We need to pick a new target for the tank here if (_tankNavigator != null && _tankNavigator.Target == null && !_tankNavigator.IsStandby) { IVisualizedObject target = SelectTarget(); if (target == null || !_foundTargets) { _tankNavigator.SetStandby(true); } else { _tankNavigator.SetTarget(target); } } }
/// <summary> /// Function to kill a object through the API. /// </summary> /// <returns></returns> public IEnumerator KillVisualizedObject(IVisualizedObject building, bool force = false) { using (UnityWebRequest webRequest = UnityWebRequest.Delete($"{_gameEndpoint}?identifier={building.Identifier}&force={force}")) { // Request and wait for the desired page. webRequest.timeout = 10; yield return(webRequest.SendWebRequest()); if (webRequest.isNetworkError || webRequest.isHttpError) { Debug.LogError($"Webrequest failed! Error: {webRequest.error}"); } yield return(null); } yield return(null); }
private static NeighbourhoodModel ParseNeighbourhoodModel(JSONNode jsonNode) { NeighbourhoodModel neighbourhood = new NeighbourhoodModel(); neighbourhood.Name = jsonNode["name"]; neighbourhood.Age = jsonNode["daysOld"]; neighbourhood.Team = jsonNode["team"]; List <LayerValueModel> visualLayers = jsonNode["layerValues"].Children.Select(visualLayer => new LayerValueModel { MinValue = visualLayer["minValue"], LayerType = visualLayer["layerType"], MaxValue = visualLayer["maxValue"] }).ToList(); neighbourhood.LayerValues = visualLayers; // Loop through all visualized objects (buildings, traffic for later, etc) foreach (JSONNode visualizedObjectJson in jsonNode["visualizedObjects"].Children) { Dictionary <string, double> layerValues = new Dictionary <string, double>(); foreach (KeyValuePair <string, JSONNode> layerValue in visualizedObjectJson["layerValues"]) { layerValues.Add(layerValue.Key, layerValue.Value); } IVisualizedObject visualizedObject = VisualizedObjectFactory.Build( visualizedObjectJson["type"], visualizedObjectJson["size"], layerValues, visualizedObjectJson["identifier"]); neighbourhood.VisualizedObjects.Add(visualizedObject); } return(neighbourhood); }
/// <summary> /// Function to process vehicle queue. Every vehicle has a navigator <see cref="VehicleNavigator"/>. /// The path has already been set in the <see cref="SpawnVehicle(VisualizedVehicleModel)"/> function /// We call the <see cref="VehicleNavigator.StartPathFinding"/> function. /// This function will enable all the renderers, making the object visible and the vehicle starts to navigate /// As soon as a vehicle reached their destination it will drive back to the start position of the vehicle /// </summary> /// <returns></returns> private IEnumerator ProcessQueue() { while (true) { while (_vehicleQueue.Count > 0) { // Grab the vehicle from the queue Vehicle v = _vehicleQueue.Dequeue(); // Check if in the main time the neighbourhood is not de-spawned together with the vehicle if (v.VehicleGameObject != null && v.NeighbourhoodModel != null) { // Start the path finding of the vehicle v.VehicleGameObject.GetComponent <VehicleNavigator>().StartPathFinding(); // Fire the event that we spawned a vehicle VehicleSpawned?.Invoke(v); // Check if the vehicle is already in the list of the neighbourhood IVisualizedObject vehicle = v.NeighbourhoodModel.VisualizedObjects.SingleOrDefault(x => x is VisualizedVehicleModel && x.Identifier == v.VehicleModel.Identifier); // If vehicle is not in the list of visualized objects of a neighbourhood, add it if (vehicle == null) { v.VehicleModel.GameObject = v.VehicleGameObject; v.NeighbourhoodModel.VisualizedObjects.Add(v.VehicleModel); } else { vehicle.GameObject = v.VehicleGameObject; } } yield return(new WaitForSeconds(0.3f)); } yield return(new WaitForSeconds(0.1f)); } }