O TEMA DO FÓRUM ESTÁ EM MANUTENÇÃO. FEEDBACKS AQUI: ACESSAR

[Unity] Como pegar variavel de outro script?

Iniciado por Aurora, 17/05/2018 às 15:57

17/05/2018 às 15:57 Última edição: 18/05/2018 às 07:36 por Corvo
Olá pessoal

Eu tenho uma variavel chamada ID dentro de um script que controla arrays, porém preciso dessa variavel para colocar em outro script, mas não to achando como fazer isso de modo que funcione.

A variável é pública/global? Só isso deve resolver, embora não muito recomendável. Por exemplo:
public int = 10;

Você também pode acessar com:
NomedaClasse.NomedaVariável

17/05/2018 às 16:52 #2 Última edição: 17/05/2018 às 17:08 por Ellye
Tem alguns casos de uso diferentes, com soluções diferentes. Vou dar alguns exemplos de como ando fazendo.




É uma classe estatica? Nesse caso dá para acessar diretamente as variaveis e metodos publicos, por exemplo:

Tenho essa classe estatica, uso ela para guardar algumas constantes e para metodos com algumas formulas globais a serem usadas em outras classes:
public static class Formulas  {
    public const float ATB_full = 50000.0f;
    public const float weak_multiplier = 0.60f;
    public const float strong_multiplier = 1.667f;

    public static float Attack_Basic(float skill_power, int level, int atk, int def, SpiritElement attack_element, SpiritElement defender_element) {
        float sp = SkillPower_Scale(skill_power, level);
        return sp * ((float)atk / (1 + (float)def / 100.0f)) * Elemental_Damage_Multiplier(attack_element, defender_element);
    }

//[...]
}


Exemplo de acesso à variável dela, em outra classe:

    private bool IsFullATB(Actor a) {
        return (a.ATB >= Formulas.ATB_full && !a.IsCasting);
    }


Notando que como Formulas é uma classe static e ATB_Full é uma variavel static, eu não preciso (e nem posso) instanciar a classe Formulas. Eu simplesmente chamo direto a variável que é membro da classe.

Exemplo de acesso a um método dessa classe static:

    public bool OnFinishCast(BattleScene battleScene) {
        Actor attacker = battleScene.ActiveActor;
        Actor defender = attacker.ActionTarget;
        int damage = (int) Formulas.Attack_Basic(DisplayedPower, attacker.Level, attacker.Attack, defender.Defense, SpiritElement.None, defender.Element);
        defender.damage(damage);
        attacker.finishCast();
        return true;
    }
Novamente, como a classe é estatica, eu devo chamar o metodo estatico Attack_Basic diretamente pela classe, sem criar uma instancia.




Agora, vamos supor que a sua váriavel está em um MonoBehaviour (componente), e você quer chamar ela de outro componente. Nesse caso, você precisa encontrar o componente com GetComponent<T> para pegar a instancia da classe.

Exemplo, tenho esse componente:

public class WorldSpriteAnimation : MonoBehaviour {
    public bool isMoving = false;
    public Vector2 facingDir = new Vector2(0.5f, 0.5f);
    //[...]
}


E preciso acessar essa bool em outro script:

public class WorldScene : MonoBehaviour {
    //[...]
    void OnEnable() {
        inputAllowed = true;
        cameraInputAllowed = true;
        camera_y_offset = 0.0f;
        player = GameObject.FindGameObjectWithTag("Player");
    }
    //[...]
    private void PlayerMovementInput() {
        float horizontalInput = Input.GetAxisRaw("Horizontal") * Time.deltaTime;
        float verticalInput = Input.GetAxisRaw("Vertical") * Time.deltaTime;
        if (horizontalInput != 0.0f || verticalInput != 0.0f) {
            player.GetComponent<WorldSpriteAnimation>().isMoving = true;
            Vector3 prevPos = player.transform.position;
            Vector3 forwardMotion = Camera.main.transform.forward * verticalInput;
            Vector3 rightMotion = Camera.main.transform.right * horizontalInput;
            Vector3 movement = (forwardMotion + rightMotion);
            movement.y = 0.0f;
            movement = movement.normalized * playerSpeed;
            player.GetComponent<CharacterController>().Move(movement);
            player.transform.position = new Vector3(player.transform.position.x, prevPos.y, player.transform.position.z);
            Vector3 newPos = player.transform.position;
            Camera.main.transform.position = Camera.main.transform.position + (newPos - prevPos);
            player.GetComponent<WorldSpriteAnimation>().facingDir = new Vector2(movement.normalized.x, movement.normalized.z);
        } else {
            player.GetComponent<WorldSpriteAnimation>().isMoving = false;
        }
    }
}
Indo por partes:

Como, nesse caso, os componentes não estão no mesmo GameObject no Unity, eu primeiro preciso encontrar o GameObject que tem o componente que eu quero. No caso, isso foi feito com GameObject.FindGameObjectWithTag, mas existem outros metodos de Find e afins. Caso o componente esteja no mesmo objeto, isso é desnecessario, já que você tem uma referencia implicita ao proprio objeto que está chamando os scripts.
Após ter a referencia ao gameobject que carrega o outro componente, eu consigo acessar o componente com GetComponent<T>, e a partir daí posso acessar todas variáveis e metodos públicos daquela instancia do script.




Por último, no caso de scripts que não são estáticos e não são componentes, você pode seguir o fluxo normal de um programa c# mesmo; basta instanciar eles com "new" (referenciar uma instancia já criada, se for o caso), e você tem acesso a tudo. Exemplo:

public class Actor {
    //[...]
    public Sprite Sprite { get; protected set; }
    //[...]
}


public class GameController : MonoBehaviour {
//[...]
    public void NewGame() {
        Party = new PlayerParty();
        Party.add(new PlayerActor(ActorDataLoader.Data[0], 1));
    }
//[...]


public class BattleScene : MonoBehaviour {
    //[...]
    private void displayPlayerParty() {
        for (int i = 0; i < playerParty.Length; i++) {
            Transform window = battleUI.transform.Find("Window - Player Party");
            Transform unitFrame = window.transform.Find("Actor" + i);
            PlayerUnitFrame uf = unitFrame.GetComponent<PlayerUnitFrame>();
            uf.Actor = playerParty[i];
        }
    }
    //[...]
}


public class PlayerUnitFrame : MonoBehaviour {
    //[...]
    public void OnGUI() {
        if (this.Actor == null) {
            return;
        }
        actorName.GetComponent<Text>().text = "Lv." + Actor.Level + " " + Actor.Name;
        spriteUI.GetComponent<Image>().sprite = Actor.Sprite;
        hpTextUI.GetComponent<Text>().text = Actor.getHP()[0] + "/" + Actor.getHP()[1];
        hpBarUI.GetComponent<DuloGames.UI.UIProgressBar>().fillAmount = (float)Actor.getHP()[0] / (float)Actor.getHP()[1];
        spTextUI.GetComponent<Text>().text = Actor.getSP()[0] + "/" + Actor.getSP()[1];
        spBarUI.GetComponent<DuloGames.UI.UIProgressBar>().fillAmount = (float)Actor.getSP()[0] / (float)Actor.getSP()[1];
        //[...]
    }
}


Exemplo um pouco mais complexo, mostrando como as vezes uma instancia fica indo sendo jogada pra lá e pra cá. O GameController cria uma instancia da classe Actor ao iniciar um novo jogo, e outras instancias dessa classe seriam guardadas em geral também nessa array Party. A BattleScene tem uma referencia para essa party (feita através do metodo que foi mostrado em um exemplo anterior, com GetComponent e tal), e faz uma iteração nela para repassar as instancias de Actor para o componente PlayerUnitFrame. Por fim, o componente PlayerUnitFrame acessa os dados dessa instancia da classe Actor para mostrar na tela o sprite, nome, HP, SP, etc.

O segundo metodo da Ellye resolveu meu problema. Valeu mesmo os dois e principalmente Ellye por explicar tudo direitinho.