Консультация № 182806
11.04.2011, 19:46
0.00 руб.
18.04.2011, 18:24
0 12 1
Здравствуйте эксперты.
Программа писалась на Pascal ABC.
Задание (ужаснетесь сразу говорю) :
===========================
Написать игру «Кирпичная кладка». Правила игры: по экрану движется объект. Создавать препятствия из кирпичей, препятствующие перемещению объекта по экрану. Кирпич перемещается клавишами управления курсором, а устанавливается клавишей Enter. Объект должен обходить препятствия.
===========================
Вот теперь ужас номер 2.:
Паскаль я раньше не изучал, команды вообще не знаю, но каким то чудесным образом умудрился написать вот такую вещь.
Комментариев очень мало, но надеюсь вы поймете.
Проблема у меня в том, что
1. Не пойму как заставить объект обходить кирпичики, перебил много алгоритмов, но все равно он либо наваливается либо перепрыгивает.
2. Если заметите то при использование клавиши она повторяет прошлое нажатие, не пойму как его обнулить, куда то не пихал.
3. Как реализовать движение объекта под кодовым видом Шарик, в независимую часть, чтобы не зависел от того была ли клавиши нажата или нет.( пока стоит взаимосвязь.)

[code h=300]
uses ABCObjects,Events,GraphABC,Timers,Utils,CRT;
var
x,y,st,k,l : integer; { переменные связанные с положением кубика(x,y), st ( отвечает за dx=смещение), k,l (k= сколько прямоугольник уже есть, l простая переменная (не нужная.)}
width,height :real; { пока не пригодились}
cx,cy,cr:integer; { значение шарика }
ax,ay:integer ; { используются для сохранения координат положения прошлого кирпичика перед созданием нового }
key: char;
const n=200;
type Mas = array[1..n,1..2] of integer;
var a:Mas;
var i,j: integer;
{ Прорисовка прошлы кирпичей }
procedure oldBox(dx,dy:integer);
begin
j:=1;
x:=a[i,j];
j:=j+1;
y:=a[i,j];
Rectangle(x,y,x+dx,y+dy);
end;
{Прорисовка нового кирпичя}
procedure Box(dx,dy:integer);
begin
x:=0;y:=0;
j:=1;
x:=x+a[i,j];
j:=j+1;
y:=y+a[i,j];
Rectangle(x,y,x+dx,y+dy);
end;
{ прорисовка шарика}
procedure Bowling(cx,cy,cr:integer);
begin
Circle (cx,cy,cr);
end;
{ Алгоритм движения шарика и проверки на кирпичи }
{ Основная процедура перерисовки}
procedure Repaint(x,y,dx,dy,cx,cy,cr:integer);
begin
clrscr;
for i:=1 to k do
for j:=1 to 1 do
begin
x:=a[i,j];
j:=j+1;
y:=a[i,j];
if (i+1=k) then
Box(st+25,st)
else
oldBox(st+25,st)
end;
if (ax>=cx) then
cx:=ax-cx;

Circle (cx,cy,cr);
end;
{ Движение Вверх }
procedure Up (dx,dy:integer);
begin
i:=k+1;
j:=1;
x:=a[i,j];
j:=j+1;
y:=a[i,j];
Repaint(x,y,st+25,st,cx,cy,cr);
cy:=cy+dy;
y:=y-dy;
j:=1;
a[i,j]:=x;
j:=j+1;
a[i,j]:=y;
end;
{ Движение Вниз }
procedure Down(dx,dy:integer);
begin
i:=k+1;
j:=1;
x:=a[i,j];
j:=j+1;
y:=a[i,j];
Repaint(x,y,st+25,st,cx,cy,cr);
cy:=cy-dy;
y:=y+dy;
j:=1;
a[i,j]:=x;
j:=j+1;
a[i,j]:=y;
end;
{ Движение Влево }
procedure Left(dx,dy:integer);
begin
i:=k+1;
j:=1;
x:=a[i,j];
j:=j+1;
y:=a[i,j];
Repaint(x,y,st+25,st,cx,cy,cr);
cx:=cx-dx;
x:=x+dx;
j:=1;
a[i,j]:=x;
j:=j+1;
a[i,j]:=y;
end;
{ Движение Вправо }
procedure Right(dx,dy:integer);
begin
i:=k+1;
j:=1;
x:=a[i,j];
j:=j+1;
y:=a[i,j];
Repaint(x,y,st+25,st,cx,cy,cr);
cx:=cx+dx;
x:=x-dx;
j:=1;
a[i,j]:=x;
j:=j+1;
a[i,j]:=y;
end;
{ Процедура за Сохранение координат кирпича }
procedure Enter(Mas:integer);
begin
i:=k;
j:=1;
a[i,j]:=x;
ax:=x;
j:=j+1;
a[i,j]:=y;
ay:=y;
k:=k+1;
i:=k;
j:=1;
a[i,j]:=0;
j:=j+1;
a[i,j]:=0;
x:=0;y:=0;
Repaint(x,y,st+25,st,cx,cy,cr);

end;
{ Основная Часть }
begin
st:=25;
SetWindowCaption('Кирпичная кладка Типо того игра Клёвая голосуем');
SetWindowSize(640,480);
SetBrushColor(RGB(100,142,12));
k:=k+1;
x:=0;
y:=0;
cx:=340;
cy:=400;
cr:=20;


while key<>#27 do
begin
// Bowling(cx,cy,cr);
key:='0';
key:=readkey;
case key of
#80 : Down(st+25,st);
#72 : Up(st+25,st);
#75 : Left(st+25,st);
#77 : Right(st+25,st);
#13 : Enter(a[k,j]);
end;
key:='0';
//Bowling(cx,cy,cr);
end;

end.

[/code]

Обсуждение

давно
Мастер-Эксперт
325460
1469
12.04.2011, 11:54
общий
к сожалению нет паскаля на данный момент, но если есть желание можем обсудить алгоритм в таком плане: проводим обсуждение, Вы пишете, говорите что не получается, проводим обсуждение далее и так приходим к истине, идет?
Об авторе:
to live is to die
давно
Старший Модератор
31795
6196
12.04.2011, 13:30
общий
ужаснетесь сразу говорю

нервно курим в сторонке.
Вот теперь ужас номер 2

Вторую пачку.




перебил много алгоритмов

Давайте определимся с механизмом поиска пути шариком.
Как Вы смотрите на Волновой алгоритм. Нахождение пути в лабиринте
[code h=200]program q182505;
const n=10;
var
a:array[1..n,1..n]of integer;
b,c,d,e,x,y,z:integer;
f,g:boolean;
begin
{сбрасываем}
for b:=1 to n do
for c:=1 to n do
a[b,c]:=0;
{вводим координаты}
repeat
write('Enter x0:');
readln(b);
until (b>0)and(b<=n);
repeat
write('Enter y0:');
readln(c);
until (c>0)and(c<=n);
a[b,c]:=1;{запоминаем начало}
{вводим координаты останова}
repeat
write('Enter x1:');
readln(b);
until (b>0)and(b<=n);
repeat
write('Enter y1:');
readln(c);
until (c>0)and(c<=n);
writeln;
z:=1;
{препятствия}
a[2,5]:=-1;
a[3,9]:=-1;a[3,10]:=-1;
a[4,1]:=-1;a[4,2]:=-1;a[4,4]:=-1;a[4,9]:=-1;a[4,10]:=-1;
a[5,5]:=-1;
a[6,7]:=-1;
a[7,1]:=-1;a[7,3]:=-1;a[7,4]:=-1;a[7,6]:=-1;a[7,7]:=-1;
a[8,8]:=-1;a[8,9]:=-1;a[8,10]:=-1;
a[9,1]:=-1;a[9,4]:=-1;a[9,6]:=-1;
a[10,1]:=-1;a[10,2]:=-1;
{цикл поиска}
repeat
f:=true;
g:=false;
for x:=1 to n do
for y:=1 to n do
if a[x,y]=z then
for d:=0 to 2 do
for e:=0 to 2 do
if(abs(d-1)<>abs(e-1))and
((x+d-1)>0)and((x+d-1)<=n)and
((y+e-1)>0)and((y+e-1)<=n)and
(a[x+d-1,y+e-1]=0)then
begin
a[x+d-1,y+e-1]:=z+1;
f:=false;
g:=g or ((x+d-1)=b)and((y+e-1)=c)
end;
inc(z);
until f or g;
{коррекция результата}
for b:=1 to n do
for c:=1 to n do
if a[b,c]>0 then dec(a[b,c]);
{вывод}
for b:=1 to n do
begin
for c:=1 to n do write(a[b,c]:3);
writeln;
end;
readln;
end.[/code]
или вариант со списками(в АВС может работать с ошибками, т.к. писался под ТР7.0):
[code h=200]const
n=10;
type
tList=^dList;
dList=record
x,y,z:integer;
w:tList;
end;
var
a:array[1..n,1..n]of integer;
b,c:tList;
s:boolean;
x,y:integer;
function F(a:integer):boolean;
begin
F:=(a>0)and(a<=n);
end;
procedure G(b:tList);
var
c,d:tList;
i,j:integer;
begin
for i:=0 to 2 do for j:=0 to 2 do
if not(s)and
(abs(i-1)<>abs(j-1))and
(a[b^.x+i-1,b^.y+j-1]=0)and
F(b^.x+i-1)and
F(b^.y+j-1) then
begin
new(c);
c^.x:=b^.x+i-1;
c^.y:=b^.y+j-1;
c^.z:=b^.z+1;
a[c^.x,c^.y]:=c^.z;
d:=b;
while d^.w<>nil do d:=d^.w;
d^.w:=c;
c^.w:=nil;
s:=(c^.x=x)and(c^.y=y);
end;
end;
begin
{}
for x:=1 to n do for y:=1 to n do a[x,y]:=0;
{препятствия}
a[2,5]:=-1;
a[3,9]:=-1;a[3,10]:=-1;
a[4,1]:=-1;a[4,2]:=-1;a[4,4]:=-1;a[4,9]:=-1;a[4,10]:=-1;
a[5,5]:=-1;
a[6,7]:=-1;
a[7,1]:=-1;a[7,3]:=-1;a[7,4]:=-1;a[7,6]:=-1;a[7,7]:=-1;
a[8,8]:=-1;a[8,9]:=-1;a[8,10]:=-1;
a[9,1]:=-1;a[9,4]:=-1;a[9,6]:=-1;
a[10,1]:=-1;a[10,2]:=-1;
{}
repeat
repeat
write('Enter xEP:');
readln(x);
until F(x);
repeat
write('Enter yEP:');
readln(y);
until F(y);
until a[x,y]=0;
{}
new(b);
b^.x:=x;
b^.y:=y;
b^.z:=1;
b^.w:=nil;
a[x,y]:=1;
{}
repeat
repeat
write('Enter xSP:');
readln(x);
until F(x);
repeat
write('Enter ySP:');
readln(y);
until F(y);
until a[x,y]=0;
{}
c:=b;
s:=false;
repeat
G(c);
c:=c^.w;
until (c=nil)or s;
for x:=1 to n do
begin
for y:=1 to n do
begin
if a[x,y]>0 then dec(a[x,y]);
write(a[x,y]:3);
end;
writeln;
end;
readln;
end.[/code]
Картинки в первом случае совпадают, во втором почти, оканчиваются в момент достижения заданой точки.

Идея такая:
Шарик каждый раз просчитывает путь, с помощью алгоритма, выбирает самый максимальный и движется в этом направлении.
Игрок перемещая кубик(думаю это лучше, чем кирпич) устанавливает на поле препятствия, т.е. записывает в массив [b]-1[/b].
Ну и так далее.


Пункты 2 и 3 несколько позже.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
12.04.2011, 17:36
общий
у меня тут не большая идейка появилась, пока ждал ответа, чуть позже постараюсь скинуть её, если все будет удачно.
давно
Старший Модератор
31795
6196
12.04.2011, 18:09
общий
3)
Цитата: 370617
Как реализовать движение объекта под кодовым видом Шарик, в независимую часть,


Приблизительно так:
Код:
      if keyPressed then
begin{key pressed}
key:=Readkey;
case key of
#80:;
#72:;
#75:;
#77:;
#13:;
end
end;{key pressed}

Пока клавиша не нажата, код изменения координат кирпича пропускается. Получается шарик "живет" сам, кирпич от пользователя. Соответственно переменные, которые хранят координаты не должны заваисить друг от друга(шарик и кирпич).
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
12.04.2011, 19:57
общий
Зенченко Константин Николаевич:
Пытался таким способ пойти, не удачно получалось, он как будто вообще не видел мои клавиши, нажимал ли я их или нет. Решил включить таймер для шарика, может быть это будет проще.
Неизвестный
12.04.2011, 19:59
общий
как можно избавится от повтора?
Код:
 while key<>#27 do
begin
// Bowling(cx,cy,cr);
key:='0';
key:=readkey;
case key of
#80 : Down(st+25,st);
#72 : Up(st+25,st);
#75 : Left(st+25,st);
#77 : Right(st+25,st);
#13 : Enter(a[k,j]);
end;
key:='0';
//Bowling(cx,cy,cr);
end;

в этой части, а то 1 раз кликнешь он все равно еще раз сдвинется.
давно
Старший Модератор
31795
6196
13.04.2011, 11:47
общий
Давайте будем эксперементировать:
Код:
uses Crt;
var key,c:char;
begin{main}
c:='a';
while key<>#27 do
begin
write(c);
if Keypressed then
begin
key:=ReadKey;
write(ord(key),'-');
case key of
'+':inc(c);
'-':dec(c);
end;
end;
delay(500);
end;
end.{main}

Как видно код с KeyPressed работает. Вопрос несколько в другом. Вводятся функциональные клавиши, а это значит, что в потоке ввода находятся два байта. Ну Вы сами это увидите.
Цитата: 370617
а то 1 раз кликнешь он все равно еще раз сдвинется.



Я предлагаю Вам сменить подход к программированию игрушки.
Посмотрите сами код процедур вверх-вниз и т.д. почти одинаков за исключением знаков в операциях.
Структура должна быть приблизительно такой:
Код:
repeat
Show;{показать изображение в соответсвии с координатами xBall, yBall, xMount, yMount и т.д.}
delay(TimeOut);{задержда отбражения}
Hide;{спрятать изображение}
KeyPressed{обработка нажатых клавиш и изменение координат: xBall, yBall, xMount, yMount и т.д.}
until c="ESC";{выход}

Заметьте, как упростится сам код:
[code h=200]procedure CheckRange(var a:integer;b,c:integer);
begin
if ((a+b)>0)and((a+b)<c)then a:a+b;{если в поле, то изменяем}
end;
procedure SetMount(a,b:integer);
begin
CheckRange(xMount,a,xMax);{контролируем поле по Х}
CheckRange(yMount,b,yMax);{контролируем поле по У}
end;
{
.
.
.
}
while key<>#27 do
begin
key:=ReadKey;{}
if ord(key)=0 then key:=ReadKey;{}
case key of
#80:SetMount(0,1);
#72:SetMount(0,-1);
#75:SetMount(-1,0);
#77:SetMount(1,0);
#13:Enter;
end;
end;
SetBall;{изменяем положение шара}
Show;{показать изображение}
delay(TimeOut);
Hide;{спрятать изображение}
{
.
.
.
}[/code]
Show и Hide, это по своей сути одна и таже процедура, в которой одна рисует, а вторая стирает, а обслуживающие их циклы одинаковы.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
14.04.2011, 19:34
общий
Ау!

Разабрались с кодом?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Неизвестный
15.04.2011, 19:41
общий
Адресаты:
еще пока нет. времени пока не хватает, чтоб сесть и сделать.)
давно
Старший Модератор
31795
6196
15.04.2011, 20:24
общий

Я продлю консультацию на пару суток, если у Вас не получится, то выложу свой код.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
18.04.2011, 18:20
общий
это ответ
Здравствуйте, АлексАлексей!

Смотрите приложение.
Реализован волновой алгоритм поиска хода в лабиринте. При вычислении возможного хода в массиве POLE отмечается положительным значением(препятствия имеют отрицательные числа) номер возможного хода, в массиве А- запоминается сам ход. Когда массив будет заполнен, находится максимальное значение и с помощью массива А, находится начальное направление движения шара. Маркер препятствия и шарик не могут перейти на уже занятое поле, но маркер может стоять на последнем выставленом препятствии.

Шарик иногда "топчется" на месте, это из-за того, что максимальное значение расчитывается при каждом ходе и иногда меняет свое положение.
ps:вопросы задавайте в мини-форум.
Удачи!

Приложение:
uses crt,graphABC;
const
x_Max=10;{максимальный размер поля по Х}
y_Max=10;{максимальный размер поля по У}
x_d=20;{размер позиции по Х}
y_d=20;{размер позиции по У}
TimeOut=500;{служебная задержка}
r_Obstacle=5;{радиус маркера препятствия}
r_Ball=8;{радиус шара}
type
tMass=array[1..x_Max,1..y_Max]of integer;
var
Pole:tMass;
x_Obstacle,y_Obstacle:integer;{координаты маркера препятствия}
x_Ball,y_Ball:integer;{координаты шара}
c:char;
function Check(a,b:integer):boolean;
begin{check}
Check:=(a>0)and(a<=b);{условие контроля}
end;{check}
function Check_All(a,b,c,d:integer):boolean;
begin{check_all}
Check_All:=Check(a+c,x_Max)and{проверяем координату Х}
Check(b+d,y_Max)and{проверяем координату У}
(Pole[a+c,b+d]=0);{проверяем наличие препятствий}
end;{check_all}
Procedure Set_A(a,b:integer);
begin{set_a}
if Pole[x_Ball,y_Ball]=0 then Pole[x_Ball,y_Ball]:=-2;{устанавливаем положение шара}
if Check_All(x_Obstacle,y_Obstacle,a,b)then
begin{if}
x_Obstacle:=x_Obstacle+a;{изменяем координату}
y_Obstacle:=y_Obstacle+b;{изменяем координату}
end;{if}
if Pole[x_Ball,y_Ball]=-2 then Pole[x_Ball,y_Ball]:=0;{освобождаем поле занятое шаром}
end;{set_a}
procedure Set_B;
var
a:tMass;
c:boolean;
i,j,n,z:integer;
begin{set_b}
if Pole[x_Obstacle,y_Obstacle]=0 then Pole[x_Obstacle,y_Obstacle]:=-3;{устанавилваем позицию маркера}
for i:=1 to x_Max do for j:=1 to y_Max do a[i,j]:=0;{сбрасываем таблицу предков :-)}
Pole[x_Ball,y_Ball]:=1;{текущее положение шара}
z:=0;{текущий уровень}
repeat
inc(z);{следующий уровень}
c:=true;{параметр выхода}
for i:=1 to x_Max do for j:=1 to y_Max do{в цикле перебираем все элементы}
if Pole[i,j]=z then{равно текущему работаем}
for n:=0 to 8 do{все возможные направления движения}
if(abs((n mod 3)-1)<>abs((n div 3)-1))and{исключаем диагонали}
Check_All(i,j,(n mod 3)-1,(n div 3)-1)then{контролируем поле}
begin{if}
a[i+(n mod 3)-1,j+(n div 3)-1]:=n;{ход, который привел к этому напрвлению}
Pole[i+(n mod 3)-1,j+(n div 3)-1]:=z+1;{новый уровень}
c:=false;{сбрасываем параметр цикла}
end;{if}
until c;{если истина, значит больше возможных ходов нет}
n:=1;z:=1;{пока максимальное число ходов левый верхний элемент}
for i:=1 to x_Max do for j:=1 to y_Max do{вцикле проверяем все значения}
if Pole[i,j]>Pole[n,z] then{если больше запоминаем}
begin
n:=i;z:=j;{новое значение}
end;
i:=n;j:=z;{запоминаем координаты максимального значения}
repeat
n:=a[i,j];{ход который привел к этой точке}
i:=i+1-(n mod 3);{считаем координаты предков по Х}
j:=j+1-(n div 3);{считаем координаты предков по У}
until (i=x_Ball)and(j=y_Ball);
x_Ball:=x_Ball+(n mod 3)-1;{изменяем положение шара по Х}
y_Ball:=y_Ball+(n div 3)-1;{изменяем положение шара по У}
for i:=1 to x_Max do for j:=1 to y_Max do{в цикле}
if Pole[i,j]>0 then Pole[i,j]:=0;{убираем таблицу поиска}
if Pole[x_Obstacle,y_Obstacle]=-3 then Pole[x_Obstacle,y_Obstacle]:=0;{освобождаем позицию маркера}
end;{set_b}
procedure Show;
var
i,j:integer;
begin{show}
for i:=1 to x_Max do for j:=1 to y_Max do{показываем статус всех полей}
begin{for for}
if Pole[i,j]=0 then SetBrushColor(clMedGray){свободно}
else SetBrushColor(clGreen);{занято}
Rectangle(i*x_d,j*y_d,(i+1)*x_d,(j+1)*y_d);{рисуем}
end;{for for}
SetBrushColor(clSkyBlue);{показываем маркер препятствия - голубым}
Circle(x_Obstacle*x_d+(x_d div 2),y_Obstacle*y_d+(y_d div 2),r_Obstacle);
SetBrushColor(clBlue);{показываем шар - синим}
Circle(x_Ball*x_d+(x_d div 2),y_Ball*y_d+(y_d div 2),r_Ball);
end;{show}
begin{main}
SetWindowCaption('This my game');
for x_Ball:=1 to x_Max do for y_Ball:=1 to y_Max do Pole[x_Ball,y_Ball]:=0;{чистим рole}
x_Obstacle:=1;y_Obstacle:=1;{начальное положение маркера}
x_Ball:=5;y_Ball:=5;{начальное положение шара}
repeat
Show;{рисуем Экран}
delay(TimeOut);{задержка отображения}
if KeyPressed then{обрабатываем нажатие клавиши}
begin{if}
c:=ReadKey;{код клавиши}
if ord(c)=0 then c:=ReadKey;{исключаем нулевой(служебный) байт}
case c of
#80:Set_A(0,1);{устанавливаем новую координату}
#72:Set_A(0,-1);{устанавливаем новую координату}
#75:Set_A(1,0);{устанавливаем новую координату}
#77:Set_A(-1,0);{устанавливаем новую координату}
#13:Pole[x_Obstacle,y_Obstacle]:=-1;{устанавливаем маркер препятствия}
end;{case}
end;{if}
Set_B;{устанавливаем новую координату шара}
until c=#27;{press ESC}
end.{main}
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Старший Модератор
31795
6196
18.04.2011, 18:22
общий
Со списками не получилось, АВС постоянно ругается на строки while b^.a<>nil do b:=b^.a; - попытка переименовать нулевой указатель.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

Форма ответа