• Entity Component System + ООП подход?

    @MarkusD
    все время мелю чепуху :)
    ECS является подходом декомпозиции не только логики и данных, но и подходом отказа от агрегации и наследования в пользу косвенной композиции. Явной композиции в ECS тоже не предусматривается, а косвенная композиция не намекает на связность или структурированность данных. Косвенная композиция обозначает только наличие каких либо данных по некоторым косвенным признакам.
    Более того, в рамках ECS сторонний код и с данными нормально работать не способен. Для стороннего кода в ECS предусматривается уровень абстракции для чтения и записи данных.

    Это все должно говорить о том, что ООП возможно применять только рядом с ECS и отдельно от ECS, но не вместе с и не внутри модели данных ECS.

    К примеру есть сущность игрок с набором компонентов наследованная от Entity,

    Нет, это сразу будет не ECS. Сущность игрок - это и есть entity, являющаяся эфемерной единицей в мире ECS.
    И методов у entity быть не может. Вся логика сущностей распределена по системам и сильно зависит от имеющихся у сущности компонент.
    Более того. Если ты говоришь о том, что в твоем мире может существовать сущность с характеристикой игрока, таких сущностей в твоем мире может быть до 100% всего ECS мира. Если игрок у тебя должен быть представлен единичной сущностью, значит это уже не сущность, а внешний объект, по ошибке введенный в ECS мир.

    В ECS базовым правилом является то, что в любой момент времени любая сущность может получить или утратить любой компонент.

    Про состояния, пустые компоненты добавлять удалять в entity как флаги что сущность в каком либо состоянии, и отдельные системы для обработки каждого состояния это нормальный подход ?!

    Битовые компоненты - это рядовая оптимизация для хранения пустых компонент. Да, так делают и обеспечивают правильную работу систем, чтобы фильтры компонент одинаково обрабатывали как полноразмерные компоненты, так и битовые тоже.
    Ответ написан
  • Как выполнить POST-запрос через fetch() на localhost?

    @Konf
    Редактирую ответы на 2 + 2 по 4 раза
    Для отображения JSON нужно сперва пропустить запрос через body-parser middleware
    Подробнее тут и тут.

    Рабочий пример


    index.html
    <script>
      fetch('users/', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json;charset=utf-8'
        },
        body: JSON.stringify({ name: 'qwerty', id: 123 })
      })
    </script>


    app.js
    const express = require('express');
    const bodyParser = require('body-parser');
    const path = require('path');
    
    const jsonParser = bodyParser.json();
    const app = express();
    const port = 3000;
    
    app.get('/', (req, res) => {
      res.sendFile(path.join(__dirname + '/index.html'));
    });
    
    app.post('/users', jsonParser, (req, res) => {
      if (!req.body) return res.sendStatus(400);
    
      console.log(req.body);
    
      res.end();
    });
    
    app.listen(port, () => {
      console.log(`Example app listening at http://localhost:${port}`);
    });


    607399ab27689738726389.png
    Ответ написан
    2 комментария
  • Как устроена математика в лутбоксах?

    dollar
    @dollar
    Делай добро и бросай его в воду.
    Математика простая, нужно лишь использовать понятие математического ожидания.

    Каждый предмет имеет некую стоимость либо в рублях, либо в игровой валюте, либо во времени, либо это некий аналог мощи/силы - не важно. Спросите у своего геймдизайнера (балансера), что почём. Прикручивая шанс к предмету, вы как бы уменьшаете его стоимость. То есть если Меч тысячи истин стоит 500 руб, то при шансе 1% его мат. ожидание будет 5 руб, очевидно. Далее просто складываете все мат. ожидания в сундуке - это будет мат. ожидание стоимости сундука, вот и берите его за основу. Затем можете увеличить или уменьшить эту стоимость сундука на некоторую величину, какую захотите, чтобы это было достаточно "честно" для вас. Как по мне, честность здесь сомнительная. Эту математику многие игроки тоже понимают, хотя бы интуитивно (когда шансы видны). Здесь нужна не честность, а баланс. Так что лучше делегировать всю эту математику геймдизайнеру, или кто там у вас отвечает за монетизацию.

    Далее, в геймдеве часто используют как раз-таки, так называемый, нечестный рандом. Он может быть по-разному нечестный, но сути это не меняет. Например, более-менее справедливый вариант: если Меч тысячи истин (с шансом 1%) не выпадает с 200го лутбокса, то игра должна впихнуть его, чтобы игрок был в конце концов счастлив. А если игроку выпал этот Меч тысячи истин, то чтобы он более не выпадал следующие 50 лутбоксов, а то уж больно жирно. В целом, шанс так и остаётся 1%, так что обмана, как такового, нет. Но, конечно, если игроки будут знать эти детали, то начнут абузить вашу систему по-чёрному, что в итоге приведёт к искажению шансов. Как говорится, думайте сами, решайте сами, нужны или не нужны вам заявленные хорошие жирные шансы. Хотя в рамках маркетинга вы, конечно, можете использовать любые слова, но это уже лучше делегировать маркетологу. А здесь в вашем вопросе эти слова слегка неуместны.

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

    Ещё к слову, каждая механика вводится для какой-то цели. Отталкивайтесь от этой цели, когда формируете состав лутбокса и прочие его особенности. То есть задача - добиться поставленной цели, а не просто ввести фичу для галочки. Обезьянничать - плохо. Нужно понимать, зачем в CSGO / DotA существуют лутбоксы и каким образом они делают игру лучше. Может быть, оно вам и не нужно вообще в вашей игре.
    Ответ написан
  • Что такое IO в backend'е веб-приложения?

    jakulov
    @jakulov
    Для веб-приложений имеется ввиду возможность записывать, считывать и отдавать данные. Когда запросов много и много данных – вы не сможете хранить все данные в памяти для быстрого доступа к ним - приходится идти за ними на диск (или на другую машину). Как правило тут и возникает bottle neck. Особенно если у вас с одной машины отдаются и статика и БД тут лежит и логи пишутся со всех возможных мест.
    Ответ написан
    1 комментарий
  • Как массив вокселей 16^3 разделить на массивы по 4*8*8 и получить один из них по id?

    i229194964
    @i229194964
    Веб разработчик
    #include <vector>
    
    const int voxel_size = 16;
    
    std::vector<short> get_voxels_from_chunk(short (*voxels)[voxel_size][voxel_size][voxel_size], int world_length, int chunk_size_x, int chunk_size_y, int chunk_size_z, int chunk_id) {
        std::vector<short> result;
        int chunk_count_x = world_length / chunk_size_x;
        int chunk_count_y = world_length / chunk_size_y;
        int chunk_count_z = world_length / chunk_size_z;
        int chunk_index_x = chunk_id % chunk_count_x;
        int chunk_index_y = (chunk_id / chunk_count_x) % chunk_count_y;
        int chunk_index_z = chunk_id / (chunk_count_x * chunk_count_y);
        int x_offset = chunk_index_x * chunk_size_x;
        int y_offset = chunk_index_y * chunk_size_y;
        int z_offset = chunk_index_z * chunk_size_z;
        for (int i = x_offset; i < x_offset + chunk_size_x; i++){
            for (int ii = y_offset; ii < y_offset + chunk_size_y; ii++){
                for (int iii = z_offset; iii < z_offset + chunk_size_z; iii++){
                    result.push_back(*(*(*(voxels + i) + ii) + iii));
                }
            }
        }
        return result;
    }
    
    int main() {
        short voxels[voxel_size][voxel_size][voxel_size]; // пример массива вокселей
        int world_length = voxel_size;
        int chunk_size_x = 4;
        int chunk_size_y = 8;
        int chunk_size_z = 8;
        int chunk_id = 3; // пример id чанка
        std::vector<short> chunk_voxels = get_voxels_from_chunk(&voxels, world_length, chunk_size_x, chunk_size_y, chunk_size_z, chunk_id);
        // обработка chunk_voxels
        return 0;
    }
    Ответ написан
    1 комментарий