id44474404 id44474404

В Княжествах Онлайн снова появились анимации, они синхронизируются с сервером и работают реалистично, т.е. нанесение урона или получение ресурсов происходит в тот момент, когда это соответствует анимации...

...
TheDarkestRed TheDarkestRed

Экспериментируем с рэгдолами 🎮🧟🤺🐺

lehha95 lehha95

Открыли страницу в Steam! Добавляйте в список желаемого!

https://store.steampowered.com/app/1355780/

romandviski romandviski

Спасибо, добрый человек.

Rummy_Games Rummy_Games

Доброго субботнего вечера! Сегодня мы поделимся с вами видео процесса разработки одного из противников (“Роя”) в нашей игре, в рамках #saturdayscreenshot, а также кратко делимся ЛОРом игры.

...
id44474404 id44474404

Всем привет!
Функционал авторитарного сервера продолжает восстанавливаться до уровня, который был на фотон клауде. На этой неделе стало возможным убийство мобов, и получение с них опыта, и прокачка персонажа...

...
Jusper Jusper

В GMS сильно поменялась структура функционала, но не все корректно мигрируется из старых проектов. Если тебе не критичны новинки, то переходить на него стоит только с новым проектом.

Kazirath Kazirath

Насколько я понял проще установть последнюю версию перед 2.3 и продолжить работать под ней. Новинка не стоит свеч после переделки скриптов

Kazirath Kazirath

Это совсем не радостная новость. Меня вполне устраивал функционал старой работы скриптов и я даже выработал некоторую систему, которая позволяла через скрипты настраивать работу объектов и прочего. Принудительная же переделка в функции у меня не сработает из за структур некоторых скриптов...

...
alexprey alexprey

Учитывая то, что написано в данной статье обратно включить это не получится и придется действительно обернуть код скриптов в функции.

Кратко из документации:

  • Раньше скрипты были индивидуальными и изолированными
  • ...
  • ...
  • ...
  • ...
...
PallSwarrow PallSwarrow

Спасибо за комменты, оч приятно)
Про ссылку тупанул - пока разбираюсь с сайтом)

alexprey alexprey

Жду линк на потестить и следующий девлог о разработке)

Jusper Jusper

Если есть прототип, было бы здорово выложить на него ссылку.
Не хватает игровых скриншотов.

Jusper Jusper

Raised, оригинал на Eurogamer.
Скорее всего, ирония.

Raised Raised

Это была такая ирония или Фортнайт тогда действительно был небольшим проектом?

id44474404 id44474404

alexprey, спасибо !)

alexprey alexprey

id44474404, поставить курсор на нужное место и у картинки нажать "вставить"

id44474404 id44474404

alexprey, в тех публикациях были были в перемешку слова и фотки, я докинул несколько скринов, но их нигде не видно, как добавить фотографии ?

alexprey alexprey

id44474404, ага, больше информации -> больше обсуждения да и в целом понимания о проекте)
В любом случае, добро пожаловать!))

id44474404 id44474404

Хм, больше инфы?) Ок

Логотип проекта Unity

Паттерны. "Strategy". Unity

Здравствуйте уважаемые читатели данной статьи. Сегодня я решил поговорить о ОО-проектировании в сфере геймдева, используя движок Unity. Сразу скажу, что данная статься является объективным видением использования паттернов и в особенности, их реализация. Кто-то может говорить о том, что в моих далее приведенных примерах лучше использовать тот или иной паттерн и возможно вы будете правы, но моя задача как минимум поверхностно пройтись по этой достаточно сложной теме. Я рассчитываю сделать небольшой цикл статей про разные паттерны и их примерное использование, чтобы архитектура вашего проекта стала гибкой и расширяемой.
Также хочу отметить, что данный цикл будет требовать определенных знаний в области ОО-программирования и базового ознакомления с понятием "паттерн".
Вроде всё оговорил, можем начинать!

Паттерн "Стратегия". Его использование.

Подробнее с самим паттерном можно ознакомится здесь: https://metanit.com/sharp/patterns/3.1.php

Данный паттерн рассчитан для добавления новых поведений объектам, имеющим один базовый класс, либо интерфейс.
Например, у нас есть объект "Enemy" и объект "Player". Наша задача - добавить новые виды врагов и NPC в нашу небольшую игру. Предположим, мы уже имеем базовую реализацию двух ранее написанных классов, но мы хотим и в перспективе добавлять всё новые типы врагов и NPC, а реализовывать отдельные классы для каждого типа - вещь затратная, как в плане времени, так в плане и "кодинга".
Если мыслить более абстрактно, мы можем выделить для класса "Enemy" , "Player" и "NPC" один абстрактный класс, который будет иметь общие хар-ки и методы. Назовём этот класс "Human". Я рассматриваю задачу на конкретных примерах и поэтому названия буду давать соответствующие.
Что мы имеем? Предположим такую реализацию класса "Human":

using UnityEngine;
using Game.Behaviours;

namespace Game.Entity
{
    public abstract class Human : MonoBehaviour
    {
        protected readonly byte maxHealth = 100;
        protected string humanName;
        protected byte currentHealth;  
    }
}

Данный объект можно было бы представить в виде интерфейса, но будем считать, что у нас есть общие параметры для всех объектов в виде максимального и текущего здоровья, а также имени.

Примечание: В целом, набор параметров можно было бы хранить двумя другими способами. 1. Хранить внутри инкапсулированной структуры . 2. Хранить внутри ScriptableObject.

Теперь перейдём к реализации класса "Player":

using UnityEngine;
using Game.Behaviours;

namespace Game.Entity
{
    public class Player : Human
    {
        [System.Serializable]
        public struct PlayerInfo
        {
            public Vector3 position;

            public PlayerInfo(Vector3 position)
            {
                this.position = position;
            }
        }
        [SerializeField]
        private Vector3 direction;
        private PlayerInfo playerInfo;
        

        private void Start()
        {
        	playerInfo = new PlayerInfo(transform.position);
        }

        private void Update()
        {
        	if (Input.GetKey(KeyCode.Space)) Movement();
        }
        
        private void Movement()
        {
  		//Здесь мы будем двигать нашего игрока (для примера)
        }

    }
}

Поясню некоторые моменты:

  1. Все изменяемые параметры игрока я храню внутри структуры (чтобы в будущем можно было бы, например, сохранять эти данные в JSON формате. (сохранение игровых данных, проще говоря).
  2. Для примера, я решил сделать передвижение игрока, поэтому добавил некоторые элементы, которые будут для нас важны в будущем.

А теперь реализация класса "Enemy":

using UnityEngine;

namespace Game.Entity
{

    public class Enemy : Human
    {

        private void Start()
        {
           
        }

        private void Update()
        {

        }
    }
}

Пока что ничего интересного, просто пустой класс. Теперь предположим, что мы хотим, чтобы наш игрок мог двигаться, но при этом, наши враги тоже могли. Для этого мы создадим... Интерфейс! Да-да, именно. А далее, мы создадим класс-поведение, которое будет наследовать данный интерфейс. А теперь, по-порядку.
Интерфейс:

public interface WalkBehaviour
    {      
        float SetMoveSpeed(float speed);
        void Move(Vector3 direction);
    }

Классический пример интерфейса для движения объекта. Далее, класс-поведение:

using UnityEngine;

namespace Game.Behaviours
{

    public class HumanWalkBehaviour :  WalkBehaviour
    {
        private Transform humanTransform;
        private float speed;

        public HumanWalkBehaviour(Transform humanTransform, float speed)
        {
            this.humanTransform = humanTransform;
            this.speed = speed;
        }
 
        public float SetMoveSpeed(float speed) => this.speed = speed;
       
        public void Move(Vector3 direction)
        {        	
            humanTransform.position += direction * speed;
            //Проверка. Как и подобает.
            Debug.LogFormat("Transform: {0}, Direction: {1}, Speed: {2}", humanTransform, direction, speed);           
        }

    }
}

Как видите, все необходимые данные инициализируются в конструкторе класса, а при этом, само поведение не будет занимать места среди компонентов игровых объектов, так как существует он только внутри классов, которыми он будет создан.
Теперь немного преобразуем класс "Human":

using UnityEngine;
using Game.Behaviours;

namespace Game.Entity
{

    public abstract class Human : MonoBehaviour
    {
        protected readonly byte maxHealth = 100;
        protected string humanName;
        protected byte currentHealth;
        private WalkBehaviour walkBehaviour;

        public void SetWalkBehaviour(WalkBehaviour behaviour) => walkBehaviour = behaviour;

        public void PerformWalkSetSpeed(float speed) => walkBehaviour.SetMoveSpeed(speed);

        public void PerformWalkMove(Vector3 direction) => walkBehaviour.Move(direction);       
        
    }
}

Если вы обратите внимание, то увидите, что благодаря методу "SetWalkBehaviour" вы имеете возможность добавить новое поведение, а конкретно поведение, реализуемое на базе интерфейса "WalkBehaviour". Достоинство этого способа заключается в том, что экзмепляр, который хранит у нас "WalkBehavoir" никак не привязан к классу "HumanWalkBehaviour". Что это значит? То, что вы можете делать несколько классов-поведений, которые связаны одной задачей, но при этом имеют разную реализацию. Конкретнее в примере далее.
Теперь преобразуем класс "Player":

using UnityEngine;
using Game.Behaviours;

namespace Game.Entity
{
    public class Player : Human
    {
        [System.Serializable]
        public struct PlayerInfo
        {
            public Vector3 position;

            public PlayerInfo(Vector3 position)
            {
                this.position = position;
            }
        }
        [SerializeField]
        private Vector3 direction;
        private PlayerInfo playerInfo;
        

        private void Start()
        {
            playerInfo = new PlayerInfo(transform.position);
            SetWalkBehaviour(new HumanWalkBehaviour(transform, .25f));
          
        }

        private void Update()
        {
            if (Input.GetKey(KeyCode.Space)) Movement();

        }
        
        private void Movement()
        {
            PerformWalkMove(direction);
           
        }

    }
}

Как вы можете видеть, класс "Player" создаёт новое для себя поведение, а также передаёт некоторые входные параметры, необходимые для данного поведения. Сам вызов поведения реализован в методе "PerformWalk" и вызывается внутри класса "Player". Если протестировать, игрок будет двигаться в том направлении, которое ему укажут (переменная 'direction' в окне "Inspector").
Таким образом, мы применили паттерн "Стратегия". Мы создали один общий класс для многих похожих друг на друга классов, которые имеют общие параметры, но при этом могут иметь или не иметь разные поведения.
Таким способом, вы можете добавлять совершенно разные поведения и устанавливать их для разных классов. Например для класса "Enemy" я создам новое поведение.
Вот новое поведение для класса "Enemy":
using UnityEngine;

namespace Game.Behaviours
{

    public class EnemyNotWalkBehaviour : WalkBehaviour
    {

        public void Move(Vector3 direction) => Debug.Log("This enemy can not walk! He can only kill!");

        public float SetMoveSpeed(float speed) => 0;
        
    }
}

И его использование в классе "Enemy":

using UnityEngine;
using Game.Behaviours;

namespace Game.Entity
{

    public class Enemy : Human
    {

        private void Start()
        {
            SetWalkBehaviour(new EnemyNotWalkBehaviour());
            PerformWalkMove(Vector3.zero);
        }
    }
}

Хм. Кажется, этот враг не может ходить... Верно, мы ведь избавили его от этой нелёгкой работы.
Как видите, я использую те же методы, что и в классе "Player", только теперь добавляю новое поведение. Однако, я могу добавить это поведение и игроку. Но стоит ли?

В следующей статье я хочу рассказать сразу о двух паттернах, а именно "Одиночка" и "Декоратор".

Заключение:
Конечно, может кто-то и скажет, что для такой задачи лучше мог подойти паттерн "состояние" с использованием конечных автоматов, но, как мне кажется, данный паттерн лучше использовать, например, для написания ИИ. А для общей картины, лучше подойдёт "Стратегия". Но это лишь моё мнение.
Кстати, если вдруг тут будет гуру-программист, у меня есть небольшая просьба в виде совета. Подробнее в ЛС, пожалуйста.

Смотрите также:


Комментарии



  • 1
  • 2 (Текущая страница)

Познавательно, спасибо.

  • 1
  • 2 (Текущая страница)
Справка