Unity How To Rotate

Hi Xander here. I kept making mistakes and wasting programming time when it comes to Transform.Rotations. It can be hard to remember what all the inbuilt Unity Vector commands do and when it’s easier to use Quaternion.LookAt() or a different inbuilt command. so I created an example project that included common ways to handle a rotation and a graphical representation of them. I’m putting it up here in the hope that other people find it useful. The code and project files are in GIT here: https://github.com/zuluonezero/UnityRotation and I will give a description of what to do with it below.

All you need to do to get it working is to open a fresh project and remove any existing Camera’s and other items from the default Scene.

Then import the RotationsPrefab from GitHub and place it in the scene.

You will see that there is a cube set up in the middle with the Axis bars shown in green, red, and blue.

Have a look at the Cube object in the Editor and check out the script attached to it called RotationScript.

This is what it looks like:

This is the bit that deals with Vectors.
This is the bit that deals with Quaternions

Have a read through the code (most of which is not my own and comes from the Unity3d Manual examples for the functions called).

The script runs in the Editor but it’s better in Run mode (don’t maximize it or you cannot play with the script while it’s running).

You can use the Move Camera button to shift from 2D to a 3D view (3D is better).

Click Play and start messing round with the tick boxes and sliders of the Rotation script in the Editor. (Most of the tick boxes need to be unchecked after you have used them to move down the execute order of the script).

The first section plays with Vectors to rotate the cube and the seconds uses Quaternions.

There is a summary of what’s happening in the script on the screen but having the code open while you play helps understand what’s going on a little easier.

Here is a little demo of what it looks like when you play around with it.

I hope you get something out of this because even after a couple of years I still get this stuff wrong time and again and have to relearn it again. Hopefully now it will stick!

Xander out.

Unity How To Do Guns

Here at ZuluOneZero we love guns in games and other fantasy settings for their ability to embody drama, tension and action. They are a super power that takes us beyond the normal abilities to exert force. Sadly in real life guns suck and if you like shooting guns for real stay the heck away from me and my friends.

Anywhoo… this is how we use Guns in Endless Elevator to dispatch the Bad Guys and generally wreak havoc in an otherwise quietly innocent building.

This is our hero The LawMan! See he comes with that super powered lawmaster pistol, standard issue bullet proof vest, sherrif’s hat, and a make no mistakes we mean business moustache (can you tell he’s smiling under that?).

The LawMan

This is how he looks in the Unity Scene Editor. See those two Objects he has as Children “Gun” and “smoke”? They sit invisibly just where the 3D curser is in the image below…just at the end of the gun barrel. The Gun object is used as the spawn point for bullets and smoke is one of two particle systems that go off when the gun fires (the other particle system does sparks and is attached as a component directly to the Game Object).

There are four scripts that handle the basic Gun actions in our game. There are of course plenty of ways to do this – but this is the way we do it for this game. One script handles the aiming of the gun as part of the Character Controller. Another script attached to the Character handles the firing of the Gun and the spawning of the bullets. The Bullets have their own script that handles Gravity, Acceleration and Animations while alive and during Collisions. The last script attached to the Bad Guy handles the impact effects of the Bullets and the “blood”.

We wanted to keep the cartoon elements of gun violence in this game and get away from realism as much as possible. That said a bullet strike has a pretty huge impact and when we had a red coloured particle system for the blood it looked really gruesome. We changed the impact force to be over the top and super exaggerated so that it’s funnier reaction and moved the particle system color to yellow (might change it to stars later on). The Bullets are supposed to look like expanding rubber dum dum bullets so they grow out of the gun and enlarge a little bit in-flight. After a collision they start to shrink again and get very bouncy.

Here is a sample of game play where our hero blasts away at some chump.

So the Hero Character has a couple of scripts that handle aiming and firing.

The snippet below is the aiming component of the Character Controller. The Player has a wide Trigger Collider out the front that picks up when it hit’s a Bad Guy. If there are no _inputs from the Controller (ie. the Player stops moving) then he will automagically rotate towards the Bad Guy and thus aim the gun at him.

void OnTriggerStay(Collider otherObj)
    {
        if (otherObj.name == "bad_spy_pnt"  || otherObj.name == "Knife_spy")
        {
            if (_inputs == Vector3.zero)
            {
                Vector3 lookatposi = new Vector3(otherObj.transform.position.x, transform.position.y, otherObj.transform.position.z);
                transform.LookAt(lookatposi);
            }
        }
}

Now once we are aiming we can fire (you can shoot at anytime – and straffing is pretty fun – but it’s far easier to hit if you stop and let the auto-aim work for you). For firing this is what the FireBullet script exposes in the Editor:

There is a “bullet” prefab which we will talk about below, the Gun transform (ie. bullet spawn point), the force at which the bullet is spawned with, the audio for the shot, and the particle system for the smoke (called PartyOn …. I know).

The script itself is pretty straightforward: The bullet is spawned at the Gun Transform with a direction and force, the gun noise goes off, and the particle system does smoke and sparks. After two seconds the bullet is destroyed. This is what it looks like:

using UnityEngine;

public class FireBullet : MonoBehaviour
{
    public GameObject bulletPrefab;
    public Transform bulletSpawn;
    public float force;
    public AudioClip fireNoise;
    private AudioSource MyAudio;
    public ParticleSystem partyOn;
    public bool includeChildren = true;
 
    void Start ()
    {
        MyAudio = GetComponent();
        partyOn = GetComponent();
    }

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            Fire();
        }  
    }

    public void Fire()
    {
        partyOn.Play(includeChildren);
        var bullet = (GameObject)Instantiate(bulletPrefab, bulletSpawn.transform.position, bulletSpawn.transform.rotation);
        MyAudio.Play();
        bullet.GetComponent().AddForce(transform.forward * force);
        Destroy(bullet, 2.0f);
    }
}

One of the really important lessons we learned from this script is to get the Transforms and X/Y/Z directions of your models imported into Unity in the right direction first up. We had a few different models for bullets over the last few weeks ranging from simple cylinders, to pillows and bean bags, and real bullet shapes. It makes it so much easier to direct objects if their rotations are correct to start with. For example we did one quick model of a cylinder but had it sitting on the Z axis instead of X so when we did the “forward” force the bullet would travel sideways.

This is how our bullet looks now:

This is how the script to handle it’s behaviours and the settings of it’s Rigidbody and Collider:

It’s got a Rubber material on the Collider so that it bounces around when Gravity is enabled in the Rigidbody on Collision. We disabled Gravity so that we could slow down the Bullet firing path and not have to use so much Force. Having a slow bullet adds to the cartoon drama, reinforces the rubber bullet idea, and looks less like killing force. Here is the script:

using UnityEngine;

public class BulletGravity : MonoBehaviour {

    private Rigidbody rb;
    public float force;
    public float accelleration;
    public bool collided;
    public float scaleFactorUp;
    public float scaleFactorDown;
    public float maxScale;
    public float bounceForce;


    void Start () {
        rb = GetComponent();
    }

    void Update()
    {
        if (transform.localScale.x  scaleFactorDown)
            {
                transform.localScale -= new Vector3(scaleFactorDown, scaleFactorDown, scaleFactorDown);
            }

        }
    }

    void FixedUpdate ()
    {
        if (!collided)
        {
            rb.AddForce(transform.forward * force * accelleration);
        }

    }

    void OnCollisionEnter(Collision col) {

        collided = true;
        rb.useGravity = true;
        rb.velocity = transform.up * bounceForce;
    }
}

Below is the Collision part of the script that handles the BadGuy flying up into the air and bleeding all over the place.

void OnCollisionEnter(Collision col)
    {
        colName = col.gameObject.name;

        if (colName == "bullet(Clone)")
        {
            hitpoint = col.transform.position;
            GameObject BloodObject = Instantiate(BloodPrefab, hitpoint, new Quaternion(0, 0, 0, 0), TargetObject.transform) as GameObject;
            Destroy(BloodObject, 5.0f);

            //   We disable his AI script so he doesn't try and walk around after being shot :) It's not a zombie game.

            var AI_script = GetComponent();
            if (AI_script)
            {
                AI_script.enabled = false;
            }

            Vector3 explosionPos = transform.position;
            explosionPos += new Vector3(1, 0, 0);
            rb.AddExplosionForce(power, explosionPos, radius, offset, ForceMode.Impulse);
            yesDead = true;

            Destroy(transform.parent.gameObject, 2f);
        }
    }

Let’s break down the whole process visually. Here is our Hero in a standoff with a Baddy. He hasn’t aimed yet but you can see his big aiming collider in yellow underneath him extending out front and of course the character box colliders are visible too in green. (The Bad Guy has a yellow sphere collider on his head cause we make him get squashed by lifts!).

Here we are just after firing. His aiming script has put him on target and his bullet is there travelling with force and bloating in size.

And this is the impact with the force applied to the Bad Guy and his yellow blood impact stuff spewing out dramatically for effect.

All we got to do now is to clean up the Bad Guy’s object and destroy the used bullets. We don’t do any object pooling for the bullets yet…the overhead for the current system has warranted it but maybe later on.

That’s about it. Hope you’ve enjoyed this gun for fun expo-say.

Trixie out.

Endless Elevator – Show Reel

DevLog March 2019: This month we did a cheesy show reel of the latest changes in development for Endless Elevator.

This is a very early “In Editor” development sketch up of some of the features currently being included… Enjoy the show.

The game will be available on the mobile app stores in 2019.
For more information subscribe to our Dev Blog at: http://www.zuluonezero.net/zuluonezero-devblog/

Violation of Usage of Android Advertising ID policy and section 4.8 of the Developer Distribution Agreement

This week we got an email from Google about our demo game Adventure Text that we had released to the public ten or so days before on the Google Play Store.

The game was removed from the Play Store with this email being the only notification after the fact. The public couldn’t see it, couldn’t search for it, and any live links from promotional material wouldn’t connect through to it. If this was a commercial product or even one that I had a vested interest in it would have been a small disaster. Those first few days of a game release are critical for generating user interest.

The reason that the app was removed was because we had included the Unity plugins for Analytics and Advertising in the packages that it was compiled with. Our app is a demo of a Text Adventure framework we built as a side project and we did not use either of these packages. They were included in our base build of the project by default even though we had the Enable Analytics switch turned off when we created the project.

One or both of these packages was capturing either user data or Android Advertiser ID’s in the background. Because we were not actively using the packages and did not capture any user data as part of our application we were kind of stumped. We did a bit of Google Foo and found that a common source was the Unity packages for Analytics and Monetization. Here they are in the project folder (below) – was kind of obvious once you look but since we weren’t using them in any of our code I figured they would not be included in the final package (just like unused assets). Wrong!

Google Play requires developers to provide a valid Privacy Policy when the app requests or handles sensitive user or device information. If they identify that your app collects and transmits the User Data or the Android Advertising Identifier then you must provide a valid Privacy Policy in both the designated field in the Play Console, and from within the app.

You can read more about the Google Play policies for Privacy in the Developer Policy Center (see Advertising and User Data Privacy). There is also more information available in the Google Play Developer Distribution Agreement.

In our case it wasn’t a big thing. We had just released a demo game for fun not for profit. But if you were going for a monetized app (and hey why not) you do need to use a valid Privacy Policy both somewhere available on the internet and also from within the application.

This was a game made in a week. There was no way we were adding another button for a privacy policy we didn’t really need. We took the offending packages out of the project in Unity (Window -> Package Manager) by using that little “Remove” button there in the top right hand corner:

We rebuilt the game and uploaded another release to the Developer Console and in a few hours the app was again available on the Google Play Store. Phew. Cool. Problem solved.

But what if we really wanted these packages? What would we have to do? Well first we needed a Privacy Policy. There were some pro-forma one’s available on the interwebs that might have been appropriate. I found several forum threads where other people had had this problem and used this site to generate one: here

I cannot endorse or even suggest that it’s a good idea to grab something off the internet that is a legally binding policy so please do your research on this subject before you leap into it.

Once you get your policy in place it needs to go somewhere on your web site so that it’s publicly available.

It also needs to be available in your Google Play Store Listing. If we wanted to use one it would go down the bottom in the Google Play Developer Console:

Finally you would need a mechanism in your game or app that allows users to easily find and see your Privacy Policy from within your game.

People’s privacy and the data you collect from your applications and games is an important topic. Both ethically and practically.

It’s kind of a dummy mistake to get caught out by this one. Don’t let it be you! Be aware that the default project settings in Unity (at least in the 2018 build) include packages that collect user data and that if you include these packages you need to have a Privacy Policy.

Maybe even if you didn’t include these packages it would be a good idea to have one anyway. It’s totally ok for app developers to gather information that’s going to enable them to make a better product and I think most game developers include either analytics and advertising in their games. It’s unfortunate that Unity includes these packages in the default project build without really making the end user aware of it but if you look it’s plain to see. Also if you are informed and have read all the Google Play Store policies that are there to protect everyone then it shouldn’t be too hard to put it all together.

Zulu out.

Demo Text Adventure Game Released on Google Play

Hi Harmony here….

We released the demo game for our Text Adventure framework on the Google Play Store this week.

https://play.google.com/store/apps/details?id=com.ZuluOneZero.AdventureText


The Code for the Project is available on GITHUB:

https://github.com/zuluonezero/AdventureText

Quick Start Instructions for building a 2D Unity project are available on the README.

More detailed information is available in the ZuluOneZero – DevBlog.

See our posts about the development of this game and more information on how to configure the project: 

I hope you enjoy playing with it.

If you have any questions or need support you can email us at zuluonezero.z10@gmail.com.

Harmony out…

Text Adventure Design and Programming

Hi Xander here….

This post is about the design and build of our Text Adventure game over the course of a week. This was a “proof of concept” project to make a framework for a text based game that could be re-used and expanded on for future use. It’s not a polished game but an exercise in execution – and a jolly fun one at that.

The main features of the game are:

A simple 2D UI with Directional buttons an Action/Attack button, and a “Show Map” button. A HUD bar at the top with Player HP (hit points) the outcome of combat interaction (Player vs Monster) and during combat the Monster HP.

A large text area for describing your location and the environment around you. This area also shows the random actions taken by both Players and Monsters during combat.

A map that is gradually exposed as you explore the game.

This is the starting layout (digging the “panelled wood” feel here):

In the Scene the main Game Objects are:

The Canvas for the UI.

An InputControl object to handle what happens when a button is pressed and provide the appropriate response.

A FightClub object to handle combat events.

Another Map Canvas to show the map and hold all the map components.

And what I call the WayPoints which are the different locations and events that can happen during the game. Each one gets a new object and in this sample game there are Thirty Four of these nodes. These objects hold all the information about a particular location including which WayPoint is next in any give direction and what Monster if any appears here.

This is what it looks like in the explorer:

I’ll go through the main scripts one by one.

I will also put all the scripts in our GIT Repository (link below).

WayPoint Script

This is a custom class that mostly just holds data about a given location and only if required Generates a Monster. See the example below (which shows a section of the full details):

The first boolean tick box Way Point Visited let’s the InputControl script know if an area has been explored before. This allows alternate short descriptions of the location (which makes navigating known areas faster) and is used by the mapping component to tell if an area of the map can be revealed or not.

The Name, UID and Description fields are not actually used but I added them in for future use. Since the Object name includes a UID and is a descriptive name (Eg. 06_StatueFight) I didn’t really need them for coding.

The Write_rate and Text_size are passed to the Main Printing System (also attached the InputControl object) so that there is some control over the speed and size of the text that prints on the screen like a typewriter for managing the pace of the game. Faster and larger for combat and exciting events and slower for more descriptive passages.

The Text Sections are self explanatory. When a Player enters a location the first time or a repeated time this is the text that is printed.

WayPoint _forward, _backwards, _left, and _right point to the name of the next WayPoint object in that direction. If it’s NULL then there is nothing in that direction.

The rest of the script is for defining if a Monster spawns in the given location, it’s attributes, and the text options passed to the FightClub combat module (each Monster has different attack and defence descriptions to make it more variable and exiting).

The WayPoint script has one Function called GenerateMonster() which when called by the InputControl system does just that with the info in the WayPoint class for the monster we defined above).

Input Control Script

The Input Control Script handles input from the four directional buttons (Forwards/Backwards/Left/Right or North/South/East/West), the Action/Attack button and the Map button. The Map button shows the map canvas and the progress the player has made within the dungeon. The Action/Attack button is only used once the Combat feature is triggered. The main body of the script is for handling navigating around with the directional buttons and triggering special events attached to some locations.

The Current Waypoint variable is the most important piece of the whole game system. It holds all the data for the current location such as the available text to print and if there is a Monster to fight or other special action.

The next public variables hold references to all the components we will need in the Input Control Script: The Combat System (FightClub), the UI buttons, and the Map Canvas.

We also have two bools. One to let us know if the game has just started so we can show the appropriate text and one to let us know if there is a Monster present (so we can initiate the Combat System).

The Generate Map function in this script does a find on all the WayPoint objects in the game and collects their names. Each map piece is tagged with it’s related WayPoint name and if the “visited” bool has been check it displays that part of the map.

Print Main Text

This is the printing workhorse of the game. It takes the input from the WayPoint (and a text size and speed of typing) and prints it out on the main screen like a typewriter.

It handles all the printing to the other smaller text components as well like the Title, HP and Combat stats.

This script is made into a Singleton so it’s easy to call from all the other scripts that have printing needs.

Fight Club

The Fight Club script is the combat system. Very simply the Player and any Monster gets a maximum and minimum limit to their random integer attack. The player gets an optional “Weapon bonus” if he/she picks up a magical sword during the course of their adventures which adds the random int. Whoever has the higher number wins. The value of their integer is also the amount of damage done. Damage is done against another integer (Hit Points or HP) which if it reaches 0 indicates that the combatant has died (usually horribly).

This is the public behaviour of the script:

The Monster’s HP and Min/Max Damage is recorded in the WayPoint for that location and passed from the MonsterStuff class that is attached to the Monster.

Monster Stuff

The Monster Stuff script is attached to a Monster prefab and is instantiated when a monster spawns. This is the behavior:

As you can see it’s the same sort of stuff that the Player has in the Fight Club script (HP, Max and Min Damage) but there are also arrays of text fields. The Monster prefab gets passed all this data from the WayPoint script on instantiation so they are really just placeholders waiting for data.

The Dead bool is pretty self explanatory – you couldn’t get more boolean!

The Monster Stuff class presents four functions:

MonsterAttack(), MonsterTakesDamage(), MonsterAttackText(), and MonsterDefenseText(). The attack and damage functions return integers for calling from the FightClub and the text functions return the appropriate text to the FightClub. Each Monster has its own special attacks and defences so the text generated for the fights is unique. The attacks and defences are arrays so you can expand the available text options at will thus making the game more interesting and variable.

Other Miscellany

That is basically all the scripting that there is to the game! It’s a Text Adventure so most of the work goes into the writing and the story that you build into the WayPoints. It’s pretty light and flexible and able to be extended a number of ways.

There is also script to open the map and close it and to reset the game back to it’s starting position but I won’t talk about them here. They are pretty generic.

GIT Hub

All of the code is available publicly on our GIT Repository: https://github.com/zuluonezero/AdventureText

Xander out.

A Week of Text Adventures

Hi Harmony here….

Last week we spent completely side tracked from our usual projects and decided to create a Text Adventure game in a week. It was a great idea and everyone feels like they have had a holiday from the daily grind. Just going with a new idea and playing it out in a limited time frame was awesome fun. We did this sort of thing when we were just starting out with the Five Games in Ten Weeks challenge and it really freshens up the creative juices.

The initial idea was to do a text adventure like I used to play when I was a kid on my Trash-80. Zulu loved those games in the days before computer graphics were interesting. So we gave it a limited scope of just using text to tell a story in the manner of a dungeon crawler that incorporated some kind of hand drawn map just like we used to do when playing D&D.

Gene did up a super simple UI and Trixie and Xander worked on getting the programming of the text and mapping underway. The incremental mapping proved to be the biggest challenge and we had to try three different ways of working it till we got it right. Xander will post the code and methodology used in a later entry.

This is how the UI ended up (Kudos to all of you who spotted the callout to “Impossible Mission” another childhood favourite):

In keeping with the theme and the timeframe we used a really simple text call to print the story. This is the opening scene:

Then we worked on the exciting monster battles (all in text):

Finally we implemented the mapping system which tracks your progress through the tomb!

So as you can see it’s pretty simple but really fun to do. I guess this is one of the real strengths of using Unity is that you can quickly mock up a working game in a short amount of time. We will post it into the Play Store as a Beta later this week so you can go for an adventure yourself.

If you are interested in this sort of game I found the following groups a great place to start:

8-Bit Text Adventures
TEXT ADVENTURES & INTERACTIVE FICTION // PLAY / DESIGN / DEVELOPMENT
r/textadventures

Harmony out.

Text Adventure

I started the New Year feeling a little dispirited and un-enthused. It takes Sooooo long to finish a game so that when your attention is flagging it just makes it seem worse.

To remedy that I woke up one morning with a new idea for a game and feeling spirited again I decided it would be really quick and easy to make it. So that’s what I did. In a couple of sessions I had worked up an interface and a print method for a text based adventure game.

I used to love these as a kid on my Trash-80. They were the bridge between the role playing genre and computer games.

So this is the start of it. It’s really simple. Laid out in nice “wood feel” with simple movement buttons to navigate, a “show map” button, and an Action/Attack button to fight off those all important monsters and to fiddle widgets with.

First Draft

Honestly I just wanted to have fun and do something quick and easy. I’ll release it for my own pleasure when it’s done. There is still a bit to go like getting the map working so that it displays where you’ve been and getting combat simulation going – but easy-pease little steps. I don’t want to spend more than a week doing it.

Endless Unity Camera Tricks

In our game currently under development called Endless Elevator I decided to add a new feature of more depth.  The game is 2.5D and mostly sits in a very shallow Z axis, a limited X axis, and an endless Y axis. As the name suggests your character is inside a never ending building trying to kill or avoid the enemies by escaping up elevators and escalators. The mock-up of a level below in the Scene view of Unity gives you the picture.  

Endless Elevator Opening Level Spawn

The player view is a much smaller slice of this level…about this much:

Roughly how much the camera views

I had the idea that I wanted to extend this playing field into a deeper third dimension where the character could walk down a hallway,  away from the camera, and seemingly deeper into the building.  Instead of the camera following the character down the hall on the Z axis (as it follows him on the X and Y) I wanted to pan around the edge of the building and take up the character again on the new parallel so that it looks like the camera is turning Ninety degrees and that we are looking at a new side of the building.  

Have a look at the .gif below and I’ll try and explain that better. The top half of the image is the Scene view and the bottom half is what the camera (and the player) sees in the game.  In the top half  Scene view you can see my character in green and highlighted by the handler arrows. He scoots around a bit and then disappears down the hall. When he gets to a set depth it triggers the camera to move in the game window below and you will see the levels reconfigure into a new building face (note the elevators and escalators and doors will be in different positions).

On the bottom half of the .gif that shows what the player sees it looks like once the character disappears down the hall the camera pans right, looks at the edge wall of the building as it goes around the corner in a Ninety degree turn, and then follows the character on the new level again.

(Watch the top half for a bit then the bottom half)

You can see in the Scene view we are not really moving anything with the building. It just recreates the levels. The camera is doing all the work.  It’s not perfect yet and without any background around the building to relate the movement to it’s a bit hard to tell if we are turning Ninety or One Hundred and Eighty degrees on that camera flip but it’s getting there.

It took a while to work out how to do this and I tried several different methods but this is the basic logic of the camera move script that is attached to the character.

  1. The movement of the camera is triggered when the character moves past a certain point on the Z axis.
  2. Stop the regular character and camera movement functions by disabling that scripted behaviour on each object.
  3. I set up an empty game object called the CameraLookAtPoint that hovers at the end of the building on the far Right of the X axis.
  4. Pan the camera Right toward the CameraLookAtPoint.
  5. When the camera gets to within a certain distance to the LookAtPoint it starts to rotate towards it.
  6. The camera moves around the LookAtPoint so that it faces that end wall of the building as it turns.
  7. At this point while the only thing the camera can see is that blank edge wall of the building I destroy the old level we just walked out of down the hall and create a new randomly generated level.
  8. This is the great illusion! The camera is then moved instantly to the far Left of the building (the opposite end) and it appears as if we have just turned a corner.
  9. Lastly the camera picks up the character again and we hand control back to the normal camera and character movement scripts.
This is where the CameraLookAtPoint sits that the camera rotates around  Ninety degrees as it gets to the edge of the building.

I’ll post the whole script below with comments but I’ll walk through the interesting bits here. 

To start off with I needed to grab references to several external elements like the camera, the level instantiating script, the character controller script, and the characters Rigidbody. (I needed the rb because when the levels were destroyed and recreated gravity would take hold between them and the character would fall into the endless abyss!)

I had to generate a series of “if” conditionals and Boolean flags to control the movements of the camera. This was surprisingly hard to get right. It’s often not intuitive when you are in the Update function what the looping iterations will do with your code but this allowed me to slow things down and get control back. 

The calls to the instantiateScene1 script were needed to copy variables used there in the main flow of the game to track what level we were on and how high up the building we had climbed. That way I could decouple that mechanism from this one and happily destroy levels and recreate them without interrupting the flow of the rest of the game.

 


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpinLevelDownHall : MonoBehaviour {
public GameObject cameraLookAtPoint;
public bool triggered;
public bool cleanAndRebuild;
public bool moveRightEnd;
public bool moveRightEndBack;
public bool moveLeftEnd;
public bool movebacktoCharacter;
public int levelHolder;
public float cleanUpHeightHolder;
public bool firstRunHolder;
public Vector3 target_camera_Position;
private GameObject the_camera;
private RigidbodyCharacter move_script;
private CameraFollow cameraFollow_script;
private InstantiateScene1 instantiate_script;
private Rigidbody rb;
// Use this for initialization
void Start () {
the_camera = GameObject.FindGameObjectWithTag("MainCamera");
move_script = GetComponent();
cameraFollow_script = the_camera.GetComponent();
instantiate_script = GetComponent();
rb = GetComponent();
}
// Update is called once per frame
void Update () {
if (transform.position.z > 15)
{
triggered = true;
moveRightEnd = true;
cleanAndRebuild = false;
if (triggered)
{
// Stop the character and the camera moving
move_script.enabled = false;
cameraFollow_script.enabled = false;
if (moveRightEnd)
{
// Set the target camera position on the x axis at the far right of the building
Vector3 target_camera_Position = new Vector3(78f, the_camera.transform.position.y, the_camera.transform.position.z);
// Set the camera look at point on the y axis (so it's on the same level as the player)
cameraLookAtPoint.transform.position = new Vector3(cameraLookAtPoint.transform.position.x, transform.position.y + 4f, cameraLookAtPoint.transform.position.z);
// start moving the camera
the_camera.transform.position = Vector3.MoveTowards(the_camera.transform.position, target_camera_Position, 50 * Time.deltaTime);
// When you get close to the end start swinging the camera around to look at the wall
if (the_camera.transform.position.x > cameraLookAtPoint.transform.position.x - 10)
{                        the_camera.transform.LookAt(cameraLookAtPoint.transform);
}
// When you get really close to the first position move the camera beyond the wall to the side
if (the_camera.transform.position.x > target_camera_Position.x - 0.5f)
{
target_camera_Position = new Vector3(78f, the_camera.transform.position.y, 4f);  // 4f is perfect when the camera is at -90 deg
moveRightEnd = false;
moveRightEndBack = true;
cleanAndRebuild = true;
if (moveRightEndBack)
{
the_camera.transform.position = Vector3.MoveTowards(the_camera.transform.position, target_camera_Position, 50 * Time.deltaTime);
// When you get really REALLY close to the second position move the camera to the negative X Axis side
if (the_camera.transform.position.z > target_camera_Position.z - 0.2f)
{
moveLeftEnd = true;
if (moveLeftEnd)
{
target_camera_Position = new Vector3(-78f, the_camera.transform.position.y, 4f);  // The other side
the_camera.transform.position = target_camera_Position;  // snap move the camera
the_camera.transform.LookAt(cameraLookAtPoint.transform);
moveRightEndBack = false;
moveLeftEnd = false;
movebacktoCharacter = true;
}
}
}
}
}
if (cleanAndRebuild)
{
// Call cleanup on everything
rb.useGravity = false;  // so the character doesn't fall through the floor
//cleanUp;
cleanUpHeightHolder = instantiate_script.floorCntr;
cleanUpHeightHolder = cleanUpHeightHolder * 8;  // so it cleans up all the floors
firstRunHolder = instantiate_script.firstRun;
instantiate_script.cleanUp(cleanUpHeightHolder, firstRunHolder);  // cleanup height is usually two levels below the character - we are raising it to two levels above him
//then make three levels
levelHolder = Mathf.RoundToInt(instantiate_script.player_level);
instantiate_script.makeLevel(levelHolder);
instantiate_script.makeLevel(levelHolder + 8);
instantiate_script.makeLevel(levelHolder + 16);
cleanAndRebuild = false;
}                
triggered = false;  // makes it only run once
}
}
if (movebacktoCharacter)
{
// new position is back to the character
// Start breaking and making your new levels in here
// first move the character
transform.position = new Vector3(transform.position.x, transform.position.y, -4);
target_camera_Position = new Vector3(transform.position.x, transform.position.y + 4.9f, -20.51f);  // the starting camera position
the_camera.transform.position = Vector3.MoveTowards(the_camera.transform.position, target_camera_Position, 50 * Time.deltaTime);
the_camera.transform.LookAt(transform);
// Once again when you get close to your original camera position disable and enable normal camera tracking again
if (the_camera.transform.position.x > transform.position.x - 0.02f)
{
movebacktoCharacter = false;
rb.useGravity = true;
move_script.enabled = true;
cameraFollow_script.enabled = true;
}
}
}
}

It’s not the prettiest code, and I admit to hacking my way through it, but it works.  Maybe you have a better method for doing something similar – if you do please feel free to add a comment – I’d like to hear it.

Zulu Out.

Making a Custom Navigation Mesh for AI

Hi Xander here…

This week I decided to totally redo the way I have been handling character movement.

I used to have a free ranging character controller that basically moved in the direction your joystick wanted. I never really had that as my vision for this game as I wanted a more 2.5D feel to the game and a limited number of places you could move to. I got to this point because I was working on the enemy AI scripts using a custom mesh to navigate around.

The game level (or rather endless pattern of a level) is 16 Units wide and two deep.  In this case a Unit is a building component like a piece of floor or doorway or elevator shaft etc.  All these components are 8 x 8 blocks in Unity scaling. This is an example of an elevator shaft:

When you build them all together it looks something like this (that’s a very basic mock up below):

So you got a forward position where you can go up the stairs on the right and a middle position where you can go up the stairs on the left (see they are set back a bit) and a very back position which is through a doorway. So basically there are three parallel positions along the X axis.

What I wanted to do was to create a “patrol point” on every floor space within that grid of a floorplan and also create a patrol point if there is a door that is open.

On the floor positioned at the top or bottom of a stair you do not have a patrol point so there is never anyone at the top or bottom of a stair to block you going up or to knock you back down.

This all gets created at instantiate time and every level is random so I cannot use any of the mesh or nav components that Unity provides.

So all my patrol points get made into lists when the floor is instantiated and added to an array of levels.

When an enemy AI agent starts off they read in all the available patrol point nodes on the floor and work out the available nodes around it to move to.

So the agent knows about the nodes around it in a four square plus it’s own central location. 

As the game mostly scrolls along the left – right axis during game play the nodes are weighted so that travel along the X axis is more likely than the Z. 

At the end of the frame after moving (in late update) the nodes list is refreshed if a new node has been reached.

How does an agent find all the nodes around it?  Using a Raycast is too expensive.  So on each move the agent parses the list of nodes and works out the closest in each direction.

Basically for each node in the list get the x and z and subtract it from your own then put that value in a temporary location – every node gets tested the same way and if the return value is less than the temporary value then you got your closest node in that direction. You would need to do this four times (left, right, forward and back) and handle the null values when there is no space to move next to you. 

At an agent update interval when a new node is reached we first check all the nodes in the list and make a new list of nodes on the floor and our closest points. This gets added to the basic agent control behaviour of “looking around” where the AI stays in one spot and looks left and right in a rotation.  In all cases if they are looking left and the character is right then they cannot pursue him.  If he fires then they will turn.  All of these behaviours are then blended by weight.

I’m not sure if I will continue with this method for the character controller but it’s pretty good for the enemy AI scripts.