Вот такое задание: Даны два шарика диаметром М. Промоделировать движение шариков по всей плоскости экрана. Шарики могут двигаться по прямым линиям. Изменение угла движения после столкновения с границей экрана или друг с другом может быть случайной величиной. Шарик не может вылететь за пределы квадрата. Пользователь может варьировать скорости движения шариков с помощью стрелок управления курсором.
Хотелось бы разобраться в коде программы... ( дело в том, что код не мой) Объясните пожалуйста назначение каждой из процедур в тексте приведённой ниже программы!
18192123
6.04.2007 0:44
procedure Change(g1,g2:integer;var n:integer;a:real); begin if g1>=g2 then begin sound(random(100)+880);randomize; n:=-n; a:=3.14*(random(90))/180;end; end;
как я поняла, эта процедура используется для произвольного изменения угла отклонения при столкновении объёктов. ( обязательно исправляйте меня, если я где-то не точна или, тем более, не права!!!)
теперь вопросы: для чего используются g1,g2 ? для чего нужна такая операция n:=-n?
a:=3.14*(random(90))/180;
Это ведь вычисление радианной меры угла?
Дальше....
procedure Change2(x,x1:integer;var n,m,n1,m1:integer); begin if x>=x1 then begin n:=abs(n);m:=-abs(m1);n1:=-abs(n1);m1:=abs(m);end; end;
мне вообще не понятно, для чего эта процедура... за что отвечают передаваемые в процедуру параметры? каково назначение здесь операций
n:=abs(n); {...} n1:=-abs(n1);
Следующее...
procedure Exit(x,y,r:integer;var flag:boolean); begin if (x-r<50) or (x+r>570) or (y-r<50) or (y+r>450) then begin flag:=true; SetColor(red); OutTextXY(170,190,'Sorry, fatal programm error! Press any key'); ReadKey end; end;
Ясно, что процедура для выхода из программы в случае ошибки. Но не ясно, что означает это длинное условие выхода
if (x-r<50) or (x+r>570) or (y-r<50) or (y+r>450) then
Заранее спасибо.
Lapp
6.04.2007 11:54
Марина, извини, но ты выбрала неправильную программу для примера.. Она слишком кривая и слабая, чтоб с нее копировать. Даже разбираться в этом коде никакого желания нет..
Движение объектов по экрану разбиралось тут не раз. Попробуй написать сама. Или хотя бы начни с алгоритма, блок-схемы.. Я, например, готов тебе помочь в этом благородном деле, но объяснять для чего в этой программе совершенно ненужные вещи - уволь..
Если согласна, поищи по форуму про движение объектов. Я могу тебе выложить чуть позже примеры основных частей кода, если будут трудности.
18192123
7.04.2007 17:49
Цитата(Lapp @ 6.04.2007 8:54)
Марина, извини, но ты выбрала неправильную программу для примера.. Она слишком кривая и слабая, чтоб с нее копировать. Даже разбираться в этом коде никакого желания нет..
Движение объектов по экрану разбиралось тут не раз. Попробуй написать сама. Или хотя бы начни с алгоритма, блок-схемы.. Я, например, готов тебе помочь в этом благородном деле, но объяснять для чего в этой программе совершенно ненужные вещи - уволь..
Если согласна, поищи по форуму про движение объектов. Я могу тебе выложить чуть позже примеры основных частей кода, если будут трудности.
Да я согласна. Час буду искать про движение объекта....
Спасибо большое, что согласился помочь!
18192123
8.04.2007 0:31
Цитата(Lapp @ 6.04.2007 8:54)
начни с алгоритма..
1. Меню (где можно выбрать радиус 2-х шариков) Я могу оставить по этому вопросу то, что было в примере(неудачном) - процедуры MENU и _case_?
2. Рисуем шарики(здесь ясно) --> Убираем с экрана( и здесь) --> ВЫбираем новое их положение (каким способом это лучше делать???) --> Показываем на новом месте
3. Проверка на выход за пределы экрана (что делать, если получается вылет за пределы экрана: аварийный выход из программы или ....??????)
---Соударение шаров друг с другом и с пределами экрана (мне не ясно, что нужно указывать по этому пункту...Может связать с законом сохранения импульса???)
4. Управление скоростями с помощью стрелок на клавиатуре - не представляю, как это осуществить!
Все мои соображения.....
Tan
8.04.2007 2:32
Случайно на компе наткнулся на задачку с шариком погляди может какие - то идем возьмёшь, не помню откуда эта прога в упор :
program biljard; uses crt,graph; var driver,mode,vektorx,vektory,x,y:integer; x1,y1,Lx,Ly:real; begin clrscr; driver:=detect; initgraph(driver,mode,'c:\bp\bgi'); setcolor(15); {white}
rectangle(70,70,500,350);{razmeri stola} x1:=80;y1:=340; {nachaljnije koordinati kruga} vektorx:=7;vektory:=12; x:=round(x1);y:=round(y1); Lx:=vektorx/(sqrt(vektorx*vektorx+vektory*vektory));{dx} Ly:=vektory/(sqrt(vektorx*vektorx+vektory*vektory));{dy} circle(x,y,5); repeat setcolor(0); {black} circle(x,y,5); if (getpixel(x-6,y)=15) or (getpixel(x+6,y)=15) then Lx:=-Lx; if (getpixel(x,y-6)=15) or (getpixel(x,y+6)=15) then Ly:=-Ly; x1:=x1+Lx;y1:=y1+Ly; x:=round(x1);y:=round(y1); {tak kak circle toljko v integer, okrugljajem xy} setcolor(15); {white} circle(x,y,5); delay(500);{pauza dlja togo 4tobi videtj dvizhenije} until keypressed; readkey; end.
Lapp
8.04.2007 13:58
Цитата(18192123 @ 7.04.2007 21:31)
1. Меню (где можно выбрать радиус 2-х шариков) Я могу оставить по этому вопросу то, что было в примере(неудачном) - процедуры MENU и _case_?
Я бы оставил меню на потом. Начни с реализации движения. Не потому, что это проше, а потому что главное. После этого тебе проще будет определяться с меню.
Цитата(18192123 @ 7.04.2007 21:31)
2. Рисуем шарики(здесь ясно) --> Убираем с экрана( и здесь) --> ВЫбираем новое их положение (каким способом это лучше делать???) --> Показываем на новом месте
Расчет нового положения производится рпо обычным формулам x1=x0+V*dt
Цитата(18192123 @ 7.04.2007 21:31)
3. Проверка на выход за пределы экрана (что делать, если получается вылет за пределы экрана: аварийный выход из программы или ....??????)
1. Находить точку пересечения с краем. 2. продолжать движение от нее - либо с отраженной скоростью, либо со случайной (как хочешь)
Цитата(18192123 @ 7.04.2007 21:31)
---Соударение шаров друг с другом и с пределами экрана (мне не ясно, что нужно указывать по этому пункту...Может связать с законом сохранения импульса???)
Соударение с друг другом пока не делай. Мне кажется, что это не присутствует в первоначальной формулировке. Всегда можно добавить потом (если строго по физике - то потребуется задание массы; она может быть пропорциональна кубу радиуса, например). Сначала сделай без взаимодействия (пусть проходят друг сквозь друга, не замечая)
Цитата(18192123 @ 7.04.2007 21:31)
4. Управление скоростями с помощью стрелок на клавиатуре - не представляю, как это осуществить!
С помощью стрелок - не очень удобно, поскольку их (шаров) несколько. Это обязательно? Можно сделать цифрами: цифра увеличивает, шифт-цифра уменьшает. Так годится?
Программу Tan'а еще не смотрел, посмотрю.. В любом случае, если уж решилась делать сама - то и делай, это лучше.
18192123
8.04.2007 15:02
Цитата(Lapp @ 8.04.2007 10:58)
С помощью стрелок - не очень удобно, поскольку их (шаров) несколько.
Мне нужно именно управление стрелками. Можно осуществить такой вариант: стрелки "вправо-влево" для одного шара, "вверх-вниз" для другого???
volvo
8.04.2007 15:13
Для того, чтобы начать реализовывать меню (интерфейс), надо сначала реализовать логику работы программы, о чем и говорил Lapp... Сделай сначала это, чтобы потом не получилось как в первой приведенной тобой программе - где "рюшечки" настолько заполонили код, что разобраться в нем просто нереально...
Цитата
Можно осуществить такой вариант: стрелки "вправо-влево" для одного шара, "вверх-вниз" для другого?
Можно и так, почему же нельзя? Какие клавиши навесишь, такие и будут...
18192123
8.04.2007 20:26
Мои "очень скромные" наработки..... вот только шарики не хотят двигаться...
procedure escape (x, y, r, bgC : integer); begin Setcolor (bgC); circle (x, y, r); Floodfill(x, y, bgC); end;
procedure move (x, y, dx, dy : integer); begin x := x+ dx; y := y + dy; end;
procedure charge_on_oppositeX (x, dx : integer); begin dx := -dx; x := x + dx; end;
procedure charge_on_oppositeY (y, dy : integer); begin dy := -dy; y := y + dy; end;
Procedure border (x, y, r : integer); begin if (x + r >= GetMaxX - 1) or ( x - r <= 1) then charge_on_oppositeX( x, dx); if (y+r>=GetMaxY-1) or (y-r<=1) then charge_on_oppositeY ( y, dy); end;
procedure move (x, y, dx, dy : integer); замените на procedure move (var x, y: integer; dx, dy : integer); и в следующих 3х процедурах тоже
18192123
8.04.2007 20:51
Цитата(TarasBer @ 8.04.2007 17:36)
procedure move (x, y, dx, dy : integer); замените на procedure move (var x, y: integer; dx, dy : integer); и в следующих 3х процедурах тоже
ээээ.....теперь слишком много стало шаров.... и ещё половина шарика с красным контуром крутится в правом нижнем угле экрана.....
volvo
9.04.2007 5:13
Значит, смотри, в чем твои ошибки:
1) если ты думаешь, что
procedure escape (x, y, r, bgC : integer); begin Setcolor (bgC); circle (x, y, r); Floodfill(x, y, bgC); end;
сотрет с экрана то, что было нарисовано процедурой draw, то очень сильно ошибаешься... Не сотрет... Ибо ты не установила шаблон заливки через SetFillPattern, а по умолчанию заливается все сплошным белым цветом... Да это и лишнее, потому что гораздо проще воспользоваться готовой процедурой отрисовки залитого круга (FillEllipse)...
2) у тебя 2 шара в любом случае будут двигаться "синхронно", то есть при изменении направления движения одного изменится и направление движения второго. Неудивительно, кстати, переменных то на 2 шара всего по одной на координату X и Y... Если хочешь более "независимое" движение шаров - добавляй еще 2 переменные: dx2, dy2...
3) ты задаешь очень большие значения dx и dy, я немного уменьшил ...
Вот так, примерно (примерно - потому, что это тоже еще надо поправить - в момент касания шаром бордюра он затирается - пересмотри условия в процедуре Border): Нажмите для просмотра прикрепленного файла
Lapp
9.04.2007 18:11
Марина, я покажу пример программы, которая гоняет объекты по полю. Программа работает в текстовой моде и без меню, но в ней есть управление скоростями. Надеюсь, она будет тебе полезна в некотором отношении.. Дело в том, что в ней четко проведено деление: все, что относится к выводу на экран, выделено в отдельный модуль. Сама же основная программа осуществляет движение и управление. По идее, если вместо существующего модуля, работающего с текстом, написать модуль, работающий с графикой, то основную программу менять не нужно (кроме строчки uses). Модуль для графики можно написать по образу и подобию текстового, заменив текстовый вывод на графический (советы volvo тут очень пригодятся).
Попробуй разобраться в том, как все это работает. Используются абстрактные координаты и экранные, что дает гибкость и удобство. В тексте вместо кружочков - квадратики, но это не самое важное . Отражение происходит просто со сменой знака соответствующей составляющей скорости (без случайностей). Начальное положение, скорости и размеры задаются случайно. Названия процедур отражают их суть. Сами объекты называются "It" (оно, нечто ).
Управление скоростями такое: нужно выбрать объект, нажав клавишу с его номером (по умолчанию выбран первый). Стрелки вверх/вниз увеличивают/уменьшают вертикальную скорость выбранного объекта, влево/вправо - горизонтальную. Пробел делает паузу (продолжение любой клавишей), Esc завершает программу. Можкшь также поиграть параметрами в программе - например, NIt (количество объектов), скоростью.. По идее, она работает в окне любого размера.
Я не совсем до конца протестировал на точность перевода, если заметишь сбои - говори.
Вот головная программа:
{Moving It's} {By Lapp} uses CRT,ItsText;
var x1,x2,y1,y2,MaxR,MaxV0:real;
procedure CreateIt(n:integer); begin with It[n] do begin r:=Random*MaxR; rx:=Round(r/(x2-x1)*(MaxX-MinX)); ry:=Round(r/(y2-y1)*(MaxY-MinY)); x:=x1+r+Random*(x2-x1-r*2); y:=y1+r+Random*(y2-y1-r*2); vx:=Random*MaxV0-MaxV0/2; vy:=Random*MaxV0-MaxV0/2; c:=(n+8)mod 15+1 end end;
procedure MoveIt(n:integer); begin with It[n] do begin x:=x+vx; if x<x1+r then begin x:=2*(x1+r)-x; vx:=-vx end; if x>x2-r then begin x:=2*(x2-r)-x; vx:=-vx end; y:=y+vy; if y<y1+r then begin y:=2*(y1+r)-y; vy:=-vy end; if y>y2-r then begin y:=2*(y2-r)-y; vy:=-vy end; xs:=Round((x-x1)/(x2-x1)*(MaxX-MinX))+MinX; ys:=Round((y-y1)/(y2-y1)*(MaxY-MinY))+MinY; end end;
var i,NIt,The:integer; ch:char; GameOver:boolean;
begin NIt:=9; {Number of It's, 1<=NIt<=9} MaxV0:=50; {Maximum speed } MaxR:=50; {Maximum radius}
OpenBoard; x1:=0; x2:=MaxX*10; y1:=0; y2:=Round(MaxY*10*Aspect); Randomize; for i:=1 to NIt do begin CreateIt(i); MoveIt(i) end; GameOver:=false; for i:=1 to NIt do ShowIt(i); The:=1; repeat for i:=1 to NIt do begin MoveIt(i); with It[i] do if (xs<>xs0)or(ys<>ys0) then begin HideIt(i); ShowIt(i) end end; if KeyPressed then begin ch:=ReadKey; case ch of #0: begin ch:=ReadKey; with It[The] do case ch of #72:if vy<100 then vy:=vy*2; #75:if vx>0.01 then vx:=vx*0.5; #77:if vx<100 then vx:=vx*2; #80:if vy>0.01 then vy:=vy*0.5; end end; '1'..'7':The:=Ord(ch)-48; ' ':repeat ReadKey until not KeyPressed; #27:GameOver:=true end end until GameOver; for i:=1 to NIt do HideIt(i); CloseBoard end.
А это - текстовый модуль:
{unit for moving It's} {by Lapp} unit ItsText; interface uses CRT;
const MIt=9; {max number of Iteatures}
type tIt=record x,y,vx,vy,r:real; {position, speed, real radius} rx,ry,c,xs,ys,xs0,ys0:integer; {screen radius, color, screen pos, old screen pos} end;
var It:array[1..MIt]of tIt; NIt:integer; Aspect,MinX,MinY,MaxX,MaxY,x0,y0:integer; TA:byte;
procedure HideIt(n:integer); var i,j:integer; begin with It[n] do begin for j:=ys0-ry to ys0+ry do for i:=xs0-rx to xs0+rx do begin GoToXY(i,j); Write(' ') end; end end;
procedure OpenBoard; begin MinX:=1; MaxX:=WindMax and 255+1; MinY:=1; MaxY:=WindMax shr 8+1; Aspect:=2; x0:=WhereX; y0:=WhereY; TA:=TextAttr end;
procedure CloseBoard; begin GoToXY(x0,y0); TextAttr:=TA end;
begin end.
18192123
9.04.2007 22:37
Цитата(Lapp @ 9.04.2007 15:11)
Марина, я покажу пример программы, которая гоняет объекты по полю.
Спасибо! Буду разбираться!
18192123
10.04.2007 1:02
Цитата(volvo @ 9.04.2007 2:13)
в момент касания шаром бордюра он затирается - пересмотри условия в процедуре Border):
Не пойму, почему происходит "затирание"?
Добавлено через 8 мин. Такой вопрос: как учесть (при столкновении) изменение угла движения?
volvo
10.04.2007 1:23
Цитата
Не пойму, почему происходит "затирание"?
Потому, что надо сначала менять положение шара, и только потом проверять его на столкновение с бордюром, правда?
Вот так:
... move (x1, y1, dx1, dy1); { <--- Сначала это } move (x2, y2, dx2, dy2); border (x1, y1, r1, dx1, dy1); { <--- и только потом - проверка } border (x2, y2, r2, dx2, dy2); ...
Цитата
как ещё учесть (при пристолкновении) изменение угла движения?
Ты имеешь в виду при столкновении шаров между собой? Тебе понадобится функция, определяющая, было ли такое столкновение... На каждом шаге кроме того, что ты проверяешь столкновения шаров с бортом, надо будет вызывать еще и эту функцию, и если столкновение было (расстояние между центрами шаров меньше суммы их радиусов), то менять направление движения...
А вот как менять - это уже зависит от того, насколько реалистично ты это хочешь сделать... Можно просто поменять знак DX или DY на противоположный, можно рассчитать новые направления движения шаров по формулам...
18192123
10.04.2007 2:56
Цитата(volvo @ 9.04.2007 22:23)
А вот как менять - это уже зависит от того, насколько реалистично ты это хочешь сделать... Можно просто поменять знак DX или DY на противоположный, можно рассчитать новые направления движения шаров по формулам...
Я хочу делать наиболее реалистично... Про ф-цию - понятно, буду делать. Спасибо.
Lapp
10.04.2007 4:41
Цитата(18192123 @ 9.04.2007 23:56)
Я хочу делать наиболее реалистично... Про ф-цию - понятно, буду делать. Спасибо.
Реалистично - я уже говорил: нужно вводить массы. Тогда можно будет использовать ЗСИ. Но это можно сделать только имея нормальную интерперетацию скорости! В моем примере скорость практически реальная, при этом время течет квантами (в цикле). Посмотри, как это устроено, и сможешь менять скорость по ЗСИ.
Для максимальной реалистичности можно использовать натуральное время (в секундах) и натуральные рамеры экранного окна (в см). Это не так сложно, но реально того, как сделано в моей проге, достаточно для описания физики соударений. Только там у меня рассчитано на несколько (до 9) объектов, при этом проверка на соударение производится, ессно, циклом по всем для каждого. При девяти это еще не так много, но если еще увеличивать количество, то производительность может начать падать..
за что отвечают переменные x1,x2,y1,y2 и Aspect,MinX (относительно чего определяется максимальные и минимальные координаты?),MinY,MaxX,MaxY,x0,y0 и ТА ?
Lapp
11.04.2007 5:13
Цитата(18192123 @ 11.04.2007 0:36)
за что отвечают переменные x1,x2,y1,y2 и Aspect,MinX (относительно чего определяется максимальные и минимальные координаты?),MinY,MaxX,MaxY,x0,y0 и ТА ?
Вот, смотри. x1,x2,y1,y2 - это абстрактные координаты, приписанные окну (границы по Х и по У). Им можно приписать любые значения (есть только ограничения x1<x2 и y1<y2, но и они появляются не сразу, а только при рассмотрении выхода шарика за границу окна). Например, если исходить из реальных размеров на экране, то им можно дать значения в см, типа от 0 до 20 по Х и от 0 до 10 по У. Но если ты представляешь себе окно, как поле космического сражения (в игре), то можно присвоить им значения от 100 до 200 парсеков по Х и от 0 до 50 парсеков по У, например. Если (другой пример) ты используешь окно для построения графика, при этом строишь в нем график синуса, то разумно по Х сделать от -пи до +пи, а по У - от -1 до +1 (или от +1 до -1, поскольку при построении графика не нужно проверять выход за границы окна).
Эти абстрактные координаты мспользуются для осуществления движения шариков. То есть пересчет координат по скорости со времением происходит именно в них. Перевод в реальные координаты экрана (пикселы в графике или символы в тексте) производится только перед выводом (за небольшим исключением, скажу позже). Существуют формулы для перевода, они явно написаны, например, в процедурах ShowIt (ПоказатьЭто) и HideIt (СпрятатьЭто).
Aspect - это параметр, который учитывает "неквадратность" точки. Точка - это маленькое пятнышко. В идеале это квадратик (в ЖК-мониторах так и есть) поверхности, который закрашен в некоторый цвет. В современных мониторах пиксел имеет одинаковые размеры по горизонтали и вертикали (даже если это не квадратик, а пятнышко, как в ЭЛТ-мониторе). Иными словами, сместившись на 100 пикселов вправо и 100 вниз, мы пройдем (примерно) 2.5 см вправо и 2.5 см вниз. Это было не всегда - в старых мониторах типа EGA и CGA эти пути были не равны - но сейчас можно считать, что это так (хотя в некоторых модах все же бывает искажение). Совсем другое дело в текстовой моде.. Пиксел (символ) в ней совсем не квадратный, это прямоугольник. Вот это число, Aspect, как раз и учитывает эту неквадратность. Сейчас объясню, как.
Окно может быть разным - большим, маленьким. (Попробуй менять размер окна. Правда, для этого, пожалуй, нужно использовать FPC.. Кстати, какой компилятор ты используешь?) Я стараюсь сделать абстрактные координаты так, чтоб они как-то соответствовали размерам окна. Поэтому я сначала, в процедуре OpenBoard (ОткрытьПоле) выясняю его размеры (в символах):
MinX:=1; MaxX:=WindMax and 255+1; MinY:=1; MaxY:=WindMax shr 8+1;
Информацию о переменной WindMax смотри в описании модуля CRT. MinX,MinY,MaxX,MaxY - это реальные координаты окна на экране, в пикселах (символах).
После этого я вычисляю абстрактные координаты по реальным, давая по 10 абстрактных единиц на одну ширину пиксела (символа) :
Применение переменной Aspect тут должно учесть, что пиксел наш не квадратный. В моем примере я ему присвоил значение 2, поскольку высота символа примерно вдвое больше ширины (если хочешь, можешь измерить и уточнить это значение).
Что это нам дает? А вот, что. Если скорости объекта (ну, пока скажем, пиксела) по Х и У одинаковые, то без учета Aspect'а, если пиксел смещать за один цикл на одну позицию, то реальная скорость пиксела на экране по У будет вдвое больше, чем по Х. Мы же делаем так: по формулам с учетом скоростей по Х и У мы высчитываем новое положение объекта. Допустим, по Х он смещается на расстояние 1 пкс, и скорости по Х и У равны. Тогда использование Aspect=2 даст то, что по У смещение будет 0.5 пкс, то есть реально объект по У не сместится. На следующем цикле объект сместится по Х еще на 1 пкс, а по У - еще на 0.5 пкс, что в сумме со смещением на предыдущем ходу даст 1 (0.5+0.5=1). На этот раз объект сместится по У на 1 пкс. Мы же увидим на экране ломаную траекторию, но ведущую в правильном направлении (под 45 градусов).
Этот способ - двойные координаты, абстрактные и реальные - очень эффективен в разных ситуациях. Иногда желательно иметь тройные координаты (например, пикселы - экранные_сантиметры - парсеки). Большей глубины вложения я пока не встречал, хотя возможно.
Таким образом, можно реально осуществлять движение объектов во всех направлениях и при этом скорости по Х и У будут соотноситься между собой правильно. Идея понятна? Про реализацию еще можно повыяснять..
Ну, а ТА, x0, y0 - это глупости... В некотором смысле лишнее , но желательное. В эту переменную я запоминаю текущие текстовые атрибуты (цвет символа и цвет фона), чтобы вернуть их по завершении работы программы на место. Я также возвращаю на место курсор (все это в процедуре CloseBoard, ЗакрытьПоле), для запоминания которых я и использую x0 и y0. Если это не сделать, то курсор останется в том месте, где рисовался последний объект, и цвет символов будет такой же, как цвет последнего объекта. Это все тебе в графике не понадобится..
Успехов, и продолжай задавать вопросы.
18192123
12.04.2007 17:43
возник такой вопрос: если теоретически я должна управлять скоростью движения шаров с клавиатуры, есть ли смысл, чтобы писать процедуру, которая бы вычисляла скорости шаров после столкновения, опираясь на ЗСИ (з-н сохранения импульса)? По-моему, смысла в этом нет... или я не права?
18192123
13.04.2007 0:49
Попыталась добавить в программу движение под углом и меню (не знаю, как при выборе одного из пунктов потом снова вернутся с главное меню.....)
кроме того, проблема в function balls_hit ( на ней выдает ошибку 207)...
что касается реальных и абстрактных координат, то посоветовалась со своим преподавателем.... он сказал, что мне не стоит на этом заоострять внимание (но всё равно спасибо большое, мне это было полезно узнать).
ниже программа....
Lapp
13.04.2007 2:52
Цитата(18192123 @ 12.04.2007 14:43)
если теоретически я должна управлять скоростью движения шаров с клавиатуры, есть ли смысл, чтобы писать процедуру, которая бы вычисляла скорости шаров после столкновения, опираясь на ЗСИ (з-н сохранения импульса)?
Вопрос не вполне понятен.. Неясня связь между твоим "если" и "то". Управляешь с клавы - ну, управляй. А при чем тут столкновение? Вычисляй по ЗСИ или еще как-то (случайно - это, мне кажется выглядело вы дико на экране). А может, ты спрашивала, есть ли смысл делать отдельную процедуру для этого или вычислять прямо в тексте?.. Это вопрос вкуса, но я вообще не понимаю (блин, так много стал не понимать.. ), почему ты делаешь из этого проблему.. ЗСИ - это звучит гордо, даже в сокращении, но фактически - это одна строчка несложных действий! Реши один раз на бумажке (столкновение считай абсолютно упругим), набей это в Паскаль - и забудь про физику! только не на всю жизнь.. )))
Цитата(18192123 @ 12.04.2007 21:49)
что касается реальных и абстрактных координат, то посоветовалась со своим преподавателем.... он сказал, что мне не стоит на этом заоострять внимание (но всё равно спасибо большое, мне это было полезно узнать).
Дело твое, и в принципе я согласен - начинать нужно с самого простого. Но штука в том, что потом (если продолжишь этим заниматься) ты можешь открыть для себя совершенно неожиданно, что абстрактные координаты не усложняют, а упрощают реализацию. Потому что многие вопросы, которым нужно было придумывать специальное решение, тут решаются сами собой очень естественным образом.. Но я согласен, что чтобы осознать это, нужно набраться немного опыта. Успехов тебе в этом - а я, если найду время вставить комменты, выложу это в FAQ, чтоб не пропадало..
18192123
13.04.2007 12:48
Цитата(Lapp @ 12.04.2007 23:52)
Управляешь с клавы - ну, управляй. А при чем тут столкновение? Вычисляй по ЗСИ или еще как-то (случайно - это, мне кажется выглядело вы дико на экране).
Спасибо , на мой вопрос ты ответил.
18192123
14.04.2007 17:45
Цитата(18192123 @ 12.04.2007 21:49)
Попыталась добавить в программу движение под углом и меню (не знаю, как при выборе одного из пунктов потом снова вернутся с главное меню.....)
кроме того, проблема в function balls_hit ( на ней выдает ошибку 207)...
что касается реальных и абстрактных координат, то посоветовалась со своим преподавателем.... он сказал, что мне не стоит на этом заоострять внимание (но всё равно спасибо большое, мне это было полезно узнать).
ниже программа....
никак не получается найти ошибки....
volvo
14.04.2007 19:01
Цитата
никак не получается найти ошибки....
Насчет #207, которая возникает в balls_hit ...
Для того, чтобы разобраться, откуда возникает эта ошибка, надо вспомнить, что же это вообще такое - RunTime Error #207:
Цитата
Invalid Floating Point Operation (Недопустимая операция с плавающей запятой) Возможные причины возникновения: 1. Аргумент функции Trunc или Round не может быть преобразован в целое число, находящееся внутри диапазона типа LongInt. 2. Отрицательный аргумент функции Sqrt. 3. Аргумент функции Ln равен нулю, или имеет отрицательное значение. 4. Произошло переполнение стека сопроцессора
Путем небольшой модификации программы (для проверки, КАКАЯ именно из причин приводит к ошибке в твоем случае), выяснилось, что это - причина №4... Вот так программа работает без #207:
.... меню (не знаю, как при выборе одного из пунктов потом снова вернутся с главное меню.....)
с этим тоже проблема... как можно это реализовать?
volvo
14.04.2007 22:20
Цитата
как можно это реализовать?
Обрамляешь все, что делается в меню Repeat / Until ... Вот так:
... Begin Gd := Detect; InitGraph (Gd, Gm, ''); If GraphResult <> grOk then halt(1);
repeat Choise := Menu ('INFO'#13'Ypravlenie'#13'Moving Balls'#13'Exit'); ... { Здесь - все, что было у тебя в программе от Choise := Menu() до ReadKey } until Choise = 3;
ReadKey; CloseGraph; End.
18192123
14.04.2007 23:54
вот такие вопросы появились: 1. если шарики соприкасаются, то они просто проходят сквозь друг друга, а предполагалось, что направление будет меняться... в чём же дело?
2. не понимаю, как изменить угол ( для взятия угла у меня function ygol) при столкновении со стенками и при столкновени шаров...я применяла эту функцию (это место в программе взято в комментарий), но шарики при движении только колебаются.....
3. про варьирование скоростью с помощью стрелок управления курсором.... не пойму сам механизм этого ( "привязать" к этому клавиши - это ладно..., но вот, так скажем, к чему привязывать - ну не пойму!)
18192123
16.04.2007 2:23
Цитата(18192123 @ 14.04.2007 20:54)
вот такие вопросы появились: 1. если шарики соприкасаются, то они просто проходят сквозь друг друга, а предполагалось, что направление будет меняться... в чём же дело?
2. не понимаю, как изменить угол ( для взятия угла у меня function ygol) при столкновении со стенками и при столкновени шаров...я применяла эту функцию (это место в программе взято в комментарий), но шарики при движении только колебаются.....
3. про варьирование скоростью с помощью стрелок управления курсором.... не пойму сам механизм этого ( "привязать" к этому клавиши - это ладно..., но вот, так скажем, к чему привязывать - ну не пойму!)
помогите, пожалуйста! очень хочу разобраться!!!
18192123
17.04.2007 1:46
Цитата(18192123 @ 14.04.2007 20:54)
вот такие вопросы появились: 1. если шарики соприкасаются, то они просто проходят сквозь друг друга, а предполагалось, что направление будет меняться... в чём же дело?
2. не понимаю, как изменить угол ( для взятия угла у меня function ygol) при столкновении со стенками и при столкновени шаров...я применяла эту функцию (это место в программе взято в комментарий), но шарики при движении только колебаются.....
3. про варьирование скоростью с помощью стрелок управления курсором.... не пойму сам механизм этого ( "привязать" к этому клавиши - это ладно..., но вот, так скажем, к чему привязывать - ну не пойму!)
про 1 - может у меня с вызовом function balls_hit , procedure balls_hit_2, .........._3 что-то не то?
а с остальным - не получается.....
18192123
17.04.2007 23:05
по вопросу2:
begin dx := -dx; dy := -dy; x := round( x + dx*cos(ygol)); y := round( y + dy*sin(ygol)); end;
может я здесь dx и dy не к месту использую или нужно дополнительно вычислять расстояние , которое должен проходить шарик после изменения угла движения?
18192123
18.04.2007 1:53
а насчёт варьирования скоростями: от чего отталкиваться (какое условие задавать) ,чтобы регулировать скорости?
Lapp
18.04.2007 6:19
Цитата(18192123 @ 17.04.2007 22:53)
а насчёт варьирования скоростями: от чего отталкиваться (какое условие задавать) ,чтобы регулировать скорости?
Марина, привет. Я скажу немного не то, что ты, возможно, ожидаешь. Ты написала довольно большую программу - сама! что, безусловно, хорошо. Но ты пренебрегла советами.. что не всегда есть хорошо. Я посмотрел твою программу сразу после твоего поста #30, и пришел к выводу, что на разгребание того, что ты наворотила придется потратить несколько часов, а потом еще несколько часов на объяснеия, что там неправильно - и этого времени у меня нету.. Потом я честно посмотрел ее снова после поста 31 - повертел, покрутил и пришел к тому же выводу.. И т.д...
Если можно, я приведу сравнение.. Некто хочет научиться варить суп. Прежде всего он идет на кухню в общаге, хватает с плиты первую попавшуюся кастрюлю, тащит ее к шеф-повару и говорит: "Объясите мне пожалуйста, зачем тут вот эти штуки.." - и показывает на плавающие там обрывки упаковочной бумаги, куски полиэтилена (нет, волосы упоминать не буду, можете не зажмать рты.. ). Что может сказать шеф-повар? Его спросили не нужно ли это, а именно с какой целью это тут. Прямо показали пальчиком, и заинтересованно и серьезно ждут ответа.. Я думаю, он поступит как в том старом анекдоте из серии про студента кулинарного техникума (у Хазанова было такое амплуа), когда упомянутый студент пришел к врачу с обваренными гениталиями. Он скажет: "вылейте все это на ..."
После этого он прочтет бедному несчастному студенту лекцию на тему о варке супа, и проведет практическое занятие, а также подарит тарелку хорошего супа. А потом скажет, как это свойственно профессорам-шеф-поварам: если что неясно - я к Вашим услугам, милейший.
Но студент, уяснив кое-что (хоть и не много), говорит - а, не хочу я разбираться в его супе. Его суп слишком сложен для меня (и мой семинарист говорит, что мне такой суп никогда не сварить..) Сварю-ка я свой собственный суп.. И варит. Но суп получается горький, пересоленый, мясо в нем не разжевать.. Что делать? Конечно, идти к шеф-повару! И спрашивать: а зачем я сделал так? а почему я сделал этак?..
Понимаешь, если программа небольшая или речь идет о фрагменте, где локализована ошибка - это одно. Но если нужно расхлебывать весь переперченый недосоленный суп... И учесть еще неправильное форматирование текста.. Ей-Богу лучше вылить его ... Ты бы сделала хотя бы некоторый вывод из того, что тебе никто не отвечает!
Не знаю, поняла ли ты меня.. Если что не так сказал - извини, я не хотел тебя обидеть. Но только на твой вопрос (повторю его) :
Цитата(18192123 @ 17.04.2007 22:53)
а насчёт варьирования скоростями: от чего отталкиваться (какое условие задавать) ,чтобы регулировать скорости?
- на этот вопрос я ответил в самом начале темы. Если хочешь - я могу снова подключиться. Но только не для того, чтобы отвечать на вопросы типа "а как пришить пуговицу пеньковой веревкой?". Если согласна - you are welcome!
18192123
19.04.2007 2:50
Если у меня положения центров шаров будут находиться с помощью такой процедуры:
procedure move (var x, y: integer; angle : single; speed : integer); begin x := round(x + speed*cos(angle)); y := round(y + speed*sin(angle)); end;
то как должны выглядеть процедуры procedure charge_on_oppositeX procedure charge_on_oppositeY, которые я использую для изменения направления движения шариков на противоположные при столкновении с границей?
Я сделала предположение ,что так:
procedure charge_on_oppositeX (var x : integer; speed : integer; angle : single); var dx : integer; begin dx := round(speed*cos(angle)); dx := -dx; x := x + dx; end;
результат - шарики ,когда сталкиваются с границей , движутся вдоль неё и замирают в углу.
Lapp
19.04.2007 10:29
Цитата(18192123 @ 18.04.2007 23:50)
как должны выглядеть процедуры ..., которые я использую для изменения направления движения шариков на противоположные при столкновении с границей? Я сделала предположение ,что так: ... результат - шарики ,когда сталкиваются с границей , движутся вдоль неё и замирают в углу.
Нет, не так. Эти процедуры долхны менять угол, а не положение! Примерно так: по Х: angle:=180-angle; по Y: angle:=-angle; Иначе эффект действительно будет похожим на то, что ты говоришь
PS Если в названиях процедур ты подразумевала "изменить", то это слово пишется change. А слово charge означает нечто другое.. И предлог лучше to, а не on. Это так, к слову..
Добавлено через 15 мин. Вообще-то правильние было бы написать не 180, а Pi .. Извиняюсь.
18192123
19.04.2007 17:46
Цитата(Lapp @ 19.04.2007 7:29)
Примерно так: по Х: angle:=180-angle; по Y: angle:=-angle;
С этим получилось , но в результате , если один из шаров сталкивается с границей, то и второй , где бы он не находился в этот момент, меняет свой угол движения.
Как я полагаю, причина в этом:
function angleX (angle : single):single; begin angleX := (pi - angle); end;
function angleY (angle : single): single; begin angleY := -angle; end;
Procedure border (var x, y: integer; r : integer; speed: integer{; angle : single}); begin if (x + r >= GetMaxX-1) or (x - r <= 1) then angle := angleX(angle); if (y + r >= GetMaxY-1) or (y - r <= 1) then angle := angleY(angle); end;
если менять скорость обоих шариков одновременно , то , когда шарики сталкиваются, то они просто сцепливаются.... - не знаю, как это исправить?) столкновение шаров предусмотрено в следующих процедурах:
function value(const r: integer):real; begin value := 4/3*pi*r*r*r; end;
procedure balls_hit_2; begin if balls_hit(r1,r2,x1,y1,x2,y2) then after_hit (speed1, speed2, x1, y1,x2, y2,angle); end;
Lapp
20.04.2007 2:47
Цитата(18192123 @ 19.04.2007 14:46)
С этим получилось , но в результате , если один из шаров сталкивается с границей, то и второй , где бы он не находился в этот момент, меняет свой угол движения.
Видимо, у тебя один угол на два шара. А надо иметь на каждый шар свой угол.
18192123
20.04.2007 12:33
Цитата(Lapp @ 19.04.2007 23:47)
Видимо, у тебя один угол на два шара. А надо иметь на каждый шар свой угол.
а как учесть два угла для разных шаров в процедуре border (может нужно и туда передавать углы?) или это нужно учитывать в ф-ях angleX и angleY?
18192123
22.04.2007 3:21
Мне бы хотелось, чтобы шарики, при столкновении друг с другом, изменяли угол движения... но добиться этого не удаётся:
{проверка на столкновение} function balls_hit (const r1,r2 : integer; x1,y1,x2,y2 : integer) : boolean; var dist : real; t1, t2, t3, t4, t5: real; begin t1 := abs(x2-x1); t2 := sqr(t1); t3 := abs(y2-y1); t4 := sqr(t3); t5 := t2 + t4; dist := sqrt(t5);
balls_hit := (dist < (r1 + r2)); end;
{если шары стлкнулись - изменяем скорость и угол } procedure balls_hit_2; begin if balls_hit(r1,r2,x1,y1,x2,y2) then after_hit (speed1, speed2, x1, y1,x2, y2,angle1,angle2); end;
но шарики только проводят друг через друга.....
18192123
22.04.2007 3:42
Цитата(18192123 @ 22.04.2007 0:21)
но шарики только проводят друг через друга.....
не пойму, в чём причина?
Lapp
22.04.2007 14:20
Цитата(18192123 @ 22.04.2007 0:42)
не пойму, в чём причина?
Причин несколько. 1. ты снова забываешь сменить углы.. 2. одна переменная у тебя называется spee1 (должно быть, видимо, speed1) 3. Ты пересчитываешь параметры, но обратно из процедуры они у тебя не передаются. Чтоб передавались, используй декларацию var.
Можно один вопрос? Зачем ты искусственно увеличиваешь код программы? Тебе кажется, так проще? или так от вас требуют препы? Например, функция balls_hit моогла бы выглядеть много короче..
function balls_hit (r1,r2,x1,y1,x2,y2 : integer) : boolean; begin balls_hit := Sqrt(Sqr(x2-x1)+Sqr(y2-y1)) < r1+r2 end;
Разве так не проще? Все сразу видно..
18192123
22.04.2007 19:32
Цитата(Lapp @ 22.04.2007 11:20)
Например, функция balls_hit моогла бы выглядеть много короче..
function balls_hit (r1,r2,x1,y1,x2,y2 : integer) : boolean; begin balls_hit := Sqrt(Sqr(x2-x1)+Sqr(y2-y1)) < r1+r2 end;
Разве так не проще? Все сразу видно..
ф-я работала некорректно , компилятор выдавал ошибку 207, и чтобы понять причину этого выражение Sqrt(Sqr(x2-x1)+Sqr(y2-y1)) < r1+r2 было разбито на более простые (пост #27)
18192123
23.04.2007 0:38
Цитата(Lapp @ 22.04.2007 11:20)
3. Ты пересчитываешь параметры, но обратно из процедуры они у тебя не передаются. Чтоб передавались, используй декларацию var.
не совсем тебя поняла....какие параметры я ещё должна описать внутри ф-ции? (всё, что нужно я уже передаю из программы)
18192123
23.04.2007 1:01
Цитата(Lapp @ 22.04.2007 11:20)
ты снова забываешь сменить углы..
а как их менять? ( по какой состовляющей? ведь другой шарик - это не граница!)
Lapp
23.04.2007 4:47
Цитата(18192123 @ 22.04.2007 21:38)
не совсем тебя поняла....какие параметры я ещё должна описать внутри ф-ции? (всё, что нужно я уже передаю из программы)
- после этого выходишь из процедуры. Как ты думаешь, что случается с переменными x1,y1,x2,y2? Они просто уничтожаются. Чтобы они передавались в вызывающую программу, ты должна в описании фрмальных параметров употребить декларацию var :
Но у меня шарики всё равно проходят друг через друга...
Значит, так. 1. Ты выбрала очень неудобное представление - через углы (модули скоростей и углы). Я рекомендовал тебе давно иметь просто Vx и Vy для каждого шара вместо модуля скорости и угла. Ты бы избежала очень многих проблем (это я все брюзжу про то, что то, что кажется на первый взгляд сложнее, на самом деле легче).
2. Тебе совсем не нужно вычислять координаты (x и y) в этой процедуре. Вычисляй только параметры скорости (в твоем представлении - модуль и угол). Только эти параметры используй в загаловке процедуры и описывай их как var.
3. Скорость персчитывай по ЗСИ по каждой компоненте вектора (Vx и Vy). Для этого сначала высчитай эти компоненты (как модуль скорости умножить на косинус и синус угла), потом для каждой реши уравнение ЗСИ и пересчитай. По этим новым компонентам рассчитай новый модуль скорости и угол. Эти значения нужно вернуть в вызывающую программу.
Вот так все будет работать..
PS Представление в виде модуля и угла удобно только в реальном пространстве. Если осилишь - переделай всю прогу, замени их на компоненты по осям. Ты сама увидишь, насколько будет проще. Я уж не говорю, что на том способе, который я предлагал в начале (абстрактные координаты) ты могла бы сэкономить себе много дней времени..
18192123
25.04.2007 0:59
Цитата(Lapp @ 24.04.2007 11:14)
3. Скорость персчитывай по ЗСИ по каждой компоненте вектора (Vx и Vy). Для этого сначала высчитай эти компоненты (как модуль скорости умножить на косинус и синус угла), потом для каждой реши уравнение ЗСИ и пересчитай. По этим новым компонентам рассчитай новый модуль скорости и угол. Эти значения нужно вернуть в вызывающую программу.