Вот такое задание: Даны два шарика диаметром М. Промоделировать движение шариков по всей плоскости экрана. Шарики могут двигаться по прямым линиям. Изменение угла движения после столкновения с границей экрана или друг с другом может быть случайной величиной. Шарик не может вылететь за пределы квадрата. Пользователь может варьировать скорости движения шариков с помощью стрелок управления курсором.
Хотелось бы разобраться в коде программы... ( дело в том, что код не мой) Объясните пожалуйста назначение каждой из процедур в тексте приведённой ниже программы!
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
Марина, извини, но ты выбрала неправильную программу для примера.. Она слишком кривая и слабая, чтоб с нее копировать. Даже разбираться в этом коде никакого желания нет..
Движение объектов по экрану разбиралось тут не раз. Попробуй написать сама. Или хотя бы начни с алгоритма, блок-схемы.. Я, например, готов тебе помочь в этом благородном деле, но объяснять для чего в этой программе совершенно ненужные вещи - уволь..
Если согласна, поищи по форуму про движение объектов. Я могу тебе выложить чуть позже примеры основных частей кода, если будут трудности.
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
Марина, извини, но ты выбрала неправильную программу для примера.. Она слишком кривая и слабая, чтоб с нее копировать. Даже разбираться в этом коде никакого желания нет..
Движение объектов по экрану разбиралось тут не раз. Попробуй написать сама. Или хотя бы начни с алгоритма, блок-схемы.. Я, например, готов тебе помочь в этом благородном деле, но объяснять для чего в этой программе совершенно ненужные вещи - уволь..
Если согласна, поищи по форуму про движение объектов. Я могу тебе выложить чуть позже примеры основных частей кода, если будут трудности.
Да я согласна. Час буду искать про движение объекта....
1. Меню (где можно выбрать радиус 2-х шариков) Я могу оставить по этому вопросу то, что было в примере(неудачном) - процедуры MENU и _case_?
2. Рисуем шарики(здесь ясно) --> Убираем с экрана( и здесь) --> ВЫбираем новое их положение (каким способом это лучше делать???) --> Показываем на новом месте
3. Проверка на выход за пределы экрана (что делать, если получается вылет за пределы экрана: аварийный выход из программы или ....??????)
---Соударение шаров друг с другом и с пределами экрана (мне не ясно, что нужно указывать по этому пункту...Может связать с законом сохранения импульса???)
4. Управление скоростями с помощью стрелок на клавиатуре - не представляю, как это осуществить!
Случайно на компе наткнулся на задачку с шариком погляди может какие - то идем возьмёшь, не помню откуда эта прога в упор :
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.
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'а еще не смотрел, посмотрю.. В любом случае, если уж решилась делать сама - то и делай, это лучше.
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
Для того, чтобы начать реализовывать меню (интерфейс), надо сначала реализовать логику работы программы, о чем и говорил Lapp... Сделай сначала это, чтобы потом не получилось как в первой приведенной тобой программе - где "рюшечки" настолько заполонили код, что разобраться в нем просто нереально...
Цитата
Можно осуществить такой вариант: стрелки "вправо-влево" для одного шара, "вверх-вниз" для другого?
Можно и так, почему же нельзя? Какие клавиши навесишь, такие и будут...
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 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 килобайт )
Кол-во скачиваний: 658
Марина, я покажу пример программы, которая гоняет объекты по полю. Программа работает в текстовой моде и без меню, но в ней есть управление скоростями. Надеюсь, она будет тебе полезна в некотором отношении.. Дело в том, что в ней четко проведено деление: все, что относится к выводу на экран, выделено в отдельный модуль. Сама же основная программа осуществляет движение и управление. По идее, если вместо существующего модуля, работающего с текстом, написать модуль, работающий с графикой, то основную программу менять не нужно (кроме строчки 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.
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
Потому, что надо сначала менять положение шара, и только потом проверять его на столкновение с бордюром, правда?
Вот так:
... move (x1, y1, dx1, dy1); { <--- Сначала это } move (x2, y2, dx2, dy2); border (x1, y1, r1, dx1, dy1); { <--- и только потом - проверка } border (x2, y2, r2, dx2, dy2); ...
Цитата
как ещё учесть (при пристолкновении) изменение угла движения?
Ты имеешь в виду при столкновении шаров между собой? Тебе понадобится функция, определяющая, было ли такое столкновение... На каждом шаге кроме того, что ты проверяешь столкновения шаров с бортом, надо будет вызывать еще и эту функцию, и если столкновение было (расстояние между центрами шаров меньше суммы их радиусов), то менять направление движения...
А вот как менять - это уже зависит от того, насколько реалистично ты это хочешь сделать... Можно просто поменять знак DX или DY на противоположный, можно рассчитать новые направления движения шаров по формулам...
А вот как менять - это уже зависит от того, насколько реалистично ты это хочешь сделать... Можно просто поменять знак DX или DY на противоположный, можно рассчитать новые направления движения шаров по формулам...
Я хочу делать наиболее реалистично... Про ф-цию - понятно, буду делать. Спасибо.
Я хочу делать наиболее реалистично... Про ф-цию - понятно, буду делать. Спасибо.
Реалистично - я уже говорил: нужно вводить массы. Тогда можно будет использовать ЗСИ. Но это можно сделать только имея нормальную интерперетацию скорости! В моем примере скорость практически реальная, при этом время течет квантами (в цикле). Посмотри, как это устроено, и сможешь менять скорость по ЗСИ.
Для максимальной реалистичности можно использовать натуральное время (в секундах) и натуральные рамеры экранного окна (в см). Это не так сложно, но реально того, как сделано в моей проге, достаточно для описания физики соударений. Только там у меня рассчитано на несколько (до 9) объектов, при этом проверка на соударение производится, ессно, циклом по всем для каждого. При девяти это еще не так много, но если еще увеличивать количество, то производительность может начать падать..
--------------------
я - ветер, я северный холодный ветер я час расставанья, я год возвращенья домой
за что отвечают переменные x1,x2,y1,y2 и Aspect,MinX (относительно чего определяется максимальные и минимальные координаты?),MinY,MaxX,MaxY,x0,y0 и ТА ?