Rise: Lighting, Textures and the VR experience

Hi All,

Okay, so where am I? There is some early texture work in there, experiencing some FPS drops and with the procedural generation in the map it means some of the one way textures are a little off. I need a perfect square texture, which is identical from all four sides, and I can use that to replace the current floor. Aside from that I think it looks pretty good! Next, there is the lighting, real time lighting looks good, although it’s difficult to see from the gif below, there is a full blown torch in effect, and a pistol in the right hand. This is my working inventory that needs to be expanded. Next comes the sound, which needs a lot of work. My pistol currently sounds like a firework! (The only sound I had at the time), so I think a few new sounds are needed!

Finally, the AI, when it works, it’s fantastic, but it’s sporadically bad. I mean, nine out of ten times it’s amazing, but that one in ten time when you realise that the zombies are “special” and just moonwalk on the spot means that I need to do some tweaking!

Well, given where I started ten days ago, and taking into consideration that my pc decided to die right in the middle of the ten days, I don’t think the final result is too bad. I’m going to continue for the next few days to polish this up into a proper game, and in it’s final form it should have: A torch (see below), a few weapons, a few items, a HUD and a menu.  It’s nice to know how much you can get done in just a few days with perseverance and drive!

The next big goal is to put this out there for others to play, get some feedback, develop and push on with the actual game!

Keep following, more to come!

-H

Rise: PC Issues and Upgrades

Hi All,

So after some severe PC issues and being relegated to my laptop I’m finally back in full flow, so you should see more updates coming. For whatever reason my graphics card died, and I’ve been relegated to using an R9 290x for VR development, which is a little clunky, but works well when I need it too!

My fear is that this card is also on it’s way out and I’m not sure if I should pick up a 1080, wait for Vega, or see what the announcement is on the 1080ti, but only time will tell, for now I’m just going to press on, and get what I can done!

So, four days to go, and this morning has been about updating Unity, and all my projects to 5.5.2, then updating my graphics drivers, and finally updating the steamVR plugin.

Back to work,

more coming soon!

-H

Rise: Combining everything together

Hi All,

It’s been a while since the last post, but trying to wrap everything together into a working Alpha, and iron out all of those pesky bugs is a nightmare. As I’m becoming more familiar with Unity, I’m learning little things like not throwing exceptions in the final build (as it’s script) and instead just running but being a little buggy. Just to clarify, this is not on Unity’s behalf, this is completely my own undoing. Now, moving on, what have I been doing? Well, tying everything together, the procedural generation, the player, the pathfinding and a few other bits to try and get to a point where I can actually see a game starting to form. (There’s no motivation like progress!!!)

So, where is it, well here:

I think it’s looking pretty slick! The AI path nodes are editor only and disappear in the full build, which s pretty awesome, and the path joins are seamlessly working now, so once a Zombie see’s you, it’s going to chase you until you either lose it, or it doesn’t hear you anymore.

Also, the procedural AI paths are working nicely, meaning that there are no breaks in the pathway. Although, I’d like to do something a little smarter, and get group AI in there.

A taste of what is to come:

Aminated weapons, better environments, procedually spawning weapons and enemies based on distance to player, (e.g. better guns/harder enemies pending on where you are), functioning doors,  and different classes of NPC.

It’s going to be a busy week.

-H

Rise: Focussing on AI development, sound awareness and pathfinding

Hi All,

Right, next steps, getting in pathfinding, and making sure that sounds is as important as I want it to be.

So what did I do? Simple, I created my own sound emitter script, which instantiates an Audio object, and is called instead of the audio object whenever I want something to emit noise that Zombies will here. The final setup looks like this:

Now, this is a little confusing, as how do the Zombies hear? Well, this is where the AI starts to get a little more complex, but I’ll take it step by step and hopefully this will all make sense in the end. Right, firstly, pathfinding, the goal is to allow the Zombies to Navigate throughout the corridor/hall/room ridden floor, and be able to attack the player, however I don’t want them just to spawn and start running in the players direction. (Not a wave shooter, repeat, not a wave shooter!) I want them to respond to the sound of gunfire, explosions, or things being thrown or dropped. This should give the player a very simple yet powerful tool to be able to work around having to shoot something, or challenge something head on when they have no ammo. Maybe just throw a can, and have the zombies wander over to it and stare (Maybe attack, but I’m thinking through something that I’ll try and implement later.)

Now, what does A* need to pathfind? Well, nodes of course. Some way of referencing where the path can flow. Now, for my particular kind of path I’ve decided to use large green cylinders. Now, I don’t particularly care what colour they are as they’re going to be removed from the ingame renderer eventually, and as long as I can see them in the editor, I’m good. I set the layer to a new layer called “AIPathNode”, and pass them all into a script which then creates a map of where they all are. Now, whenever the AI needs a path, it can call FindPath(), and the existing node structure is duplicated for that particular AI, and then used to pathFind.

This is my Node, there are many like it, but this one is mine. I shall call him Billy.

Right, this brings me onto my pathfinding exercise, the theory being, spawn enough nodes, pump them into the AI manager, pass that as a parameter to the NPC (Non player character, for those of you not in the know), then pick up a gun, and fire, which will emit a noise, which will then notify the NPC that I’m there, and he won’t know it’s the player until he can see me, then he’ll chase and start attacking. (Breathe!) Now, this is what the setup looks like:

and below is what it looks like when I press play. The red lines are the ray trace from my guns, please ignore them for now, and don’t be offended. The blue is the pathfinding!

Next up, weapon damage (should be an easy win, just need to check the colliding object, see if it is an NPC, the cast and call a damaging function), coming soon.

-H

Rise: Getting the enemy to see and attack the player

Hi All,

After the last little update, I figured that I’d try and link the AI together, meaning that I wanted the Zombies current “ChaseObject” code to expand to include “Chase object then when I get near the object, attack that object”, although damage is not yet included in the demonstration. So, how do I proceed?

Well, news, my HTC isn’t connected to my development PC, it’s in my living room on a different, less powerful machine, and the way I’m testing, and to stop me from getting into the debug every five seconds route, I’ve added a first person character from the Unity default asset set. This works well, as all I really needed to do is add a pseudo controller, map the key bindings to the controller functions, then I have a keyboard controller. A simple trace from the centre of the camera forwards (raycasting), gives me a hit location, and then I create a box with a collision mesh and a hit mesh and call it “Hand”. This is my FPS psuedo vive controller hand. I then created an empty object, attached it to the player camera, and now I can pretty much use the inventory in the same way, albeit with one hand. (I can’t do the two handed stuff I planned on implementing)

Now, what next. Well, with regards to the Zombie, I wanted to do a simple sphere cast every half second (ish) in the forwards direction, and if the sphere cast collides with something called “Player” (No clues to what it’s referencing), then store that GameObject in memory, and walk directly to it’s transform. (No pathfinding yet, that comes later). Then when the Zombie is within a specific range, start attacking. If the player moves away, then stop attacking and start chasing. The pseudocode runs something like this:

float ATTACK_RANGE = 1.2f;

void update()

{

if(hasTarget)

{
DoMove(this.transform, target.transform);

if(DistanceBetween(this.transform, target.transform)  < ATTACK_RANGE)

{

GotoState(Attacking);

}

}

}

the resulting effect is below,

more to follow soon,

-H

Rise: Getting the Inventory and weapons working in VR

Hi All,

Right, I was looking at an old Unity demo project I was working on, looking for the best way to be able to do an inventory for VR, and realised that the majority didn’t work, yet with a little tweaking I might be able to put something together that actually fits.

The problem is this:

Whenever I’ve worked on FPS inventory systems, they are very much “object on the floor is a trigger, when you touch that trigger, make the object appear from the players perspective using a different mesh”. It’s like 101 of the simple inventories to do. Now, how do you do that with VR? How do you compensate for each hand? Do you want to change the mesh when an object is picked up? What about anim states? What about…. What about… *cries*. Seriously though, it’s not as simple as you think, but still a lot simpler than you think it’s going to be.

I started by thinking “Whatever the object is when it’s on the floor, must be the same object when picked up”, this means that the fire mechanism (only talking about weapons for now), must be the same whether it’s on the floor or in the players hand. So a weapon GameObject should be able to be fired if the trigger is pulled from anywhere, now, how to do this in an abstract way that applies to all objects. I figured something like this would work:


BaseObject

{

public abstract PrimaryFire(float deltaTime);

public abstract SecondaryFire(float deltaTime);

public abstract TertiaryFire(float deltaTime);

}

Then depending on the object in the hand, each function would be slightly different. For an apple “PrimaryFire” would eat the apple, for an SMG “PrimaryFire” would, well… fire. This was simple enough, I just needed to add an AudioSource and link it to a gunshot sound, add a simple laser trace (stolen from the SteamVR asset), and when I pick up an object (using the grip button) just transfer that object from the floor into a “GameObject” container, which has a script to call the methods of the script on the inventory item. Simple. :/

Now, once that is all in, I realise that using some methods of Unity to access child objects of transforms are a bit messy, or require knowing the objects name or place in the list of objects in the node, and I stressed thinking about “What if I need to hold two items”, now really, my brain is kind of in overdrive, so once I remembered that I only really need to hold one pistol in the hand, then it started to make a lot more sense. “Special Time”.

I pulled the weapon firing scripts from an FPS I prototyped and plugged them in, including a crappy particle effect and auto fire routine. The effect is pretty cool, although a bit like cardboard as there are no anims or anything in yet.

I also created a “Backpack” GameObject, which is an empty game object, to which I hold a reference in my inventory controller, meaning that I can just drop things in there. The initial idea is to be able to cycle through these objects using the grip buttons, but not sure how much sense that makes. (Seriously though, not enough buttons on the Vive controller!)

So, creating a simple box collider and rigid body on the controller, then doing a “check if it’s hit anything” when I press the grip allows me to identify the object on the floor, move it from the floor to the child node of my controller. All weapons need to face the same way, so I had to give the child transform a rotation of 45 degrees to make sure the guns faced forward.

This is the final result, of which I’m pretty happy:

Next steps are dropping in an Enemy, handling the trace, calling a function to damage the Enemy, then killing the enemy and destroying it. Aiming to get that done after Lunch!

-H

 

 

Rise: Working with VR and Unity3D

Hi All,

So, getting a simple VR rig setup in unity was actually a lot easier than expected. I simply used the Valve SteamVR asset from the Unity store, dropped it into an empty project and it was good to go! Seriously! Checked the Height of the hallways, and width of the rooms in VR just to make sure that they made sense, and below you can see my excitement in actually getting the VR controllers registering.

Although, seriously, plug and play.

Already working on the inventory mechanic, but as many of you probably know, breaking your train of thought to write blog posts is exceptionally difficult!

-H

Rise: The Zombies have risen, picking an enemy.

Hi All,

This is kind of a part past, part present post, as I’m slowly catching up with my posts from last night and my code from this morning. I found the Mocap stuff on the Unity Asset store really awesome, and easy to implement. I played around with the Zombie Starter: Mocap Animation pack, and once I’d got it in and doing some funky things, I switched over to the ZOMBIE PRO: MoCap Animation Pack version for $99! Honestly, it’s been a while since I’ve done anything in 3D, but this definitely seems very cheap for the high quality animations that you get in the store.

First things first, getting the zombies ingame, and getting an anim node setup. Something that’s pretty easy in Unity, as all I did was overwrite the existing mocam_anim set with something a little more spicy! Voila:

From there it was really a case of implementing a basic chase mechanic, adding a CharacterController, and making it walk towards a GameObject. This gives us our basic mechanic of “know where stuff is, then walk in direction of stuff”, this is your generic wave based Zombie shooter mechanic for “See player, walk towards player, attack player when in range”. It looks something like this:

Yes, it’s a shaky video, but I’ve recently just taught myself how to record GIFs (pretty easy actually!)

Also, I just lost about 20 minutes fighting with Godaddy to try and get my upload limit increased from 2M to 8M. FML.

Right, moving on…

-H

Rise: Working on AI, a simple console application

Hi All,

Right, so it was time to get some AI in last night so I needed two major components, firstly I needed some kind of path finding (I’m thinking A*, I’m sure some of you know it), and secondly I need some kind of Zombie in there. So where did I start? With the path finding of course. After digging around in my console toolbox, I found a little gem called “SmartSearch”, something which I thought that I wrote to analyse twitter feeds actually turned out to be a simple A* pathfinding algorithm in C#. (I am that organised!)

Now I hit F5 in Visual Studio and I instantly remember this working, which is awesome, quick look through the project file and realised that this was some of the nicer code I’d written (woohoo, thank you past Hassan!).

Now, after swapping a couple of variables around it appeared that this is working from left to right:

and… top to bottom. I mean, there are no obstacles and my “IsReachable()” method was returning true, so I’m needed to implement that, but generally it works:

It was time to plug it in,

-H

p.s. I’ll post all these little apps when I’m done!

Rise: Creating a world and walking around

Hi All,

Okay, it’s been a while since the last one (lol). So the goal was to actually make a procedurally generated level in Unity, using 3D meshes as “tiles”, now, this basically involved hacking in a bunch of existing BSP code into a Unity project (that had a player character from the unity demo already in there, and was pre-setup for VR). Now, what next? well, we need to tie everything together.

So where did I start? Copy paste, ctrl-c, ctrl-v for the uninitiated, copy and pasting my demo console application into Unity, changing the namespace (I know, time, but really, OCD). Then I just needed to create something to generate a map, convert the tiles to 3D, instantiate them, and place them in the world. Simples.

This is my level class, now I’ll probably post my BSP code at some stage, but I don’t think it’s worth it now. What is good to know is how do you instantiate objects in unity, in a clear concise manner, well as clean as you can be when speed is of the essence.

Not my most majestic code, but its in, and it works!

Next, food break, I’m hungry and a hungry Hassan is not a productive Hassan.

More to come.

-H

Code samples are below, so you can see my shaky hack code. 🙂

 

 

So, this is my Level Setup class:


public class LevelSetup : MonoBehaviour
{
public int MapSize { get; set; }

// Use this for initialization
void Start()
{
CreateWorld();
SpawnPlayer();
}

private void CreateWorld()
{
MapSize = 20;

//this is my BSP Class.
Building br = new Building(MapSize, MapSize);
br.Initialise();
MapTilePlacer mtp = ScriptableObject.CreateInstance&lt;MapTilePlacer&gt;();
mtp.PlaceMapPoints(br);
}

private void SpawnPlayer()
{
GameObject startLocation = GameObject.FindWithTag("SpawnLocation");
GameObject player = GameObject.Find("FPSController");
player.transform.position = startLocation.transform.position;
}

// Update is called once per frame
void Update()
{

}
}

and this is the placer:


class MapTilePlacer : ScriptableObject
{
private const float TILE_SIZE = 8;
private const float TILE_MIDPOINT = TILE_SIZE / 2.0f;
private float _mapSize;
private float _topleftTile;

private int _mapX;
private int _mapY;
GameObject[,] _floorTiles;

MapTileLoader mapTileLoader;

internal void PlaceMapPoints(Building br)
{
mapTileLoader = CreateInstance&lt;MapTileLoader&gt;();
mapTileLoader.LoadTiles();

float xPlacement;
float yPlacement;
this._mapX = br.MapX;
this._mapY = br.MapY;

this._floorTiles = new GameObject[this._mapX, this._mapY];

//this._floorTiles[0, 0] = Instantiate(floorTile, new Vector3(0, 0, 0), new Quaternion(0,0,0,0));

this._mapSize = (TILE_SIZE * br.MapX);
this._topleftTile = (this._mapSize / 2.0f) - this._mapSize;
string mapTileTypeString = "";
for (int y = 0; y &lt; this._mapY; y++)
{
yPlacement = this._topleftTile + (y * TILE_SIZE);

for (int x = 0; x &lt; this._mapX; x++)
{
xPlacement = this._topleftTile + (x * TILE_SIZE);

MapTileTypes mtt = MapStringTypes.GetCurrentMapTileType(br.RoomIndentityMap[x, y]);

switch (mtt)
{
case MapTileTypes.NOTHING:
continue;
case MapTileTypes.FLOOR:
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.FloorTile, xPlacement, yPlacement, 0);// Instantiate(mapTileLoader.FloorTile, new Vector3(xPlacement, 0, yPlacement), new Quaternion(0, 0, 0, 0));
continue;
case MapTileTypes.START_LOCATION:
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.FloorStartTile, xPlacement, yPlacement, 0);//
//this._floorTiles[x, y] = Instantiate(mapTileLoader.FloorStartTile, new Vector3(xPlacement, 0, yPlacement), new Quaternion(0, 0, 0, 0));
continue;
case MapTileTypes.HORIZONTAL_CORRIDOR:
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.HorizontalCorridorTile, xPlacement, yPlacement, 0);//
//this._floorTiles[x, y] = Instantiate(mapTileLoader.HorizontalCorridorTile, new Vector3(xPlacement, 0, yPlacement), new Quaternion(0, 0, 0, 0));
continue;
case MapTileTypes.VERTICAL_CORRIDOR:
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.VerticalCorridorTile, xPlacement, yPlacement, 0);//
//this._floorTiles[x, y] = Instantiate(mapTileLoader.VerticalCorridorTile, new Vector3(xPlacement, 0, yPlacement), new Quaternion(0, 0, 0, 0));
continue;
}

mapTileTypeString = mtt.ToString();

if (mapTileTypeString.Contains("EDGE_DOOR"))
{
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.EdgeDoorTile, xPlacement, yPlacement, 0, mapTileTypeString);
//this._floorTiles[x, y] = Instantiate(mapTileLoader.EdgeDoorTile, new Vector3(xPlacement, 0, yPlacement), GetRotation(mapTileTypeString));
continue;

}
else if (mapTileTypeString.Contains("EDGE"))
{
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.EdgeTile, xPlacement, yPlacement, 0, mapTileTypeString);
//this._floorTiles[x, y] = Instantiate(mapTileLoader.EdgeTile, new Vector3(xPlacement, 0, yPlacement), GetRotation(mapTileTypeString));
continue;
}

if(mapTileTypeString.Contains("CORNER_FULL"))
{
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.CornerTile, xPlacement, yPlacement, 0, mapTileTypeString);
//this._floorTiles[x, y] = Instantiate(mapTileLoader.CornerTile, new Vector3(xPlacement, 0, yPlacement), GetRotation(mapTileTypeString));
continue;
}

if (mapTileTypeString.Contains("CORNER_LOWER"))
{
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.CornerLowerDoorTile, xPlacement, yPlacement, 0, mapTileTypeString);
//this._floorTiles[x, y] = Instantiate(mapTileLoader.CornerLowerDoorTile, new Vector3(xPlacement, 0, yPlacement), GetRotation(mapTileTypeString));
continue;
}

if (mapTileTypeString.Contains("CORNER_UPPER"))
{
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.CornerUpperDoorTile, xPlacement, yPlacement, 0, mapTileTypeString);
//this._floorTiles[x, y] = Instantiate(mapTileLoader.CornerUpperDoorTile, new Vector3(xPlacement, 0, yPlacement), GetRotation(mapTileTypeString));
continue;
}

if (mapTileTypeString.Contains("CORNER_2"))
{
this._floorTiles[x, y] = GetTileForWorld(mapTileLoader.CornerFullDoorTile, xPlacement, yPlacement, 0, mapTileTypeString);
//this._floorTiles[x, y] = Instantiate(mapTileLoader.CornerFullDoorTile, new Vector3(xPlacement, 0, yPlacement), GetRotation(mapTileTypeString));
continue;
}

}
}

}

private Quaternion GetRotation(string mapTileName)
{
if(mapTileName.Contains("90"))
{
return Quaternion.Euler(new Vector3(0, 90, 0));
}
if (mapTileName.Contains("180"))
{
return Quaternion.Euler(new Vector3(0, 0, 0));
}
if (mapTileName.Contains("270"))
{
return Quaternion.Euler(new Vector3(0, 270, 0));
}

return Quaternion.Euler(new Vector3(0, 180, 0));
}

private GameObject GetTileForWorld(GameObject typeOfTile, float x, float y, float height)
{
return GetTileForWorld(typeOfTile, x, y, height, Quaternion.Euler(new Vector3(0, 0, 0)));
}

private GameObject GetTileForWorld(GameObject typeOfTile, float x, float y, float height, string rotationType)
{
return GetTileForWorld(typeOfTile, x, y, height, GetRotation(rotationType));
//return Instantiate(mapTileLoader.CornerFullDoorTile, new Vector3(x, 0, y), GetRotation(rotationType));
}

private GameObject GetTileForWorld(GameObject typeOfTile, float x, float y, float height, Quaternion quaternion)
{
return Instantiate(typeOfTile, new Vector3(x, height, y), quaternion);
}
}
}

and this is where I instantiate the objects (GameObjects) to be able to spawn them in the world:


class MapTileLoader : ScriptableObject
{
public GameObject FloorTile { get; set; }
public GameObject FloorStartTile { get; set; }
public GameObject EdgeTile { get; set; }
public GameObject EdgeDoorTile { get; set; }
public GameObject CornerTile { get; set; }
public GameObject CornerLowerDoorTile { get; set; }
public GameObject CornerUpperDoorTile { get; set; }
public GameObject CornerFullDoorTile { get; set; }
public GameObject HorizontalCorridorTile { get; set; }
public GameObject VerticalCorridorTile { get; set; }

internal void LoadTiles()
{
//This has to be the hackiest code I've ever written. 🙂

FloorTile = (GameObject)Resources.Load("MapTileTemplates/BasicFloor");
FloorStartTile = (GameObject)Resources.Load("MapTileTemplates/BasicFloorStartLocation");
EdgeTile = (GameObject)Resources.Load("MapTileTemplates/BasicWall");
EdgeDoorTile = (GameObject)Resources.Load("MapTileTemplates/BasicDoorWall");
CornerTile = (GameObject)Resources.Load("MapTileTemplates/FullCorner");
HorizontalCorridorTile = (GameObject)Resources.Load("MapTileTemplates/HorizontalCorridor");
VerticalCorridorTile = (GameObject)Resources.Load("MapTileTemplates/VerticalCorridor");
CornerLowerDoorTile = (GameObject)Resources.Load("MapTileTemplates/CornerLowerDoor");
CornerUpperDoorTile = (GameObject)Resources.Load("MapTileTemplates/CornerUpperDoor");
CornerFullDoorTile = (GameObject)Resources.Load("MapTileTemplates/CornerDoubleDoor");
}

}