Search Unity

Question Obj Movement via Mouse (+ particular physics rulles)

Discussion in '2D' started by Rchd, Apr 8, 2021.

  1. Rchd

    Rchd

    Joined:
    Apr 8, 2021
    Posts:
    2
    Greetings,

    I'm working on a 2D Unity puzzle game in which user can drag blocks horizontally with the mouse and place them in correct positions one by one to solve the puzzles in each level. Therefore, I have some fixed-size blocks, each with a



    1- Rigidbody2D (for Gravity stuff in case there is empty space that needs to be filled with another block)

    2- BoxCollider2D (for the sake of Rigidbody2D , and collision stuff)

    3- RayCast2D (to detect distance with other blocks and limit right-side and left-side movements)

    4- Single C# script that controls the movement, collision detection and ...


    For the dragging part, user clicks on a block (MouseDown) and starts dragging (OnMouseDrag). When released (MouseUp), the block Snaps To Grid ( I've attached a GIF file that illustrates both the movement, and the issue which I need help on)

    For the movement part, a block's movement should be limited to available free area on the right and left side. It means that if a block is surrounded by 2 blocks on its right and left side, it shouldn't pass them at all. To do that, I use the Raycast2D functionality that helps me detect collision and limit the movement. Here is the C# script so far :

    Code (CSharp):
    1.  using System.Collections;
    2.     using System.Collections.Generic;
    3.     using UnityEngine;
    4.     using UnityEngine.UI;
    5.    
    6.     public class blockProcess : MonoBehaviour
    7.     {
    8.  
    9.         public Canvas cnv;
    10.  
    11.         [SerializeField]
    12.         private Vector3 gridsize = default;
    13.         [SerializeField]
    14.         Transform castPoint_right;
    15.         [SerializeField]
    16.         Transform castPoint_left;
    17.         [SerializeField]
    18.         Transform castPoint_BottomLeft;
    19.         [SerializeField]
    20.         Transform castPoint_Bottomright;
    21.    
    22.    
    23.         float current_mouse_pos;
    24.         bool is_mouse_to_right = false;
    25.         float current_obj_pos;
    26.         float next_obj_pos;
    27.         bool ismovingRight;
    28.    
    29.         bool isClicked = false;
    30.         Vector2 lastAllowedPos;
    31.    
    32.         public float speed;
    33.         private float mZCoord;
    34.         private Vector3 mOffset;
    35.    
    36.    
    37.         void Start()
    38.         {
    39.    
    40.             gridsize = new Vector3(cnv.scaleFactor, 1, 1);
    41.    
    42.         }
    43.    
    44.         string sideCheck_right_collided()
    45.         {
    46.        
    47.             float laserLength = 0.2f;
    48.          
    49.             Vector2 endPos = castPoint_right.position + Vector3.right * laserLength ;
    50.    
    51.             RaycastHit2D hit = Physics2D.Linecast(castPoint_right.position, endPos,  1 << LayerMask.NameToLayer("Default"));
    52.    
    53.             if (hit.collider !=null)
    54.             {
    55.                return hit.collider.tag;
    56.             }
    57.             else
    58.             {
    59.                 return "";
    60.             }
    61.         }
    62.  
    63.         string sideCheck_left_collided()
    64.         {
    65.    
    66.      
    67.             float laserLength = 0.2f;
    68.             bool val = false;
    69.             Vector2 endPos = castPoint_left.position + Vector3.left * laserLength;
    70.    
    71.             RaycastHit2D hit = Physics2D.Linecast(castPoint_left.position, endPos, 1 << LayerMask.NameToLayer("Default"));
    72.    
    73.             if (hit.collider != null)
    74.             {
    75.                 return hit.collider.tag;
    76.             }
    77.             else
    78.             {
    79.                 return "";
    80.             }
    81.    
    82.         }
    83.    
    84.         bool is_mouse_moving_to_right ()
    85.         {
    86.             if (GetMouseAsWorldPoint().x < current_mouse_pos)
    87.             {
    88.                 return false;
    89.             }
    90.             else
    91.             {
    92.                 return true;
    93.             }
    94.    
    95.         }
    96.    
    97.    
    98.         bool is_obj_moving_to_right ()
    99.         {
    100.             if (next_obj_pos > current_obj_pos)
    101.             {
    102.                 return true;
    103.    
    104.             }
    105.             else
    106.             {
    107.                 return false;
    108.    
    109.    
    110.             }
    111.         }
    112.    
    113.         private Vector3 GetMouseAsWorldPoint()
    114.    
    115.         {
    116.  
    117.             Vector3 mousePoint = Input.mousePosition;
    118.    
    119.             mousePoint.z = mZCoord;
    120.    
    121.             return Camera.main.ScreenToWorldPoint(mousePoint);
    122.    
    123.         }
    124.    
    125.    
    126.         void OnMouseDrag()
    127.    
    128.         {
    129.          
    130.        
    131.             next_obj_pos = transform.position.x;
    132.    
    133.    
    134.             if (sideCheck_right_collided()=="" && sideCheck_left_collided() == "")
    135.    
    136.              
    137.             {
    138.    
    139.                 lastAllowedPos.x = 0;
    140.    
    141.                 Vector3 ss = new Vector3(GetMouseAsWorldPoint().x, transform.position.y, GetMouseAsWorldPoint().z);
    142.    
    143.    
    144.                 transform.position = Vector3.MoveTowards(transform.position, ss, speed * Time.deltaTime);
    145.    
    146.    
    147.    
    148.             } else
    149.             {
    150.    
    151.    
    152.                 lastAllowedPos = new Vector2(transform.position.x, transform.position.y);
    153.    
    154.    
    155.                 if (sideCheck_right_collided()!="" && sideCheck_left_collided() == "") {
    156.    
    157.    
    158.                     if (GetMouseAsWorldPoint().x < lastAllowedPos.x && lastAllowedPos.x >0)
    159.                 {
    160.    
    161.              
    162.                         Vector3 ss = new Vector3(GetMouseAsWorldPoint().x, transform.position.y, GetMouseAsWorldPoint().z);
    163.                         transform.position = Vector3.MoveTowards(transform.position, ss, speed * Time.deltaTime);
    164.                
    165.              
    166.                 }
    167.                 }
    168.    
    169.                 if (sideCheck_right_collided() == "" && sideCheck_left_collided() != "")
    170.                
    171.                     {
    172.    
    173.      
    174.                     if (GetMouseAsWorldPoint().x > lastAllowedPos.x && lastAllowedPos.x > 0)
    175.                     {
    176.    
    177.    
    178.                         Vector3 ss = new Vector3(GetMouseAsWorldPoint().x, transform.position.y, GetMouseAsWorldPoint().z);
    179.                         transform.position = Vector3.MoveTowards(transform.position, ss, speed * Time.deltaTime);
    180.    
    181.                     }
    182.                 }
    183.             }
    184.     }
    185.     }
    186.     }
    187.  
    188.         private void OnMouseDown()
    189.         {
    190.             isClicked = true;
    191.          
    192.    
    193.             current_obj_pos = transform.position.x;
    194.    
    195.             current_mouse_pos = GetMouseAsWorldPoint().x;
    196.    
    197.             Rigidbody2D rd2 = GetComponent<Rigidbody2D>();
    198.             rd2.gravityScale=0;
    199.    
    200.    
    201.             mZCoord = Camera.main.WorldToScreenPoint(
    202.             gameObject.transform.position).z;
    203.             mOffset = gameObject.transform.position - GetMouseAsWorldPoint();
    204.      
    205.    
    206.         }
    207.    
    208.         private void OnMouseUp()
    209.         {
    210.             isClicked = false;
    211.      
    212.             current_mouse_pos = 0;
    213.    
    214.             Rigidbody2D rd2 = GetComponent<Rigidbody2D>();
    215.             rd2.gravityScale = 1;
    216.    
    217.             SnaptoGrid();
    218.    
    219.         }
    220.    
    221.         private void SnaptoGrid()
    222.         {
    223.          
    224.             var position = new Vector3(Mathf.Round(this.transform.position.x / this.gridsize.x) * this.gridsize.x,
    225.            transform.position.y,
    226.            transform.position.z) ;
    227.    
    228.             this.transform.position = position  ;
    229.         }
    230.     }
    231.    

    Now, the issue:
    As you can see in the GIF attached, If user drags the block normally (with normal reasonable speed), it works like a charm. BUT, when he drags it fast, blocks overlap each other visually and if the dragging
    is much faster, the Snap To Grid functionality places the moving block in wrong position (pushing another blocking block to the above position and place the moving block under it).
    I tired testing with different mouse dragging speeds (like 100,35,50 and ...); the less the value, the better the result, but still not Perfect!. I can't decrease the speed as much as I want, because with values less than 50, it affects dragging quality (block moves slower that the mouse). I need the dragging speed to be as fast as the mouse movement.


    What would be your approach to solve the issue? any fix to my code ? I was thinking of using "Input.GetAxis("Mouse X");" in my calculations, but no idea HOW!




    * The CastPoints (Red dots) on the bottom of the blocks are for checking collision with specific area of the ground (These are other rules of the game that do not related to the issue in this thread, so no need to mention more)

    * I don't want to use BoxCollider2D for sides collision detection, because of other rules of the game (In a nut shell, I need to check below part of each block, If it isn't empty then It can move around)


    Thanks for your attention.
     

    Attached Files: