WPFObjects Objects Clear DestroyAll

Abs(Complec) - исправлен тип возвращаемого значения
в WPFObjects host1.ClipToBounds := False - во избежание глюка при совмещении WPFObjects и GraphWPF
Новый пример ShooterWithInterface.pas
Новый пример Sqrt2.pas
This commit is contained in:
Mikhalkovich Stanislav 2020-08-09 18:15:34 +03:00
parent f697fc8be6
commit 46d371fa30
18 changed files with 271 additions and 32 deletions

View file

@ -15,7 +15,7 @@ internal static class RevisionClass
public const string Major = "3";
public const string Minor = "6";
public const string Build = "3";
public const string Revision = "2613";
public const string Revision = "2614";
public const string MainVersion = Major + "." + Minor;
public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision;

View file

@ -1,4 +1,4 @@
%MINOR%=6
%REVISION%=2613
%COREVERSION%=3
%REVISION%=2614
%MINOR%=6
%MAJOR%=3

View file

@ -0,0 +1,4 @@
##
var x := 2.0;
SeqGen(6,x,a (a + x/a) / 2).Last.Println;
x.Sqrt.Print;

View file

@ -1,8 +1,11 @@
// Модуль Controls - замена графического окна элементом "ListView"
uses Controls,GraphWPF;
type My = auto class
Поле1,Поле2: integer;
type My = class
public
auto property Поле1: integer;
auto property Поле2: integer;
constructor (п1,п2: integer) := (Поле1,Поле2) := (п1,п2);
end;
begin

View file

@ -26,7 +26,7 @@ begin
var kl,kr,ku,kd: boolean;
BeginFrameBasedAnimationTime(dt->begin
OnDrawFrame := dt -> begin
Window.Title := 'Количество объектов: '+Objects.Count;
// Перемещение игрока
if kr then
@ -53,7 +53,7 @@ begin
// Конец игры
end;
end);
end;
CreateTimerAndStart(100,procedure -> // Таймер убивания монстров и умирания объектов за пределами экрана
begin

View file

@ -0,0 +1,197 @@
uses WPFObjects, Timers, Controls;
type
BulletWPF = class(CircleWPF) end;
MonsterWPF = class(SquareWPF) end;
PlayerWPF = class(EllipseWPF) end;
TGameState = (Paused, Started, EndOfGame);
var
// Состояние игры
GameState: TGameState := Paused;
// Глобальные интерфейсные объекты
sb: StatusBarWPF;
bstart, bstop, bnewgame: ButtonWPF;
// Глобальные игровые объекты
Player: PlayerWPF;
// Клавиатура
kl, kr, ku, kd: boolean;
procedure InitGame;
begin
Player := new PlayerWPF(GraphWindow.Center, 30, 50, RandomColor);
Player.Velocity := 100;
Player.Number := 0;
loop 10 do
begin
var m := new MonsterWPF(750, Random(10, 550), 30, RandomColor);
m.Velocity := 50;
end;
end;
procedure NewGame;
begin
sb.Text := '';
Objects.Clear;
InitGame;
end;
// Конец игры - игрок погиб
procedure GameOver;
begin
sb.Text := 'Игрок погиб';
GameState := EndOfGame;
bstart.Enabled := False;
bstop.Enabled := False;
bnewgame.Enabled := True;
Player.Color := Colors.Black;
end;
// Конец игры - победа!
procedure GameOverWin;
begin
sb.Text := 'Победа!';
GameState := EndOfGame;
bstart.Enabled := False;
bstop.Enabled := False;
bnewgame.Enabled := True;
Player.Color := Colors.Yellow;
end;
procedure InitInterface;
begin
Window.SetSize(1000, 600);
LeftPanel(200, Colors.Orange);
bstart := Button('Start');
bstop := Button('Stop');
bnewgame := Button('Новая игра');
bstop.Enabled := False;
bstart.Enabled := False;
bstart.Click := procedure begin
GameState := Started;
bstart.Enabled := False;
bstop.Enabled := True;
end;
bstop.Click := procedure begin
GameState := Paused;
bstart.Enabled := True;
bstop.Enabled := False;
end;
bNewGame.Click := procedure begin
GameState := Started;
bnewgame.Enabled := False;
bstart.Enabled := False;
bstop.Enabled := True;
NewGame;
end;
sb := StatusBar;
end;
// Обработчик таймера убивания монстров и умирания объектов за пределами экрана
procedure KillMonstersHandler;
begin
if GameState <> Started then
exit;
// Удалить пули, вылетевшие за экран
Objects.DestroyAll(o o.OutOfGraphWindow and not (o is PlayerWPF));
// Удалить монстра, убитого пулей, вместе с пулей
foreach var o in Objects do
begin
if o is BulletWPF then
foreach var x in o.IntersectionList do
if x is MonsterWPF then
begin
x.Destroy;
o.Destroy;
Player.Number += 1;
break;
end;
end;
end;
// Обработчик перерисовки экрана
procedure DrawFrame(dt: real);
begin
if GameState <> Started then exit;
Window.Title := 'Количество объектов: ' + Objects.Count;
// Перемещение игрока
if kr then
Player.Dx := 1
else if kl then
Player.Dx := -1
else Player.Dx := 0;
if ku then
Player.Dy := -1
else if kd then
Player.Dy := 1
else Player.Dy := 0;
// Перемещение остальных объектов
foreach var o in Objects do // все перемещаются в своём направлении со своей скоростью
begin
if o is MonsterWPF then
o.Direction := (Player.Center.X - o.Center.X, Player.Center.Y - o.Center.Y);
o.MoveTime(dt);
end;
// Проверка гибели игрока
if Player.IntersectionList.Any(o o is MonsterWPF) then
GameOver;
// Проверка выигрыша игрока
if Player.Number >= 10 then
GameOverWin;
end;
/// Обработчик таймера рождения монстров
procedure CreateMonstersHandler;
begin
if GameState <> Started then exit;
var x := if Random(2) = 0 then 750 else 50;
var m := new MonsterWPF(x, Random(10, 550), 30, RandomColor);
m.Velocity := 50;
end;
begin
InitInterface;
CreateTimerAndStart(100, KillMonstersHandler);
CreateTimerAndStart(1000, CreateMonstersHandler);
// Обработчик перерисовки кадров
OnDrawFrame := DrawFrame;
// Обработчики мыши и клавиатуры
OnMouseMove := (x, y, mb) begin
if GameState <> Started then exit;
Player.RotateToPoint(x, y);
end;
OnMouseDown := (x, y, mb) begin
if GameState <> Started then exit;
var cc := new BulletWPF(Player.CenterTop, 5, Colors.Red);
cc.Direction := (x - Player.Center.X, y - Player.Center.Y);
cc.Velocity := 300;
end;
OnKeyDown := k begin
case k of
Key.w, Key.Up: begin ku := true; kd := false; end;
Key.s, Key.Down: begin kd := true; ku := false; end;
Key.a, Key.Left: begin kl := true; kr := false; end;
Key.d, Key.Right: begin kr := true; kl := false end;
end;
end;
OnKeyUp := k begin
case k of
Key.w, Key.Up: ku := false;
Key.s, Key.Down: kd := false;
Key.a, Key.Left: kl := false;
Key.d, Key.Right: kr := false;
end;
end;
end.

View file

@ -1 +1 @@
3.6.3.2613
3.6.3.2614

View file

@ -1 +1 @@
!define VERSION '3.6.3.2613'
!define VERSION '3.6.3.2614'

View file

@ -1924,6 +1924,9 @@ public
host1 := new Canvas;
host := new MyVisualHost();
// Попытка отсекать рисование частей объектов за пределами host. Актуально при наличии панелей.
// К сожалению, почему-то при использовании WPFObjects объекты GraphWPF становятся не видны
// Выход - в WPFObjects host1.ClipToBounds := False
host1.ClipToBounds := True;
host1.SizeChanged += (s,e) ->
begin
@ -1944,6 +1947,8 @@ public
RTbmap := new RenderTargetBitmap(Round(SystemParameters.PrimaryScreenWidth * scalex), Round(SystemParameters.PrimaryScreenHeight * scaley), dpiX, dpiY, PixelFormats.Pbgra32);
im.Source := RTbmap;
// Рисуем на host
// Когда накопится много объектов, переносим их на im
host1.Children.Add(im);
host1.Children.Add(host);

View file

@ -123,7 +123,7 @@ type
property IsFixedSize: boolean read GetFixedSize write SetFixedSize;
/// Очищает графическое окно белым цветом
procedure Clear; virtual;
/// Очищает графическое окно цветом c
/// Очищает графическое окно указанным цветом
procedure Clear(c: GColor); virtual;
/// Устанавливает размеры клиентской части главного окна
procedure SetSize(w, h: real);

View file

@ -38,6 +38,7 @@ type
property TimerProc: ()->() read _procedure write _procedure;
end;
/// Создать и запустить таймер, вызывающий процедуру TimerProc каждые ms миллисекунд
function CreateTimerAndStart(ms: integer; TimerProc: procedure): Timer;
implementation

View file

@ -140,6 +140,12 @@ type
begin
Result := l.GetEnumerator;
end;
/// Очистить список игровых объектов
procedure Clear;
begin
for var i:=Count-1 downto 0 do
Destroy(Items[i]);
end;
end;
@ -1597,12 +1603,14 @@ begin
GraphWindow := GraphWPF.GraphWindow;
host := new Canvas();
host.ClipToBounds := True;
{host.SizeChanged += (s,e) ->
begin
var sz := e.NewSize;
host.DataContext := sz;
end;}
var g := MainWindow.Content as DockPanel;
(g.children[0] as Canvas).ClipToBounds := False; // SSM 04/08/20 - возвращаем в False иначе графику GraphWPF становится не видно
g.children.Add(host); // Слой графики WPF - последний
end;
app.Dispatcher.Invoke(AdditionalInit);

View file

@ -2206,15 +2206,15 @@ type
procedure SetN(n: integer);
function GetN: integer;
protected
function CreateObject: Object3D; override := new PrismT(X, Y, Z, N, Radius, Height, Material.Clone);
function CreateObject: Object3D; override := new PrismT(X, Y, Z, Sides, Radius, Height, Material.Clone);
public
constructor(x, y, z: real; N: integer; r, h: real; m: Gmaterial);
/// Радиус правильной призмы
property Radius: real read GetR write SetR;
/// Высота правильной призмы
property Height: real read GetH write SetH;
/// Количество углов правильной призмы
property N: integer read GetN write SetN;
/// Количество боковых граней правильной призмы
property Sides: integer read GetN write SetN;
/// Возвращает клон правильной призмы
function Clone := (inherited Clone) as PrismT;
end;
@ -2226,15 +2226,15 @@ type
PyramidT = class(PrismT)
private
protected
function CreateObject: Object3D; override := new PyramidT(X, Y, Z, N, Radius, Height, Material.Clone);
function CreateObject: Object3D; override := new PyramidT(X, Y, Z, Sides, Radius, Height, Material.Clone);
public
constructor(x, y, z: real; N: integer; r, h: real; m: GMaterial);
/// Радиус правильной пирамиды
property Radius: real read GetR write SetR;
/// Высота правильной пирамиды
property Height: real read GetH write SetH;
/// Количество углов правильной пирамиды
property N: integer read GetN write SetN;
/// Количество боковых граней правильной пирамиды
property Sides: integer read GetN write SetN;
/// Возвращает клон правильной пирамиды
function Clone := (inherited Clone) as PyramidT;
end;
@ -2288,8 +2288,8 @@ type
begin
var pc := new Point3DCollection;
var a := PartitionPoints(0, 2 * Pi, N).Select(x -> P3D(fr * cos(x), fr * sin(x), 0)).ToArray;
var b := PartitionPoints(0, 2 * Pi, N).Select(x -> P3D(fr * cos(x), fr * sin(x), fh)).ToArray;
var a := PartitionPoints(0, 2 * Pi, Sides).Select(x -> P3D(fr * cos(x), fr * sin(x), 0)).ToArray;
var b := PartitionPoints(0, 2 * Pi, Sides).Select(x -> P3D(fr * cos(x), fr * sin(x), fh)).ToArray;
for var i := 0 to a.High - 1 do
begin
pc.Add(a[i]);
@ -2320,12 +2320,12 @@ type
end;
protected
function CreateObject: Object3D; override := new PrismTWireframe(X, Y, Z, N, Radius, Height, (model as LinesVisual3D).Thickness, (model as LinesVisual3D).Color);
function CreateObject: Object3D; override := new PrismTWireframe(X, Y, Z, Sides, Radius, Height, (model as LinesVisual3D).Thickness, (model as LinesVisual3D).Color);
public
function Points: Point3DCollection; virtual;
begin
var a := PartitionPoints(0, 2 * Pi, N).Select(x -> P3D(fr * cos(x), fr * sin(x), 0)).SkipLast;
var b := PartitionPoints(0, 2 * Pi, N).Select(x -> P3D(fr * cos(x), fr * sin(x), fh)).SkipLast;
var a := PartitionPoints(0, 2 * Pi, Sides).Select(x -> P3D(fr * cos(x), fr * sin(x), 0)).SkipLast;
var b := PartitionPoints(0, 2 * Pi, Sides).Select(x -> P3D(fr * cos(x), fr * sin(x), fh)).SkipLast;
var pc := new Point3DCollection(a + b);
Result := pc;
@ -2338,8 +2338,8 @@ type
property Radius: real read fr write SetR;
/// Высота проволочной правильной призмы
property Height: real read fh write SetH;
/// Количество углов проволочной правильной призмы
property N: integer read fn write SetN;
/// Количество боковых граней проволочной правильной призмы
property Sides: integer read fn write SetN;
/// Цвет проволоки правильной призмы
property Color: GColor read GetC write SetC; override;
/// Толщина проволоки правильной призмы
@ -2352,13 +2352,13 @@ type
/// Класс проволочной правильной пирамиды
PyramidTWireframe = class(PrismTWireframe)
protected
function CreateObject: Object3D; override := new PyramidTWireframe(X, Y, Z, N, Radius, Height, (model as LinesVisual3D).Thickness, (model as LinesVisual3D).Color);
function CreateObject: Object3D; override := new PyramidTWireframe(X, Y, Z, Sides, Radius, Height, (model as LinesVisual3D).Thickness, (model as LinesVisual3D).Color);
private
function CreatePoints: Point3DCollection; override;
begin
var pc := new Point3DCollection;
var a := PartitionPoints(0, 2 * Pi, N).Select(x -> P3D(fr * cos(x), fr * sin(x), 0)).ToArray;
var a := PartitionPoints(0, 2 * Pi, Sides).Select(x -> P3D(fr * cos(x), fr * sin(x), 0)).ToArray;
var b := P3D(0, 0, fh);
for var i := 0 to a.High - 1 do
begin
@ -2377,8 +2377,8 @@ type
property Radius: real read fr write SetR;
/// Высота проволочной правильной пирамиды
property Height: real read fh write SetH;
/// Количество углов проволочной правильной пирамиды
property N: integer read fn write SetN;
/// Количество боковых граней проволочной правильной пирамиды
property Sides: integer read fn write SetN;
/// Цвет проволоки правильной пирамиды
property Color: GColor read GetC write SetC; override;
/// Толщина проволоки правильной пирамиды
@ -3373,15 +3373,15 @@ function FileModel3D(p: Point3D; fname: string; m: Material): FileModelT := File
function Prism(x, y, z: real; Sides: integer; Height, Radius: real; m: Material): PrismT := Inv(()->PrismT.Create(x, y, z, Sides, Radius, Height, m));
function Prism(p: Point3D; Sides: integer; Height, Radius: real; m: Material): PrismT := Prism(p.X, p.Y, p.Z, Sides, Radius, Height, m);
function Prism(p: Point3D; Sides: integer; Height, Radius: real; m: Material): PrismT := Prism(p.X, p.Y, p.Z, Sides, Height, Radius, m);
function PrismWireFrame(x, y, z: real; Sides: integer; Height, Radius: real; Thickness: real; c: Color): PrismTWireFrame := Inv(()->PrismTWireFrame.Create(x, y, z, Sides, Radius, Height, thickness, c));
function PrismWireFrame(p: Point3D; Sides: integer; Height, Radius: real; Thickness: real; c: Color): PrismTWireFrame := PrismWireFrame(p.x, p.y, p.z, Sides, Radius, Height, thickness, c);
function PrismWireFrame(p: Point3D; Sides: integer; Height, Radius: real; Thickness: real; c: Color): PrismTWireFrame := PrismWireFrame(p.x, p.y, p.z, Sides, Height, Radius, thickness, c);
function Pyramid(x, y, z: real; Sides: integer; Height, Radius: real; m: Material): PyramidT := Inv(()->PyramidT.Create(x, y, z, Sides, Radius, Height, m));
function Pyramid(p: Point3D; Sides: integer; Height, Radius: real; m: Material): PyramidT := Pyramid(p.X, p.Y, p.Z, Sides, Radius, Height, m);
function Pyramid(p: Point3D; Sides: integer; Height, Radius: real; m: Material): PyramidT := Pyramid(p.X, p.Y, p.Z, Sides, Height, Radius, m);
function PyramidWireFrame(x, y, z: real; Sides: integer; Height, Radius: real; Thickness: real; c: Color): PyramidTWireFrame := Inv(()->PyramidTWireFrame.Create(x, y, z, Sides, Radius, Height, thickness, c));

View file

@ -1924,6 +1924,9 @@ public
host1 := new Canvas;
host := new MyVisualHost();
// Попытка отсекать рисование частей объектов за пределами host. Актуально при наличии панелей.
// К сожалению, почему-то при использовании WPFObjects объекты GraphWPF становятся не видны
// Выход - в WPFObjects host1.ClipToBounds := False
host1.ClipToBounds := True;
host1.SizeChanged += (s,e) ->
begin
@ -1944,6 +1947,8 @@ public
RTbmap := new RenderTargetBitmap(Round(SystemParameters.PrimaryScreenWidth * scalex), Round(SystemParameters.PrimaryScreenHeight * scaley), dpiX, dpiY, PixelFormats.Pbgra32);
im.Source := RTbmap;
// Рисуем на host
// Когда накопится много объектов, переносим их на im
host1.Children.Add(im);
host1.Children.Add(host);

View file

@ -123,7 +123,7 @@ type
property IsFixedSize: boolean read GetFixedSize write SetFixedSize;
/// Очищает графическое окно белым цветом
procedure Clear; virtual;
/// Очищает графическое окно цветом c
/// Очищает графическое окно указанным цветом
procedure Clear(c: GColor); virtual;
/// Устанавливает размеры клиентской части главного окна
procedure SetSize(w, h: real);

View file

@ -1760,7 +1760,7 @@ function CplxFromPolar(magnitude, phase: real): Complex;
/// Возвращает квадратный корень из комплексного числа
function Sqrt(c: Complex): Complex;
/// Возвращает модуль комплексного числа
function Abs(c: Complex): Complex;
function Abs(c: Complex): real;
/// Возвращает комплексно сопряженное число
function Conjugate(c: Complex): Complex;
/// Возвращает косинус комплексного числа

View file

@ -38,6 +38,7 @@ type
property TimerProc: ()->() read _procedure write _procedure;
end;
/// Создать и запустить таймер, вызывающий процедуру TimerProc каждые ms миллисекунд
function CreateTimerAndStart(ms: integer; TimerProc: procedure): Timer;
implementation

View file

@ -140,6 +140,19 @@ type
begin
Result := l.GetEnumerator;
end;
/// Очистить список игровых объектов
procedure Clear;
begin
for var i:=Count-1 downto 0 do
Destroy(Items[i]);
end;
/// Удалить все игровые объекты, удовлетворяющие условию
procedure DestroyAll(condition: ObjectWPF -> boolean);
begin
for var i := Count - 1 downto 0 do
if condition(Items[i]) then
Destroy(Items[i]);
end;
end;
@ -1597,12 +1610,14 @@ begin
GraphWindow := GraphWPF.GraphWindow;
host := new Canvas();
host.ClipToBounds := True;
{host.SizeChanged += (s,e) ->
begin
var sz := e.NewSize;
host.DataContext := sz;
end;}
var g := MainWindow.Content as DockPanel;
(g.children[0] as Canvas).ClipToBounds := False; // SSM 04/08/20 - возвращаем в False иначе графику GraphWPF становится не видно
g.children.Add(host); // Слой графики WPF - последний
end;
app.Dispatcher.Invoke(AdditionalInit);