Jeu du Taquin en jQuery sur vos sites !
Vous connaissez probablement ce jeu ou l'on mélange une image composée de 4 fois 4 carrés dans le seul but de la remettre en ordre une fois celle-ci mélangée. Il peut s'agir de la reconstituer de mémoire ou à partir d'un modèle. Ce jeu c'est le Taquin et je vous le propose sous la forme d'un plugin jQuery pour votre site.
Démonstration du plugin
En jouant avec les paramètres ci-dessous vous pourrez construire le Taquin qui vous intéresse. Vous n'aurez plus qu'à l'inclure dans votre site. Bien entendu, pour les développeurs, le détail du plugin est fait plus loin dans cet article.
Paramètres
Aperçu
Cliquer sur l'image ci-dessous pour voir le résultat après mélange.
Installation
Si vous n'êtes pas un expert en JavaScript, vous pouvez paramétrer le jeu ci-dessus (dans "Aperçu") avec les éléments dans "Paramètres" et inclure les codes ci-dessous dans votre site.
- Il faut auparavant avoir inclus le script jQuery dans sa page.
- Le chemin du plugin est celui où vous avez placé le script sur votre site.
Téléchargement
Vous trouverez ce code à http://www.haeresis.fr/framework/jquery/plugin/jquery.game-taquin.js
sinon
Copiez-collez le code ci-dessus dans un fichier appelé par exemple jquery.game-taquin.js :
//////////////////////////////////////////// // Jeu du Taquin en jQuery sur vos sites. // ////////////////////////////////////////////// // Auteur : Bruno Lesieur - www.haeresis.fr // ////////////////////////////////////////////// (function ($) { "use strict"; // ==Description== // Pour chaque élément 'fn' : // Créé un nouvel élément juste après l'image cible composée de <div> en absolute. // Un clique permet de mélanger le jeu. // La résolution du tableau remet les éléments aux états initiaux. // ==image== // Ceci réprésente l'adresse de l'image qui sera fractionnée pour être jouée. // ==params== // width : Indique la taille que fait l'image en largeur. Si rien ou zéro est précisé, la taille par défaut est celle de l'image. // height : Indique la taille que fait l'image en hauteur. Si rien ou zéro est précisé, la taille par défaut est celle de l'image. // division : Indique le nombre de carré en largeur/hauteur qui compose le taquin. // hidePart : Indique quelle partie du carré est masquée pour faire office de trou pour les déplacements. Les valeurs possibles sont Haut Gauche "tl", Haut droite "tr", Bas gauche "bl", Bas droite "br" (par défaut). // mixing : Indique le nombre de déplacement fait aléatoirement pour simuler un mélange à la main du taquin. // success : Si écrasé par une fonction, exécute cette fonction en cas de complétion du taquin. Sinon, renvoi sous chaine de caractère le message passé dans un "alert()". $.fn.gameTaquin = function (image, params, success) { // Paramètres initiaux écrasés s'ils sont passés en paramètres d'entrées. params = $.extend({ width: 0, height: 0, division: 4, hidePart: "br", mixing: 200, success: "Complete" }, params); // Si la division est inférieur à 2, la valeur est 2. if (params.division < 2) { params.division = 2; } // Fonction éxécutée par défaut en cas de succès. if (!$.isFunction(params.success)) { var temp = params.success; params.success = function () { alert(temp); }; } /***********************************************/ /** Initialisation des variables et fonctions **/ /***********************************************/ var clickFunction, gameStart, gameState, squareWidth = 0, squareHeight = 0; // Créer les états de jeu. function initialiseGameVar(gameDivision) { var game = [], gameRow, gameDiv, xi = 0, yi = 0, currentDisplay; for (xi = 0; xi < gameDivision; xi += 1) { gameRow = []; for (yi = 0; yi < gameDivision; yi += 1) { gameDiv = []; currentDisplay = true; if ((xi === 0) && (yi === 0) && (params.hidePart === "tl")) { currentDisplay = false; } if ((xi === (gameDivision - 1)) && (yi === 0) && (params.hidePart === "tr")) { currentDisplay = false; } if ((xi === 0) && (yi === (gameDivision - 1)) && (params.hidePart === "bl")) { currentDisplay = false; } if ((xi === (gameDivision - 1)) && (yi === (gameDivision - 1)) && (params.hidePart === "br")) { currentDisplay = false; } gameDiv[0] = currentDisplay; gameDiv[1] = "taquin-" + xi + "-" + yi; gameRow[yi] = gameDiv; } game[xi] = gameRow; } return game; } // Repéré la case dans le jeu. function getId(taquin) { var classList = taquin.attr("class").split(/\s+/), result = ""; $.each(classList, function (index, item) { if (index === 0) { result = item; } }); return result; } function getCoord(id) { var coord = [], xi = 0, yi = 0; for (xi = 0; xi < gameStart.length; xi += 1) { for (yi = 0; yi < gameStart[0].length; yi += 1) { if (gameState[xi][yi][1] === id) { coord[0] = xi; coord[1] = yi; } } } return coord; } // Repéré l'élément vide. function getEmpty() { var empty = [], xi = 0, yi = 0; for (xi = 0; xi < gameStart.length; xi += 1) { for (yi = 0; yi < gameStart[0].length; yi += 1) { if (gameState[xi][yi][0] === false) { empty[0] = xi; empty[1] = yi; empty[2] = gameState[xi][yi][1]; } } } return empty; } // vérifier si un élément peut être bougé. function getIsMovable(x, y) { var isMovable = false; try { if (gameState[x][y - 1][0] === false) { isMovable = true; } } catch (err1) {} try { if (gameState[x + 1][y][0] === false) { isMovable = true; } } catch (err2) {} try { if (gameState[x][y + 1][0] === false) { isMovable = true; } } catch (err3) {} try { if (gameState[x - 1][y][0] === false) { isMovable = true; } } catch (err4) {} return isMovable; } // Mélange pièce. function randomGame(mixing) { var empty, possibleMove, temp, i = 0, j = 0, xi = 0, yi = 0, xj = 0, yj = 0, rand = 0, newPosTop = 0, newPosLeft = 0; for (j = 0; j < mixing; j += 1) { empty = getEmpty(); possibleMove = []; i = 0; // On cherche les voisins déplaçable. try { if (gameState[empty[0]][empty[1] - 1][0] === true) { possibleMove[i] = []; possibleMove[i][0] = empty[0]; possibleMove[i][1] = empty[1] - 1; i += 1; } } catch (err1) {} try { if (gameState[empty[0] + 1][empty[1]][0] === true) { possibleMove[i] = []; possibleMove[i][0] = empty[0] + 1; possibleMove[i][1] = empty[1]; i += 1; } } catch (err2) {} try { if (gameState[empty[0]][empty[1] + 1][0] === true) { possibleMove[i] = []; possibleMove[i][0] = empty[0]; possibleMove[i][1] = empty[1] + 1; i += 1; } } catch (err3) {} try { if (gameState[empty[0] - 1][empty[1]][0] === true) { possibleMove[i] = []; possibleMove[i][0] = empty[0] - 1; possibleMove[i][1] = empty[1]; i += 1; } } catch (err4) {} // On choisit au hasard le voisin à interchanger. rand = Math.floor(Math.random() * possibleMove.length); // On l'interchange dans l'état de jeu. temp = gameState[empty[0]][empty[1]]; gameState[empty[0]][empty[1]] = gameState[possibleMove[rand][0]][possibleMove[rand][1]]; gameState[possibleMove[rand][0]][possibleMove[rand][1]] = temp; } // On trouve les déplacements pour l'animation. // Pour chaque élément positionné au départ. for (xi = 0; xi < gameStart.length; xi += 1) { for (yi = 0; yi < gameStart[0].length; yi += 1) { // On cherche sa nouvelle position for (xj = 0; xj < gameState.length; xj += 1) { for (yj = 0; yj < gameState[0].length; yj += 1) { // On trouve la nouvelle position. if (gameStart[xi][yi][1] === gameState[xj][yj][1]) { // On récupère les coordonnées de la nouvelle position. if (gameStart[xi][yi][0] === true) { newPosTop = parseInt((squareHeight * yj) - $(".taquin-" + xi + "-" + yi).position().top, 10) + "px"; newPosLeft = parseInt((squareWidth * xj) - $(".taquin-" + xi + "-" + yi).position().left, 10) + "px"; $(".taquin-" + xi + "-" + yi).animate({ top: "+=" + newPosTop, left: "+=" + newPosLeft }); } else { $(".taquin-" + xi + "-" + yi).css({ "top": (squareHeight * yj), "left": (squareWidth * xj) }); break; } } } } } } } // Démarrer le jeu function launcher(generate) { // On enlève l'intialisation de jeu. generate.find(".taquin-part").unbind("click"); // On cherche l'élément vide. var empty = getEmpty(); $("." + empty[2]).animate({ opacity: "0" }, function () { // On le cache. $(this).hide(); // On mélange le jeu. randomGame(params.mixing); // Annules toutes les animations s'il y en a de pas finie. generate.find(".taquin-part").clearQueue(); // Permettre le déplacement des pièces, jeu jouable ! generate.find(".taquin-part").bind("click", function () { clickFunction(generate, $(this)); }); }); } // Quand on clique sur une partie après le lancement du jeu. clickFunction = function (generate, source) { // rempli ici mais défini plus haut car appelé dans la fonction d'au dessus. var empty, moveTop = 0, moveLeft = 0, tempTop = 0, tempLeft = 0, temp, // Identifier l'élément. id = getId(source), // Trouver sa position dans le jeu. coord = getCoord(id), // Vérifier si il est déplaçable. isMovable = getIsMovable(coord[0], coord[1]); // Si il est déplaçable, interchanger les positions. if (isMovable) { // Trouver l'élément vide. empty = getEmpty(); // On trouve les déplacements pour l'animation. generate.find("." + empty[2]).show(); moveTop = generate.find("." + id).position().top - generate.find("." + empty[2]).position().top; moveLeft = generate.find("." + id).position().left - generate.find("." + empty[2]).position().left; generate.find("." + empty[2]).hide(); //On met les variable en temporaire pour l'interchangement. tempTop = source.position().top; tempLeft = source.position().left; // On inverse les positions de l'éléments vide. temp = gameState[coord[0]][coord[1]]; gameState[coord[0]][coord[1]] = gameState[empty[0]][empty[1]]; gameState[empty[0]][empty[1]] = temp; // On anime le changement. source.unbind("click").animate({ top: "-=" + moveTop, left: "-=" + moveLeft }, function () { source.bind("click", function () { clickFunction(generate, source); }); // Si l'état initial après animation est le même que l'état actuel, on a fini le jeu. if (gameState.toString() === gameStart.toString()) { // On enlève les fonctions de déplacement. generate.find(".taquin-part").unbind("click"); // On cherche l'élément vide pour le ré-afficher. var empty = getEmpty(); $("." + empty[2]).show().animate({ opacity: "1" }, function () { // On replace le mécanisme de démarrage du jeu. generate.find(".taquin-part").bind("click", function () { launcher(generate); }); // On exécute la fonction de réussite. params.success(); }); } }); generate.find("." + empty[2]).css({ "top": tempTop + "px", "left": tempLeft + "px" }); } }; // Fonction exécutée sur chaque élément sélectionné comme model pour devenir un taquin. function taquin(generate, imageOriginalSize) { var gameDivision = params.division, imageWidth = 0, imageHeight = 0, xi = 0, yi = 0, backgroundSizeString; // Récupère la largeur et hauteur des partis du taquin. if (parseInt(params.width, 10) !== 0) { imageWidth = params.width; } else { imageWidth = imageOriginalSize[0]; } if (parseInt(params.height, 10) !== 0) { imageHeight = params.height; } else { imageHeight = imageOriginalSize[1]; } squareWidth = Math.round(imageWidth / gameDivision); squareHeight = Math.round(imageHeight / gameDivision); // Initialise l'état initial et actuelle du jeu. gameStart = initialiseGameVar(gameDivision); gameState = initialiseGameVar(gameDivision); generate.css({ "position": "relative", "width": imageWidth + "px", "height": imageHeight + "px" }); // Générer les partis du taquin. for (xi = 0; xi < gameStart.length; xi += 1) { for (yi = 0; yi < gameStart[0].length; yi += 1) { backgroundSizeString = ((params.width != 0) ? params.width : imageOriginalSize[0]) + "px " + ((params.height != 0) ? params.height : imageOriginalSize[1]) + "px"; $("<div>", { css: { cursor: "pointer", backgroundImage: "url('" + image + "')", backgroundPosition : "-" + parseInt(squareWidth * xi, 10) + "px -" + parseInt(squareHeight * yi, 10) + "px", "background-size" : backgroundSizeString, position: "absolute", top: parseInt(squareHeight * yi, 10) + "px", left: parseInt(squareWidth * xi, 10) + "px", width: squareWidth + "px", height: squareHeight + "px" } }).appendTo(generate).addClass(gameStart[xi][yi][1]).addClass("taquin-part"); } } // Permettre de démarrer le jeu. generate.find(".taquin-part").bind("click", function () { launcher(generate); }); } // S'execute pour chaque élément 'fn' trouvé. return this.each(function () { // Information sur l'image. var waitForImageSize, forImage = new Image(), element = $(this), imageSize = []; forImage.src = image; // Quand on obtient une taille pour l'image, on execute le mécanisme. waitForImageSize = setInterval(function () { if (forImage.width !== 0) { imageSize[0] = forImage.width; imageSize[1] = forImage.height; // Génère l'élément qui contiendra les partis du taquin. var generate = $("<div>").addClass("taquin-generate"); if (element.next().hasClass("taquin-generate")) { element.next().remove(); } element.after(generate); taquin(generate, imageSize); clearInterval(waitForImageSize); } }, 50); }); }; }(jQuery));
Documentation
Utilisation
La fonction de base s'utilise comme suit :
- $(dom_element).gameTaquin(image);
Exemple sur l'élément de DOM suivant <div id="taquin"></div>.
$("#taquin").gameTaquin("http://blog.haeresis.fr/upload/image/image-taquin.jpg");
image
Ceci réprésente l'adresse de l'image qui sera fractionnée pour être jouée.
Paramètres
Les paramètres se donnent sous forme d'objet JSON après l'url de l'image :
- $(DOM_ELEMENT).gameTaquin(IMAGE_URL, { PARAMETERS... });
Les paramètres sont cumulables comme dans cet exemple.
$("#taquin").gameTaquin( "http://blog.haeresis.fr/upload/image/image-taquin.jpg", { division: 6, hidePart: "tl", success: "Félicitation !" } );
width
Indique la taille que fait l'image en largeur. Si rien ou zéro est précisé, la taille par défaut est celle de l'image.
height
Indique la taille que fait l'image en hauteur. Si rien ou zéro est précisé, la taille par défaut est celle de l'image.
division
Indique le nombre de carré en largeur/hauteur qui compose le taquin.
hidePart
Indique quelle partie du carré est masquée pour faire office de trou pour les déplacements. Les valeurs possibles sont Haut Gauche "tl", Haut droite "tr", Bas gauche "bl", Bas droite "br" (par défaut).
mixing
Indique le nombre de déplacement fait aléatoirement pour simuler un mélange à la main du taquin.
success
Si écrasé par une fonction, exécute cette fonction en cas de complétion du taquin. Sinon, renvoi sous chaine de caractère le message passé dans un "alert()".
3 Commentaires
Choisir un Avatar depuis une url
Adresse : (64px x 64px)ou Changer la couleur de fond
et Choisir un Avatar dans la liste
Votre commentaire a été ajouter ci-dessous ! Si vous désirez le supprimer ultérieurement, servez vous du code suivant :
Les commentaires sont actuellement affiché du plus rescent au plus ancien. Vous pouvez inverser l'ordre en cliquant ci-dessous :
Bonjour,
Super sujet. j'aimerai que le taquin soit mélangé immédiatement à 'ouverture de la page, sans clic. Comment faire, je n'arrive pas à le faire.
Merci
Je trouve ce commentaire pertinent ?
Bonjour,
j'aimerai intégrer 1 jeu de taquin dans 1 page perso contenant une image présélectionné. Je ne comprends pas quelles parties je dois inclure, ni ou dans ma page.
Pouvez-vous m'aider ?
Je trouve ce commentaire pertinent ?
Belle démonstration ! Merci pour le code source :p
Tu gères !
Je trouve ce commentaire pertinent ?
Je trouve ce commentaire pertinent ?