So I have two scripts one to press a button which changes between two objects, and what I want to do is be able to switch out the second avatar with others when I hit e when near another object. the scripts are working, but I have no clue how to get it to switch
here are the trigger script and the switch script
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwitchCharacterScript : MonoBehaviour
{
private const string ButtonName = "E";
// references to controlled game objects
public GameObject avatar1, avatar2;
// variable contains which avatar is on and active
int whichAvatarIsOn = 1;
// Use this for initialization
void Start()
{
// anable first avatar and disable another one
avatar1.gameObject.SetActive(true);
avatar2.gameObject.SetActive(false);
}
// public method to switch avatars by pressing the UI button
public void SwitchAvatar()
{
// processing whichAvatarIsOn variable
switch (whichAvatarIsOn)
{
// if the first avatar is on
case 1:
// then the second avatar is on now
whichAvatarIsOn = 2;
// disable the first one and enable the second one
avatar1.gameObject.SetActive(false);
avatar2.gameObject.SetActive(true);
break;
// if the second avatar is on
case 2:
// then the first avatar is on now
whichAvatarIsOn = 1;
// disable the second one and enable the first one
avatar1.gameObject.SetActive(true);
avatar2.gameObject.SetActive(false);
break;
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.LeftAlt))
{
SwitchAvatar();
}
}
}
`
`
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using UnityEngine;
public class Trigger : MonoBehaviour
{
public SwitchCharacterScript player;
[SerializeField] private bool triggerActive = false;
public GameObject GameObject;
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
triggerActive = true;
}
}
void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.tag == "Player")
{
triggerActive = false;
}
}
private void Update()
{
if (triggerActive && Input.GetKeyDown(KeyCode.E))
{
SomeCoolAction();
}
}
public void SomeCoolAction()
{
}
}
`
In the somecoolaction is where I don't know what to do to be able to switch them; if you could not tell, I am new at this both coding and using StackOverflow.
I could not find anything on how to do something similar, or I did not know what to search for and could not find if anyone had a way to do it or a video or something.
Instead of bools I would rather store the actual reference:
public class Trigger : MonoBehaviour
{
private SwitchCharacterScript player;
void OnTriggerEnter2D(Collider2D other)
{
if (other.TryGetComponent<SwitchCharacterScript>(out var switchCharacer))
{
player = switcCharacter;
}
}
void OnTriggerExit2D(Collider2D other)
{
if (player.gameObject == other.gameObject)
{
player = null;
}
}
private void Update()
{
if (player && Input.GetKeyDown(KeyCode.E))
{
player.SwitchAvatar();
}
}
}
In general to be a bit more dynamic I would rather use an array for the characters and do e.g.
public class SwitchCharacterScript : MonoBehaviour
{
// references to controlled game objects
public GameObject[] avatars;
// variable contains which avatar is on and active
private int whichAvatarIsOn = -1;
// Use this for initialization
private void Start()
{
foreach(var avatar in avatars)
{
avatar.SetActive(false);
}
SwitchAvatar();
}
// public method to switch avatars by pressing the UI button
public void SwitchAvatar()
{
if(whichAvatarIsOn > 0 && whichAvatarIsOn < avatars.Length)
{
avatars[whichAvatarIsOn].SetActive(false);
}
whichAvatarIsOn = (whichAvatarIsOn + 1) % avatars.Length;
avatars[whichAvatarIsOn].SetActive(true);
}
}
Related
So I'm new to C# I somewhat know Python I couldn't understand how functions work I tried doing something like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisiondetectorleft : MonoBehaviour
{
public class Triggerdetecting()
{
public void OnTriggerStay(Collider other)
{
if (other.attachedRigidbody)
other.attachedRigidbody.AddForce((Vector3.up * 10);
}
}
void FixedUpdate()
{
if (Input.GetKeyDown("space"))
{
//I'm so lost
Triggerdetecting objTriggerdetecting = new Triggerdetecting();
}
}
}
I'm trying to create some sort of hitbox by detecting trigger if a button pressed and meets the condition make the object more faster. I tried few ways to call function non of them worked. Thank you for your time. If you unable to understand what I meant you can ask me I'll try to explain in other ways.
Want something like this:
def detection():
if OnTriggerStay == True:
moveobject up
if Input.GetKeyDown("space")) == True:
detection()
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class collisiondetectorleft : MonoBehaviour
{
//create bool to set it true or false while inside the object
private bool _canHit;
private void Update()
{
if (_canHit)
{
if (Input.GetKeyDown(KeyCode.A))
{
_canHit = false;
//task
}
}
}
//set _canHit true if object enters trigger
private void OnTriggerEnter(Collider other)
{
if (other.attachedRigidbody)
_canHit = true;
}
//set _canHit false if object exits trigger
private void OnTriggerExit(Collider other)
{
if (other.attachedRigidbody)
_canHit = false;
}
}
I was able to detect and log while true but I didn't figured how to react to object that triggers
I would go the same route as you did in your answer attempt.
The last bit missing in order to b able to actually use the according object is simple: Instead of a bool rather directly store the object
public class collisiondetectorleft : MonoBehaviour
{
private Collider _currenTarget;
private void Update()
{
if (_currenTarget && Input.GetKeyDown(KeyCode.A))
{
Debug.Log($"I am interacting with {_currentTarget}");
_currenTarget = null;
}
}
private void OnTriggerEnter(Collider other)
{
if (!other.attachedRigidbody) return;
_currenTarget = other;
}
private void OnTriggerExit(Collider other)
{
if (other != _currenTarget) return;
_currenTarget = null;
}
}
I'm trying to keep the player skin, even when reloading the scene, or moving on to a new one. The player object changes every scene.
The player skin is chosen in a pause menu, with three buttons. Each one of those buttons calls a function in the script below. I'm trying to call one of these functions, based on what value the PlayerPrefs int holds, and the function does get called; But throws the error MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it
Below is what i have already tried, but this throws an error on scene reload (death)
i don't know what i'm doing wrong here.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Pausemenu : MonoBehaviour
{
public static bool gameIsPaused = false;
public GameObject pauseMenuUI;
public Material BelgianMat;
public Material Ball2;
public Material Rainbow;
public GameObject Player;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Escape)) {
if (gameIsPaused) {
Resume();
} else {
Pause();
}
}
}
public void Resume(){
pauseMenuUI.SetActive(false);
Time.timeScale = 1f;
gameIsPaused = false;
}
void Pause() {
pauseMenuUI.SetActive(true);
Time.timeScale = 0f;
gameIsPaused = true;
}
public void LoadMenu() {
Time.timeScale = 1f;
gameIsPaused = false;
SceneManager.LoadScene("Menu");
}
public void QuitGame() {
Debug.Log("Quitting");
Application.Quit();
}
public void ApplyBelgian() {
Player.GetComponent<Renderer>().material = BelgianMat;
PlayerPrefs.SetInt("playerMat", 0);
}
public void ApplyBall2() {
Player.GetComponent<Renderer>().material = Ball2;
Debug.Log("Applied ball two");
PlayerPrefs.SetInt("playerMat", 1);
}
public void ApplyRainbow() {
Player.GetComponent<Renderer>().material = Rainbow;
PlayerPrefs.SetInt("playerMat", 2);
}
void OnEnable()
{
Debug.Log("OnEnable called");
SceneManager.sceneLoaded += OnSceneLoaded;
}
// called second
void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
Debug.Log("OnSceneLoaded: " + scene.name);
Debug.Log(mode);
if (PlayerPrefs.GetInt("playerMat") == 0) {
ApplyBelgian();
}
else if (PlayerPrefs.GetInt("playerMat") == 1) {
Debug.Log("gonna apply ball 2");
ApplyBall2();
}
else if (PlayerPrefs.GetInt("playerMat") == 2) {
ApplyRainbow();
}
}
}
I don't know why but it seems like the reference to the Player object may be broken after loading the scene. If this is the case, add a "Player" tag to your Player object and add this to the OnEnable function: Player = GameObject.FindWithTag("Player");
This is my code. I think it is this script.
I have no idea where the error is, but I think it is in OnTriggerEnter2d in the second if statement.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Pickup : MonoBehaviour
{
private InventoryTest inventory;
public GameObject itembutton;
// Start is called before the first frame update
void Start()
{
inventory = GameObject.FindGameObjectWithTag("Player").GetComponent<InventoryTest>();
}
void OnTriggerEnter2D(Collider2D other)
{
if(other.CompareTag("Player")) {
for (int i = 0; i < inventory.slots.Length; i++) {
if (inventory.isfull[i] == false) {
inventory.isfull[i] = true;
Instantiate(itembutton, inventory.slots[i].transform, false);
Destroy(gameObject);
break;
}
}
}
}
// Update is called once per frame
void Update()
{
}
}
I have several gameobjects: each have an "Interactable" and "Data" class. I also have a "PauseGameController" class not attached to those gameobjects in which I want to use the data for each object dynamically if an event is triggered when the Key I is pressed AND the variable "isInteracting" from the "Interactable" class is true. In other words , the "PauseGameController" class does not know which gameobject data will be using until this 2 events happend for one specific object
My question is:
How can I retrieve the data dynamically that I typed on the inspector in the class "Data" for each gameobject from another script not attached to this gameobject?
I want to re-use the "data" and "interactable" class and be able to set different data to different gameobjects as I am creating them in the scene. And I don't want to use the Finds functions because the documentation says that it's slow.
Code:
Interactables class
using UnityEngine;
using System.Collections;
public class Interactables : MonoBehaviour {
public static bool interactable = false;
public bool interactableown = false;
public Material[] material;
Renderer rend;
// Use this for initialization
void Start () {
rend = GetComponent<Renderer>();
rend.enabled = true;
rend.sharedMaterial = material[0];
}
// Update is called once per frame
void Update () {
if (interactableown)
{
rend.sharedMaterial = material[1];
}else
{
rend.sharedMaterial = material[0];
}
}
void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "Player")
{
interactable = true;
interactableown = true;
}
}
void OnTriggerExit(Collider other)
{
if (other.gameObject.tag == "Player")
{
interactable = false;
interactableown = false;
}
}
}
Pause Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Puase : MonoBehaviour {
public static bool isPause = false;
public GameObject MenuUI;
public Text txt;
// Update is called once per frame
void Update () {
if (Input.GetKeyUp(KeyCode.I) && Interactables.interactable)
{
if (isPause)
{
Resume();
}
else
{
Pause();
}
}
}
public void Resume()
{
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
MenuUI.SetActive(false);
Time.timeScale = 1f;
isPause = false;
}
public void Pause()
{
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
MenuUI.SetActive(true);
Time.timeScale = 0f;
isPause = true;
}
}
Data Class
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class DataObj : MonoBehaviour {
public string info = "";
void Start () {
}
// Update is called once per frame
void Update () {
}
}
Capture of the editor
Capture
I am working on 2D game.
When player collides with BOMBPrefab lose 1 heart (initial 3 heart), if collides 3 times = GameOver.
Thats is the code (works fine for BombPrefab):
using UnityEngine;
using System.Collections;
public class Heart : MonoBehaviour {
public Texture2D[] initialHeart;
private int heart;
private int many;
// Use this for initialization
void Start () {
GetComponent<GUITexture>().texture = initialHeart[0];
heart = initialHeart.Length;
}
// Update is called once per frame
void Update () {}
public bool TakeHeart()
{
if (heart < 0) {
return false;
}
if (many < (heart - 1)) {
many += 1;
GetComponent<GUITexture> ().texture = initialHeart [many];
return true;
} else {
return false;
}
}
}
I have a second HeartPrefab, I want to check when player collides... IF I have 3 hearts do nothing, IF have 1 or 2 hearts ADD extra heart.
BombPrefab Scrip:
using UnityEngine;
using System.Collections;
public class Bomb : MonoBehaviour
{
public AudioClip clipBomba;
private Heart heart;
private Gerenciador gerenciador;
void Awake ()
{
}
// Use this for initialization
void Start ()
{
gerenciador = FindObjectOfType (typeof(Gerenciador)) as Gerenciador;
}
// Update is called once per frame
void Update ()
{
}
void OnCollisionEnter2D (Collision2D colisor)
{
if (colisor.gameObject.tag == "floor") {
Destroy (gameObject, 2f);
} else {
if (colisor.gameObject.tag == "Bee") {
Som();
heart= GameObject.FindGameObjectWithTag ("Heart").GetComponent<Vidas> () as Vidas;
if (heart.TakeHeart ()) {
Destroy (gameObject);
} else {
gerenciador.GameOver ("GameOver");
}
}
}
}
void Som()
{
GetComponent<AudioSource> ().clip = clipBomb;
AudioSource.PlayClipAtPoint (clipBomb, transform.position);
}
}
First of all try not use GetComponent<>() in update and functions that are run often. It is better to cache components in Start() method. Using FindGameObjectWith...() is also not very efficient.
I would make it differently, each heart as a separate UI element (Toggle), with two states active and inactive. Then your player should have a list of those hearts and methods that allow to take damage and gain life.
int currentHeartsCount = 3;
int maxHeartsCount = 3;
List<Heart> hearts = new List<Heart>();
public void TakeDamage(int damage) {
ChangeHearts(-damage);
}
public void GainLife(int life) {
ChangeHearts(life);
}
private void ChangeHearts(int amount) {
currentHeartsCount += amount;
if(currentHeartsCount> maxHeartsCount)
currentHeartsCount = maxHeartsCount;
if(currentHeartsCount<=0) {
// call player dead code
}
int i = 1;
foreach(Heart heart in hearts) {
heart.SetHeartActive(i<=currentHeartsCount);
i++;
}
}
This is a simplified solution to give you an idea. It is more robust than yours because you can easily change start heart count, and make things like heart "overcharge". Just add base hearts, set max to desired value, and now you can create some special power ups which increase hearts over the initial limit.