Всем привет! Возник вопрос, как в консоли реализовать подобие таймера? Мне нужно, чтобы каждые 3 милисекунды выполнялся код моего сервера... Сделал счётчик, но вместа ождаемого fps = 300, увидел всего 60. Пробовал в делфи 7 и лазарусе, одинаково... Помогите, пжст
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;
Можно сделать так называемый "мультимедиа таймер". Кстати, он гораздо надёжнее и точнее обычного компонента-таймера, и чаще используется в играх... Хотя есть более рациональный вариант - в событии "ничего не делания" проверять системное время... Вот код примера использования мультимедийного таймера:
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
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
ilnarko, эээ, ты предлагаешь использовать компонент TTimer, а он, насколько я понимаю, доступен только в визуальном режиме. А у него консольная программа. Да и тем более - этот компонент довольно-таки не точный и имеет серьёзное ограничение на минимальный период (кажется, 30 мс).
TimKruz, о май мозг! ну меня в принципе и sleep устраивает!))
Добавлено (24.12.2011, 15:55) --------------------------------------------- Всем привет, снова вопрос по теме:) Собственно всё вроде как создаётся, НО программа благополучно вылетает, даже не думая выполнять мой цикл...
AGENTX001, так ты же создаёшь простую программу. Без окна и, что самое важное, обработчика сообщений. Она у тебя после строчки step_timer:=... просто и благополучно завершается, и всё. Не знаю, что делают функции ...Ini (Из модуля windmill? Что-то такое припоминается, но не помню название), но даже если создаётся окно, обработки сообщений нет. Что это вообще за сообщения такие? Сообщения Windows, посылаемые программе (окну), когда пока она "висит" в памяти. Она постоянно (в бесконечном цикле) должна проверять наличие сообщений и обрабатывать их. Минимальная программа Windows на Delphi выглядит так (код из книги "OpenGL в Delphi" М.Краснова):
Code
program WinMin;
uses Windows, Messages;
const AppName = 'WinMin';
Var Window : HWnd; {Ссылка на окно, позволяет однозначно определить каждое окно.} Message : TMsg; {Сообщение - реакция ядра Windows на какое-либо событие.} WindowClass : TWndClass; {Структура класса окна, включает адрес "оконной" функции, обрабатывающей поступающие от Windows сообщения, атрибуты всех окон, принадлежащих этому классу, т.е. задаются основные свойства класса.}
// Специальная "оконная" функция, обрабатывающая сообщения, посылаемые окну. // Вызывается непосредственно ядром Windows (косвенно-вызываемая - callback function). // Параметры эквивалентны полям структуры типа TMsg. function WindowProc (Window : HWnd; Message, WParam : Word; LParam : LongInt) : LongInt; stdcall; begin WindowProc := 0; // Здесь указывается реакция оконной функции на сообщения Windows. case Message of wm_Destroy : begin {Ядро Windows пытается закрыть окно - обработку этого сообщения нельзя опускать.} PostQuitMessage (0); {Посылает прикладной программе сообщение wm_Quit код 0 - успешное завершение.} Exit; {Выход из текущей процедуры.} end; end; // Все сообщения, не обрабатываемые оконной функцией, передаются функции ядра Windows DefWindowProc. WindowProc := DefWindowProc (Window, Message, WParam, LParam); {DefWindowProc обеспечивает обработку тех сообщений окна, которые не обрабатывает прикладная программа.} end;
// Точка входа в программу, которая получает управление от ядра Windows. begin // Всем полям структуры присваиваются определённые значения (определяются атрибуты окна). with WindowClass do begin Style := cs_HRedraw or cs_VRedraw; {Стиль окна класса: окно будет перерисовываться при изменении его горизонтальных и вертикальных размеров.} lpfnWndProc := @WindowProc; {Указатель на оконную функцию, которая будет обрабатывать все сообщения, посылаемые окну.} cbClsExtra := 0; {Выделенная память, используемая программой по своему усмотрению.} cbWndExtra := 0; {Выделенная память, используемая программой по своему усмотрению.} hInstance := 0; {Ссылка на экземпляр программы, используется ядром Windows для однозначного определения сегмента данных экземпляра программы.} hIcon := LoadIcon (0, idi_Application); {Ссылка на иконку для окна, для отображения минимизированного окна, сейчас - иконка, соответствующая приложению.} hCursor := LoadCursor (0, idc_Arrow); {Ссылка на курсор, сейчас - в виде стрелки.} hbrBackground := GetStockObject (White_Brush); {Ссылка на шаблон заполнения фона для окна.} lpszMenuName := ''; {Ссылка на строку имени меню.} lpszClassName := AppName; {Имя класса.} end; // Регистрация окна с заданными атрибутами. // Параметр функции - структура типа TWndClass, содержащая атрибуты окон данного класса. If RegisterClass (WindowClass) = 0 then Halt (255); {Регистрация невозможна, завершение работы программы.} Window := CreateWindow {Создает окно и возвращает ссылку на окно типа HWnd.} (AppName, {Имя класса, к которому принадлежит создаваемое окно.} 'Win_Min', {Заголовок окна.} ws_OverlappedWindow, {Стиль окна, сейчас - комбинация стилей.} cw_UseDefault, {X - начальная позиция верхнего левого угла, сейчас - значение по умолчанию.} cw_UseDefault, {Y - начальная позиция верхнего левого угла, сейчас - значение по умолчанию.} cw_UseDefault, {Width - начальная ширина окна, сейчас - значение по умолчанию.} cw_UseDefault, {Height - начальная ширина окна, сейчас - значение по умолчанию.} 0, {WndParent - родительское окно данного окна.} 0, {Menu - меню, используемое данным окном.} HInstance, {Instance - указывает на экземпляр программы. этот параметр указывается, чтобы оконная функция имела доступ к сегменту данных программы.} nil); {Param - определяет дополнительную информацию, посылаемую через сообщение wm_Create.} // Окно создано, его необходимо отбразить на экране. ShowWindow (Window, CmdShow); {Отображает или делает невидимым указанное окно.} UpdateWindow (Window); {Указывает прикладной программе, что часть окна нуждается в перерисовке.} // После того, как окно отбражено на экране, управление передаётся циклу обработки сообщений. // GetMessage извлекает сообщения из очереди и помещается в структуру типа TMsg. // Для всех сообщений, отличных от wm_Quit (завершение работы программы), эта // функция возвращает ненулевое значение и цикл продолжает обработку сообщений. while GetMessage (Message, 0, 0, 0) do { GetMessage возвращает сообщение из очереди GetMessagePos } begin // TranslateMessage передает структуру типа TMsg ядру Windows для преобразования сообщений о введенных символах TranslateMessage (Message); {Переводит сообщение виртуальных клавиш в символьное сообщение.} DispatchMessage (Message); {Передает сообщение оконной функции указанного окна.} {После того, как оконная функция обработала сообщение, управление возвращается} {в цикл обработки сообщений.} end;// конец цикла обработки сообщений Halt (Message.wParam); {Программа завершается.} end.
*** Собственно, нужно узнать, что и как делает твой движок, и придумать, какой сделать цикл, чтобы программа не завершалась раньше времени.
*** В принципе, можно использовать не таймер из MMSystem, а напрямую из WinAPI, если тебе нужна минимальная программа. Там примерно то же, только обработка сообщения таймера (WM_TIMER) происходит в цикле обработки сообщений... Для его создания - SetTimer(указатель на окно, идентификатор таймера, период, указатель на функцию[для обработки в обработчике сообщений - nil]), и для убийства - KillTimer (указатель на окно, идентификатор таймера);
Сообщение отредактировал TimKruz - Суббота, 24 Декабря 2011, 16:19
Потому что программа просто выполняет переход в начало пустого цикла каждый такт процессора, следовательно, забивает все ресурсы. Тут нужно делать иначе...
Видимо, окно-то она создаёт, но без основного окна оно не функционирует... или без цикла обработки сообщений... В любом случае, тут нужно либо копать движок, либо искать инструкции на официальном сайте... А вот функция
Quote (AGENTX001)
GraphicsIni (0,false,COLOR(255,38,27,0));
обязательно применяется к своему окну движка (которое создаётся WindowIni), или можно применить к любому? Или, возможно, WindowIni может "прикрепляться" к существующему окну, т.е. не создавать новое?
Прикрепляется к любому, там первый аргумент - хэндл, но если поставить 0, то применется к окну созданному WindowIni
Добавлено (24.12.2011, 16:33) --------------------------------------------- TimKruz, есть ещё функция RunEngine(@main_procedure), но если юзать её, то баг с графикой, всё ужасно мигает.
Прикрепляется к любому, там первый аргумент - хэндл, но если поставить 0, то применется к окну созданному WindowIni
Вот оно! Вот и сделай по примеру минимальное окно, цикл обработки сообщений, и при появлении сообщения wm_create инициализируй движок, прикрепляя графику к своему окну...
Как я понимаю, Print выводит текст на окно? А лишний текст мешать не будет?.. Хотя, конечно, там может быть что-то полезное... Вообще-то надо читать документацию по движку, чтобы всё правильно сделать...
Quote (AGENTX001)
{запуск таймера}
А удалить?.. Хотя, кажется, Windows сама всё чистит...
SetTimer(FindWindow(nil,'Land Of Hero') {или переменная-указатель, если такую можно вытащить из движка}, idTimer {константа}, 20, @RenderLoop)
и тогда выкинуть MMSystem, т.к. это WinAPI-функция... Собственно, у мультимедиа-таймера есть несколько дополнительных возможностей, но тебе же нужен просто таймер. А вот на счёт различия в точности между ними не знаю... Теоретически, API-функции всегда лучше использовать, хотя иногда сложнее...
Quote (AGENTX001)
TimKruz, спасибо за время которое на меня потратил!)