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

YouTube-канал про геймдев и программирование. Критикуйте, господа и дамы (7 стр)

Страницы: 16 7 8 912 Следующая »
#90
22:37, 13 июля 2019

Adler
> что-то странное, почему нельзя делать так:
Потому что ты думаешь в контексте одного t_cd_sys. А ты сразу подумай, где ты будешь "особенности пространства" хранить. И как ты будет меинтейнить "особенности пространства".
А когда поймешь как будешь работать с пространством, поймешь заодно почему темплейты тут не нужны.


#91
23:12, 13 июля 2019

MrShoor
> А ты сразу подумай, где ты будешь "особенности пространства" хранить.
преждевременная оптимизация же. например, вдруг там всего три объекта на всю сцену?

ну и да, если добавить оптимизацию которая использует "особенности пространства" то в результате получиться что-то очень похожее на не читаемое говно для роботов мазохистов.
а ещё 95% читателей будут недовольны что "не читаемое говно" есть результат оптимизации не по тому параметру который для них родной. оно того стоит, так рисковать?

#92
23:16, 13 июля 2019

Adler
> преждевременная оптимизация же. например, вдруг там всего три объекта на всю
> сцену?
Мы уже знаем, что там не 3 объекта. Ты crimsonland видел? N^2 тут уже не канает. Какие дальнейшие действия?

> то в результате получиться что-то очень похоже на не читаемое говно для роботов
> мазохистов
Не надо про нечитаемость. Если писать нормально - все читается. Если же насувать темплейтов ради темплейтов, то да, на выходе получится говно.

#93
23:22, 13 июля 2019

В общем сделал так:

class AbstractHitmap
{
public:
  AbstractHitmap(const Point2D ¢er = Point2D());
  virtual ~AbstractHitmap();

  void setCenter(const Point2D ¢er);
  Point2D getCenter() const;

protected:
  Point2D rotatePoint(const Point2D &point, const Point2D ¢erOfRotation, double angle);

  bool intersectCircles(const Point2D & center1, double radius1, const Point2D & center2, double radius2);
  bool IntersectCircleLine(const Point2D & center, double radius, const Point2D & p1, const Point2D & p2);
  bool intersectRectCircle(double rectX, double rectY, double width, double height, const Point2D & circleCenter, double circleRadius);
  bool intersectRotatedRectCircle(double rectX, double rectY, double width, double height, double rotationAngle, const Point2D & circleCenter, double circleRadius);

protected:
  Point2D m_center;
};
class RoundHitmap;
class RectHitmap;

class IHitmap
{
public:
  IHitmap();
  virtual ~IHitmap();

  virtual bool checkIntersection(const RoundHitmap &roundHitmap) = 0;
  virtual bool checkIntersection(const RectHitmap &rectHitmap) = 0;
};
class RectHitmap : public AbstractHitmap, private IHitmap
{
public:
  RectHitmap(const Point2D ¢er = Point2D(), int32_t width = 0, int32_t height = 0, double rotationAngle = 0);
  ~RectHitmap();

  virtual bool checkIntersection(const RoundHitmap &roundHitmap);
  virtual bool checkIntersection(const RectHitmap &rectHitmap);

  double getRotationAngle() const;
  void setRotationAngle(double rotationAngle);
  Point2D getLeftCorner() const;
  int32_t getWidth() const;
  int32_t getHeight() const;

private:
  int32_t m_width, m_height;
  double m_rotationAngle;
  Point2D m_leftCorner;
};

bool RectHitmap::checkIntersection(const RoundHitmap & roundHitmap)
{
  return intersectRotatedRectCircle(m_leftCorner.getX(), m_leftCorner.getY(), m_width, m_height, m_rotationAngle, roundHitmap.getCenter(), roundHitmap.getRadius());
}

bool RectHitmap::checkIntersection(const RectHitmap & rectHitmap)
{
  return false;
}
class RoundHitmap : public AbstractHitmap, private IHitmap
{
public:
  RoundHitmap(const Point2D ¢er = Point2D(), double radius = 1.0);
  ~RoundHitmap();

  double getRadius() const;
  void setRadius(double radius);

  virtual bool checkIntersection(const RoundHitmap &roundHitmap);
  virtual bool checkIntersection(const RectHitmap &rectHitmap);

private:
  double m_radius;
};


bool RoundHitmap::checkIntersection(const RoundHitmap & roundHitmap)
{
  return intersectCircles(m_center, m_radius, roundHitmap.getCenter(), roundHitmap.getRadius());
}

bool RoundHitmap::checkIntersection(const RectHitmap & rectHitmap)
{
  return intersectRotatedRectCircle(rectHitmap.getLeftCorner().getX(), rectHitmap.getLeftCorner().getY(),
    rectHitmap.getWidth(), rectHitmap.getHeight(), rectHitmap.getRotationAngle(),
    m_center, m_radius);
}


Осталось только пробежаться и посравнивать хитмапы.

#94
0:14, 14 июля 2019

MrShoor
> Мы уже знаем, что там не 3 объекта. Ты crimsonland видел? N^2 тут уже не канает.
пока N<200 можно класть болт, для нубского crimsonland должно хватить.

> Какие дальнейшие действия?
если не скатываться ещё дальше, то можно просто каждый кадр строить "особенности пространства" и сразу же использовать. вроде должно хватить где-то на 3000 объектов.

struct t_cd_sys_with_spaces{
  t_space_for_rects r2r;
  t_space_for_circles c2c;
  t_space_for_r2c r2c;
  ...
};
struct t_game{
  void update_cd(){
    cd_sys.write_to_spaces(rects);
    cd_sys.write_to_spaces(circles);
    //
    cd_sys.solve(rects,circles); // если использовать вывод типов то можно сохранить api и тогда пара параметров (rects,circles) запустит solve для объектов в "r2c".
    cd_sys.solve(rects);
    cd_sys.solve(circles);
  }
};

MrShoor
> Не надо про нечитаемость. Если писать нормально - все читается.
"писать нормально" - это наверно какой-то случайны/родной/секретный критерий оптимизации? почему этот критерий нельзя продать ради производительности?

> Если же насувать темплейтов ради темплейтов, то да, на выходе получится говно.
неженка :)

#95
1:23, 14 июля 2019

MrShoor
> Держи вот:
У вас инкапсуляция как продажная девка, где-то ей можно пренебречь, а где-то попользоваться. Напомню, что изначально речь шла вот об этом:

Avoid getters and setters whenever possible

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

#96
3:44, 14 июля 2019

totoro
> где-то ей можно пренебречь, а где-то попользоваться.
Логично. Где-то используется пила, а где-то лобзик. Там где ненужна инакпсуляция - она не нужна. Там где нужна - она нужна. Ваш кэп.

> Напомню, что в рамках одного проекта/библиотеки принято писать в единообразном
> стиле, так какой же выбрать?
Если это POD (или что-то близкое) - то не надо ничего инкапсулировать. Если это объект с потенциально сложным поведением - то надо. Казалось бы, все просто.

Adler
> пока N<200 можно класть болт, для нубского crimsonland должно хватить.
Вот тут 256 врагов:
256 | YouTube-канал про геймдев и программирование. Критикуйте, господа и дамы
А вот тебе собственно кримсонленд:
Изображение
Я не считал врагов, но я думаю тут их 200+
Проверять 40К + коллизий каждый кадр - ну такое себе.

> "писать нормально" - это наверно какой-то случайны/родной/секретный критерий
> оптимизации? почему этот критерий нельзя продать ради производительности?
Потому что не надо ничего продавать. Можно оставить нормально написанный код, но так, что его можно просто оптимизировать.

Adler
> если не скатываться ещё дальше, то можно просто каждый кадр строить
> "особенности пространства" и сразу же использовать. вроде должно хватить где-то
> на 3000 объектов.
Я согласен, в данном случае можно на лету строить эти "особенности пространства".
Давай рассмотрим твой код, который ты предложил:

struct t_cd_sys_with_spaces{
  t_space_for_rects r2r;
  t_space_for_circles c2c;
  t_space_for_r2c r2c;
  ...
};
struct t_game{
  void update_cd(){
    cd_sys.write_to_spaces(rects);
    cd_sys.write_to_spaces(circles);
    //
    cd_sys.solve(rects,circles); // если использовать вывод типов то можно сохранить api и тогда пара параметров (rects,circles) запустить solve для объектов в "r2c".
    cd_sys.solve(rects);
    cd_sys.solve(circles);
  }
};
Я пока не вижу здесь никакой оптимизации. Ты просто предлагаешь разложить rect и circles в разные списки. Как работает твоя "оптимизация"? Я продолжаю настаивать, что их не нужно раскладывать в разные списки. Это только мешает.
#97
9:01, 14 июля 2019

MrShoor
> Потому что не надо ничего продавать. Можно оставить нормально написанный код,
> но так, что его можно просто оптимизировать.
Ну это победа, однозначно. Всё сдаюсь. Я тоже за то чтобы писать N^2 код, а автоматическую оптимизацию на основе разбиения пространства оставить компилятору.

MrShoor
> Я пока не вижу здесь никакой оптимизации
ну хотя бы видно что API системы решения столкновений начало требовать дополнительных танцов/телодвижений со стороны пользователя? а это только начало пути в ад.

MrShoor
> Как работает твоя "оптимизация"
t_space_for_* - фасад ускоряющих структур использующих разбиение пространства на сектора/ячейки.

#98
9:49, 14 июля 2019

Adler
> t_space_for_* - фасад ускоряющих структур использующих разбиение пространства
> на сектора/ячейки.
Давай, напиши цикл, который использует этот самый t_space_for. Ты как-то очень интересно избегаешь показать что с чем ты будешь резолвить в результате оптимизации.

Для моего варианта код с гридом вот:

class CollisionSystem {
//.....
  std::unordered_map<vec2i, std::vector<Collider*>> grid;

  std::vector<Collider*>* tryGetCellValue(vec2i cell) {
    auto it = grid.find(cell);
    if (it == grid.end()) return nullptr;
    return &it.second;
  }
  
  void resolveCollision(Collider* item1, Collider* item2) {
    if (item1 >= item2) return; //если проверили коллизии A с B, то B с A можно уже не проверять
    if (item1.Kind() < item2.Kind()) swap(item1, item2);
    switch (item1.Kind()) {
      case ColliderKind::Circle:
         if (item2.Kind()==ColliderKind::Circle)
           resolveCollision_CircleCircle(item1, item2);
         else
           resolveCollision_CircleRectangle(item1, item2);
         break;
      case ColliderKind::Rectangle:
         resolveCollision_RectangleRectangle(item1, item2);
         break;
    }
  }

  void resolveCollisionsGroups(const std::vector<Collider*>& group1, const std::vector<Collider*>& group2) {
    for(auto& item1 : group1)
      for(auto& item2 : group2)
        resolveCollision(item1, item2);
  }

  void resolveCollisions(){
    for(auto& cell : grid) { //перебираем весь грид
      if (x.second.size()==0) continue;
      for(int dx = -1; dx < 2; dx++ ) //перебираем соседей
        for(int dy = -1; dy < 2; dy++) {
          std::vector<Collider*>* other = tryGetCellValue(x.first+vec2i(dx, dy));
          if (other) resolveCollisionsGroups(x.second, *other); //резолвим коллизии внутри групп
        }
    }
  }
};
Покажи теперь аналогичный код для своего варианта. Я хочу посмотреть как ты на своём варианте будешь перебирать соседние ячейки грида, и сравнивать всё со всеми в этих соседних ячейках.
У меня например хорошо видно, как я перебираю 9 соседей в диапазоне от -1 до +1 вокруг каждой ячейки:
for(int dx = -1; dx < 2; dx++ )
  for(int dy = -1; dy < 2; dy++)
И в результате сравниваю все из центральной ячейки со всем, что в соседних 9 ячейках.
А как это выглядит в твоем коде?

#99
9:53, 14 июля 2019

Кажись в кримсонленде не считают коллизий между врагами, там даже на скриншоте выше заметно.
Сойдет даже самое простое решение.

#100
9:54, 14 июля 2019

Zegalur
> Кажись в кримсонленде не считают коллизий между врагами, там даже на скриншоте
> выше заметно.
> Сойдет даже самое простое решение.
У топикстартера в задаче надо считать.

#101
10:48, 14 июля 2019

MrShoor
> Покажи теперь аналогичный код для своего варианта
там можно спрятать почти все тоже самое.

только hash_map можно заменить на честный grid.
а ещё можно в каждой ячейке хранить small_vector - будет чуть быстрее.
ещё если t_space_for решает столкновения только между двумя типами объектов то всю эту возню с kind`ами и прочее передёргивание на абстракции типа collider можно выкинуть - тоже будет чуть быстрее, в теории.

MrShoor
> Я хочу посмотреть как ты на своём варианте будешь перебирать соседние ячейки
> грида, и сравнивать всё со всеми в этих соседних ячейках.
почти так же, но можно попробовать только 4 соседа проверять:
{-1,-1},{-0,-1},{-1,-0},{-0,-0}

#102
11:00, 14 июля 2019

Adler
> там можно спрятать почти все тоже самое.
Ты в коде покажи, потому я например не пойму нафига вот такое:
t_space_for_r2c r2c;
Заводить

Adler
> почти так же, но можно попробовать только 4 соседа проверять:
> {-1,-1},{-0,-1},{-1,-0},{-0,-0}
Код покажешь как это сделать на гриде?

#103
12:53, 14 июля 2019

MrShoor
> Держи вот:

А читаем текст мы жопой?

class Node {
  std::vector<Node> _children;
protected:
  vec2 m_pos;
public:
  const vec2& GetPos() { return m_pos; }
  void SetPos(const vec2& newpos) { m_pos = newpos; }
  void UpdateSomeKindOfShit() {
    for(const Node& child: _children) {
      child.m_pos.x = GetSomeXFromSomeOtherShit();
    }
  }
}

И, да, при пользовании сеттером, внезапно, исчезает аргумент
MrShoor
> проще писать a.x += 2 чем a.setX(a.getX()+2);

#104
15:54, 14 июля 2019

MrShoor
> Логично. Где-то используется пила, а где-то лобзик. Там где ненужна
> инакпсуляция - она не нужна. Там где нужна - она нужна.
Соответственно, объектно-ориентированный язык используется там где инкапсуляция нужна, процедурный - там где не нужна. Действительно логично.

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