Unity: Waypoint Scanning

waypoint_scanning

First stages in implementing the waypoint scanning behaviour in waypoints. The idea is when a waypoint is reached, and this waypoint instructs the robot to scan, the robot picks up the waypoint’s scan points. Any number of ‘scan points’ can be specified by parenting transforms under the main scan point object of that waypoint.

The scanning movement is handled by the RobotMovementClass, not the RobotGameClass, though I’m still feeling it out whether that’s the best solution.

On another note, I’ve modified the Game Pause/Unpause behaviour by using SendMessage to NavMeshAgents instead of using if() conditions on their Update() callback; this is mainly because NavMeshAgent functions like Resume() are unintentionally getting called when they’re supposed to sit still!

3400AD: Lookups

So I had been working in Open Office Calc recently, something I didn’t expect to do more than just table up some values and do simple additions. In fact, I got a little deeper than I thought I would.

Normally, I would weigh up the worth of learning something new with the practicality of getting stuff done. Furthermore, ‘getting stuff done’ is about keeping the flow of the work going so that I don’t get stuck, don’t procrastinate, don’t lose my train of thought. So it’s more than just producing new code, or new assets; it’s about striking when and where the iron is hot.

I had been working on tables in Calc because I use lookups for system rolls such as chance-to-hit and defence. Up to this point I had been simply inputting the values by hand (temporarily hard-coding it in Unity). But I realised that I wanted a way to visualise skill improvements as the player levelled up and apply this visualisation to the actual values. This visualisation was simply being able to draw a curve that represents increase of values over another value (eg skills).

2015-12-03 23_52_32-DisguiseStealth.ods - OpenOffice Calc

The basic premise is that I define a curve, whose Y value is from 0-1, and whose X value represents a real number, which, in the case I had been working on, skill level points of the player. (Thinking about it now, I could have further made the curve generic by using 0-1 on the X as well and interpolate the skill points on the table.) When the curve is defined, I take the min/max values that are pre-defined, map the inbetween values using the interpolation code, which derives itself from the curve.

This was just as much to do with automation as it is with experimentation and balancing; it would take too much time to keep tweaking a list of skill values vis a vis a corresponding item for that skill value (eg “how much disguise bonus do we award a player who wears a hoodie at a given skill level?”).

Linear interpolation is quick and dirty, but is simply a compromise. I could have compromised and put more code into Unity to interpolate internally, but that’s just putting more code than required.

So I turned to Calc’s cell formula functionality. I have no deep understanding of Calc, so I relied on someone else’s example to learn from. Though this was not the first time I brushed with polynormals, coefficients, and plotting curves, I’m math-stupid, so it takes me some time to figure it out. This kind of math is something that always interested me, but interest and talent are two different things. I wish I was smarter in math; it would make my life so much easier.

Anyway, after 2 hours looking into the math, I figured out what the example was getting at. With this technique sorted, it frees me up to implement more lookups that require curve interpolation. It’s easier to see what’s going, instead of just looking at numbers. Also, it’s much easier to tweak the system, to balance the game as I continue to develop.

Unity: ScannerClass

ScannerClass in action. Robot is targeting the player; green line is where the robot is facing; the red line is the centre of the scan direction, and the blue line is an indicator that robot has a positive LOS on its target. Note that when player beyond maximum scan angle (ie red line is limited to a certain angle), LOS is still positive until it goes beyond the field-of-view of the scan direction.

This class was a functionality that I deferred when I was creating the robot’s ‘game’ class. Originally, I had simply used a Raycast to determine LOS; I knew a scanning behaviour was needed, so I coded the robot generically in that respect.

The ScannerClass is attached to a scanning object that is parented under the the robot’s root transform. The behaviour is that it scans around (oscillating pattern or full revolution) using the parent transform as its base direction. The class itself rotates the scanner game object for (my) convenience.

When the RobotGameClass asks ScannerClass for LOS to a specified target (usually the target that attacked it), the scanner will determine at that time if the target had been found; if so, it locks on to it. The RobotGameClass, meanwhile, instructs the RobotMovementClass to face and move towards target, making the the scanner face the target naturally. If the target gets lost out of sight, the lock is broken by the ScannerClass itself and it goes back to scanning, and based on the RobotGameClass AI, it will either reacquire or not.

What I learned from the coding the ScannerClass was more awareness of how rotations — expressed in Quaternions — and vectors are translated to and from each other. Because the scanner is controlled by a ‘scan angle’, which is a float, I needed to make a procedure to translate target vectors to Quaternion rotations to get to the Euler angles. It sounds a bit convoluted, but I think to keep the simplicity of the driving values, which is where the source of the confusion often is, the messy bit had be sorted out that way.

Unity and Second Steps

I’ve not been completely been informing this quiet corner of the interwebs of a little venture — equally as quiet — that saw me in the aftermath of shelving Zombots. The (temporary?) abandonment of Zombots was a decision come to all those concerned. If I were honest — and I was — Zombots wasn’t hitting the kind of obsessive note in me, and I couldn’t get to the same level of passion when I was developing Janus. So, it was just a matter of time before I had to drop it.

However, the upside to Zombots was that it allowed me to play, to get my feet wet with the first steps into Unity. Zombots allowed me to experiment and get used to its system and its scripting without having to concern myself too much with the structure of the game. It taught me a lot of things, and that’s why I’ve gathered more confidence in trying to make a game inspired by an old one from my childhood.

When I look down, I find the task so daunting that I feel like I’m crazy sinking so much time on this. But I don’t want to look down, I don’t want to rationalise potential. I don’t want to be distracted by anything.

On another note, and the primary reason for this post, I humbly managed to implement my first custom interface called ICombatMessage. I hooked it up this way:

public interface ICombatMessage extends IEventSystemHandler
{
    function OnBeingAttacked(attacker:GameObject);
}

… extending from IEventSystemHandler is required. This registers _OnBeingAttacked_ as an EventFunction under ICombatMessage.

Now the next bit is implementing that; so in the CombatClass.js, where the event function needs to fire (to inform the target that it is being shot at):

ExecuteEvents.Execute.<ICombatMessage>(target,null,function (x,y) { x.OnBeingAttacked(shooter);});

… the syntax of which confused me at first because there were no Unityscript examples (only C#). At any rate, the .<ICombatMessage> refers to the Type (ie <> denotes Type of the Type that’s put inside). Then the rest are almost self-explanatory. The functor, or what I see as a lambda function, is the EventFunction and based on the linked docs, an EventFunction always carries the handles (which refers to the function I had defined — OnBeingAttacked) and a BaseEventData object, which is something I didn’t use.

So with that in place, I implement ICombatMessage in CombatantClass.js:

function OnBeingAttacked(attacker:GameObject)
{
   Debug.Log("HELP!");
}