Помните как мы бегали по горам и не придавали значение тому как быстро спускались или поднимались на них?
Как мы знаем в реальной жизни перемещаясь на плоскости горизонтальная скорость у нас постоянная.
Как только мы начинаем преодолевать горы и другие неровности то горизонтальная скорость у нас будет меньше.
Но не в мире Lineage 2 где горизонтальная скорость всегда постоянная и нее зависит от неровностей.
Связанно это с тем чтобы было проще синхронизировать персонажа на сервере и клиенте.
Ведь на сервере нет точной модели мира, а лишь примерное очертание называемое geodata.
А из-за того, что geodata приблизительно повторяет ландшафт клиента то было бы невозможно синхронизировать персонажа по Z оси.
Поэтому синхронизация идет только по X и Y оси.
Видео:
1) Горизонтальная скорость на плоскости постоянная.
2) Как было бы в жизни. Взбираясь на гору горизонтальная скорость падает.
3) Как сделано в игре. Горизонтальная скорость постоянная.
4) Демонстрация из игры. Бежит словно нет никаких гор.
Я разрабатываю эмулятор сервера для Lineage 2 Chronicle 1: Harbingers of war на Node.js.
Столкнулся с проблемой синхронизации скорости персонажа на сервере с клиентом. Когда в игре вы нажимаете мышкой в то место, куда хотите перейти то происходит плавный переход с анимацией движения. На сервере в этот момент тоже происходит движение по таймеру, но не такое плавное.
GIF
GIF
C(client) – двигается плавно из одной точки в другую. S(server) – делает прирост координат по таймеру.
Для примера я взял сборку написанную на java l2j-lisvus Сборок много. Но все они являются fork’ами проекта l2jserver https://l2jserver.com/ и многое наследуется. В том числе и передвижение персонажа.
В l2j-lisvus, как и во всех сборках l2jserver перемещение персонажа на сервере идет при помощи таймера с приростом одинаковых значений.
Проблема проявляется, когда нам надо сделать какое-то действие после того, как персонаж добежал до пункта назначения. Например, нанести удар по NPC.
GIF
На коротких расстояниях проблема незаметна. Нога наступает точно в монету.
GIF
На длинных расстояниях действие атака начинается раньше, чем персонаж добегает до цели.
GIF
А если выкрутить скорость на максимум (900) то проблема расхождения очевидна. Это связанно с тем, что помимо скорости бега есть скорость ходьбы.
Как работает передвижение персонажа на сервере.
За основу взяты базовые характеристики персонажа. Скорость бега 126.
126 — это количество внутренних unit’ов за секунду.
На данной схеме идет прирост координат персонажа каждые 1000мс на 126 unit’ов. Исходя из схемы выше пример кода для действий персонажем после достижения пункта назначения:
// Прироста координат нет. Просто считаем когда персонаж дойдет до конечных координат.
const distance = 1500;
const playerSpeed = 126;
const ticks = distance / playerSpeed; // 11.90
const time = ticks * 1000; // 11900mc
setTimeout(() => {
// действие персонажа после бега
}, time);
GIF
На коротких расстояниях.
GIF
На длинных расстояниях.
Расхождения на коротких расстояниях.
Расхождения на длинных расстояниях.
Зеленой зоной показана точка куда должна ступить нога персонажа если бы не было расхождений.
Рост скорости при развитии персонажа.
126 — это базовая скорость. И по мере развития персонажа будет расти и скорость передвижения. А значит расхождение будет больше. Но перед тем, как создать формулу надо подтвердить теорию, что скорость ходьбы влияет на расхождение.
Данные о характеристиках персонажа передаются от сервера к клиенту.
Выставляю значения walkSpeed: 126. Если скорость ходьбы будет равна скорости бега, то расхождения должны пропасть.
GIF
Нога персонажа достигает правильной конечной точки.
Персонаж синхронизирован и начинает атаку вовремя. Теперь надо понять, как скорость ходьбы влияет на расхождения между клиентом и сервером.
Сколько же персонаж успевает пройти перед тем, как начинает бежать?
Надо поймать момент когда ходьба переходит в бег. Для этого передадим в клиент данные, где скорость ходьбы будет больше скорости бега. Из-за этой разницы будет виден переход и можно будет рассчитать пройденное расстояние при ходьбе.
runSpeed: 10
walkSpeed: 600
GIF
Ходьба быстрее бега.
При скорости шага в 600 персонаж успевает пройти 250, прежде чем начинает бежать.
600 / 250 = 2.4
700 / 291 = 2.4
800 / 333 = 2.4
Из этого вывод, что персонаж перед тем, как начать бежать успевает пройти расстояние в 2.4 раза меньше, чем его скорость ходьбы.
Значит при скорости ходьбы 88 персонаж пройдет 36 unit’ов.
88 / 2.4 = 36
Первое деление — это начало движения (ходьба) а следующие деления — это бег.
У проекта появилась чёткая архитектура управления сущностями. Теперь NPC, игроки, питомцы и другие объекты взаимодействуют в мире через систему менеджеров — рассказываю, как это работает.
В игровом мире есть разные типы сущностей: NPC, игроки (Player), питомцы (Pet) и другие. Каждая из них имеет свои состояния (движение, атака, бездействие) и требует управления.
Основные сущности и их поведение
• NPC – управляет собой (перемещение, атака, idle).
• Player – управляется игроком (те же состояния: ходьба, атака и т. д.).
• Pet – похож на NPC, но принадлежит игроку.
Менеджеры и их задачи
1. NpcManager – создаёт NPC, реагирует в случае смерти NPC.
2. PlayersManager – отвечает за вход игроков в мир.
3. PetsManager – управляет питомцами (аналогично NPC, но с привязкой к игроку).
4. EntitiesManager – главный координатор:
o Управляет NpcManager и PlayersManager.
o Обрабатывает взаимодействия (например, если игрок подошёл к NPC, оба получают информацию друг о друге).
5. VisibilityManager– отвечает за видимость объектов:
o Определяет, кто кого видит.
o Периодически обновляет списки видимости для оптимизации.
6. MovingManager – обновляет позиции всех подвижных объектов в мире.
Я разрабатываю эмулятор сервера для Lineage 2 Chronicle 1: Harbingers of war на Node.js.
Столкнулся с проблемой синхронизации скорости персонажа на сервере с клиентом. Когда в игре вы нажимаете мышкой в то место, куда хотите перейти то происходит плавный переход с анимацией движения. На сервере в этот момент тоже происходит движение по таймеру, но не такое плавное.
GIF
GIF
C(client) – двигается плавно из одной точки в другую. S(server) – делает прирост координат по таймеру.
Для примера я взял сборку написанную на java l2j-lisvus Сборок много. Но все они являются fork’ами проекта l2jserver https://l2jserver.com/И многое наследуется. В том числе и передвижение персонажа.
В l2j-lisvus, как и во всех сборках l2jserver перемещение персонажа на сервере идет при помощи таймера с приростом одинаковых значений.
Проблема проявляется, когда нам надо сделать какое-то действие после того, как персонаж добежал до пункта назначения. Например, нанести удар по NPC.
GIF
На коротких расстояниях проблема незаметна. Нога наступает точно в монету.
GIF
На длинных расстояниях действие атака начинается раньше, чем персонаж добегает до цели.
GIF
А если выкрутить скорость на максимум (900) то проблема расхождения очевидна. Это связанно с тем, что помимо скорости бега есть скорость ходьбы.
Как работает передвижение персонажа на сервере.
За основу взяты базовые характеристики персонажа. Скорость бега 126.
126 — это количество внутренних unit’ов за секунду.
На данной схеме идет прирост координат персонажа каждые 1000мс на 126 unit’ов. Исходя из схемы выше пример кода для действий персонажем после достижения пункта назначения:
// Прироста координат нет. Просто считаем когда персонаж дойдет до конечных координат. const distance = 1500; const playerSpeed = 126; const ticks = distance / playerSpeed; // 11.90 const time = ticks * 1000; // 11900mc
setTimeout(() => { // действие персонажа после бега }, time);
GIF
На коротких расстояниях.
GIF
На длинных расстояниях.
Расхождения на коротких расстояниях.
Расхождения на длинных расстояниях.
Зеленой зоной показана точка куда должна ступить нога персонажа если бы не было расхождений.
Рост скорости при развитии персонажа.
126 — это базовая скорость. И по мере развития персонажа будет расти и скорость передвижения. А значит расхождение будет больше. Но перед тем, как создать формулу надо подтвердить теорию, что скорость ходьбы влияет на расхождение.
Данные о характеристиках персонажа передаются от сервера к клиенту.
Выставляю значения walkSpeed: 126. Если скорость ходьбы будет равна скорости бега, то расхождения должны пропасть.
GIF
Нога персонажа достигает правильной конечной точки.
Персонаж синхронизирован и начинает атаку вовремя. Теперь надо понять, как скорость ходьбы влияет на расхождения между клиентом и сервером.
Сколько же персонаж успевает пройти перед тем, как начинает бежать?
Надо поймать момент когда ходьба переходит в бег. Для этого передадим в клиент данные, где скорость ходьбы будет больше скорости бега. Из-за этой разницы будет виден переход и можно будет рассчитать пройденное расстояние при ходьбе.
runSpeed: 10
walkSpeed: 600
GIF
Ходьба быстрее бега.
При скорости шага в 600 персонаж успевает пройти 250, прежде чем начинает бежать.
600 / 250 = 2.4
700 / 291 = 2.4
800 / 333 = 2.4
Из этого вывод, что персонаж перед тем, как начать бежать успевает пройти расстояние в 2.4 раза меньше, чем его скорость ходьбы.
Значит при скорости ходьбы 88 персонаж пройдет 36 unit’ов.
88 / 2.4 = 36
Первое деление — это начало движения (ходьба) а следующие деления — это бег.
Привет. Я продолжаю разрабатывать сервер для Lineage 2 C1 на JavaScript Проект
При добавлении SoulShot функционала не добавил проверку не только на наличие оружия, но и кто атакует — игрок или NPC.
Как итог теперь все атакуют с помощью SoulShot.
Тестирую синхронизацию объектов на перемещение и атаку между NPC и игроком и немного намусорил. Дроп, который падает, показывает текущее местоположение объекта на стороне сервера. Каждый n-ный тик происходит синхронизация. Блог про разработку сервера для Lineage 2 в телеге https://t.me/lineage2js
Совиной почтой в магическом мире Гарри Поттера можно было слать письма, но не только — можно было послать и некоторые другие вещи. Можно было послать и разные предметы — например, Гарри получал таким образом подарки вроде набора по уходу за метлой от Гермионы.
Вот и в программировании один кусочек данных, значение, может быть не только текстом, но и целым числом, числом с дробной частью, логическим значением(«да» или «нет») и т.д.
Но вы можете обнаружить, что в некоторых языках сразу несколько типов данных для того же целого числа. Целое число может быть и int, и short, и byte, и long и т.д. Почему так?
Потому что числа бывают разных размеров и под некоторые числа хватает одной ячейки памяти(байт), для некоторых надо две, а для некоторых и 4! В каких-то языках программирования сам компьютер следит за тем, сколько байт выделяется для значения переменной. А где-то нужно указывать.
Совы в мире Гарри Поттера, похоже, могут тащить посылку любого размера и веса, но представим, что у них есть какие-то ограничения. Больше какого-то веса одна сова не может нести, и тогда подключаются другие совы.
Представим, что человек изначально прикидывает вес посылки и сколько сов потребуется, и заказывает нужное количество сов для доставки. Тогда тем и отличаются типы данных. Целое число типа byte — там один байт. int — два байта. long — 4 байта.
Если вернуться к совам, то byte это одна сова, небольшой вес, int — две совы, посылка потяжелее, long — 4 совы. Тяжёлая большая посылка.
Чтобы участвовать в Турнире Трёх Волшебников, нужно было опустить кусочек пергамента со своим именем в Кубок Огня. Он должен был магически обдумать, выбрать лучшего представителя каждого факультета и выбросить столб пламени вместе с кусочками пергамента, где написаны имена представителей.
Когда люди опускают свои имена в Кубок Огня — они вводят в него данные, свои имена. Когда Кубок Огня выплёвывает пергаменты с именами избранных — он выводит данные из себя во внешний мир.
Так же и в программировании. Когда какая-то информация отправляется в устройство, например, в компьютер — с помощью клавиатуры, мыши, какого-то кабеля и т.д. и т.п. — это ввод данных в компьютер. Когда устройство вроде компьютера, получив какую-то информацию в результате вычислений («размышлений» устройства), отправляет её человеку на экран или ещё куда-то, то это вывод данных. Так и говорят — «выводит на экран», например.
В книгах о Гарри Поттере рассказывается обо многих магических артефактах, обладающих чем-то вроде разума, или хотя бы какими-то зачатками, с помощью которых они могут принять какое-то решение. Первый такой артефакт — Распределяющая Шляпа. В неё вводятся другие данные и другим способом — нужно засунуть голову, чтобы Шляпа телепатически получила доступ ко всей нужной информации. И выводит она данные не таким способом, как Кубок Огня — она громким голосом объявляет имя.
Вот и в программировании существуют разные
способы и устройства для ввода и вывода данных. Клавиатура, мышь, сенсорный экран, микрофон, камера, сканнер и т.д. — устройства ввода. Экран, колонки, принтер и т.д. — устройства вывода.
Наконец закончился мой отпуск и я могу взяться за фотографии.
В это место я давно хотела попасть, но никак не удавалось. И вот вчера, на последнем издыхании, мы всё-таки сделали это.
Британское военное кладбище находится в городе Рамле, единственном, кстати, городом на территории Израиля, основанном арабами.
На кладбище похоронены военные, павшие на территории Подмандатной Палестины в Первую и Вторую мировые войны.
.
К 2010 году арабские смотрители кладбища стали замечать нереальный интерес посетителей к одной единственной могиле. Вскоре выяснилось, что это могила некоего Гарри Поттера, о котором работники, конечно, не знали.
С личной страницы в Вики: “Гарри Поттер родился в многодетной семье сапожника Дэвида Поттера, инвалида Первой мировой войны в городке Киддерминстер[англ.], недалеко от Бирмингема. У него было 7 братьев и сестёр. В 14 лет оставил школу и пошёл работать на ковровую фабрику, чтобы прокормить семью. 3 января 1938 года, в возрасте 16 лет, с той же целью записался в Бирмингеме в армию, прибавив себе два года, остававшиеся до совершеннолетия (поэтому на надгробии указан возраст 19 лет). Был зачислен в 1-й батальон Вустерширского полка, служил шофёром в автотранспортном отделении. Имел прозвище «Гарри-авария» (Crash Harry).”
В сентябре батальон был направлен в подмандатную Палестину для подавления арабского восстания и сразу же активно включился в антиповстанческие операции. С весны 1939 года Гарри был придан роте «D», расквартированной у водокачки, подающей воду в Хеврон, и расположенной в 10 км (6 миль) к югу от города, по дороге на Вирсавию. Это место было прозвано англичанами «Пампет» («Pumpet», сокращение от «pumping station»).
Поздним вечером 22 июля рота «D», возвращавшаяся из Ас-Саму, была атакована под прикрытием темноты вооружённой группой на 39-м км дороги Хеврон — Вирсавия. Во время боя рядовой Гарри Поттер был убит, а рядовые Дерби, Варвик, Пирсон и Симмондс ранены. Джозеф Дерби умер в Иерусалимском госпитале 7 сентября.
Рядовой Поттер (слева) и его лучший друг рядовой Холланд
Сохранилось письмо Поттера матери, в котором он обещает приехать на Рождество и купить велосипед 6-летнему брату Кену. Письмо было получено через день после того, как семья узнала о его гибели:
“Дорогая мама,в ответ на твое письмо, у меня все в порядке. Я надеюсь быть дома на Рождество. Если я не буду, значит, мне немного не повезло.
В настоящее время я нахожусь в месте, которое мы называем Пампет. Теперь нас особенно не загружают работой, и я надеюсь, что у вас все в порядке. Я надеюсь, что папа все еще на работе. Скажи Кену, что я не забыл о его велосипеде. Я надеюсь, Алиса в порядке.
Мы много ходили и плавали в последнее время. Вы, наверное, читали в газетах.
Я не хвастаюсь, но слушайте новости по радио, и услышите, какую работу сделали вустерширцы. Ну, я думаю, что это все на сегодня.
Будьте здоровы — Гарри-авария.”
Поттер был похоронен с воинскими почестями на британском военном кладбище в Рамле. На надгробии было написано:
“Памяти рядового Гарри Поттера, №5251351, 1-й б-н Вустерширского полка, убитого в бою под Хевроном 22.7.1939, в возрасте 19 лет и 10 месяцев”.
Могила внесена местным муниципалитетом в списки городских туристических достопримечательностей.
Несмотря на популярность могилы, нигде в интернете не указано её точное положение. И хоть я заранее по фотографиям в сети определила примерную точку, бродить под палящим солнцем в поисках пришлось очень долго.
На кладбище похоронены почти 6000 солдат, есть много неопознанных. Всего здесь лежат представители 57 национальностей.
Вот поляк
Чех
Англичанин
Британская пехота
Китайский корпус рабочей силы
Эссекский полк британской армии
Тут чернокожий француз
Румын?
Собственный Его Величества королевский полк, Королевский Ланкастерский полк
Скорее всего сефардский еврей, инженерные войска
Польский украинец
Опять африканец
Немец
Итальянец
Бельгийское Конго
Ещё еврей
Новозеландец
Мусульманский участок. Фото не моё. Я сюда просто не доползла
.
Офицер палестинской полиции
Индийцы и египтяне. Индийцев предали огню по индуистской традиции
Зачем эти мальчики бросили свои семьи, дома? Чтобы стать пушечным мясом и навечно лежать безымянными в чужой земле? Сердце разрывается.
Такси — это легковой или грузовой автомобиль, предназначенный для перевозки пассажиров и багажа в любую указанную точку с оплатой проезда.
В саге о Гарри Поттере эту роль исполняет автобус “Ночной рыцарь”.
Автобус «Ночной Рыцарь» (англ. Knight Bus) — заколдованный трёхэтажный автобус «для ведьм и волшебников, попавших в трудное положение». Он доставит вас в любую точку мира, находящуюся не под водой. Чтобы вызвать автобус, нужно взмахнуть палочкой. У Гарри Поттера именно так и получилось. При этом появившийся «Ночной рыцарь» он видел впервые в жизни, а за секунду до этого даже не знал, что такой автобус есть. Впрочем, билет на «Ночной рыцарь» можно заказать заранее, и точно оговорить время и место, когда и где вас подберут. Скорость автобуса — приблизительно 7000км/ч.
Днём в фиолетовом трёхэтажном автобусе можно найти сиденья, а ночью кровати. Он не слишком удобен и не стоит заказывать горячие напитки, даже если таковые будут предложены, так как постоянные прыжки автобуса из одного пункта назначения в другой, происходящие без какого либо предупреждения, могут привести к обильным расплескиваниям. «Ночной рыцарь» — это относительно современное изобретение волшебного сообщества, которое иногда (хоть и редко это признает) заимствует идеи из мира маглов. Необходимость в средстве передвижения, которое могло бы безопасно и тайно использоваться несовершеннолетними или нерешительными волшебниками, возникла довольно давно. Было внесено множество предложений (коляски на метлах типа такси, корзины для переноски, подвешенные под фестралами), но все они были отвергнуты Министерством. Наконец Министру магии Дугалду Макфайлу пришла в голову идея имитировать относительно новое «автобусное сообщение» маглов, и в 1865 году «Ночной рыцарь» появился на дорогах. И хотя некоторые волшебники (в основном чистокровные фанатики) заявили о своём намерении бойкотировать «это магловское безобразие», как назвали его на страницах писем читателей «Ежедневного пророка», «Ночной рыцарь» доказал свою огромную популярность среди волшебников и пользуется спросом по сей день.
Проезд на «Рыцаре» стоит достаточно дорого. Например, из пригорода Лондона Литтл Уингинга до самого Лондона — 11 сиклей. И ещё 3, если хотите получить кружку горячего шоколада. И ещё один, если вам понадобится грелка и зубная щётка... Короче, сервис в «Ночном Рыцаре» мало чем отличается от сервиса междугородних магловских автобусов. Правда, для того, чтобы поспать ночью маглы всего лишь откидывают спинки кресел, в то время как «Рыцарь» превращается в некое подобие гостиницы с салоном, уставленным железными кроватями.
Фото из личного архива из Юнивёрсала.
Автобус обслуживает кондуктор Стэнли Шанпайк, а ведёт Эрни Прэнг. Маглы не видят и не слышат волшебный автобус, и это просто замечательно. Потому что стиль езды «Ночного Рыцаря» таков, что без крайней нужды во второй раз вы его не вызовете. Он берёт резко с места такой разгон, что пассажиры падают с кресел днём и слетают с кроватей ночью, тормозит не лучше, при этом никогда не ездит ровно по дороге, а встречающиеся на его пути деревья, фонарные столбы, почтовые ящики и прочая «мелочь» только успевают отскакивать в сторону. С оглушительным «бах!» «Рыцарь» трансгрессирует со всем своим содержимым в самые неожиданные места и, не снижая скорости, несётся дальше, не разбирая дороги. Неудивительно, что пассажиры покидают автобус с позеленевшими лицами, еле сдерживая позывы рвоты и неизменным чувством «О! Наконец-то я на твёрдой земле!»
В узнике Азкабана «Ночной рыцарь» подвозит Гарри Поттера от Литтл Уингинга до Лондона, а Хагрид отправляется на «Ночном рыцаре» на слушание по делу Клювокрыла.
В Ордене Феникса Гермиона Грейнджер на рождественских каникулах прибывает в дом Блэков на этом автобусе. Также «Ночной рыцарь» отвозит Гарри Поттера, детей Уизли (Фреда, Джорджа, Рона и Джинни), Гермиону Грейнджер и сопровождающих их Нимфадору Тонкс и Римуса Люпина от Лондона до ворот Хогвартса. Рон, изначально радовавшийся выпавшей возможности прокатиться на этом «чуде», под конец поездки поклялся, что ноги его в этом автобусе больше никогда не будет...
Автобус «Ночной рыцарь» так назван, во-первых, из-за того что рыцарь (англ. knight) был омонимом ночи (англ. night), и кстати, есть ночные автобусы, работающие по всей Великобритании, когда другой транспорт не ходит. Во-вторых, рыцарь имеет коннотацию «приходит на помощь, защиту», и это представляется целесообразным для транспортного средства, которое часто становится последней надеждой на то, чтобы уехать.
Водитель и кондуктор «Ночного рыцаря» в «Гарри Поттер и узнике Азкабана» были названы в честь двух дедов Джоан Роулинг - Эрнеста и Стэнли.
В фильмах «Ночной рыцарь» появляется только в части «Гарри Поттер и узник Азкабана». Больше нигде в фильмах нет упоминаний ни о нём, ни о Стэне Шанпайке, ни об Эрни Прэнге.
В фильме в кабине Прэнга появляются висящие говорящие сушёные человеческие головы, тсантсы. Именно эти головы — наиболее говорливые обитатели автобуса. Тсантса — это особым образом высушенная и уменьшенная человеческая голова, которую изготавливали индейцы южноамериканских племён хиваро (шуар), живших в Эквадоре и Перу
Хагрид сказал «Ты волшебник, Гарри!». Тем самым создал связь: под именем Harry_Potter подразумевается волшебник. Получилась пара «имя-значение, которое за ним скрывается». В программировании такие пары называются переменным и они пронизывают всё программирование. Напишем вот это создание переменной на языках программирования:
Harry_Potter = "волшебник"
let Harry_Potter = "волшебник";
String Harry_Potter = "волшебник";
Выше — три варианта, как создать переменную, пару «имя-значение» на трёх разных языках программирования. Во многих языках создание такой пары обозначается с помощью «=». Слева от него пишем имя, справа — значение. Имя пишется всегда без кавычек. Значение, если это текст — в кавычках. Остальное варьируется.
Но! Позже значение Гарри Поттера меняется. Мы узнаём, что он важный символ, «Мальчик, который выжил». Значение человека, скрывающегося за именем Harry Potter, меняется, и с переменной в программировании такое тоже бывает. Чтобы поменять значение в переменной, тоже используют «=», вот вариант для двух языков:
Harry_Potter = "Мальчик, который выжил"
Harry_Potter = "Мальчик, который выжил";
В третьем языке точно так же это делается, как во втором.
Всё, после этого Harry_Potter означает "Мальчик, который выжил". И так можно делать снова и снова. Например, когда Гарри начинает учиться, многие читатели приходят к выводу, что он дурачок и двоечник, особенно на фоне Гермионы Грейнджер. И так постепенно появляются новые значения, и снова и снова мы можем менять значения имени Harry Potter с помощью «=».
А теперь предлагаю поупражняться и немного поиграть. Попробуйте сами найти в Гарри Поттере пары «имя-значение» и увидеть, как и сколько раз значения в этих парах менялись по ходу прочтения книг. И напишите сюда. Да, имя с точки зрения программирования не только у одушевлённых объектов может быть. В программировании это синоним слова «название». «Табуретка» — тоже имя, если за ним скрывается что-то определённое.
Комментарии