C/C++ - Игра Ксоникс

Ответить
Аватара пользователя
Doom77

C/C++ - Игра Ксоникс

Сообщение Doom77 »

Пишу игру Ксоникс на C. Подскажите как вырезать картинку.



Есть масив

0000000000

0000000000

0000000000

0000000000



Пользователь произвольно ставит 1.



0000000000

0000000000

0000001111

0000001000





0000100000

0000100000

1111100000

0000000000



Как эти элементы поменять на 2?

1111

1000





00001

00001

11111
Аватара пользователя
pva

Re: C/C++ - Игра Ксоникс

Сообщение pva »

Если не прибегать к библиотекам сторонних производителей, например gdi32.dll от микрософт, не пользоваться алгоритмами стандартной библиотеки c++, то код будет выглядеть примерно так:



Код:

Код: Выделить всё

typedef int surf_bit_t;
struct rect_t
{
   int left, top, right, bottom;
}
struct surface_desc
{
  surf_bit_t *begin; // начало данных
  unsigned width, height, stride; // длина, ширина блока, длина строчки
};
void __blt(surface_desc* from, surface_desc* to)
{
    // копирование без проверки исходых данных.
    // чтобы случайно не попортить память при записи, руководствуемся размерами конечной области
    for(surf_bit_t *row_first1=to->begin,
       *row_last1=to->begin+from->stride*to->width,
       *row_first2=from->from->begin;
        row_first1stride, row_first2+=from->stride)
    {
// закомментирован пример кода для копирования,
// можешь поиграться с ним (переделать в закрашивание)
//        for(unsigned col=0; colwidth; ++col)
//        {
//            row_first1[col] = row_first2[col];
//        }
           memcpy(row_first2, row_first1, to->width*sizeof(surf_bit_t));
    }
}
inline int __constraint(int x, int min, int max)
{
   return x < min ? min : (x < max ? x : max);
}
void blt(surface_desc* from, int x, int y, int width, int height, surface_desc* to, int to_x, int to_y)
{
  // более удобный для пользователя интерфейс
  // с проверкой исходных данных
  // вычисляем перекрывающийся прямоугольник для копирования.
  surface_desc from1, to1;
  {
	// пересечение прямоугольника {0, 0, width, height} с
	// исходным изображением, в координатах копируемого окошка
	rect_t rect_src = {
		__constraint(-x, 0, width),
		__constraint(-y, 0, height),
		__constraint(from->width - x, 0, width),
		__constraint(from->height - y, 0, height)},
	// пересечение  {0, 0, width, height} с
	// конечным изображением и сразу с пересечённым исходным rect_src
	  	rect_dest = {
		__constraint(__constraint(-x_to, 0, width), rect_src.left, rect_src.right),
		__constraint(__constraint(-y_to, 0, height), rect_src.top, rect_src.bottom),
		__constraint(__constraint(to->width - x_to, 0, width), rect_src.left, rect_src.right),
		__constraint(__constraint(to->height - y_to, 0, height), rect_src.top, rect_src.bottom)};
	// составляем полётное задание для __blt
	from1.begin  = from->begin + (rect_dest.top + y)*from->stride + rect_dest.left + x;
 	from1.stride = from->stride;
        from1.width  = rect_desc.right - rect_dest.left;
        from1.height = rect_desc.bottom - rect_dest.top;
	to1.begin  = to->begin + (rect_dest.top + to_y)*from->stride + rect_dest.left + to_x;
 	to1.stride = to->stride;
        to1.width  = rect_desc.right - rect_dest.left;
        to1.height = rect_desc.bottom - rect_dest.top;
   }  
   __blt(&from1, &to1);
}
...
// как пользоваться
surf_bit_t screen1_bits[320*200];
surface_desc screen1 = {&screen1_bits, 320, 200, 320};
surf_bit_t screen2_bits[50*100];
surface_desc screen2 = {&screen2_bits, 50, 100, 50};
...
blt(&screen1, 100, 100, 60, 60, &screen2, 10, 10);

если внутри __blt заменить memcpy на memset, то получится "закрашивание". Рекомендую почитать в сторону функции BitBlt от винды. Если surf_bit_t - 8 битный, то можно сделать 8-битные картинки в памяти и смело пользоваться функциями GDI
Аватара пользователя
Doom77

Re: C/C++ - Игра Ксоникс

Сообщение Doom77 »

Не могу разобраться в коде не могли бы вы упростить код или объяснить доходчивей
Аватара пользователя
Doom77

Re: C/C++ - Игра Ксоникс

Сообщение Doom77 »

Цитата Doom77:



не могли бы вы упростить код
C/C++ - Игра Ксоникс




только если подняться на высокий уровень (С++).

Добавил комментариев



Код:

Код: Выделить всё

// это чтобы можно было легко подменить тип-носитель
// для "цвета" ячейки
typedef int surf_bit_t;
struct rect_t
{
    // прямоугольник - понадобится для пересечений
   int left, top, right, bottom;
}
// стркуктура, которая указывает, в каком виде хранится картинка.
// данные хранятся в виде линейного массива определённой ширины строчки
//                     на картинке нарисован массив, у которого stride = 6,
//     x x x x x x     width = 4, height = 3. Можно сказать, что мы работаем
//     x x 1 1 1 1                   с большим массивом 6x5, а можно что с
//     x x 1 0 0 0     1 1 1 1 ? ?   маленьким 4x3, строчки которого
//     x x 1 0 0 0     1 0 0 0 ? ?   расположены через 6 элементов.
//     x x x x x x     1 0 0 0 ? ?   begin в последнем случае указывает на
//                                   начало "маленького" массива.
struct surface_desc
{
  surf_bit_t *begin; // начало данных
  unsigned width, height, stride; // длина, ширина блока, длина строчки
};
void __blt(surface_desc* from, surface_desc* to)
{
    // функция НЕ ПОЗВОЛЯЕТ копировать в себя, то есть когда from и to могут пересекаться.
    // копирование без проверки исходых данных.
    // чтобы случайно не попортить память при записи, руководствуемся размерами конечной области
    // эта функция используется как внутренняя, исходные данные должны быть уже проверены.
    // в качестве аргументов получает поверхности экрана, описанные выше (surface_desc)
    // row_first1 пробегает строчки, куда копировать, от начала до конца, с шагом stride
    // row_last1 - это и есть конец (посчитали и запомнили)
    // row_first1 пробегает строчки, откуда копировать, с шагом stride
    for(surf_bit_t *row_first1=to->begin,
       *row_last1=to->begin+from->stride*to->width,
       *row_first2=from->from->begin;
        row_first1stride, row_first2+=from->stride)
    {
        // закомментирован пример кода для копирования,
        // можешь поиграться с ним (переделать в закрашивание)
        for(unsigned col=0; colwidth; ++col)
        {
            // копирование
            row_first1[col] = row_first2[col];
            // а это могло бы быть закрашивание
            // row_first1[col] = 2;
        }
        // простейший случай - просто копирование памяти. Сэкономил код функцией
        //   memcpy(row_first2, row_first1, to->width*sizeof(surf_bit_t));
    }
}
inline int __constraint(int x, int min, int max)
{
    // ограничивает значение x - прибмвает к одному из порогов.
    // нужно для пересечения прямоугольников
   return x < min ? min : (x < max ? x : max);
}
//                                          функция, которая вычисляет аргументы для __blt
//     x x x x x x                          по заданным исходному прямоугольнику и конечной
//     x x 1 1 1 1        y 1 1 1 1 y y     точке, куда содержимое этого прямоугольника
//     x x 1 0 0 0  ->    y 1 0 0 0 y y     скопировать.
//     x x 1 0 0 0        y 1 0 0 0 y y     Надо учесть случаи, когда часть прямоугольника
//     x x x x x x                          будет выходить за пределы исходного или
//                                          конечного экранов. Для этого сделаем следующее:
// (1) пересчитаем координаты прямоугольников экранов в координатах исходного и конечного
// прямоугольника, (2) пересечём их с исходным и конечным прямоугольником. Затем (3)
// пересечём что получилось между собой. Получится прямоугольник (4), который и надо
// копировать. Пересчитаем его в координатах экранов (5), запишем в виде поверхностей (6) и
// отдадим функции __blt
//
//  (0,0)              (0,0)                  (0,0)
//    +---+ (w,0)        +---+ (w,0)            +---+ (w,0)
//    |   |              |   |                  |   |
//    |  x|x x x         |y y|y y y     ->      |  N|    область, которая_
//    |  x|x x x         |y y|y y y             |  N|    будет скопирована
//    +--x+x x x         +y-y+y y y             +--N+
// (0,h) x x x x      (0,h)                  (0,h)
//
void blt(surface_desc* from, /*поверхность-откуда*/
        int x, int y,  /*координаты, откуда копировать*/
        int width, int height,  /*размеры окошка*/
        surface_desc* to, /*поверхность-куда*/
        int to_x, int to_y) /*координаты куда*/
{
  // более удобный для пользователя интерфейс
  // с проверкой исходных данных
  // вычисляем перекрывающийся прямоугольник для копирования.
  surface_desc from1, to1;
  {
    // пересечение прямоугольника {0, 0, width, height} с
    // исходным изображением, в координатах копируемого окошка
    rect_t rect_src = {
        /*2*/__constraint(/*1*/-x, 0, width),
        /*2*/__constraint(/*1*/-y, 0, height),
        /*2*/__constraint(/*1*/from->width - x, 0, width),
        /*2*/__constraint(/*1*/from->height - y, 0, height)},
    // пересечение  {0, 0, width, height} с
    // конечным изображением и сразу с пересечённым исходным rect_src
        rect_dest = /*4*/{
        /*3*/__constraint(/*2*/__constraint(/*1*/-x_to, 0, width), rect_src.left, rect_src.right),
        /*3*/__constraint(/*2*/__constraint(/*1*/-y_to, 0, height), rect_src.top, rect_src.bottom),
        /*3*/__constraint(/*2*/__constraint(/*1*/to->width - x_to, 0, width), rect_src.left, rect_src.right),
        /*3*/__constraint(/*2*/__constraint(/*1*/to->height - y_to, 0, height), rect_src.top, rect_src.bottom)};
    // составляем полётное задание для __blt
    from1.begin  = /*6*/from->begin + (/*5*/rect_dest.top + y)*from->stride + /*5*/rect_dest.left + x;
    from1.stride = /*6*/from->stride; /*сохраняется для подобласти*/
    from1.width  = /*6*/rect_desc.right - rect_dest.left;
    from1.height = /*6*/rect_desc.bottom - rect_dest.top;
    to1.begin  = /*6*/to->begin + (/*5*/rect_dest.top + to_y)*from->stride + /*5*/rect_dest.left + to_x;
    to1.stride = /*6*/to->stride;     /*сохраняется для подобласти*/
    to1.width  = /*6*/rect_desc.right - rect_dest.left;
    to1.height = /*6*/rect_desc.bottom - rect_dest.top;
   }
   __blt(&from1, &to1);
}
// как пользоваться_
// где-то в программе выделена память под экран, сделано описание для этой памяти:
surf_bit_t screen1_bits[/*width*/320 * /*height*/200];
surface_desc screen1 = {/*begin*/ &screen1_bits, /*width*/320, /*height*/200, /*stride=width*/320};
surf_bit_t screen2_bits[/*width*/50 * /*height*/100];
surface_desc screen2 = {/*begin*/ &screen2_bits, /*width*/50, /*height*/100, /*stride=width*/50};
// в том месте, где надо скопировать делаем так:
// копируем прямоугольник 60x60 из точки (100,100) в (10,10) на другом экране
blt(&screen1, 100, 100, 60, 60, &screen2, 10, 10);
Ответить

Вернуться в «Программирование и базы данных»