Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Написание игр _ Оптимизация алгоритма

Автор: pashist 20.07.2006 0:27

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

" (Показать/Скрыть)

Автор: klem4 20.07.2006 1:15

Видимо не верно ты ридкей юзать пытаешься ... Делай так :

 while keypressed do ch := readkey; 


Паузы в ожидании нажатия не будет.

Автор: pashist 21.07.2006 1:19

Это выход, но все равно скорости работы явно не хватает. Может, есть принципиально другие решения? И что с вторым вопросом?

Автор: Бродяжник 21.07.2006 13:58

Вот это

PutPixel(xT,yT,0);

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

Автор: Гость 21.07.2006 15:49

Пишу именно лабораторку..

Автор: pashist 24.07.2006 4:48

Всем доброе время суток. Переписал алгоритм, используя 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) Так никто и не ответил на вопрос, как проверить то, что я правильно прицелился на мышь, когда выстрелил? Нужно сравнить углы положения ружья и мышки относительно центра, и если они будут равны, то я удачно прицелился? Так? Как это сделать?

Автор: Бродяжник 24.07.2006 13:20

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 24.07.2006 13:32

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-шника.

Автор: Бродяжник 24.07.2006 14:43

Ну так вот:
в этом цикле

	 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 24.07.2006 15:41

Поменяй в этом цикле

     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 24.07.2006 15:47

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

Тебе I и J менять надо...

Автор: Бродяжник 24.07.2006 15:57

Тем более, что матрица-то квадратная, 18х18, так что m и n равны. Сколько их не меняй... smile.gif

Автор: pashist 24.07.2006 16:37

Спасибо! smile.gif А как заюзать функу angle? Как поместить начало координат в центр охотника(центр экрана)?

Автор: Бродяжник 24.07.2006 17:27

Ну...
Предположим, что режим 640 на 480. И начало координат вверху слева. И ось У направлена вниз. Так, как это обычно в графических режимах бывает. Пусть Xg и Yg - это координаты точки в данной системе отсчета.
Переносим начало координат в центр экрана и разворачиваем ось Y.

X1 := Xg - 320;
Y1 := 240 - Yg;

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

По-моему, так!

Автор: pashist 24.07.2006 18:25

Опять косяк.. 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;

После выстрела появляются левые убитые мышки.. =(
Прикрепил доработанную полную версию. Прикрепленный файл  MAIN.PAS ( 5.55 килобайт ) Кол-во скачиваний: 570

Автор: Бродяжник 24.07.2006 20:02

Отвечу завтра. Единственное замечание - стоит ли сравнивать углы на точное равенство? Не лучше ли вычислять их разность и сравнивать ее с некоторой дельтой? Тем более что и мышка ведь не точечная...

Автор: pashist 24.07.2006 20:22

Я так и хотел сделать, но сначала я хотел разобраться с точными данными, чтобы потом можно было вносить погрешности.

Автор: Бродяжник 25.07.2006 15:23

Простой корявый пример, иллюстрирущий идею.


Прикрепленные файлы
Прикрепленный файл  short.pas ( 2.4 килобайт ) Кол-во скачиваний: 287

Автор: pashist 25.07.2006 17:33

Круто! Бродяжник, спасибо! Вот, что примерно получилось. Уже играть можно)) Прикрепленный файл  MAIN.PAS ( 5.97 килобайт ) Кол-во скачиваний: 541
Теперь нужно перевести это в объекты.

Автор: pashist 25.07.2006 23:15

Мужики, зацените мой первый опыт в ООП =) Переписал в ООП охотника из игры. Нормально?

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 31.07.2006 0:53

Переписываю мышь в ООП =) Написал с использованием 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 Прикрепленный файл  BMP.PAS ( 4.8 килобайт ) Кол-во скачиваний: 503

Мышки Прикрепленный файл  Mouse.bmp ( 346 байт ) Кол-во скачиваний: 887
Прикрепленный файл  kill.bmp ( 346 байт ) Кол-во скачиваний: 913

Автор: volvo 31.07.2006 1:54

Цитата(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 31.07.2006 3:17

volvo, спасибо большое! Ты очень мне помог smile.gif