Advertisement
Guest User

Untitled

a guest
Mar 5th, 2015
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 35.88 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. // the JigsawPuzzle Class is the base class that can be used to create an in-game jigsaw puzzle
  5. //
  6. // the normal procedure would be to create a custom JigsawPuzzle subclass
  7. // and override the following base functions :
  8. //
  9. // - PuzzleStart();                         : is called when new puzzle is started
  10. // - ActivatePiece(GameObject piece);       : is called when a 'loose' puzzle piece is selected (start drag)
  11. // - DeactivatePiece(GameObject piece);     : is called when a 'loose' puzzle piece is released (stop drag)
  12. // - PiecePlaced(GameObject piece);         : is called when a puzzle piece is placed on the puzzle on the right spot
  13. // - PuzzleSolved(int moves, float time);   : is called when the puzzle has been solved
  14. //
  15. // (see DemoJigsawPuzzle class included with the product Demo)
  16. //
  17. [System.Serializable]
  18. public class JigsawPuzzle : MonoBehaviour {
  19.  
  20.     // ---------------------------------------------------------------------------------------------------------
  21.     // public (published) attributes - these can be set after adding the
  22.     // script to a container (like a cube primitive)
  23.     // ---------------------------------------------------------------------------------------------------------
  24.  
  25.     public Texture image = null;                // will contain the jigsaw projected picture
  26.     public Texture[] randImage;  
  27.     public Vector2 size = new Vector2(5,5);     // how many pieces will this puzzle have (x,y)
  28.     public string topLeftPiece = "11";          // topleft piece - format YX (1,2,3,4,5) so 11 to 55 - 25 unique start possiblities
  29.     public bool showImage = true;               // display 'helper' semi-transparant - greyscale sample picture
  30.     public bool showLines = true;               // display 'helper' puzzle matrix
  31.     public int placePrecision = 12;             // how precise must a piece beeing placed on the puzzle ( = percentage | 6 - 15 are good values , maybe higher up to 25 for small children )
  32.     public bool scatterPieces = true;           // scatter pieces when puzzle starts - if false the pieces are placed on their spot on the puzzle
  33.     public float spacing = 0.01f;
  34.  
  35.     bool rotatePieces = false;                  // true to add rotation support - NOT IMPLEMENTED YET
  36.    
  37.     // ---------------------------------------------------------------------------------------------------------
  38.     // protected attributes (accessable in 'custom' subclass)
  39.     // ---------------------------------------------------------------------------------------------------------
  40.  
  41.     // number of pieces of current puzzle
  42.  
  43.     void Awake()
  44.     {
  45.         randomPic = Random.Range(0,5);
  46.  
  47.     }
  48.  
  49.  
  50.  
  51.     protected int pieceCount                    
  52.     {
  53.         get
  54.         {
  55.             return (int)(size.x * size.y);
  56.         }
  57.     }
  58.  
  59.     // number of pieces placed in current puzzle
  60.     protected int piecesPlaced              
  61.     {
  62.         get
  63.         {
  64.             return puzzleContainer.transform.GetChildCount();
  65.         }
  66.     }
  67.  
  68.     // number of pieces to go in current puzzle
  69.     protected int piecesScattered              
  70.     {
  71.         get
  72.         {
  73.             return piecesContainer.transform.GetChildCount();
  74.         }
  75.     }
  76.  
  77.     // puzzle progress - percentage 0-100
  78.     protected float puzzleProgress    
  79.     {
  80.         get
  81.         {
  82.             return (piecesPlaced/pieceCount) * 100;
  83.         }
  84.     }
  85.    
  86.     // ---------------------------------------------------------------------------------------------------------
  87.     // private attributes
  88.     // ---------------------------------------------------------------------------------------------------------
  89.  
  90.     private JigsawMain main = null;
  91.     private bool checkedOnce = false;          
  92.     private int puzzleMode = 0;                
  93.     private GameObject linesH = null;      
  94.     private GameObject linesV = null;          
  95.     private GameObject sampleImage = null;     
  96.     private GameObject piecesContainer = null; 
  97.     private GameObject puzzleContainer = null;
  98.     private GameObject pieceCache = null;
  99.     private GameObject puzzlePlane = null;
  100.     private int puzzleMoves = 0;
  101.     private int puzzleTicks = 0;
  102.     private bool restarting = false;
  103.     private bool dragging = false;
  104.     private Touch dragTouch;
  105.     private int randomPic;
  106.     private GameObject activePiece = null;
  107.     private Vector3 activePoint;
  108.  
  109.     private Vector2 checkSize;
  110.     private Vector2 checkContainerSize;
  111.     private string  checkTopLeftPiece = "";
  112.  
  113.     private Hashtable piecesLookup = new Hashtable();
  114.     private Hashtable piecePositions = new Hashtable();
  115.  
  116.     private ArrayList pieces = new ArrayList();
  117.  
  118.     // ---------------------------------------------------------------------------------------------------------
  119.     // virtual methods
  120.     // ---------------------------------------------------------------------------------------------------------
  121.    
  122.     // This will be called when a new puzzle has been started
  123.     // you need to override this method when you create your 'custom' subclass
  124.     protected virtual void PuzzleStart()
  125.     {
  126.     }
  127.    
  128.        
  129.     // This will be called when a 'loose' puzzle piece has been selected (start drag)
  130.     // you need to override this method when you create your 'custom' subclass
  131.     protected virtual void ActivatePiece(GameObject piece)
  132.     {
  133.     }
  134.    
  135.        
  136.     // This will be called when a puzzle piece has been released (stop drag)
  137.     // you need to override this method when you create your 'custom' subclass
  138.     protected virtual void DeactivatePiece(GameObject piece)
  139.     {
  140.     }
  141.    
  142.        
  143.     // This will be called when a piece has been placed on the puzzle on the correct spot
  144.     // you need to override this method when you create your 'custom' subclass
  145.     protected virtual void PiecePlaced(GameObject piece)
  146.     {
  147.     }
  148.    
  149.        
  150.     // This will be called when the puzzle has been solved
  151.     // you need to override this method when you create your 'custom' subclass
  152.     protected virtual void PuzzleSolved(int moves, float time)
  153.     {
  154.     }  
  155.    
  156.     // this will be called when a piece is about to be scattered - if null is returned the default scattering is performed
  157.     // you need to override this method when you create your 'custom' subclass
  158.     protected virtual GameObject ScatterPiece(GameObject piece)
  159.     {
  160.         return null;
  161.     }
  162.    
  163.     // ---------------------------------------------------------------------------------------------------------
  164.     // methods
  165.     // ---------------------------------------------------------------------------------------------------------
  166.    
  167.     // restart the current puzzle
  168.     public void Restart()
  169.     {
  170.         // set indicator that puzzle has to be restarted - this is picked up in the Update() - process
  171.         restarting = true;
  172.     }
  173.    
  174.     // Update is called once per frame
  175.     protected void Update () {
  176.         if (main == null)
  177.         {
  178.             // main puzzle initialization
  179.             if (!checkedOnce)
  180.             {
  181.                 // check ONCE if JigsawMain Script is found on JisawMain Prefab
  182.                 GameObject go = GameObject.Find("JigsawMain");
  183.                 if (go == null)
  184.                 {
  185.                     Debug.LogError("JigsawMain (prefab) GameObject not added to scene!");
  186.                     checkedOnce = true;
  187.                     return;
  188.                 }
  189.                 // get JigsawMain class for piece prototype access
  190.                 main = go.GetComponent("JigsawMain") as JigsawMain;
  191.                 // check if main is initialized correctly so isValid should be true
  192.                 if (main != null)
  193.                     if (!main.isValid)
  194.                     {
  195.                         Debug.LogError("JigsawMain (prefab) GameObject is not valid - Base puzzle pieces could not be found!");
  196.                         main = null;
  197.                         checkedOnce = true;
  198.                         return;
  199.                     }
  200.  
  201.                 // check if TopLeftPiece Exists , if not we will take '11'
  202.                 if (main.GetBase(topLeftPiece) == null)
  203.                     topLeftPiece = "11";
  204.  
  205.                 // initialization of this puzzle
  206.                 // create horizontal and vertical lines
  207.                 SetLines();
  208.                 // create sample image
  209.                 SetSample();
  210.                 // create pieces of this puzzle
  211.                 SetPieces(false);
  212.                 // create mouse control 'hit' plane
  213.                 SetPlane();
  214.             }
  215.             else
  216.                 // puzzle system is invalid so return;
  217.                 return;
  218.         }
  219.         else
  220.         {
  221.             // JigsawMain was found and is valid so we can go on with our puzzle   
  222.             // Lets first check if base puzzle settings have been changed like size or the top-left piece so we have to force a restart
  223.             if (!Vector2.Equals(size, checkSize) || topLeftPiece!=checkTopLeftPiece || restarting)
  224.             {
  225.                 if (activePiece)
  226.                 {
  227.                     // deactivate the current active piece
  228.                     DeactivatePiece(activePiece);
  229.                     activePiece = null;
  230.                 }
  231.                 // base puzzle settings have been changed so reset lines, sample image and pieces.
  232.                 SetLines();
  233.                 SetSample();
  234.                 SetPieces(true);
  235.                 // restart puzzle - so puzzleMode to 0
  236.                 puzzleMode = 0;
  237.             }
  238.  
  239.             // check if lines have to be shown/hidden
  240.             if (linesH.active != showLines) linesH.active = showLines;
  241.             if (linesV.active != showLines) linesV.active = showLines;
  242.             // check if sample image has to be shown/hidden
  243.             if (sampleImage.active != showImage) sampleImage.active = showImage;
  244.  
  245.             // Puzzle control
  246.             switch (puzzleMode)
  247.             {
  248.                 case 0:     // puzzle initialization
  249.                     if (pieceCount == 0) return;
  250.                
  251.                     if (scatterPieces)
  252.                         // we have pieces so scatter them around
  253.                         ScatterPieces();
  254.                
  255.                     if (rotatePieces)
  256.                         // rotate the pieces on the scattered spot
  257.                         RotatePieces();
  258.                
  259.                     // starting to puzzle so reset move count and puzzleTime
  260.                     puzzleMoves = 0;
  261.                     puzzleTicks = System.Environment.TickCount;
  262.                     restarting = false;
  263.                     // call overriden PuzzleStart function
  264.                     PuzzleStart();
  265.                     // Puzzle control to next step
  266.                     puzzleMode++;
  267.                     break;
  268.                
  269.                 case 1:     // we are puzzling
  270.  
  271.                     if (Input.GetMouseButton(0))
  272.                     {
  273.                         // register first touch
  274.                         if (Input.multiTouchEnabled && !dragging)
  275.                             dragTouch = Input.touches[0];
  276.    
  277.                         if (!Input.multiTouchEnabled || (Input.multiTouchEnabled && dragTouch.fingerId == Input.touches[0].fingerId))
  278.                         {
  279.                             // only check position is mouse click or first touch is active
  280.                             Vector3 position = Input.mousePosition;
  281.                             if (Input.multiTouchEnabled)
  282.                                 position = Input.touches[0].position;
  283.                             // left mouse button is down so check if we have an active piece
  284.                             if (activePiece != null)
  285.                             {
  286.                                 // if we have an active piece we will move it, if we moved the mouse
  287.                                 RaycastHit hit;
  288.                                 // cast a ray from the camera to the mouse control hitplane
  289.                                 if (puzzlePlane.collider.Raycast(Camera.main.ScreenPointToRay(position), out hit,Vector3.Distance(Camera.main.transform.position, transform.position)*2))
  290.                                 {
  291.                                     // calculate the distance between the previous hit.point and the current
  292.                                     Vector3 d = hit.point - activePoint;
  293.                                     // move active piece with the calculated distance
  294.                                     activePiece.transform.position += d;
  295.                                     // current point becomes new hit.point
  296.                                     activePoint = hit.point;
  297.                                 }
  298.                             }
  299.                             else
  300.                             {
  301.                                 // no active piece so check if we can get one
  302.                                 // cast a ray from the camera collect all hits that correspond with the 'puzzle' layer mask (31 = default but can be set on JigSawMain class)
  303.                                 RaycastHit[] hits = Physics.RaycastAll(Camera.main.ScreenPointToRay(position),Vector3.Distance(Camera.main.transform.position, transform.position)*2, 1 << main.layerMask);
  304.                                 if (hits.Length>0)
  305.                                 {
  306.                                     // we have hit something so check them
  307.                                     for (int h=0; h<hits.Length; h++)
  308.                                     {
  309.                                         if (hits[h].collider.gameObject == puzzlePlane)
  310.                                         // if we hit the mouse control hit plane we register the hit.point for piece moving purposes
  311.                                             activePoint = hits[h].point;
  312.                                         else
  313.                                             if (hits[h].collider.gameObject.transform.parent.gameObject == piecesContainer)
  314.                                             {
  315.                                                 // we hit a piece so make it active if dont have one or if it is 'forward' the current active piece
  316.                                                 if ((activePiece!=null && activePiece.transform.position.z >  hits[h].collider.gameObject.transform.position.z) || activePiece==null)
  317.                                                     activePiece = hits[h].collider.gameObject;
  318.                                             }
  319.                                     }
  320.                                     // active the piece if we have found one
  321.                                     if (activePiece != null)
  322.                                        ActivatePiece(activePiece);
  323.                                     dragging = true;
  324.                                 }
  325.                             }
  326.                         }
  327.                     }
  328.                     else
  329.                     {
  330.                         dragging = false;
  331.                         // mouse left button is not down
  332.                         if (activePiece != null)
  333.                         {
  334.                             // if we have an active piece we have to deactivate it.
  335.                             DeactivatePiece(activePiece);
  336.                             // increase the number of moves
  337.                             puzzleMoves++;
  338.                        
  339.                             if (PieceInPlace())
  340.                             {
  341.                                 // piece is released in the right spot so snap it into position
  342.                                 activePiece.transform.position = PiecePosition((Vector2)piecePositions[activePiece.name]);
  343.                                 // set parent to puzzleContainer so we lock it for dragging
  344.                                 activePiece.transform.parent = puzzleContainer.transform;
  345.                                 // call overriden PiecePlaced function
  346.                                 PiecePlaced(activePiece);
  347.  
  348.                                 if (puzzleProgress == 100)
  349.                                 {
  350.                                     // puzzle is solved so call overridden PuzzleSolved function
  351.                                     PuzzleSolved(puzzleMoves, (System.Environment.TickCount - puzzleTicks) / 1000);
  352.                                     puzzleMode++;
  353.                                 }
  354.                                
  355.                             }
  356.                             activePiece = null;
  357.                         }
  358.                     }
  359.  
  360.                     break;
  361.                 case 2:     // puzzle is Done - this a kind of sleep state.
  362.                     break;                        
  363.             }
  364.         }  
  365.     }
  366.    
  367.     // Determine if active piece is in the right spot.
  368.     // the placePrecision setting tells us how accurate we have to fit the piece on the puzzle
  369.     // 12-15 is a good setting
  370.     // 15-25 for young kids
  371.     private bool PieceInPlace()
  372.     {
  373.         // call base piece size
  374.         float dX = (transform.localScale.x / size.x);
  375.         float dY = (transform.localScale.y / size.y);
  376.         // calculate distance vector between active piece correct position and current position
  377.         Vector3 dV = PiecePosition((Vector2)piecePositions[activePiece.name]) - activePiece.transform.position;
  378.         // control vector is piece size
  379.         Vector3 cV = new Vector3(dX, dY, 0);
  380.         // check distance (with place precicion) from current position to correct position
  381.         return ((Vector3.Distance(Vector3.zero, dV) / Vector3.Distance(Vector3.zero, cV) * 100) < placePrecision);
  382.     }
  383.    
  384.     // Create horizontal lines to display on puzzle
  385.     private void SetLinesHorizontal()
  386.     {
  387.         // we must have a valid topLeftPiece
  388.         if (topLeftPiece.Length != 2) return;
  389.         // get starting x-line from top left piece
  390.         int tpX = System.Convert.ToInt32(topLeftPiece.Substring(1, 1));
  391.         // get starting y-line from top left piece
  392.         int tpY = System.Convert.ToInt32(topLeftPiece.Substring(0, 1));
  393.         // we will recreate so destroy if we already have lines
  394.         if (linesH != null) GameObject.Destroy(linesH);
  395.         // create a cube primitive for these lines
  396.         linesH = GameObject.CreatePrimitive(PrimitiveType.Cube);
  397.         linesH.name = "lines-horizontal";
  398.         // add lines to puzzle
  399.         linesH.transform.parent = gameObject.transform;
  400.         // set 'transparent' material to lines horizontal
  401.         linesH.renderer.material = main.linesHorizontal;
  402.         // set the right scale (z = very thin) rotation and position so it will cover the puzzle
  403.         linesH.transform.localScale = new Vector3(-1, -1 * (1 / size.y) * (size.y - 1), 0.0001F);
  404.         linesH.transform.rotation = transform.rotation;
  405.         // move this 'thin' cube so that it floats just above the puzzle
  406.         linesH.transform.position = transform.position +
  407.             transform.forward * ((transform.localScale.z / 2) + 0.001F);
  408.         // scale the texture in relation to specified size
  409.         linesH.renderer.material.mainTextureScale = new Vector2(-0.2F * size.x, -0.2F * (size.y - 1));
  410.         // set the right offset in relation to the specified size and the specified topLeftPiece
  411.         linesH.renderer.material.mainTextureOffset = new Vector2(((5 - size.x) * -0.2F) + ((tpX - 1) * 0.2F), 0.005F + ((tpY - 1) * -0.2F));
  412.         linesH.active = false;
  413.     }
  414.    
  415.     // Create vertical lines to display on puzzle
  416.     private void SetLinesVertical()
  417.     {
  418.         // we must have a valid topLeftPiece
  419.         if (topLeftPiece.Length != 2) return;
  420.         // get starting x-line from top left piece
  421.         int tpX = System.Convert.ToInt32(topLeftPiece.Substring(1, 1));
  422.         // get starting y-line from top left piece
  423.         int tpY = System.Convert.ToInt32(topLeftPiece.Substring(0, 1));
  424.         // we will recreate so destroy if we already have lines
  425.         if (linesV != null) GameObject.Destroy(linesV);
  426.         // create a cube primitive for these line
  427.         linesV = GameObject.CreatePrimitive(PrimitiveType.Cube);
  428.         linesV.name = "lines-vertical";
  429.         // add lines to puzzle
  430.         linesV.transform.parent = gameObject.transform;
  431.         // set 'transparent' material to lines horizonta
  432.         linesV.renderer.material = main.linesVertical;
  433.         // set the right scale (z = very thin) rotation and position so it will cover the puzzl
  434.         linesV.transform.localScale = new Vector3(-1 * (1 / size.x) * (size.x - 1), -1, 0.0001F);
  435.         linesV.transform.rotation = transform.rotation;
  436.         // move this 'thin' cube so that it floats just above the puzzle
  437.         linesV.transform.position = transform.position +
  438.             transform.forward * ((transform.localScale.z / 2) + 0.001F);
  439.         // scale the texture in relation to specified size
  440.         linesV.renderer.material.mainTextureScale = new Vector2(-0.2F * (size.x - 1), -0.2F * size.y);
  441.         // set the right offset in relation to the specified size and the specified topLeftPiece
  442.         linesV.renderer.material.mainTextureOffset = new Vector2(-0.2F * ((5 - size.x) + 1) + ((tpX - 1) * 0.2F), 0 + +((tpY - 1) * -0.2F));
  443.         linesV.active = false;
  444.     }
  445.  
  446.     private void SetLines()
  447.     {
  448.         // create puzzle lines
  449.         SetLinesHorizontal();
  450.         SetLinesVertical();
  451.         // store size and top left piece so we can force a restart if they change
  452.         checkSize = size;
  453.         checkTopLeftPiece = topLeftPiece;
  454.     }
  455.    
  456.     // rotate the pieces on their scattered spot
  457.     private void RotatePieces()
  458.     {
  459.         // we will use the world space coordinates and scale of the puzzle for piece locations
  460.         Vector3 s = transform.localScale;
  461.         float dX = s.x / size.x;
  462.         float dY = s.y / size.y;
  463.         for (int p = 0; p<pieces.Count; p++)
  464.         {
  465.             GameObject piece = pieces[p] as GameObject;
  466.             Transform  parent = piece.transform.parent;
  467.             Vector3 oldScale = piece.transform.localScale;
  468.             piece.transform.parent = null;
  469.             piece.transform.RotateAround(piece.transform.position+transform.right * -1 * (dX/2) +transform.up * -1 * (dY/2),transform.forward,Random.value * 360);
  470.             // piece.transform.parent = parent;
  471.         }
  472.     }
  473.    
  474.     // scatter the pieces and place them randomly around the puzzle
  475.     private void ScatterPieces()
  476.     {
  477.         ArrayList piecesToScatter = new ArrayList(pieces);
  478.         while (piecesToScatter.Count > 0)
  479.         {
  480.             // take a random piece
  481.             GameObject piece = piecesToScatter[(int)(Mathf.Floor(Random.value * piecesToScatter.Count))] as GameObject;
  482.             piecesToScatter.Remove(piece);
  483.            
  484.             // first try the custom scatter function
  485.             if (ScatterPiece(piece)!=null)
  486.                 continue;
  487.            
  488.             // will will determine in what rectangle a random position can be calculated for this piece
  489.             Rect r = new Rect();
  490.            
  491.             // we will use the world space coordinates and scale of the puzzle for piece locations
  492.             Vector3 p = transform.position;
  493.             Vector3 s = transform.localScale;
  494.             float dX = s.x / size.x;
  495.             float dY = s.y / size.y;
  496.            
  497.             // si will hold the smallest scatter area size ( puzzle height/width devided by 4 `)
  498.             var si = s.x / 4;
  499.             if (s.y / 4 < si) si = s.y / 4;
  500.            
  501.             // determine randomly if the piece should be place above, to the left, to the right or below the puzzle
  502.             switch ((int)(Mathf.Floor(Random.value * 4)) + 1)
  503.             {
  504.                 case 1: // above
  505.                     r = new Rect(p.x - (s.x/2) - (dX/2) + (s.x * 0.1f) , p.y + (s.y/2) + dY + si - (dY/2) , s.x * 0.8f , -1 * (si - dY));
  506.                     break;
  507.                 case 2: // right side
  508.                     r = new Rect(p.x + (s.x / 2) + dX - (dX/2), p.y + (s.y / 2) - (s.y * 0.1f), si - dX, -1 * s.y * 0.8f);
  509.                     break;
  510.                 case 3:  // below
  511.                     r = new Rect(p.x - (s.x / 2) - (dX / 2) + (s.x * 0.1f), p.y - (s.y / 2) - (dY/2) , s.x * 0.8f, -1 * (si - dY));
  512.                     break;
  513.                 case 4:  // left side
  514.                     r = new Rect(p.x - (s.x / 2) - dX - si + (dX/2) , p.y + (s.y/2) - (s.y * 0.1f) , si - dX, -1 * s.y * 0.8f);
  515.                     break;
  516.             }
  517.  
  518.             // because we used world coordinates we have to transfer the piece to the world by removing the parent
  519.             //piece.transform.parent = null;
  520.             // determine the random position with the valid rectangle
  521.             piece.transform.parent = piecesContainer.transform;
  522.  
  523.             piece.transform.position =
  524.                 // start from puzzle position
  525.                 transform.position +
  526.                 // go to x of placement rectangle
  527.                 transform.right * -1 * r.xMin +
  528.                 // add random x position
  529.                 transform.right * -1 * Random.value * r.width +
  530.                 // go to top of placement rectangle
  531.                 transform.up * r.yMin +
  532.                 // add random y position
  533.                 transform.up * Random.value * r.height +
  534.                 // move to just 'forward' the surface of the puzzle cuve primitive
  535.                 transform.forward * ((transform.localScale.z / 2) + 0.001f) +
  536.                 // add a random forward value for better moving and selecting.
  537.                 transform.forward * (0.004f + (0.001F * Random.value * 20));
  538.                        
  539.             if (transform.parent!=null)
  540.             {
  541.                 Vector2 vp = transform.parent.localToWorldMatrix.MultiplyPoint3x4(transform.localPosition);
  542.                 piece.transform.position -= (Vector3)vp;
  543.             }
  544.            
  545.                        
  546.         }
  547.     }
  548.  
  549.     // create mouse control hit plane
  550.     private void SetPlane()
  551.     {
  552.         // Create Hit Plane Primitive GameObject for puzzle movement control
  553.         puzzlePlane = GameObject.CreatePrimitive(PrimitiveType.Cube);
  554.         puzzlePlane.name = "puzzlePlane";
  555.         // position, rotate and scale it related to the puzzle (x/y scale x10)
  556.         puzzlePlane.transform.parent = transform;
  557.         puzzlePlane.transform.rotation = transform.rotation;
  558.         puzzlePlane.transform.localScale = new Vector3(10, 10, 0.0001F);
  559.         // let this hitplane float just 'forward' of the puzzle
  560.         puzzlePlane.transform.position = transform.position +
  561.             transform.forward * ((transform.localScale.z / 2) + 0.0004F);
  562.         // set the layer mask for quick RayCasting
  563.         puzzlePlane.layer = main.layerMask;
  564.         // remove the renderer so we only use the collider
  565.         Destroy(puzzlePlane.GetComponent("MeshRenderer"));
  566.     }
  567.  
  568.     // create the sample image
  569.     private void SetSample()
  570.     {
  571.         // if we already have one destroy it first
  572.         if (sampleImage != null) GameObject.Destroy(sampleImage);
  573.         // create a primitive cube
  574.         sampleImage = GameObject.CreatePrimitive(PrimitiveType.Cube);
  575.         sampleImage.name = "sampleImage";
  576.         // position, rotate and scale it related to the puzzle ( very thin )
  577.         sampleImage.transform.parent = gameObject.transform;
  578.         sampleImage.transform.localScale = new Vector3(1, 1, 0.0001F);
  579.         sampleImage.transform.rotation = transform.rotation;
  580.         sampleImage.transform.position = transform.position +
  581.             transform.forward * ((transform.localScale.z / 2) + 0.0005F);
  582.         // set image to puzzle material to sample image material (can be set on JigsawMain class)
  583.         sampleImage.renderer.material = main.sampleImage;
  584.         // set image to puzzle image
  585.        // sampleImage.renderer.material.mainTexture = image;
  586.         sampleImage.renderer.material.mainTexture = randImage[1];
  587.         sampleImage.renderer.material.mainTextureOffset = Vector2.zero;
  588.         sampleImage.active = false;
  589.     }
  590.    
  591.     // create piece containers
  592.     private void CreateContainers()
  593.     {
  594.         if (piecesContainer != null) GameObject.Destroy(piecesContainer);
  595.         if (puzzleContainer != null) GameObject.Destroy(puzzleContainer);
  596.         if (pieceCache != null) GameObject.Destroy(pieceCache);
  597.        
  598.         // piecesContainer will hold all 'loose' scattered pieces
  599.         piecesContainer = new GameObject("piecesContainer");
  600.         piecesContainer.transform.parent = gameObject.transform;
  601.         piecesContainer.transform.rotation = transform.rotation;
  602.         piecesContainer.transform.localScale = transform.localScale;
  603.         piecesContainer.transform.position = transform.position;
  604.        
  605.         // puzzleContainer will hold all 'placed' pieces
  606.         puzzleContainer = new GameObject("puzzleContainer");
  607.         puzzleContainer.transform.parent = gameObject.transform;
  608.         puzzleContainer.transform.rotation = transform.rotation;
  609.         puzzleContainer.transform.localScale = transform.localScale;
  610.         puzzleContainer.transform.position = transform.position;
  611.        
  612.         // pieceCache will hold all pieces that were created but no longer
  613.         // are used on current puzzle - but can re-use after resize or restart
  614.         pieceCache = new GameObject("pieceCache");
  615.         pieceCache.transform.parent = gameObject.transform;
  616.         pieceCache.transform.rotation = transform.rotation;
  617.         pieceCache.transform.localScale = transform.localScale;
  618.         pieceCache.transform.position = transform.position;
  619.     }
  620.    
  621.     // get piece type (9) related to provided position on puzzle
  622.     //
  623.     //  TL  T   TR
  624.     //  L   C   R
  625.     //  BL  B   BR
  626.     //
  627.     private string GetType(Vector2 pos)
  628.     {
  629.         float x = pos.x;
  630.         float y = pos.y;
  631.  
  632.         string pt = "C";
  633.         if (y == 1)
  634.         {
  635.             if (x == 1) pt = "TL";
  636.             else
  637.                 if (x == size.x) pt = "TR";
  638.                 else
  639.                     pt = "T";
  640.         }
  641.         else
  642.             if (y == size.y)
  643.             {
  644.                 if (x == 1) pt = "BL";
  645.                 else
  646.                     if (x == size.x) pt = "BR";
  647.                     else
  648.                         pt = "B";
  649.             }
  650.             else
  651.                 if (x == 1)
  652.                     pt = "L";
  653.                 else
  654.                     if (x == size.x)
  655.                         pt = "R";
  656.         return pt;
  657.     }
  658.  
  659.     // calculate right position for a x,y positioned piece on puzzle
  660.     private Vector3 PiecePosition(Vector3 pos)
  661.     {
  662.         float dX = transform.localScale.x / size.x;
  663.         float dY = transform.localScale.y / size.y;
  664.  
  665.         // determine the position related x/y vector for this piece
  666.         Vector3 positionVector =
  667.             ((((transform.localScale.x / 2) * -1) + (dX * (pos.x - 1))+ (dX * (spacing/2))) * transform.right * -1) +
  668.             (((transform.localScale.y / 2)) - (dY * (pos.y - 1)) - (dY * (spacing/2))) * transform.up;
  669.  
  670.         // set piece position to its right spot on the puzzle
  671.         return transform.position +
  672.             transform.forward * ((transform.localScale.z / 2) + 0.001f) +
  673.             positionVector;
  674.     }
  675.    
  676.     // initialize specific piece with right scale, position and texture (scale/offset)
  677.     private void InitPiece(GameObject puzzlePiece, Vector2 pos)
  678.     {
  679.        
  680.         // if we had a 5x5 puzzle we should scale the prototype pieces (from blender) like this
  681.         //Vector3 scale5x5 = Vector3.Scale( new Vector3(0.1146f, 0.1146f, 0.25f), transform.localScale);
  682.         Vector3 scale5x5 = Vector3.Scale(new Vector3(11.45f, 11.45f, 36.14547f), transform.localScale);
  683.         // determine the puzzle size related scale vector
  684.         Vector3 CxR = new Vector3(1 / (0.2F * size.x), 1 / (0.2F * size.y), 25 / (size.x * size.y));
  685.         // set piece to world space so we can work with puzzle dimensions
  686.         puzzlePiece.transform.parent = null;
  687.         // set right scale for piece in world space
  688.         puzzlePiece.transform.localScale = Vector3.Scale( scale5x5 * (1-spacing), CxR);    
  689.         // rotate like puzzle
  690.         puzzlePiece.transform.rotation = transform.rotation;
  691.         // add piece to container
  692.         puzzlePiece.transform.parent = piecesContainer.transform;              
  693.         // set piece position to its right spot on the puzzle
  694.         puzzlePiece.transform.position = PiecePosition(pos);
  695.         // add correct x,y position Vector2 to piecePositions for InPlace() control
  696.         piecePositions.Add(puzzlePiece.name, pos);             
  697.         // we now are gonna work with local scale for the texture so 1 = puzzle width/height
  698.         float scaleX = 1 / (0.2F * size.x);
  699.         float scaleY = 1 / (0.2F * size.y);
  700.         // set surface/image material to scatteredPieces material (can be set on JigsawMainClass)
  701.         puzzlePiece.renderer.material = main.scatteredPieces;
  702.         // set piece base material to pieceBase material (can be set on JigsawMainClass)
  703.         puzzlePiece.renderer.materials[1] = main.pieceBase;
  704.         // set surface texture to the puzzle image
  705.         //puzzlePiece.renderer.material.mainTexture = image;
  706.  
  707.         Debug.Log (randomPic);
  708.         puzzlePiece.renderer.material.mainTexture = randImage[randomPic];
  709.         // scale the surface texture
  710.         puzzlePiece.renderer.material.mainTextureScale = new Vector2(scaleX, scaleY);
  711.         // determine the texture offset related to the size and piece position
  712.         puzzlePiece.renderer.material.mainTextureOffset = new Vector2(0.2F * scaleX * (pos.x - 1), -0.2F * scaleY * (pos.y - 1 + (5-size.y)));
  713.     }
  714.    
  715.     // create a new piece from a specific prototype on a specific position with a specific piece type
  716.     private GameObject CreateNewPiece(Vector2 piece, Vector2 pos, string pType)
  717.     {
  718.         GameObject puzzlePiece = null;
  719.         // get piece prototype from main
  720.         Transform basePiece = main.GetPiece("" + piece.y + "" + piece.x, pType);
  721.         if (basePiece != null)
  722.         {
  723.             // prototype has been found so make an instance
  724.             puzzlePiece = GameObject.Instantiate(basePiece.gameObject, new Vector3(pos.x * 2F, pos.y * -2F, 0), Quaternion.Euler(new Vector3(0, 180, 0))) as GameObject;
  725.             // add collider to puzzle Pience
  726.             puzzlePiece.AddComponent("BoxCollider");
  727.         }
  728.         // add to specific layer for fast future RayCasting
  729.         puzzlePiece.layer = main.layerMask;
  730.         return puzzlePiece;
  731.     }
  732.  
  733.     // Create or set (initialize) all pieces of the current puzzle
  734.     private void SetPieces(bool recreate)
  735.     {
  736.         // we have to have a valid piece
  737.         if (topLeftPiece.Length != 2) return;
  738.         if (size.x <= 1 || size.y <= 1) return;
  739.  
  740.         if (!recreate)
  741.             // only create piece containers the first time
  742.             CreateContainers();
  743.         else
  744.         {
  745.             // remove all active pieces from puzzle
  746.             while (pieces.Count>0)
  747.             {
  748.                 GameObject p = pieces[0] as GameObject;
  749.                 // create pieces array and positions
  750.                 pieces.Remove(p);
  751.                 piecePositions.Remove(p.name);
  752.                 p.active = false;
  753.                 // add piece to cache for re-use
  754.                 p.transform.parent = pieceCache.transform;
  755.             }
  756.         }
  757.        
  758.         // determine topleft piece x and y line
  759.         int tpX = System.Convert.ToInt32(topLeftPiece.Substring(1, 1));
  760.         int tpY = System.Convert.ToInt32(topLeftPiece.Substring(0, 1));
  761.         int bX = tpX;
  762.  
  763.         int idX = 1;
  764.         int idY = 1;
  765.        
  766.         // loop vertical rows of the puzzle
  767.         for (int y = 1; y <= size.y; y++)
  768.         {
  769.             // loop horizontal columns of the puzzle
  770.             for (int x = 1; x <= size.x; x++)
  771.             {
  772.                 // get piece type of current position
  773.                 string pType = GetType(new Vector2(x, y));
  774.                 // check if specific piece was created earlier
  775.                 GameObject puzzlePiece = piecesLookup["" + tpY + tpX + pType+ "-" + idX] as GameObject;
  776.                 if (puzzlePiece != null)
  777.                 {
  778.                     // puzzlePiece was created but can not be active, if so we have to increase the piece identifier index
  779.                     // to find an inactive created piece
  780.                     while (puzzlePiece!=null && puzzlePiece.active == true)
  781.                     {
  782.                         idX++;
  783.                         puzzlePiece = piecesLookup["" + tpY + tpX + pType + "-" + idX] as GameObject;
  784.                     }
  785.                 }
  786.                 if (puzzlePiece!=null)
  787.                 {
  788.                     // a created piece has been found that can be used
  789.                     puzzlePiece.name = "" + tpY + tpX + pType + "-" + idX;
  790.                     // add puzzlePiece to this puzzle's pieces
  791.                     InitPiece(puzzlePiece, new Vector2(x,y));
  792.                     pieces.Add(puzzlePiece);
  793.                     puzzlePiece.active = true;
  794.                 }
  795.                 else
  796.                 {
  797.                     // create a new puzzlePiece
  798.                     puzzlePiece = CreateNewPiece(new Vector2(tpX, tpY), new Vector2(x,y), pType);
  799.                     puzzlePiece.name = "" + tpY + tpX + pType + "-" + idX;
  800.                     if (puzzlePiece != null)
  801.                     {
  802.                         // add puzzlePiece to this puzzle's pieces and to lookup table
  803.                         InitPiece(puzzlePiece, new Vector2(x, y));
  804.                         piecesLookup.Add(puzzlePiece.name, puzzlePiece);
  805.                         pieces.Add(puzzlePiece);
  806.                     }
  807.                 }
  808.                 tpX++;
  809.                 if (tpX == bX + size.x || tpX == 6)
  810.                 {
  811.                     if (tpX == 6)
  812.                     {
  813.                         tpX = 1;
  814.                         idX++;
  815.                     }
  816.                     else
  817.                       tpX = bX;
  818.                 }
  819.             }
  820.             tpX = bX;
  821.             idX = 1;
  822.             tpY++;
  823.             if (tpY == 6)
  824.             {
  825.                tpY = 1;
  826.                idY++;
  827.             }
  828.         }
  829.     }
  830.  
  831. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement