_Q12_ Ответов: 1

Гигель не нападает на жизнь деревьев


        Sprite gigel = new Sprite(WindowsFormsApplication2.Properties.Resources.Gigel_img);
        Sprite tree = new Sprite(WindowsFormsApplication2.Properties.Resources.tree_img);

        void Screen_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.E)
            {
                gigel.Atack(tree.life);
                tree.LifeUpdate();
            }
            gigel.Reposition();
            Refresh();
        }

...
inside Sprite class 
        public void Atack(int targetLife)
        {
            targetLife -= damage;
        }



"targetLife" сокращает свой "урон"
но не передает значение дереву.жизнь от "гигеля.Атак(древо жизни);"
дерево.жизнь не получает ценности от процесса ! Почему? Или что я делаю не так?
Спасибо.

Что я уже пробовал:

//I hope now is more clear: 

            if (e.KeyCode == Keys.E)
            {
                int num = 20;
                gigel.Atack(num);
                tree.life = num; // num is 20 and not 7

                tree.LifeUpdate();
            }
...
inside Sprite class 
        public void Atack(int targetLife) //targetLife = 20
        {
            targetLife -= damage; // 20-13 targetLife=7
            //from this point (num) must take targetLife value of 7
            //but (num) remains at 20.
        }

Gerry Schmitz

Вы не показали, что делает "LifeUpdate".

Кроме того, "Гигель", кажется, высасывает свою собственную жизнь.

_Q12_

1 - дерево.жизнь не обновляется, поэтому другие классы (LifeUpdate) после этого не имеют значения.
2 - не совсем... это единственный класс под названием [Sprite], из которого я создал 2 объекта - gigel и tree. Эти 2 объекта имеют один и тот же базовый класс, из которого они происходят. Но, похоже, что-то не так работает.

Eric Lynch

У меня возникли некоторые проблемы с пониманием вашего вопроса. Я предполагаю, что вы спрашиваете, почему tree.life, который передается в качестве параметра, не обновляется при вызове Attack.

Если это так, то это происходит потому, что тип данных int является типом значения. Это означает, что когда вы передаете его в качестве параметра, вы передаете копию значения (если только вы не укажете ключевое слово ref или out). Когда вы уменьшаете targetlife, вы уменьшаете копию. Поскольку вы ничего не делаете с этой копией, ее значение отбрасывается после того, как она выходит из области видимости.

Предполагая, что "жизнь" - это свойство дерева, это создает дополнительные трудности. Вы не можете просто передать свойства по ссылке (с ключевым словом ref/out).

Итак, у вас есть несколько возможных вариантов. Выставьте свойство "урон" от спрайта, а затем: дерево.жизнь -= Гигель.Ущерб.

Или измените сигнатуру метода атаки: public int Attack(targetlife) { return targetlife - damage; }, а затем: tree.жизнь = Гигель.Атака(древо жизни).

_Q12_

Я обновил раздел " Что я пробовал:" с более четким примером того, что я пробовал, кроме оригинального поста.

Eric Lynch

Прочитайте комментарий немного более внимательно. Это имеет точно такую же проблему. Когда вы передаете "num" в "Attack", вы передаете копию значения. Именно так работают типы значений (например, int). Затем вы увеличиваете "targetlife" (который является копией, а не оригиналом). После этого вы вернетесь. Поскольку "targetlife" выходит за рамки, когда вы возвращаетесь, он перестает существовать.

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

Например, если у Спрайта есть как жизнь, так и урон, вы можете сделать следующее:

атака общественного недействительными(Спрайт мишени)
{
цель.жизнь -= урон;
}

Гигель.Атака(дерево);

Чтобы лучше понять разницу между типами значений (int, struct и т. д.) и ссылочными типами (class), вы можете прочитать здесь:

http://www.albahari.com/valuevsreftypes.aspx

_Q12_

Мой дорогой @Eric-Lynch, ты гений!
Это сработало, как вы подслащивали ! Я не смог бы увидеть его без твоей помощи.
Большое вам спасибо и не забудьте сделать это в качестве решения, чтобы дать вам всю заслугу. Вы, конечно, заслужили это.

Eric Lynch

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

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

CHill60

Я пытался понять, как "ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" говорит нам, что вы сделали! Этот раздел предназначен для вашего кода, а тело вопроса-это то, где вы объясняете свою проблему

_Q12_

Я обновил раздел " Что я пробовал:" с более четким примером того, что я пробовал, кроме оригинального поста.

CHill60

Спасибо - я вижу, что вы тоже выиграли, так как @Eric-Lynch опубликовал отличный ответ :-)

1 Ответов

Рейтинг:
12

Eric Lynch

Итак, вот основная проблема: тип значения в сравнении с эталонным типом. Для получения более подробной информации читайте:

Значение против ссылочных типов в C#[^]

Когда вы передаете тип значения (например, int) любить num или tree.life в качестве параметра, передается копировать именно такой ценности. В вашем методе (Attack), то вы затем уменьшаете копировать о ценности (targetlife), нет оригинал. Когда вы вернетесь из Attack метод, который копирует (targetlife) выходит за рамки и отбрасывается.

В современных версиях C# можно передать тип значения по ссылке, используя ref или out ключевое слово. Дополнительные сведения см. по следующим ссылкам:

номер модели / ref (Справочник по c#) | Майкрософт документы[^]
параметры-модификаторы (Справочник по c#) | Майкрософт документы[^]

Однако в вашем случае могут возникнуть дополнительные соображения. Хотя исходный код не является общим, я подозреваю, что life может быть, это собственность. К сожалению, в настоящее время невозможно передать собственность с помощью ref/out ключевое слово.

Итак, я бы подумал о том, чтобы немного смоделировать ваш Sprite класс, который является общим для обоих gigel и tree В вашем коде, похоже, что gigel нападает tree, таким образом, сигнатура метода для Attack вероятно, это действие должно было бы больше походить на настоящее.

Я бы посоветовал вам изменить сигнатуру метода Attack следующим образом:

public void Attack(Sprite target) =>
  target.life -= damage;
Затем, чтобы иметь gigel атаковать tree, вы бы сделали следующее:
gigel.Attack(tree);


_Q12_

Потрясающий ответ ! Большое спасибо. Это решило мою проблему! Я действительно даже не думал о ценностно-референтных типах. Я действительно читал ваш рекомендуемый учебник по этому предмету. Из него я получаю, что классы являются ссылочными, а структура-типом значения. После этого он попадает в сборщик мусора и более продвинутые вещи, но идея у меня есть. Очень интересно о классе Dispose (), что я нахожу его почти везде в c#; это-ручная очистка оперативной памяти (особенно для файлов) . Эту информацию я тоже нахожу очень хорошей. Я должен использовать его чаще.
Мой Гигель теперь может с удовольствием рубить деревья.