Массив массивов

Тема в разделе "Arduino & Shields", создана пользователем DrProg, 19 июн 2015.

  1. DrProg

    DrProg Вечный нерд

    Имеется двухмерный массив который объявляется и заполняется при объявлении. Тут все просто и понятно:
    Код (Text):
    byte masRG [8][8] = {
      {1, 1, 1, 1, 1, 1, 1, 1},
      {1, 2, 2, 2, 2, 2, 2, 1},
      {1, 2, 1, 1, 1, 1, 2, 1},
      {1, 2, 1, 0, 3, 1, 2, 1},
      {1, 2, 1, 3, 0, 1, 2, 1},
      {1, 2, 1, 1, 1, 1, 2, 1},
      {1, 2, 2, 2, 2, 2, 2, 1},
      {1, 1, 1, 1, 1, 1, 1, 1}
    };
     
    Но вот потребовалось иметь несколько таких массивов с разными данными, но с возможностью доступа к ним из цикла, то есть имя должно быть одно, индексы разные. Первое что пришло в голову - создать структуру с двумерным массивом внутри и создать массив из таких структур:

    Код (Text):
    struct spryteRG {
    byte mRG [8][8];
    };

    spryteRG spryte [2];
     
    Все замечательно, казалось бы, но вот как заполнить из скетча элементы этого массива массивов? Интуитивно не получилось, гуглование пока что ответа не дало, но чувствую, что он где то в орфографии:

    Код (Text):
    spry[0] = {  <-- не работает
      {1, 1, 1, 1, 1, 1, 1, 1},
      {1, 2, 2, 2, 2, 2, 2, 1},
      {1, 2, 1, 1, 1, 1, 2, 1},
      {1, 2, 1, 0, 3, 1, 2, 1},
      {1, 2, 1, 3, 0, 1, 2, 1},
      {1, 2, 1, 1, 1, 1, 2, 1},
      {1, 2, 2, 2, 2, 2, 2, 1},
      {1, 1, 1, 1, 1, 1, 1, 1}
    };
    Или я зверски путаю инициализацию массива с его заполнением?
     
    Последнее редактирование: 19 июн 2015
  2. Megakoteyka

    Megakoteyka Оракул Модератор

    А что мешает сделать трехмерный массив?
     
  3. iglooshtosser

    iglooshtosser Гик

    Да и вообще n-мерный при необходимости. Можно работать с одномерным массивом как с n-мерным, пересчитывая вычисляя индекс в массиве по n "псевдоиндексов". В памяти они всё равно хранятся линейно.
    Можно пойти дальше и определять размерность массива во время выполнения. Решается или динамическим двусвязным (вообще даже n-связным) списком или динамическим буфером.
     
  4. Unixon

    Unixon Оракул Модератор

    Синтаксис языка так не позволяет делать. При инициализации заполняйте весь массив полностью, а не только один элемент. После инициализации при объявлении больше такое присваивание не работает.
     
  5. DrProg

    DrProg Вечный нерд

    Проблема не в том, чтобы сделать 3х мерный массив, а в том, чтобы его наглядно заполнить. Сейчас вот картинку практически видно, а какая каша получится при трех измерениях?

    Я это уже понял, очень жаль. То есть заполнить массив в таком виде можно только один раз. (
     
  6. geher

    geher Гуру

    Если я правильно понял задачу, то можно сделать примерно примерно так:
    Код (Text):

    #define SET_SPRITE(to,from) memcpy(to,from,sizeof(from));

    typedef byte spryteRG [8][8];

    spryteRG spryte1={
       {1, 1, 1, 1, 1, 1, 1, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 1, 0, 3, 1, 2, 1},
       {1, 2, 1, 3, 0, 1, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 1, 1, 1, 1, 1, 1, 1}
    };
    spryteRG spryte2=
    {
       {5, 1, 1, 1, 1, 1, 1, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 1, 0, 3, 1, 2, 1},
       {1, 2, 1, 3, 0, 1, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 1, 1, 1, 1, 1, 1, 1}
    };

    spryteRG spryte[2];
    А далее по месту, где надо задать значение элемента массива спрайтов, делать
    Код (Text):
      SET_SPRITE(spryte[0],spryte2);
    Естественно, в жизни вместо spryte1 и spryte2 надо использовать осмысленные имена, чтобы было наглядно видно, какой именно спрайт был присвоен элементу массива. И сами спрайты сделать разными.
     
  7. DrProg

    DrProg Вечный нерд

    То есть проинициализировать одноразовые двухмерные массивы, а потом переносить их в массивы с индексами для автоматизированного использования?
     
  8. geher

    geher Гуру

    Может я чего-то недопонимаю в постановке задачи?
    Я полагал, что речь о динамическом присваивании спрайтов элементам массива.
    Например, формирование последовательности спрайтов на основании данных из последовательного порта.

    Если же надо просто изначально инициализировать массив спрайтов, а потом его пользовать, не изменяя, то все делается одним объявлением
    Код (Text):

    byte spryte [2][8][8]={
       {{1, 1, 1, 1, 1, 1, 1, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 1, 0, 3, 1, 2, 1},
       {1, 2, 1, 3, 0, 1, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 1, 1, 1, 1, 1, 1, 1}},
       {{5, 1, 1, 1, 1, 1, 1, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 1, 0, 3, 1, 2, 1},
       {1, 2, 1, 3, 0, 1, 2, 1},
       {1, 2, 1, 1, 1, 1, 2, 1},
       {1, 2, 2, 2, 2, 2, 2, 1},
       {1, 1, 1, 1, 1, 1, 1, 1}}
    };
     
     
  9. DrProg

    DrProg Вечный нерд

    Пятерка в середине имеет какой то смысл?

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

    Unixon Оракул Модератор

    Код (Text):

    typedef uint8_t cubeblock_t[64];
    cubeblock_t cubedata;

    void plotCube(cubeblock_t& data)
    {
      uint8_t ptr = 0;
      // layer 0
      data[ptr++] = B11111111;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B11111111;
      // layer 1-6
      for (uint8_t lay=1; lay<=6; lay++)
      {
        data[ptr++] = B10000001;
        data[ptr++] = B00000000;
        data[ptr++] = B00000000;
        data[ptr++] = B00000000;
        data[ptr++] = B00000000;
        data[ptr++] = B00000000;
        data[ptr++] = B00000000;
        data[ptr++] = B10000001;
      }
      // layer 7
      data[ptr++] = B11111111;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B10000001;
      data[ptr++] = B11111111;
    }

    void plotStar(cubeblock_t& data)
    {
      uint8_t ptr = 0;
      // layer 0
      data[ptr++] = B10000001;
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      data[ptr++] = B00011000;
      data[ptr++] = B00011000;
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      data[ptr++] = B10000001;
      // layer 1
      data[ptr++] = B00000000;
      data[ptr++] = B01000010;
      data[ptr++] = B00000000;
      data[ptr++] = B00011000;
      data[ptr++] = B00011000;
      data[ptr++] = B00000000;
      data[ptr++] = B01000010;
      data[ptr++] = B00000000;
      // layer 2
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      data[ptr++] = B00100100;
      data[ptr++] = B00011000;
      data[ptr++] = B00011000;
      data[ptr++] = B00100100;
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      // layer 3
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      data[ptr++] = B00011000;
      data[ptr++] = B00111100;
      data[ptr++] = B00111100;
      data[ptr++] = B00011000;
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      // layers 4-7
      uint8_t sptr = ptr;
      for (uint8_t lay = 4; lay <= 7; lay++)
      {
        for (uint8_t row = 0; row < 8; row++)
        {
          data[ptr++] = data[--sptr];
        }
      }
    }
     
     
  11. Unixon

    Unixon Оракул Модератор

    Код (Text):

    void plotStar2(cubeblock_t& data)
    {
      uint8_t ptr = 0;
      // layer 0
      data[ptr++] = B00010010;
      data[ptr++] = B10000000;
      data[ptr++] = B00000000;
      data[ptr++] = B00011001;
      data[ptr++] = B10011000;
      data[ptr++] = B00000000;
      data[ptr++] = B00000001;
      data[ptr++] = B01001000;
      // layer 1
      data[ptr++] = B00000000;
      data[ptr++] = B01001010;
      data[ptr++] = B00000000;
      data[ptr++] = B01011000;
      data[ptr++] = B00011010;
      data[ptr++] = B00000000;
      data[ptr++] = B01010010;
      data[ptr++] = B00000000;
      // layer 2
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      data[ptr++] = B00101100;
      data[ptr++] = B00111000;
      data[ptr++] = B00011100;
      data[ptr++] = B00110100;
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      // layer 3
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      data[ptr++] = B00011000;
      data[ptr++] = B00111100;
      data[ptr++] = B00111100;
      data[ptr++] = B00011000;
      data[ptr++] = B00000000;
      data[ptr++] = B00000000;
      // layers 4-7
      uint8_t sptr = ptr;
      for (uint8_t lay = 4; lay <= 7; lay++)
      {
        for (uint8_t row = 0; row < 8; row++)
        {
          data[ptr++] = data[--sptr];
        }
      }
    }
     
     
  12. Unixon

    Unixon Оракул Модератор

    Код (Text):

    #define N_FRAMES 10
    #define DELAY_FRAME 20

    cubeblock_t animation[N_FRAMES];

    void show(cubeblock_t& data)
    {
      uint8_t ptr = 0;
      uint8_t mask = 1;
      for (uint8_t lay = 0; lay < 8; lay++)
      {
        ShiftOut(PIN_LAYER_CLK, PIN_LAYER_DATA, mask);
        digitalWrite(PIN_LAYER_LATCH, LOW); // 595
        digitalWrite(PIN_LAYER_LATCH, HIGH); // 595
        mask <<= 1;
        for (uint8_t row = 0; row < 8; row++)
        {
          ShiftOut(PIN_ROW_CLK, PIN_ROW_DATA, data[ptr++]);
        }
        digitalWrite(PIN_ROW_LATCH, LOW); // 595
        digitalWrite(PIN_ROW_LATCH, HIGH); // 595
      }
    }

    void initAnimation(cubeblock_t *data, int frames)
    {
      for (int i = 0; i < frames; i++)
      {
        // plotFrame(i, data[i]);
      }
    }

    void playAnimation(cubeblock_t *data, int frames, int frame_delay)
    {
      for (int i = 0; i < frames; i++)
      {
        show(data[i]);
        delay(frame_delay);
      }
    }

    void test()
    {
      initAnimation(animation, N_FRAMES);
      playAnimation(animation, N_FRAMES, DELAY_FRAME);
    }
     
     
    Последнее редактирование: 20 июн 2015
  13. DrProg

    DrProg Вечный нерд

    Это первый способ с цветоразделением, который я применил в первую очередь. Он неудобен тем, что картинку труднее составить, менее наглядно получается. Замеры показали, что единый массив обрабатывается медленнее всего на 8%, что не критично, 240 фпс против 260.
     
  14. geher

    geher Гуру

    Никакого особенного смысла. Всего лишь одно из чисел, забиваемых в массив.
    Сам не знаю, как туда пятерка затесалась, заполнение спрайта просто копировалось одно и то же.
     
  15. DrProg

    DrProg Вечный нерд

    Пришел к выводу, что для данной задачи действительно оптимально использовать трехмерный массив. Вот например оформление двух кадров:
    Код (Text):
    byte masRG [2][8][8] = {
      1, 1, 1, 1, 1, 1, 1, 1,
      1, 2, 2, 2, 2, 2, 2, 1,
      1, 2, 0, 0, 0, 0, 2, 1,
      1, 2, 0, 2, 2, 0, 2, 1,
      1, 2, 0, 2, 2, 0, 2, 1,
      1, 2, 0, 2, 2, 0, 2, 1,
      1, 2, 2, 2, 2, 2, 2, 1,
      1, 1, 1, 2, 2, 1, 1, 1,
      2, 1, 1, 1, 1, 1, 1, 2,
      1, 2, 2, 2, 2, 2, 2, 1,
      1, 2, 0, 0, 0, 0, 2, 1,
      2, 2, 0, 3, 3, 0, 2, 2,
      2, 2, 0, 3, 3, 0, 2, 2,
      1, 2, 0, 3, 3, 0, 2, 1,
      1, 2, 2, 2, 2, 2, 2, 1,
      2, 1, 1, 2, 2, 1, 1, 2
    };
     
    Работает довольно быстро, fps на UNO без дополнительной нагрузки порядка 260.
     
  16. Максим B

    Максим B Гуру

    DrProg никак тоже куб собираешь???
     
  17. DrProg

    DrProg Вечный нерд

    Пока что одну его плоскость разве что. )
    Хотя, думаю, что принцип одинаков, только массив будет четырехмерный и не уверен, что Ардуино его потянет.
     
  18. DrProg

    DrProg Вечный нерд

    Пример готового скетча с 4 кадрами (спрайтами) и анимацией из серии "все любят гипножабу". Всем спасибо за советы!
    Код (Text):
    #define DATA_PIN    13
    #define LATCH_PIN  12
    #define CLOCK_PIN  11

    #define kadrTime    100 // мс на кадр
    #define kadrov      4 // колво кадров


    byte masRG [4][8][8] = {
      0, 0, 0, 0, 0, 0, 0, 0, // 1
      0, 1, 1, 1, 1, 1, 1, 0,
      0, 1, 3, 3, 3, 3, 1, 0,
      0, 1, 3, 2, 2, 3, 1, 0,
      0, 1, 3, 2, 2, 3, 1, 0,
      0, 1, 3, 3, 3, 3, 1, 0,
      0, 1, 1, 1, 1, 1, 1, 0,
      0, 0, 0, 0, 0, 0, 0, 0,

      1, 1, 1, 1, 1, 1, 1, 1, //2
      1, 3, 3, 3, 3, 3, 3, 1,
      1, 3, 2, 2, 2, 2, 3, 1,
      1, 3, 2, 0, 0, 2, 3, 1,
      1, 3, 2, 0, 0, 2, 3, 1,
      1, 3, 2, 2, 2, 2, 3, 1,
      1, 3, 3, 3, 3, 3, 3, 1,
      1, 1, 1, 1, 1, 1, 1, 1,

      3, 3, 3, 3, 3, 3, 3, 3, // 3
      3, 2, 2, 2, 2, 2, 2, 3,
      3, 2, 0, 0, 0, 0, 2, 3,
      3, 2, 0, 1, 1, 0, 2, 3,
      3, 2, 0, 1, 1, 0, 2, 3,
      3, 2, 0, 0, 0, 0, 2, 3,
      3, 2, 2, 2, 2, 2, 2, 3,
      3, 3, 3, 3, 3, 3, 3, 3,

      2, 2, 2, 2, 2, 2, 2, 2, // 4
      2, 0, 0, 0, 0, 0, 0, 2,
      2, 0, 1, 1, 1, 1, 0, 2,
      2, 0, 1, 3, 3, 1, 0, 2,
      2, 0, 1, 3, 3, 1, 0, 2,
      2, 0, 1, 1, 1, 1, 0, 2,
      2, 0, 0, 0, 0, 0, 0, 2,
      2, 2, 2, 2, 2, 2, 2, 2
    };


    long unsigned int ts; // таймер кадров
    byte kadrV; // видимый кадр

    // для подсчета fps
    //long unsigned int ttt;
    //unsigned int sss = 0;
    //unsigned int fps = 0;

    void setup() {
      pinMode(DATA_PIN, OUTPUT);
      pinMode(CLOCK_PIN, OUTPUT);
      pinMode(LATCH_PIN, OUTPUT);
      kadrV = 0;
      ts = millis();
    //  Serial.begin(9600);
    }

    void loop() {

      if ((millis() - ts) >= kadrTime) { // циклическое чередование кадров
        kadrV++;
        if (kadrV >= kadrov) kadrV = 0;
        ts = millis();
      }
      setKadr_RG(masRG, kadrV); // отрисовка кадра

    // подсчет fps
    //  fps++;
    //    if ((millis() - ttt) > 2000) {
    //      Serial.println(fps);
    //    while (true);
    //    }

    }
    void setKadr_RG (byte mRG[2][8][8], byte kadr) { // отрисовка кадра
      byte bytSTR;
      byte mR;
      byte mG;
      for (byte s = 0; s <= 7; s++) {
        bytSTR = 0;
        bitSet(bytSTR, s);
        for (byte i = 0; i <= 7; i++) {
          bitWrite(mR, i, !(bitRead(mRG[kadr][s][i], 0)));
          bitWrite(mG, i, !(bitRead(mRG[kadr][s][i], 1)));
        }
        digitalWrite(LATCH_PIN, LOW);
        writeByte(bytSTR);
        writeByte(mR);
        writeByte(mG);
        digitalWrite(LATCH_PIN, HIGH);
      }
    }

    byte writeByte(byte byteW) { // аналог shiftIn, работает чуть быстрее
      for (int i = 7; i >= 0; i--) {
        digitalWrite(DATA_PIN, (bitRead(byteW, i)));
        digitalWrite(CLOCK_PIN, HIGH);
        digitalWrite(CLOCK_PIN, LOW);
      }
    }