Помощь - Поиск - Пользователи - Календарь
Полная версия: Оптимизация алгоритма
Форум «Всё о Паскале» > Pascal, Object Pascal > Написание игр
pashist
Привет еще раз. Пишу игру Охотник на мышек=) Столкнулся с проблемой: как выполнять две процедуры одновременно? Ответ: никак =) Есть процедура, которая генерит вывод мышей на экран. Еще есть процедура, которая рисует охотника в центре экрана, которым нужно управлять. Но как управлять охотником, если уже выполняется процедура вывода мышей на экран? ReadKey не помогает, он останавливает программу в ожидании нажатия клавиши.
Второй вопрос, но тоже по теме. Чтобы убить мышку, нужно направить ружьё охотника на неё и нажать клавишу "Пробел". Как это можно реализовать в моём коде?

" (Показать/Скрыть)
klem4
Видимо не верно ты ридкей юзать пытаешься ... Делай так :

 while keypressed do ch := readkey; 


Паузы в ожидании нажатия не будет.
pashist
Это выход, но все равно скорости работы явно не хватает. Может, есть принципиально другие решения? И что с вторым вопросом?
Бродяжник
Вот это
PutPixel(xT,yT,0);

ЗЛО.
Злое злостное зло.
Рисовать ПутПикселем медленно.
Лучше использовать PutImage.
И вообще Unit Graph тормозной. С его помощью быструю игру не сделаешь. И прозрачность в спрайтах он не поддерживает. Конечно, если все дело в том, что нужно сделать лабораторку, тогда ничего не попишешь, а так-то лучше перейти на Delphi и использовать что-то вроде Asphyre. Для "Охотника на мышей" самое то.
Гость
Пишу именно лабораторку..
pashist
Всем доброе время суток. Переписал алгоритм, используя GetImage. Сама по себе эта функция не устранила тормоза, но с ней работать оказалось гораздо удобнее. smile.gif

Вот код: (Показать/Скрыть)


А теперь вопросы smile.gif
1) Почему в коде
     For i:=1 To m Do
For j:=1 To n Do
PutPixel(j,i,Mouse^[i,j]);
в PutPixel i и j нужно поменять местами, чтобы мышка выводилась на экран не в перевернутом виде? То есть если я пишу
PutPixel(i,j,Mouse^[i,j]);
, то изображение выводится на экран, повернутое на 90 град. против часовой стрелки.
2) Так никто и не ответил на вопрос, как проверить то, что я правильно прицелился на мышь, когда выстрелил? Нужно сравнить углы положения ружья и мышки относительно центра, и если они будут равны, то я удачно прицелился? Так? Как это сделать?
Бродяжник
2) Так, наверное, и сделать - сравнить углы. Нужно только поместить начало координат в пузо охотнику smile.gif
Вот функция пересчета из декартовых координат в полярный угол (перевел с сишного алгоритма с algolist.ru).
function Angle(x, y: real): real;
var theta: real;
begin
if (x = 0.0) and (y = 0.0) then
Angle := -1.0
else if x = 0.0 then
begin
if y > 0
then Angle := 0.5*Pi
else Angle := 1.5*Pi;
end
else
begin
theta := arctan(y/x);

if x > 0.0 then
begin
if y > 0.0
then Angle := theta
else Angle := 2*Pi+theta;
end
else Angle := Pi + theta;
end;
end;


Возвращает полярный угол в радианах для точки с координатами Х,У (в нормальной декартовой системе!).
Если бы еще был выложен файл Mouse.Dat, можно было бы подумать над какими-то улучшениями, а так ведь без него программу не запустить...
pashist
Mouse.dat-файл, содержащий матрицу 18х18=) Вот генератор:
Uses Crt;
Const m=18;n=18;
Type Data=Array[1..m,1..n] Of Integer;
Var Mouse: Data;
FT: File Of Data;
T: Text;
Str: Char;
i,j,vStr,Err: Integer;
Begin
ClrScr;
Assign(T,'Picture.txt');
Assign(FT,'Mouse.Dat');
ReSet(T);
ReWrite(FT);
For i:=1 To n Do
Begin
For j:=1 To m Do
Begin
Read(T,Str);
Val(Str,vStr,Err);
Mouse[i,j]:=vStr;
Write(vStr);
End;
ReadLn(T);
WriteLn
End;
Write(FT,Mouse);
Close(FT);
Close(T);
ReadLn;
End.


Файл Picture.txt
Цитата
002220000000222000
020002000002000200
200000200020000020
200000200020000020
020002020202000200
200000002000000020
200022200022200020
200200020200020020
200202020202020020
200022200022200020
020000002000000200
020000002000000200
002000020200002000
002000000000002000
000200222220020000
000200200020020000
000020022200200000
000002222222000000

=) Вообще хотелось бы грузить мышку из стандартного bmp-шника.
Бродяжник
Ну так вот:
в этом цикле
	 For i:=1 To n Do
Begin
For j:=1 To m Do
Begin
Read(T,Str);
Val(Str,vStr,Err);
Mouse[i,j]:=vStr;
Write(vStr);
End;
ReadLn(T);
WriteLn
End;


индекс i отвечает за строки, а j за столбцы. То есть Mouse[строка,столбец].
А в этом цикле
	 For i:=1 To m Do
For j:=1 To n Do
PutPixel(i,j,Mouse^[i,j]);


наоборот: индекс j отвечает за строки, а i за столбцы. То есть PutPixel(столбец,строка). Поэтому и приходится переставлять индексы местами.
А что тормозит? Охотник медленно вертится, или мыши редко появляются? А то у меня компьютер быстрый, может я не замечаю чего...
pashist
Поменяй в этом цикле
     For i:=1 To n Do
Begin
For j:=1 To m Do
Begin
Read(T,Str);
Val(Str,vStr,Err);
Mouse[i,j]:=vStr;
Write(vStr);
End;
ReadLn(T);
WriteLn
End;

m и n местами-и ничего не произойдет-изображение все равно придется переворачивать. Я так и не разобрался, почему. Тормозов больше в игре нет, я же писал. smile.gif
volvo
Цитата
Поменяй в этом цикле <...> m и n местами-и ничего не произойдет
Правильно... у тебя индексы-то по-прежнему перепутаны: I так же отвечает за строки, а J - за столбцы... Чего ты добился заменой M <-> N ???

Тебе I и J менять надо...
Бродяжник
Тем более, что матрица-то квадратная, 18х18, так что m и n равны. Сколько их не меняй... smile.gif
pashist
Спасибо! smile.gif А как заюзать функу angle? Как поместить начало координат в центр охотника(центр экрана)?
Бродяжник
Ну...
Предположим, что режим 640 на 480. И начало координат вверху слева. И ось У направлена вниз. Так, как это обычно в графических режимах бывает. Пусть Xg и Yg - это координаты точки в данной системе отсчета.
Переносим начало координат в центр экрана и разворачиваем ось Y.
X1 := Xg - 320;
Y1 := 240 - Yg;

Теперь у нас X1 и Y1 это координаты той же точки, но в декартовых координатах с началом отсчета в центре экрана. То есть, если экранные координаты мышонка Xm и Ym, то чтобы получить угол прицела на данную мышь, надо делать так:
Ugol := Angle(Xm-320.0, 240.0-Ym);

По-моему, так!
pashist
Опять косяк.. sad.gif Я неправильно использую функу Angle?
Function Shot(xH,yH: Real): Boolean;
Var xM,yM,HunterAngle,MouseAngle: Real;
i: Integer;
Flag: Boolean;
St: String;
Begin
HunterAngle:=Angle(xH-320,240-yH);
SetColor(Black);
OutTextXY(10,460,St);
SetColor(Red);
Str(HunterAngle,St);
OutTextXY(10,460,St);
For i:=1 To Mouses Do
Begin
MouseAngle:=Angle(Mas[i]^.x-320,240-Mas[i]^.y);
If HunterAngle=MouseAngle Then
Begin
Flag:=True;
Break;
End;
End;
If Flag Then
Begin
MouseVis(Mas[i]^,True);
Shot:=True;
End
Else
Shot:=False;
End;

После выстрела появляются левые убитые мышки.. =(
Прикрепил доработанную полную версию. Нажмите для просмотра прикрепленного файла
Бродяжник
Отвечу завтра. Единственное замечание - стоит ли сравнивать углы на точное равенство? Не лучше ли вычислять их разность и сравнивать ее с некоторой дельтой? Тем более что и мышка ведь не точечная...
pashist
Я так и хотел сделать, но сначала я хотел разобраться с точными данными, чтобы потом можно было вносить погрешности.
Бродяжник
Простой корявый пример, иллюстрирущий идею.
pashist
Круто! Бродяжник, спасибо! Вот, что примерно получилось. Уже играть можно)) Нажмите для просмотра прикрепленного файлаТеперь нужно перевести это в объекты.
pashist
Мужики, зацените мой первый опыт в ООП =) Переписал в ООП охотника из игры. Нормально?
Program Hunt;
Uses Graph,Crt;
Const
Left = #75;
Right = #77;
Type
Hunter=Object
Public
Constructor Init(xC,yC,WeaponLen,Head,Hat: Integer; Speed: Real);
Destructor Done;
Function CountX(D: Real): Integer;
Function CountY(D: Real): Integer;
Procedure Direction(c: Char);
Procedure Draw;
Private
x0,y0,x1,y1,r,HIn,HOut: Integer;
Spd,t: Real;
End;
Constructor Hunter.Init(xC,yC,WeaponLen,Head,Hat: Integer; Speed: Real);
Begin
x0:=xC;
y0:=yC;
r:=WeaponLen;
HIn:=Head;
HOut:=Hat;
Spd:=Speed;
x1:=r+x0;
y1:=y0;
t:=0;
End;
Destructor Hunter.Done;
Begin
WriteLn('Done');
End;
Function Hunter.CountX(D: Real): Integer;
Begin
CountX:=Round(r*Cos(D))+x0;
End;
Function Hunter.CountY(D: Real): Integer;
Begin
CountY:=Round(r*Sin(D))+y0;
End;
Procedure Hunter.Direction(c: Char);
Begin
Case c Of
Left: t:=t-Spd;
Right: t:=t+Spd;
End;
If (t>=2*Pi) Or (t<=-2*Pi) Then t:=0;
End;
Procedure Hunter.Draw;
Begin
SetColor(Black);
Line(x0,y0,x1,y1);
x1:=CountX(t);
y1:=CountY(t);
SetColor(Red);
Line(x0,y0,x1,y1);
SetColor(Blue);
SetFillStyle(1,Blue);
PieSlice(x0,y0,0,360,HIn);
SetColor(Red);
SetFillStyle(1,Red);
PieSlice(x0,y0,0,360,HOut);
End;
Var GD,GM: Integer;
H: Hunter;
k: Char;
Begin
GD:=Detect;
InitGraph(GD,GM,'');
H.Init(320,240,20,10,6,0.1);
Repeat
k:=ReadKey;
H.Direction(k);
H.Draw;
Until k=#27;
CloseGraph;
H.Done;
ReadLn
End.
pashist
Переписываю мышь в ООП =) Написал с использованием BMP, но не пойму, где ошибка( Мужики, помогите! Почему не работает?
Uses Graph,Crt,Bmp;
Const m=18;
n=18;
Mouses=10;
Type
MouseData=Record
x,y: Integer;
End;
Data=Array[1..m,1..n] Of Integer;
TMouse=Object
Public
Constructor Init(MousePath,KillPath: String; xC,yC: Integer);
Destructor Done;
Function Work: Boolean;
Function xW: Integer;
Function yW: Integer;
Procedure DrawMouse;
Private
x,y: Integer;
Mouse,Kill: String;
Working: Boolean;
End;
Constructor TMouse.Init(MousePath,KillPath: String; xC,yC: Integer);
Begin
Mouse:=MousePath;
Kill:=KillPath;
x:=xC;
y:=yC;
Working:=True;
End;
Destructor TMouse.Done;
Begin
BMPDisplay(Kill,x,y,False);
Delay(10000);
BMPDisplay(Kill,x,y,True);
Working:=False;
End;
Function TMouse.Work: Boolean;
Begin
Work:=Working;
End;
Function TMouse.xW: Integer;
Begin
xW:=x;
End;
Function TMouse.yW: Integer;
Begin
yW:=y;
End;
Procedure TMouse.DrawMouse;
Begin
BMPDisplay(Mouse,x,y,False);
End;
Var Mas: Array[1..Mouses] Of ^TMouse;
i,GD,GM,xT,yT: Integer;
Function RandCoord(Coord: Char): Integer;
Var z,i: Integer;
Flag: Boolean;
Begin
If Coord='x' Then {m}
Begin
Repeat
Flag:=True;
z:=Random(640);
For i:=1 To Mouses Do
If (ABS(z-Mas[i]^.xW))<20 Then
Begin
Flag:=False;
Break
End;
Until (z<622) AND Flag AND ((z<280) Or (z>360));
End;
If Coord='y' Then {n}
Begin
Repeat
Flag:=True;
z:=Random(480);
For i:=1 To Mouses Do
If (ABS(z-Mas[i]^.yW))<20 Then
Begin
Flag:=False;
Break
End;
Until (z<462) AND Flag AND ((z<200) Or (z>280));
End;
RandCoord:=z;
End;
Begin
GD:=Detect;
InitGraph(GD,GM,'');
Randomize;
Repeat
Repeat i:=Random(Mouses) Until i>0;
If Mas[i]^.Work Then
Begin
Mas[i]^.Done
End
Else
Begin
xT:=RandCoord('x');
yT:=RandCoord('y');
Mas[i]^.Init('Mouse.bmp','Kill.bmp',xT,yT);
Mas[i]^.DrawMouse;
End;
Delay(65535);
Until KeyPressed;
End.

Модуль BMP Нажмите для просмотра прикрепленного файла
Мышки Нажмите для просмотра прикрепленного файла Нажмите для просмотра прикрепленного файла
volvo
Цитата(pashist @ 30.07.2006 20:53)
Переписываю мышь в ООП =) Написал с использованием BMP, но не пойму, где ошибка( Мужики, помогите! Почему не работает?
Потому, что ты некорректно работаешь с указателями на объекты... Здесь:
  If Mas[i]^.Work Then ...
формально ты допускаешь грубую ошибку - пытаешься обратиться к переменной объекта, который, возможно, еще не инициализирован. Если твой Object будет содержать виртуальные методы (а то, что ты использовал Constructor - первый шаг к этому), то программа просто вылетит у тебя при первой же попытке выполнения вышеприведенной строки. Да и сама инициализация объектов хромает... Вот так попробуй:
Type
PTMouse = ^TMouse;

Begin
GD:=Detect;
InitGraph(GD,GM,'');
Randomize;
Repeat
Repeat i:=Random(Mouses) Until i>0;
If Mas[i] <> nil then Begin
Dispose(Mas[i], Done); { Это - корректный вызов деструктора }
Mas[i] := nil;
End
Else Begin
xT:=RandCoord('x');
yT:=RandCoord('y');

{ А вот это - правильная инициализация }
Mas[i] := New(PTMouse, Init('Mouse.bmp','Kill.bmp',xT,yT));
Mas[i]^.DrawMouse;
End;
Delay(65535);
Until KeyPressed;
End.


Все остальное - без изменений...
pashist
volvo, спасибо большое! Ты очень мне помог smile.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.