Помощь - Поиск - Пользователи - Календарь
Полная версия: Очень нужна помощь в написании игры! использование bmp в Pascal
Форум «Всё о Паскале» > Pascal, Object Pascal > Написание игр
ninja
Необходимо на паскале написать игрушку-стрелялку, проблема заключается в том что нигде не могу найти описания как в паскаль вставить картинку, желаетельно bmp, используя модуль graph для рисования человечика стандартными процедурами не подходит, т.е. задание заключается именно в том чтобы использовать картинку, помогите оч нужна помощь!!!!!!!
volvo
1) преобразовать картинку в OBJ-файл через BINOBJ (как это делается - см. на форуме, уже было)
2) подключить OBJ как процедуру к программе на Паскале (директивой {$L}, таким образом у тебя изображение уже будет добавлено к EXE-шнику)
3) написать процедуру отображения BMP из памяти, в которую передать адрес подключенной процедуры.

Вот, собственно, и все. Помощь нужна, или сам справишься?

P.S. Ты бы тему переименовал все-таки, а то ее название не очень-то информативно.
ninja
Да если можешь, помоги, буду признателен
volvo
Значит, смотри на последовательность действий...

Дано: файл Walker.BMP, который надо включить в EXE-шник и отобразить потом на экране.
Что делаем:
1) копируем BMP в папку, где установлен сам TurboPascal (чтоб не заморачиваться с путями), и потом из командной строки:
Цитата
F:\Tp70\BIN>binobj walker.bmp walker.obj Walker
- преобразуем его в OBJ-файл... Можешь забрать WALKER.OBJ и закинуть его в папку со своим проектом...
2) берем любой модуль, который способен отобразить BMP-файл (из файла, собственно). Я взял отсюда: Модули для вывода графики. (bmp, Pcx ...) (BMP.PAS). И чуть-чуть корректируем его, чтобы он принимал не название файла, а указатель на участок памяти, и работал с ним точно так же, как и раньше с файлом.
3) в основной программе подключаем OBJ, инициализируем любой нужный режим (я сделал 256 цветов, просто чтобы показать, как оно делается, с 16-ю ты наверняка знаком, раз замахнулся на игрушку), и выводим картинку в двух местах...

Результат - в архиве. Распакуй, откомпилируй и посмотри...
ninja
Спасибо большущее, ща буду разбераться.
ninja
volvo еще не большой вопрос, а можно как нибудь сделать фон картинки прозрачным, т.е. если одну картинку накладывать на другую чтоб обе было видно?
volvo
Цитата
а можно как нибудь сделать фон картинки прозрачным
Там, где выводится очередной пиксель на экран, делай проверку, если выводимый цвет совпадает с цветом фона - ничего не делать. Но для этого придется, скажем, принять за правило, что самый первый пиксель, который должен был бы отобразиться на экране (верхний левый) является "цветом прозрачности", и все пиксели, которые имеют тот же цвет, просто не будут выводиться. Устраивает тебя такой вариант?
ninja
Допусти цвет пекселя может совпадать с цветом фона находящемся внутри тела рисунка, как быть в такой ситуации, и где в модуле осуществляется проверка пикселя.
volvo
Ну вот же:
for yt:= height-1   downto 0 do
begin
move(p^[curr_index], lin8^.Data, width); inc(curr_index, width);
for i:=0 to width-1 do
if (lin8^.data[i]+palOffset) <> TransparentColor then { <--- Вот это добавлено }
putpixel(Xstart+i, Ystart+yt,lin8^.data[i]+palOffset)
end;
, только надо значение цвета для верхнего левого правого (обработка идет сверху вниз, но справа налево) пикселя занести в переменную TransparentColor. (проверить сейчас не могу, набирал прямо здесь)

Тогда все, что НЕ совпадает с цветом фона, будет выводиться, все, что совпадает - будет пропускаться... Идея понятна?
ninja
ага, сейчас попробую сделать
ninja
Возникла небольшая проблема:
При последовательном выводе рисунков, тот рисунок который был выведен первым закрашевается совершенно другими цветами, второй нормальными цветами, если выводить дальше, то предыдущий закрышивается непонятными цветами, т.е. если выводить 2 рисунка первый закрашевается совершенно другими цветами, а второй нормальными, если еще вывести рисунок, то 2й непонятными цветами, а 3й нормальными и т.д.
как испрвить положение?


PROCEDURE ShowImage8(palOffset: integer; xstart,Ystart:WORD);
type
TLin8=record
x,y:word;
data:array[0..1023] of byte;
end;
var
lin8 : ^TLin8;
i : integer;
l,col :longint;
width,height,xt,yt,sizeP :word;
TransparentColor:word;
begin
TransparentColor:=white;
width:=bfh.biwidth;
height:=bfh.biheight;
while (width mod 4)<>0 do inc(width);
{seek(f,bfh.bfoffbits);}
curr_index := bfh.bfOffbits;
sizeP:=sizeof(Tlin8);
getmem(lin8,sizep);
lin8^.X:=bfh.biwidth-1;
lin8^.Y:=0;
for yt:= height-1 downto 0 do
begin
{blockRead(f,lin8^.Data,width);}
move(p^[curr_index], lin8^.Data, width); inc(curr_index, width);
for i:=0 to width-1 do
if (lin8^.data[i]+palOffset) <> TransparentColor then
putpixel(Xstart+i, Ystart+yt,lin8^.data[i]+palOffset)
end;
freeMem(lin8,sizep)
end;
volvo
Цитата
как испрвить положение?
Никак. Это объясняется тем, что у всех рисунков разная палитра, в таком случае НЕтекущие изображения будут менять цвета (если вызывать SetPalette, разумеется). Если же SetPalette убрать, то с самого начала цвета могут быть искажены, но зато при добавлении рисунков никаких "мельканий предыдущих рисунков" не будет...

Либо создавай рисунки так, чтобы у всех была одинаковая палитра, и устанавливай ее только при выводе первого рисунка.
ninja
блин плохо((((( А если попробовать каждому изображению назначить свой индекс, и для каждого создавать свою палитру? У меня просто в игрушке используется примерно 10 рисунков, и все с разной палитрой... как быть даже не знаю...


И еще такой вопрос почему не рботает процедура setbkcolor?


setbkcolor(2);
clearviewport;


и цвет всеравно черный.

P.S. Спасибо тебе огромное что помогаешь!
volvo
Цитата
А если попробовать каждому изображению назначить свой индекс, и для каждого создавать свою палитру?
Это ничего не даст... Палитра может быть только одна в каждый момент времени, если ты меняешь ее для вывода очередного изображения, то она меняется и для всего экрана, т.е., изменения затрагивают и все остальные, ранее выведенные картинки.

Цитата
И еще такой вопрос почему не рботает процедура setbkcolor?
Потому что не работает SetBkColor в 256-цветном режиме под Турбо-Паскалем... В качестве замены могу предложить:
setfillstyle(solidfill, green);
bar(с_нужными_координатами);
, это по крайней мере сработает. Но опять же, при выводе картинки палитра изменится и цвет с зеленого может стать любым другим.
ninja
получается вся работа коту под хвост((((((

если не трудно посмотри плз тут когда вставляю 2 картинки проблема с фоном

Нажмите для просмотра прикрепленного файла


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

 if (lin8^.data[i]+palOffset) <>  TransparentColor then
опять проблема с фоном.

Движение рисунка на стрелки влево-вправо, прыжок - пробел
Нажмите для просмотра прикрепленного файла

как решить проблему даже не представляю, может использовать 16 цветов, другой драйвер, хотя пробывал другие драйвера замечались "глюки" торможения, или формат файла использовать pcx? Но опять же редактировать bmp легче чем pcx, не нашел ни одного редактора чтоб можно было менять количество цветов в pcx, в отличие от bmp.

Заранее спасибо.
volvo
Погоди. А зачем ты рисуешь картинки по отдельности? Рисуй их на одном большом изображении, а когда они будут готовы - просто разрежешь их один раз и всё. Тогда все эти изображения (и фон, и персонаж тоже) будут иметь одну палитру, и никаких проблем с отображением не будет. Вот, смотри:
Нажмите для просмотра прикрепленного файла
(сначала нарисована полная картинка в 24-битном labirynth.bmp, туда же добавишь своего персонажа, потом порезана на части и сконвертирована в формат "256 цветов". При отображении все в порядке...)
ninja
Сделал как ты сказал, сохраняю все объекты на одном рисунке, далее вырезаю каждый объект и вставляю по отдельности, все равно закрашивание идет палитрой последнего объекта



вот рисунок



Нажмите для просмотра прикрепленного файла
volvo
Цитата
Сделал как ты сказал
Я не это сказал... Я сказал
Цитата
сначала нарисована полная картинка в 24-битном labirynth.bmp
. А ты рисуешь в 256-цветном... Есть большая разница, рисовать ли в 256-цветах сразу или конвертировать Paint-ом 24bit -> 8bit. При подобном конвертировании как раз и будет одинаковая палитра... Вот, я взял твой рисунок, скопировал его в Paint, и сохранил как 24-битное изображение. Потом оттуда вырезал 2 фрагмента, сохранил их опять же как 24-битные (через выделение + Copy To...). И только потом - открыл каждый сохраненный кусок и сконвертировал (Save As -> 256 color bitmap) в нужный формат... И, о - чудо ! smile.gif
Нажмите для просмотра прикрепленного файла

Где видно смену палитры? Я не вижу...
ninja
Спасибо!!! все получилось smile.gif
ninja
Сталкнулся с такой проблемой, что при движении картинки оч сильно мерцает экран, как можно это исправить??? Пробовал SetVisualPage и SetActivePage - не помогает.
Пробывал так же ассемблеровскую вставку


Function wait: Integer; Assembler;
Asm
mov dx, $03DA
@@1:
in al,dx
test al,8
jz @@1
End



Еще проблема с исключением цвета, точнее с этим условием:

if (lin8^.data[i]+palOffset) <>  TransparentColor then


задаю цвет

TransparentColor:=getpixel(1,1);


и все равно рисует все цвета


begin

width:=bfh.biwidth;
height:=bfh.biheight;
while (width mod 4)<>0 do inc(width);
{seek(f,bfh.bfoffbits);}
curr_index := bfh.bfOffbits;
sizeP:=sizeof(Tlin8);
getmem(lin8,sizep);
lin8^.X:=bfh.biwidth-1;
lin8^.Y:=0;
TransparentColor:=getpixel(1,1);
for yt:= height-1 downto 0 do
begin

{blockRead(f,lin8^.Data,width);}
move(p^[curr_index], lin8^.Data, width); inc(curr_index, width);
for i:=0 to width-1 do
if (lin8^.data[i]+palOffset) <> TransparentColor then
putpixel(Xstart+i, Ystart+yt,lin8^.data[i]+palOffset)
end;
freeMem(lin8,sizep)
end;

volvo
Цитата
при движении картинки оч сильно мерцает экран, как можно это исправить???
Присоедини тестовый проект, чтоб можно было откомпилировать его и запустить. Интересует, как именно ты двигаешь картинку.
Цитата
задаю цвет
TransparentColor:=getpixel(1,1);

и все равно рисует все цвета
А какой цвет имеет пиксель (1, 1) на экране? Такие цвета точно есть в картинке?
ninja
Движение осуществляется при нажатии клавиш влево-вправо, пробел, клавиш Z и X
При движении меняется координата рисунка по X экран очищается и заново выводяится но у же на новой координате.

Нажмите для просмотра прикрепленного файла

Цвет фиолетовый
volvo
А теперь ответь мне на 2 вопроса:
1) Зачем тебе отображать заново то, что не изменяется? Если у тебя движется только фигура человечка, а сам фон остается неизменным, гораздо проще перед отрисовкой фигуры запомнить изображение ПОД ней (GetMem + GetImage), а потом, вместо того, чтобы перерисовывать всё, просто восстановить изображение (PutImage + FreeMem) и отрисовать фигуру в другом месте.

2) я спрашивал тебя, какой цвет в позиции (1, 1) на экране. Ты сказал "фиолетовый". Можно назвать номер строки и название файла, где пиксел, имеющий координаты (1, 1) становится фиолетовым? Я например этого не вижу, он равен цвету фона, а это - черный (не путать с битмапом, я спрашивал именно про экран, потому что ты сам сделал:
Цитата
TransparentColor:=getpixel(1,1);
, я тебя за язык не тянул, а GetPixel работает именно с изображением на мониторе)... Откуда вывод: все выводится правильно, если TransparentColor будет содержать значение "фиолетовый цвет" - то этот цвет выводиться не будет...
ninja
 TransparentColor:=5;

5- т.к мне нужно исключить фиолетовый цвет которому соответствует цифра 5.

Все вроде получилось, но почему то у меня возникли сомнения что цвета просто совпали 16 и 256 цветов, или все правильно?





P.S. Спасибо тебе!!!
volvo
Цитата
почему то у меня возникли сомнения что цвета просто совпали 16 и 256 цветов
Не знаю, откуда такое сомнение... 5-ый элемент палитры содержит RGB(128, 0, 128, 0), а это именно фиолетовый цвет... Вот такая палитра у Paint-а. Первые 16 ее элементов совпадают с 16-ю цветами BGI-графики.
ninja
При загрузки картинки в память происходит зависание программы либо она просто вылетает, а если запускать через DOS-box просто зависает, никак не пойму из-за чего
 
var
size:word
p:pointer
........
Size:=imagesize(0,0,getmaxX,getmaxY);
getmem(p,size);
getimage(0,0,getmaxx,getmaxy,p^);

volvo
Цитата
никак не пойму из-за чего
Максимальный блок памяти, который можно выделить за один раз - 65520 байт. Скорее всего, ImageSize выдает тебе неправильное значение (правильное просто не помещается в Word и усекается), а потом при попытке GetImage ты "вылезаешь" за пределы выделенной памяти, и портишь другие области памяти.

А все потому, что ты хочешь сохранять ВЕСЬ экран. А зачем? Сохраняй только то, что будет непосредственно под выводимой картинкой (у тебя же есть ее размеры, есть координаты, куда она будет выводиться), это будет требовать гораздо меньше памяти и выполняться будет быстрее.
ninja
Если сохранять изображение только под объектом, то уйдет памяти не меньше, т.к. на экране будет не один движущийся объект, и придется выделять память для каждого! Как быть в данной ситуации?
volvo
Цитата
Если сохранять изображение только под объектом, то уйдет памяти не меньше
А хоть бы и не меньше, но:
1) у тебя будет возможность выделить каждый раз маленький кусок памяти (большой, под весь экран - не выделишь, я объяснил выше, почему)
2) при изменении положения одного объекта будет восстановлен фон под ним, и объект перерисуется в другой позиции (опять с сохранением фона), то есть, при изменении положения одного объекта не будет перерисовываться ВЕСЬ экран, что приведет к уменьшению мерцания...
ninja
Мерцание стало на порядок меньше smile.gif

Еще такой вопрос: что делает процедура FreeMem очищает ли она блок динамической памяти, или просто разрывает связь указателя с этим блоком?

При длительном нажатии клавиш, все начинает подтормаживать. Это может означать заполненость динамической памяти или клавиатурного буфера?
volvo
Цитата
что делает процедура FreeMem очищает ли она блок динамической памяти, или просто разрывает связь указателя с этим блоком?
Освобождает память, разрывая связь переменной с блоком памяти (освобожденная память не очищается, а просто добавляется в список свободных блоком. Следующий GetMem может опять получить этот же участок памяти, если размер позволяет).
Цитата
Это может означать заполненость динамической памяти или клавиатурного буфера?
Это буфер клавиатуры. Можно попробовать избавиться от подтормаживаний путем написания своего обработчика клавиатурного прерывания, но проверить свою идею я смогу только завтра.
ninja
А если уменьшить клавиатурный буфер?


Если тебя не затруднит, помоги решить данную проблему с подтормаживанием.


P.S. буду очень благодарен.
ninja
Появилась такая идея: что если первому адресу клавиатурного буфера присвоить последний адрес? т.е. при каждом попадании значения в буфер, он будет очищаться.


MemW[Seg0040:$1C]:=MemW[Seg0040:$1A]

Lapp
Цитата(ninja @ 10.07.2009 19:29) *
Появилась такая идея: что если первому адресу клавиатурного буфера присвоить последний адрес? т.е. при каждом попадании значения в буфер, он будет очищаться.
Прекрасная идея для любителей музыки типа "бип-бииииииип" smile.gif. Если твоя программа не успевает обрабатывать вводимую информацию, то буфер надо не уменьшать, а увеличивать. В этом и состоит весь смысл буфера. Почему ты решл, что буфер - это вред? Типа придумали его, чтоб осложнять жизнь людям? lol.gif

Но увеличение буфера тоже не выход. Если ты собираешься жать кнопку, пока оно не забьется - оно забьется обязательно smile.gif. Воспринимай сложности с буфером как признак того, что у тебя что-то не так. Тебе надо прогу свою менять. Я бы рекомендовал сделать так.. Когда читаешь символ - читай не один, а сразу все из буфера. И складывай их в свой собственный буфер. При этом ты можешь предусмотреть параметр количества, то есть вместо повторения разных кодов хранить число введенных символов. Например, если ты вводишь:
aaabbbccabcccccc
- а хранишь:
3a3b2c1a1b6c.
При этом программа может распознавать множественные символы и ускоряться - например, рисовать не каждый кадр, а через кадр (если, скажем, коэффициент превышает 10).

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

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


Добавлено через 2 мин.
Да, еще: адреса переменных, хранящих начало и конец буфера, которые ты привел, мне что-то кажутся странными.. Но я мог это забыть.
Archon
Labyrinth Вот от туда можешь взять модуль для клавы, и не мучаться.
ninja
Спасибо, правда я уже написал, прикольный лабиринт smile.gif

Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.