Wednesday, August 20, 2014

Making the NPC

For the purpose of this tutorial, let's copy the player sprite and just change the tint to something else. Like red. This will be our NPC.

Drag the player sprite to your hierarchy and name the new GameObject as First NPC. Or anything you like. Now, select the object and change its tint from the inspector:

Now we need to give the NPC a tag. In the top of the inspector click the box that says Tag and add a new tag called "npc":

Don't forget to select your npc GameObject again and assign that tag to it.

Scripting the NPC

Next create a new interface called NPCinterface (just create a new C# script and remove everything in it, then write the interface):

1
2
3

publicinterfaceNPCinterface{voidExecuteAI();}

This is where you can define methods for the NPC that can be used from other scripts. Next create another script and call it NPCController. This will be our abstract class that all NPC inherit from. We can define common methods in this class:

You will get some errors because pos and moving are not defined but we will do that next. Notice that we added NPCController here instead of MonoBehaviour (because MonoBehaviour is implemented in NPCController already).

Go back to your NPCController script and add these properties:

protectedVector2pos;protectedboolmoving=false;

Protected means these properties will be accessible to the child objects (in this case our FirstNPC script). Next add this piece of code to the ExecuteAI -method:

intdirection=Random.Range(1,5);if(direction==1){pos+=Vector2.up;moving=true;}elseif(direction==2){pos+=Vector2.right;moving=true;}elseif(direction==3){pos-=Vector2.up;moving=true;}elseif(direction==4){pos-=Vector2.right;moving=true;}else{;// do nothing}

In this script, first we get a random direction. We have 4 directions so the range starts from 1 and goes up to 5 (the range starts from 0 so the fifth element is actually 4) . We then set the position depending on this random direction. The Update -method in our FirstNPC class will handle the actual moving.

So... how do we call the ExecuteAI? Our player object is the center of attention in this type of game, the turns are pretty much dependent on what the player does. So let's open up our PlayerController -script and do some changes.

OK, our game only has 1 NPC but let's look to the future and determine that there will be more. Add these properties to the PlayerController -script:

privateGameObject[]npcObjects;privateNPCController[]npcControllers;

In the Start() -method, add these lines:

// Find all NPCs with the tag "npc":npcObjects=GameObject.FindGameObjectsWithTag("npc");npcControllers=newNPCController[npcObjects.Length];// Iterate through them and store their NPCController to// npcControllers array:for(inti=0;i<npcObjects.Length;i++){npcControllers[i]=(NPCController)npcObjects[i].GetComponent(typeof(NPCController));}

The code comments describe what this code snippet does. Next let's do a convenience method called ExecuteNPCAI where we iterate through the npcController array and execute the AI for each NPC:

usingUnityEngine;usingSystem.Collections;abstractpublicclassNPCController:MonoBehaviour,NPCinterface{protectedVector2pos;protectedboolmoving=false;publicvoidExecuteAI(){intdirection=Random.Range(1,5);if(direction==1){pos+=Vector2.up;moving=true;}elseif(direction==2){pos+=Vector2.right;moving=true;}elseif(direction==3){pos-=Vector2.up;moving=true;}elseif(direction==4){pos-=Vector2.right;moving=true;}else{;// do nothing}}}

usingUnityEngine;usingSystem.Collections;publicclassPlayerController:MonoBehaviour{privateVector2pos;privateGameObject[]npcObjects;privateNPCController[]npcControllers;privateboolmoving=false;voidStart(){// First store our current position when the// script is initialized.pos=transform.position;// Find all NPCs with the tag "npc":npcObjects=GameObject.FindGameObjectsWithTag("npc");npcControllers=newNPCController[npcObjects.Length];// Iterate through them and store their NPCController to// npcControllers array:for(inti=0;i<npcObjects.Length;i++){npcControllers[i]=(NPCController)npcObjects[i].GetComponent(typeof(NPCController));}}voidUpdate(){CheckInput();if(moving){transform.position=pos;moving=false;}}privatevoidCheckInput(){// WASD control// We add the direction to our position,// this moves the character 1 unit (32 pixels)if(Input.GetKeyDown(KeyCode.D)||Input.GetKeyDown(KeyCode.RightArrow)){pos+=Vector2.right;moving=true;ExecuteNPCAI();}// For left, we have to substract the directionelseif(Input.GetKeyDown(KeyCode.A)||Input.GetKeyDown(KeyCode.LeftArrow)){pos-=Vector2.right;moving=true;ExecuteNPCAI();}elseif(Input.GetKeyDown(KeyCode.W)||Input.GetKeyDown(KeyCode.UpArrow)){pos+=Vector2.up;moving=true;ExecuteNPCAI();}// Same as for the left, substraction for downelseif(Input.GetKeyDown(KeyCode.S)||Input.GetKeyDown(KeyCode.DownArrow)){pos-=Vector2.up;moving=true;ExecuteNPCAI();}// Then change the transform to the new position with// the given speed:}privatevoidExecuteNPCAI(){foreach(NPCControllernpcinnpcControllers){npc.ExecuteAI();}}}

Monday, August 18, 2014

I checked some outdated tutorials how to change the default system mouse cursor in Unity but it lagged considerably. So I searched the Unity manual (now why didn't I check there first?). However, I couldn't get this working right away and wondered what was wrong, until I took another look at the inspector. When you're importing your cursor, select the Cursor from the Texture type in the inspector:

CursorMode.Auto means the hardware mouse acceleration will be used on platforms that support it. The hotspot is like the offset location of the cursor. In this case the tip (at 0,0) is the effective part of the cursor.

Next, drag the cursor texture from the Assets to the Cursor Texture field in the object's script:

On Mac, I couldn't get the cursor showing in the editor while testing. Building and running worked fine though.

You'll notice the difference in higher resolutions in fullscreen mode.

Also, if you didn't do it before, select the player sprite from your assets and in the inspector, change the Filter Mode to Point and hit Apply. This will make the sprite look like it's meant to look:

Lighting the map

To add some dynamic lighting to our map, create a new material in the assets. Like so:

In the inspector, change the shader to Sprites/Diffuse:

Now select the map from the hierarchy (the object with grass grid) and in the inspector, change its material to this new material:

You can add the material to anything you want to be affected by light but let's leave the player sprite alone for now because he's always illuminated. The player sprite might disappear after you add the material, so bring him up by adjusting the Order in Layer (or adding another sorting layer for the player altogether):

Next, add a new point light from the GameObject / Create Other menu:

You must adjust the light so it shows on the scene. In the hierarchy window, drop the light object to the player object (this will make it the player object's child and it will follow the player). Also use the arrows on the light object to move it to the center of the player object:

Change the light object's Z-value to something negative to make it show on the map. The higher the number (to negative), the farther the light goes from the player. Set it to -1.5 for now. You can experiment with it for better results.

You can also move the light in the Z-axis in 3D mode. Just click the little 2D button on top of your scene window to toggle the mode.

To make it really dark, like night time, change the ambient lighting from Edit / Render Settings:

usingUnityEngine;usingSystem.Collections;publicclassCamController:MonoBehaviour{publicGameObjecttarget;// The playerprivateVector3offset;voidStart(){// Change the z value of the offset// to something below the sprites.// Otherwise you can't see anything:offset=newVector3(0f,0f,-10f);}voidUpdate(){}// Let's put the movement in LateUpdate (called after Update function)voidLateUpdate(){// Change camera's position to the same as the player (with the z-value of -10)transform.position=target.transform.position+offset;}}

Now drag the script to the Main Camera -object in the hierarchy view. In the inspector, scroll down to Cam Controller (Script) component and set the target by clicking the small circle:

CamController in Main Camera object

Go back to PlayerController script and change the speed to something higher, like 50 to make the movement snappier.

DISCLAIMER: This is my tutorial of making a really simple RPG or roguelike with Unity in 2D mode. I'm not a professional Unity developer (just picked it up) and I'm prototyping as I go. Feel free to comment some good practices.

Setting up the project

Then start your new project normally (in 2D mode), let's call it RPGTutorial. Now I made a really simple 32 x 32 pixel square character for this purpose and imported it to Unity:

The character

Drag the character to Assets in Unity project

Then use the inspector (click the player sprite) and change the pixels to units to 32 and hit apply:

Then, for prototyping purposes I made a grid background (you will probably make the level with a tile based editor but for this purpose, I just quickly whipped up a single image and imported it to Unity):

Background

Also change the pixels to units to 32 for this asset, then drag it to the scene. Also drag the player sprite on top of the grid like so:

Scene view

Change the transform X and Y in the inspector to 0 (zero) for the grid to center it. For the player change the X and Y to -3.5 to put it in the corner.

Scripting

Create a new C# script in the assets and name it PlayerController. Edit the file like so:

usingUnityEngine;usingSystem.Collections;publicclassPlayerController:MonoBehaviour{privateVector2pos;privateboolmoving=false;voidStart(){// First store our current position when the// script is initialized.pos=transform.position;}voidUpdate(){CheckInput();if(moving){// pos is changed when there's input from the playertransform.position=pos;moving=false;}}privatevoidCheckInput(){// WASD control// We add the direction to our position,// this moves the character 1 unit (32 pixels)if(Input.GetKeyDown(KeyCode.D)||Input.GetKeyDown(KeyCode.RightArrow)){pos+=Vector2.right;moving=true;}// For left, we have to subtract the directionelseif(Input.GetKeyDown(KeyCode.A)||Input.GetKeyDown(KeyCode.LeftArrow)){pos-=Vector2.right;moving=true;}elseif(Input.GetKeyDown(KeyCode.W)||Input.GetKeyDown(KeyCode.UpArrow)){pos+=Vector2.up;moving=true;}// Same as for the left, subtraction for downelseif(Input.GetKeyDown(KeyCode.S)||Input.GetKeyDown(KeyCode.DownArrow)){pos-=Vector2.up;moving=true;}}}

Save the script and drag it from the assets to the player object in the Hierarchy view. Hit play and test the movement with WASD keys.

Sunday, March 2, 2014

First things first, Zunyrook the Sci-Fi RPG is doing well. I have developed a dialogue system which is still quite naive but we're getting there. I also experimented with GameMaker Studio on how it could improve my productivity. I cooked up the same basis for the game in a week so it promises well. However, optimizing the game can get tricky the more areas I add so I must now make pros and cons and choose whether I want to continue with LibGDX or GameMaker. I kinda like them both but from a different perspective.

During February I also published my first game. I made it while I was learning the GameMaker interface so it's really simple and a clone of millions of similar games. The idea was to test the publishing process, advertisement, feedback, etc.

I put it in the models.journal package to keep everything organized. The journal at this stage is pretty simple, we will deal with the UI in another class. Here we will make an Array of the Quest class. You could add a Quest to the array by calling getQuests().add() but I made a convenience method for readability.

The class is pretty self explanatory if you know Java or other object-oriented languages already. The attribute priority is used in sorting. And attribute finished is also used to move the quest to the "Done Quests" -tab in the UI.

We can now add some test quests to the Journal from the Player class.

Player.journal.addQuest(newQuest("Clear the basement","The basement is filled with rats, you must clear them or this is not considered RPG",1));

Since the journal in the Player class is static, we must access it like that. This would be the initial quest that shows in the player's journal, with title, description and the 1st priority.

Saturday, February 8, 2014

This case study is much like a personal journal I'm writing while
programming the engine for a turn based role playing game. It is not a tutorial but I hope you will find it useful nonetheless.

I'm using LibGDX as the framework (programmed with Java), Tiled as the map editor and some placeholder graphics I made. The project loosely follows MVC pattern as explained in The MVC pattern tutorial by Tamas Jano.

DISCLAIMER: I'm prototyping as I go so some design choices and practices are not the best ones. Feel free to comment. :)

Where to start

Building a turn based role playing
game is as complex as you make it. That's why I keep it simple for now. I
start with the Player class that will grow with these articles. To
follow the MVC pattern, I place it in the models package.

Stats

RPG characters must have stats; hit points, attack, etc. so let's give them to our Player:

packagecom.atsiitech.rpg.models;publicclassPlayer{privateStringname;privateinthpMax;// Maximum amount of hitpointsprivateinthitpoints;// Current amount of hitpointsprivateintattack;// Could be also damage, base attack }

I'm omitting the other stats for now because this is a prototype. You should initialize them in the constructor.

RPG characters usually have an inventory and journal as well so let's create instances of those and implement them later.

I made them static so they are accessible to the game engine. That way we avoid passing the player as a reference back and forth. It's an issue to debate about but after a lot of spaghetti code I decided to do it like this.

Sprite

Nothing new here if you already know what it is. We just instantiate a new Sprite with a texture found in the assets/data folder in the Android project of LibGDX. We'll change this into an animation later on but it could be a static image too if that is what you fancy.

Positions

The position -attribute is the one that we use to draw our sprite on the screen and locationOnMap is used for calculating collisions and other map-related data. Facing is an enumerator that we will implement next. It basically just tells what way our character is facing.

Enums

For the facing we will create Facing.java file. I like to keep them in the models.enums package like so: