Будет ли завершена разработка игры?
Будет ли завершена разработка игры?
Оу, как же мне повезло расписал тут всё подробненько, а сайт выдал ошибку - пишу заново. Но впрочем нет худа без добра, не буду вас, ребят, загружать своими сложностями и нюансами, буду краток:
Общение комп - электроника происходит по USB, с передачей одно байтных слов друг за дружкой (до 20-ти слов в цепочке). Поэтому передаваемых данных мало. Расчёт чаще - сравнение одного числа с другим. И такое сравнение даже проще вшить в электронику (что мы в основном и делает), то есть расчётами пренебрегаем.
Электроника готова к "общению" с компьютером каждые 40 мкс (а то и каждую 1 мкс). Честно, не знаю сколько времени нужно языку на "подготовку к общению", но на Delphi приходится между командами послать\принять ставить секундную задержку, иначе данные "проходят мимо". Впрочем мне кажется тут больше влияет пропускная способность USB модуля, а не язык.
Общение комп - электроника происходит по USB, с передачей одно байтных слов друг за дружкой (до 20-ти слов в цепочке). Поэтому передаваемых данных мало. Расчёт чаще - сравнение одного числа с другим. И такое сравнение даже проще вшить в электронику (что мы в основном и делает), то есть расчётами пренебрегаем.
Электроника готова к "общению" с компьютером каждые 40 мкс (а то и каждую 1 мкс). Честно, не знаю сколько времени нужно языку на "подготовку к общению", но на Delphi приходится между командами послать\принять ставить секундную задержку, иначе данные "проходят мимо". Впрочем мне кажется тут больше влияет пропускная способность USB модуля, а не язык.
Будет ли завершена разработка игры?
Можно кнопочку "Назад" в браузере нажать, всё вернётся. И текст в форме тоже. По крайней мере у меня в "Опера" так.
Ну и уже наученный горьким опытом, даже несмотря на наличие такой возможности стараюсь перестраховаться и копирую в буфер текст до отправки формы. Делается это быстро (Ctrl+A, Ctrl+C).
Будет ли завершена разработка игры?
Malin писал(а): ↑19 апр 2013, 18:46Общение комп - электроника происходит по USB, с передачей одно байтных слов друг за дружкой (до 20-ти слов в цепочке). Поэтому передаваемых данных мало. Расчёт чаще - сравнение одного числа с другим. И такое сравнение даже проще вшить в электронику (что мы в основном и делает), то есть расчётами пренебрегаем.
Электроника готова к "общению" с компьютером каждые 40 мкс (а то и каждую 1 мкс). Честно, не знаю сколько времени нужно языку на "подготовку к общению", но на Delphi приходится между командами послать\принять ставить секундную задержку, иначе данные "проходят мимо". Впрочем мне кажется тут больше влияет пропускная способность USB модуля, а не язык.
ну... если расчетов зверских нет (а "сравнение одного числа с другим" это не тот расчет, который можно назвать сложным)... то особой скорострельности тут и не надо (т.е. с++ здесь не поможет)...
проблема скорее в том, что делфи требуется много времени (вот это - "но на Delphi приходится между командами послать\принять ставить секундную задержку")...
и то много... обычно пишут 60 мсек... т.е. можно попробовать поставить задержку не 1 сек, а где-то около 100 мсек... если данные будут теряться, то тут скорее всего с++ вообще не поможет... тут уже скорость usb-портов (имхо)...
Оффтоп
возникает такой вопрос... вы в делфи пишете консольное приложение или с формами? по идее в консольном не должно быть таких задержек...
ну и вот это попробовать можно:
[SPOILER="Как реализовать сверхточный таймер?
"]
Windows is not a real time operating system so it is not really able to reliably achieve high accuracy timing without using a device driver. The best I have been able to get is a few nanoseconds using QueryPerformanceCounter. This is the procedure I use:
Код: Выделить всё
var
WaitCal: Int64;
procedure Wait(ns: Integer);
var
Counter, Freq, WaitUntil: Int64;
begin
if QueryPerformanceCounter(Counter) then
begin
QueryPerformanceFrequency(Freq);
WaitUntil := Counter + WaitCal + (ns * (Freq div 1000000));
while Counter < WaitUntil do
QueryPerformanceCounter(Counter);
end
else
Sleep(ns div 1000);
end;
To get improved accuracy do this a little while before using Wait()
Код: Выделить всё
var
Start, Finish: Int64;
Application.ProcessMessages;
Sleep(10);
QueryPerformanceCounter(Start);
Wait(0);
QueryPerformanceCounter(Finish);
WaitCal := Start - Finish;
A trick I have found to increase the reliability of this on my computer is to call Wait like this:
Код: Выделить всё
Application.ProcessMessages;
Sleep(0);
DoSomething;
Wait(10);
DoSomethingElse;
****
Код: Выделить всё
Unit Counter; (* Written by Jin *)
{$O-,F-,S-,N-,R-,Q-}
Interface
Type
tTimerValue = record
Micro: Word; { Счётчик 8253/8254 }
Counter: Longint { Счётчик BIOS }
End;
Const
MicroFreq = 1193181 { $1234DD }; { Частота обновления счётчика Micro (1/сек) }
CounterFreq = MicroFreq / 65536; { Частота обновления счётчика Counter (1/сек) }
MicroInterval = 1 / MicroFreq; { Интервал обновления счётчика Micro (сек) }
CounterInterval = 1 / CounterFreq; { Интервал обновления счётчика Counter (сек) }
Var
BIOSCounter: Longint absolute $0040:$006C;
{ Системный счётчик (обновляется CounterFreq раз/сек, }
{ то есть каждые CounterInterval секунд) }
Procedure InitTimer;
{ Инициализировать таймер (перевести в нужный режим работы). }
{ Эту процедуру необходимо выполнять перед использованием функций }
{ и процедур для получения значения таймера (или счётчика), если }
{ Вы в своей программе изменили режим работы таймера. В противном }
{ случае эта процедура Вам не понадобится, так как она выполняется }
{ в секции инициализации модуля (сразу после запуска программы) ! }
Procedure GetTimerValue(var Timer: tTimerValue);
{ Записать значение таймера в переменную Timer }
Function GetTimerSec: Real;
{ Получить значение таймера в секундах (с точностью до 1 мкс) }
Function GetTimerMillisec: Longint;
{ Получить значение таймера в миллисекундах }
Procedure GetTimerDifference(var Older, Newer, Result: tTimerValue);
{ Записать разницу значений Newer и Older в переменную Result }
Function GetTimerDifSec(var Older, Newer: tTimerValue): Real;
{ Получить разницу значений Newer и Older в секундах }
Function GetTimerDifMillisec(var Older, Newer: tTimerValue): Longint;
{ Получить разницу значений Newer и Older в миллисекундах }
Function ConvTimer2Sec(var Timer: tTimerValue): Real;
{ Получить количество секунд по значению переменной Timer }
Function ConvTimer2Millisec(var Timer: tTimerValue): Longint;
{ Получить количество миллисекунд по значению переменной Timer }
Procedure ConvSec2Timer(Sec: Real; var Timer: tTimerValue);
{ Преобразовать значение секунд Sec типа Real в тип tTimerValue }
Procedure ConvMillisec2Timer(Millisec: Longint; var Timer: tTimerValue);
{ Преобразовать значение миллисекунд Millisec типа Longint в тип tTimerValue }
Procedure ResetCounter;
{ Сбросить счётчик (то есть принять текущее значение таймера за ноль для }
{ процедуры GetCounterValue и функции GetCounterSec) }
Procedure GetCounterValue(var Timer: tTimerValue);
{ Записать значение счётчика в переменную Timer }
Function GetCounterSec: Real;
{ Получить значение секунд счётчика }
Function GetCounterMillisec: Longint;
{ Получить значение миллисекунд счётчика }
Procedure Delay(MS: Word);
{ Задержка MS миллисекунд (1 сек = 1000 мс) }
Procedure DelaySec(Sec: Real);
{ Задержка Sec секунд }
Procedure MDelay(N: Longint);
{ Задержка N * MicroInterval секунд (приближённо N * 0.838095813 мкс). }
{ Если Вам нужны наиболее точные короткие задержки, лучше использовать }
{ эту процедуру, так как она даёт наименьшую погрешность по сравнению }
{ с двумя предыдущими процедурами. }
Implementation
Var Now: tTimerValue;
Var Zero: tTimerValue;
Procedure InitTimer; assembler;
Asm
mov al,34h { Режим 2 таймера 0 }
out 43h,al
xor al,al { 65536 циклов до IRQ }
out 40h,al
out 40h,al
End
Procedure GetTimerValue; assembler;
Asm
cld
xor ax,ax
mov es,ax
mov bx,46Ch { DS:BX = 0000h:046Ch = Таймер BIOS }
cli
mov dx,es:[bx]
mov cx,es:[bx+2]{ CXX = Первое значение таймера BIOS }
sti
out 43h,al { Замораживаем таймер 8253/8254 }
cli
mov si,es:[bx]
mov di,es:[bx+2]{ DI:SI = Второе значение таймера BIOS }
in al,40h
mov ah,al
in al,40h
sti
xchg ah,al { AX = Таймер 8253/8254 }
not ax { Обратный отсчёт -> Прямой отсчёт }
cmp dx,si { Первое значение таймера BIOS равно второму значению ? }
je @Ok { Да! Оставляем как есть (CXX), иначе... }
or ax,ax { Таймер BIOS изменился после заморозки таймера 8253/8254 (между OUT и CLI) ? }
js @Ok { Да! Оставляем как есть (CXX), иначе... }
mov dx,si
mov cx,di { CXX = DI:SI, если таймер BIOS изменился между STI и OUT }
@Ok:
les di,Timer
stosw { Low Word }
xchg ax,dx
stosw { Middle Word }
xchg ax,cx
stosw { High Word - Записаны из CXX:AX }
End
Function GetTimerSec;
Begin
GetTimerValue(Now);
GetTimerSec := ConvTimer2Sec(Now)
End;
Function GetTimerMillisec;
Begin
GetTimerMillisec := Trunc(GetTimerSec*1000)
End;
Procedure GetTimerDifference; assembler;
Asm
cld
push ds
lds si,Newer
lodsw { Low Word }
xchg cx,ax
lodsw { Middle Word }
xchg dx,ax
lodsw { High Word }
xchg cx,ax { Прочитаны в CXX:AX }
lds si,Older
sub ax,[si]
sbb dx,[si+2]
sbb cx,[si+4] { Вычитаем Older из Newer }
les di,Result
stosw { Low Word }
xchg ax,dx
stosw { Middle Word }
xchg ax,cx
stosw { High Word - Записано из CXX:AX }
pop ds
End
Function GetTimerDifSec;
Begin
GetTimerDifference(Older, Newer, Now);
GetTimerDifSec := ConvTimer2Sec(Now)
End;
Function GetTimerDifMillisec;
Begin
GetTimerDifMillisec := Trunc(GetTimerDifSec(Older, Newer)*1000)
End;
Function ConvTimer2Sec;
Begin
ConvTimer2Sec := (Timer.Counter*65536 + Timer.Micro) / MicroFreq
End;
Function ConvTimer2Millisec;
Begin
ConvTimer2Millisec := Trunc(ConvTimer2Sec(Timer)*1000)
End;
Procedure ConvSec2Timer;
Begin
Timer.Counter := Trunc(Sec * CounterFreq);
Timer.Micro := Trunc(Sec * MicroFreq) mod 65536
End;
Procedure ConvMillisec2Timer;
Begin
Timer.Counter := Trunc(Millisec/1000 * CounterFreq);
Timer.Micro := Trunc(Millisec/1000 * MicroFreq) mod 65536
End;
Procedure ResetCounter;
Begin
GetTimerValue(Zero)
End;
Procedure GetCounterValue;
Begin
GetTimerValue(Timer);
GetTimerDifference(Zero, Timer, Timer)
End;
Function GetCounterSec;
Begin
GetTimerValue(Now);
GetTimerDifference(Zero, Now, Now);
GetCounterSec := ConvTimer2Sec(Now)
End;
Function GetCounterMillisec;
Begin
GetCounterMillisec := Trunc(GetCounterSec*1000)
End;
Procedure Delay;
Var Zero: Longint;
Begin
If MS <= 0 then Exit;
Zero := GetTimerMillisec;
Repeat
Until GetTimerMillisec-Zero >= MS
End;
Procedure DelaySec;
Var Zero: Real;
Begin
If Sec <= 0 then Exit;
Zero := GetTimerSec;
Repeat
Until GetTimerSec-Zero >= Sec
End;
Procedure MDelay;
Label Check;
Var Zero: tTimerValue;
Begin
If N <= 0 then Exit;
GetTimerValue(Zero);
Check:
GetTimerValue(Now);
GetTimerDifference(Zero, Now, Now);
Asm
mov ax,word ptr Now
mov dx,word ptr Now+2 { DX:AX - Прошедшее время }
{ mov cx,word ptr Now+4
or cx,cx
jnz @Exit}
cmp dx,word ptr N+2 { Проверяем старшие слова }
jb Check
cmp ax,word ptr N { Проверяем младшие слова }
jb Check
@Exit:
EndEnd;
Begin
InitTimer
End.
И вот ещё программа-тестер:
Код: Выделить всё
Uses Counter;
Var
Ans: Char;
i: Longint;
Sec: Real;
Begin
Asm
mov ah,0Dh
int 21h { Сбрасываем кэш }
mov ax,1681h
int 2Fh { Запрещаем Windows Task Switch }
End
Write('Без задержки...');
ResetCounter;
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('1000 раз холостой цикл...');
ResetCounter;
For i := 1 to 1000 do ;
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('1000 раз по 0 сек...');
ResetCounter;
For i := 1 to 1000 do
DelaySec(0);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
WriteLn('-------------------------------------------------');
Write('1 раз 1 сек...');
ResetCounter;
DelaySec(1);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('1000 раз по 0.001 сек...');
ResetCounter;
For i := 1 to 1000 do
DelaySec(0.001);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('10000 раз по 0.0001 сек...');
ResetCounter;
For i := 1 to 10000 do
DelaySec(0.0001);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('100000 раз по 0.00001 сек...');
ResetCounter;
For i := 1 to 100000 do
DelaySec(0.00001);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('119318 раз по 1/119318.1 сек...');
ResetCounter;
For i := 1 to 119318 do
MDelay(10);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
WriteLn('-------------------------------------------------');
Write('Запускать тесты по микросекундам (м.б. очень долгими) [Y/N] ? : ');
Asm
@Repeat:
xor ah,ah
int 16h
or al,20h
cmp al,'y'
je @Ok
cmp al,'n'
jne @Repeat
@Ok:
mov Ans,al
End
WriteLn(Ans);
If Ans = 'y' then
Begin
Write('1000000 раз по 0.000001 сек...');
ResetCounter;
For i := 1 to 1000000 do
DelaySec(0.000001);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек');
Write('1193181 раз по 1/1193181 сек...');
ResetCounter;
For i := 1 to 1193181 do
MDelay(1);
Sec := GetCounterSec;
WriteLn(#8#8#8': прошло ', Sec: 0: 6, ' сек')
End;
Asm
mov ax,1682h
int 2Fh { Разрешаем Windows Task Switch }
EndEnd.
Не забывайте, что погрешности, которые будет выдавать программа-тестер будут из-за того, что какое-то время тратиться на вызов процедуры, циклы и т.д. (т.к. там используются процедуры DelaySec, MDelay).... Но если вызвать ResetCounter, а через некоторое время GetCounterSec, то результат будет точным (собственно, именно так здесь и измеряются погрешности)! И можно вызывать его (GetCounterSec) ещё хоть 10000 раз! ;D
Кстати, запускайте тестер только в полноэкранном режиме, т.к. программа отключает многозадачность Windows, и на экране вы ничего не увидите (будет впечатление, что прога повисла).
[/SPOILER]
Как отчитывать промежутки времени с точностью, большей чем 60 мсек?
О таймере
Будет ли завершена разработка игры?
Формами) мы там всё не ахти какие программисты. Намёк понял, надо будет попробовать консольно.
Да, мне тоже так кажется.
Snake_B, спасибо! Будем разбираться.
Будет ли завершена разработка игры?
создаете консольный проект....
там будет такая строчка: "{$APPTYPE CONSOLE}", её удаляете... и программа вообще не будет ни как себя показывать.... если надо уже MessageBox() делаете..
Будет ли завершена разработка игры?
С сверхчувствительных фотодетекторов, но это не важно)
То есть вообще не будет никакого окна? Но нам нужно вводить и выводить данные, посылать команды на то или иное действие. Ну и графики (световой импульс во времени, но это тоже не важно), по идее графики можно будет собрать и сохранённого файла данных. Но в форме это быстро и удобно.
Будет ли завершена разработка игры?
Malin писал(а): ↑25 апр 2013, 14:09То есть вообще не будет никакого окна? Но нам нужно вводить и выводить данные, посылать команды на то или иное действие. Ну и графики (световой импульс во времени, но это тоже не важно), по идее графики можно будет собрать и сохранённого файла данных. Но в форме это быстро и удобно.
ну... тогда наверно не стоит отказываться от форм..
-
- Сообщения: 53
- Регистрация: 25 янв 2011
Будет ли завершена разработка игры?
Про Vala все написано довольно таки не плохо. Но есть большое НО! Этот язык написан для ОС Linux, а не для Windows. Для винды тоже есть, но не от официальных разработчиков. Еще один очень важный момент - язык родился в 2006 года, а сегодня 2013 год, а версия языка только 0.20, то есть до версии 1.0 еще очень далеко. Задумка языка очень даже хороша и перспективна, но к тому времени когда появится полная документация на русском языке для изучения его нами, боюсь мы уже будем на пенсии )))