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

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

Форум «Всё о Паскале» _ Написание игр _ Моделирование движения шаров

Автор: 18192123 4.04.2007 1:03

Вот такое задание:
Даны два шарика диаметром М. Промоделировать движение шариков по всей плоскости экрана. Шарики могут двигаться по прямым линиям. Изменение угла движения после столкновения с границей экрана или друг с другом может быть случайной величиной. Шарик не может вылететь за пределы квадрата. Пользователь может варьировать скорости движения шариков с помощью стрелок управления курсором.

Хотелось бы разобраться в коде программы... ( дело в том, что код не мой)
Объясните пожалуйста назначение каждой из процедур в тексте приведённой ниже программы!


Прикрепленные файлы
Прикрепленный файл  CIRCLES.PAS ( 10.21 килобайт ) Кол-во скачиваний: 705

Автор: 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. Управление скоростями с помощью стрелок на клавиатуре - не представляю, как это осуществить!

Все мои соображения..... unsure.gif

Автор: Tan 8.04.2007 2:32

Случайно на компе наткнулся на задачку с шариком погляди может какие - то идем возьмёшь, не помню откуда эта прога в упор cool.gif :

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

Мои "очень скромные" наработки.....
вот только шарики не хотят двигаться...


uses crt,
graph;
var x1, x2, y1, y2, r1, r2,
dx, dy, bgC, Gd, Gm : integer;

procedure draw (x, y, r, c : integer);
begin
Setcolor ©;
circle (x, y, r);
Floodfill(x, y, c);
end;

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;

begin
Gd := Detect;
InitGraph (Gd, Gm, '');
If GraphResult <> grOk then halt(1);
x1 := 50; y1 := 150; x2 := 400; y2 := 300; r1 := 30; r2 := 40; dx := 100; dy := 90;
bgC := 0;
rectangle (1,1, getMaxX - 1, getMaxY - 1);
repeat
begin
draw (x1, y1, r1, white);
draw (x2, y2, r2, red );
delay(100);
escape (x1, y1, r1, bgC);
escape (x2, y2, r2, bgC);
border (x1, y1, r1);
border (x2, y2, r2);
move (x1, y1, dx, dy);
move (x2, y2, dx, dy);
end;
until keypressed;
readkey;
closegraph;
end.



Автор: TarasBer 8.04.2007 20:36

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):
Прикрепленный файл  circles.pas ( 1.5 килобайт ) Кол-во скачиваний: 560

Автор: Lapp 9.04.2007 18:11

Марина, я покажу пример программы, которая гоняет объекты по полю. Программа работает в текстовой моде и без меню, но в ней есть управление скоростями. Надеюсь, она будет тебе полезна в некотором отношении..
Дело в том, что в ней четко проведено деление: все, что относится к выводу на экран, выделено в отдельный модуль. Сама же основная программа осуществляет движение и управление. По идее, если вместо существующего модуля, работающего с текстом, написать модуль, работающий с графикой, то основную программу менять не нужно (кроме строчки uses). Модуль для графики можно написать по образу и подобию текстового, заменив текстовый вывод на графический (советы volvo тут очень пригодятся).

Попробуй разобраться в том, как все это работает. Используются абстрактные координаты и экранные, что дает гибкость и удобство. В тексте вместо кружочков - квадратики, но это не самое важное smile.gif. Отражение происходит просто со сменой знака соответствующей составляющей скорости (без случайностей). Начальное положение, скорости и размеры задаются случайно. Названия процедур отражают их суть. Сами объекты называются "It" (оно, нечто smile.gif).

Управление скоростями такое: нужно выбрать объект, нажав клавишу с его номером (по умолчанию выбран первый). Стрелки вверх/вниз увеличивают/уменьшают вертикальную скорость выбранного объекта, влево/вправо - горизонтальную. Пробел делает паузу (продолжение любой клавишей), 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 ShowIt(n:integer);
procedure HideIt(n:integer);
procedure OpenBoard;
procedure CloseBoard;

implementation

procedure ShowIt(n:integer);
var
i,j,xs1,ys1,rx,ry:integer;
begin
with It[n] do begin
TextColor©;
for j:=ys-ry to ys+ry do for i:=xs-rx to xs+rx do begin
GoToXY(i,j);
Write('█')
end;
GoToXY(xs,ys); Write(n);
xs0:=xs;
ys0:=ys;
end
end;

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

Цитата
Не пойму, почему происходит "затирание"?

Потому, что надо сначала менять положение шара, и только потом проверять его на столкновение с бордюром, правда? smile.gif

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

Автор: 18192123 11.04.2007 3:36

Цитата(Lapp @ 9.04.2007 15:11) *




x1,x2,y1,y2 : real;




А это - текстовый модуль:

{unit for moving It's}
{by Lapp}
It:array[1..MIt]of tIt;
NIt:integer;
Aspect,MinX,MinY,MaxX,MaxY,x0,y0:integer;
TA:byte;




за что отвечают переменные 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 абстрактных единиц на одну ширину пиксела (символа) :
  x1:=0; x2:=MaxX*10;
y1:=0; y2:=Round(MaxY*10*Aspect);

Применение переменной Aspect тут должно учесть, что пиксел наш не квадратный. В моем примере я ему присвоил значение 2, поскольку высота символа примерно вдвое больше ширины (если хочешь, можешь измерить и уточнить это значение).

Что это нам дает? А вот, что.
Если скорости объекта (ну, пока скажем, пиксела) по Х и У одинаковые, то без учета Aspect'а, если пиксел смещать за один цикл на одну позицию, то реальная скорость пиксела на экране по У будет вдвое больше, чем по Х. Мы же делаем так: по формулам с учетом скоростей по Х и У мы высчитываем новое положение объекта. Допустим, по Х он смещается на расстояние 1 пкс, и скорости по Х и У равны. Тогда использование Aspect=2 даст то, что по У смещение будет 0.5 пкс, то есть реально объект по У не сместится. На следующем цикле объект сместится по Х еще на 1 пкс, а по У - еще на 0.5 пкс, что в сумме со смещением на предыдущем ходу даст 1 (0.5+0.5=1). На этот раз объект сместится по У на 1 пкс. Мы же увидим на экране ломаную траекторию, но ведущую в правильном направлении (под 45 градусов).

Этот способ - двойные координаты, абстрактные и реальные - очень эффективен в разных ситуациях. Иногда желательно иметь тройные координаты (например, пикселы - экранные_сантиметры - парсеки). Большей глубины вложения я пока не встречал, хотя возможно.

Таким образом, можно реально осуществлять движение объектов во всех направлениях и при этом скорости по Х и У будут соотноситься между собой правильно. Идея понятна? Про реализацию еще можно повыяснять.. smile.gif

Ну, а ТА, x0, y0 - это глупости... В некотором смысле лишнее smile.gif, но желательное. В эту переменную я запоминаю текущие текстовые атрибуты (цвет символа и цвет фона), чтобы вернуть их по завершении работы программы на место. Я также возвращаю на место курсор (все это в процедуре CloseBoard, ЗакрытьПоле), для запоминания которых я и использую x0 и y0. Если это не сделать, то курсор останется в том месте, где рисовался последний объект, и цвет символов будет такой же, как цвет последнего объекта. Это все тебе в графике не понадобится..

Успехов, и продолжай задавать вопросы. smile.gif

Автор: 18192123 12.04.2007 17:43

возник такой вопрос: если теоретически я должна управлять скоростью движения шаров с клавиатуры, есть ли смысл, чтобы писать процедуру, которая бы вычисляла скорости шаров после столкновения, опираясь на ЗСИ (з-н сохранения импульса)? По-моему, смысла в этом нет... или я не права?

Автор: 18192123 13.04.2007 0:49

Попыталась добавить в программу движение под углом и меню (не знаю, как при выборе одного из пунктов потом снова вернутся с главное меню.....)

кроме того, проблема в function balls_hit ( на ней выдает ошибку 207)...

что касается реальных и абстрактных координат, то посоветовалась со своим преподавателем....
он сказал, что мне не стоит на этом заоострять внимание (но всё равно спасибо большое, мне это было полезно узнать).

ниже программа....




Прикрепленные файлы
Прикрепленный файл  CIRCLES2.PAS ( 4.95 килобайт ) Кол-во скачиваний: 272

Автор: Lapp 13.04.2007 2:52

Цитата(18192123 @ 12.04.2007 14:43) *

если теоретически я должна управлять скоростью движения шаров с клавиатуры, есть ли смысл, чтобы писать процедуру, которая бы вычисляла скорости шаров после столкновения, опираясь на ЗСИ (з-н сохранения импульса)?

Вопрос не вполне понятен..
Неясня связь между твоим "если" и "то". blink.gif Управляешь с клавы - ну, управляй. А при чем тут столкновение? Вычисляй по ЗСИ или еще как-то (случайно - это, мне кажется выглядело вы дико на экране).
А может, ты спрашивала, есть ли смысл делать отдельную процедуру для этого или вычислять прямо в тексте?.. Это вопрос вкуса, но я вообще не понимаю (блин, так много стал не понимать.. smile.gif), почему ты делаешь из этого проблему.. ЗСИ - это звучит гордо, даже в сокращении, но фактически - это одна строчка несложных действий! Реши один раз на бумажке (столкновение считай абсолютно упругим), набей это в Паскаль - и забудь про физику! только не на всю жизнь.. smile.gif)))
Цитата(18192123 @ 12.04.2007 21:49) *

что касается реальных и абстрактных координат, то посоветовалась со своим преподавателем....
он сказал, что мне не стоит на этом заоострять внимание (но всё равно спасибо большое, мне это было полезно узнать).

Дело твое, и в принципе я согласен - начинать нужно с самого простого. Но штука в том, что потом (если продолжишь этим заниматься) ты можешь открыть для себя совершенно неожиданно, что абстрактные координаты не усложняют, а упрощают реализацию. Потому что многие вопросы, которым нужно было придумывать специальное решение, тут решаются сами собой очень естественным образом.. smile.gif Но я согласен, что чтобы осознать это, нужно набраться немного опыта. Успехов тебе в этом - а я, если найду время вставить комменты, выложу это в 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:

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;


Автор: 18192123 14.04.2007 21:20

Цитата(18192123 @ 12.04.2007 21:49) *

.... меню (не знаю, как при выборе одного из пунктов потом снова вернутся с главное меню.....)


с этим тоже проблема... как можно это реализовать?

Автор: 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. про варьирование скоростью с помощью стрелок управления курсором.... не пойму сам механизм этого ( "привязать" к этому клавиши - это ладно..., но вот, так скажем, к чему привязывать - ну не пойму!)


Прикрепленные файлы
Прикрепленный файл  CIRCLES2.PAS ( 5.57 килобайт ) Кол-во скачиваний: 267

Автор: 18192123 16.04.2007 2:23

Цитата(18192123 @ 14.04.2007 20:54) *

вот такие вопросы появились:
1. если шарики соприкасаются, то они просто проходят сквозь друг друга, а предполагалось, что направление будет меняться... в чём же дело?

2. не понимаю, как изменить угол ( для взятия угла у меня function ygol) при столкновении со стенками и при столкновени шаров...я применяла эту функцию (это место в программе взято в комментарий), но шарики при движении только колебаются.....

3. про варьирование скоростью с помощью стрелок управления курсором.... не пойму сам механизм этого ( "привязать" к этому клавиши - это ладно..., но вот, так скажем, к чему привязывать - ну не пойму!)

помогите, пожалуйста! очень хочу разобраться!!! smile.gif

Автор: 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 - повертел, покрутил и пришел к тому же выводу.. И т.д...

Если можно, я приведу сравнение..
Некто хочет научиться варить суп. Прежде всего он идет на кухню в общаге, хватает с плиты первую попавшуюся кастрюлю, тащит ее к шеф-повару и говорит: "Объясите мне пожалуйста, зачем тут вот эти штуки.." - и показывает на плавающие там обрывки упаковочной бумаги, куски полиэтилена (нет, волосы упоминать не буду, можете не зажмать рты.. smile.gif). Что может сказать шеф-повар? Его спросили не нужно ли это, а именно с какой целью это тут. Прямо показали пальчиком, и заинтересованно и серьезно ждут ответа.. Я думаю, он поступит как в том старом анекдоте из серии про студента кулинарного техникума (у Хазанова было такое амплуа), когда упомянутый студент пришел к врачу с обваренными гениталиями. Он скажет: "вылейте все это на ..."

После этого он прочтет бедному несчастному студенту лекцию на тему о варке супа, и проведет практическое занятие, а также подарит тарелку хорошего супа. А потом скажет, как это свойственно профессорам-шеф-поварам: если что неясно - я к Вашим услугам, милейший.

Но студент, уяснив кое-что (хоть и не много), говорит - а, не хочу я разбираться в его супе. Его суп слишком сложен для меня (и мой семинарист говорит, что мне такой суп никогда не сварить..) Сварю-ка я свой собственный суп.. И варит. Но суп получается горький, пересоленый, мясо в нем не разжевать.. Что делать? Конечно, идти к шеф-повару! И спрашивать: а зачем я сделал так? а почему я сделал этак?..

Понимаешь, если программа небольшая или речь идет о фрагменте, где локализована ошибка - это одно. Но если нужно расхлебывать весь переперченый недосоленный суп... И учесть еще неправильное форматирование текста.. Ей-Богу лучше вылить его ...
Ты бы сделала хотя бы некоторый вывод из того, что тебе никто не отвечает!

Не знаю, поняла ли ты меня.. Если что не так сказал - извини, я не хотел тебя обидеть. Но только на твой вопрос (повторю его) :
Цитата(18192123 @ 17.04.2007 22:53) *

а насчёт варьирования скоростями: от чего отталкиваться (какое условие задавать) ,чтобы регулировать скорости?

- на этот вопрос я ответил в самом начале темы. Если хочешь - я могу снова подключиться. Но только не для того, чтобы отвечать на вопросы типа "а как пришить пуговицу пеньковой веревкой?". Если согласна - you are welcome! smile.gif

Автор: 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;

результат - шарики ,когда сталкиваются с границей , движутся вдоль неё и замирают в углу.





Прикрепленные файлы
Прикрепленный файл  CIRCLES3.PAS ( 6.17 килобайт ) Кол-во скачиваний: 236

Автор: 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 .. smile.gif
Извиняюсь.

Автор: 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;




а это вызов процедур ,описанных выше:

begin
draw (x1, y1, r1, white);
draw (x2, y2, r2, red );
delay(15100);
escape (x1, y1, r1, bgC);
escape (x2, y2, r2, bgC);
move (x1, y1, angle, speed1);
move (x2, y2, angle, speed2);
border (x1, y1, r1, speed1{,angle} );
border (x2, y2, r2, speed2{, angle});
balls_hit_2;
end;



если менять скорость обоих шариков одновременно , то , когда шарики сталкиваются, то они просто сцепливаются.... - не знаю, как это исправить?)
столкновение шаров предусмотрено в следующих процедурах:

function value(const r: integer):real;
begin
value := 4/3*pi*r*r*r;
end;

procedure after_hit (spee1, speed2 : integer; x1, y1, x2, y2 : integer; angle : single);
var m1, m2 : real;
begin
m1 := value(r1);
m2 := value(r2);
speed1 := round((2*m2*speed2 + (m1-m2)*speed1)/(m1+m2));
speed2 := round((2*m1*speed1 + (m2-m1)*speed2)/(m1+m2));
x1 := round(x1 + speed1*cos(angle));
y1 := round(y1 + speed1*sin(angle));
x2 := round(x2 + speed2*cos(angle));
y2 := round(y2 + speed2*sin(angle));
end;


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,angle);
end;






Прикрепленные файлы
Прикрепленный файл  CIRCLES5.PAS ( 5.96 килобайт ) Кол-во скачиваний: 316

Автор: 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

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


{изменяем скорость и угол после столкновения}
procedure after_hit (spee1, speed2 : integer; x1, y1, x2, y2 : integer; angle1, angle2 : single);
var m1, m2 : real;
begin
m1 := value(r1);
m2 := value(r2);
speed1 := round((2*m2*speed2 + (m1-m2)*speed1)/(m1+m2));
speed2 := round((2*m1*speed1 + (m2-m1)*speed2)/(m1+m2));
x1 := round(x1 + speed1*cos(pi-angle1));
y1 := round(y1 + speed1*sin(-angle1));
x2 := round(x2 + speed2*cos(pi-angle2));
y2 := round(y2 + speed2*sin(-angle2));
end;

{проверка на столкновение}
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 := round(x1 + speed1*cos(pi-angle1));
y1 := round(y1 + speed1*sin(-angle1));
x2 := round(x2 + speed2*cos(pi-angle2));
y2 := round(y2 + speed2*sin(-angle2));
end;

- после этого выходишь из процедуры.
Как ты думаешь, что случается с переменными x1,y1,x2,y2? Они просто уничтожаются.
Чтобы они передавались в вызывающую программу, ты должна в описании фрмальных параметров употребить декларацию var :

procedure after_hit (spee1, speed2 : integer; VAR x1, y1, x2, y2 : integer; angle1, angle2 : single);

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

Автор: 18192123 24.04.2007 1:13

Цитата(Lapp @ 23.04.2007 1:47) *



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

Да, понятно. Извини, с этим я "стормозила" по полной программе.

Но у меня шарики всё равно проходят друг через друга...

procedure after_hit (var speed1, speed2 : integer; var x1, y1, x2, y2 : integer; var angle1, angle2 : single);
var m1, m2 : real;
begin
m1 := value(r1);
m2 := value(r2);
angle1 := -angle1;
angle2 := pi - angle2;
speed1 := round((2*m2*speed2 + (m1-m2)*speed1)/(m1+m2));
speed2 := round((2*m1*speed1 + (m2-m1)*speed2)/(m1+m2));
x1 := round(x1 + speed1*cos(angle1));
y1 := round(y1 + speed1*sin(angle1));
x2 := round(x2 + speed2*cos(angle2));
y2 := round(y2 + speed2*sin(angle2));
end;


wacko.gif

Автор: Lapp 24.04.2007 14:14

Цитата(18192123 @ 23.04.2007 22:13) *

Но у меня шарики всё равно проходят друг через друга...

Значит, так.
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). Для этого сначала высчитай эти компоненты (как модуль скорости умножить на косинус и синус угла), потом для каждой реши уравнение ЗСИ и пересчитай. По этим новым компонентам рассчитай новый модуль скорости и угол. Эти значения нужно вернуть в вызывающую программу.


вот что написала:

Vx1 := speed1*cos(angle1);
Vy1 := speed1*sin(angle1);
Vx2 := speed2*cos(angle2);
Vy2 := speed2*sin(angle2);




дальше не пойму...объясни, пожалуйста, подробнее.

Автор: Lapp 25.04.2007 2:10

Дальше для каждой компоненты записываешь (на бумажке) ЗСИ и ЗСЭ:

m1*Vx1 + m2*Vx2 = m1*Vx1' + m2*Vx2
m1*Vx1^2 + m2*Vx2^2 = m1*Vx1'^2 + m2*Vx2'^2

(Для Vy аналогично).

Дальше решаешь эти две системы (тоже на бумажке). Находишь Vx1' и Vx2' (а также Vy1' и Vy2'). Заводишь в программу эти решения:

Vx1 := {выражение через Vx1 и Vx2 }
Vx2 := {выражение через Vx1 и Vx2 }
Vy1 := {выражение через Vy1 и Vy2 }
Vy2 := {выражение через Vy1 и Vy2 }

После этого находишь модули и углы:

V1 := Sqrt(Vx1*Vx1+Vy1*Vy1);
Angle1 := ArcTan(Vy1/Vx1);
if Abs(Vx1)<1e-5 then begin
Angle1:=Pi/2;
if Vy1<0 then Angle1:=-Angle1
end
else begin
Angle1:=ArcTan(Vy1/Vx1);
if Vx<0 then Angle1:=-Angle1
end;

- и плюс аналогично для второго шарика.
Сделай и выложи тут, я проверю.
Если все еще непонятно - говори.

Теперь ты видишь, сколько мороки с углами? Если бы не они, то все, что нужно было бы в этой процедуре - это те четыре строчки с решениями ЗСИ и ЗСЭ..

Автор: 18192123 25.04.2007 3:10

Цитата(Lapp @ 24.04.2007 23:10) *

Находишь Vx1' и Vx2' (а также Vy1' и Vy2'). Заводишь в программу эти решения:

Vx1 := {выражение через Vx1 и Vx2 }
Vx2 := {выражение через Vx1 и Vx2 }
Vy1 := {выражение через Vy1 и Vy2 }
Vy2 := {выражение через Vy1 и Vy2 }


ты имел ввиду
Vx1' := {выражение через Vx1 и Vx2 }
Vx2' := {выражение через Vx1 и Vx2 }
Vy1' := {выражение через Vy1 и Vy2 }
Vy2' := {выражение через Vy1 и Vy2 }
?

Abs(Vx1)< 1e-5 - что такое 1е-5?

А морока с углами - не куда не денешься, как сказали, так и приходиться делать....( имею ввиду в универе)

Автор: Lapp 25.04.2007 3:38

Цитата(18192123 @ 25.04.2007 0:10) *

ты имел ввиду
Vx1' :=
?
Нет, я имел в виду то, что написал. Пересчитываем значения через старые и кладем их в те же самые переменные. Логично? Это программирование уже, математика кончилась..
Цитата(18192123 @ 25.04.2007 0:10) *

Abs(Vx1)< 1e-5 - что такое 1е-5?
Это аналог сравнения с нулем. Математически формула теряет смысл при Vx1=0. Но реально в программе это может произойти и раньше, когда модуль этой величины становится слишком маленьким - и возникнет переполнение, сбой в программе. Для твоей программы вполне достаточно приблизительно сравнения с 0.0001 (то есть 1e-5). Я взял это наобум, но суть выдержана.
Цитата(18192123 @ 25.04.2007 0:10) *

А морока с углами - не куда не денешься, как сказали, так и приходиться делать....( имею ввиду в универе)
Ну, слава Богу - хоть какое-то объяснение есть.. smile.gif

Автор: 18192123 25.04.2007 22:38

Цитата(Lapp @ 24.04.2007 23:10) *

Дальше для каждой компоненты записываешь (на бумажке) ЗСИ и ЗСЭ:

m1*Vx1 + m2*Vx2 = m1*Vx1' + m2*Vx2
m1*Vx1^2 + m2*Vx2^2 = m1*Vx1'^2 + m2*Vx2'^2

(Для Vy аналогично).

Дальше решаешь эти две системы (тоже на бумажке). Находишь Vx1' и Vx2' (а также Vy1' и Vy2'). Заводишь в программу эти решения:


ох...что-то я залезла в дебри.....


Эскизы прикрепленных изображений
Прикрепленное изображение

Автор: 18192123 26.04.2007 23:01

перед тем, как шарики сталкиваются, программа вылетает и выдаёт ошибку 207....первое, о чём подумала- стек переполнился из длинных выражений для скоростей, разбила на более простые - не помогло...


procedure after_hit (var speed1, speed2 : integer; var angle1, angle2 : single);
var m1, m2 : real;
Vx1, Vy1, Vx2, Vy2 : real;
t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 : real;
begin
m1 := value®;
m2 := value®;
Vx1 := speed1*cos(angle1);
Vy1 := speed1*sin(angle1);
Vx2 := speed2*cos(angle2);
Vy2 := speed2*sin(angle2);
t1 := m2/(m1*(m2 + m1));
t2 := (Vx1 - Vx2);
t3 := (m1*m1*m2 - m1);
Vx1 := Vx1 + t1*t2*t3;
t4 := (Vy1 - Vy2);
Vy1 := Vy1 + t1*t4*t3;
t5 := Vx1*m1 + m2*Vx2;
t6 := m1*m1*Vx1;
t7 := m1*m1*m2*Vx2;
vx2 := (t5 - t6 + t7)/(m2 + m1);
t8 := Vy1*m1 + m2*Vy2;
t9 := m1*m1*Vy1;
t10 := m1*m1*m2*Vy2;
vy2 := (t8 - t9 + t10)/(m2 + m1);
speed1 := round(sqrt(Vx1*Vx1 + Vy1*Vy1));
Angle1 := Arctan(Vy1/Vx1);
if abs(Vx1) < 1e - 5 then begin
Angle1 := pi/2;
if Vy1 < 0 then Angle1 := - angle1
end
else begin
Angle1 := ArcTan(Vy1/Vx1);
if Vx1 < 0 then Angle1 := - angle1
end;
speed2 := round(sqrt(Vx2*Vx2 + Vy2*Vy2));
Angle2 := Arctan(Vy2/Vx2);
if abs(Vx2) < 1e - 5 then begin
Angle2 := pi/2;
if Vy2 < 0 then Angle2 := - angle2
end
else begin
Angle2 := ArcTan(Vy2/Vx2);
if Vx2 < 0 then Angle2 := - angle2
end;
end;




Автор: Lapp 27.04.2007 9:35

Цитата(18192123 @ 26.04.2007 20:01) *

перед тем, как шарики сталкиваются, программа вылетает и выдаёт ошибку 207....первое, о чём подумала- стек переполнился из длинных выражений для скоростей, разбила на более простые - не помогло...

Почему, собственно, стек?.. blink.gif А, ты что ли о стеке ко-процессора?.. Нет, это маловероятно, а главное - это все равно означает ошибку, а не большие формулы smile.gif.
Короче, либо корень из отрицательного числа, либо перевод в целые (round) очень большого числа..

Я прогнал ее с некими среднепотолочными значениями - все прошло нормально, не повезло мне.
Ищи ошибку в математике. Не найдешь - приходи, будем искать вместе smile.gif.

Кстати, а в какой строке это происходит? Это же ключ к поиску! Обязательно обрати внимание.

Автор: 18192123 28.04.2007 2:41

Ошибок в математике не нашла.... (но у меня получилось 2 набора значений для Vx1' и Vx2' (а также Vy1' и Vy2'), подставляла каждое - результат тот же)

в какой строке это происходит - не разберусь...




Эскизы прикрепленных изображений
Прикрепленное изображение Прикрепленное изображение

Прикрепленные файлы
Прикрепленный файл  CIRCLES8.PAS ( 10.55 килобайт ) Кол-во скачиваний: 344

Автор: Lapp 28.04.2007 2:49

Цитата(18192123 @ 27.04.2007 23:41) *

в какой строке это происходит - не разберусь...

В чем ты работаешь? в ТР/ВР или FPC?

Автор: 18192123 28.04.2007 3:05

Цитата(Lapp @ 27.04.2007 23:49) *

В чем ты работаешь? в ТР/ВР или FPC?

ТР

Автор: Lapp 28.04.2007 3:33

Цитата(18192123 @ 28.04.2007 0:05) *

ТР

ТР обычно показывает строку с ошибкой.. Странно.

Хорошо, сделай, пожалуйста, вот, что.
Перед передачей параметров в эту процедуру, распечатай их. И покажи тут результат. Сделаешь?

Автор: 18192123 28.04.2007 23:27

Цитата(Lapp @ 28.04.2007 0:33) *


Перед передачей параметров в эту процедуру, распечатай их.

speed1 = 3, speed2 = 12, angle1 = -12.344778061, angle2 = -9,2031850815

Автор: 18192123 29.04.2007 2:58

А если не применять з-ны сохранения ( изменение скорости на совести пользователя - с помощью стрелок), то как можно записать углы, на которые должны отклоняться шарики после соударения?

может так:


procedure after_hit (var angle1, angle2 : single);
begin
angle1 := pi-random(628)/40;
angle2 := -random(628)/20;
end;



При такой записи шарики проскакивают через друг друга сравнительно редко (чем раньше), но всё вероятность такая остаётся.... и как эту вероятность убрать smile.gif ?

Автор: Чужак 29.04.2007 3:16

18192123, здравствуй!
Читал НЕ мало твою тему, и прочитав вот это:

Цитата(Lapp @ 18.04.2007 3:19) *

Некто хочет научиться варить суп. Прежде всего он идет на кухню в общаге, хватает с плиты первую попавшуюся кастрюлю, тащит ее к шеф-повару и говорит: "Объясите мне пожалуйста, зачем тут вот эти штуки.." - и показывает на плавающие там обрывки упаковочной бумаги, куски полиэтилена (нет, волосы упоминать не буду, можете не зажмать рты.. smile.gif). Что может сказать шеф-повар? Его спросили не нужно ли это, а именно с какой целью это тут. Прямо показали пальчиком, и заинтересованно и серьезно ждут ответа.. Я думаю, он поступит как в том старом анекдоте из серии про студента кулинарного техникума (у Хазанова было такое амплуа), когда упомянутый студент пришел к врачу с обваренными гениталиями. Он скажет: "вылейте все это на ..."
После этого он прочтет бедному несчастному студенту лекцию на тему о варке супа, и проведет практическое занятие, а также подарит тарелку хорошего супа. А потом скажет, как это свойственно профессорам-шеф-поварам: если что неясно - я к Вашим услугам, милейший.
Но студент, уяснив кое-что (хоть и не много), говорит - а, не хочу я разбираться в его супе. Его суп слишком сложен для меня (и мой семинарист говорит, что мне такой суп никогда не сварить..) Сварю-ка я свой собственный суп.. И варит. Но суп получается горький, пересоленый, мясо в нем не разжевать.. Что делать? Конечно, идти к шеф-повару! И спрашивать: а зачем я сделал так? а почему я сделал этак?..
Понимаешь, если программа небольшая или речь идет о фрагменте, где локализована ошибка - это одно. Но если нужно расхлебывать весь переперченый недосоленный суп...

опечалился сильно, подумав, что супу в твоем приготовлении мы так и не отведаем (а супу надо), потому решил настрогать в твою тему пару "премудрых телег"...
Программу, твою не смотрел, извини, но по кускам кода, в которых ты плаваеш, пытаясь разобраться, диагноз мне стал ясен.
А именно-ТЫ НЕ ПОНИМАЕШЬ ЛОГИКИ ДЕЙСТВИЙ ПРОГРАММЫ, КОТОРАЯ БУДЕТ РЕШАТЬ ТВОЮ ЗАДАЧУ.
Вот смотри: есть шарик, с параметрами (X,Y,R) (пусть R в простейшем случае не меняется) и программа должна постоянно отслеживать их состояние, и причем на основании определенной логики (Если А, то В). Сначала надо было понять эту логику, потом прописать алгоритм, затем уже начинать писать программу, а не наоборот. Ты же сразу пытаешься разобраться в коде (сначала чужом, затем в своем).
(Если все понятно, можешь дальше не читать...)
Да, на первый взгляд простая задача-и чуть ли не на уровень Искуственного Интеллекта тянет...Но не баись-вдвоем не пропадем!-(она чуть проще).
Щас "аз, многогрешный" будет перечить Lapp'у-уже коленки трясуться...
Все советы из раздела "Физика" оставь побоку, поскольку на Паскале можно моделировать не только физическую среду, а какую угодно среду, хватило бы знания программирования, математики и логики, и (главное!) фантазии, творческого воображения и воли...
Я знаю, о чем говорю, потому что изучал Паскаль в рамках предмета "Математич.моделирование электромеханических систем", и там надо было не только написать работающий код, и даже не просто решить систему уравнений, а чтобы эта система уравнений правильно моделировала электродвигатель, и чтобы он работал, т.е. вращался...Так вот: проверка на соответсвие реальной физике в Паскаль не встроена, там можно прописать уравнения и логику, которая моделирует то, чего в природе нет...В твоем случае это означает, что шарики можно заставить пульсировать, отражаться и вообще плясать под балалайку...
Не зацикливайся не на физике процесса (какая захочешь, такая и будет), не на коде-взгляни на проблему шире...(Стереотипное мышление-между нами!-не лучший советчик...)
Это называется "открытый простор"-включи воображение, сначала представь себе идеальный конечный результат (т.е.в твоем случае-какой ты хочешь видеть свою программу), а затем препятствия, которые мешают тебе в его достижении-и не наоборот, иначе твоя мысля отразиться от первого же препятсвия, как шарик от борта, и конечная цель даже в представлении будет неясной...
Приемы раскрытия творческого мышления человека (типа "открытого простора" ), не только известны, но систематизированы. Есть даже ТРИЗ-Теория Решения Изобретательских Задач (если проснулась творческая жилка и решимость самой решить до конца-прочитай об этом всем www.trizland.ru,www.trizminsk.org и др.) и вперед...
(Если все понятно, можешь дальше не читать...)
Теперь о решении твоей задачи-если в Паскале полно возможностей и опций (процедуры, фунции, массивы и др.) для Cod-Master'а типа volvo или Lapp-не пытайся сразу все использовать, используй лишь те, что нужны для решения твоей задачи...Еще раз говорю-задача не на физику, а на корректную логику-вот и рассуждай логически.
Итак, есть шарик, с параметрами (X,Y,R), и для начала один. Есть направления его движения на восемь сторон Верх(V), Верх-Право(VP), Право(P), Низ-Право (NP), Низ (N), Низ-Лево(NL), Лево (L), Верх-Лево(VL).
(Пока берем четырехсторонюю...VP,NP,VL,NL). И изменения направления на границе. Это всё! И все это реализовано в моей простоватой программе:
 program Sharik;
uses graph,crt;
var Gd, Gm, X, Y, R: Integer; Napr: string;
begin
Gd := Detect; InitGraph(Gd, Gm, ' ');
X:=320; Y:=240; R:=10; Napr:='NP';
repeat
setcolor(15);
Line(20, 40,20, 440); Line(20,40,620,40);
Line(620,40,620,440); Line(620,440,20,440);
Circle(X,Y,R);
delay(500);
setcolor(0);
Circle(X,Y,R);
if Napr='VP' then begin
X:=X+1; Y:=Y-1;
end;
if Napr='NP' then begin
X:=X+1; Y:=Y+1;
end;
if Napr='NL' then begin
X:=X-1; Y:=Y+1;
end;
if Napr='VL' then begin
X:=X-1; Y:=Y-1;
end;
if Y=40 then begin
if Napr='VP' then Napr:='NP';
if Napr='VL' then Napr:='NL';
end;
if X=620 then begin
if Napr='VP' then Napr:='VL';
if Napr='NP' then Napr:='NL';
end;
if Y=440 then begin
if Napr='NP' then Napr:='VP';
if Napr='NL' then Napr:='VL';
end;
if X=20 then begin
if Napr='VL' then Napr:='VP';
if Napr='NL' then Napr:='NP';
end;
until keypressed;
CloseGraph
end.

Так вот-это базовая конструкция-хочешь поменять параметры шарика, поменяй X,Y,R, хочешь изменить скорость-вместо X+1 поставь X+N (и для Y тоже, и пропиши N в Var'е), или просто уменьши/увеличь задержку в delay(), хочешь добавь еше шарик-тогда у каждого шарика свои параметры ш1(X1,Y1,R1), ш2(X2,Y2,R2)(И сделай логику для соударения шариков, как я сделал для границ-там все просто), потом сделай ввод переменных скорости и др. с клавиатуры и т.д..Главное-вноси изменения поэтапно, и по изменению за раз-внесла одно-проверила, внесла следующее и т.д. Короче, твори!
"Гуру", Марина, это хорошо, а "своим умом" гораздо лучше. Гуру-он витает в высотах Объектно-Ориентированного Программинга, куда небожителям снизойти до Нас, простых людей...
Будь здорова, Мариночка!
Жму лапку котику на твоем аватарчике!
С нетерпением жду твоего супчика!
Искренне, от души, Чужак.
P.S. а кто посмеяся над сим посланием-тот посмеяся над собой.