ФлеймФорумПрограммирование

Покажите свой базовый класс (8 стр)

Страницы: 15 6 7 8 9 10 Следующая »
#105
18:55, 25 авг 2011

Sh.Tac.
>например сериализация у меня сейчас выглядит очень просто, если кто-то унаследован от такого пустого IBase, я вызываю его метод, если нет, - то обычный memcpy () для POD
memcpy это не сериализация, даже для POD.

#106
16:18, 10 окт 2011

Часто базовый класс выглядит на подобии вот этого:

class GameObject {
  void update(float dt);
  void render(RenderTarget target);
}

Иногда нужно изменить поведение некотрому экземпляру, не трогая другие.

Думаю сделать базовый класс вот таким образом, на колбеках:

class GameObject {
  GameObject() {
    update = &defaultUpdate;
    render = &defaultRender;
  }
  
  void (*update)(float);
  void (*render)(void);
  void defaultUpdate(float dt){...}
  void defaultRender(){...}
}

И если нужно сделать один экземпляр особенным, то можно просто присвоить лямбду. Хорошая ли это идея?

#107
16:25, 10 окт 2011

AvrDragon
> Хорошая ли это идея?

переизобретаем наследование?

#108
16:27, 10 окт 2011

AvrDragon
> Иногда нужно изменить поведение некотрому экземпляру, не трогая другие.
может этот экземпляр просто другого класса?

#109
16:31, 10 окт 2011

berserkovich
конечно можно унаследовать класс и перегрузить нужный метод, но плодить классы для каждой мелочи загрязняет пространство имен

Pushkoff
У меня есть 10 самолетиков. Летят они цепочкой. Хочу чтоб 7ой выстрелил.
Конечно можно сделать подкласс, но мое* решение покрасивей и покомпактней вроде как. Или нет?

*сомневаюсь что я первый додумался

#110
16:48, 10 окт 2011

AvrDragon
> плодить классы для каждой мелочи загрязняет пространство имен
чистота пространства имён - последняя вещь, о которой бы я беспокоился

такой подход может быть оправдан при реализации состояний как замена else if/switch. это при условии, что один и тот же экземляр может поменять этот стейт в течении жизни
и скорее всего это будет где-то внутри update, а не полная его замена. а для render это вообще очень сомнительно

#111
17:11, 10 окт 2011

AvrDragon
> У меня есть 10 самолетиков. Летят они цепочкой. Хочу чтоб 7ой выстрелил.
и эта задача у тебя требует подмены update и draw? мне тебя жаль...
надели все самолетики возможностью выстрелить, а стреляет пусть 7, либо посылай ему сообщение либо пусть сами думают кто должен выстрелить
либо сделай 9 самолетиков не стреляющими, а седьмой стреляющим

#112
18:25, 10 окт 2011

berserkovich
>чистота пространства имён - последняя вещь, о которой бы я беспокоился
это пока их мало

>такой подход может быть оправдан при реализации состояний как замена else if/switch. это при условии, что один и тот же экземляр может поменять этот стейт в течении жизни
это совсем другая тема

лично мне такая возможность динамически наделить обьект особыми свойствами не прибегая к наследованию кажется довольно выразительной и чистой в сравнении с другими возмозжностями

>а для render это вообще очень сомнительно
Для render и правда маловероятно, хотя ситуацию тоже множно себе представить.

Pushkoff
>и эта задача у тебя требует подмены update и draw?
А почему б и не подменить update()? как будто подмена метода лямбдой очень долгое дело.
>мне тебя жаль...
:3

>надели все самолетики возможностью выстрелить, а стреляет пусть 7
грязно

>либо посылай ему сообщение
>либо пусть сами думают кто должен выстрелить
тоже предпологает что стрелять умеют все, а не только тот который надо

>либо сделай 9 самолетиков не стреляющими, а седьмой стреляющим
вот я же так и пытаюсь сделать

#113
18:58, 10 окт 2011

AvrDragon
ты зря выбрал С++, посмотри на питон или flash. там твои методы более применимы

AvrDragon
> вот я же так и пытаюсь сделать
так это 2 класса, стреляющий самолет и не стреляющий
а твои функторы лучше вынести в скрипт, то что ты делаешь это адъ и ужосъ

#114
19:08, 10 окт 2011

nes
> Думаю у многих тут (которые пишут свои игры) есть нечто подобное, предлагаю
> показать и обсудить свои творения )

Ну смотри:

#ifndef BREAKOUT_GAME_ACTOR_H
#define BREAKOUT_GAME_ACTOR_H
#pragma once

#include "event_system.h"
#include "processes.h"
#include "serializer.h"

#include "actor_data_component.h"

namespace pegas
{
  namespace dream3d
  {
    using namespace pegas::core;

    //
    
    class GameLogic;
    class GameActor;
    struct CollisionData;

    typedef SmartPointer<GameActor> GameActorPtr;
    typedef GameLogic* GameLogicPtr;
    typedef size_t ACTORID;
    typedef String ACTORTYPE;
            
    class GameActor  
    {
    public:
      enum eDataScope
      {
        k_actorDataAll = 1,
        k_actorDataCommon,
        k_actorDataInstance,          
      };
      typedef size_t DataScope;

      static const String k_unamedActor;
      static const ACTORID k_actorIdNull;

    public:
      GameActor();
      virtual ~GameActor() {}
            
      //general events
      virtual void onCreate() {}
      virtual void onDestroy() {}
      virtual void onCollisionEnter(ACTORID sender, const CollisionData& eventData) {}
      virtual void onCollisionLeave(ACTORID sender, const CollisionData& eventData) {}
      virtual void onTick(MILLISECONDS deltaTime) {}
      
      ProcessPtr getProcess();
      virtual bool isTickable() const { return false; }; 
      
      //возвращает тип обьекта ("персонаж", "монстр", "ящик" и т.д.)
      //обычно используеться при приобразовании указателя на базовый класс в указатель
      //на конкретный класс игрового обьекта
      virtual ACTORTYPE getType() const = 0;

      void setID(ACTORID actorID) { m_id = actorID; }
      ACTORID getID() const { return m_id; }
      void setName(const String& name) { m_name = name; }
      String getName() const { return m_name; }

      void setParentID(ACTORID actorID) { m_parentID = actorID; }
      ACTORID getParentID() const { return m_parentID; }
      void setGroupName(const String& name) { m_groupName = name; }
      String getGroupName() const { return m_groupName; }

      
      void addComponent(ActorDataPtr component);
      void removeComponent(const ComponentID& name);
      void removeComponentsByType(const ComponentType& _type);
      bool hasComponent(const ComponentID& name);
      bool hasComponentOfType(const ComponentType& name);
      ActorDataPtr getComponent(const ComponentID& name);
      void getComponentsByType(const ComponentType& name, std::list<ActorDataPtr>& _out);
      bool renameComponent(ActorDataPtr component, const ComponentID& name);
      bool enableComponent(const ComponentID& name);
      void disableComponent(const ComponentID& name);

      virtual GameActorPtr clone() const;

      virtual void parse(const pugi::xml_node& data, DataScope scope);
      virtual void load(ISerializer& serializer, DataScope scope);
      virtual void save(ISerializer& serializer, DataScope scope);
    
    protected:
      ACTORID m_id; //уникальный ИД, назначаемый менеджером игровой логики
      String  m_name; //имя (обычно устанавливаемое пользователем в редакторе, 
                  //которое используеться в скриптах
      ACTORID m_parentID;
      String  m_groupName;

      //этот метод непосредственно создает экземпляр обьекта
      //и должен переопределяться в подклассах
      virtual GameActorPtr _clone() const = 0;
      
      ProcessPtr m_process;
/*
      friend class GameLogic;  
      GameLogicPtr  m_gameLogic; //класс игровой логики устанавливает ссылку на себя напрямую
                    //=> делаем его дружественным*/

      typedef std::multimap<ComponentType, ActorDataPtr> ComponentsTypeMap;
      typedef ComponentsTypeMap::iterator ComponentsTypeMapIt;
      typedef std::map<ComponentID, ActorDataPtr> ComponentsIDMap;
      typedef ComponentsIDMap::iterator ComponentsIDMapIt;
      
      ComponentsIDMap    m_components;
      ComponentsTypeMap  m_typeComponents;

      void notifyUpdate(const ComponentType& component, const String& propertyName = _text("all"));
          
    private:
      ComponentID generateComponentID(const ComponentType& _type);

      GameActor(const GameActor& src);
      GameActor& operator=(const GameActor& src);
    };

    class ProcessProxy: public Process
    {
    public:
      ProcessProxy(GameActor* actor)
        :m_actor(actor)
      {
        assert(actor != 0 && "invalid argument");
      }

      virtual void update(MILLISECONDS deltaTime)
      {
        m_actor->onTick(deltaTime);
      }
    private:
      GameActor* m_actor;
    };
  }
}

#endif
[/cpp]
#115
19:19, 10 окт 2011

Pushkoff
>ты зря выбрал С++, посмотри на питон или флаш. там твои методы более применимы
я собственно на шарпе сейчас пишу, с++ просто для примера, там это будет через делегаты конечно

>так это 2 класса, стреляющий самолет и не стреляющий
которые отличаются только одним методом, самое оно для лямбд

>а твои функторы лучше вынести в скрипт, то что ты делаешь это адъ и ужосъ
А чем они плохи??? Они абсолютно опциональны - не хочешь, используй стандартные функции-члены, перегружай если надо. Но вот если не хочеться плодить лишних классов из-за каждой мелочи, то метод с заменой функции-члена намного более элегантен.

>так это 2 класса,
Тем более наследование очень скоро станет очень непонятным, если один стреляет, другой облетает сбоку, третий помигивает, четвертый делает все одновременно, кроме помигивания и что-то еще. А на колбеках все очень тонко настраивается, при этом никакого риска - не надо не используй.

Единственный минус который я вижу это несколько усложняет понимание интерфейса класса - методов update() и render() как таковых нет, вместо них defaultUpdate() и defaultRender() и именно их и нужно перегружать.

А так не хочешь не используй, но одновременно такая гибкая опция доступна.

#116
19:25, 10 окт 2011

AvrDragon
> которые отличаются только одним методом, самое оно для лямбд
не вопрос. это и есть разделение представление и логики и это хорошо, и хорошо что ты к этому пришел. но тогда лучше логику выделить в один класс со своим интерфейсом и спрашивать у этого класса что делать.

#117
22:32, 10 окт 2011

Албанец

а что, без map* никак нельзя ? :)

#118
23:10, 10 окт 2011

Албанец
у тебя в одном объекте собрано слишком много функционала, попробуй разобрать на части и собрать миксином

#119
7:34, 11 окт 2011

innuendo
> а что, без map* никак нельзя ? :)

можно, но мне удобней ТАК.

Pushkoff
> у тебя в одном объекте собрано слишком много функционала, попробуй разобрать на
> части и собрать миксином

Чушь, ничего лишнего там нет. Ровно столько, сколько нужно. А для сравнения, где "много функционала", гляньте базовый класс Actor.uc из UDK, написанный эпиками, где закодировано все вселенское бытие.

Страницы: 15 6 7 8 9 10 Следующая »
ФлеймФорумПрограммирование

Тема в архиве.