I am trying to create a select object script in unity.
What it should do is when I hover over an object it colors red (and it does) and when I press "1" the GameObject's targetHighlighted will be filled with the object I am hovering over at that moment. In a Debug.Log this all works fine, targetHighlightedis filled.
When I press "1" however the targetHighlighted object is still left empty. It doesn't matter if I press it while hovering over the object or away from it.
My full code is much more extensive than this. But this section of code contains the problem, so I reduced it to this.
Can anyone explain to me how come when I press "1" the the Debug.Log doesn't show the targetHighlighted or targetSelected?
Basically why do the mouseenter and mouseexit log the right Object, but the setTarget function doesn't?
using UnityEngine;
using System.Collections;
public class TargetSelectionScript: MonoBehaviour {
// Store the current selected gameobject
GameObject targetHighlighted;
Renderer rend;
Color initialColor = Color.white;
Color selectedColor = Color.red;
public GameControllerScript gameController;
void Start() {
}
void Update() {
if (Input.GetKeyDown("1")) {
SetTarget();
}
}
void OnMouseEnter() {
SelectTarget();
}
void OnMouseExit() {
ClearTarget();
}
void SelectTarget() {
RaycastHit hitInfo = new RaycastHit();
Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo);
targetHighlighted = hitInfo.transform.gameObject;
rend = targetHighlighted.GetComponent < Renderer > ();
rend.material.color = selectedColor;
Debug.Log("Highlighted target: " + targetHighlighted);
}
void ClearTarget() {
Debug.Log(targetHighlighted);
}
void SetTarget() {
Debug.Log(targetHighlighted);
}
}
Because no key is registered under "1"
for this reason, you must resort to using the appropriate KeyCode,
if (GetKeyDown(KeyCode.Alpha1))
SetTarget();
Try these changes:
GameObject targetHighlighted;
Renderer rend;
Color initialColor = Color.white;
Color selectedColor = Color.red;
public GameControllerScript gameController;
[SerializeField]
private bool targetSelected = false;
void Start() {
}
void Update() {
if (Input.GetKeyDown("1") && this.targetSelected == true) {
SetTarget();
}
}
void OnMouseEnter() {
SelectTarget();
}
void OnMouseExit() {
ClearTarget();
}
void SelectTarget() {
RaycastHit hitInfo;
Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo);
this.targetHighlighted = hitInfo.transform.gameObject;
rend = this.targetHighlighted.GetComponent < Renderer > ();
rend.material.color = selectedColor;
Debug.Log("Highlighted target: " + targetHighlighted);
this.targetSelected = true;
}
void ClearTarget() {
Debug.Log(this.targetHighlighted);
}
void SetTarget() {
Debug.Log(this.targetHighlighted);
}
Related
so I have this code :
public class ball_physics : MonoBehaviour
{
public Rigidbody ball;
public open2close claw;
public Vector3 offset;
Rigidbody rb;
private float forceMultiplier = 20;
private bool isShoot;
Vector3 start_position;
public path path;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.Sleep();
start_position = transform.position;
}
void Update()
{
// *************
}
void Shoot(Vector3 Force)
{
if (isShoot)
{
print("isshot false");
return;
}
rb.AddForce(new Vector3(Force.x, Force.y,Force.z)* forceMultiplier);
isShoot = true;
path.Instance.HideLine();
}
private void OnTriggerStay(Collider ball)
{
if (isShoot)
{
return;
}
print("ontriggerstay");
if (claw.isClosed && claw.transform.gameObject.tag == "claw" )
{
print("claw");
//rb.Sleep();
transform.position = claw.rightClaw.transform.position + offset;
Vector3 forceInit = (start_position - transform.position);
path.Instance.UpdateTrajectory(forceInit * forceMultiplier, rb, transform.position);
}
}
private void OnTriggerExit(Collider ball)
{
if (claw.isClosed && claw.transform.gameObject.tag == "claw")
{
rb.WakeUp();
}
if (claw.isClosed == false)
{
Shoot(start_position - transform.position);
}
}
}
So on my other codes I have OnStayTrigger, which basically a clawhand grabs a ball and pulls. But this code is suppose to show a trajectory line and shoot. When I shoot the first time it works. But when I try again, The clawhand can grab the ball but it doesnt show the trajectory line nor shoots it. So im guessing this is the code that needs to be fixed. How can I make OnTriggerStay work all the time. I wouldnt want to change any code because it works perfectly. How can I just keep updating the OnTriggerstay so it can work?
At first glance it appears that You never set isShoot back to false, so it would never fire again because in OnTriggerStay you have it return if isShoot = true.
Below is my script, I want to check that animator state finished or not. If animator state(animation) is complete then do some action, but I am enable to do so, Thanks in advance.
using UnityEngine;
using System.Collections;
public class fun_for_level_complet : MonoBehaviour
{
public Animator animator_obj;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
check_end_state ();
}
public void level_complete()
{
if (this.GetComponent<movement_of_player> () != null)
{
this.GetComponent<movement_of_player> ().enabled = false;
}
animator_obj.SetBool ("congo",true);
}
public void check_end_state ()
{
// here I want to check if animation ends then print
// my state name is congo
// animation name Waving
// using base layer
if (animator_obj.GetCurrentAnimatorStateInfo (0).IsName ("congo") && !animator_obj.IsInTransition (0))
{
Debug.Log ("anim_done");
}
}
}
You can use events on animation clips. It's explained in Unity manual:
https://docs.unity3d.com/Manual/AnimationEventsOnImportedClips.html
In Animation Inport Settings in Annimations tab You can find Event heading. Position the playback to the end and click Add Event. Fill the Function field with name of the function to call at the end of animation. Just make sure that Game Object with this animation has a corresponding function.
I figure it out, and I done it by checking state starts or not if starts then check for end, by states names. Below is code, and working fine, remember(in last state you have to create empty state)
using UnityEngine;
using System.Collections;
public class fun_for_level_complet : MonoBehaviour
{
public Animator animator_obj;
private string[] states = new string[]{ "congo" };
private string current_state_name = "";
private bool waiting_end_state = false;
private bool wait_for_anim_start = false;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if (waiting_end_state)
{
if (wait_for_anim_start)
{
if (animator_obj.GetCurrentAnimatorStateInfo (0).IsName (current_state_name))
{
wait_for_anim_start = false;
}
} else
{
check_end_state ();
}
}
}
public void level_complete()
{
if (this.GetComponent<movement_of_player> () != null)
{
this.GetComponent<movement_of_player> ().enabled = false;
}
animator_obj.SetBool ("congo",true);
waiting_end_state = true;
wait_for_anim_start = true;
current_state_name = states [0];
}
public void check_end_state()
{
if (!animator_obj.GetCurrentAnimatorStateInfo (0).IsName (current_state_name))
{
waiting_end_state = false;
if( current_state_name==states[0] )
{
GameObject.FindGameObjectWithTag ("inagmegui").SendMessage ("make_it_true");
print ( "animation has been ended" );
}
}
}
}
If you do not have any transitions and would like to to be notified when the animation has ended for the "stateName" in layer 0, I did by calling the following IEnumerator :
public IEnumerator PlayAndWaitForAnim(Animator targetAnim, string stateName)
{
targetAnim.Play(stateName);
//Wait until we enter the current state
while (!targetAnim.GetCurrentAnimatorStateInfo(0).IsName(stateName))
{
yield return null;
}
//Now, Wait until the current state is done playing
while ((targetAnim.GetCurrentAnimatorStateInfo(0).normalizedTime) % 1 < 0.99f)
{
yield return null;
}
//Done playing. Do something below!
EndStepEvent();
}
The main logic is once the state is entered, we should check if the fractional part of 'normalizedTime' variable reached 1, which means the animation has reached its end state.
Hope this helps
You can create custom StateMachineBehaviour like this:
using UnityEngine;
public class AttackBehaviour : StateMachineBehaviour
{
public GameObject particle;
public float radius;
public float power;
protected GameObject clone;
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
clone = Instantiate(particle, animator.rootPosition, Quaternion.identity) as GameObject;
Rigidbody rb = clone.GetComponent<Rigidbody>();
rb.AddExplosionForce(power, animator.rootPosition, radius, 3.0f);
}
override public void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Destroy(clone);
}
override public void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("On Attack Update ");
}
override public void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("On Attack Move ");
}
override public void OnStateIK(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
Debug.Log("On Attack IK ");
}
}
Documentation https://docs.unity3d.com/ScriptReference/StateMachineBehaviour.html
I am developing a simple 2D game. In game, I've created a prefab for charcaters. and I am changing sprite of prefab runtime. This all execute fine. Now I want to apply click event on a particular prefab clone and want to increase scale of prefab. I am attaching a c# script what I have did till now.
public class ShoppingManager : MonoBehaviour {
public static ShoppingManager instance;
[System.Serializable]
public class Shopping
{
public string CharacterName;
public Sprite CharacterSprite;
}
public GameObject CharacterPrefab;
public Transform CharacterSpacer;
public List<Shopping> ShoppingList;
private CharacterScript NewCharacterScript;
/*********************************************Awake()******************************************/
void Awake()
{
MakeSingleton ();
}
/******************************Create object of the script**********************************/
void MakeSingleton()
{
instance = this;
DontDestroyOnLoad (gameObject);
}
// Use this for initialization
void Start () {
LoadCharacters ();
}
void LoadCharacters()
{
foreach (var characters in ShoppingList) {
GameObject NewCharacter = Instantiate (CharacterPrefab) as GameObject;
NewCharacterScript = NewCharacter.GetComponent<CharacterScript> ();
NewCharacterScript.CharacterName = characters.CharacterName;
NewCharacterScript.Charcater.GetComponent<Image> ().sprite = characters.CharacterSprite;
NewCharacterScript.GetComponent<Button> ().onClick.AddListener (() => CharacterClicked (NewCharacterScript.CharacterName, NewCharacterScript.Charcater));
NewCharacter.transform.SetParent (CharacterSpacer, false);
}
}
void CharacterClicked(string CharacterName, GameObject Char)
{
StartCoroutine (IncreaseScale (Char));
}
IEnumerator IncreaseScale(GameObject TempCharacter)
{
int i = 5;
while (i > 0) {
yield return new WaitForSeconds (0.1f);
Vector3 TempVector = TempCharacter.GetComponent<RectTransform> ().localScale;
TempVector.x = TempVector.x + 0.2f;
TempVector.y = TempVector.y + 0.2f;
TempCharacter.GetComponent<RectTransform> ().localScale = TempVector;
i--;
}
}
}
This code triggers click event and also it increases scale but of last clone, not of clicked prefab clone. What I am missing, I can't understand. What should I correct in this. and Yeah! I am also attaching code of a script that I've added on prefab.
public class CharacterScript : MonoBehaviour {
public string CharacterName;
public GameObject Charcater;
}
create collider for your object attach the script below to it this way each object is responsible for handling its own functionalities like increasing its own size
public class characterFunctionalities: MonoBehaviour{
void OnMouseDown()
{
StartCoroutine (IncreaseScale (this.gameobject));
}
IEnumerator IncreaseScale(GameObject TempCharacter)
{
int i = 5;
while (i > 0) {
yield return new WaitForSeconds (0.1f);
Vector3 TempVector = TempCharacter.GetComponent<RectTransform> ().localScale;
TempVector.x = TempVector.x + 0.2f;
TempVector.y = TempVector.y + 0.2f;
TempCharacter.GetComponent<RectTransform> ().localScale = TempVector;
i--;
}
}
}
using UnityEngine;
using System.Collections;
public class underWater : MonoBehaviour {
public float uwaterLevel=15f;
public Color normalColor;
public Color underWaterColor;
void Start () {
normalColor = new Color (0.5f,0.5f,0.5f,0.5f);
underWaterColor = new Color (0.22f,0.65f,0.77f,0.5f);
}
void Update () {
Debug.Log (uwaterLevel);
Debug.Log (transform.position.y);
if(Camera.main.transform.position.y<uwaterLevel){
Debug.Log("Underwater Update");
setUnderWater();
}else{
Debug.Log("Normal Update");
setNormal();
}
}
public void setUnderWater(){
Debug.Log("Under Water");
RenderSettings.fog = true;
RenderSettings.fogDensity = 0.05f;
RenderSettings.fogColor = underWaterColor;
}
public void setNormal(){
Debug.Log("Normal");
RenderSettings.fog = true;
RenderSettings.fog = false;
RenderSettings.fogDensity = 0.003f;
RenderSettings.fogColor = normalColor;
}
}
How can I detect if my character is under water? Water is above the ground(a lake between the hills) so I can't use negative Y-axis. I'm using FPSController from Unity Standard Assests.
Make a large Collider the size of the water. Make it a trigger. Make it's tag "Water"
public void OnTriggerEnter(Collider col)
{
if(col.tag == "Water")
{
// In water
}
}
public void OnTriggerStay(Collider col)
{
if(col.tag == "Water")
{
// In water
}
}
public void OnTriggerExit(Collider col)
{
if(col.tag == "Water")
{
// Exit water
}
}
I'm posting an answer rather than a comment since I can't comment yet.
Similar to what Andrew said, to prevent your game from thinking you're underwater as soon as your character puts its foot in the water, You could add an empty gameobject a few centimeters above your character's head and put a collider on that.
Then use Andrew's logic to determine that your character is underwater.
I would like to make a gameobject in my game, which when enter trigger, then it will teleport my character to an another position (otherTeleport.transform.position), however when I use the script what I have written, my character won't teleport there, while the enemy will. If I put a Debug.Log in the bounce script which will log the character's position I see that my character has been at the otherTeleport's position, but only for one debuglog, and after that it's back to the original teleport's position. The teleport's would be working two-way so if the user go to one it will port it to the second, and if he goes to the second, then it will be ported to the first.
Here is my code:
public class TeleportScript : MonoBehaviour {
public GameObject otherTeleport;
private Collider otherTeleportColl;
public bool isNeedToTeleport;
private TeleportScript otherTeleportScript;
private GameObject player;
private Bounce bounceScript;
// Use this for initialization
void Start () {
isNeedToTeleport = true;
otherTeleportColl = otherTeleport.GetComponent<Collider>();
otherTeleportScript = otherTeleport.GetComponent<TeleportScript>();
player = GameObject.Find("Player");
bounceScript = player.GetComponent<Bounce>();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider collider) {
if (isNeedToTeleport == true) {
if (collider.tag == "Enemy") {
otherTeleportScript.setNeedToTeleport(false);
collider.transform.position = otherTeleport.transform.position;
}
if (collider.tag == "Player") {
otherTeleportScript.setNeedToTeleport(false);
bounceScript.player.transform.position = otherTeleport.transform.position;
collider.transform.position = otherTeleport.transform.position;
bounceScript.playerTransform.position = otherTeleport.transform.position;
}
}
}
void OnTriggerExit(Collider collider) {
Debug.Log ("TELEPORTED OUT");
setNeedToTeleport(true);
otherTeleportScript.setNeedToTeleport(true);
}
public void setNeedToTeleport(bool value) {
if (value == true) {
isNeedToTeleport = true;
}
else {
isNeedToTeleport = false;
}
}
}
Any help would be appreciated!
I did some changes to your code, can't test it because I don't have access to unity right now, let me know if it works...
public class TeleportScript : MonoBehaviour {
public GameObject otherTeleport;
private Collider otherTeleportColl;
public bool isNeedToTeleport;
private TeleportScript otherTeleportScript;
private GameObject player;
private Bounce bounceScript;
// Use this for initialization
void Start () {
isNeedToTeleport = true;
otherTeleportColl = otherTeleport.GetComponent<Collider>();
otherTeleportScript = otherTeleport.GetComponent<TeleportScript>();
player = GameObject.Find("Player");
bounceScript = player.GetComponent<Bounce>();
}
// Update is called once per frame
void Update () {
}
void OnTriggerEnter(Collider collider) {
if(collider.tag == "Player" && isNeedToTeleport)
{
otherTeleportScript.setNeedToTeleport(false);
collider.transform.position = otherTeleport.transform.position;
bounceScript.player.transform.position = otherTeleport.transform.position; //not sure what is this for....
}
}
void OnTriggerExit(Collider collider) {
Debug.Log ("TELEPORTED OUT");
setNeedToTeleport(true);
otherTeleportScript.setNeedToTeleport(true);
}
public void setNeedToTeleport(bool value) {
if (value == true)
isNeedToTeleport = true;
else
isNeedToTeleport = false;
}
}
Your character teleports to the other place
after that you move the collider over there aswell, notice that the collider's object of other script of teleportation has been initialized with the isNeedToTeleport = true;
The character now also bounces there, hits the collider of the other object, it checks that isNeedToTelport is in fact true in this other script and it goes into the same If condition and teleports back!
Take this line:
otherTeleportScript.setNeedToTeleport(true);
out of your OnTriggerExit, or set it to false. Actually setting it to false might be better. You want to tell the other script that someone is incoming and it shouldn't immediately teleport them back.
As an aside, you should change your setNeedToTeleport function to this:
public void setNeedToTeleport(bool value) {
isNeedToTeleport = value;
}
Those ifs are redundant.