Хорошо, прошу прощения, что это будет довольно глупый вопрос, но я пытаюсь получить полное представление о назначении и использовании объектов. В частности, я работаю в 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();
}
}
Итак, вот вопросы:
Я пока оставлю это на этих двоих, так как, надеюсь, это поможет с некоторой путаницей для некоторых других вещей. Спасибо за помощь.
Для № 2 посмотрите на C# статические методы и методы экземпляра, чтобы узнать, почему иногда вам нужен экземпляр класса (имя переменной) для вызова метода, а в других случаях вы просто используете имя класса (для статических методов).
У вас должна быть функция Update, если она не используется, хуже по производительности. Кроме того, вы не должны включать его в сообщение о переполнении стека, поскольку оно не связано с вашей проблемой.
Я предлагаю вам потратить немало времени на самостоятельное изучение C# и основных концепций программирования, прежде чем пытаться создать игру. Мне потребовалось довольно много времени, прежде чем я наконец был готов к игре. Прямо сейчас вы учитесь очень сложным вещам одновременно, и это мешает вам изучать обе вещи.





Когда вы запускаете 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() имеет ту же семантику». Конечно, как отмечалось выше, вы не можете использовать любую форму, если пытаетесь вызвать метод экземпляра из статического метода.
this означает «ссылку на текущий экземпляр класса». Это действительно синтаксический сахар (он может сделать ваш код более понятным для чтения).Когда ты делаешь
public static void Using() {
Attack();
this.Attack();
}
За кулисами компилятор выполнит это так:
public static void Using() {
this.Attack();
this.Attack();
}
так что в вашем контексте они такие же.
Иногда бывает полезно см. эта почта
Допустим, вы хотите вывести имя игрока на экран.
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.
И этот первый образец кода (вызов метода экземпляра Attack из статического метода Using) не будет компилироваться. Два примера метода Start тоже немного странные. Как отметил @ itsme86, первый создает новый объект Player, но, поскольку ссылка немедленно выходит за пределы области видимости, этот объект навсегда теряется и имеет право на «сборку мусора». Второй пример будет работать только в том случае, если класс Player имеет общедоступное строковое свойство с именем name (которое, по соглашению, действительно должно начинаться с заглавной буквы). Вызов WriteLine полагается на то, что Player имеет метод ToString отвергать
NB, просто цитирую код OP для объяснения. Оставили без внимания комментарии по поводу качества кода и других факторов, выходящих за рамки вопроса.
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 ориентированы на сцены.
Нет никакой разницы. это. что-то можно использовать, чтобы пометить что-либо как «из объекта класса» (обычно свойства или переменные), чтобы отличать от параметров.
Запись Связь игрока = новый игрок (); должна быть предупреждением, потому что вы не должны делать этого с 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, так что это совсем другая проблема. Спасибо за вашу помощь.
Этот сайт не похож на форумы. Вы не должны публиковать ответы как ответы. Вы можете использовать комментарии или открыть новый вопрос.
Согласен, вероятно, лучше всего добавить и отредактировать внизу исходного сообщения, потому что это будет пропущено, поскольку оно классифицируется как ответ
Помимо других ответов, вы также можете использовать 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.
1) В этом случае разницы нет. 2) Вам необходимо фундаментальное понимание переменных, свойств и области действия. У вас должен быть член класса
Player, экземпляр которого вы создаете вStart(). Вместо этого вы создаете проигрыватель, а затем выбрасываете его, потому что он выходит за рамки, когда возвращаетсяStart().