Класс и объекты Unity C#

Хорошо, прошу прощения, что это будет довольно глупый вопрос, но я пытаюсь получить полное представление о назначении и использовании объектов. В частности, я работаю в Unity, но не уверен, что это имеет значение. Также я должен отметить, что язык довольно обширный. Но вот простой пример, над которым я работаю.

public class Player : MonoBehaviour 
{
    private string name = "Players Name";

    private void Start () {
        var nexus = new Player();
    }

    public static void Using() {
        // how are these different?
        Attack();
        this.Attack();
    }

    public static void Move() {
        print ("The player is moving"); 
    }

    private void Attack () {
        print ("The player is attacking"); 
    }
}

public class UsingStuff : MonoBehaviour 
{
    private void Start () {
        Player.Move();
    }
}

Итак, вот вопросы:

  1. В чем разница между вызовом функции Attack () и this.Attack? С точки зрения новичка, они, казалось бы, делают то же самое. Однако я предполагаю, что мой пример слишком упрощен.
  2. Я создал объект класса Player со случайным именем nexus. Однако, когда я вызываю функцию из другого класса, я, кажется, использую имя класса, а не это имя переменной. Итак, какова цель создания имени переменной?

Я пока оставлю это на этих двоих, так как, надеюсь, это поможет с некоторой путаницей для некоторых других вещей. Спасибо за помощь.

1) В этом случае разницы нет. 2) Вам необходимо фундаментальное понимание переменных, свойств и области действия. У вас должен быть член класса Player, экземпляр которого вы создаете в Start(). Вместо этого вы создаете проигрыватель, а затем выбрасываете его, потому что он выходит за рамки, когда возвращается Start().

itsme86 08.08.2018 23:42

Для № 2 посмотрите на C# статические методы и методы экземпляра, чтобы узнать, почему иногда вам нужен экземпляр класса (имя переменной) для вызова метода, а в других случаях вы просто используете имя класса (для статических методов).

Rufus L 08.08.2018 23:48

У вас должна быть функция Update, если она не используется, хуже по производительности. Кроме того, вы не должны включать его в сообщение о переполнении стека, поскольку оно не связано с вашей проблемой.

AustinWBryan 09.08.2018 07:07

Я предлагаю вам потратить немало времени на самостоятельное изучение C# и основных концепций программирования, прежде чем пытаться создать игру. Мне потребовалось довольно много времени, прежде чем я наконец был готов к игре. Прямо сейчас вы учитесь очень сложным вещам одновременно, и это мешает вам изучать обе вещи.

AustinWBryan 09.08.2018 07:12
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
2 392
8

Ответы 8

Когда вы запускаете Player nexus = new Player();, вы создаете новый экземпляр (/ object) типа (/ class) «Player». Переменная nexus является ссылкой на объект (т. Е. Ссылается на только что созданный вами экземпляр объекта). Когда у вас есть экземпляр, вы можете вызывать методы экземпляра для этого объекта, устанавливать или читать его свойства (которых, кстати, у вас нет). Поскольку существует только одна ссылка на этот объект (переменная nexus), когда эта ссылка выходит за пределы области видимости (в конце функции), объект больше не ссылается на что-либо и имеет право на сборку мусора.

Когда вы объявляете метод (/ функцию) с ключевым словом static, вы создаете его на уровне класса, а не на уровне экземпляра. Если вы хотите вызвать нестатические методы Update или Attack, вам нужно будет сказать nexus.Update или nexus.Attack. Чтобы вызвать статические методы Using или Move, вы должны использовать имя класса (Player), например: Player.Using или Player.Move.

Опубликованный вами код не компилируется, не так ли? Вы не можете вызвать метод экземпляра из статического метода. Вы не можете вызвать метод экземпляра Attack или this.Attack из статического метода Using (там нет «this» (this - это текущий экземпляр объекта, связанный с методом экземпляра)). Лучше всего опубликовать код, который хотя бы компилирует (если вы не скажете (в комментарии) //this is the code that doesn't compile

Вы также создаете новый экземпляр Player только в методе Start, что немного странно. Как правило, вы создаете экземпляры объектов в других классах или в статических методах фабрика (не всегда, но обычно).

Прочтите о природе объектно-ориентированного программирования, о ключевом слове C# static и о природе экземпляров объектов (в целом). Вы, вероятно, захотите также ознакомиться со свойствами C#.

Да, и наименование чего-то Using в конечном итоге повредит (нижний регистр using - это ключевое слово C#, которое уже имеет два значения).

Наконец, чтобы ответить на ваш вопрос, «вызов метода экземпляра таким способом: Attack() или другим способом: this.Attack() имеет ту же семантику». Конечно, как отмечалось выше, вы не можете использовать любую форму, если пытаетесь вызвать метод экземпляра из статического метода.

  1. Ключевое слово this означает «ссылку на текущий экземпляр класса». Это действительно синтаксический сахар (он может сделать ваш код более понятным для чтения).

Когда ты делаешь

public static void Using() {
    Attack();
    this.Attack();
}

За кулисами компилятор выполнит это так:

public static void Using() {
    this.Attack();
    this.Attack();
}

так что в вашем контексте они такие же.

Иногда бывает полезно см. эта почта

  1. Если я правильно понимаю, этот вопрос относится к тому, почему вам нужно иметь переменную с именем name, а не просто называть объект как игрок название. Переменная «имя» и имя объекта - это разные вещи.

Допустим, вы хотите вывести имя игрока на экран.

void Start () {
    Player nexus = new Player();

}

в методе выше я не могу [просто] сделать это

void Start () {
    Player p = new Player();
    p.name = "nexus";
    Console.WriteLine(p);
}

Здесь же я вывожу значение переменной с именем name. Переменные - это в основном поле с именем на (имя), которое содержит значения (нексус).

Я предлагаю вам взглянуть на базовые руководства по программированию, прежде чем заняться Unity

Обратите внимание, что код в функции Using не будет компилироваться, потому что это функция static, в то время как Attack не является функцией static. Вы не могу вызываете функцию, отличную от static, из функции static.

Programmer 09.08.2018 00:03

И этот первый образец кода (вызов метода экземпляра Attack из статического метода Using) не будет компилироваться. Два примера метода Start тоже немного странные. Как отметил @ itsme86, первый создает новый объект Player, но, поскольку ссылка немедленно выходит за пределы области видимости, этот объект навсегда теряется и имеет право на «сборку мусора». Второй пример будет работать только в том случае, если класс Player имеет общедоступное строковое свойство с именем name (которое, по соглашению, действительно должно начинаться с заглавной буквы). Вызов WriteLine полагается на то, что Player имеет метод ToString отвергать

Flydog57 09.08.2018 00:03

NB, просто цитирую код OP для объяснения. Оставили без внимания комментарии по поводу качества кода и других факторов, выходящих за рамки вопроса.

SEarle1986 09.08.2018 00:17

What is the difference between calling a function Attack() versus this.Attack?

Например, когда вы кодируете класс Player и хотите использовать метод «Attack ()», вы можете сделать это, набрав Attack () или this.Attack (). В обоих случаях происходит одно и то же.

Когда вы используете «это». вы гарантируете, что используемый вами метод реализован в классе, в котором вы находитесь. Например:

public void GroupAttack(DifferentPlayer ally){
    Attack(); 
    ally.Attack();
}

public void GroupAttackWithThis(DifferentPlayer ally){
    this.Attack(); 
    ally.Attack();
}

Нет никакой разницы между методом GroupAttack и GroupAttackWithThis.

Полезная ссылка, чтобы увидеть разницу: В чем разница между this.method () и method () в Java?

I created the object of the Player class with the random name nexus. However, when I call a function from a different class I seem to use the class name rather than this variable name. So what is the purpose of creating a variable name?

Это происходит потому, что вы сделали функцию «Перемещение» статической, это означает, что для каждого экземпляра этого класса она будет делать то же самое. Статический используется, когда вы хотите, чтобы метод или переменная имели одно и то же значение или имели одинаковое поведение каждый раз для каждого экземпляра класса. Если ваш метод не является статическим, вам нужно будет использовать имя переменной для его использования, потому что вы хотите, чтобы ваш метод изменял свое поведение для каждого экземпляра. Простой пример:

public string GetName(){
    return name;
}

Этот метод вернет для каждого игрока другое имя (вернет имя игрока в переменной). Итак, если вы это сделаете:

Player jhon = new Player();
jhon.name = "Jhon";
String jhonsName = jhon.GetName();

Переменная «jhonsName» будет содержать строку со значением «Jhon».

Я надеюсь, что это может быть полезно для вас и удачи в вашей игре.

Между Unitys MonoBehaviour и обычными классами C# есть некоторые отличия. Я рекомендую посмотреть несколько уроков по Unity. Скрипты Unity ориентированы на сцены.

  1. Нет никакой разницы. это. что-то можно использовать, чтобы пометить что-либо как «из объекта класса» (обычно свойства или переменные), чтобы отличать от параметров.

  2. Запись Связь игрока = новый игрок (); должна быть предупреждением, потому что вы не должны делать этого с MonoBehaviour.

Вы создаете игрока в сцене, помещая скрипт «Player» в GameObject. Вы должны получить доступ к сценарию Player из GameObject. Поэтому вам следует убрать "статику" в методах. Затем поместите общедоступный игрок Player; внутрь UsingStuff (в открытом классе UsingStuff: MonoBehaviour {). Затем перетащите свой Player на заполнитель для Player. Вы найдете его в GameObject с использованием сценария UsingStuff в сцене. Теперь вы можете вызвать player.Move () (с маленькой p) в методе запуска.

Попробуйте другое имя для вашей переменной название. Он уже существует для каждого MonoBehaviour. Это относится к имени GameObject, на котором лежит скрипт. Ваше именование также должно вызывать предупреждение.

Хорошо, поэтому прежде всего спасибо всем за то, что указали на разные детали. Я думаю, что у меня все в голове. Теперь у меня есть рабочий пример:

public class Player : MonoBehaviour {

    public string name;
    public int power;
    public int speed;

    public void gameData() {
        print ("Player name = " + name);
        print ("Player power = " + power);
        print ("Player speed = " + speed);   
    }
    private void Attack () { }
}
...

public class UsingStuff : MonoBehaviour {

var P1 = new Player();
var P2 = new Player();
var P3 = new Player();

private void Start () {
    P1.name  = "Bill";
    P1.power = 10;
    P1.speed = 30;

    P2.name  = "Bob";
    P2.power = 100;
    P2.speed = 3;

    P3.name  = "Jerry";
    P3.power = 50;
    P3.speed = 10;

    P1.gameData();
    P2.gameData();
    P3.gameData();
}

Однако, хотя программа работает, я получаю предупреждение, относящееся к использованию Unity и MonoDevelop, так что это совсем другая проблема. Спасибо за вашу помощь.

Этот сайт не похож на форумы. Вы не должны публиковать ответы как ответы. Вы можете использовать комментарии или открыть новый вопрос.

Nikaas 09.08.2018 08:45

Согласен, вероятно, лучше всего добавить и отредактировать внизу исходного сообщения, потому что это будет пропущено, поскольку оно классифицируется как ответ

SEarle1986 09.08.2018 11:48

Помимо других ответов, вы также можете использовать this для устранения неоднозначности. Типичный пример:

public MyType(this name) => this.name = name;

Или использовать методы расширения:

public static void MyCustomExtensionMethod(this Foo foo) { }
...
public class Bar() : Foo
{
   // I did not create Foo and do not have access to Foo
   this.MyCustomExtensionMethod();
}

Я не могу комментировать, поэтому отвечу на ваш второй пост так:

Первый случай:

Если вы ненужен игрок как скрипт, связанный с функциями GameObject и Unity, такими как циклы обновления: удалите наследование (от MonoBehaviour), и он будет работать: public class Player { ... }

Второй более частый случай:

Если вам нужен Player как объект в сцене, который использует функции Unity оставить скрипт плеера как есть. Ошибка в использовании var P1 = новый игрок ();. Вы знаете, что нужно добавить свой скрипт к GameObject в Unity Scene? Чтобы понять, просмотрите несколько базовых руководств по Unity: https://unity3d.com/de/learn/tutorials/topics/interface-essentials/game-objects-and-components?playlist=17090

Это показывает, как управлять сценарием GameObject из другого сценария: https://unity3d.com/de/learn/tutorials/topics/scripting/activating-gameobjects?playlist=17117

Вы можете просто прочитать еще немного теории ООП, прежде чем погрузиться в код. Надеюсь, я могу дать несколько советов, которые помогут вам встать на правильный путь :)

Во-первых, вызов Attack () изнутри класса аналогичен this.Attack (). это просто немного более ясно, что вы говорите о текущем объекте, а не о какой-то другой функции, называемой Attack.

Ваш класс Player - это ваш шаблон того, что должно понравиться игроку. У вас не должно быть доступа к Player. потому что это доступ к вашему шаблону, а не к объекту игрока. НАПРИМЕР

Player.Something() //Accesses a function inside the Player class.

Вы редко будете делать что-то подобное, это более сложная идея. Они называются статическими свойствами / функциями и применяются к шаблону класса. Все ваши функции здесь статичны, а не должны быть :)

Итак, ваш класс - это ваш шаблон того, каким должен быть игрок, но как нам сделать из игрока объект?

public class UsingStuff : MonoBehaviour 
{
    private void Start () {
        Player myPlayer = new Player(); //Makes an object called myPlayer
        Player otherPlayer = new Player(); //Another player object
        //For functions
        myPlayer.Attack(); //myPlayer will attack
        otherPlayer.Move(); //otherPlayer.move
        //For variables
        myPlayer.name = "Dave";
        otherPlayer.name = "Emma";
        //Now both our players have different names
    }
}

Надеюсь, в этом есть немного больше смысла. Ваш класс - это ваш шаблон того, что игрок должен / уметь делать. Чтобы на самом деле использовать / создавать игроков, вы создаете из них объекты, а затем у каждого из них есть свои переменные. Например, если Ouch(){this.hp--);, то myPlayer.Ouch() приведет к потере 1 единицы здоровья myPlayer, но это не повлияет на otherPlayer.

Другие вопросы по теме