Pull to refresh

Колобок в гостях у Windows 8: дневники разработки (часть 1)

Reading time 5 min
Views 5K
Пару недель назад мы опубликовали наш первый материал "Колобок в гостях у Windows 8: дневники разработки (введение)", сегодня мы продолжаем эту тему и рассказываем более детально структуру абстрактного уровня нашей архитектуры, в том виде как мы ее на сегодня организовали.

Первые эскизы


Недавно мы получили первые картинки от художника. Вот такой концепт на данный момент:



Абстрактный класс BaseGame


Этот класс берет на себя обязанности по управлению основным жизненным циклом игры, а также включает в себя логику и физику игры.

public abstract class BaseGame:DisposeSupport
/// <summary>
 /// Describes an abstract game
 /// </summary>
 public abstract class BaseGame:DisposeSupport
    {
        /// <summary>
        /// The game Logic
        /// </summary>
        protected abstract ILogic Logic { get; }
        /// <summary>
        /// The game Physics
        /// </summary>
        protected abstract IPhysics Physics { get; }
        /// <summary>
        /// Initialize the game
        /// </summary>
        public void Initialize(){}
        /// <summary>
        /// Start the new game
        /// </summary>
        public void StartNewGame(){}
        /// <summary>
        /// Activate the game
        /// </summary>
        public void ActivateGame(){}
        /// <summary>
        /// Pause on game
        /// </summary>
        public void Pause(){}
        /// <summary>
        /// Restart the game
        /// </summary>
        public void Restart(){}
        /// <summary>
        /// Resume the game
        /// </summary>
        public void Resume(){}
        /// <summary>
        /// Exit the game
        /// </summary>
        public void Exit(){}
        public event Action Win;
        public event Action GameOver;
        public event Action Lose;
 
    }


Жизненный цикл можно представить так:


Визуализация


Визуализация на верхнем уровне не привязана к игре. Связь с рендерингом происходит только в конкретной реализации игры.
За визуализацию отвечает интерфейс IRenderer, который обеспечивает реализацию трех методов:
  • Initialize выполняется во время инициализации устройства,
  • Render вызывается при отрисовке каждого кадра,
  • SizeChanged вызывается во время смены размеров экрана, и в этот момент возможна инициализация.

public interface IRenderer<TInit, TRender>: IDisposable
/// <summary>
    /// Describes a renderer class
    /// </summary>
    /// <typeparam name="TInit">Type that used for method Initialize parameter</typeparam>
    /// <typeparam name="TRender">Type that used for methods Render and ScreenSizeChanged parameters</typeparam>
    public interface IRenderer<TInit, TRender>: IDisposable
    {
        /// <summary>
        /// On initialize a device
        /// </summary>
        /// <param name="initParameter">Initialize parameter</param>
        void Initialize(TInit initParameter);
        /// <summary>
        /// On render per frame
        /// </summary>
        /// <param name="renderParameter">Render parameter</param>
        void Render(TRender renderParameter);
        /// <summary>
        /// On screen size changed
        /// </summary>
        /// <param name="renderParameter">Render parameter</param>
        void ScreenSizeChanged(TRender renderParameter);
    }


Цикл визуализации:

IRenderer также наследует интерфейс IDisposable, что обеспечивает реализацию комплектом методов по детерминированному уничтожению объектов. В нашей реализации объекты по рисованию также наследуются от класса Component из библиотеки SharpDX, у которого можно использовать методы связанные с помещением ресурсов в список удаления, по которому проходит объект перед уничтожением, и мы получаем готовую реализацию IDisposable.

Логика


В нашей игре представлена интерфейсом ILogic

public interface ILogic
/// <summary>
    /// Describes a game logic
    /// </summary>
    public interface ILogic
    {
        /// <summary>
        /// Start game 
        /// </summary>
        void StartGame();
        /// <summary>
        /// Stop game 
        /// </summary>
        void StopGame();
        /// <summary>
        /// Pause game 
        /// </summary>
        void PauseGame();
        /// <summary>
        /// Resume game 
        /// </summary>
        void ResumeGame();
        /// <summary>
        /// Fire game event 
        /// </summary>
        void FireEvent(IGameEvent @event);
        /// <summary>
        /// Win game event 
        /// </summary>
        event Action Win;
        /// <summary>
        /// Lose game event 
        /// </summary>
        event Action Lose;
        /// <summary>
        /// Delete game object event 
        /// </summary>
        event Action<string> ObjectDeleted;
        /// <summary>
        ///Character moved event 
        /// </summary>
        event Action<string,float,float,float> CharacterMoved;
        /// <summary>
        ///Character moved by path event 
        /// </summary>
        event Action<string, IList<PathData>> CharacterMovedPath;
        /// <summary>
        ///Character patrol by path event 
        /// </summary>
        event Action<string, IList<PathData>> CharacterPatrolPath;
        /// <summary>
        ///Character patrol event
        /// </summary>
        event Action<string, float, float, float> CharacterPatrol;
        /// <summary>
        ///Character moved to object event
        /// </summary>
        event Action<string, string, float> CharacterMovedToObject;
        /// <summary>
        ///Character in chase for object event
        /// </summary>
        event Action<string, string, float> CharacterChase;
        /// <summary>
        /// watch if the one object look at another;
        /// </summary>
        event Action<string, string> WatchedLook; 
        /// <summary>
        /// watch the distance between two objects;
        /// </summary>
        event Action<string, string, float> WatchedDistance;
        /// <summary>
        /// character stop;
        /// </summary>
        event Action<string> ActionStopped;
        /// <summary>
        ///The rules factory
        /// </summary>
        IRuleFactory RuleFactory { get; }

    }

При возникновении игрового события логика обрабатывает набор правил, проверяет условия и возможность их выполнения, и потом инициирует события Win, Lose или Game Over, которые передаются в игру.

Рабочий цикл логики игры:


Физика



public interface IPhysics
public interface IPhysics
    {
        /// <summary>
        /// add object to simulation
        /// </summary>
        /// <param name="obj">object</param>
        void AddObject(IObject obj);
        /// <summary>
        /// remove object from simulation
        /// </summary>
        /// <param name="obj">object</param>
        void RemoveObject(IObject obj);
        /// <summary>
        /// simulate world on specified time after start
        /// </summary>
        /// <param name="time">seconds</param>
        void Simulate(float time);
        /// <summary>
        /// signal that initialization starts
        /// </summary>
        void BeginInitialization();
        /// <summary>
        /// signal that initialization included adding of objects is finished
        /// </summary>
        void EndInitialization();
        /// <summary>
        /// getting movement observer for observing different events related to movement of 
objects
        /// </summary>
        /// <returns>moevement observer</returns>
        IMovementObserver GetMovementObserver();
        /// <summary>
        /// get object factory
        /// </summary>
        /// <returns>getting object factory</returns>
        IObjectFactory GetObjectFactory();
    
    }


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

public interface IObject
public interface IObject
    {
        /// <summary>
        /// getting transformation matrix of object
        /// </summary>
        /// <returns>matrix</returns>
        Matrix GetTransform();
        float X { get; set; }
        float Y { get; set; }
        float Z { get; set; }
    }


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

Выводы:


Хотим сказать, что знакомство с DirectX и самой разработкой игр — это очень интересная и новая для нас сфера.

По C# 5.0 и разработке под Windows Store хотим выделить такие вот особенности:
  • очень много изменений в .Net;
  • нет синхронных операций чтения файлов, теперь все асинхронное (тут нету ничего плохого, иногда такой дизайн не подходит и приходится превращать асинхронный код в синхронный);
  • нет многих стандартных для .Net 4.0 классов;
  • внесены изменения в работу с метаданными типов и рефлексией;
  • немного отличается Xaml набором полезных классов от WPF;
  • чтобы писать под Windows Store нужно обязательно работать в среде Windows 8.
Tags:
Hubs:
-13
Comments 12
Comments Comments 12

Articles