Консультация № 199858
13.12.2020, 08:03
0.00 руб.
0 8 1
Здравствуйте, уважаемые эксперты! Прошу вас ответить на следующий вопрос: В программе(код прикреплён) реализуется движение молекул. Вопрос: как случайным образом разделить молекулы на красные и синие(в класс добавить значение цвета и с помощью RGB бахнуть...), при этом одноцветные должны отталкиваться, а красные поглощают синих?

Приложение:
unit Unit1;

interface

uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.ComCtrls, Math;

type
TForm1 = class(TForm)
GroupBox1: TGroupBox;
GroupBox2: TGroupBox;
EditL: TEdit;
EditH: TEdit;
EditNum: TEdit;
EditRad: TEdit;
UpDownNum: TUpDown;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
ButtonGo: TButton;
ButtonStop: TButton;
ButtonColor: TButton;
ButtonFon: TButton;
ColorDialog1: TColorDialog;
Timer1: TTimer;
PaintBox1: TPaintBox;
procedure FormCreate(Sender: TObject);
procedure ButtonColorClick(Sender: TObject);
procedure ButtonFonClick(Sender: TObject);
procedure ButtonGoClick(Sender: TObject);
procedure EditLKeyPress(Sender: TObject; var Key: Char);
procedure Timer1Timer(Sender: TObject);
procedure ButtonStopClick(Sender: TObject);
procedure UpDownNumClick(Sender: TObject; Button: TUDBtnType);
private
{ Private declarations }
procedure Painting;
public
{ Public declarations }
end;

TMolekula=class //молекула
Fx, Fy, FVx, FVy, FR: integer; //Fx и Fy-координатная плоскость,FR-радиус,FVx и FVy-значения проекций вектора скорости на оси OX и OY
public
constructor Create(x,y,Vx,Vy:integer);
procedure Wall(i:integer; width,height:integer);
procedure Strike(i:integer);
end;

TMolekulaList=class(TList) //список экземпляров TMolekula
public
procedure Add(Mol:TMolekula);//добавление молекулы в список
procedure Clear; //очистка списка молекул
procedure Delete(n:integer); //удаление молекул из списка
end;

var
result:integer;
p:integer;
Form1: TForm1;
MolColor:TColor; //цвет молекул
FonColor:TColor; //цвет фона
MolList:TMolekulaList; //список всех молекул
pbWidth, pbHeight:integer; //ширина и высота сосуда
Rad:integer; //радиус молекул
const MaxSpeed=10; //максимальная скорость движения молекул

implementation

Constructor TMolekula.Create(x: Integer; y: Integer; Vx: Integer; Vy: Integer);
begin
Fx:=x;
Fy:=y;
FVx:=Vx;
FVy:=Vy;
FR:=Rad;
end;
{$R *.dfm}

procedure TMolekula.Wall(i: Integer; width: Integer; height: Integer);
var Mol:TMolekula;
begin
Mol:=TMolekula(MolList.Items[i]);
if Mol.Fx+Rad>=width then //право
begin
Mol.FVx:=-Mol.FVx;
Mol.Fx:=-width-Rad;
end
else
if Mol.Fy+Rad<=0 then
begin
Mol.FVy:=-Mol.FVy;
Mol.Fy:=Rad;
end
else
if Mol.Fx-Rad<=0 then
begin
Mol.FVx:=-Mol.FVx;
Mol.Fx:=Rad;
end
else
if Mol.Fy-Rad>=height then
begin
Mol.FVy:=-Mol.FVy;
Mol.Fy:=height-Rad;
end;
end;

function DistanceBetween(Mol1,Mol2:TMolekula):real;
begin
Result:=sqrt(sqr(Mol1.Fx-Mol2.Fx)+sqr(Mol1.Fy-Mol2.Fy));
end;

procedure TMolekula.Strike(i:integer);
var j:byte;
Mol1,Mol2:TMolekula;
temp:integer;
begin
Mol1:=TMolekula(MolList.Items[i]);
for j:= 0 to MolList.Count-1 do
begin
if j<>i then
begin
Mol2:=TMolekula(MolList.Items[j]);
if DistanceBetween(Mol1,Mol2)<=2*Rad then
begin //обмен векторами скоростей
temp:=Mol1.FVx;
Mol1.FVx:=Mol2.FVx;
Mol2.FVx:=temp;
temp:=Mol1.FVy;
Mol1.FVy:=Mol2.FVy;
Mol2.FVy:=temp;
break;
end;
end;
end;
end;

procedure TMolekulaList.Add(Mol: TMolekula);
begin
inherited Add(Mol);
end;

procedure TMolekulaList.Clear;
var i:integer;
begin
for i := 0 to Count-1 do TMolekula(Items[i]).Free;
Inherited Clear;
end;

procedure TMolekulaList.Delete(n: Integer);
begin
if (n>=0) and (n<=Count-1) then
begin
TMolekula(Items[n]).Free;
Inherited Delete(n);
end;
end;

function CreateMol:TMolekula;
var x,y,vx,vy:integer;
begin
x:=RandomRange(Rad, pbWidth-Rad);
y:=RandomRange(Rad, pbHeight-Rad);
Vx:=RandomRange(1, MaxSpeed);
Vy:=RandomRange(1, MaxSpeed);
if RandomRange(1,100)>50 then Vx:=-Vx;
if RandomRange(1,100)>50 then Vy:=-Vy;
Result:=TMolekula.Create(x,y,Vx,Vy);
end;

procedure TForm1.ButtonColorClick(Sender: TObject);
begin
if ColorDialog1.Execute then
MolColor:=ColorDialog1.Color;
end;

procedure TForm1.ButtonFonClick(Sender: TObject);
begin
if ColorDialog1.Execute then
FonColor:=ColorDialog1.Color;
end;

procedure TForm1.ButtonGoClick(Sender: TObject);
var i,n,ph,pv,j,s,a:integer;
Mol:TMolekula;
begin
ph:=StrToInt(EditL.Text);
pv:=StrToInt(EditH.Text);
Rad:=StrToInt(editRad.Text);
n:=StrToInt(editNum.Text);
pbWidth:=ph;
pbHeight:=pv;

PaintBox1.Width:=pbWidth;
PaintBox1.Height:=pbHeight;

MolList.Clear;

for i := 1 to n do
begin
Mol:=CreateMol;
MolList.Add(Mol);
end;
Timer1.Enabled:=true;
ButtonStop.Caption:='Стоп';
end;

procedure TForm1.ButtonStopClick(Sender: TObject);
begin
Timer1.Enabled:=not Timer1.Enabled;
if Timer1.Enabled then
begin
ButtonStop.Caption:='Стоп'
end
else
begin
ButtonStop.Caption:='Продолжить'
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
MolColor:=clBlack;
FonColor:=clWhite;
MolList:=TMolekulaList.Create;
Randomize;
end;

procedure TForm1.Painting;
var i:integer;
Mol:TMolekula;
begin
paintBox1.Canvas.Brush.Color:=FonColor;
paintBox1.Canvas.Rectangle(0,0,pbWidth,pbHeight);
paintBox1.Canvas.Brush.Color:=MolColor;

for i := 0 to MolList.Count-1 do
begin
Mol:=TMolekula(MolList.Items[i]);
PaintBox1.Canvas.Ellipse(Mol.Fx-Rad, Mol.Fy-Rad, Mol.Fx+Rad, Mol.Fy+Rad);
end;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var x,y:integer;
i:integer;
Mol:TMolekula;
begin
for i := 0 to MolList.Count-1 do
begin
Mol:=TMolekula(MolList.Items[i]);
Mol.Fx:=Mol.Fx+Mol.FVx;
Mol.Fy:=Mol.Fy+Mol.FVy;
Mol.Wall(i,pbwidth,pbheight);
Mol.Strike(i);
Painting;
end;
end;

procedure TForm1.UpDownNumClick(Sender: TObject; Button: TUDBtnType);
var Mol:TMolekula;
begin
if ButtonStop.Caption='Стоп' then
if Button=btNext then
begin
Mol:=CreateMol;
MolList.Add(Mol);
end
else
if MolList.Count>1 then
MolList.Delete(0);
end;

end.

Обсуждение

давно
Посетитель
404602
7
13.12.2020, 19:17
общий
в класс TMolekula нужно ещё добавить значение цвета
давно
Старший Модератор
31795
6196
14.12.2020, 12:32
общий
14.12.2020, 12:34
Адресаты:
Цитата: QWERUIO
в класс TMolekula нужно ещё добавить значение цвета

Зачем?
Ставите в класс TMolekula две булевые переменные absorber(поглощатель)=красный и show(показать). При создании молекулы Вы всем ставите параметр show:=истина, только красным absorber:=истина, остальным ложь.

show:
Если молекула поглощенная сбрасываете show:=ложь, все она больше нигде не участвует, не двигается и не отображается, также игнорируется при расчете дистанции. По большому счету саму молекулу нужно исключать из списка, но так как Вы все обрабатываете с циклах может нарушится индексация, а так
Код:
if Mol.show then
begin
. . .
end;

И никаких заморочек.

absorber:
Есть такая команда XOR.
[table][row][col]true[/col][col]true[/col][col]false[/col][/row][row][col]true[/col][col]false[/col][col]true[/col][/row][row][col]false[/col][col]true[/col][col]true[/col][/row][row][col]false[/col][col]false[/col][col]false[/col][/row][/table]
Из таблицы видно, что если у молекул разные значения, то простым условием
Код:
if Mol1.adabsorber xor Mol2.absorber then
begin
. . .{поглощение}
end
else
begin
. . .{столкновение}
end;

И тоже никаких заморочек.
И рисование тоже простое:
Код:
procedure TForm1.Painting;
var i:integer;
Mol:TMolekula;
begin
paintBox1.Canvas.Brush.Color:=FonColor;
paintBox1.Canvas.Rectangle(0,0,pbWidth,pbHeight);

for i := 0 to MolList.Count-1 do
begin
Mol:=TMolekula(MolList.Items[i]);
if Mol.absorber then paintBox1.Canvas.Brush.Color:=RedColor
else paintBox1.Canvas.Brush.Color:=BlueColor;
PaintBox1.Canvas.Ellipse(Mol.Fx-Rad, Mol.Fy-Rad, Mol.Fx+Rad, Mol.Fy+Rad);
end;
end;

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

давно
Старший Модератор
31795
6196
16.12.2020, 17:44
общий
Адресаты:
Получилось?
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
404602
7
19.12.2020, 04:40
общий
19.12.2020, 04:47
Нет, не совсем понятно как написать в программе первые два кода. То есть что должно быть вместо этих точек и в какие процедуры эти if прописать?
давно
Посетитель
404602
7
19.12.2020, 04:53
общий
[q=404602][/q]

Объявлять так?
TMolekula=class //молекула
Fx, Fy, FVx, FVy, FR: integer;
absorder,show:boolean;
давно
Старший Модератор
31795
6196
19.12.2020, 17:35
общий
Адресаты:
Цитата: QWERUIO
Объявлять так

Да.

Цитата: QWERUIO
в какие процедуры эти if прописать

Я дал Вам всю нужную информацию:
Цитата: Зенченко Константин Николаевич
Если молекула поглощенная сбрасываете show:=ложь, все она больше нигде не участвует, не двигается и не отображается, также игнорируется при расчете дистанции.
Об авторе:
Мне безразлично, что Вы думаете о обо мне, но я рад за Вас - Вы начали думать.

давно
Посетитель
404602
7
20.12.2020, 01:22
общий
Спасибо, разобралась
давно
Старший Модератор
31795
6196
22.12.2020, 11:58
общий
это ответ
Здравствуйте, QWERUIO!

Вам нужно добавить в TMolekula два свойства Show и Absorber. Show отвечает за отображение на экране молекулы, Absorber - поглощение и цвет.

Изменить процедуры следующим образом:
Код:
procedure TForm1.Painting;
var
i:integer;
Mol:TMolekula;
begin
paintBox1.Canvas.Brush.Color:=FonColor;
paintBox1.Canvas.Rectangle(0,0,pbWidth,pbHeight);
for i := 0 to MolList.Count-1 do
begin
Mol:=TMolekula(MolList.Items[i]);
if Mol.Show then
begin
if Mol.absorber then paintBox1.Canvas.Brush.Color:=RedColor
else paintBox1.Canvas.Brush.Color:=BlueColor;
PaintBox1.Canvas.Ellipse(Mol.Fx-Rad, Mol.Fy-Rad, Mol.Fx+Rad, Mol.Fy+Rad);
end;
end;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
x,y:integer;
i:integer;
Mol:TMolekula;
begin
for i := 0 to MolList.Count-1 do
begin
Mol:=TMolekula(MolList.Items[i]);
if Mol.Show then
begin
Mol.Fx:=Mol.Fx+Mol.FVx;
Mol.Fy:=Mol.Fy+Mol.FVy;
Mol.Wall(i,pbwidth,pbheight);
Mol.Strike(i);
end;
end;
Painting;
end;
procedure TMolekula.Strike(i:integer);
var
j:byte;
Mol1,Mol2:TMolekula;
temp:integer;
begin
Mol1:=TMolekula(MolList.Items[i]);
for j:= 0 to MolList.Count-1 do
begin
if j<>i then
begin
Mol2:=TMolekula(MolList.Items[j]);
if Mol2.Show then
if DistanceBetween(Mol1,Mol2)<=2*Rad then
if Mol1.absorber xor Mol2.absorber then
begin
Mol1.Show:=Mol1.absorber;
Mol2.Show:=Mol2.absorber;
end
else
begin
temp:=Mol1.FVx;
Mol1.FVx:=Mol2.FVx;
Mol2.FVx:=temp;
temp:=Mol1.FVy;
Mol1.FVy:=Mol2.FVy;
Mol2.FVy:=temp;
end;
end;
end;
end;

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

Форма ответа