%% Ball on a Slide - Simple Physics Game
%
% This example creates a simple slide with 2 blocks - rotating gates at its
% lower end. A heavy ball is placed above the slide.
%
% When you double click on the gates, they drop on the floor at their
% current orientation (by setting their 'Gravity' property to 'true').
% When you double clik on the ball, it falls down and hits the gates,
% respecting the physics. Tracing trail with decay time 5 s is defined for
% the ball.
%
% You can also double click on the green slide, making it to fall down
% from the original position. The slide guards are created as children of
% the slide, so they move with it.
%
% You can restart the game by clicking on the R button on the left edge of
% the Viewer window.

%   Copyright 1998-2021 HUMUSOFT s.r.o.

%% Initialize the 3D Foundation object
FW = F3D.World(mfilename);
initialize(FW, [0 -6 3], [0 0 1.5]);

% Units and coordinate system
FW.CoordinateSystem = 'unreal';
FW.AngleUnits = 'deg';

% Set the viewport properties
VP = FW.Viewports.Main;
VP.Title = mfilename;
Path = fileparts(which(mfilename));
setLogo(VP, fullfile(Path, 'data', 'MatlabLogo.png'));

F3D.Geometry.templateFloor(FW.Root, [20 20 0.1]);

% Create Base Plate
Plate = addChild(FW.Root, 'Plate');
createShape(Plate, 'box', [2 2 0.1]);
Plate.Color = [1 1 1];
Plate.Location = [0 -2 2];

% Slant
Slant = addChild(Plate, 'Slant');
createShape(Slant, 'box', [1 1.50 0.2]);
Slant.Color = [1 1 1];
Slant.Location = [0 -1 0.5];
Slant.Rotation(1) = 30;

% Slide
Slide = addChild(FW.Root, 'Slide');
createShape(Slide, 'box', [0.8 3 0.1]);
Slide.Color = [0.8 1 0];
Slide.Location = [0 0 1.30];
Slide.Rotation(1) = 15;
Slide.OnActivate = @(act, ~) setfield(act, 'Physics', true);
%Slide.OnActivate = 'Slide.Physics = true';

% Guards are created as children of the Slide, so they move with it
Guard1 = addChild(Slide);
createShape(Guard1, 'cylinder', [0.1 3 0.1], 16, 2);
Guard1.Color = [0.6 0.8 0];
Guard1.Location = [-0.4 0 0.25];

Guard2 = addChild(Slide);
createShape(Guard2, 'cylinder', [0.1 3 0.1], 16, 2);
Guard2.Color = [0.6 0.8 0];
Guard2.Location = [0.4 0 0.25];

% Gate1
Gate1 = addChild(FW.Root, 'Gate1');
createShape(Gate1, 'box', [1 0.2 2]);
Gate1.Color = [0.6 0.2 0.8];
Gate1.Transparency = 0.5;
Gate1.Location = [-0.6 2.4 1.2];
Gate1.Gravity = false;
Gate1.Physics = true;
Gate1.Torque = [0 0 -10];
Gate1.OnActivate = @EnableGravity;
playSound(Gate1, 1, -1);

% Gate2
Gate2 = addChild(FW.Root, 'Gate2');
createShape(Gate2, 'box', [1 0.2 2]);
Gate2.Color = [0.8 0.2 0.6];
Gate2.Transparency = 0.5;
Gate2.Location = [0.6 2.4 1.2];
Gate2.Gravity = false;
Gate2.Physics = true;
Gate2.Torque = [0 0 10];
Gate2.OnActivate = @EnableGravity;
playSound(Gate2, 1, -1);

% Ball
Ball = addChild(FW.Root, 'Ball');
createShape(Ball, 'sphere', [0.5 0.5 0.5], 32);
Ball.Color = [1 0 0];
Ball.TextureMapping.Bumps = 10;
Ball.Location = [0 -3 3.5];
Ball.Gravity = false;
Ball.Physics = true;
Ball.Mass = 100;
Ball.Trail = F3D.Type.Trail('Color', [0 0 100], 'Duration', 5);
Ball.OnActivate = @EnableGravity;

VP.Button5 = F3D.Type.Button([0 0 0], '(R)', 'Restart Game', 'sl3dexf_physicsslide;');

message(VP, ['Ball on a Slide:' ,...
    newline 'Double click on the gate blocks to fix them on the floor.' ,...
    newline 'Double click on the ball to start the game.' ,...
    newline 'Double click on the green slide to make it fall down.' ,...
    newline 'Click on the R button to restart the game.']);


function EnableGravity(Actor, ~)
    Actor.Gravity = true;
    stopSound(Actor);
end
