Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > C++ Builder
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 16.05.2010, 14:25   #11
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

С графическим движком удобно работать, когда рисование каждого изображения можно вызвать не по какому-то безликому числу, а по строковому идентификатору (по крайней мере в небольшом проекте). Поэтому можно использовать стандартный контейнер std::map, например, такой:
Код:
std::map<AnsiString, TBitmap*> GameImageList;
Изображение теперь можно рисовать так:
Код:
Form1 -> Canvas -> Draw(PlayerX, PlayerY, GameImageList["PlayerMoveUp"]);
Этот код, конечно, крайне далек от идеального, т.к. и рисовать лучше на буфер, и координаты игрока будут членами класса игрока, да и т.н. "банк текстур" вместе с анимацией лучше сделать отдельными классами.
Собственно, я тут хотел показать только как использовать map. Вообще почитайте про стандартные контейнеры (STL-евские) - очень полезная вещь.
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 16.05.2010, 14:57   #12
Alex Roth
Пользователь
 
Аватар для Alex Roth
 
Регистрация: 15.05.2010
Сообщений: 11
По умолчанию

Спасибо, займусь !
"Один человек может спасти весь мир. При условии, что один человек может этот мир уничтожить." (c)
"Bad side of mind seize my dreams..." (c)
Alex Roth вне форума Ответить с цитированием
Старый 16.05.2010, 18:23   #13
Alex Roth
Пользователь
 
Аватар для Alex Roth
 
Регистрация: 15.05.2010
Сообщений: 11
Злость Проблема с std::map

Собственно, решил попробовать std::map. Написал небольшую прогу, где при нажатии на кнопку из файла '_all' грузится список файлов, и 2 изображения (в файле только 2 прописи) выводятся на экран. Суть проблемы: на экран, как и задумано, выводятся 2 тайла, но они одинаковые. Это изображение, которое в файле прописано последним. Подскажите, в чем ошибка?

Код:
#include <vcl.h>
#include <map>
#pragma hdrstop

#include "Unit2.h"

#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
String DataPath;
int GridWidth, GridHeight;
TRect MapRect;
std::map<AnsiString, Graphics::TBitmap*> TileList;
Graphics::TBitmap *MapBuffer=new Graphics::TBitmap;

__fastcall TForm1::TForm1(TComponent* Owner)
  : TForm(Owner)
{
  DataPath=GetCurrentDir()+"\\";
  GridWidth=32;
  GridHeight=GridWidth;
  MapBuffer->Width=Map->Width;
  MapBuffer->Height=Map->Height;
  MapRect=Rect(0,0,MapBuffer->Width,MapBuffer->Height);
}

void __fastcall TForm1::rTileClick(TObject *Sender)
{        
Graphics::TBitmap *tmp_bmp=new Graphics::TBitmap;
String err_msg;
  TStringList *TextFile=new TStringList();
  String tmp_filename=DataPath+"Tiles\\_all";
  if(FileExists(tmp_filename))
    TextFile->LoadFromFile(DataPath+"Tiles\\_all");
  else
  {
    err_msg="Cannot find file '"+tmp_filename+"'!";
    MessageBox(0, err_msg.c_str(), "ERROR", MB_OK|MB_ICONHAND);
  }
  for(int i=0;i<TextFile->Count;i++)
  {
    String tmp_str=TextFile->Strings[i]; 
    tmp_filename=DataPath+"Tiles\\"+tmp_str+".bmp";
    if(FileExists(DataPath+"Tiles\\"+tmp_str+".bmp"))
    {
      tmp_bmp->LoadFromFile(tmp_filename);
      TileList[tmp_str]=tmp_bmp;
    }
    else
    {
      err_msg="Cannot find file '"+tmp_filename+"'!";
      MessageBox(0, err_msg.c_str(), "ERROR", MB_OK|MB_ICONHAND);
    }
  }
  MapBuffer->Canvas->Draw(0,0,TileList["Sand"]);
  MapBuffer->Canvas->Draw(32,0,TileList["Grass"]);  
  Map->Canvas->CopyRect(MapRect,MapBuffer->Canvas,MapRect);
  tmp_bmp->Free();
  TextFile->Free();
}
"Один человек может спасти весь мир. При условии, что один человек может этот мир уничтожить." (c)
"Bad side of mind seize my dreams..." (c)

Последний раз редактировалось Alex Roth; 16.05.2010 в 18:39.
Alex Roth вне форума Ответить с цитированием
Старый 17.05.2010, 12:14   #14
Alex Roth
Пользователь
 
Аватар для Alex Roth
 
Регистрация: 15.05.2010
Сообщений: 11
По умолчанию

Жаль что никто не может помочь
Попробую разобраться своими силами...
Быть может кто-нибудь из участников форума писал спрайтовые движки?
Хотелось бы посмотреть такой в работе. И вообще, насколько эффективно писать такие вещи на визуале?
"Один человек может спасти весь мир. При условии, что один человек может этот мир уничтожить." (c)
"Bad side of mind seize my dreams..." (c)
Alex Roth вне форума Ответить с цитированием
Старый 17.05.2010, 12:56   #15
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Дело в том, что у вас память под рисунок выделяется всего один раз:
Код:
Graphics::TBitmap *tmp_bmp=new Graphics::TBitmap;
Потом через этот указатель происходит загрузка первого изображения и адрес tmp_bmp запоминается под индексом из первой строки списка картинок. А потом через этот же самый указатель происходит загрузка второго изображения и адрес той же самой области памяти сохраняется под другим индексом.
Нужно просто при загрузке каждого изображения заново выделять память. Примерно так:
Код:
  for(int i=0;i<TextFile->Count;i++)
  {
    Graphics::TBitmap *tmp_bmp=new Graphics::TBitmap;
    String tmp_str=TextFile->Strings[i]; 
    tmp_filename=DataPath+"Tiles\\"+tmp_str+".bmp";
    if(FileExists(DataPath+"Tiles\\"+tmp_str+".bmp"))
    {
      tmp_bmp->LoadFromFile(tmp_filename);
      TileList[tmp_str]=tmp_bmp;
    }
Кстати, выражения вроде
Код:
  tmp_bmp->Free();
  TextFile->Free();
это дельфийская ересь, местный аналог operator delete, поэтому совершенно не нужно его тащить из Delphi, когда в C++ можно записать с помощью всего родного:
Код:
  delete tmp_bmp;
  delete TextFile;
Добавлю, пожалуй, еще свою старую реализацию простенького графического движка, еще без анимации и многих хороших вещей, самого простого. Просто класс хранилища изображений, или "банк текстур", как называет его многоуважаемый Beermonza, плюс двойная буферизация.
Вложения
Тип файла: rar GraphicEngine.rar (1.4 Кб, 14 просмотров)
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 17.05.2010, 13:12   #16
Alex Roth
Пользователь
 
Аватар для Alex Roth
 
Регистрация: 15.05.2010
Сообщений: 11
По умолчанию

Гром, складывается ощущение, что вы единственный, кто работал с такими вещами . Спасибо! Исправил свои ошибки, все работает как надо. А насчет Free() - действительно подсмотрел в Delphi, когда работал на чистом С++ не использовал такие вещи вообще .
"GraphicEngine.h" подключает библиотеку "MyPoint.h" - где ее можно взять?
"Один человек может спасти весь мир. При условии, что один человек может этот мир уничтожить." (c)
"Bad side of mind seize my dreams..." (c)
Alex Roth вне форума Ответить с цитированием
Старый 17.05.2010, 13:26   #17
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Многие из вещей подсмотрены в разделе "СиОИ", просто там в основном пишут на Delphi.
А про MyPoint - совсем забыл. Это я просто сделал структуру для удобства обращения с координатами. Вот весь ее текст:
Код:
//MyPoint.h
#ifndef MYPOINT_H
#define MYPOINT_H

struct MyPoint
   {
   MyPoint(int x = 0, int y = 0);
   int X, Y;
   };

#endif


//MyPoint.cpp
//--------------------------------------------------------------

#pragma hdrstop

#include "MyPoint.h"
//--------------------------------------------------------------
#pragma package(smart_init)

MyPoint::MyPoint(int x, int y):
   X(x), Y(y)
   {
   }
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Старый 19.05.2010, 13:39   #18
Alex Roth
Пользователь
 
Аватар для Alex Roth
 
Регистрация: 15.05.2010
Сообщений: 11
Сообщение Перегруз памяти

Снова проблема :
Код:
void __fastcall TForm1::rTileClick(TObject *Sender)
{
String err_msg,tmp_tilename;
TStringList *TextFile=new TStringList();
String tmp_filename=DataPath+"Tiles\\_all";
  if(FileExists(tmp_filename))
    TextFile->LoadFromFile(DataPath+"Tiles\\_all");
  else
  {
    err_msg="Cannot find file '"+tmp_filename+"'!";
    MessageBox(0, err_msg.c_str(), "ERROR", MB_OK|MB_ICONHAND);
  }
  for(int i=0;i<TextFile->Count;i++)
  {
    Graphics::TBitmap *tmp_tile=new Graphics::TBitmap;
    String tmp_str=TextFile->Strings[i];
    tmp_filename=DataPath+"Tiles\\"+tmp_str+".bmp";
    if(FileExists(tmp_filename))
    {
      tmp_tile->LoadFromFile(tmp_filename);
    }
    else
    {
      err_msg="Cannot find file '"+tmp_filename+"'!";
      MessageBox(0, err_msg.c_str(), "ERROR", MB_OK|MB_ICONHAND);
    }
    for(int x=0;x<tmp_tile->Width/GridWidth;x++)
      for(int y=0;y<tmp_tile->Height/GridHeight;y++)
      {       
        Graphics::TBitmap *tmp_bmp=new Graphics::TBitmap;  //вот злополучный Bitmap
        TRect tmp_rect1,tmp_rect2;
        tmp_bmp->Width=GridWidth;
        tmp_bmp->Height=GridHeight;
        tmp_rect1=Rect(0,0,GridWidth,GridHeight);
        tmp_rect2=Rect(x*GridWidth,y*GridHeight,GridWidth+(x*GridWidth),GridHeight+(y*GridHeight));
        tmp_bmp->Canvas->CopyRect(tmp_rect1,tmp_tile->Canvas,tmp_rect2);
        tmp_tilename=tmp_str+"_"+IntToStr(x)+IntToStr(y);
        TileList[tmp_tilename]=tmp_bmp;
      }
    delete tmp_tile;
  }           
  delete TextFile;
}
Обратил внимание на диспетчер задач:
Изначально мое приложение занимает в памяти ~5900KB
При выполнении функции повышается на ~50KB (при каждом нажатии на кнопку)
Переваливает за ~10000KB - приложению хана.

Ошибка:
Цитата:
Project Project2.exe raised exception class EOutOfResources with message 'Неверный дескриптор.'
Сама ошибка ясна, не понимаю что значит 'Неверный дескриптор.'

Отсюда вопрос - как удалить tmp_bmp. Или как другим способом избавится от заполнения памяти ?
"Один человек может спасти весь мир. При условии, что один человек может этот мир уничтожить." (c)
"Bad side of mind seize my dreams..." (c)

Последний раз редактировалось Alex Roth; 19.05.2010 в 13:40. Причина: лишний код
Alex Roth вне форума Ответить с цитированием
Старый 19.05.2010, 14:48   #19
Гром
Старожил
 
Аватар для Гром
 
Регистрация: 21.03.2009
Сообщений: 2,193
По умолчанию

Так... Пока вообще не понял, зачем несколько раз нажимать на кнопку. Вроде как это загрузчик всех изображений в память?
И еще немного не понял, что здесь происходит? Загружается картинка, разрезается на кусочки и кусочки сохраняются в памяти? Я лично реализовал это по-другому: сохранял в памяти всю картинку целиком, а вырезал нужный кадр из нее прямо во время рисования и тут же удалял. С хранением в виде кучи мелких кадров, наверное, будет быстрее работать, хотя сложность работы, да и объем памяти немного возрастут.
Не берусь судить, какой из способов лучше, да и вопрос тут скорее в удобстве использования.
Что касается собственно пожирания памяти - то все так и должно быть. При каждом запуске загрузки всех картинок выделяется память под новые картинки, а память, выделенная под старые, не освобождается.
Правильно это должно работать следующим образом: в начале работы программы или, как вариант, при загрузке очередной игровой карты, происходит однократная загрузка всех вообще или всех относящихся к данной карте изображений. Во время выхода из программы или при необходимости загрузки новой карты вместо старой (правда, вы можете еще хранить несколько карт в кэше при желании - в этом случае - при необходимости удалить эту карту из кэша чтобы поместить туда новую) происходит очистка соответственно всех изображений вообще или всех изображений данной карты (во втором случае вы просто имеете свой собственный массив изображений карты одновременно с массивом изображений интерфейса и подобных вездесущих).
Есть, конечно, еще вариант проверять, есть ли в map элемент с таким индексом и только тогда выделять память под кадр:
Код:
tmp_tilename=tmp_str+"_"+IntToStr(x)+IntToStr(y);
if (TileList.find(tmp_tilename) != TileList.end())
 {
 Graphics::TBitmap *tmp_bmp=new Graphics::TBitmap;
 //И так далее...
 }
Но это не имеет особого смысла для практического применении, т.к. имена всегда будут одни и те же.
А дескриптор неверный - это, скорее всего, у него просто память закончилась под многочисленные картинки.
Простые и красивые программы - коды программ + учебник C++
Создание игры - взгляд изнутри - сайт проекта
Тема на форуме, посвященная ему же
Гром вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Borland C++ Builder m@rusl@12 C++ Builder 1 25.04.2010 15:47
c++ Borland builder 4ika C++ Builder 1 27.11.2009 20:32
работа со StringGrid(borland C++ builder) Greenoren Помощь студентам 4 20.11.2009 22:57
Проблема с установкой Borland C++ Builder 6!!! seeker78 Помощь студентам 4 21.09.2009 20:04
Borland C++Builder 2007 Sota Софт 1 14.03.2008 20:21