Перейти к содержанию
Fire Monkey от А до Я
  • 0

Стрелковый тир (игра)


denprox

Вопрос

Доброго времени суток! Пытаюсь сделать небольшое приложение в виде игры на тему "Стрелковый тир". Столкнулся с основной проблемой, решение которой обеспечит решение всей задачи, а именно Определение объекта попадания. Проблема в том, что кроме мишеней, могут присутствовать еще укрытия, а в укрытиях могут быть окна. Визуально мы видим как мишень появляется в "окне" и стреляем в нее, но по скольку программно это TImage один за другим, то событие ОнКлик срабатывает для Укрытия (TImage на переднем плане). 

Были такие идеи:

1. Воспользоваться функционалом, который используют для придания окну программы произвольной формы (функция SetWindowRgn() ), но для этого нужно знать Handle объекта 

2. При клике определять позицию курсора, определять какие объекты в этой позиции находятся, и послойно определять точку попадания для каждого объекта по маске. - но боюсь, что этот метод будет не очень быстро работать. 

Буду признателен, если предложите свои идеи, как можно решить такую задачу. Если есть примеры - еще лучше! 

Ссылка на комментарий

Рекомендуемые сообщения

  • 0

как задается укрытие? либо векторным описанием, либо битовой маской.

в первом случае делаем проверку по вхождению в многоугольник(и)

во втором - в маску

тут без ТЗ не очень

P.S.

Я обычно вообще не рассматриваю компоненты в качестве отображения сцены. Вам нужно всего лишь рисовать битмап в нужных координатах. Зачем TImage?

 

Ссылка на комментарий
  • 0

Если игра под Windows, то самый простой выход (по моему мнению) - работа с регионами. Ведь каждый объект это по сути дела какой-то замкнутый полигон, а функции CreatePolygonRgn и PtInRegion еще никто не отменял. А вообще функций для работы с регионами немало, так что почитайте о них на MSDN

Если не хотите использовать WinAPI-шные функции - работайте с полигонами. Мне когда-то очень помогла библиотека AlgLib - из нее можно вытянуть много полезных функций, чтобы самому не реализовывать алгоритмы.

Ссылка на комментарий
  • 0

krapotkin 

Предполагается, что пользователь сам должен создать свой "тренировочный полигон", установить фон, выбрать мишени и укрытия. Для упрощения предлагается нарисовать в Paint мишени/укрытия, как на картинках ниже. По большому большой роли не играет Image это или Bitmap. Для Укрытия красный цвет означает стену, белый (или отсутствие цвета, если это png с альфа каналом) - соответственно окно. Для мишени, у маски несколько цветов, каждый из которых отвечает за определенный балл.  

dnekrasov

На счет регионов, думаю этот вариант подошел бы как нельзя кстати. Но как я уже писал ранее, к примеру для функции SetWindowRgn - нужен хэндл окна (объекта). В VCL к примеру без проблем можно для TPanel применить эту функцию. 

Cover.png

Cover_Mask.png

Target.png

Target_mask.png

Ссылка на комментарий
  • 0

А зачем Вам использовать SetWindowRgn? Если у Вас есть битмапки, то Ваша задача правильно преобразовать их в регионы (HRGN). Создать какой-то класс, который будет сопоставлять эти битмапки и созданные в памяти объекты HRGN + содержать в себе информацию о Z-координате битмапки. Далее отрисовать битмапки на форме. ну и и по клику просто отследить какой регион содержит точку клика, в соответсвии с Z-Order. 

Я понимаю, хочется как раньше - любому TWinControl дал SetWindowRgn - и все ОК, но проблема в том, что в Firemonkey контролы не имеют хэндла да и кидать кучу контролов один на другой с одной целью - определить в какой из них попал клик, по-моему не очень хорошее решение.

Ссылка на комментарий
  • 1

Описание того что нужно как то расплывчато, но вот примерно так можно сделать.

Всего один TImage который используется для отрисовки битмапов.

Видео

Скрытый текст
Скачать видео

 

 и проект 

 

Tire.rar

Ссылка на комментарий
  • 0
29 минут назад, denprox сказал:

Мишени и укрытия заранее не известны.

Сделать так что бы были известны :)

Создай что то типа редактора карт, где пользователь сможет выбрать текстуру, задать размеры и положение, потом сохранить все это в файл.

А потом в игре отрывать его и будет известно все что нужно.

Для примера, создать запись(record)

type
  TMap = record
    Texture: string[255];
    wallRect: TRectF;
    targetRect: TRectF;
    winRect: TRectF;
    RadArr: array[0..3] of Single;
    ClrArr: array[0..3] of TAlphaColor;
  end;

Пользователь во время создания/редактирования карты заполняет его.

...............
var
Map: TMap;
...............
Texture := 'wall.bmp';
wallRect := TRectF.Create(0, 0, 20, 50);
...............
...............

Сохраняем в файл

var
  mStream: TMemoryStream;
begin
 mStream := TMemoryStream.Create;
 mStream.Write(Map, SizeOf(TMap));
 mStream.SaveToFile('maps\tire.dat');
 mStream.Free;
end;

В игре создаем точно такую же запись(record) как и в редакторе, загружаем сохраненный файл с параметрами и заполняем из него запись

var
  mStream: TMemoryStream;
  Map: TMap;
begin
 mStream := TMemoryStream.Create;
 mStream.LoadFromFile('maps\tire.dat');
 mStream.Read(Map, SizeOf(TMap));
 mStream.Free;
end;

В таком случае будут все нужные параметры известны, и примерно так же в играх и делают.

Ссылка на комментарий
  • 0

Мне кажется идея с регионами, звучит попроще. К примеру, если использовать такую функцию: 

function BitmapToRgn(Image: TBitmap): HRGN;
var
  TmpRgn: HRGN;
  x, y: integer;
  ConsecutivePixels: integer;
  CurrentPixel: TColor;
  CreatedRgns: integer;
  CurrentColor: TColor;

  tmpImage:TBitmapData;
begin
  Image.Map(TMapAccess.ReadWrite, tmpImage);

  CreatedRgns := 0;
  Result := CreateRectRgn(0, 0, Image.Width, Image.Height);
  inc(CreatedRgns);

  if (Image.Width = 0) or (Image.Height = 0) then
    exit;

  for y := 0 to Image.Height - 1 do
  begin
    CurrentColor := tmpImage.GetPixel(0,y);

    ConsecutivePixels := 1;
    for x := 0 to Image.Width - 1 do
    begin
      CurrentColor := tmpImage.GetPixel(x,y);

      if CurrentColor = CurrentPixel then
        inc(ConsecutivePixels)
      else
      begin
        // Входим в новую зону
        if CurrentColor = TColorRec.White then
        begin
          TmpRgn := CreateRectRgn(x - ConsecutivePixels, y, x, y + 1);
          CombineRgn(Result, Result, TmpRgn, RGN_DIFF);
          inc(CreatedRgns);
          DeleteObject(TmpRgn);
        end;
        CurrentColor := CurrentPixel;
        ConsecutivePixels := 1;
      end;
    end;

    if (CurrentColor = TColorRec.White) and (ConsecutivePixels > 0) then
    begin
      TmpRgn := CreateRectRgn(x-ConsecutivePixels, y, x, y+1);
      CombineRgn(Result, Result, TmpRgn, RGN_DIFF);
      inc(CreatedRgns);
      DeleteObject(TmpRgn);
    end;
  end;
end;

Только мне пока не ясно, как применить регион к Bitmap'у или, как писал dnekrasov сопоставить Битмап и регион 

 

Ссылка на комментарий
  • 0

брр. да что ж такое то...

изобретите уже "прозрачный" цвет у битмапа и используйте простую проверку - да/нет

еще в win 3.0 спрайты делали дважды отображая картинку с разными режимами CopyMode

с делфи-1 на кнопках битмапы таким образом делали прозрачными

http://www.delphisources.ru/pages/faq/base/copyrect_anim.html

Ссылка на комментарий
  • 0

denprox, твое желание сделать по проще понятно. Но нужно понимать что если ты делаешь проще для себя, то усложняешь все для пользователя :)

Имхо, сделать свой редактор карт будет лучшей идеей, во первых ты будешь точно знать что потом будет загружаться в игру, во вторых упростишь все для пользователя, а это главное :)

Редактор можно сделать примерно по такому принципу.

Скрытый текст

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

Их просто отрисовываем на общем битмапе, который в игре будет грузиться как фон.

Или картинка может быть каким нибудь объектом, например мишенью или стеной. Эти картинки сохраняем отдельно а размеры и координаты сохраняем в файл.

Так же для объектов можно указать какие нибудь действия(которые предусмотрены редактором), например если попали по мишени то она падает.

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

Далее в игре

Скрытый текст

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

Но в случае если загружать карту созданную в редакторе то и тут все сильно облегчается :)

И совсем не обязательно точь в точь следовать моему примеру, то есть отрисовывать все битмапами.

Зная координаты и размеры например мишени, можно по ним создать любой контрол, например TPanel, на нем уже отрисовать картину выбранную пользователем в редакторе.

А уж с контролом потом можно делать что угодно, при этом не зная его хэндла, но зная его координаты :)

Из моего примера видно, что определение того "попала" пуля в нужные координаты или нет используется всего одна функция.

На самом деле все проще чем кажется, к тому же убиваем еще одного зайца, код получается кроссплатформенным.

Хотя тут утверждать не буду, на Токио у меня проекты под андроид не собираются а других девайсов нету :)

 

 

 

Ссылка на комментарий

Присоединяйтесь к обсуждению

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

Гость
Ответить на вопрос...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...