So I have my control script, which changes color of the sprites. When I click onto the sprite it falls and stops changing color. On collision it checks whether the color is the same, then it teleports the sprite back up. So now my question is: How can I make it change the color again?
My color changer:
public class control : MonoBehaviour
{
public static bool m_isRunning = false;
public static bool loop = true;
public SpriteRenderer m_spriteRenderer;
private Rigidbody2D rb;
public static int random;
public static float loopdelay = 0f;
public static float intervalplayer = 1f; //interval
public static bool changecolorborder = true;
public static bool fall = false;
public static int gravity = 0;
public static bool transform1 = false;
private void Update()
{
random = Random.Range(1, 4);
if (fall)
{
rb.gravityScale = gravity;
}
if (transform1)
{
transform.position = transform.position + new Vector3(0.002f, 1.998f, 0);
}
if(Input.touchCount == 1)
{
Debug.Log("Helloo");
}
}
private void Start()
{
m_spriteRenderer = this.GetComponent<SpriteRenderer>();
rb = GetComponent<Rigidbody2D>();
StartCoroutine(Changecolor(0f));
}
private IEnumerator Changecolor(float loopdelay)
{
while (loop)
{
yield return new WaitForSeconds(intervalplayer);
if (loop)
{
if (random == 1)
{
Color newColor = new Color(0.68f, 0.63f, 0.76f);
m_spriteRenderer.color = newColor;
}
else if (random == 2)
{
Color newColor = new Color(0.89f, 0.25f, 0.23f);
m_spriteRenderer.color = newColor;
}
else if (random == 3)
{
Color newColor = new Color(0.68f, 0.88f, 0.33f);
m_spriteRenderer.color = newColor;
}
else
{
Color newColor = new Color(0.38f, 0.21f, 0.72f);
m_spriteRenderer.color = newColor;
}
}
}
}
private void OnMouseDown()
{
fall = true;
loop = !loop;
gravity = 1;
changecolorborder = !changecolorborder;
}
}
My collision checker:
public class collision : MonoBehaviour
{
public static int counter = 0;
public static float waitime = 1f;
public Rigidbody2D rb;
public void OnCollisionEnter2D(Collision2D collision)
{
Text textMy = GameObject.Find("Canvas/Text").GetComponent<Text>();
if (collision.gameObject.GetComponent<SpriteRenderer>().color != gameObject.GetComponent<SpriteRenderer>().color)
{
Destroy(collision.gameObject);
}
else
{
counter++;
textMy.text = counter.ToString();
control.gravity = 0;
StartCoroutine(waitfor());
}
}
IEnumerator waitfor()
{
yield return new WaitForSeconds(1);
control.transform1 = true;
yield return new WaitForSeconds(0.033f);
control.transform1 = false;
}
}
I guess reseting your values like in the beggining
fall = false;
loop = true;
gravity = 0;
changecolorborder = !changecolorborder;
And calling the coroutine again
StartCoroutine(Changecolor(0f));
Related
Very new to Unity, I'm making a tactical RPG game similar to Fire Emblem. I've followed a tutorial on movement from this website and followed everything he did.
The player character can only move 5 tiles in the directions +z, -z, +x, -x on a 12x12 tile grid, however I want it to move 6. In the TacticsMove.cs script, there is this variable: public int move = 5; with the amount of the variable being how many tiles the player moves. I've changed the variable to public int move = 6; and saved the script, but everything is the exact same as before.
I want public int move = 6 to allow the player to move up to 6 tiles instead of 5. There are no comments on the tutorial or youtube videos of this happening so the next place im coming to is here. My code is below, I don't know if all of this is relevant. If you need me to add/remove something, tell me.
TacticsMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TacticsMove : MonoBehaviour
{
public bool turn = false;
List<Tile> selectableTiles = new List<Tile>();
GameObject[] tiles;
Stack<Tile> path = new Stack<Tile>();
Tile currentTile;
public bool moving = false;
public int move = 6;
public float jumpHeight = 2;
public float moveSpeed = 2;
public float jumpVelocity = 4.5f;
Vector3 velocity = new Vector3();
Vector3 heading = new Vector3();
float halfHeight = 0;
bool fallingDown = false;
bool jumpingUp = false;
bool movingEdge = false;
Vector3 jumpTarget;
public Tile actualTargetTile;
protected void Init()
{
tiles = GameObject.FindGameObjectsWithTag("Tile");
halfHeight = GetComponent<Collider>().bounds.extents.y;
TurnManager.AddUnit(this);
}
public void GetCurrentTile()
{
currentTile = GetTargetTile(gameObject);
currentTile.current = true;
}
public Tile GetTargetTile(GameObject target)
{
RaycastHit hit;
Tile tile = null;
if (Physics.Raycast(target.transform.position, -Vector3.up, out hit, 1))
{
tile = hit.collider.GetComponent<Tile>();
}
return tile;
}
public void ComputeAdjacencyLists(float jumpHeight, Tile target)
{
//tiles = GameObject.FindGameObjectsWithTag("Tile");
foreach (GameObject tile in tiles)
{
Tile t = tile.GetComponent<Tile>();
t.FindNeighbors(jumpHeight, target);
}
}
public void FindSelectableTiles()
{
ComputeAdjacencyLists(jumpHeight, null);
GetCurrentTile();
Queue<Tile> process = new Queue<Tile>();
process.Enqueue(currentTile);
currentTile.visited = true;
//currentTile.parent = ?? leave as null
while (process.Count > 0)
{
Tile t = process.Dequeue();
selectableTiles.Add(t);
t.selectable = true;
if (t.distance < move)
{
foreach (Tile tile in t.adjacencyList)
{
if (!tile.visited)
{
tile.parent = t;
tile.visited = true;
tile.distance = 1 + t.distance;
process.Enqueue(tile);
}
}
}
}
}
public void MoveToTile(Tile tile)
{
path.Clear();
tile.target = true;
moving = true;
Tile next = tile;
while (next != null)
{
path.Push(next);
next = next.parent;
}
}
public void Move()
{
if (path.Count > 0)
{
Tile t = path.Peek();
Vector3 target = t.transform.position;
//Calculate the unit's position on top of the target tile
target.y += halfHeight + t.GetComponent<Collider>().bounds.extents.y;
if (Vector3.Distance(transform.position, target) >= 0.05f)
{
bool jump = transform.position.y != target.y;
if (jump)
{
Jump(target);
}
else
{
CalculateHeading(target);
SetHorizotalVelocity();
}
//Locomotion
transform.forward = heading;
transform.position += velocity * Time.deltaTime;
}
else
{
//Tile center reached
transform.position = target;
path.Pop();
}
}
else
{
RemoveSelectableTiles();
moving = false;
TurnManager.EndTurn();
}
}
protected void RemoveSelectableTiles()
{
if (currentTile != null)
{
currentTile.current = false;
currentTile = null;
}
foreach (Tile tile in selectableTiles)
{
tile.Reset();
}
selectableTiles.Clear();
}
void CalculateHeading(Vector3 target)
{
heading = target - transform.position;
heading.Normalize();
}
void SetHorizotalVelocity()
{
velocity = heading * moveSpeed;
}
void Jump(Vector3 target)
{
if (fallingDown)
{
FallDownward(target);
}
else if (jumpingUp)
{
JumpUpward(target);
}
else if (movingEdge)
{
MoveToEdge();
}
else
{
PrepareJump(target);
}
}
void PrepareJump(Vector3 target)
{
float targetY = target.y;
target.y = transform.position.y;
CalculateHeading(target);
if (transform.position.y > targetY)
{
fallingDown = false;
jumpingUp = false;
movingEdge = true;
jumpTarget = transform.position + (target - transform.position) / 2.0f;
}
else
{
fallingDown = false;
jumpingUp = true;
movingEdge = false;
velocity = heading * moveSpeed / 3.0f;
float difference = targetY - transform.position.y;
velocity.y = jumpVelocity * (0.5f + difference / 2.0f);
}
}
void FallDownward(Vector3 target)
{
velocity += Physics.gravity * Time.deltaTime;
if (transform.position.y <= target.y)
{
fallingDown = false;
jumpingUp = false;
movingEdge = false;
Vector3 p = transform.position;
p.y = target.y;
transform.position = p;
velocity = new Vector3();
}
}
void JumpUpward(Vector3 target)
{
velocity += Physics.gravity * Time.deltaTime;
if (transform.position.y > target.y)
{
jumpingUp = false;
fallingDown = true;
}
}
void MoveToEdge()
{
if (Vector3.Distance(transform.position, jumpTarget) >= 0.05f)
{
SetHorizotalVelocity();
}
else
{
movingEdge = false;
fallingDown = true;
velocity /= 5.0f;
velocity.y = 1.5f;
}
}
protected Tile FindLowestF(List<Tile> list)
{
Tile lowest = list[0];
foreach (Tile t in list)
{
if (t.f < lowest.f)
{
lowest = t;
}
}
list.Remove(lowest);
return lowest;
}
protected Tile FindEndTile(Tile t)
{
Stack<Tile> tempPath = new Stack<Tile>();
Tile next = t.parent;
while (next != null)
{
tempPath.Push(next);
next = next.parent;
}
if (tempPath.Count <= move)
{
return t.parent;
}
Tile endTile = null;
for (int i = 0; i <= move; i++)
{
endTile = tempPath.Pop();
}
return endTile;
}
protected void FindPath(Tile target)
{
ComputeAdjacencyLists(jumpHeight, target);
GetCurrentTile();
List<Tile> openList = new List<Tile>();
List<Tile> closedList = new List<Tile>();
openList.Add(currentTile);
//currentTile.parent = ??
currentTile.h = Vector3.Distance(currentTile.transform.position, target.transform.position);
currentTile.f = currentTile.h;
while (openList.Count > 0)
{
Tile t = FindLowestF(openList);
closedList.Add(t);
if (t == target)
{
actualTargetTile = FindEndTile(t);
MoveToTile(actualTargetTile);
return;
}
foreach (Tile tile in t.adjacencyList)
{
if (closedList.Contains(tile))
{
//Do nothing, already processed
}
else if (openList.Contains(tile))
{
float tempG = t.g + Vector3.Distance(tile.transform.position, t.transform.position);
if (tempG < tile.g)
{
tile.parent = t;
tile.g = tempG;
tile.f = tile.g + tile.h;
}
}
else
{
tile.parent = t;
tile.g = t.g + Vector3.Distance(tile.transform.position, t.transform.position);
tile.h = Vector3.Distance(tile.transform.position, target.transform.position);
tile.f = tile.g + tile.h;
openList.Add(tile);
}
}
}
//todo - what do you do if there is no path to the target tile?
Debug.Log("Path not found");
}
public void BeginTurn()
{
turn = true;
}
public void EndTurn()
{
turn = false;
}
}
Tile.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile : MonoBehaviour
{
public bool walkable = true;
public bool current = false;
public bool target = false;
public bool selectable = false;
public List<Tile> adjacencyList = new List<Tile>();
//Needed BFS (breadth first search)
public bool visited = false;
public Tile parent = null;
public int distance = 0;
//For A*
public float f = 0;
public float g = 0;
public float h = 0;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (current)
{
GetComponent<Renderer>().material.color = Color.magenta;
}
else if (target)
{
GetComponent<Renderer>().material.color = Color.green;
}
else if (selectable)
{
GetComponent<Renderer>().material.color = Color.blue;
}
else
{
GetComponent<Renderer>().material.color = Color.white;
}
}
public void Reset()
{
adjacencyList.Clear();
current = false;
target = false;
selectable = false;
visited = false;
parent = null;
distance = 0;
f = g = h = 0;
}
public void FindNeighbors(float jumpHeight, Tile target)
{
Reset();
CheckTile(Vector3.forward, jumpHeight, target);
CheckTile(-Vector3.forward, jumpHeight, target);
CheckTile(Vector3.right, jumpHeight, target);
CheckTile(-Vector3.right, jumpHeight, target);
}
public void CheckTile(Vector3 direction, float jumpHeight, Tile target)
{
Vector3 halfExtents = new Vector3(0.25f, (1 + jumpHeight) / 2.0f, 0.25f);
Collider[] colliders = Physics.OverlapBox(transform.position + direction, halfExtents);
foreach (Collider item in colliders)
{
Tile tile = item.GetComponent<Tile>();
if (tile != null && tile.walkable)
{
RaycastHit hit;
if (!Physics.Raycast(tile.transform.position, Vector3.up, out hit, 1) || (tile == target))
{
adjacencyList.Add(tile);
}
}
}
}
}
PlayerMove.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : TacticsMove
{
// Use this for initialization
void Start ()
{
Init();
}
// Update is called once per frame
void Update ()
{
Debug.DrawRay(transform.position, transform.forward);
if (!turn)
{
return;
}
if (!moving)
{
FindSelectableTiles();
CheckMouse();
}
else
{
Move();
}
}
void CheckMouse()
{
if (Input.GetMouseButtonUp(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (hit.collider.tag == "Tile")
{
Tile t = hit.collider.GetComponent<Tile>();
if (t.selectable)
{
MoveToTile(t);
}
}
}
}
}
}
Im using unity version 2019.3.12f1.
Any help is appreciated.
As Etienne de Martel hints, Unity saves your public variables in the scene along with all the other GameObject/Component data, and restores that data on load
Field initializers are the default values for new components, they do not set the values for existing components even with a recompile.
I've been through this a few times myself.
From what I know, variables that have been serialized (which means it is visible in the inspector using [serialize] or it is set to public) will always overwrite scripts. This means that the moment u save ur script after u have create a variable and before u start the program, it can only be adjusted using the inspector
I am having a problem with my RTS game where my enemy units will not attack any base buildings I create after the level starts. They go to attack every other building that was there when the level starts, but none of the built ones.
There is a list being set up of the closest targets to units and they will go to attack their closest target, but any newly instantiated buildings or units, don't get attacked for some reason.
The function DecideWhatToDo() is called on all units in the WorldObject script when they are not doing anything. It then calls FindNearbyObjects() from the WorkManager script.
Everything works up until new units and buildings are created, has anyone experienced this kind of problem before?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using RTS;
public class WorldObject : MonoBehaviour {
BoxCollider boxCollider;
bool isDead;
bool isSinking;
public string objectName;
public Texture2D buildImage;
public int cost, sellValue, maxHitPoints;
public float hitPoints;
public virtual bool IsActive { get { return true; } }
public float weaponRange = 10.0f;
public float weaponRechargeTime = 1.0f;
public float weaponAimSpeed = 1.0f;
public AudioClip attackSound, selectSound, useWeaponSound;
public float attackVolume = 1.0f, selectVolume = 1.0f, useWeaponVolume = 1.0f;
public int ObjectId { get; set; }
public float detectionRange = 20.0f;
public GameObject explosionPrefab, splat;
protected NavMeshAgent agent;
protected AudioElement audioElement;
protected Animator anim;
protected List<WorldObject> nearbyObjects;
protected Rect playingArea = new Rect(0.0f, 0.0f, 0.0f, 0.0f);
protected Player player;
protected string[] actions = { };
protected bool currentlySelected = false;
protected Bounds selectionBounds;
protected GUIStyle healthStyle = new GUIStyle();
protected float healthPercentage = 1.0f;
protected WorldObject target = null;
protected bool attacking = false;
protected bool movingIntoPosition = false;
protected bool aiming = false;
private List<Material> oldMaterials = new List<Material>();
private float currentWeaponChargeTime;
//we want to restrict how many decisions are made to help with game performance
//the default time at the moment is a tenth of a second
private float timeSinceLastDecision = 0.0f, timeBetweenDecisions = 0.1f;
protected virtual void Awake()
{
anim = GetComponent<Animator>();
boxCollider = GetComponent<BoxCollider>();
selectionBounds = ResourceManager.InvalidBounds;
CalculateBounds();
}
protected virtual void Start()
{
agent = GetComponent<NavMeshAgent>();
SetPlayer();
if (player) SetTeamColor();
InitialiseAudio();
}
protected virtual void Update()
{
if (isSinking)
{
this.transform.Translate(-Vector3.up * 2.5f * Time.deltaTime);
}
if (ShouldMakeDecision()) DecideWhatToDo();
currentWeaponChargeTime += Time.deltaTime;
if (attacking && !movingIntoPosition && !aiming)
{
PerformAttack();
}
}
/**
* A child class should only determine other conditions under which a decision should
* not be made. This could be 'harvesting' for a harvester, for example. Alternatively,
* an object that never has to make decisions could just return false.
*/
protected virtual bool ShouldMakeDecision()
{
if (!attacking && !movingIntoPosition && !aiming)
{
//we are not doing anything at the moment
if (timeSinceLastDecision > timeBetweenDecisions)
{
timeSinceLastDecision = 0.0f;
Debug.Log("");
return true;
}
timeSinceLastDecision += Time.deltaTime;
}
return false;
}
protected virtual void DecideWhatToDo()
{
//determine what should be done by the world object at the current point in time
Vector3 currentPosition = transform.position;
nearbyObjects = WorkManager.FindNearbyObjects(currentPosition, detectionRange);
if (CanAttack())
{
List<WorldObject> enemyObjects = new List<WorldObject>();
foreach (WorldObject nearbyObject in nearbyObjects)
{
Resource resource = nearbyObject.GetComponent<Resource>();
if (resource) continue;
if (nearbyObject.GetPlayer() != player) enemyObjects.Add(nearbyObject);
}
WorldObject closestObject = WorkManager.FindNearestWorldObjectInListToPosition(enemyObjects, currentPosition);
if (closestObject)
{
attacking = true;
//agent.isStopped = true;
BeginAttack(closestObject);
}
}
}
public Player GetPlayer()
{
return player;
}
protected virtual void OnGUI()
{
if (currentlySelected && !ResourceManager.MenuOpen) DrawSelection();
}
protected virtual void InitialiseAudio()
{
List<AudioClip> sounds = new List<AudioClip>();
List<float> volumes = new List<float>();
if (attackVolume < 0.0f) attackVolume = 0.0f;
if (attackVolume > 1.0f) attackVolume = 1.0f;
sounds.Add(attackSound);
volumes.Add(attackVolume);
if (selectVolume < 0.0f) selectVolume = 0.0f;
if (selectVolume > 1.0f) selectVolume = 1.0f;
sounds.Add(selectSound);
volumes.Add(selectVolume);
if (useWeaponVolume < 0.0f) useWeaponVolume = 0.0f;
if (useWeaponVolume > 1.0f) useWeaponVolume = 1.0f;
sounds.Add(useWeaponSound);
volumes.Add(useWeaponVolume);
audioElement = new AudioElement(sounds, volumes, objectName + ObjectId, this.transform);
}
public void SetPlayer()
{
player = transform.root.GetComponentInChildren<Player>();
}
public bool IsOwnedBy(Player owner)
{
if (player && player.Equals(owner))
{
return true;
}
else
{
return false;
}
}
public void CalculateBounds()
{
selectionBounds = new Bounds(transform.position, Vector3.zero);
foreach (Renderer r in GetComponentsInChildren<Renderer>())
{
selectionBounds.Encapsulate(r.bounds);
}
}
//!!!!!MULTI SELECTION!!!!!
public virtual void SetSelection(bool selected, Rect playingArea)
{
currentlySelected = selected;
if (selected)
{
if (audioElement != null) audioElement.Play(selectSound);
this.playingArea = playingArea;
}
CalculateBounds();
}
//!!!!!MULTI SELECTION!!!!!
public Bounds GetSelectionBounds()
{
return selectionBounds;
}
public string[] GetActions()
{
return actions;
}
public void SetColliders(bool enabled)
{
Collider[] colliders = GetComponentsInChildren<Collider>();
foreach (Collider collider in colliders) collider.enabled = enabled;
}
public void SetTransparentMaterial(Material material, bool storeExistingMaterial)
{
if (storeExistingMaterial) oldMaterials.Clear();
Renderer[] renderers = GetComponentsInChildren<Renderer>();
foreach (Renderer renderer in renderers)
{
if (storeExistingMaterial) oldMaterials.Add(renderer.material);
renderer.material = material;
}
}
public void RestoreMaterials()
{
Renderer[] renderers = GetComponentsInChildren<Renderer>();
if (oldMaterials.Count == renderers.Length)
{
for (int i = 0; i < renderers.Length; i++)
{
renderers[i].material = oldMaterials[i];
}
}
}
public void SetPlayingArea(Rect playingArea)
{
this.playingArea = playingArea;
}
public virtual void SetHoverState(GameObject hoverObject)
{
//only handle input if owned by a human player and currently selected
if (player && player.human && currentlySelected)
{
//something other than the ground is being hovered over
if (hoverObject.name != "Ground")
{
Player owner = hoverObject.transform.root.GetComponent<Player>();
Unit unit = hoverObject.transform.parent.GetComponent<Unit>();
Building building = hoverObject.transform.parent.GetComponent<Building>();
if (owner)
{ //the object is owned by a player
if (owner.username == player.username) player.hud.SetCursorState(CursorState.Select);
else if (CanAttack()) player.hud.SetCursorState(CursorState.Attack);
else player.hud.SetCursorState(CursorState.Select);
}
else if (unit || building && CanAttack()) player.hud.SetCursorState(CursorState.Attack);
else player.hud.SetCursorState(CursorState.Select);
}
}
}
public virtual bool CanAttack()
{
//default behaviour needs to be overidden by children
return false;
}
public virtual void PerformAction(string actionToPerform)
{
//it is up to children with specific actions to determine what to do with each of those actions
}
public virtual void MouseClick(GameObject hitObject, Vector3 hitPoint, Player controller)
{
//only handle input if currently selected
if (currentlySelected && hitObject && hitObject.name != "Ground")
{
WorldObject worldObject = hitObject.transform.parent.GetComponent<WorldObject>();
//clicked on another selectable object
if (worldObject)
{
Resource resource = hitObject.transform.parent.GetComponent<Resource>();
if (resource && resource.isEmpty()) return;
Player owner = hitObject.transform.root.GetComponent<Player>();
if (owner)
{ //the object is controlled by a player
if (player && player.human)
{ //this object is controlled by a human player
//start attack if object is not owned by the same player and this object can attack, else select
if (player.username != owner.username && CanAttack())
{
BeginAttack(worldObject);
}
else ChangeSelection(worldObject, controller);
}
else ChangeSelection(worldObject, controller);
}
else ChangeSelection(worldObject, controller);
}
}
}
protected virtual void BeginAttack(WorldObject target)
{
//if (audioElement != null) audioElement.Play(attackSound);
this.target = target;
if (TargetInRange())
{
anim.SetBool("Attacking", true);
attacking = true;
PerformAttack();
}
else AdjustPosition();
}
protected void SetTeamColor()
{
TeamColor[] teamColors = GetComponentsInChildren<TeamColor>();
foreach (TeamColor teamColor in teamColors) teamColor.GetComponent<Renderer>().material.color = player.teamColor;
}
protected virtual void DrawSelectionBox(Rect selectBox)
{
GUI.Box(selectBox, "");
CalculateCurrentHealth(0.35f, 0.65f);
DrawHealthBar(selectBox, "");
}
protected virtual void CalculateCurrentHealth(float lowSplit, float highSplit)
{
healthPercentage = (float)hitPoints / (float)maxHitPoints;
if (healthPercentage > highSplit) healthStyle.normal.background = ResourceManager.HealthyTexture;
else if (healthPercentage > lowSplit) healthStyle.normal.background = ResourceManager.DamagedTexture;
else healthStyle.normal.background = ResourceManager.CriticalTexture;
}
protected void DrawHealthBar(Rect selectBox, string label)
{
healthStyle.padding.top = -20;
healthStyle.fontStyle = FontStyle.Bold;
GUI.Label(new Rect(selectBox.x, selectBox.y - 7, selectBox.width * healthPercentage, 5), label, healthStyle);
}
protected virtual void AimAtTarget()
{
aiming = true;
//this behaviour needs to be specified by a specific object
}
private void ChangeSelection(WorldObject worldObject, Player controller)
{
//this should be called by the following line, but there is an outside chance it will not
SetSelection(false, playingArea);
if (controller.SelectedObject) controller.SelectedObject.SetSelection(false, playingArea);
controller.SelectedObject = worldObject;
worldObject.SetSelection(true, controller.hud.GetPlayingArea());
}
private void DrawSelection()
{
GUI.skin = ResourceManager.SelectBoxSkin;
Rect selectBox = WorkManager.CalculateSelectionBox(selectionBounds, playingArea);
//Draw the selection box around the currently selected object, within the bounds of the playing area
GUI.BeginGroup(playingArea);
DrawSelectionBox(selectBox);
GUI.EndGroup();
}
private bool TargetInRange()
{
Vector3 targetLocation = target.transform.position;
Vector3 direction = targetLocation - transform.position;
if (direction.sqrMagnitude < weaponRange * weaponRange)
{
return true;
}
return false;
}
private void AdjustPosition()
{
Unit self = this as Unit;
if (self)
{
movingIntoPosition = true;
Vector3 attackPosition = FindNearestAttackPosition();
self.StartMove(attackPosition);
attacking = true;
}
else
{
attacking = false;
}
}
private Vector3 FindNearestAttackPosition()
{
Vector3 targetLocation = target.transform.position;
Vector3 direction = targetLocation - transform.position;
float targetDistance = direction.magnitude;
float distanceToTravel = targetDistance - (0.9f * weaponRange);
return Vector3.Lerp(transform.position, targetLocation, distanceToTravel / targetDistance);
}
private void PerformAttack()
{
if (!target)
{
attacking = false;
anim.SetBool("Attacking", false);
anim.SetBool("IsRunning", false);
return;
}
if (!TargetInRange())
{
AdjustPosition();
}
else if (!TargetInFrontOfWeapon())
{
AimAtTarget();
}
else if (ReadyToFire())
{
//attacking = true;
UseWeapon();
}
//if (TargetInRange() && (attacking = true))
//{
// AdjustPosition();
//}
}
private bool TargetInFrontOfWeapon()
{
Vector3 targetLocation = target.transform.position;
Vector3 direction = targetLocation - transform.position;
if (direction.normalized == transform.forward.normalized) return true;
else return false;
}
private bool ReadyToFire()
{
if (currentWeaponChargeTime >= weaponRechargeTime)
{
return true;
}
return false;
}
protected virtual void UseWeapon()
{
if (audioElement != null && Time.timeScale > 0) audioElement.Play(useWeaponSound);
currentWeaponChargeTime = 0.0f;
//this behaviour needs to be specified by a specific object
}
public void TakeDamage(float damage)
{
//GameObject.Instantiate(impactVisual, target.transform.position, Quaternion.identity);
hitPoints -= damage;
if (hitPoints <= 0)
{
Instantiate(explosionPrefab, transform.position + new Vector3(0, 5, 0), Quaternion.identity);
Instantiate(splat, transform.position, Quaternion.identity);
Destroy(gameObject);
}
}
}
using UnityEngine;
using System.Collections.Generic;
namespace RTS
{
public static class WorkManager
{
public static Rect CalculateSelectionBox(Bounds selectionBounds, Rect playingArea)
{
//shorthand for the coordinates of the centre of the selection bounds
float cx = selectionBounds.center.x;
float cy = selectionBounds.center.y;
float cz = selectionBounds.center.z;
//shorthand for the coordinates of the extents of the selection bounds
float ex = selectionBounds.extents.x;
float ey = selectionBounds.extents.y;
float ez = selectionBounds.extents.z;
//Determine the screen coordinates for the corners of the selection bounds
List<Vector3> corners = new List<Vector3>();
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy + ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy + ey, cz - ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy - ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy + ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx + ex, cy - ey, cz - ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy - ey, cz + ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy + ey, cz - ez)));
corners.Add(Camera.main.WorldToScreenPoint(new Vector3(cx - ex, cy - ey, cz - ez)));
//Determine the bounds on screen for the selection bounds
Bounds screenBounds = new Bounds(corners[0], Vector3.zero);
for (int i = 1; i < corners.Count; i++)
{
screenBounds.Encapsulate(corners[i]);
}
//Screen coordinates start in the bottom left corner, rather than the top left corner
//this correction is needed to make sure the selection box is drawn in the correct place
float selectBoxTop = playingArea.height - (screenBounds.center.y + screenBounds.extents.y);
float selectBoxLeft = screenBounds.center.x - screenBounds.extents.x;
float selectBoxWidth = 2 * screenBounds.extents.x;
float selectBoxHeight = 2 * screenBounds.extents.y;
return new Rect(selectBoxLeft, selectBoxTop, selectBoxWidth, selectBoxHeight);
}
public static GameObject FindHitObject(Vector3 origin)
{
Ray ray = Camera.main.ScreenPointToRay(origin);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, ResourceManager.RayCastLimit)) return hit.collider.gameObject;
return null;
}
public static Vector3 FindHitPoint(Vector3 origin)
{
Ray ray = Camera.main.ScreenPointToRay(origin);
RaycastHit hit;
Debug.DrawRay(ray.origin, ray.direction * ResourceManager.RayCastLimit, Color.yellow);
if (Physics.Raycast(ray, out hit, ResourceManager.RayCastLimit)) return hit.point;
return ResourceManager.InvalidPosition;
}
public static List<WorldObject> FindNearbyObjects(Vector3 position, float range)
{
Collider[] hitColliders = Physics.OverlapSphere(position, range);
HashSet<int> nearbyObjectIds = new HashSet<int>();
List<WorldObject> nearbyObjects = new List<WorldObject>();
for (int i = 0; i < hitColliders.Length; i++)
{
Transform parent = hitColliders[i].transform.parent;
if (parent)
{
WorldObject parentObject = parent.GetComponent<WorldObject>();
if (parentObject && !nearbyObjectIds.Contains(parentObject.ObjectId))
{
nearbyObjectIds.Add (parentObject.ObjectId);
nearbyObjects.Add (parentObject);
}
}
}
return nearbyObjects;
}
public static WorldObject FindNearestWorldObjectInListToPosition(List<WorldObject> objects, Vector3 position)
{
if (objects == null || objects.Count == 0) return null;
WorldObject nearestObject = objects[0];
float sqrDistanceToNearestObject = Vector3.SqrMagnitude(position - nearestObject.transform.position);
for (int i = 1; i < objects.Count; i++)
{
float sqrDistanceToObject = Vector3.SqrMagnitude(position - objects[i].transform.position);
if (sqrDistanceToObject < sqrDistanceToNearestObject)
{
sqrDistanceToNearestObject = sqrDistanceToObject;
nearestObject = objects[i];
}
}
return nearestObject;
}
}
}
The first thing you need to check is if inside
FindNearbyObjects()
The variable
hitColliders = Physics.OverlapSphere(position, range);
Changes it's size when you instantiate new buildings. In case that is not the case, it may be because you are not adding colliders to the buildings when you instantiate them.
However, I think there are better ways for you to detect buildings without using this Physics.OverlapSphere(), which may be expensive in performance. If I were you I will would give a special tag to the buildings (the original and the instantiated ones) and I will use that in my logic to detect them. So they will be potential targets in your method:
DecideWhatToDo()
Here you can read about how to tag the GameObjects:
https://docs.unity3d.com/Manual/Tags.html
I have a Timer that counts down every 3 seconds (The white circle). It has a script attached called ReloadTimer.
I have a script that fires bullets (TankShooter) and reloads for 3 seconds.
How do I make it so that my countdown starts when I am reloading?
I tried looking at a lot of Unity forums and the advice didn't work.
ReloadTimer.cs
[ExecuteInEditMode]
public class ReloadTimer : MonoBehaviour
{
public Image filled;
public Text text;
public float maxValue = 3;
public float value = 0;
// UpdateReload is called once per frame
public void UpdateReload ()
{
value = Mathf.Clamp(value, 0, maxValue);
float amount = value / maxValue;
filled.fillAmount = amount;
text.text = value.ToString();
}
}
TankShooter
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public AudioSource m_ShootingAudio;
public AudioClip m_FireClip;
public float m_ShellVelocity = 100f;
private string m_FireButton;
public int maxAmmo = 5;
private int currentAmmo;
public float reloadTime = 2f;
private bool isReloading = false;
public ReloadTimer reloadTimer;
public class TankShootingT : NetworkBehaviour
{
public ReloadTimer reloadTimer;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
currentAmmo = maxAmmo;
m_FireButton = "Fire" + m_PlayerNumber;
}
private void Update()
{
if (isReloading)
return;
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
reloadTimer.UpdateReload();
if (m_FireButton == "Fire1" && Input.GetButtonUp(m_FireButton))
{
// we released the button, have not fired yet
CmdShoot();
}
}
IEnumerator Reload()
{
isReloading = true;
Debug.Log("Reloading...");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
}
[Command]
private void CmdShoot()
{
currentAmmo--;
// Instantiate and launch the shell.
Rigidbody shellInstance = Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = m_ShellVelocity * m_FireTransform.forward;
// Server spawns the shell
NetworkServer.Spawn(shellInstance.gameObject);
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
}
}
For starters, There isn't such thing as UpdateReload that would be "called once per frame" as this is not a predetermined Unity function, it is just a function that you created (You can read about this here). Another problem is that you didn't even call that function anywhere else in your scripts. And even if you did, Mathf.Clamp() needs to be placed in an Update() function so it can update it's value each frame.
I made some modifications to the scripts that you posted, but I haven't tested them yet. give it a try and let me know how it goes:
ReloadTimer.cs
public class ReloadTimer : MonoBehaviour
{
public static ReloadTimer Instance { set; get; }
public Image filled;
public Text text;
public float coolDownTime = 3;
public bool isCoolingDown = false;
void Awake()
{
Instance = this;
}
void Update()
{
if (isCoolingDown == true)
{
filled.fillAmount += 1.0f / coolDownTime * Time.deltaTime;
int percentageInt = Mathf.RoundToInt((filled.fillAmount / coolDownTime) * 10);
text.text = percentageInt.ToString();
}
}
}
TankShootingT.cs
public int m_PlayerNumber = 1;
public Rigidbody m_Shell;
public Transform m_FireTransform;
public AudioSource m_ShootingAudio;
public AudioClip m_FireClip;
public float m_ShellVelocity = 100f;
private string m_FireButton;
public int maxAmmo = 5;
private int currentAmmo;
public float reloadTime = 2f;
private bool isReloading = false;
public ReloadTimer reloadTimer;
public class TankShootingT : NetworkBehaviour
{
public ReloadTimer reloadTimer;
private void Start()
{
if (!isLocalPlayer)
{
return;
}
currentAmmo = maxAmmo;
m_FireButton = "Fire" + m_PlayerNumber;
}
private void Update()
{
if (isReloading)
return;
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
reloadTimer.UpdateReload();
if (m_FireButton == "Fire1" && Input.GetButtonUp(m_FireButton))
{
// we released the button, have not fired yet
CmdShoot();
}
}
IEnumerator Reload()
{
isReloading = true;
ReloadTimer.Instance.isCoolingDown = true;
Debug.Log("Reloading...");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
ReloadTimer.Instance.isCoolingDown = false;
ReloadTimer.Instance.filled.fillAmount = 0.0f;
}
[Command]
private void CmdShoot()
{
currentAmmo--;
// Instantiate and launch the shell.
Rigidbody shellInstance = Instantiate(m_Shell, m_FireTransform.position, m_FireTransform.rotation) as Rigidbody;
shellInstance.velocity = m_ShellVelocity * m_FireTransform.forward;
// Server spawns the shell
NetworkServer.Spawn(shellInstance.gameObject);
m_ShootingAudio.clip = m_FireClip;
m_ShootingAudio.Play();
}
}
Hope this helps a bit.
Like the title says, the enemy projectiles are not launching. They are spawned and destroyed in the same place. They do not fire toward the target. Code in link:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MonkeyController : MonoBehaviour {
private const int MAX_INJURES = 1;
public float DurationMovement = 2f;
public Transform SpawnLocation;
public Transform[] PatrolPoints;
public GameObject MonkeyProjectile;
public Rigidbody2D Abby;
public float AttackDelay = 0.75f;
public float ProjectileSpeed = 1;
public int ProjectilesCount = 4;
public float activePosition;
public float passivePosition;
private List<GameObject> ProjectileList = new List<GameObject>();
private int PatrolIndex = 0;
private int injures = 0;
private bool canPatrol;
private Coroutine fireCoroutine;
private Coroutine patrolCoroutine;
private Coroutine movementCoroutine;
WaitForSeconds delay;
Vector2 AttackVector = Vector2.zero;
// Use this for initialization
private void Start () {
delay = new WaitForSeconds(AttackDelay);
InitializeProjectileList();
fireCoroutine = StartCoroutine(MonkeyFireProjectileBehaviour());
patrolCoroutine = StartCoroutine(PatrolBehaviour(PatrolPoints[PatrolIndex].position));
}
private IEnumerator MonkeyFireProjectileBehaviour()
{
yield return delay;
if (GameManager.GetInstance().gameState == GameState.GAME_OVER)
yield return null;
AttackVector = Abby.transform.position - (transform.position /*+ (Vector3)Abby.velocity/10f*/);
FireProjectile(AttackVector);
fireCoroutine = StartCoroutine(MonkeyFireProjectileBehaviour());
}
private IEnumerator PatrolBehaviour(Vector3 animationLocation)
{
canPatrol = true;
float distance = (transform.position - animationLocation).magnitude;
float duration = DurationMovement;
Vector3 startingPos = transform.position;
float t = 0;
while (t < 1 && canPatrol)
{
t += Time.deltaTime / duration;
transform.position = Vector3.Lerp(startingPos, animationLocation, t);
yield return null;
}
if (!canPatrol)
yield break;
transform.position = animationLocation;
IncrementMovementIndex();
patrolCoroutine = StartCoroutine(PatrolBehaviour(PatrolPoints[PatrolIndex].position));
yield return null;
}
private void IncrementMovementIndex()
{
PatrolIndex++;
if(PatrolIndex == PatrolPoints.Length)
{
PatrolIndex = 0;
}
}
private void InitializeProjectileList()
{
GameObject Projectile;
for (int i = 0; i < ProjectilesCount; i++)
{
Projectile = Instantiate(MonkeyProjectile);
Projectile.SetActive(false);
ProjectileList.Add(Projectile);
}
}
private void FireProjectile(Vector2 forceProjectile)
{
foreach (GameObject projectile in ProjectileList)
{
if (!projectile.activeInHierarchy)
{
projectile.transform.position = SpawnLocation.position;
projectile.SetActive(true);
projectile.GetComponent<TrailRenderer>().enabled = true;
projectile.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic;
projectile.GetComponent<Rigidbody2D>().AddForce(forceProjectile * (ProjectileSpeed + Random.Range(0, ProjectileSpeed/2)), ForceMode2D.Impulse);
break;
}
}
}
private IEnumerator DoMovementCoroutine()
{
yield return new WaitForSeconds (0.01F);
transform.localPosition = new Vector2(passivePosition, 0);
yield return AnimatorExecutive.AnimatePositionCoroutine (gameObject, new Vector2 (activePosition, 0), 5.0F);
fireCoroutine = StartCoroutine(MonkeyFireProjectileBehaviour());
patrolCoroutine = StartCoroutine(PatrolBehaviour(PatrolPoints[PatrolIndex].position));
}
private void OnCollisionEnter2D(Collision2D otherCollision)
{
if (otherCollision.gameObject.tag == "Projectile")
{
injures++;
if (injures >= MAX_INJURES)
{
injures = 0;
canPatrol = false;
GetComponent<AudioSource>().Play();
if(fireCoroutine != null) StopCoroutine (fireCoroutine);
if(patrolCoroutine != null) StopCoroutine (patrolCoroutine);
movementCoroutine = StartCoroutine (DoMovementCoroutine());
}
}
}
}
With the information your provided, I would say the problem you may be facing is the GameObject you pass in the inspector to get the SpawnLocation has got a collider and a script with a OnCollisionEnter2D, which detect the projectil when you instantiate it and destroy it.
However, you are not destroying the projectil inside this OnCollisionEnter2D.
private void OnCollisionEnter2D(Collision2D otherCollision)
{
if (otherCollision.gameObject.tag == "Projectile")
{
injures++;
if (injures >= MAX_INJURES)
{
injures = 0;
canPatrol = false;
GetComponent<AudioSource>().Play();
if(fireCoroutine != null) StopCoroutine (fireCoroutine);
if(patrolCoroutine != null) StopCoroutine (patrolCoroutine);
movementCoroutine = StartCoroutine (DoMovementCoroutine());
}
}
}
In the case you dont have in your code any line to destroy the projectil gameobject after a collision. The problem could be you are not reaching this line projectile.SetActive(true);
I will try to replicate your code and check what may be happening
I'm making a game in Unity3D with C#. I am using GUI.box to show a healthbar for the mobs, but I only want to show the GUI.box if there is a target.
This is my code at the moment.
public GameObject target;
public bool existsTarget;
// Use this for initialization
void Start()
{
PlayerAttack pa = (PlayerAttack)GetComponent("PlayerAttack");
target = pa.target;
existsTarget = false;
}
// Update is called once per frame
void Update()
{
if(target != null)
existsTarget = true;
else
existsTarget = false;
}
void OnGUI()
{
if(existsTarget)
GUI.Box(new Rect(500, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
else {
GUI.Box(new Rect(Screen.width, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
}
Unfortunately this doesn't show any healthbars at all. Any ideas as to why?
Posting the scripts here after popular demand.
public class Targetting : MonoBehaviour {
public List<Transform> targets;
public List<Transform> items;
public GameObject TheSelectedTarget {get; set;}
private Transform selectedTarget;
private Transform selectedItem;
private Transform myTransform;
// Use this for initialization
void Start () {
targets = new List<Transform>();
items = new List<Transform>();
selectedTarget = null;
selectedItem = null;
myTransform = transform;
TheSelectedTarget = null;
addAllEnemies();
addAllItems();
}
//adds all targets to a list
private void addAllEnemies() {
GameObject[] go = GameObject.FindGameObjectsWithTag("Enemy");
foreach(GameObject enemy in go){
addTarget(enemy.transform);
}
}
//adds a target
private void addTarget(Transform enemy) {
targets.Add(enemy);
}
//sorts target by distance
private void sortTargets() {
targets.Sort(delegate(Transform t1, Transform t2) {
return Vector3.Distance(t1.position, myTransform.position).CompareTo(Vector3.Distance(t2.position, myTransform.position));
});
}
//targets an enemy
private void targetEnemy() {
addAllEnemies();
if(selectedTarget == null) {
sortTargets();
selectedTarget = targets[0];
} else {
int index = targets.IndexOf(selectedTarget);
if(index < targets.Count -1) {
index++;
} else {
index = 0;
}
deselectTarget();
selectedTarget = targets[index];
}
selectTarget();
targets.Clear();
}
//selects a specific target, and colors it red
public void selectTarget() {
selectedTarget.renderer.material.color = Color.red;
PlayerAttack pa = (PlayerAttack)GetComponent("PlayerAttack");
pa.target = selectedTarget.gameObject;
TheSelectedTarget = pa.target;
}
//deselects the current selected target, and colors i grey
private void deselectTarget() {
selectedTarget.renderer.material.color = Color.gray;
selectedTarget = null;
}
//adds all items to a list
void addAllItems() {
GameObject[] go = GameObject.FindGameObjectsWithTag("Book");
foreach(GameObject book in go){
addItem(book.transform);
}
}
'
.... And then the script continues but without any relevance to this...
' public class EnemyHealth : MonoBehaviour
{
public string enemyName;
public int maxHealth = 100;
public int curHealth = 100;
public float healthBarLength;
public GameObject target;
public bool existsTarget;
public AudioSource dying;
// Use this for initialization
void Start()
{
//enemyName = this.enemyName;
healthBarLength = Screen.width / 3;
existsTarget = false;
}
// Update is called once per frame
void Update()
{
adjustCurHealth(0);
Targetting ta = (Targetting)GetComponent("Targetting");
target = ta.TheSelectedTarget;
Debug.Log (target);
if(target != null)
existsTarget = true;
else {
existsTarget = false;
}
}
void OnGUI()
{
if(existsTarget)
GUI.Box(new Rect(500, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
else {
GUI.Box(new Rect(Screen.width, 10, healthBarLength, 20), curHealth + "/" + maxHealth);
}
}
public void adjustCurHealth(int adj)
{
curHealth += adj;
if (curHealth < 0)
curHealth = 0;
if (curHealth > 100)
curHealth = 100;
if (maxHealth < 0)
maxHealth = 1;
if(curHealth == 0)
{
//dying.Play ();
GameObject.Destroy(gameObject);
}
healthBarLength = (Screen.width / 3) * (curHealth / (float)maxHealth);
}
}
Are you ever setting the target anywhere other than the Start() method? The code you show will only ever show a GUI.box if the PlayerAttack.Target is not null at the start. Try moving this code to the Update() method.
PlayerAttack pa = (PlayerAttack)GetComponent("PlayerAttack");
target = pa.target;
Edit:
Check to see if the target is null, that could be the issue.
target = pa.target;
Debug.Log(target);
This will either print to the log as whatever GameObject it is, or null. If it's null, then there is no target.