Пятница, 29 Марта 2024, 14:09

Приветствую Вас Гость

[ Новые сообщения · Игроделы · Правила · Поиск ]
  • Страница 1 из 1
  • 1
Форум игроделов » Программирование » Delphi/Pascal/Object Pascal » Не получается сделать таймер. (аналог step в GM)
Не получается сделать таймер.
AGENTX001Дата: Понедельник, 12 Декабря 2011, 01:50 | Сообщение # 1
почётный гцупер
Сейчас нет на сайте
Всем привет! Возник вопрос, как в консоли реализовать подобие таймера? Мне нужно, чтобы каждые 3 милисекунды выполнялся код моего сервера... Сделал счётчик, но вместа ождаемого fps = 300, увидел всего 60. Пробовал в делфи 7 и лазарусе, одинаково... Помогите, пжст smile
Code
while (true) do
   begin
   if GetTickCount - t1 >= 3 then
    begin
      t1 := GetTickCount;
      Inc(kol);
      {тут будет код серва}
    end;

   if GetTickCount - t2 >= 1000 then {каждую секунду показываю фпс}
    begin
      t2 := GetTickCount;
      WriteLn('fps: ',kol);
      kol := 0;
    end;
   end;
GECKДата: Понедельник, 12 Декабря 2011, 04:45 | Сообщение # 2
заслуженный участник
Сейчас нет на сайте
Quote (AGENTX001)
но вместа ождаемого fps = 300, увидел всего 60

Значит код серва жрет намного больше времени, чем ожидалось smile

Можешь еще попробовать
Code
while (true) do begin
   {код чего угодно}
   Delay(3); // зажержка
end;


Всё гениальное просто. И хреново работает.
AGENTX001Дата: Понедельник, 12 Декабря 2011, 11:37 | Сообщение # 3
почётный гцупер
Сейчас нет на сайте
Quote (GECK)
Значит код серва жрет намного больше времени, чем ожидалось

Там пока вообще пусто!))
Quote (GECK)
Можешь еще попробовать

Ага, попробую.

Добавлено (12.12.2011, 11:37)
---------------------------------------------
GECK, сапсибо, так действительно лучше!)
ps нет функции delay, есть sleep biggrin

TimKruzДата: Понедельник, 12 Декабря 2011, 13:57 | Сообщение # 4
старожил
Сейчас нет на сайте
Quote (AGENTX001)
как в консоли реализовать подобие таймера?

Можно сделать так называемый "мультимедиа таймер". Кстати, он гораздо надёжнее и точнее обычного компонента-таймера, и чаще используется в играх... Хотя есть более рациональный вариант - в событии "ничего не делания" проверять системное время...
Вот код примера использования мультимедийного таймера:
Code
uses MMSystem; //Модуль с мультимедиа-функциями
var Timer1:Integer; //Идентификатор таймера, с помощью которого происходит управление таймером
//Функция, вызываемая таймером
procedure TimeCallBack(TimerID, Msg: Uint; dwUser, dw1, dw2: DWORD); pascal;
begin
     //Делаем что-нибудь здесь
end;
//Создание таймера
procedure TForm1.Button1Click(Sender: TObject);
begin
      Timer1:=TimeSetEvent(10, {Слева период вызова функции справа в миллисекундах} 0, @TimeCallBack, 0, TIME_PERIODIC);
end;
//Убить таймер
procedure TForm1.FormDestroy(Sender: TObject);
begin
    TimeKillEvent(Timer1);
end;

***
Ну и в консольном режиме тоже можно сделать такое. Подробнее о функции TimeSetEvent читай в интернете.




Сообщение отредактировал TimKruz - Понедельник, 12 Декабря 2011, 14:04
ilnarkoДата: Понедельник, 12 Декабря 2011, 14:19 | Сообщение # 5
был не раз
Сейчас нет на сайте
var
i:integer;

procedure TForm1.Button1Click(Sender: TObject);
begin
i:=5; //Допустим надо отсчитать 5 секунд
Timer1.Enabled:=true; //Запускаем таймер
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
i:=i-1; //Отнимаем по секунде
// Если время закончилось, то останавливаем таймер и показываем сообщение.
if i=0 then
begin
Timer1.Enabled:=false;
ShowMessage('Время истекло');
end;
end;


Сообщение отредактировал ilnarko - Понедельник, 12 Декабря 2011, 14:22
TimKruzДата: Понедельник, 12 Декабря 2011, 14:25 | Сообщение # 6
старожил
Сейчас нет на сайте
ilnarko, эээ, ты предлагаешь использовать компонент TTimer, а он, насколько я понимаю, доступен только в визуальном режиме. А у него консольная программа. Да и тем более - этот компонент довольно-таки не точный и имеет серьёзное ограничение на минимальный период (кажется, 30 мс).

AGENTX001Дата: Суббота, 24 Декабря 2011, 15:55 | Сообщение # 7
почётный гцупер
Сейчас нет на сайте
TimKruz, о май мозг! ну меня в принципе и sleep устраивает!))

Добавлено (24.12.2011, 15:55)
---------------------------------------------
Всем привет, снова вопрос по теме:) Собственно всё вроде как создаётся, НО программа благополучно вылетает, даже не думая выполнять мой цикл...

Code
program lofh;

{$mode objfpc}{$H+}

uses
   MMSystem,
   sysutils,
   windmill,
   windows;

{$R *.res}

var
   step_timer : integer;

procedure MainLoop (uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD); stdcall;
begin
   work();
end;

begin
   WindowIni ('Land Of Hero',640,524,false,false,0,'Cursor.cur');
   GraphicsIni (0,false,COLOR(255,38,27,0));
   SceneManagerIni(525);
   ResourceIni();
   InputIni();
   TextIni('font.png','font.dat',32);

   step_timer := TimeSetEvent(20, 0, @MainLoop, 0, TIME_PERIODIC);
end.          
TimKruzДата: Суббота, 24 Декабря 2011, 16:10 | Сообщение # 8
старожил
Сейчас нет на сайте
AGENTX001, так ты же создаёшь простую программу. Без окна и, что самое важное, обработчика сообщений. Она у тебя после строчки step_timer:=... просто и благополучно завершается, и всё. Не знаю, что делают функции ...Ini (Из модуля windmill? Что-то такое припоминается, но не помню название), но даже если создаётся окно, обработки сообщений нет. Что это вообще за сообщения такие? Сообщения Windows, посылаемые программе (окну), когда пока она "висит" в памяти. Она постоянно (в бесконечном цикле) должна проверять наличие сообщений и обрабатывать их. Минимальная программа Windows на Delphi выглядит так (код из книги "OpenGL в Delphi" М.Краснова):


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

***
В принципе, можно использовать не таймер из MMSystem, а напрямую из WinAPI, если тебе нужна минимальная программа. Там примерно то же, только обработка сообщения таймера (WM_TIMER) происходит в цикле обработки сообщений... Для его создания - SetTimer(указатель на окно, идентификатор таймера, период, указатель на функцию[для обработки в обработчике сообщений - nil]), и для убийства - KillTimer (указатель на окно, идентификатор таймера);




Сообщение отредактировал TimKruz - Суббота, 24 Декабря 2011, 16:19
AGENTX001Дата: Суббота, 24 Декабря 2011, 16:18 | Сообщение # 9
почётный гцупер
Сейчас нет на сайте
Quote (TimKruz)
что делают функции ...Ini

Инициализируют движок
Quote (AGENTX001)
WindowIni ('Land Of Hero',640,524,false,false,0,'Cursor.cur');

Создаёт окно.
Quote (TimKruz)
Собственно, нужно узнать, что и как делает твой движок, и придумать, какой сделать цикл, чтобы программа не завершалась раньше времени.

Пытался while (true) - жутко виснет...(
TimKruzДата: Суббота, 24 Декабря 2011, 16:20 | Сообщение # 10
старожил
Сейчас нет на сайте
Quote (AGENTX001)
Пытался while (true) - жутко виснет...(

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


AGENTX001Дата: Суббота, 24 Декабря 2011, 16:21 | Сообщение # 11
почётный гцупер
Сейчас нет на сайте
TimKruz, а как сделать, при этом не трогая формы? Там у движка начинается жуткий крах, всё глючит так, что капец...
TimKruzДата: Суббота, 24 Декабря 2011, 16:25 | Сообщение # 12
старожил
Сейчас нет на сайте
Quote (AGENTX001)
Создаёт окно.

Видимо, окно-то она создаёт, но без основного окна оно не функционирует... или без цикла обработки сообщений... В любом случае, тут нужно либо копать движок, либо искать инструкции на официальном сайте...
А вот функция
Quote (AGENTX001)
GraphicsIni (0,false,COLOR(255,38,27,0));

обязательно применяется к своему окну движка (которое создаётся WindowIni), или можно применить к любому? Или, возможно, WindowIni может "прикрепляться" к существующему окну, т.е. не создавать новое?


AGENTX001Дата: Суббота, 24 Декабря 2011, 16:33 | Сообщение # 13
почётный гцупер
Сейчас нет на сайте
Quote
GraphicsIni (0,false,COLOR(255,38,27,0));

Прикрепляется к любому, там первый аргумент - хэндл, но если поставить 0, то применется к окну созданному WindowIni

Добавлено (24.12.2011, 16:33)
---------------------------------------------
TimKruz, есть ещё функция RunEngine(@main_procedure), но если юзать её, то баг с графикой, всё ужасно мигает.

TimKruzДата: Суббота, 24 Декабря 2011, 16:36 | Сообщение # 14
старожил
Сейчас нет на сайте
А специального таймера там, случаем, нет?
Quote (AGENTX001)
Прикрепляется к любому, там первый аргумент - хэндл, но если поставить 0, то применется к окну созданному WindowIni

Вот оно! Вот и сделай по примеру минимальное окно, цикл обработки сообщений, и при появлении сообщения wm_create инициализируй движок, прикрепляя графику к своему окну...


AGENTX001Дата: Суббота, 24 Декабря 2011, 16:52 | Сообщение # 15
почётный гцупер
Сейчас нет на сайте
TimKruz, удалось сделать всё гараздо проще!))
Code

program lofh;

{$mode objfpc}{$H+}

uses
   MMSystem,
   sysutils,
   windmill,
   windows;

{$R *.res}

var
   step_timer : integer;

procedure GameLoop ();
begin
   Print('!!!',100,100,1,2,COLOR(255,255,0,0)) {тут Игра}
end;

procedure RenderLoop (uTimerID, uMessage: UINT; dwUser, dw1, dw2: DWORD); stdcall;
begin
   work(); {тут ТОЛЬКО рендер}
end;

begin
   {инициализация двига}
   WindowIni ('Land Of Hero',640,524,false,false,0,'Cursor.cur');
   GraphicsIni (0,false,COLOR(255,0,0,0));
   SceneManagerIni(525);
   ResourceIni();
   InputIni();
   TextIni('font.png','font.dat',32);
   RunEngine(@GameLoop);

   {запуск таймера}
   step_timer := TimeSetEvent(20, 0, @RenderLoop, 0, TIME_PERIODIC);
end.  

Добавлено (24.12.2011, 16:52)
---------------------------------------------
TimKruz, спасибо за время которое на меня потратил!)

TimKruzДата: Суббота, 24 Декабря 2011, 17:12 | Сообщение # 16
старожил
Сейчас нет на сайте
Quote (AGENTX001)
Print('!!!',100,100,1,2,COLOR(255,255,0,0))

Как я понимаю, Print выводит текст на окно? А лишний текст мешать не будет?.. Хотя, конечно, там может быть что-то полезное... Вообще-то надо читать документацию по движку, чтобы всё правильно сделать...
Quote (AGENTX001)
{запуск таймера}

А удалить?.. Хотя, кажется, Windows сама всё чистит...

В принципе, можно вместо
Quote (AGENTX001)
step_timer := TimeSetEvent(20, 0, @RenderLoop, 0, TIME_PERIODIC);

написать
Quote
SetTimer(FindWindow(nil,'Land Of Hero') {или переменная-указатель, если такую можно вытащить из движка}, idTimer {константа}, 20, @RenderLoop)

и тогда выкинуть MMSystem, т.к. это WinAPI-функция... Собственно, у мультимедиа-таймера есть несколько дополнительных возможностей, но тебе же нужен просто таймер. А вот на счёт различия в точности между ними не знаю... Теоретически, API-функции всегда лучше использовать, хотя иногда сложнее...

Quote (AGENTX001)
TimKruz, спасибо за время которое на меня потратил!)

Всегда рад помочь. smile


Форум игроделов » Программирование » Delphi/Pascal/Object Pascal » Не получается сделать таймер. (аналог step в GM)
  • Страница 1 из 1
  • 1
Поиск:

Все права сохранены. GcUp.ru © 2008-2024 Рейтинг