Search Unity

Simple square movement and a more complex question

Discussion in 'Getting Started' started by theodor1289, Feb 8, 2016.

  1. theodor1289

    theodor1289

    Joined:
    Feb 8, 2016
    Posts:
    13
    Hi there, guys ! I am quite new to object oriented programming and I was wondering if you could help me out with some kind of advice. Yes, I know I can find a lot of resources such and tutorials and books related to this and no, I am not telling you to build me exactly what I am asking, for I have proven below that I'm not a lazy person, who asks for efficient solutions, by providing my own, most probably inefficient ones. What I'm asking is that you merely provide an idea/ maybe some C# code related to what I'm about to ask. Good, now that we got that out of the way, let us begin.

    I am accustomed to C++ procedural oriented programming ( I have not finished high school yet, but I do understand basic techniques such as backtracking, graph theory and its applications - Breadth First Search, Depth First Search etc., Divide et Impera etc. and how to dynamically allocate and use memory - though I heard C# doesn't have this ) and therefore what I'm asking seems painfully hard for me to implement and probably is shockingly easy for you guys.

    So let me finally get to the point:

    Firstly, I'm trying to make a 10x10 red square move on the screen ( or Game Screen, unity's way of showing me what the player sees ) in the - let's say - following way:




    Yes, that's about it. I have made the square in Photoshop ( simple ) and I can imagine quite some possible solutions, such as setting point destinations like in this video:

    but I hardly believe they are optimal. I am interested in the optimal way of solving the problem.

    Secondly, I am looking for a way of changing the square's color every - let's say - three seconds. My procedural logic strikes again and makes me think about the following solution:
    • I create two objects - Sprites. One for the red square and another one for the blue square. The blue square follows the path just like the red square and moves in the same exact position, only that it is not visible ( I do no call the draw methods ).
    • In the Update method whenever the game time divides exactly by three I alternate: I make the red one invisible ( by not drawing it ) and the blue one visible and the exact opposite.
    Is this the best solution?

    Thirdly, this is the big question. Let's pretend we have a matrix with walls - four walls defining a room. The square can go through walls. When the user touches the screen, white pixels spread from the red square and cover the current room. Hand drawn picture below:



    How on Earth would one do it ? I again came with a personal solution:
    I somehow? implement this matrix. I use the Lee Algorithm - also known as a Breadth First Search in graph theory - where every matrix element is a vertex. I use it starting from the location where the square was when the touch happened. From there on, surrounding (squares? does this mean I have to add a square for every vertex??) turn - let's say - white until they hit a wall. Pretty simple to do it in basic C++ logic and utterly impossible for me to do it with C# in visual studio and unity.

    Ok, It took me longer than expected, roughly about two or three hours to write this question in a convenient manner - including the time spent on scanning drawings. I hope you guys understand what I meant, if not you can ask questions and I am more than happy to respond. Thanks for listening to my utter frustrations and I'm looking forward to your responses !
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, first, welcome to the Unity community! You're light-years ahead of most high schoolers, and I'm confident you will go far.

    Let's take these one at a time.

    1. Moving from point to point. Quit looking for the "optimal" way. Instead look for the simplest way that gets the job done. Bonus points if it's a way that you clearly understand. These are the most important criteria: is the code simple, and can you understand it? If so, then you have found the optimal way for you.

    I can tell you how I would approach it, if you like, but what's optimal for me may not be optimal for you.

    2. Changing sprite color. Here you probably have missed a very handy trick or two. Unity sprites have a "main color" that is mixed with the color of each pixel. So if you design your sprite in white (or shades of gray), then you can make it appear any color you want just by changing the sprite color. For example:
    Code (CSharp):
    1. GetComponent<SpriteRenderer>().color = Color.red;
    3. Pixel flood. This is hard to do in Unity out of the box. It's not really designed for pixel-level operations. But that's why I made PixelSurface, which makes this sort of thing quite easy.

    Good luck, have fun, and feel free to ask questions when you have 'em!

    - Joe
     
    theodor1289 likes this.
  3. theodor1289

    theodor1289

    Joined:
    Feb 8, 2016
    Posts:
    13
    Ok, needless to say I am very thankful for your quick response. Problem number 2 has been solved right away.

    I am sorry for misguiding you.
    On the one hand I had used the words 'optimal' and 'best' only because I am actively participating in informatics contests and therefore, when speaking about that, what is easy to implement is almost always a bad choice in means of time use. So ignore these, I am interested in simple, understandable ways of making the square move as presented above.

    On the other hand, I had also used the word 'pixels' wrong. I do not want individual pixels to turn white, but similar 10x10 squares. What is my newest solution then? I thought about creating white squares efficiently ( which are momentarily invisible - maybe by setting the Z coordinate behind the background?) in a 5x5 matrix in the following way: (example in pseudo code)
    for(int i=0;i<5;i*=10)
    for(int j=0;j<5;j*=10)
    {
    create WhiteSquare;
    set WhiteSquare location(x,y) = location(10*i, 10*j);
    }
    Then I simply modify their Z to be in front of the background in sequence by using BFS on the matrix starting from the location of the red square when screen has been touched.
    Is this the simplest way to do it? If not, could you tell me what would it be? Thanks!
     
  4. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    Even if your squares are 10x10 pixels or larger, PixelSurface would still be the easiest and most efficient way to do it. (You can zoom in on a PixelSurface as much as you want — the elements don't need to correspond to actual pixels. It's technically a texel surface.)

    But I understand that PixelSurface is an asset, and there may be good reasons you can't use it for your project.

    In that case, the next simplest solution (though far less efficient) would be to make a 2D array of sprites, which I think is what you're suggesting above. You'll need references to these in code, which is easiest if you actually create them in code; you should do that by instantiating a prefab for each cell in the array.

    But I don't recommend you show/hide sprites by mucking with their Z value. Simple activate/deactivate them (by calling SetActive). Or, if there is some reason you need them to remain active (so that their scripts run) but still be invisible, then you can do GetComponent<Renderer>().enabled = false (or true) to disable/enable just the renderer (which is what actually draws them on screen). (EDIT: Or, you can just set their SpriteRenderer color to Color.clear!)

    For the algorithm to decide which squares to show, this wikipedia article might be helpful.
     
    theodor1289 likes this.
  5. theodor1289

    theodor1289

    Joined:
    Feb 8, 2016
    Posts:
    13
    Wow, you surely are helpful! I can't really afford the asset for now, but I am going to download the demo for 'High Frontier' haha:)

    Problem three has been successfully solved thanks to you ! Only that I'm not using a flood algorithm ( that would not perpetuate squares in waves ), but this https://en.wikipedia.org/wiki/Lee_algorithm .

    Lastly, how do I make the square move according to the path in the first drawn picture ( from point to point ) ? He has to continually follow it, not stopping if starting point is reached again. I assume this is pretty simple to do, but I obviously am lacking something.
     
  6. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, for that I would make a list of waypoints. The simplest way to do this is to just make a public array of Vector3's in your script:
    Code (CSharp):
    1. public class Patrol : Monobehaviour {
    2.     public Vector3[] waypoints;
    3.     ...
    Now when you inspect an object with this script on it, you'll see this array in the inspector, and be able to set each of the waypoints there.

    To go to a waypoint, you'll use Vector3.MoveTowards. When you reach a waypoint, you'll go on to the next one, wrapping around back to 0 when you get to the end. Something like this (untested) code:
    Code (CSharp):
    1. public class Patrol : Movobehaviour {
    2.     public Vector3[] waypoints;
    3.     public float speed = 1;        // speed in units/second
    4.     int targetNum;
    5.    
    6.     public void Update() {
    7.         // move towards the current target
    8.         Vector3 pos = transform.position;
    9.         transform.position = Vector3.MoveTowards(pos, waypoints[targetNum], speed * Time.deltaTime);
    10.        
    11.         // if we reach it, go on to the next one
    12.         if (transform.position == waypoints[targetNum]) {
    13.             targetNum = (targetNum + 1) % waypoints.Length;
    14.         }
    15.     }
    16. }
    I'm using the % (mod) operator here to wrap around back to 0 when we get as large as the length of the array.
     
    theodor1289 likes this.
  7. theodor1289

    theodor1289

    Joined:
    Feb 8, 2016
    Posts:
    13
    Sweet ! Thank you.