begin process at 2013 05 25 06:18:59
  Trouver un code source :
 
dans
 
Accueil > 

Code

 > 

Jeux

 > RUBIK'S CUBE AVEC FIREMONKEY 3D

RUBIK'S CUBE AVEC FIREMONKEY 3D


 Information sur la source

Note :
Aucune note
Catégorie :Jeux Classé sous :delphi, Rubik cube, Firemonkey, 3D, XE2 Niveau :Initié Date de création :19/04/2012 Date de mise à jour :23/04/2012 06:35:28 Vu / téléchargé :4 170 / 249

Auteur : Fireman

Ecrire un message privé
Site perso
Commentaire sur cette source (19)
Ajouter un commentaire et/ou une note

 Description

Cliquez pour voir la capture en taille normale
Le but de ce programme a été pour moi de travailler avec la partie 3D de Firemonkey et d'une certaine manière promouvoir mon outil preferé.



A/ But et limites

Le Rubik's Cube est fonctionnel mais ne dispose pas la fonctionnalité resolution automatique.
Ceci a deja été fait et ne presente plus de fort interet.

Ceux qui s'attendent a un respect de la notation officielle des faces du Rubik's cube seront déçus.
Comment reperer la face AVANT apres des rotations des plans X Y ou Z.
J'ai donc utilisé la couleur du cube pivot (central à chaque face) pour decrire un plan.
Ceci est important pour la lecture du source. Mais aussi pour le jeu au clavier et avec les boutons colorés.
Par contre pour le jeu à la souris no souci !  


les cubes coins sont sensibles au clic souris pour les rotations de face. Un tirer/Lacher sur la zone
grise permet une rotation de tout le cube.


Z- plan Rouge  (avant au depart)
Z+ plan Orange (arriere au depart)
X+ plan Bleu   (Droit au depart)
X- plan Vert   (Gauche au depart)
Y- plan Blanc  (Haut au depart)
Y+ plan Jaune  (Bas au depart)

Source

  • unit UMain;
  • interface
  • // ______ __
  • // /\ ___\ /\ \__
  • // _____ \ \ \__/ ___ ___\ \ ,_\ __ ___ __ __ __ __
  • // /\ '__`\ \ \ _\/ __`\/' _ `\ \ \/ /'__`\/' _ `\ /'__`\ /'__`\ /\ \/\ \
  • // \ \ \_\ \ __ \ \ \/\ \_\ \\ \/\ \ \ \_/\ __//\ \/\ \/\ __//\ \_\ \_\ \ \_\ \
  • // \ \ ,__/ / \_\ \ \_\ \____/ \_\ \_\ \__\ \____\ \_\ \_\ \____\ \__/ \_\\ \____/
  • // \ \ \/ \/_/ \/_/\/___/ \/_/\/_/\/__/\/____/\/_/\/_/\/____/\/__/\/_/ \/___/
  • // \ \_\
  • // \/_/ P2F - 2012 - Rubik'sCube
  • // FREEWARE - Aucune diffusion commerciale basée sur ce code source
  • // n'est autorisée sans autorisation préalable de l'auteur.
  • // Rubik's Cube 3D Pascal Fonteneau
  • // Interfaces- Fun Parts - Pascal Fonteneau and Whiler
  • uses
  • System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  • FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Types3D, FMX.Objects3D,
  • FMX.Ani, FMX.Layouts, FMX.Memo, System.Math, System.StrUtils, FMX.Effects, FMX.Platform,
  • FMX.Objects, FMX.ListBox, FMX.Colors;
  • const
  • FUN_LABELS : array[0..11] of string = ('Damier', 'Barre', '2 Cubes',
  • '3 Cubes', 'Carré', 'Damier coloré',
  • 'Plus', 'Bande', 'Diagonale',
  • 'Angle', 'L', 'Tetris');
  • FUN_VALUES : array[0..11] of AnsiString =
  • ('OORRWWYYGGBB', 'RRGGOORRGGor', 'WWGGRRwOOYBrBrBryOOw',
  • 'GGyRRyowoRByWBOGGOWW', 'gBrOYwgB', 'OORRWWYYGGBBgBrOYwgFB',
  • 'RGGBBRROOWWGGBBRROOYYr', 'rGGRRbyRRWRRBBRRYRRwbRRGG', 'GBROGBROGBRO',
  • 'WGGRbGoRRBgYWWrGGw', 'OBBYRbGyoRyWgRRw', 'GBROGBROGBROWWYY');
  • ANIMATION : array[0..10] of String = ('Linear','Quadratic','Cubic','Quartic','Quintic','Sinusoidal',
  • 'Exponential','Circular','Elastic','Back','Bounce');
  • type
  • TStickPosition = (PoFront, PoBack, PoTop, PoBottom, PoRight, PoLeft, PoNone);
  • TDirection = (DiNone, DiLeft, DiRight, DiTop, DiBottom);
  • TFormMain = class(TForm)
  • LabelX: TLabel;
  • LabelY: TLabel;
  • LabelZ: TLabel;
  • StyleBook1: TStyleBook;
  • Viewport3D2: TViewport3D;
  • CubeCentral: TCube;
  • RedPivot: TCube;
  • GreenPivot: TCube;
  • WhitePivot: TCube;
  • OrangePivot: TCube;
  • BluePivot: TCube;
  • YellowPivot: TCube;
  • BtnRedLeft: TButton;
  • BtnRedRight: TButton;
  • BtnGreenLeft: TButton;
  • BtnGreenRight: TButton;
  • BtnWhiteLeft: TButton;
  • BtnWhiteRight: TButton;
  • BtnOrangeLeft: TButton;
  • BtnOrangeRight: TButton;
  • BtnBlueLeft: TButton;
  • BtnBlueRight: TButton;
  • BtnYellowLeft: TButton;
  • BtnYellowRight: TButton;
  • FaTurnRed: TFloatAnimation;
  • FaTurnGreen: TFloatAnimation;
  • FaTurnWhite: TFloatAnimation;
  • FaTurnOrange: TFloatAnimation;
  • FaTurnYellow: TFloatAnimation;
  • Dummy: TDummy;
  • Camera: TCamera;
  • GbRotation: TGroupBox;
  • ArcDialX: TArcDial;
  • ArcDialY: TArcDial;
  • ArcDialZ: TArcDial;
  • FaTurnBlue: TFloatAnimation;
  • CC1: TCube;
  • CC2: TCube;
  • CC5: TCube;
  • CC3: TCube;
  • CC4: TCube;
  • CC6: TCube;
  • CC8: TCube;
  • CC7: TCube;
  • CA1: TCube;
  • CA2: TCube;
  • CA3: TCube;
  • CA4: TCube;
  • CA5: TCube;
  • CA6: TCube;
  • CA7: TCube;
  • CA8: TCube;
  • CA9: TCube;
  • CA10: TCube;
  • CA11: TCube;
  • CA12: TCube;
  • PLCC1R: TPlane;
  • PLCA1R: TPlane;
  • PLCA2R: TPlane;
  • PLCA3R: TPlane;
  • PLCA4R: TPlane;
  • PLCC2R: TPlane;
  • PLCC3R: TPlane;
  • PLCC4R: TPlane;
  • PLCC5W: TPlane;
  • PLCA9W: TPlane;
  • PLCC6W: TPlane;
  • PLCA5W: TPlane;
  • PLCA6W: TPlane;
  • PLCC1W: TPlane;
  • PLCA1W: TPlane;
  • PLCC2W: TPlane;
  • PLCC2B: TPlane;
  • PLCA6B: TPlane;
  • PLCC6B: TPlane;
  • PLCA3B: TPlane;
  • PLCA11B: TPlane;
  • PLCC3B: TPlane;
  • PLCA7B: TPlane;
  • PLCC7B: TPlane;
  • PLCC5V: TPlane;
  • PLCA5V: TPlane;
  • PLCC1V: TPlane;
  • PLCA10V: TPlane;
  • PLCA2V: TPlane;
  • PLCC8V: TPlane;
  • PLCA8V: TPlane;
  • PLCC4V: TPlane;
  • PLCC4J: TPlane;
  • PLCA4J: TPlane;
  • PLCC3J: TPlane;
  • PLCA8J: TPlane;
  • PLCA7J: TPlane;
  • PLCC8J: TPlane;
  • PLCA12J: TPlane;
  • PLCC7J: TPlane;
  • PLCC6O: TPlane;
  • PLCA9O: TPlane;
  • PLCC5O: TPlane;
  • PLCA11O: TPlane;
  • PLCA10O: TPlane;
  • PLCC7O: TPlane;
  • PLCA12O: TPlane;
  • PLCC8O: TPlane;
  • GbSize: TGroupBox;
  • BtnStart: TButton;
  • GBFun: TGroupBox;
  • LbInfoLink: TLabel;
  • ShadowEffectP2F: TShadowEffect;
  • cbFun: TComboBox;
  • sclytCommand: TScaledLayout;
  • recCommand: TRectangle;
  • pbFun: TProgressBar;
  • GbAnimation: TGroupBox;
  • CbAnimation: TComboBox;
  • tbSpeedAnim: TTrackBar;
  • CPnlSpeedAnimHint: TCalloutPanel;
  • txtSpeedAnimHint: TText;
  • FaSpeedAnimHint: TFloatAnimation;
  • TbSize: TTrackBar;
  • CbRotateX: TCheckBox;
  • CbRotateY: TCheckBox;
  • CbRotateZ: TCheckBox;
  • FaAutoRotateZ: TFloatAnimation;
  • FaAutoRotateY: TFloatAnimation;
  • FaAutoRotateX: TFloatAnimation;
  • LbSpeedAnimation: TLabel;
  • TbSpeedRotation: TTrackBar;
  • CPnlSpeedRotatHint: TCalloutPanel;
  • TxtSpeedRotateHint: TText;
  • FaSpeedRotateHint: TFloatAnimation;
  • LbSpeedRotate: TLabel;
  • CpnlCubeSize: TCalloutPanel;
  • TxtCubeSize: TText;
  • FaCubeSize: TFloatAnimation;
  • MainLight: TLight;
  • GbLight: TGroupBox;
  • RbAmbiance: TRadioButton;
  • RbSpotLight: TRadioButton;
  • BwTbLight: TBWTrackBar;
  • procedure ColorBtnClick(Sender: TObject);
  • procedure RotationFinish(Sender: TObject);
  • procedure ArcDialXChange(Sender: TObject);
  • procedure BtnStartClick(Sender: TObject);
  • procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
  • procedure StickCornerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
  • procedure StickMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
  • procedure FormCreate(Sender: TObject);
  • procedure LbInfoLinkClick(Sender: TObject);
  • procedure Viewport3D2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  • procedure Viewport3D2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  • procedure Viewport3D2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  • procedure StickCornerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single;
  • RayPos, RayDir: TVector3D);
  • procedure cbFunChange(Sender: TObject);
  • procedure RotatePlan(Pos1, Pos2: Single; TheDirection, Di1, Di2, Di3, Di4: TDirection;
  • P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12: AnsiChar);
  • procedure CbAnimationChange(Sender: TObject);
  • procedure tbSpeedAnimChange(Sender: TObject);
  • procedure TbSizeChange(Sender: TObject);
  • procedure CbRotateZChange(Sender: TObject);
  • procedure CbRotateXChange(Sender: TObject);
  • procedure CbRotateYChange(Sender: TObject);
  • procedure TbSpeedRotationChange(Sender: TObject);
  • procedure TbHorizontalChange(Sender: TObject);
  • procedure RbAmbianceChange(Sender: TObject);
  • procedure BwTbLightChange(Sender: TObject);
  • private
  • { Déclarations privées }
  • LastDirection: ShortInt; // Sens de la dernière rotation 90 Aig -90 Inv
  • Direction: TDirection; // Sens du Mvt de la souris
  • ClickX: Single; // Emplacement du clic X initial
  • ClickY: Single; // Emplacement du clic Y initial
  • ClickXR: Single; // Emplacement du clic X Radial
  • ClickYR: Single; // Emplacement du clic Y Radial
  • MvtOn: Boolean; // Vaut Vrai lors d'un clic sur un stick
  • MvtAuto: Boolean; // Vaut Vrai lors des déplacements programmés
  • procedure Rotate(ThePivotAnimation: TFloatAnimation; StartValue, StepValue: Integer); overload;
  • procedure Rotate(Value: AnsiChar); overload;
  • procedure TurnXPlan(TheCube: TCube);
  • procedure TurnYPlan(TheCube: TCube);
  • procedure TurnZPlan(TheCube: TCube);
  • Function GetStickPosition(TheStick: TPlane): TStickPosition;
  • procedure MoveStick(TheStick: TPlane; Px, Py, Pz, Rx, Ry, Rz: Single);
  • procedure PlayMvt(TheMvts: AnsiString);
  • procedure SortRubik;
  • procedure SortCubes;
  • procedure SortCube(TheCube: TCube; Px, Py, Pz: Single);
  • procedure SortSticks;
  • procedure SetLight;
  • // function Translate(s: string): string;
  • public
  • { Déclarations publiques }
  • end;
  • var
  • FormMain: TFormMain;
  • implementation
  • {$R *.fmx}
  • uses uWxPlatform;
  • procedure TFormMain.FormCreate(Sender: TObject);
  • var
  • iLoop: Integer;
  • begin
  • MvtOn := False; // pas de mouvement de la souris en cours
  • MvtAuto := False; // pas de mouvement automatique en cours
  • // Load the arrays
  • for iLoop := Low(FUN_LABELS) to High(FUN_LABELS) do
  • cbFun.Items.Add(FUN_LABELS[iLoop] + ' (' + IntToStr(Length(FUN_VALUES[iLoop])) + ')');
  • for iLoop := Low(ANIMATION) to High(ANIMATION) do
  • CbAnimation.Items.Add(ANIMATION[iLoop]);
  • CbAnimation.ItemIndex := 0;
  • CbAnimation.OnChange(Self);
  • tbSpeedAnim.Value := 1.6;
  • TbSpeedRotation.Value := 11;
  • TbSize.Value := 39;
  • end;
  • /// *************************************************
  • /// Rubik's cube camera zoom +/-
  • /// *************************************************
  • procedure TFormMain.TbSizeChange(Sender: TObject);
  • begin
  • FaCubeSize.Stop;
  • CpnlCubeSize.Opacity := 1;
  • TxtCubeSize.Text := Format('%2.0f', [TbSize.Value + 10]);
  • Camera.Position.Z := TbSize.Value - 60;
  • FaCubeSize.Start;
  • end;
  • // Rotation speed
  • procedure TFormMain.tbSpeedAnimChange(Sender: TObject);
  • var
  • speed: Single;
  • begin
  • FaSpeedAnimHint.Stop;
  • CPnlSpeedAnimHint.Opacity := 1;
  • speed := 2.1 - tbSpeedAnim.Value;
  • txtSpeedAnimHint.Text := Format('%2.1f s', [speed]);
  • FaTurnRed.Duration := speed;
  • FaTurnGreen.Duration := speed;
  • FaTurnWhite.Duration := speed;
  • FaTurnOrange.Duration := speed;
  • FaTurnYellow.Duration := speed;
  • FaTurnBlue.Duration := speed;
  • FaSpeedAnimHint.Start;
  • end;
  • // ****************************************
  • // Automatic speed rotation of the cube
  • // ****************************************
  • procedure TFormMain.TbSpeedRotationChange(Sender: TObject);
  • begin
  • FaSpeedRotateHint.Stop;
  • CPnlSpeedRotatHint.Opacity := 1;
  • TxtSpeedRotateHint.Text := Format('%2.1f s', [Abs(TbSpeedRotation.Value - 22)]);
  • FaAutoRotateX.Duration := 22 - TbSpeedRotation.Value;
  • FaAutoRotateY.Duration := 22 - TbSpeedRotation.Value;
  • FaAutoRotateZ.Duration := 22 - TbSpeedRotation.Value;
  • FaSpeedRotateHint.Start;
  • end;
  • procedure TFormMain.TbHorizontalChange(Sender: TObject);
  • begin
  • end;
  • // ******************************************************
  • // Lors du changement de l'animation
  • // ******************************************************
  • procedure TFormMain.CbAnimationChange(Sender: TObject);
  • begin
  • FaTurnRed.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  • FaTurnGreen.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  • FaTurnWhite.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  • FaTurnOrange.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  • FaTurnYellow.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  • FaTurnBlue.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  • end;
  • /// *************************************************
  • /// Common procedure for the click on a color button
  • /// *************************************************
  • procedure TFormMain.ColorBtnClick(Sender: TObject);
  • begin
  • cbFun.ItemIndex := -1;
  • Rotate(AnsiChar((Sender as TButton).Text[1]));
  • end;
  • /// *************************************************
  • /// Procedure de lancement de rotation au clavier
  • /// *************************************************
  • procedure TFormMain.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
  • begin
  • Rotate(AnsiChar(KeyChar));
  • end;
  • /// *************************************************
  • /// Lance un appel au bon FloatAnimation et boucle en
  • /// Attendant la fin de l'animation
  • /// *************************************************
  • procedure TFormMain.Rotate(Value: AnsiChar);
  • begin
  • case Value of
  • 'r': Rotate(FaTurnRed, 360, 270);
  • 'R': Rotate(FaTurnRed, 0, 90);
  • 'o': Rotate(FaTurnOrange, 0, 90);
  • 'O': Rotate(FaTurnOrange, 360, 270);
  • 'y': Rotate(FaTurnYellow, 0, 90);
  • 'Y': Rotate(FaTurnYellow, 360, 270);
  • 'b': Rotate(FaTurnBlue, 0, 90);
  • 'B': Rotate(FaTurnBlue, 360, 270);
  • 'g': Rotate(FaTurnGreen, 360, 270);
  • 'G': Rotate(FaTurnGreen, 0, 90);
  • 'w': Rotate(FaTurnWhite, 360, 270);
  • 'W': Rotate(FaTurnWhite, 0, 90);
  • end;
  • end;
  • /// *****************************************************
  • /// Rechercher les cubes Coins et Arretes situés sur le
  • /// même plan que le cube allant pivoter et en faire ses
  • /// enfants.
  • /// Puis, lancement de l'animation ROTATION
  • /// *****************************************************
  • procedure TFormMain.Rotate(ThePivotAnimation: TFloatAnimation; StartValue, StepValue: Integer);
  • var
  • I: Integer;
  • begin
  • recCommand.Enabled := False; // desactiver le panneau de commandes
  • // récuperation du sens de la rotation
  • LastDirection := 90; // sens des aiguilles d'une montre pour 90 degres
  • if StartValue = 360 then
  • LastDirection := -90; // sens trigo
  • // Lier les cubes Coins et Arretes au cube allant pivoter
  • for I := 0 to FormMain.ComponentCount - 1 do
  • begin
  • if (FormMain.Components[I] Is TCube) then
  • begin
  • if ((FormMain.Components[I] As TCube).Tag = 2) or ((FormMain.Components[I] As TCube).Tag = 3) then
  • begin
  • // Red plan
  • if (SameValue((FormMain.Components[I] As TCube).Position.Z, -3, 0.1)) and (ThePivotAnimation = FaTurnRed) then
  • begin
  • (FormMain.Components[I] As TCube).Parent := RedPivot;
  • (FormMain.Components[I] As TCube).Position.Z := 0;
  • end;
  • // Orange plan
  • if (SameValue((FormMain.Components[I] As TCube).Position.Z, 3, 0.1)) and (ThePivotAnimation = FaTurnOrange) then
  • begin
  • (FormMain.Components[I] As TCube).Parent := OrangePivot;
  • (FormMain.Components[I] As TCube).Position.Z := 0;
  • end;
  • // Green plan
  • if (SameValue((FormMain.Components[I] As TCube).Position.X, -3, 0.1)) and (ThePivotAnimation = FaTurnGreen) then
  • begin
  • (FormMain.Components[I] As TCube).Parent := GreenPivot;
  • (FormMain.Components[I] As TCube).Position.X := 0;
  • end;
  • // Blue plan
  • if (SameValue((FormMain.Components[I] As TCube).Position.X, 3, 0.1)) and (ThePivotAnimation = FaTurnBlue) then
  • begin
  • (FormMain.Components[I] As TCube).Parent := BluePivot;
  • (FormMain.Components[I] As TCube).Position.X := 0;
  • end;
  • // White plan
  • if (SameValue((FormMain.Components[I] As TCube).Position.Y, -3, 0.1)) and (ThePivotAnimation = FaTurnWhite) then
  • begin
  • (FormMain.Components[I] As TCube).Parent := WhitePivot;
  • (FormMain.Components[I] As TCube).Position.Y := 0;
  • end;
  • // Yellow plan
  • if (SameValue((FormMain.Components[I] As TCube).Position.Y, 3, 0.1)) and (ThePivotAnimation = FaTurnYellow) then
  • begin
  • (FormMain.Components[I] As TCube).Parent := YellowPivot;
  • (FormMain.Components[I] As TCube).Position.Y := 0;
  • end;
  • end; // si cube Coin ou cuble arrete
  • end; // si un cube
  • end; // du for
  • // Valuer et lancer l'animation
  • ThePivotAnimation.StartValue := StartValue;
  • ThePivotAnimation.StopValue := StepValue;
  • ThePivotAnimation.Start;
  • while ThePivotAnimation.Running do Application.ProcessMessages;
  • end;
  • /// *************************************************
  • /// En fin d'animation ROTATION le cube ayant pivoté
  • // rend au cube central les enfants
  • /// *************************************************
  • procedure TFormMain.RotationFinish(Sender: TObject);
  • Var
  • I: Integer;
  • TmpX, TmpY, TmpZ: Single;
  • ThePlan: TCube;
  • begin
  • for I := 0 to FormMain.ComponentCount - 1 do
  • begin
  • if (FormMain.Components[I] Is TCube) then
  • begin
  • if ((FormMain.Components[I] As TCube).Tag = 2) or ((FormMain.Components[I] As TCube).Tag = 3) then
  • begin
  • if (FormMain.Components[I] As TCube).Parent <> CubeCentral then
  • begin
  • TmpX := (FormMain.Components[I] As TCube).AbsolutePosition.X;
  • TmpY := (FormMain.Components[I] As TCube).AbsolutePosition.Y;
  • TmpZ := (FormMain.Components[I] As TCube).AbsolutePosition.Z;
  • ThePlan := TCube((FormMain.Components[I] As TCube).Parent);
  • (FormMain.Components[I] As TCube).Position.X := TmpX;
  • (FormMain.Components[I] As TCube).Position.Y := TmpY;
  • (FormMain.Components[I] As TCube).Position.Z := TmpZ;
  • (FormMain.Components[I] As TCube).Parent := CubeCentral;
  • // plan Rouge (plan Z)
  • if ThePlan = RedPivot then
  • begin
  • (FormMain.Components[I] As TCube).Position.Z := -3;
  • TurnZPlan((FormMain.Components[I] As TCube));
  • end;
  • // plan Orange (Plan Z)
  • if ThePlan = OrangePivot then
  • begin
  • (FormMain.Components[I] As TCube).Position.Z := 3;
  • TurnZPlan((FormMain.Components[I] As TCube));
  • end;
  • // plan bleu (Plan X)
  • if ThePlan = BluePivot then
  • begin
  • (FormMain.Components[I] As TCube).Position.X := 3;
  • TurnXPlan((FormMain.Components[I] As TCube));
  • end;
  • // plan Vert (Plan X)
  • if ThePlan = GreenPivot then
  • begin
  • (FormMain.Components[I] As TCube).Position.X := -3;
  • TurnXPlan((FormMain.Components[I] As TCube));
  • end;
  • // plan Blanc (Plan Y)
  • if ThePlan = WhitePivot then
  • begin
  • (FormMain.Components[I] As TCube).Position.Y := -3;
  • TurnYPlan((FormMain.Components[I] As TCube));
  • end;
  • // plan Jaune (Plan Y)
  • if ThePlan = YellowPivot then
  • begin
  • (FormMain.Components[I] As TCube).Position.Y := 3;
  • TurnYPlan((FormMain.Components[I] As TCube));
  • end;
  • end;
  • end;
  • end;
  • if not MvtAuto then
  • recCommand.Enabled := True; // le panneau de commande redevient actif
  • end;
  • end;
  • /// *************************************************
  • /// Renvoi la position (le plan ) d'un stick
  • /// *************************************************
  • Function TFormMain.GetStickPosition(TheStick: TPlane): TStickPosition;
  • begin
  • Result := PoNone;
  • if SameValue(TheStick.Position.Y, -1.51, 0.1) then
  • Result := PoTop;
  • if SameValue(TheStick.Position.Y, 1.51, 0.1) then
  • Result := PoBottom;
  • if SameValue(TheStick.Position.X, -1.51, 0.1) then
  • Result := PoLeft;
  • if SameValue(TheStick.Position.X, 1.51, 0.1) then
  • Result := PoRight;
  • if SameValue(TheStick.Position.Z, 1.51, 0.1) then
  • Result := PoBack;
  • if SameValue(TheStick.Position.Z, -1.51, 0.1) then
  • Result := PoFront;
  • end;
  • /// *************************************************
  • /// Place (colle) un stick sur un plan des 6 plans
  • /// du cube
  • /// ************************************************
  • procedure TFormMain.MoveStick(TheStick: TPlane; Px, Py, Pz, Rx, Ry, Rz: Single);
  • begin
  • TheStick.ResetRotationAngle; // Remise à zero des angles de rotation IMPORTANT
  • TheStick.Position.X := Px;
  • TheStick.Position.Y := Py;
  • TheStick.Position.Z := Pz;
  • TheStick.RotationAngle.X := Rx;
  • TheStick.RotationAngle.Y := Ry;
  • TheStick.RotationAngle.Z := Rz;
  • end;
  • /// **********************************************
  • /// Pour le plan Z ( Rouge et Orange)
  • /// En fonction du dernier sens de rotation
  • /// replace les sticks sur la bonne facette
  • /// **********************************************
  • procedure TFormMain.TurnZPlan(TheCube: TCube);
  • var
  • I: Integer;
  • begin
  • for I := 0 to TheCube.ChildrenCount - 1 do
  • begin
  • if LastDirection = 90 then // sens des aiguilles
  • begin
  • if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
  • MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0) // Up
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
  • MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0); // Down
  • end
  • else
  • begin
  • if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
  • MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0) // Down
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
  • MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0); // Up
  • end;
  • end;
  • end;
  • /// / **********************************************
  • /// Idem, pour le plan X ( Bleu et vert)
  • /// / **********************************************
  • procedure TFormMain.TurnXPlan(TheCube: TCube);
  • var
  • I: Integer;
  • begin
  • for I := 0 to TheCube.ChildrenCount - 1 do
  • begin
  • if LastDirection = 90 then // sens INVERSE des aiguilles
  • begin
  • if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0) // Front
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0) // Up
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0) // Back
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0); // Down
  • end
  • else
  • begin
  • if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0) // Back
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0) // Down
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0) // Front
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0); // Up
  • end;
  • end;
  • end;
  • /// **********************************************
  • /// Idem, pour le plan Y ( Blanc et Jaune)
  • /// **********************************************
  • procedure TFormMain.TurnYPlan(TheCube: TCube);
  • var
  • I: Integer;
  • begin
  • for I := 0 to TheCube.ChildrenCount - 1 do
  • begin
  • if LastDirection = 90 then // sens des aiguilles
  • begin
  • if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
  • MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0) // Back
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
  • MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0); // Front
  • end
  • else
  • begin
  • if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
  • MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0) // Front
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
  • MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
  • else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
  • MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0); // Back
  • end;
  • end;
  • end;
  • {$REGION 'Jeu à la souris'}
  • /// **********************************************
  • /// en cliquant sur un stick on arme la recherche
  • /// d'un mouvement
  • /// **********************************************
  • procedure TFormMain.StickMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single;
  • RayPos, RayDir: TVector3D);
  • begin
  • if MvtAuto then
  • Exit;
  • ClickXR := RayDir.X; // emplacement du clic en X Radial
  • ClickYR := RayDir.Y; // emplacement du clic en Y Radial
  • MvtOn := True;
  • end;
  • /// **********************************************
  • /// En cliquant sur le fond on arme la rotation
  • /// du cube
  • /// **********************************************
  • procedure TFormMain.Viewport3D2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  • begin
  • ClickX := X; // emplacement du clic en X
  • ClickY := Y; // emplacement du clic en Y
  • end;
  • /// **********************************************
  • /// le deplacement de la souris fait pivoter le cube
  • /// **********************************************
  • procedure TFormMain.Viewport3D2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
  • begin
  • IF MvtOn then
  • Exit;
  • if ssLeft in Shift then // si la souris bouge avec le clic droit enfoncé
  • begin
  • Direction := DiNone;
  • IF (ClickX - X) > 3 then
  • Direction := DiLeft;
  • IF (X - ClickX) > 3 then
  • Direction := DiRight;
  • IF (ClickY - Y) > 3 then
  • Direction := DiTop;
  • IF (Y - ClickY) > 3 then
  • Direction := DiBottom;
  • if Direction <> DiNone then // une direction a été trouvée
  • begin
  • ClickX := X;
  • ClickY := Y;
  • if Direction = DiBottom then
  • ArcDialX.Value := ArcDialX.Value - 5;
  • if Direction = DiTop then
  • ArcDialX.Value := ArcDialX.Value + 5;
  • if Direction = DiLeft then
  • ArcDialY.Value := ArcDialY.Value - 5;
  • if Direction = DiRight then
  • ArcDialY.Value := ArcDialY.Value + 5;
  • ArcDialXChange(Self);
  • end;
  • end;
  • end;
  • /// **********************************************
  • /// Desarmement du mouvement
  • /// **********************************************
  • procedure TFormMain.Viewport3D2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
  • begin
  • MvtOn := False;
  • end;
  • procedure TFormMain.StickCornerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single;
  • RayPos, RayDir: TVector3D);
  • begin
  • MvtOn := False;
  • end;
  • procedure TFormMain.StickCornerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
  • var
  • PosXCube, PosYCube, PosZCube: int64;
  • begin
  • if not MvtOn then
  • Exit; // si pas de mouvement d'armé
  • if ssLeft in Shift then // si la souris bouge avec le clic droit enfoncé
  • begin
  • Direction := DiNone;
  • IF (ClickXR - RayDir.X) > 0.02 then
  • Direction := DiLeft;
  • IF (RayDir.X - ClickXR) > 0.02 then
  • Direction := DiRight;
  • IF (ClickYR - RayDir.Y) > 0.02 then
  • Direction := DiTop;
  • IF (RayDir.Y - ClickYR) > 0.02 then
  • Direction := DiBottom;
  • if Direction <> DiNone then // une direction a été trouvée
  • begin
  • cbFun.ItemIndex := -1;
  • // recup de la position XYU du cube sous le stick
  • PosXCube := Round(((Sender as TPlane).Parent as TCube).Position.X);
  • PosYCube := Round(((Sender as TPlane).Parent as TCube).Position.Y);
  • PosZCube := Round(((Sender as TPlane).Parent as TCube).Position.Z);
  • // desarment du mouvement et reinitialisation de l'emplacement de la souris
  • MvtOn := False;
  • ClickXR := RayDir.X;
  • ClickYR := RayDir.Y;
  • if (PosZCube = -3) and (SameValue((Sender as TPlane).Position.Z, -1.51, 0.1)) then // Plan Avant Rouge
  • RotatePlan(PosXCube, PosYCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'w', 'W', 'Y', 'y', 'B', 'b', 'w',
  • 'W', 'Y', 'y')
  • else if (PosZCube = 3) and (SameValue((Sender as TPlane).Position.Z, 1.51, 0.1)) then // Plan Arriere Orange
  • RotatePlan(PosXCube, PosYCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'W', 'w', 'y', 'Y', 'B', 'b', 'W',
  • 'w', 'y', 'Y')
  • else if (PosYCube = -3) and (SameValue((Sender as TPlane).Position.Y, -1.51, 0.1)) then // Plan Haut Blanc
  • RotatePlan(PosXCube, PosZCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'R', 'r', 'o', 'O', 'B', 'b', 'R',
  • 'r', 'o', 'O')
  • else if (PosYCube = 3) and (SameValue((Sender as TPlane).Position.Y, 1.51, 0.1)) then // Plan Bas Jaune
  • RotatePlan(PosXCube, PosZCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'r', 'R', 'O', 'o', 'B', 'b', 'r',
  • 'R', 'O', 'o')
  • else if (PosXCube = -3) and (SameValue((Sender as TPlane).Position.X, -1.51, 0.1)) then // Plan Gauche Vert
  • RotatePlan(PosYCube, PosZCube, Direction, DiRight, DiLeft, DiBottom, DiTop, 'w', 'W', 'r', 'R', 'O', 'o', 'Y', 'y', 'r',
  • 'R', 'O', 'o')
  • else if (PosXCube = 3) and (SameValue((Sender as TPlane).Position.X, 1.51, 0.1)) then // Plan Droit Bleu
  • RotatePlan(PosYCube, PosZCube, Direction, DiRight, DiLeft, DiBottom, DiTop, 'w', 'W', 'R', 'r', 'o', 'O', 'Y', 'y', 'R',
  • 'r', 'o', 'O');
  • end;
  • end;
  • end;
  • procedure TFormMain.RotatePlan(Pos1, Pos2: Single; TheDirection, Di1, Di2, Di3, Di4: TDirection;
  • P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12: AnsiChar);
  • begin
  • if Pos1 = -3 then
  • begin
  • if (TheDirection = Di1) then
  • Rotate(P1);
  • if (TheDirection = Di2) then
  • Rotate(P2);
  • if Pos2 = -3 then
  • begin
  • if (TheDirection = Di3) then
  • Rotate(P3);
  • if (TheDirection = Di4) then
  • Rotate(P4);
  • end
  • else
  • begin
  • if (TheDirection = Di3) then
  • Rotate(P5);
  • if (TheDirection = Di4) then
  • Rotate(P6);
  • end;
  • end
  • else
  • begin // coté bas
  • if (TheDirection = Di1) then
  • Rotate(P7);
  • if (TheDirection = Di2) then
  • Rotate(P8);
  • if Pos2 = -3 then
  • begin
  • if (TheDirection = Di3) then
  • Rotate(P9);
  • if (TheDirection = Di4) then
  • Rotate(P10);
  • end
  • else
  • begin
  • if (TheDirection = Di3) then
  • Rotate(P11);
  • if (TheDirection = Di4) then
  • Rotate(P12);
  • end;
  • end;
  • end;
  • {$ENDREGION}
  • {$REGION 'Sort the cube (not solving)'}
  • procedure TFormMain.BtnStartClick(Sender: TObject);
  • begin
  • if MessageDlg('Restore initial cube?', TMsgDlgType.mtInformation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = MrNo then
  • Exit;
  • SortRubik();
  • CbRotateX.IsChecked := False;
  • CbRotateY.IsChecked := False;
  • CbRotateZ.IsChecked := False;
  • ArcDialX.Value := -35;
  • ArcDialY.Value := -45;
  • ArcDialZ.Value := -18;
  • cbFun.ItemIndex := -1;
  • ArcDialXChange(Self);
  • end;
  • procedure TFormMain.SortRubik();
  • begin
  • SortCubes();
  • SortSticks();
  • end;
  • procedure TFormMain.SortSticks();
  • begin
  • // face Rouge
  • MoveStick( PLCC1R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCC2R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCC4R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCC3R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCA1R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCA2R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCA3R, 0, 0, -1.51, 0, 0, 0);
  • MoveStick( PLCA4R, 0, 0, -1.51, 0, 0, 0);
  • // Face Bleu
  • MoveStick( PLCC2B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick( PLCC6B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick( PLCC3B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick( PLCC7B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick( PLCA6B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick( PLCA3B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick(PLCA11B, 1.51, 0, 0, 0, -90, 0);
  • MoveStick( PLCA7B, 1.51, 0, 0, 0, -90, 0);
  • // Face Verte
  • MoveStick( PLCC5V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick( PLCC1V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick( PLCC8V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick( PLCC4V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick( PLCA5V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick(PLCA10V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick( PLCA8V, -1.51, 0, 0, 0, 90, 0);
  • MoveStick( PLCA2V, -1.51, 0, 0, 0, 90, 0);
  • // Orange
  • MoveStick( PLCC6O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick( PLCC5O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick( PLCC7O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick( PLCC8O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick( PLCA9O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick(PLCA11O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick(PLCA10O, 0, 0, 1.51, 180, 0, 0);
  • MoveStick(PLCA12O, 0, 0, 1.51, 180, 0, 0);
  • // Face Blanche
  • MoveStick( PLCC5W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCC6W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCC1W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCC2W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCA9W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCA5W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCA6W, 0, -1.51, 0, -90, 0, 0);
  • MoveStick( PLCA1W, 0, -1.51, 0, -90, 0, 0);
  • // Face Jaune
  • MoveStick( PLCC4J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick( PLCC3J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick( PLCC8J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick( PLCC7J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick( PLCA4J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick( PLCA8J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick( PLCA7J, 0, 1.51, 0, 90, 0, 0);
  • MoveStick(PLCA12J, 0, 1.51, 0, 90, 0, 0);
  • end;
  • procedure TFormMain.SortCubes();
  • begin
  • // les cubes coins
  • SortCube( CC1, -3, -3, -3);
  • SortCube( CC2, 3, -3, -3);
  • SortCube( CC3, 3, 3, -3);
  • SortCube( CC4, -3, 3, -3);
  • SortCube( CC5, -3, -3, 3);
  • SortCube( CC6, 3, -3, 3);
  • SortCube( CC7, 3, 3, 3);
  • SortCube( CC8, -3, 3, 3);
  • // les cubes arretes
  • SortCube( CA1, 0, -3, -3);
  • SortCube( CA2, -3, 0, -3);
  • SortCube( CA3, 3, 0, -3);
  • SortCube( CA4, 0, 3, -3);
  • SortCube( CA5, -3, -3, 0);
  • SortCube( CA6, 3, -3, 0);
  • SortCube( CA7, 3, 3, 0);
  • SortCube( CA8, -3, 3, 0);
  • SortCube( CA9, 0, -3, 3);
  • SortCube(CA10, -3, 0, 3);
  • SortCube(CA11, 3, 0, 3);
  • SortCube(CA12, 0, 3, 3);
  • end;
  • procedure TFormMain.SortCube(TheCube: TCube; Px, Py, Pz: Single);
  • begin
  • TheCube.ResetRotationAngle;
  • TheCube.Position.X := Px;
  • TheCube.Position.Y := Py;
  • TheCube.Position.Z := Pz;
  • end;
  • {$ENDREGION}
  • {$REGION 'Jouer des mouvements enregistrés'}
  • procedure TFormMain.cbFunChange(Sender: TObject);
  • begin
  • if cbFun.ItemIndex <> -1 then
  • begin
  • cbFun.DropDown; // Pour refermer immédiatement la dropdown
  • SortRubik();
  • PlayMvt(FUN_VALUES[cbFun.ItemIndex]);
  • end;
  • end;
  • procedure TFormMain.PlayMvt(TheMvts: AnsiString);
  • var
  • I: Integer;
  • iMax: Integer;
  • begin
  • // Platform.SetCursor(nil, crHourGlass); // ProcessMessages casse le curseur
  • MvtAuto := True; // On enchaine une série (l'utilisateur ne peut pas faire de modif manuelle)
  • iMax := Length(TheMvts);
  • pbFun.Value := 1;
  • pbFun.Max := iMax;
  • pbFun.Visible := True;
  • recCommand.Enabled := False; // desactiver le panneau de commandes
  • for I := 1 to iMax do
  • begin
  • Rotate(TheMvts[I]);
  • pbFun.Value := pbFun.Value + 1;
  • end;
  • MvtAuto := False; // La série est terminée, l'utilisateur peut à nouveau jouer
  • pbFun.Visible := False;
  • recCommand.Enabled := True; // le panneau de commande redevient actif
  • end;
  • {$ENDREGION}
  • {$REGION 'Ouverture de la page Web'}
  • procedure TFormMain.LbInfoLinkClick(Sender: TObject);
  • begin
  • TMisc.Open((Sender as TLabel).Text);
  • end;
  • {$ENDREGION}
  • {$REGION 'Rotation automatique du cube'}
  • /// *************************************************
  • /// Déplacement de la caméra autour du rubik's cube
  • /// *************************************************
  • Procedure TFormMain.ArcDialXChange(Sender: TObject);
  • begin
  • Dummy.RotationAngle.X := ArcDialX.Value;
  • Dummy.RotationAngle.Y := ArcDialY.Value;
  • Dummy.RotationAngle.Z := ArcDialZ.Value;
  • end;
  • Procedure TFormMain.CbRotateXChange(Sender: TObject);
  • begin
  • FaAutoRotateX.Stop;
  • if CbRotateX.IsChecked then
  • FaAutoRotateX.Start;
  • end;
  • Procedure TFormMain.CbRotateYChange(Sender: TObject);
  • begin
  • FaAutoRotateY.Stop;
  • if CbRotateY.IsChecked then
  • FaAutoRotateY.Start;
  • end;
  • Procedure TFormMain.CbRotateZChange(Sender: TObject);
  • begin
  • FaAutoRotateZ.Stop;
  • if CbRotateZ.IsChecked then
  • FaAutoRotateZ.Start;
  • end;
  • {$ENDREGION}
  • {$REGION 'Les lumières'}
  • procedure TFormMain.RbAmbianceChange(Sender: TObject);
  • Var
  • I: Integer;
  • Color: TAlphaColor;
  • begin
  • MainLight.Enabled := RbSpotLight.IsChecked;
  • BwTbLight.Enabled := RbSpotLight.IsChecked;
  • if RbSpotLight.IsChecked then
  • begin
  • Color := claNull;
  • SetLight;
  • end
  • else
  • Color := claWhite;
  • for I := 0 to FormMain.ComponentCount - 1 do
  • begin
  • // les stickers
  • if (FormMain.Components[I] Is TPlane) then
  • (FormMain.Components[I] As TPlane).material.Emissive := Color;
  • // Les cubes pivots
  • if (FormMain.Components[I] Is TCube) then
  • if (FormMain.Components[I] As TCube).Tag = 1 then
  • (FormMain.Components[I] As TCube).material.Emissive := Color;
  • end;
  • end;
  • procedure TFormMain.SetLight;
  • var
  • cLight: TAlphaColorRec;
  • begin
  • cLight.R := Round(255 * BwTbLight.Value);
  • cLight.G := Round(255 * BwTbLight.Value);
  • cLight.B := Round(255 * BwTbLight.Value);
  • MainLight.Diffuse := cLight.Color;
  • Viewport3D2.Repaint;
  • end;
  • procedure TFormMain.BwTbLightChange(Sender: TObject);
  • begin
  • SetLight;
  • end;
  • {$ENDREGION}
  • end.
unit UMain;

interface
//               ______             __
//              /\  ___\           /\ \__
//  _____       \ \ \__/ ___    ___\ \ ,_\    __    ___      __     __     __  __
// /\ '__`\      \ \  _\/ __`\/' _ `\ \ \/  /'__`\/' _ `\  /'__`\ /'__`\  /\ \/\ \
// \ \ \_\ \   __ \ \ \/\ \_\ \\ \/\ \ \ \_/\  __//\ \/\ \/\  __//\ \_\ \_\ \ \_\ \
//  \ \ ,__/ / \_\ \ \_\ \____/ \_\ \_\ \__\ \____\ \_\ \_\ \____\ \__/ \_\\ \____/
//   \ \ \/  \/_/  \/_/\/___/ \/_/\/_/\/__/\/____/\/_/\/_/\/____/\/__/\/_/ \/___/
//    \ \_\
//     \/_/     P2F - 2012 - Rubik'sCube
//     FREEWARE - Aucune diffusion  commerciale basée sur ce code source
//     n'est autorisée sans autorisation préalable de l'auteur.
//     Rubik's Cube 3D Pascal Fonteneau
//     Interfaces- Fun Parts - Pascal Fonteneau and Whiler

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs, FMX.Types3D, FMX.Objects3D,
  FMX.Ani, FMX.Layouts, FMX.Memo, System.Math, System.StrUtils, FMX.Effects, FMX.Platform,
  FMX.Objects, FMX.ListBox, FMX.Colors;

const
  FUN_LABELS : array[0..11] of string     = ('Damier', 'Barre', '2 Cubes',
                                             '3 Cubes', 'Carré', 'Damier coloré',
                                             'Plus', 'Bande', 'Diagonale',
                                             'Angle', 'L', 'Tetris');
  FUN_VALUES : array[0..11] of AnsiString =
   ('OORRWWYYGGBB', 'RRGGOORRGGor', 'WWGGRRwOOYBrBrBryOOw',
                                             'GGyRRyowoRByWBOGGOWW', 'gBrOYwgB', 'OORRWWYYGGBBgBrOYwgFB',
                                             'RGGBBRROOWWGGBBRROOYYr', 'rGGRRbyRRWRRBBRRYRRwbRRGG', 'GBROGBROGBRO',
                                             'WGGRbGoRRBgYWWrGGw', 'OBBYRbGyoRyWgRRw', 'GBROGBROGBROWWYY');

  ANIMATION : array[0..10] of String      = ('Linear','Quadratic','Cubic','Quartic','Quintic','Sinusoidal',
                                             'Exponential','Circular','Elastic','Back','Bounce');

type
  TStickPosition = (PoFront, PoBack, PoTop, PoBottom, PoRight, PoLeft, PoNone);
  TDirection     = (DiNone, DiLeft, DiRight, DiTop, DiBottom);

  TFormMain = class(TForm)
    LabelX: TLabel;
    LabelY: TLabel;
    LabelZ: TLabel;
    StyleBook1: TStyleBook;
    Viewport3D2: TViewport3D;
    CubeCentral: TCube;
    RedPivot: TCube;
    GreenPivot: TCube;
    WhitePivot: TCube;
    OrangePivot: TCube;
    BluePivot: TCube;
    YellowPivot: TCube;
    BtnRedLeft: TButton;
    BtnRedRight: TButton;
    BtnGreenLeft: TButton;
    BtnGreenRight: TButton;
    BtnWhiteLeft: TButton;
    BtnWhiteRight: TButton;
    BtnOrangeLeft: TButton;
    BtnOrangeRight: TButton;
    BtnBlueLeft: TButton;
    BtnBlueRight: TButton;
    BtnYellowLeft: TButton;
    BtnYellowRight: TButton;
    FaTurnRed: TFloatAnimation;
    FaTurnGreen: TFloatAnimation;
    FaTurnWhite: TFloatAnimation;
    FaTurnOrange: TFloatAnimation;
    FaTurnYellow: TFloatAnimation;
    Dummy: TDummy;
    Camera: TCamera;
    GbRotation: TGroupBox;
    ArcDialX: TArcDial;
    ArcDialY: TArcDial;
    ArcDialZ: TArcDial;
    FaTurnBlue: TFloatAnimation;
    CC1: TCube;
    CC2: TCube;
    CC5: TCube;
    CC3: TCube;
    CC4: TCube;
    CC6: TCube;
    CC8: TCube;
    CC7: TCube;
    CA1: TCube;
    CA2: TCube;
    CA3: TCube;
    CA4: TCube;
    CA5: TCube;
    CA6: TCube;
    CA7: TCube;
    CA8: TCube;
    CA9: TCube;
    CA10: TCube;
    CA11: TCube;
    CA12: TCube;
    PLCC1R: TPlane;
    PLCA1R: TPlane;
    PLCA2R: TPlane;
    PLCA3R: TPlane;
    PLCA4R: TPlane;
    PLCC2R: TPlane;
    PLCC3R: TPlane;
    PLCC4R: TPlane;
    PLCC5W: TPlane;
    PLCA9W: TPlane;
    PLCC6W: TPlane;
    PLCA5W: TPlane;
    PLCA6W: TPlane;
    PLCC1W: TPlane;
    PLCA1W: TPlane;
    PLCC2W: TPlane;
    PLCC2B: TPlane;
    PLCA6B: TPlane;
    PLCC6B: TPlane;
    PLCA3B: TPlane;
    PLCA11B: TPlane;
    PLCC3B: TPlane;
    PLCA7B: TPlane;
    PLCC7B: TPlane;
    PLCC5V: TPlane;
    PLCA5V: TPlane;
    PLCC1V: TPlane;
    PLCA10V: TPlane;
    PLCA2V: TPlane;
    PLCC8V: TPlane;
    PLCA8V: TPlane;
    PLCC4V: TPlane;
    PLCC4J: TPlane;
    PLCA4J: TPlane;
    PLCC3J: TPlane;
    PLCA8J: TPlane;
    PLCA7J: TPlane;
    PLCC8J: TPlane;
    PLCA12J: TPlane;
    PLCC7J: TPlane;
    PLCC6O: TPlane;
    PLCA9O: TPlane;
    PLCC5O: TPlane;
    PLCA11O: TPlane;
    PLCA10O: TPlane;
    PLCC7O: TPlane;
    PLCA12O: TPlane;
    PLCC8O: TPlane;
    GbSize: TGroupBox;
    BtnStart: TButton;
    GBFun: TGroupBox;
    LbInfoLink: TLabel;
    ShadowEffectP2F: TShadowEffect;
    cbFun: TComboBox;
    sclytCommand: TScaledLayout;
    recCommand: TRectangle;
    pbFun: TProgressBar;
    GbAnimation: TGroupBox;
    CbAnimation: TComboBox;
    tbSpeedAnim: TTrackBar;
    CPnlSpeedAnimHint: TCalloutPanel;
    txtSpeedAnimHint: TText;
    FaSpeedAnimHint: TFloatAnimation;
    TbSize: TTrackBar;
    CbRotateX: TCheckBox;
    CbRotateY: TCheckBox;
    CbRotateZ: TCheckBox;
    FaAutoRotateZ: TFloatAnimation;
    FaAutoRotateY: TFloatAnimation;
    FaAutoRotateX: TFloatAnimation;
    LbSpeedAnimation: TLabel;
    TbSpeedRotation: TTrackBar;
    CPnlSpeedRotatHint: TCalloutPanel;
    TxtSpeedRotateHint: TText;
    FaSpeedRotateHint: TFloatAnimation;
    LbSpeedRotate: TLabel;
    CpnlCubeSize: TCalloutPanel;
    TxtCubeSize: TText;
    FaCubeSize: TFloatAnimation;
    MainLight: TLight;
    GbLight: TGroupBox;
    RbAmbiance: TRadioButton;
    RbSpotLight: TRadioButton;
    BwTbLight: TBWTrackBar;
    procedure ColorBtnClick(Sender: TObject);
    procedure RotationFinish(Sender: TObject);
    procedure ArcDialXChange(Sender: TObject);
    procedure BtnStartClick(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
    procedure StickCornerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
    procedure StickMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
    procedure FormCreate(Sender: TObject);
    procedure LbInfoLinkClick(Sender: TObject);
    procedure Viewport3D2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    procedure Viewport3D2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    procedure Viewport3D2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    procedure StickCornerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single;
      RayPos, RayDir: TVector3D);
    procedure cbFunChange(Sender: TObject);
    procedure RotatePlan(Pos1, Pos2: Single; TheDirection, Di1, Di2, Di3, Di4: TDirection;
      P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12: AnsiChar);
    procedure CbAnimationChange(Sender: TObject);
    procedure tbSpeedAnimChange(Sender: TObject);
    procedure TbSizeChange(Sender: TObject);
    procedure CbRotateZChange(Sender: TObject);
    procedure CbRotateXChange(Sender: TObject);
    procedure CbRotateYChange(Sender: TObject);
    procedure TbSpeedRotationChange(Sender: TObject);
    procedure TbHorizontalChange(Sender: TObject);
    procedure RbAmbianceChange(Sender: TObject);
    procedure BwTbLightChange(Sender: TObject);

  private
    { Déclarations privées }
    LastDirection: ShortInt;  // Sens de la dernière rotation  90 Aig -90 Inv
    Direction: TDirection;    // Sens du Mvt de la souris
    ClickX: Single;           // Emplacement du clic X initial
    ClickY: Single;           // Emplacement du clic Y initial
    ClickXR: Single;          // Emplacement du clic X Radial
    ClickYR: Single;          // Emplacement du clic Y Radial

    MvtOn: Boolean;           // Vaut Vrai lors d'un clic sur un stick
    MvtAuto: Boolean;         // Vaut Vrai lors des déplacements programmés
    procedure Rotate(ThePivotAnimation: TFloatAnimation; StartValue, StepValue: Integer); overload;
    procedure Rotate(Value: AnsiChar); overload;
    procedure TurnXPlan(TheCube: TCube);
    procedure TurnYPlan(TheCube: TCube);
    procedure TurnZPlan(TheCube: TCube);
    Function  GetStickPosition(TheStick: TPlane): TStickPosition;
    procedure MoveStick(TheStick: TPlane; Px, Py, Pz, Rx, Ry, Rz: Single);
    procedure PlayMvt(TheMvts: AnsiString);
    procedure SortRubik;
    procedure SortCubes;
    procedure SortCube(TheCube: TCube; Px, Py, Pz: Single);
    procedure SortSticks;
    procedure SetLight;
    // function Translate(s: string): string;
  public
    { Déclarations publiques }

  end;

var
  FormMain: TFormMain;

implementation

{$R *.fmx}

uses uWxPlatform;

procedure TFormMain.FormCreate(Sender: TObject);
var
  iLoop: Integer;
begin
  MvtOn   := False;   // pas de mouvement de la souris en cours
  MvtAuto := False;   // pas de mouvement automatique en cours

  // Load the arrays
  for iLoop := Low(FUN_LABELS) to High(FUN_LABELS) do
    cbFun.Items.Add(FUN_LABELS[iLoop] + ' (' + IntToStr(Length(FUN_VALUES[iLoop])) + ')');

  for iLoop := Low(ANIMATION) to High(ANIMATION) do
    CbAnimation.Items.Add(ANIMATION[iLoop]);

  CbAnimation.ItemIndex := 0;
  CbAnimation.OnChange(Self);

  tbSpeedAnim.Value     := 1.6;
  TbSpeedRotation.Value := 11;
  TbSize.Value          := 39;
end;

/// *************************************************
/// Rubik's cube camera zoom +/-
/// *************************************************

procedure TFormMain.TbSizeChange(Sender: TObject);
begin
  FaCubeSize.Stop;
  CpnlCubeSize.Opacity := 1;
  TxtCubeSize.Text     := Format('%2.0f', [TbSize.Value + 10]);
  Camera.Position.Z    := TbSize.Value - 60;
  FaCubeSize.Start;
end;

// Rotation speed
procedure TFormMain.tbSpeedAnimChange(Sender: TObject);
var
  speed: Single;
begin
  FaSpeedAnimHint.Stop;
  CPnlSpeedAnimHint.Opacity := 1;
  speed                     := 2.1 - tbSpeedAnim.Value;
  txtSpeedAnimHint.Text     := Format('%2.1f s', [speed]);
  FaTurnRed.Duration        := speed;
  FaTurnGreen.Duration      := speed;
  FaTurnWhite.Duration      := speed;
  FaTurnOrange.Duration     := speed;
  FaTurnYellow.Duration     := speed;
  FaTurnBlue.Duration       := speed;
  FaSpeedAnimHint.Start;
end;

// ****************************************
// Automatic speed rotation of the cube
// ****************************************

procedure TFormMain.TbSpeedRotationChange(Sender: TObject);
begin
  FaSpeedRotateHint.Stop;
  CPnlSpeedRotatHint.Opacity := 1;
  TxtSpeedRotateHint.Text    := Format('%2.1f s', [Abs(TbSpeedRotation.Value - 22)]);
  FaAutoRotateX.Duration     := 22 - TbSpeedRotation.Value;
  FaAutoRotateY.Duration     := 22 - TbSpeedRotation.Value;
  FaAutoRotateZ.Duration     := 22 - TbSpeedRotation.Value;
  FaSpeedRotateHint.Start;
end;

procedure TFormMain.TbHorizontalChange(Sender: TObject);
begin

end;

// ******************************************************
// Lors du changement de l'animation
// ******************************************************
procedure TFormMain.CbAnimationChange(Sender: TObject);
begin
  FaTurnRed.Interpolation    := TInterpolationType(CbAnimation.ItemIndex);
  FaTurnGreen.Interpolation  := TInterpolationType(CbAnimation.ItemIndex);
  FaTurnWhite.Interpolation  := TInterpolationType(CbAnimation.ItemIndex);
  FaTurnOrange.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  FaTurnYellow.Interpolation := TInterpolationType(CbAnimation.ItemIndex);
  FaTurnBlue.Interpolation   := TInterpolationType(CbAnimation.ItemIndex);
end;

/// *************************************************
/// Common procedure for the click on a color button
/// *************************************************
procedure TFormMain.ColorBtnClick(Sender: TObject);
begin
  cbFun.ItemIndex := -1;
  Rotate(AnsiChar((Sender as TButton).Text[1]));
end;

/// *************************************************
/// Procedure de lancement de rotation au clavier
/// *************************************************
procedure TFormMain.FormKeyDown(Sender: TObject; var Key: Word; var KeyChar: Char; Shift: TShiftState);
begin
  Rotate(AnsiChar(KeyChar));
end;

/// *************************************************
/// Lance un appel au bon FloatAnimation et boucle en
/// Attendant la fin de l'animation
/// *************************************************
procedure TFormMain.Rotate(Value: AnsiChar);
begin
 case Value of
    'r': Rotate(FaTurnRed, 360, 270);
    'R': Rotate(FaTurnRed, 0, 90);
    'o': Rotate(FaTurnOrange, 0, 90);
    'O': Rotate(FaTurnOrange, 360, 270);
    'y': Rotate(FaTurnYellow, 0, 90);
    'Y': Rotate(FaTurnYellow, 360, 270);
    'b': Rotate(FaTurnBlue, 0, 90);
    'B': Rotate(FaTurnBlue, 360, 270);
    'g': Rotate(FaTurnGreen, 360, 270);
    'G': Rotate(FaTurnGreen, 0, 90);
    'w': Rotate(FaTurnWhite, 360, 270);
    'W': Rotate(FaTurnWhite, 0, 90);
 end;
end;

/// *****************************************************
/// Rechercher les cubes Coins et Arretes situés sur le
/// même plan que le cube allant pivoter et en faire ses
/// enfants.
/// Puis, lancement de l'animation ROTATION
/// *****************************************************
procedure TFormMain.Rotate(ThePivotAnimation: TFloatAnimation; StartValue, StepValue: Integer);
var
  I: Integer;
begin
  recCommand.Enabled := False; // desactiver le panneau de commandes

  // récuperation du sens de la rotation
  LastDirection := 90;      // sens des aiguilles d'une montre pour 90 degres
  if StartValue = 360 then
    LastDirection := -90;   // sens trigo

  // Lier les cubes Coins et Arretes au cube allant pivoter
  for I := 0 to FormMain.ComponentCount - 1 do
  begin
    if (FormMain.Components[I] Is TCube) then
    begin
      if ((FormMain.Components[I] As TCube).Tag = 2) or ((FormMain.Components[I] As TCube).Tag = 3) then
      begin
        // Red plan
        if (SameValue((FormMain.Components[I] As TCube).Position.Z, -3, 0.1)) and (ThePivotAnimation = FaTurnRed) then
        begin
          (FormMain.Components[I] As TCube).Parent     := RedPivot;
          (FormMain.Components[I] As TCube).Position.Z := 0;
        end;
        // Orange plan
        if (SameValue((FormMain.Components[I] As TCube).Position.Z, 3, 0.1)) and (ThePivotAnimation = FaTurnOrange) then
        begin
          (FormMain.Components[I] As TCube).Parent     := OrangePivot;
          (FormMain.Components[I] As TCube).Position.Z := 0;
        end;
        // Green plan
        if (SameValue((FormMain.Components[I] As TCube).Position.X, -3, 0.1)) and (ThePivotAnimation = FaTurnGreen) then
        begin
          (FormMain.Components[I] As TCube).Parent     := GreenPivot;
          (FormMain.Components[I] As TCube).Position.X := 0;
        end;
        // Blue plan
        if (SameValue((FormMain.Components[I] As TCube).Position.X, 3, 0.1)) and (ThePivotAnimation = FaTurnBlue) then
        begin
          (FormMain.Components[I] As TCube).Parent     := BluePivot;
          (FormMain.Components[I] As TCube).Position.X := 0;
        end;
        // White plan
        if (SameValue((FormMain.Components[I] As TCube).Position.Y, -3, 0.1)) and (ThePivotAnimation = FaTurnWhite) then
        begin
          (FormMain.Components[I] As TCube).Parent     := WhitePivot;
          (FormMain.Components[I] As TCube).Position.Y := 0;
        end;
        // Yellow plan
        if (SameValue((FormMain.Components[I] As TCube).Position.Y, 3, 0.1)) and (ThePivotAnimation = FaTurnYellow) then
        begin
          (FormMain.Components[I] As TCube).Parent     := YellowPivot;
          (FormMain.Components[I] As TCube).Position.Y := 0;
        end;
      end; // si cube Coin ou cuble arrete
    end; // si un cube
  end; // du for

  // Valuer et lancer l'animation
  ThePivotAnimation.StartValue := StartValue;
  ThePivotAnimation.StopValue  := StepValue;
  ThePivotAnimation.Start;
  while ThePivotAnimation.Running do Application.ProcessMessages;
end;

/// *************************************************
/// En fin d'animation ROTATION le cube ayant pivoté
// rend au cube central les enfants
/// *************************************************
procedure TFormMain.RotationFinish(Sender: TObject);
Var
  I: Integer;
  TmpX, TmpY, TmpZ: Single;
  ThePlan: TCube;
begin
  for I := 0 to FormMain.ComponentCount - 1 do
  begin
    if (FormMain.Components[I] Is TCube) then
    begin
      if ((FormMain.Components[I] As TCube).Tag = 2) or ((FormMain.Components[I] As TCube).Tag = 3) then
      begin
        if (FormMain.Components[I] As TCube).Parent <> CubeCentral then
        begin
          TmpX    := (FormMain.Components[I] As TCube).AbsolutePosition.X;
          TmpY    := (FormMain.Components[I] As TCube).AbsolutePosition.Y;
          TmpZ    := (FormMain.Components[I] As TCube).AbsolutePosition.Z;
          ThePlan := TCube((FormMain.Components[I] As TCube).Parent);
          (FormMain.Components[I] As TCube).Position.X := TmpX;
          (FormMain.Components[I] As TCube).Position.Y := TmpY;
          (FormMain.Components[I] As TCube).Position.Z := TmpZ;
          (FormMain.Components[I] As TCube).Parent     := CubeCentral;

          // plan Rouge (plan Z)
          if ThePlan = RedPivot then
          begin
            (FormMain.Components[I] As TCube).Position.Z := -3;
            TurnZPlan((FormMain.Components[I] As TCube));
          end;

          // plan Orange (Plan Z)
          if ThePlan = OrangePivot then
          begin
            (FormMain.Components[I] As TCube).Position.Z := 3;
            TurnZPlan((FormMain.Components[I] As TCube));
          end;

          // plan bleu (Plan X)
          if ThePlan = BluePivot then
          begin
            (FormMain.Components[I] As TCube).Position.X := 3;
            TurnXPlan((FormMain.Components[I] As TCube));
          end;

          // plan Vert (Plan X)
          if ThePlan = GreenPivot then
          begin
            (FormMain.Components[I] As TCube).Position.X := -3;
            TurnXPlan((FormMain.Components[I] As TCube));
          end;

          // plan Blanc (Plan Y)
          if ThePlan = WhitePivot then
          begin
            (FormMain.Components[I] As TCube).Position.Y := -3;
            TurnYPlan((FormMain.Components[I] As TCube));
          end;

          // plan Jaune  (Plan Y)
          if ThePlan = YellowPivot then
          begin
            (FormMain.Components[I] As TCube).Position.Y := 3;
            TurnYPlan((FormMain.Components[I] As TCube));
          end;
        end;
      end;
    end;
    if not MvtAuto then
      recCommand.Enabled := True; // le panneau de commande redevient actif
  end;
end;

/// *************************************************
/// Renvoi la position (le plan ) d'un stick
/// *************************************************
Function TFormMain.GetStickPosition(TheStick: TPlane): TStickPosition;
begin
  Result := PoNone;
  if SameValue(TheStick.Position.Y, -1.51, 0.1) then
    Result := PoTop;
  if SameValue(TheStick.Position.Y, 1.51, 0.1) then
    Result := PoBottom;
  if SameValue(TheStick.Position.X, -1.51, 0.1) then
    Result := PoLeft;
  if SameValue(TheStick.Position.X, 1.51, 0.1) then
    Result := PoRight;
  if SameValue(TheStick.Position.Z, 1.51, 0.1) then
    Result := PoBack;
  if SameValue(TheStick.Position.Z, -1.51, 0.1) then
    Result := PoFront;
end;

/// *************************************************
/// Place (colle)  un stick sur un plan des 6 plans
/// du cube
/// ************************************************
procedure TFormMain.MoveStick(TheStick: TPlane; Px, Py, Pz, Rx, Ry, Rz: Single);
begin
  TheStick.ResetRotationAngle; // Remise à zero des angles de rotation  IMPORTANT
  TheStick.Position.X      := Px;
  TheStick.Position.Y      := Py;
  TheStick.Position.Z      := Pz;
  TheStick.RotationAngle.X := Rx;
  TheStick.RotationAngle.Y := Ry;
  TheStick.RotationAngle.Z := Rz;
end;

/// **********************************************
/// Pour le plan Z ( Rouge et Orange)
/// En fonction du dernier sens de rotation
/// replace les sticks sur la bonne facette
/// **********************************************
procedure TFormMain.TurnZPlan(TheCube: TCube);
var
  I: Integer;
begin
  for I := 0 to TheCube.ChildrenCount - 1 do
  begin
    if LastDirection = 90 then // sens des aiguilles
    begin
      if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
        MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
        MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0) // Up
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
        MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0); // Down

    end
    else
    begin
      if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
        MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0) // Down
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
        MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
        MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0); // Up
    end;
  end;
end;

/// / **********************************************
/// Idem, pour le plan X ( Bleu et vert)
/// / **********************************************
procedure TFormMain.TurnXPlan(TheCube: TCube);
var
  I: Integer;
begin
  for I := 0 to TheCube.ChildrenCount - 1 do
  begin
    if LastDirection = 90 then // sens INVERSE des aiguilles
    begin
      if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0) // Front
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
        MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0) // Up
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0) // Back
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0); // Down
    end
    else
    begin
      if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoTop then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0) // Back
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 1.51, 0, 90, 0, 0) // Down
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBottom then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0) // Front
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
        MoveStick((TheCube.Children[I] AS TPlane), 0, -1.51, 0, -90, 0, 0); // Up
    end;
  end;
end;

/// **********************************************
/// Idem, pour le plan Y ( Blanc et Jaune)
/// **********************************************
procedure TFormMain.TurnYPlan(TheCube: TCube);
var
  I: Integer;
begin
  for I := 0 to TheCube.ChildrenCount - 1 do
  begin
    if LastDirection = 90 then // sens des aiguilles
    begin
      if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
        MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0) // Back
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
        MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0); // Front

    end
    else
    begin
      if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoFront then
        MoveStick((TheCube.Children[I] AS TPlane), 1.51, 0, 0, 0, -90, 0) // Right
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoLeft then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, -1.51, 0, 0, 0) // Front
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoBack then
        MoveStick((TheCube.Children[I] AS TPlane), -1.51, 0, 0, 0, 90, 0) // Left
      else if GetStickPosition((TheCube.Children[I] AS TPlane)) = PoRight then
        MoveStick((TheCube.Children[I] AS TPlane), 0, 0, 1.51, 180, 0, 0); // Back
    end;
  end;
end;

{$REGION 'Jeu à la souris'}

/// **********************************************
/// en cliquant sur un stick on arme la recherche
/// d'un mouvement
/// **********************************************
procedure TFormMain.StickMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single;
  RayPos, RayDir: TVector3D);
begin
  if MvtAuto then
    Exit;
  ClickXR := RayDir.X; // emplacement du clic en X  Radial
  ClickYR := RayDir.Y; // emplacement du clic en Y  Radial
  MvtOn   := True;
end;

/// **********************************************
/// En cliquant sur le fond on arme la rotation
/// du cube
/// **********************************************
procedure TFormMain.Viewport3D2MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  ClickX := X; // emplacement du clic en X
  ClickY := Y; // emplacement du clic en Y
end;

/// **********************************************
/// le deplacement de la souris fait pivoter le cube
/// **********************************************
procedure TFormMain.Viewport3D2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
begin
  IF MvtOn then
    Exit;
  if ssLeft in Shift then // si la souris bouge avec le clic droit enfoncé
  begin
    Direction := DiNone;
    IF (ClickX - X) > 3 then
      Direction := DiLeft;
    IF (X - ClickX) > 3 then
      Direction := DiRight;
    IF (ClickY - Y) > 3 then
      Direction := DiTop;
    IF (Y - ClickY) > 3 then
      Direction := DiBottom;

    if Direction <> DiNone then // une direction a été trouvée
    begin
      ClickX := X;
      ClickY := Y;
      if Direction = DiBottom then
        ArcDialX.Value := ArcDialX.Value - 5;
      if Direction = DiTop then
        ArcDialX.Value := ArcDialX.Value + 5;
      if Direction = DiLeft then
        ArcDialY.Value := ArcDialY.Value - 5;
      if Direction = DiRight then
        ArcDialY.Value := ArcDialY.Value + 5;
      ArcDialXChange(Self);
    end;
  end;
end;

/// **********************************************
/// Desarmement du mouvement
/// **********************************************
procedure TFormMain.Viewport3D2MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  MvtOn := False;
end;

procedure TFormMain.StickCornerMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single;
  RayPos, RayDir: TVector3D);
begin
  MvtOn := False;
end;

procedure TFormMain.StickCornerMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single; RayPos, RayDir: TVector3D);
var
  PosXCube, PosYCube, PosZCube: int64;
begin
  if not MvtOn then
    Exit; // si pas de mouvement d'armé

  if ssLeft in Shift then // si la souris bouge avec le clic droit enfoncé
  begin
    Direction := DiNone;
    IF (ClickXR - RayDir.X) > 0.02 then
      Direction := DiLeft;
    IF (RayDir.X - ClickXR) > 0.02 then
      Direction := DiRight;
    IF (ClickYR - RayDir.Y) > 0.02 then
      Direction := DiTop;
    IF (RayDir.Y - ClickYR) > 0.02 then
      Direction := DiBottom;

    if Direction <> DiNone then // une direction a été trouvée
    begin
      cbFun.ItemIndex := -1;
      // recup de la position XYU du cube sous le stick
      PosXCube := Round(((Sender as TPlane).Parent as TCube).Position.X);
      PosYCube := Round(((Sender as TPlane).Parent as TCube).Position.Y);
      PosZCube := Round(((Sender as TPlane).Parent as TCube).Position.Z);
      // desarment du mouvement et reinitialisation de l'emplacement de la souris
      MvtOn   := False;
      ClickXR := RayDir.X;
      ClickYR := RayDir.Y;
      if (PosZCube = -3) and (SameValue((Sender as TPlane).Position.Z, -1.51, 0.1)) then // Plan Avant Rouge
        RotatePlan(PosXCube, PosYCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'w', 'W', 'Y', 'y', 'B', 'b', 'w',
          'W', 'Y', 'y')
      else if (PosZCube = 3) and (SameValue((Sender as TPlane).Position.Z, 1.51, 0.1)) then // Plan Arriere Orange
        RotatePlan(PosXCube, PosYCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'W', 'w', 'y', 'Y', 'B', 'b', 'W',
          'w', 'y', 'Y')
      else if (PosYCube = -3) and (SameValue((Sender as TPlane).Position.Y, -1.51, 0.1)) then // Plan Haut Blanc
        RotatePlan(PosXCube, PosZCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'R', 'r', 'o', 'O', 'B', 'b', 'R',
          'r', 'o', 'O')
      else if (PosYCube = 3) and (SameValue((Sender as TPlane).Position.Y, 1.51, 0.1)) then // Plan Bas Jaune
        RotatePlan(PosXCube, PosZCube, Direction, DiTop, DiBottom, DiRight, DiLeft, 'g', 'G', 'r', 'R', 'O', 'o', 'B', 'b', 'r',
          'R', 'O', 'o')
      else if (PosXCube = -3) and (SameValue((Sender as TPlane).Position.X, -1.51, 0.1)) then // Plan Gauche Vert
        RotatePlan(PosYCube, PosZCube, Direction, DiRight, DiLeft, DiBottom, DiTop, 'w', 'W', 'r', 'R', 'O', 'o', 'Y', 'y', 'r',
          'R', 'O', 'o')
      else if (PosXCube = 3) and (SameValue((Sender as TPlane).Position.X, 1.51, 0.1)) then // Plan Droit Bleu
        RotatePlan(PosYCube, PosZCube, Direction, DiRight, DiLeft, DiBottom, DiTop, 'w', 'W', 'R', 'r', 'o', 'O', 'Y', 'y', 'R',
          'r', 'o', 'O');
    end;
  end;
end;

procedure TFormMain.RotatePlan(Pos1, Pos2: Single; TheDirection, Di1, Di2, Di3, Di4: TDirection;
                               P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12: AnsiChar);
begin
  if Pos1 = -3 then
  begin
    if (TheDirection = Di1) then
      Rotate(P1);
    if (TheDirection = Di2) then
      Rotate(P2);
    if Pos2 = -3 then
    begin
      if (TheDirection = Di3) then
        Rotate(P3);
      if (TheDirection = Di4) then
        Rotate(P4);
    end
    else
    begin
      if (TheDirection = Di3) then
        Rotate(P5);
      if (TheDirection = Di4) then
        Rotate(P6);
    end;
  end
  else
  begin // coté bas
    if (TheDirection = Di1) then
      Rotate(P7);
    if (TheDirection = Di2) then
      Rotate(P8);
    if Pos2 = -3 then
    begin
      if (TheDirection = Di3) then
        Rotate(P9);
      if (TheDirection = Di4) then
        Rotate(P10);
    end
    else
    begin
      if (TheDirection = Di3) then
        Rotate(P11);
      if (TheDirection = Di4) then
        Rotate(P12);
    end;
  end;
end;

{$ENDREGION}
{$REGION 'Sort the  cube (not solving)'}

procedure TFormMain.BtnStartClick(Sender: TObject);
begin
  if MessageDlg('Restore initial cube?', TMsgDlgType.mtInformation, [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0) = MrNo then
    Exit;
  SortRubik();
  CbRotateX.IsChecked := False;
  CbRotateY.IsChecked := False;
  CbRotateZ.IsChecked := False;
  ArcDialX.Value      := -35;
  ArcDialY.Value      := -45;
  ArcDialZ.Value      := -18;
  cbFun.ItemIndex     := -1;
  ArcDialXChange(Self);
end;

procedure TFormMain.SortRubik();
begin
  SortCubes();
  SortSticks();
end;

procedure TFormMain.SortSticks();
begin
  // face Rouge
  MoveStick( PLCC1R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCC2R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCC4R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCC3R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCA1R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCA2R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCA3R,     0,     0, -1.51,   0,   0, 0);
  MoveStick( PLCA4R,     0,     0, -1.51,   0,   0, 0);
  // Face Bleu
  MoveStick( PLCC2B,  1.51,     0,     0,   0, -90, 0);
  MoveStick( PLCC6B,  1.51,     0,     0,   0, -90, 0);
  MoveStick( PLCC3B,  1.51,     0,     0,   0, -90, 0);
  MoveStick( PLCC7B,  1.51,     0,     0,   0, -90, 0);
  MoveStick( PLCA6B,  1.51,     0,     0,   0, -90, 0);
  MoveStick( PLCA3B,  1.51,     0,     0,   0, -90, 0);
  MoveStick(PLCA11B,  1.51,     0,     0,   0, -90, 0);
  MoveStick( PLCA7B,  1.51,     0,     0,   0, -90, 0);
  // Face Verte
  MoveStick( PLCC5V, -1.51,     0,     0,   0,  90, 0);
  MoveStick( PLCC1V, -1.51,     0,     0,   0,  90, 0);
  MoveStick( PLCC8V, -1.51,     0,     0,   0,  90, 0);
  MoveStick( PLCC4V, -1.51,     0,     0,   0,  90, 0);
  MoveStick( PLCA5V, -1.51,     0,     0,   0,  90, 0);
  MoveStick(PLCA10V, -1.51,     0,     0,   0,  90, 0);
  MoveStick( PLCA8V, -1.51,     0,     0,   0,  90, 0);
  MoveStick( PLCA2V, -1.51,     0,     0,   0,  90, 0);
  // Orange
  MoveStick( PLCC6O,     0,     0,  1.51, 180,   0, 0);
  MoveStick( PLCC5O,     0,     0,  1.51, 180,   0, 0);
  MoveStick( PLCC7O,     0,     0,  1.51, 180,   0, 0);
  MoveStick( PLCC8O,     0,     0,  1.51, 180,   0, 0);
  MoveStick( PLCA9O,     0,     0,  1.51, 180,   0, 0);
  MoveStick(PLCA11O,     0,     0,  1.51, 180,   0, 0);
  MoveStick(PLCA10O,     0,     0,  1.51, 180,   0, 0);
  MoveStick(PLCA12O,     0,     0,  1.51, 180,   0, 0);
  // Face Blanche
  MoveStick( PLCC5W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCC6W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCC1W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCC2W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCA9W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCA5W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCA6W,     0, -1.51,     0, -90,   0, 0);
  MoveStick( PLCA1W,     0, -1.51,     0, -90,   0, 0);
  // Face Jaune
  MoveStick( PLCC4J,     0,  1.51,     0,  90,   0, 0);
  MoveStick( PLCC3J,     0,  1.51,     0,  90,   0, 0);
  MoveStick( PLCC8J,     0,  1.51,     0,  90,   0, 0);
  MoveStick( PLCC7J,     0,  1.51,     0,  90,   0, 0);
  MoveStick( PLCA4J,     0,  1.51,     0,  90,   0, 0);
  MoveStick( PLCA8J,     0,  1.51,     0,  90,   0, 0);
  MoveStick( PLCA7J,     0,  1.51,     0,  90,   0, 0);
  MoveStick(PLCA12J,     0,  1.51,     0,  90,   0, 0);
end;

procedure TFormMain.SortCubes();
begin
  // les cubes coins
  SortCube( CC1, -3, -3, -3);
  SortCube( CC2,  3, -3, -3);
  SortCube( CC3,  3,  3, -3);
  SortCube( CC4, -3,  3, -3);
  SortCube( CC5, -3, -3,  3);
  SortCube( CC6,  3, -3,  3);
  SortCube( CC7,  3,  3,  3);
  SortCube( CC8, -3,  3,  3);
  // les cubes arretes
  SortCube( CA1,  0, -3, -3);
  SortCube( CA2, -3,  0, -3);
  SortCube( CA3,  3,  0, -3);
  SortCube( CA4,  0,  3, -3);
  SortCube( CA5, -3, -3,  0);
  SortCube( CA6,  3, -3,  0);
  SortCube( CA7,  3,  3,  0);
  SortCube( CA8, -3,  3,  0);
  SortCube( CA9,  0, -3,  3);
  SortCube(CA10, -3,  0,  3);
  SortCube(CA11,  3,  0,  3);
  SortCube(CA12,  0,  3,  3);
end;

procedure TFormMain.SortCube(TheCube: TCube; Px, Py, Pz: Single);
begin
  TheCube.ResetRotationAngle;
  TheCube.Position.X := Px;
  TheCube.Position.Y := Py;
  TheCube.Position.Z := Pz;
end;

{$ENDREGION}
{$REGION 'Jouer des mouvements enregistrés'}

procedure TFormMain.cbFunChange(Sender: TObject);
begin
  if cbFun.ItemIndex <> -1 then
  begin
    cbFun.DropDown; // Pour refermer immédiatement la dropdown
    SortRubik();
    PlayMvt(FUN_VALUES[cbFun.ItemIndex]);
  end;
end;

procedure TFormMain.PlayMvt(TheMvts: AnsiString);
var
  I: Integer;
  iMax: Integer;
begin
  // Platform.SetCursor(nil, crHourGlass); // ProcessMessages casse le curseur
  MvtAuto            := True;  // On enchaine une série (l'utilisateur ne peut pas faire de modif manuelle)
  iMax               := Length(TheMvts);
  pbFun.Value        := 1;
  pbFun.Max          := iMax;
  pbFun.Visible      := True;
  recCommand.Enabled := False; // desactiver le panneau de commandes
  for I := 1 to iMax do
  begin
    Rotate(TheMvts[I]);
    pbFun.Value := pbFun.Value + 1;
  end;
  MvtAuto            := False; // La série est terminée, l'utilisateur peut à nouveau jouer
  pbFun.Visible      := False;
  recCommand.Enabled := True;  // le panneau de commande redevient actif
end;

{$ENDREGION}
{$REGION 'Ouverture de la page Web'}

procedure TFormMain.LbInfoLinkClick(Sender: TObject);
begin
  TMisc.Open((Sender as TLabel).Text);
end;
{$ENDREGION}
{$REGION 'Rotation automatique du cube'}

/// *************************************************
/// Déplacement de la caméra autour du rubik's cube
/// *************************************************
Procedure TFormMain.ArcDialXChange(Sender: TObject);
begin
  Dummy.RotationAngle.X := ArcDialX.Value;
  Dummy.RotationAngle.Y := ArcDialY.Value;
  Dummy.RotationAngle.Z := ArcDialZ.Value;
end;

Procedure TFormMain.CbRotateXChange(Sender: TObject);
begin
  FaAutoRotateX.Stop;
  if CbRotateX.IsChecked then
    FaAutoRotateX.Start;
end;

Procedure TFormMain.CbRotateYChange(Sender: TObject);
begin
  FaAutoRotateY.Stop;
  if CbRotateY.IsChecked then
    FaAutoRotateY.Start;
end;

Procedure TFormMain.CbRotateZChange(Sender: TObject);
begin
  FaAutoRotateZ.Stop;
  if CbRotateZ.IsChecked then
    FaAutoRotateZ.Start;
end;
{$ENDREGION}
{$REGION 'Les lumières'}

procedure TFormMain.RbAmbianceChange(Sender: TObject);
Var
  I: Integer;
  Color: TAlphaColor;
begin
  MainLight.Enabled := RbSpotLight.IsChecked;
  BwTbLight.Enabled := RbSpotLight.IsChecked;

  if RbSpotLight.IsChecked then
  begin
    Color := claNull;
    SetLight;
  end
  else
    Color := claWhite;
  for I := 0 to FormMain.ComponentCount - 1 do
  begin
    // les stickers
    if (FormMain.Components[I] Is TPlane) then
      (FormMain.Components[I] As TPlane).material.Emissive := Color;
    // Les cubes pivots
    if (FormMain.Components[I] Is TCube) then
      if (FormMain.Components[I] As TCube).Tag = 1 then
        (FormMain.Components[I] As TCube).material.Emissive := Color;
  end;
end;

procedure TFormMain.SetLight;
var
  cLight: TAlphaColorRec;
begin
  cLight.R := Round(255 * BwTbLight.Value);
  cLight.G := Round(255 * BwTbLight.Value);
  cLight.B := Round(255 * BwTbLight.Value);
  MainLight.Diffuse := cLight.Color;
  Viewport3D2.Repaint;
end;

procedure TFormMain.BwTbLightChange(Sender: TObject);
begin
  SetLight;
end;

{$ENDREGION}

end.

 Conclusion

A/ Caméra et Dummy

Premier point important. Il existe 2 façons de voir un objet sous tous ses angles.
Soit faire pivoter l'objet (rotationAngle)
Soit pivoter autour de l'objet en continuant à le fixer (camera et Dummy)

Le premier cas convient tres bien avec un seul objet. Seuls les rotationAngle XYZ varient.
Dans tous les autres cas utilisez la seconde méthode. Ainsi les coordonnées X,Y et Z des objets resteront
bien mieux maitrisables.

B/ Notions diverses

Le rubik est composé  :
-D'un cube central (TCube) celui qui est invisible.
-De 6 cubes Pivots (TCube) sitée au centre,avec un rendu Bitmap pour la couleur
-6 Composants anitmations (TFloatAnimation) , un par pivot. Ils sont enfant des Pivots et mémorisent l'axe de rotation du pivot.
-8 Cubes coins (TCube) Noir avec 3 facettes(TPlane) chacuns. Nommé Stickers dans le source et les commentaires.
-12 cubes Arretes  (TCube) Noir avec 2 facettes(TPlane) chacuns. Nommé Stickers dans le source et les commentaires.  


C.1  Une fiche dispose de composants accèssibles depuis toujours avec ComponentCount et Components[]. Les objets 3D
eux gerent des enfants accessibles avec ChildrenCount et Children[]. Pensez y !

C.2 Rotation des enfants
La rotation d'un parent declenche la rotation de ses enfants autour du même axe (principe utilisé dans le prog).
A l'issue de la rotation, les enfants ont gardé les mêmes  positions X,Y,Z et rotationAngle puisque directement
lié a leur parent. Bien retenir que les positions X,Y,Z et rotationAngle sont donc relatif au parent.
Seules les positions Absolues Varient.

C.3 Changement de parent
Pour effectuer une rotation le programme recherche les cubes coins et cubes arrêtes situés sur le même plan que
le cube central devant pivoter et en fait ses enfants, Puis s'effectue la rotation. Enfin, les cubes enfants
sont rendu au cube central.

Problème, le changement de parent replace l'enfant avec le même décalage et la même rotation qu'il avait avec son ex parent(4.2).
les rotationsAngles et le repositionnement relatif au cube centrale doivent être refait (c'est a vous de le gerer)

C.4 Animation en Thread
Les animations sont threadées, il faut donc attendre la fin d'une rotation pour en lancer une autre


C.6 Pour finir

C.6 Pour finir

les cubes coins sont sensibles au clic souris pour les rotations de face. Un tirer-lâcher sur la zone
grise permet une rotation de tout le cube.

La partie 'Fun' exécute des figures pré-enregistrées.

Modifiez la taille de la fenêtre, changez l'éclairage, changez les animations, vitesse, jouez les auto-rotations
et vous verrez la puissance de l'outil Firemonkey


Merci à Whiler pour son Aide.
Pour ceux qui veulent tester l'exe
ftp://ftp2.p2f-logiciels.com/pflogicie/SetupRubik. exe

Pascal Fonteneau Alias Fireman





 Fichier Zip

Les Membres Club peuvent télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip


 Historique

19 avril 2012 11:38:07 :
ajout image et zip
23 avril 2012 06:35:32 :
Améliorations : Gestion des lumières Hints personnalisés actifs Simplification des sources Interfaces et noms de variables,procedures en anglais Rotations automatique du cube. Correction de bug mineurs Pour ceux qui veulent tester l'exe ftp://ftp2.p2f-logiciels.com/pflogicie/SetupRubik.exe

 Sources du même auteur

Source avec Zip Source avec une capture JEU WINBRIQUE
Source avec Zip Source avec une capture COMPOSANT CODE BARRE 39
Source avec Zip Source avec une capture SOURCES D'UN JEU DE TAQUIN OU POUSSE-POUSSE
ECRAN CACHÉ DANS DELPHI 7
Source avec Zip CRÉER UNE FICHIER D'AIDE (CHM ) ET L'APPELER DEPUIS DELPHI

 Sources de la même categorie

Source avec Zip Source avec une capture BILLARD FLIPPER par Toidil
Source avec Zip Source avec une capture PETIT JEU POUR NOËL KASTET par dubois77
Source avec Zip AWÉLÉ JEU DE STRATÉGIE AFRICAIN par Toidil
Source avec Zip Source avec une capture JEUX D' OTHELLO par fredbluefish
Source avec Zip BATAILLE NAVALE CONTRE ORDINATEUR par Toidil

 Sources en rapport avec celle ci

Source avec Zip Source avec une capture FIREMONKEY : PATHDATA ET FORMAT SVG par Christophe67
Source avec Zip Source avec une capture FIREMONKEY : ROTATION CUBE par Christophe67
Source avec Zip Source avec une capture EXEMPLE D'UTILISATION FIREMONKEY par Neftali
Source avec Zip Source avec une capture FIREMONKEY : HELLO WORLD ! par Christophe67
Source avec Zip Source avec une capture MOTEUR PHYSIQUE 2D CHIPMUNK.. EN DELPHI! par Bacterius

Commentaires et avis

Commentaire de tlaborde le 21/04/2012 11:13:25

Plus de 500 Vues et plus de 30 téléchargements et aucuns commentaires, je trouve ça dommage.
Donc moi j'en profite pour dire un grand merci à Pascal pour son travail et surtout pour le partager avec tout le monde.

Merci encore.

Thierry.

Commentaire de cirec le 21/04/2012 11:45:14 administrateur CS

Salut Thierry,

oui c'est dommage mais encore faut il posséder Delphi XE2 pour pouvoir compiler et apprécier ce code ...
ce qui explique les, bientôt, 600 vues et 36 téléchargements ... et encore sur les 36 il doit bien en avoir une pelleté qui l'a téléchargé pensant pouvoir le compiler avec sa bonne vielle version :D

Avec les versions précédentes on pouvait "bricoler" le code pour l'adapter à un compilateur plus ancien ... d'ailleurs beaucoup d'entre nous faisaient l'effort de "portabilité" dans les codes déposés  ... ce qui est devenu impossible avec cette dernière version de Delphi.

Commentaire de aliilyas le 21/04/2012 13:20:00

Merci

Commentaire de Fireman le 21/04/2012 13:30:17

Un update est en cours, avec QQ options permettant de mettre encore plus l'outil en valeur.
Un lien vers l'exe sera églament proposé pour la version PC et MAC, puisque que le test d'execution sur Mac a été réalisé avec succès par ketufe.

Pascala
Alias Fireman

Commentaire de ketufe le 22/04/2012 15:17:32

Salut je n'ai pas mit de commentaire mais c'est très bien et merci

ça fonctionne très bien sous win et mac ;)

Commentaire de Fireman le 22/04/2012 16:35:11

Bonjour a tous
Un Update est en cours.

Commentaire de Fireman le 22/04/2012 16:37:30

(suite du messsage)
diffusion prevue cette semaine.

Bon week end à tous

Commentaire de dodfr le 23/04/2012 08:00:47

La remarque de @tlaborde est en effet exacte, peu de personnes ont XE2 et peuvent tester ce code.

Commentaire de Fireman le 23/04/2012 08:36:39

La mise à jour est en ligne.

Pour ceux qui n'ont pas Delphi XE2. Vous pouvez charger l'exe pour PC Windows,ici ftp://ftp2.p2f-logiciels.com/pflogicie/SetupRubik.exe




Commentaire de ketufe le 23/04/2012 11:21:37

Salut je peux compiler pour MAC pour ceux qui n'ont pas de PC ???

Commentaire de Whiler le 23/04/2012 11:53:42

Salut Fireman,

La version OS X compilée : http://www.whiler.com/delphi/rubikcube.zip
(Tu peux la télécharger et l'ajouter à ton FTP si tu veux...)

++

  W.

Commentaire de Palomar le 23/04/2012 15:28:50

Alors là, chapeau!
Joli travail...
Excellent exemple pour moi qui commence à peine à découvrir Firemonkey.
Merci!

Commentaire de Fireman le 24/04/2012 16:21:10

Pour finir,un article et une petite video sur Youtube

http://blogs.wittwer.fr/whiler/2012/04/24/rubiks-cube/

http://youtu.be/M8lvwOwYCBY

Merci à toi Whiler

Commentaire de Whiler le 24/04/2012 16:24:08

Merci à toi pour ton code et la réf ;o)

Commentaire de MozarellaTd le 25/04/2012 11:42:18

Quel boulot. :o
Très bien fait, avec mon niveau de débutant je suis impressionné !
Merci à toi pour ton travail, mais si je peux me permettre malgré tout un commentaire :

On ne peut pas tourner les bandes centrales, c'est dommage (obligé de tourner les 2 adjacentes pour obtenir ce résultat).

(Mais vu ton code, ou tu te sert d'une face coloré comme face de référencement, c'est normal, je sais ^^)

Sinon bah, un grand bravo, et merci, et pour ceux que ça intéresse : http://www.francocube.com/cyril/rubik_index.php
:)

Commentaire de dodfr le 25/04/2012 11:59:33

La chose que l'on regrettera (pas de la faute de l'auteur) c'est 10Mo pour juste pour ça (firemonkey est une grosse librairie) et quasiment 70% de CPU sur un Dual-Core 2.4Ghz pour faire tourner un simple cube (on croirait du flash).

Commentaire de laoubiadel le 27/04/2012 13:37:18

merci

Commentaire de dodfr le 27/04/2012 13:44:44

Je ne vois pas mon dernier commentaire donc je re-poste.

Je trouve tout de même dommage (ce n'est pas le faute de l'auteur) que cette simple appli fasse 10Mo (la faute à l'énorme librairie FireMonkey) et pompe 70% du CPU Dual-Core 2.4Ghz pour animer une forme aussi simple.

Commentaire de dodfr le 27/04/2012 14:33:29

Oups désolé pour le double post, je revois le commentaire (bizarre il n'y étais plus tout à l'heure, peut-être un problème de cache).

 Ajouter un commentaire


Discussions en rapport avec ce code source dans le forum

DELPHI et 3D [ par sebrs1 ] Qu'est-ce que vous me conseillez pour faire de la 3D en delphi, parce que entre delphiX qui est pas compatible avec delphi6, glscene où il n'y a aucun JE CHERCHE UN MOTEUR 3D POUR DELPHI! [ par nono009 ] Voilà je recherche un moteur 3d pour delphi (gratuit si possible)Opengl ou directXMerci d'avancea+ creer un moteur de jeu 3D [ par ewertheimer ] Bonjour,J'aimerais creerb un jeu en 3D sous delphi. Je mis connait pas mal en delphi mais j'aimerais juste savoir &#224; quoi sert &#224; creer un mot Animations 3D [ par Katespower ] Bonjour à tous !!Je développe en ce moment avec des amis un jeu en 3D sous Delphi à l'aide e DirectX. Nous avons réussi à créer ma base de notre jeu e delphi modélisation 3D [ par gamellemaleh ] Slt! Je bosse sur un projet de scanner d'empreinte dentaire et notamment sur la mod&#233;lisation de l'empreinte &#224; partir d'une liste de points. fichier 3ds de GLscene [ par ahlemBH ] salut tous l monde, je suis débutante en Delphi, et je suis entrain de faire un petit projet sur le traitement des images médicales. j'ai un problème Version XE2 [ par jderf ] Bonjour, Je voudrai avoir la confirmation sur les capacitées de connexion aux SGBD en fonction des versions. - Delphi XE2 starter (199¤) Une connec Installation XE2 Delphi [ par sky1414 ] Bonjour, Sur PC W7Pro formater il y a 2 jour et MAJ , j'obtiens le message suivant à la compilation d'un projet vierge [DCC Erreur] Compilateur pour l A propos de FireMonkey 3D [ par dan479 ] Bonjour à tous, Je viens juste de migrer de Delphi 7 vers XE2 Starter. C'est le jour et la nuit ! Firemonkey n'étant pas encore documenté, je ne peux gestion de base de donnees avec delphi XE2 [ par mlamXE2 ] bonjour, Est ce que qqn pourrait me donner une idée pour démarrer avec une application en delphi xe2 qui gère des base de données. j'ai lu les aides


Nos sponsors


Sondage...

Comparez les prix

CalendriCode

Mai 2013
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Photothèque

A découvrir



 
Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils.
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés

Google Coop CodeS-SourceS Google Coop CodeS-SourceS
Temps d'éxécution de la page : 0,920 sec (4)

Nous contacter | Annoncer sur CodeS-SourceS | Mentions légales