Comme mon fils adore les puzzles en ligne, j'ai eu envie de lui bricoler ça cette semaine. Le but étant :
- être fier d'avoir fabriquer un jeu pour lui (c'est quand même sympa de fabriquer soit-même des jeux ou jouets )
- qu'il puisse utiliser des photos comme image de puzzle
Donc, voilà son petit puzzle, qui n'est pas encore abouti..?. mais l'essentiel est là
► Afficher le texte
Code : Tout sélectionner
#include <Array.au3>
#include <Constants.au3>
#include <GDIPlus.au3>
#include <GUIConstants.au3>
#include <Misc.au3>
#include <StaticConstants.au3>
#include <WinAPI.au3>
#include <WindowsConstants.au3>
; Variables -------------------------------------------------------------------------------------
; Récupération de la taille du bureau (mieux que @DesktopWidth/Heigth pour du multi-écran)
Local $desktopInfo = WinGetPos("[TITLE:Program Manager; CLASS:Progman]")
Local $desktopX = $desktopInfo[0]
Local $desktopY = $desktopInfo[1]
Local $desktopW = $desktopInfo[2]
Local $desktopH = $desktopInfo[3]
; --
Global $pics[16][4] ; Nombre de pièces du puzzle (attention, si on modifie cette valeur, il faudra modifier les dimensions ($ctrlW et $ctrlH)
Global $ctrlW = 200, $ctrlH = 150 ; Taille des pièces
Global $guiW = 800, $guiH = 600 ; Taille du puzzle
Global $path = @ScriptDir & "\miniatures" ; Emplacement des pièces crées
Global $tStruct = DllStructCreate($tagPOINT)
Global $gui, $ombreV, $ombreH, $title = "Mon Puzzle", $img, $mainGui, $exit, $guiOK[4]
Global $hDLL = DllOpen("user32.dll")
Global $puzzleAreaX = ($desktopW - $guiW) / 2, $puzzleAreaY = ($desktopH - $guiH) / 2
; Configuration ---------------------------------------------------------------------------------
Global $activeOnHover = True ; Affiche au premier plan la pièce survolée
Global $autoPlacement = True ; Placer automatiquement la pièce lorsqu'elle est à quelques pixels de son emplacement ($autoPlacementSensor)
Global $playSound = True ; Jouer un son lorsque le puzzle est terminée
Global $showRedBorder = True ; Encadre la pièce si elle est bien placée (pendant 1/2 seconde)
Global $showShadow = True ; Afficher l'ombre de la pièce sélectionnée
Global $showTemplate = True ; Afficher l'image en filigrane
Global $autoPlacementSensor = 20 ; Distance en pixel : si la pièce se situe à -X ou +X pixel de l'emplacement, elle est placé directement
Global $backgroundColor = 0x003366 ; Couleur de fond du puzzle
Global $onMouseBrightness = 200 ; Transparence de la pièce sélectionnée
Global $shadowColor = 0x000011 ; Couleur de l'ombre
Global $shadowBrightness = 190 ; Transparence de l'ombre
Global $shadowDistance = 25 ; Distance de l'ombre
Global $sound = "sound.wav" ; Son a jouer lorsque le puzzle est terminée
; -----------------------------------------------------------------------------------------------
; Choix de l'image
$img = FileOpenDialog ( "Choisissez une image", @ScriptDir, "Images (*.jpg)" )
If $img = "" Then Exit
; Création des pièces du puzzle
_cut($img , $path, $ctrlW, $ctrlH)
; Création de la fenêtre principale
_mainGui()
; Affichage des pièces
; Chaque pièce est fait partie d'une fenêtre distincte afin de pouvoir gérer la position de type Z-Index
For $i = 0 To 15
$randomX = Random(0, $desktopW - $ctrlW , 1)
$randomY = Random(0, $desktopH - $ctrlH , 1)
$pics[$i][0] = GUICreate("", $ctrlW, $ctrlH, $randomX, $randomY, $WS_POPUP, $WS_EX_MDICHILD, $mainGui )
GUICtrlCreatePic($path & "\" & $i & ".jpg" , 0, 0, $ctrlW , $ctrlH)
GUICtrlSetCursor(-1, 0)
GUISetstate(@SW_SHOW, $pics[$i][0])
Next
While 1
$msg = GUIGetMsg()
If $msg = $GUI_EVENT_CLOSE OR $msg = $exit Then
ExitLoop
EndIf
If _IsPressed("01", $hDLL) Then _Drag()
; Quand on survol une pièce avec la souris, la pièce passe au premier plan
If $activeOnHover Then _WinActivationHoverWindow()
WEnd
Func _mainGui()
; Fenêtre principale--------------------------------------------------------------------
$mainGui = GUICreate($title, $desktopW, $desktopH , $desktopX, $desktopY, $WS_POPUP)
GUISetBkColor($backgroundColor)
; On affiche l'image en filigrane
If $showTemplate Then GUICtrlCreatePic(@ScriptDir & "\miniatures\background.jpg", $puzzleAreaX, $puzzleAreaY, $guiW, $guiH)
GUISetState(@SW_SHOW, $mainGui)
GUISetState(@SW_DISABLE, $mainGui)
; Fenêtre enfant : la zone du puzzle---------------------------------------------------
$fond = GUICreate("Fond", $guiW, $guiH, $puzzleAreaX, $puzzleAreaY, $WS_POPUP, $WS_EX_MDICHILD, $mainGui )
GUISetBkColor(0xFFFFFF, $fond)
GUISetState(@SW_SHOW, $fond)
GUISetState(@SW_DISABLE, $fond)
WinSetTrans($fond, "", 80)
; Fenêtres enfant : ombre de chaque pièce----------------------------------------------
; L'ombre est créé avec 2 fenêtres translucides
$ombreV = GUICreate("", $shadowDistance, $ctrlH, $ctrlW - $shadowDistance, 0, $WS_POPUP, -1, $mainGui)
$ombreH = GUICreate("", $ctrlW - $shadowDistance, $shadowDistance, 0, $ctrlH - $shadowDistance, $WS_POPUP, -1, $mainGui)
GUISetBkColor($shadowColor, $ombreV)
GUISetBkColor($shadowColor, $ombreH)
GUISetstate(@SW_HIDE, $ombreV)
GUISetstate(@SW_HIDE, $ombreH)
WinSetTrans($ombreV, "", $shadowBrightness)
WinSetTrans($ombreH, "", $shadowBrightness)
; Menu (pour l'instant, uniquement le bouton Quitter)
$menu = GUICreate("Menu", 100, 40, $desktopW - 100 - 10, 10, $WS_POPUP, $WS_EX_MDICHILD, $mainGui )
GUISetBkColor(0x000000, $menu)
$exit = GUICtrlCreateButton("Quitter", 10, 10, 80, 20)
GUISetState(@SW_SHOW, $menu)
; Fenêtre enfant : rectangle qui appparait quand la pièce est bien placée
$guiOK[0] = GUICreate("", $ctrlW, 2, 0, 0, $WS_POPUP, $WS_EX_MDICHILD, $mainGui)
$guiOK[1] = GUICreate("", 2, $ctrlH, $ctrlW - 2, 0, $WS_POPUP, $WS_EX_MDICHILD, $mainGui)
$guiOK[2] = GUICreate("", 2, $ctrlH, 0, 0, $WS_POPUP, $WS_EX_MDICHILD, $mainGui)
$guiOK[3] = GUICreate("", $ctrlW, 2, 0, $ctrlH - 2, $WS_POPUP, $WS_EX_MDICHILD, $mainGui)
For $i = 0 To UBound($guiOK) - 1
GUISetBkColor(0xFF0000, $guiOK[$i])
Next
EndFunc
Func _Drag()
Local $hWnd = WinGetHandle("[Active]") ; Fenêtre active
Local $inApp = False
For $i = 0 To UBound($pics, 1) - 1
If $hWnd = $pics[$i][0] Then
$inApp = True ; Si la fenêtre active est une pièce, on peut la déplacer
ExitLoop
EndIf
Next
If NOT $inApp Then Return 0
If $hWnd <> _WinAPI_GetAncestor(_WinAPI_WindowFromPoint($tStruct), $GA_ROOT) Then Return 0
$objPos = WinGetPos($hWnd)
WinSetTrans($hWnd, "", $onMouseBrightness)
$mPos = MouseGetPos()
; On calcule la position de la souris dans la pièce active
$diffX = $mPos[0] - $objPos[0]
$diffY = $mPos[1] - $objPos[1]
If $showShadow Then
; On affiche et place l'ombre à côté de la pièce
; On utilse _WinAPI_SetWindowPos pour placer la fenêtre en coordonnées Z (z-index)
GUISetState(@SW_SHOW, $ombreV)
GUISetState(@SW_SHOW, $ombreH)
_WinAPI_SetWindowPos($ombreV, $HWND_TOP, $objPos[0] + $ctrlW, $objPos[1] + $shadowDistance, $shadowDistance, $ctrlH, $SWP_NOACTIVATE)
_WinAPI_SetWindowPos($ombreH, $HWND_TOP, $objPos[0] + $shadowDistance, $objPos[1] + $ctrlH, $ctrlW - $shadowDistance, $shadowDistance, $SWP_NOACTIVATE)
EndIf
; Et là on déplace la pièce en suivant la souris
While _IsPressed("01", $hDLL)
$mPos = MouseGetPos()
$posX = $mPos[0] - $diffX
$posY = $mPos[1] - $diffY
_WinAPI_SetWindowPos($hWnd, $HWND_TOP, $posX, $posY, $ctrlW, $ctrlH, $SWP_NOACTIVATE)
_WinAPI_SetWindowPos($ombreV, $HWND_TOP, $posX + $ctrlW, $posY + $shadowDistance, $shadowDistance, $ctrlH, $SWP_NOACTIVATE)
_WinAPI_SetWindowPos($ombreH, $HWND_TOP, $posX + $shadowDistance, $posY + $ctrlH, $ctrlW - $shadowDistance, $shadowDistance, $SWP_NOACTIVATE)
WEnd
GUISetState(@SW_HIDE, $ombreV)
GUISetState(@SW_HIDE, $ombreH)
WinSetTrans($hWnd, "", 255)
$picPos = WinGetPos($hWnd)
$picPosX = $picPos[0] - $puzzleAreaX
$picPosY = $picPos[1] - $puzzleAreaY
; Place la pièce au bon endroit si elle est déposée à quelques pixels près
If $autoPlacement Then
If $picPosX > ($pics[$i][1] - $autoPlacementSensor) AND $picPosX < ($pics[$i][1] + $autoPlacementSensor) AND $picPosY > ($pics[$i][2] - $autoPlacementSensor) AND $picPosY < ($pics[$i][2] + $autoPlacementSensor) Then
WinMove($hWnd, "", $pics[$i][1] + $puzzleAreaX, $pics[$i][2] + $puzzleAreaY )
$picPosX = $pics[$i][1]
$picPosY = $pics[$i][2]
EndIf
EndIf
; Si la pièce est au bon endroit ...
If $picPosX = $pics[$i][1] AND $picPosY = $pics[$i][2] Then
$pics[$i][3] = True
; On affiche le cadre rouge si $showRedBorder = True
If $showRedBorder Then
For $j = 0 To UBound($guiOK) - 1
GUISetState(@SW_SHOW, $guiOK[$j])
Next
_WinAPI_SetWindowPos($guiOK[0], $HWND_TOP, $pics[$i][1] + $puzzleAreaX, $pics[$i][2] + $puzzleAreaY, $ctrlW, 2, $SWP_NOACTIVATE)
_WinAPI_SetWindowPos($guiOK[1], $HWND_TOP, $pics[$i][1] + $puzzleAreaX + $ctrlW - 2, $pics[$i][2] + $puzzleAreaY, 2, $ctrlH, $SWP_NOACTIVATE)
_WinAPI_SetWindowPos($guiOK[2], $HWND_TOP, $pics[$i][1] + $puzzleAreaX, $pics[$i][2] + $puzzleAreaY, 2, $ctrlH, $SWP_NOACTIVATE)
_WinAPI_SetWindowPos($guiOK[3], $HWND_TOP, $pics[$i][1] + $puzzleAreaX, $pics[$i][2] + $puzzleAreaY + $ctrlH - 2 , $ctrlW, 2, $SWP_NOACTIVATE)
Sleep(500)
For $j = 0 To UBound($guiOK) - 1
GUISetState(@SW_HIDE, $guiOK[$j])
Next
EndIf
Else
$pics[$i][3] = False
EndIf
; On compte combien de pièce sont bien placée
$good = 0
For $i = 0 To UBound($pics, 1) - 1
If $pics[$i][3] = True Then $good += 1
Next
; Si toutes les pièces sont bien positionnées, la partie est finie
If $good = UBound($pics, 1) Then
If $playSound Then
If FileExists($sound) Then SoundPlay($sound, 0)
EndIf
MsgBox(0, $title, "Bravo !")
Exit
EndIf
EndFunc
Func _WinActivationHoverWindow()
Position()
$hWnd = _WinAPI_GetAncestor(_WinAPI_WindowFromPoint($tStruct), $GA_ROOT) ; Handle de la fenêtre survolée
For $i = 0 To UBound($pics, 1) - 1
If $hWnd = $pics[$i][0] Then
; Si la fenêtre survolée est une pièce, on l'affiche au premier plan (sauf si elle l'est déjà)
If WinGetHandle("[Active]") <> $hWnd Then WinActivate( $pics[$i][0] )
EndIf
Next
EndFunc ;===>_WinActivationHoverWindow
; Découpage de l'image
Func _cut($sImage, $sPath, $iW, $iH)
Local $hClone, $hImage, $imgW, $imgH
If NOT FileExists($sPath) Then
If NOT DirCreate($sPath) Then Return 0
EndIf
_GDIPlus_Startup()
$hImage = _GDIPlus_ImageLoadFromFile($sImage)
$imgW = _GDIPlus_ImageGetWidth($hImage)
$imgH = _GDIPlus_ImageGetHeight($hImage)
; Test si l'image est au format 4/3
If ($imgH / $imgW ) <> (3 / 4) Then
MsgBox(16, "Erreur", "Les dimensions de cette image ne sont pas compatibles (uniquement images au format 4/3)")
Exit
EndIf
; On redimmensionne en 800x600
_imageResize($sImage, $sPath & "\background.jpg", 800, 600)
$hImage = _GDIPlus_ImageLoadFromFile($sPath & "\background.jpg")
$i = 0
For $y = 0 To $guiH - $ctrlH Step $ctrlH
For $x = 0 To $guiW - $ctrlW Step $ctrlW
; On crée les petites images de gauche à droite et de bas en haut
$hClone = _GDIPlus_BitmapCloneArea($hImage, $x, $y, $ctrlW, $ctrlH, $GDIP_PXF24RGB)
_GDIPlus_ImageSaveToFile($hClone, $sPath & "\" & $i & ".jpg")
$pics[$i][1] = $x
$pics[$i][2] = $y
$i += 1
Next
Next
_GDIPlus_ImageDispose($hClone)
_GDIPlus_ImageDispose($hImage)
_GDIPlus_Shutdown()
EndFunc
; récupéré sur le forum : merci Matwachich
Func _imageResize($oldImage, $newImage, $newW, $newH)
Local $img, $gContext, $newBmp, $gNewContext, $closeGDI = False
If $ghGDIPDll = 0 Then
_GDIPlus_Startup()
$closeGDI = True
EndIf
$img = _GDIPlus_ImageLoadFromFile($oldImage)
$gContext = _GDIPlus_ImageGetGraphicsContext($img)
$newBmp = _GDIPlus_BitmapCreateFromGraphics($newW, $newH, $gContext)
$gNewContext = _GDIPlus_ImageGetGraphicsContext($newBmp)
_GDIPlus_GraphicsDrawImageRect($gNewContext, $img, 0, 0, $newW, $newH)
_GDIPlus_ImageSaveToFile($newBmp, $newImage)
_GDIPlus_ImageDispose($img)
_GDIPlus_GraphicsDispose($gContext)
_GDIPlus_GraphicsDispose($gNewContext)
_GDIPlus_BitmapDispose($newBmp)
If Not FileExists($newImage) Then Return 0
Return SetError(0, FileGetSize($newImage), 1)
If $closeGDI Then _GDIPlus_Shutdown()
EndFunc ;==>_imageResize
Func Position()
DllStructSetData($tStruct, "x", MouseGetPos(0))
DllStructSetData($tStruct, "y", MouseGetPos(1))
EndFunc ;==>Position
- Dire bravo quand le puzzle est terminée
- Placer automatiquement les pièces quand elles sont à quelques pixels près