Thinking in graphs

So in my game, I added code to my cursor class so that it does a little bit more than move around and do nothing. I added some functions to trace the expected path that the character will take. However, I want it to act more intelligently rather than rely on the player to select each step. And there is this additional problem.

2018-07-25_1647

That’s right, I need to figure out how to maneuver around obstacles that the character shouldn’t be able to walk through. Pathfinding in general, is a topic that I don’t know very much about. And from initial research into the topic, I’ve learned that it requires that I view my map differently. Rather than just (x,y) coordinates, there is a mathematical concept called a graph which is used to model relationships between the locations. The terms used are nodes which represents locations and edges which are the connections/paths between the locations.

squares

Taking that information and translating it into code that actually does something is a bit overwhelming. So the first step for me is to take a square grid and figure out how to turn that into a graph. Here is my grid. The problem to solve is: Where are the connections?

Doing this in Unity is overkill for a problem like this and having to manage game objects seems like it would be distracting. So instead, I’m doing my research in Java.

The class ends up being simpler than I expected. Essentially all I need are an x and y variable that specify where they are and a list of objects of itself representing the different connections. Then I just add all the nodes to  a static list and build the connections with a for loop and similarly print by referencing the node from the static list.

So for instance this

</pre>
<pre>for(DemoGraph d : nodes)
        {
            d.addConnections();
            d.printConnections();
        }

Will output to 2018-07-25_1715


	

Getting started on the battle system

So green tiles on a screen isn’t a game. So my latest goal is to start working on the battle system. What I’m going for is a turn based tactical system similar to a fire emblem game but with more damage and generally shorter engagements. For that I will need a cursor to control where the player moves. This is the progress so far.

2018-07-21_2040

Looks pretty much the same…

Well sort of. I added a cursor (the black square) and a few UI elements that I will utilize shortly, but most of my changes are with the code that isn’t visible. All in all, I’ve rewritten a good chunk of my scripts so far.

I’ve added a game manager. In Unity it seems pretty common to have a game manager with a static version of itself. I utilized that technique for my game manager and its helps getting an easily reference game object to tie the rest of your game onto. But, I’m a little wary of overusing something like that. I think keeping things organized is important, and having a lot of those static objects floating around just because they are convenient doesn’t seem like a good idea.

With that in mind, I changed my entity manager from a static instance to a member of the game manager. My concept is simply its role to manage the list of entities, and I created a second manager called the battle manager to facilitate a turn based battle system.

Those changes broke pretty much everything that I had previously written. While I think the end result was worth it. I should probably be better at planning and not just “write code”.

Refining player movement

So now that my changes to the background tiles went through, the next thing I want to work on is to add some animation to the player movement.  There are a couple things I need to change in order to make it work. First, I needed to make some more sprites for the animation. I’m still not an artist so am utilizing programmer art once again and the animations are a animated arrows pointing in the direction of movement.

player_animations

Second,I need to smooth out the movement. Right now players basically teleport from one square to another. So I need to change from editing the position to using the translate method.

The reason I did not originally use translate was the code ensuring the sprite stopped at the point I wanted was more complex. But I felt like now was a better time to try and tackle it. So here is my new move function.

 


 protected IEnumerator SmoothMovement(Vector3 destination)
{
while(Vector3.Distance(transform.position, destination) > 0)
{
transform.Translate((destination - transform.position) * Speed * Time.deltaTime);
if (Vector3.Distance(transform.position, destination) < 0.01)
Move(destination - transform.position);
yield return null;
}

EnablePlayerInput = true; // Input was disabled when input was collected
}

As evident by the IEnumerator type, The new movement function is what Unity calls a Coroutine. It works by moving a small distance to each frame and fixes itself to the correct location when the distance is less than 0.01. I don’t know if I really like the last part, but for now it is working well enough.animated

Lastly I added the new sprites and animation clips into. Here is the sprite at rest on the left and a move right animation on the right.

 

Getting fancy with tiles

So far I have drawn the background using sprites that were set as public variables. It was convenient for getting things to work fast. However there are things that I don’t like about it.

Managing the sprites manually in Unity sounds really tedious to me with all the clicking and dragging. Furthermore, I’m not working with final assets right now so I expect my tileset to change. So I feel an incentive to  write code that does the boring part for me.

In fact, I want to minimize the work of adding new tiles as much as possible. Its with that desire in mind that I came up with my new scheme for handling the tilesmaps. It works like this:

  1. I created a new class called TerrainData. This new class only holds 3 bits of data: An identifier, the sprites index on the spritesheet, and if it collides with the player (example being water)
  2. In the Tilemap Manager I added a dictionary of TerrainData and filled the dictionary from a JSON file with all my data on my sprites.
  3. From the dictionary I created another collection of Tiles with all the correct sprites and if any of my tilemaps need a tile they can easily pull a reference to it.

Overall, I got all of that working and I’m pretty satisfied with how its going. I’m fully anticipating some unanticipated problems to crop from it that I need to fix. Also spent a good hour on a bug where everything compiled fine but on closer inspection the problem was hiding in plain sight. It’s in the section below.


public void AddPrototype(string key, TerrainTile tt)
{
if (prototypes.ContainsKey(key) == false)
{
prototypes.Add("key", tt);
}
else
{
Debug.Log("Invalid Prototype");
//throw new ArgumentException();
}
}

 

Working with tiles and managing players

So with basic collision detection added, I started looking at a couple things that involved much more C# scripting than anything I did on the project previously. Anyways here is the latest.

2018-07-12_2048

So what’s different? Well 3 things.

I wanted more tiles on the screen, so I zoomed out. It was fairly simple, just one setting on the camera.

Next, while I found being able to paint tiles onto the screen directly in Unity to be convenient; I wanted to have a little more control over the tiles on the screen. For that I spent time figuring out how to add tiles through scripts. Or, more accurately, straining my eyes on the documentation and banging my head against my desk while missing the completely obvious answers to questions I had. Questions like, “how does one create a tile on the tilemap, if a tile is a necessary parameter?” The answer is, of course, you just create the tile separately and then fix it to the location you want in the tilemap.

So with that figured out, I replaced the old terrain with a 32 by 16 square of grass. All the terrain was created by a script. The code wasn’t pretty and I’ll be revisiting it later to make it better, but instead moved onto the third task.

Previously, my keyboard input directed the object on the screen called player to move it around. However I’m not going to only be controlling that one single player. Like any good rpg game, I want to give keyboard input to other characters. So I added a new class that had a list for all potential characters where I can get references of whichever of them is currently getting user input. To test it, I promoted the npc to Player2 and added a switch player button on the top left to toggle change the active player. It ended up being good practice working with Unity game objects.

Adding tile based collision

My original plan of adding the colliders and letting Unity deal with all the collisions failed pretty miserably the first time. My new plan is to call a function to check if there are any collisions at the destination, and only move if it is clear. In Unity, typically functions called raycasts or linecasts are used. They invisibly extend in the given direction and return any collisions.  After a bit of checking the documentation on linecasts, I wrote a function to validate movement.


protected bool ValidateMove(Vector3 movement)
{
// linecast one unit over in the proper direction. If null return false. Otherwise return true.
float xPos = transform.position.x;
float yPos = transform.position.y;
Vector2 startPoint = new Vector2(xPos, yPos);
Vector2 endPoint = new Vector2(movement.x + xPos, movement.y + yPos);

if (Physics2D.Linecast(startPoint, endPoint))
{
Debug.Log("Blocked - Something is in the way");
return false;
}
return true;
}

There is a problem thought. Turns out that linecasts will return any  collisions from the start point and end point and this includes the box collider surrounding the very object I am moving, so I need to disable it while running the linecast. Here is the second try, accounting for that.


protected bool ValidateMove(Vector3 movement)
{
// linecast one unit over in the proper direction. If null return false. Otherwise return true.
float xPos = transform.position.x;
float yPos = transform.position.y;
Vector2 startPoint = new Vector2(xPos, yPos);
Vector2 endPoint = new Vector2(movement.x + xPos, movement.y + yPos);

// get the objects box collider and disable for the linecast. Reenable after the linecast is complete.
BoxCollider2D box = this.GetComponent();
box.enabled = false;
RaycastHit2D linecast = Physics2D.Linecast(startPoint, endPoint);
box.enabled = true;

if (linecast)
{
Debug.Log("Blocked - Something is in the way");
return false;
}
return true;
}
}

So, I save everything and run it. Voila, my sprite moves around and properly collides with the water, rock and npc. No walking on water or clipping through things. There are a couple things, I can still do to improve the code. For instance, I can direct my linecast to check particular layers in case I wanted to treat collisions differently. An example of that would be if I wanted to let my player push the rock instead of having it block movement (something, I will do eventually). But for now, I’m satisfied with it.

2018-07-11_1443

 

Generalizing movement

While the lack of collision detection is bugging me, I need to tackle one other matter first. My code for moving the player currently looks like this:


public class PlayerController : MonoBehaviour {

void Update () {
if (Input.GetKeyDown("right"))
transform.position += new Vector3(1, 0, 0);
else if (Input.GetKeyDown("left"))
transform.position += new Vector3(-1, 0, 0);
else if (Input.GetKeyDown("up"))
transform.position += new Vector3(0, 1, 0);
else if(Input.GetKeyDown("down"))
transform.position += new Vector3(0, -1, 0);
}
}

Depending on whichever arrow key is pressed, my player will move one unit in that direction. The problem is, instructions how to move is all written directly into the player’s script. It isn’t a big deal right now because its just a transform.position statement(one line of code), but I’m going to be adding stuff to check for collisions before movement and there is nothing really unique about how the player moves compared to anything else. At best its pointless to have the same bits of code in multiple spots and at worst it will become confusing and tedious to make any change to movement because I would need to make the change in more places than one.

So I’d rather have one function for movement to use for multiple different things.  In that case, how will I know that it works?

2018-07-10_1012

I redid the scenario from last time. I added an npc to the bottom right. I’m going to have him move around once every hundred or so frames. Then I’ll have the player move with the keyboard. If both move as expected, then the code does what I want it to do.

In my Java prototype I did that by making a parent class called Entity where the move function existed and was available for anything that needed to move. The solution here is essentially the same.


public abstract class Entity : MonoBehaviour {
protected void Move(Vector3 movement)
{
transform.position += movement;
}
}

Having the Entity class as an abstract class was advantageous in my Java prototype, so even though the one here doesn’t need to be abstract to work, I still went ahead and made it one. The code is not going to know (or care) that the movement is originally from keyboard inputs, so I’m just asking for the direction of movement.

Then all I need to do is change the class for Player to inherit from Entity, and make it use the new Move function. I decided to go one step farther and move all the Keyboard stuff onto a separate function which is called from update.

<blockquote>void KeyboardInput()
{
if (Input.GetKeyDown("up"))
Move(new Vector3(0, 1, 0));
else if (Input.GetKeyDown("down"))
Move(new Vector3(0, -1, 0));
else if (Input.GetKeyDown("left"))
Move(new Vector3(-1, 0, 0));
else if (Input.GetKeyDown("right"))
Move(new Vector3(1, 0, 0));
}</blockquote>

Lastly, I saved everything and hit the play button. The npc is running around in circles as expected, and my player moves around according to my commands.