Monday, October 13, 2014

void EverythingThatRisesMust(Collision collision)



In its resting state, the current build of project_catalan may not look much different from the previous one (a bit more red maybe), but a lot has changed under the hood. The changes, in my mind, are akin to standing in the doorway of the empty shell of a house and thinking "all right, we're going to need to shape out the living room, so we'll need walls here, and a load-bearing column there, through which we'll route water and electricity..." We haven't even gotten to the studs and sheetrock, much less the arguments about which of your friends' paintings are going to hang near where people might be, like, eating. As in any self-impelled project, you're always glancing that far ahead from time to time, and it can be useful to attempt to anticipate what problems you may need to solve in the future, to the extent that it helps you choose the solutions to your current problems that make future you's life easier, but it would be a classic game development mistake to fall afoul of something so seductive and misleading as a plan.

This last sprint was about damage, death and communication. How does one character damage another, and how is that information communicated to everyone who needs it, including the player. I found Unity's new UI system (introduced in 4.3?) to be an absolute miracle, in the sense that it allowed me to do sensible things. My previous experiences with Unity UI involved making instances of things like GUI.Box in the OnGUI function of something attached to the camera, which seemed to mostly work for what I needed but had the usability flavor of writing a Windows GUI application in C# without the benefit of XAML, or doing web layout by changing numerical values in raw CSS files and then refreshing the page. It wasn't very IDE-integrated, is what I'm saying, and the new version totally is. When I was contemplating how to implement MMO health bars for the enemies, I was at first thinking about scripted GUI.Texture instances translating and scaling based on a mathematical relationship between the enemy and the camera. You'd have to be a masochist to write such a system, so I imagine the preferred solution was just some Doom-style billboarding on quad meshes attached as children of whoever gets a healthbar, all on some custom collision layer that ignores the rest of the game world. Unity recognized that not using the UI system was better than using it, so they fixed it. Now we can have world space Canvases as children of moving gameObjects, and a an enemy's health bar can be built with basically no code:



Allowing for player damage was somewhat trickier. I wanted a standard player HUD, and using the new Canvas tools in combination with the main gameplay camera produced undesirable results. I ended up adapting a technique I had seen the Snuggletruck guys explain in a seminar: I created an orthograhic camera "box" far away from the action, and gave it a positive Depth so that it would render over the gameplay camera. This freed me to compose a UI in Scene view without feeling crowded by actual gameplay objects:


The problem with this approach (Screen Space - Camera) is that it's not very forgiving to resizing / rescaling. Right now I'm viewing all of my current projects as portfolio pieces aimed at a standard web browser, but not building in UI scaling functionality as you go is a recipe for "platform prison syndrome". The new anchor system is quite elegant and only a little over my head, so this feels like a very solvable problem once it needs to get solved.

The idea of implementing one last feature for this build, pushing a character away from a damage impact, turned out be much like Columbo un-mouthing his cigar, turning his head slightly, and asking about "one more thing". The ur-idea here is of course from the NES Legend Of Zelda  (yes, catalan is a Zelda clone. I will also stay up all night with you argiung that the Diablo games are Zelda clones, provided you're buying). A character being melee'd by an enemy should be slammed back, not far enough or long enough to disrupt gameplay, just enough to provide that sensation of "yes, dumbass, you touched a hot stove. How bout you try to avoid doing that?"

Teaching in video games is not done thorough tutorials, which are not widely read or played or viewed or whatever. Teaching is done by presenting the player with a variety of hot stoves and inviting them to make like Buddy Rich on some bongos. See what you like! They'll figure it out. If not, they'll leave you a nasty review claiming the game is too hard. Look, all I can do here is make stoves and heat them to various degrees. It's up to you to decide what to touch, that's what our relationship is about.

Trying to sort out combat, I worked through all the permutations of Unity colliders, triggers, rigidbodies... you can't just point at any of the onscreen characters and ask what collisions they've experienced recently, it's all very dependent on what components the attacker and defender were sporting, the complexity got silly, I even used some joints (er, Fixed Joints, that is). One morning at about 3:40AM I realized part of one of my "Push" function involved assigning one variable's value to another variable that just had a different name. I was writing in circles. I called it off.

The "Zelda Push" ended up not making use of colliders at all. It doesn't even require rigidbodies! It's dirty secret is performing a while loop inside a CoRoutine, and using "yield return null" at the end of each loop iteration. so the while loop actually updates at the same speed as the main game loop. Here's how the whole thing ended up looking (for context, this method lives in healthStates.cs, which is attached to any object whose health we care about:
IEnumerator DoPush(GameObject pusher)
 {
  Vector3 startPoint = transform.position;
  Ray pushRay = new Ray();
  if(pusher.GetComponent())
  {
   //Debug.Log ("melee push");
   pushRay = new Ray(startPoint, transform.position - pusher.transform.position);
  }
  else if(pusher.GetComponent())
  {
   //in this case using the bullet for the ray origin gets wonky
   //so we get the gun location and start the ray there
   //Debug.Log ("bullet push");
   bullet_base bulletScript = pusher.GetComponent();
   Transform firearm = bulletScript.weapon;
   pushRay = new Ray(startPoint, transform.position - firearm.transform.position);                
  }
  else
  {
   Debug.Log ("invalid pusher");
  }
  Vector3 flatPushDir = new Vector3(pushRay.direction.x, 0.0f, pushRay.direction.z);
  pushRay.direction = flatPushDir;
  Debug.DrawRay(pushRay.origin, pushRay.direction*1000, Color.red, 10.0f);

  float pushLength = 5.0f;
  Vector3 pushPoint; 
  pushPoint = pushRay.GetPoint(pushLength);
  //pushBall = Instantiate(pushBallTemplate, flatEndPoint, Quaternion.identity) as GameObject;

  float pushStartTime = Time.time;
  float distanceCovered = 0.0f;
  float fractionComplete = 0.0f;
  float pushSpeed = 50.0f; //this actually matters in relation to the pushLength
  while(fractionComplete < 0.9f)
  {
   distanceCovered = (Time.time - pushStartTime) * pushSpeed;
   fractionComplete = distanceCovered / pushLength;
   transform.position = Vector3.Lerp(startPoint, pushPoint, fractionComplete);
   //Debug.Log("fractionComplete = " + fractionComplete);
   yield return null;
  }
 }


Once I built the new version, befoe deploying it to the web I tested it locally and encounteerd this error:
Built with beta version of Unity. Will only work on your computer!
which is pretty delightful. I guess as of 4.6.0, the games we're able to build at home are somehow ahead of the WebPlayer to the point where they could become dysfunctional? As a matter of fact when I ran the game under chrome, the healthbars were offset and didn't scale properly, as I'm sure you'll see if you check the game out. I don't know how FF or IE deal, I didn't have the heart to find out. I mean, yes, it's my own fault for trying to create software to present to the public with beta tools, but I much would have preferred messages more specific to my situation:

  • Other computers may choke on your ridiculous, leaky algorithms!
  • Other computers may just not have the CPU/GPU muscle to simultaneously lift and lower all the vertices of your tremendously detailed and natural game world which is not optimized in any significant way 
  • Your game world has, in defining its origins and boundaries, mishandled the spatial and memory assumptions of the machine you're working on so as to create some sort of novel geometric figure, somewhat like a turd the size of the universe spinning at (0,0,0).

Just some decent error messages. That's all anyone should feel comfortable asking for.

Coming Up:

  • How bout them models
  • Some kind of hooky concept seems about ripe... this can only stay generic for so long
  • Models should perform some kind of death sequence
  • What's it all about, killing purple dudes? Do they drop money which allows you to buy better guns? From whom? The more solid your gameplay systems become, the more there is this need to commit to some kind of content interpretation in order to build more sophisticated sub-systems that enhance that interpretation. Generic gameplay engines are great, but you have to plant an conceptual / content-centric flag in order to make that into a game, and that's a process of walking through one of many doors and feeling a ton of other doors slam closed. You better hope you walked through a door you can live with!  





Sunday, September 21, 2014

Out On The Tiles


Once a certain mega-game shipped, I found myself with a little time in which to return to some Unity prototypes. Something about The Benko isometric project kept drawing me back, but I was frustrated by the control scheme. I wanted to control the main character more directly, and I wanted to be able to use a gamepad to do it. However, I also wanted the game to be playable in-browser by anyone with a keyboard and mouse, which meant a back-up set of controls. Surely, I thought, this would be a snap.

Unity did meet me more than halfway here, because rather than having to plow through a bunch of GetKeyDown type functions, I could use Input.GetAxis, which was automatically mapped to WASD for movement, and could quickly be taught to recognize the trusty 360 gamepad. Getting parity in movement was easy. Getting parity in facing was not quite so easy.

The gamepad’s right thumbstick gave me a pair of clean, normalized Vector3s right out of the box, so I was golden there. The interesting part was getting that same result out of a mouse position. I knew that a ScreenToWorld translation would be involved, but there was more to it. I fooled around for many a Designated Leisure Period trying to covert Quaternions to Vector3s using EulerAngles, exploring all the LookAt, LookTowards, and TurnToLookAtThatGuy functions, and generally achieving jack all. I would find solutions that had the right direction but the wrong magnitude, or solutions that worked great until you moved the player away from the origin point, at which point they broke down. Eventually I bumped my head or something and realized that what I needed was a Ray. I guess I had unconsciously filed Rays away in the part of my knowledge that dealt with collisions, and since I wasn't working explicitly on the physics I didn't make the connection that this was an available tool. But yes, when you need any information on where one point lies in relation to another, and how one object might face another, at an arbitrary distance from the origin, your best bet is to break out the Rays:

void HandleLookInput()
{
    //this func is how we set the lookDirection var every tick
 
    //MOUSE VERSION (first so gamepad can override if plugged in)
    mouseTarget = mouseScript.mouseTarget;
    //subtracting player pos from target gives us correct magnitude, which is then normalized to match gamepad
    Ray lookRay = new Ray(transform.position, (mouseTarget-transform.position).normalized);    
    Debug.DrawRay(transform.position, (mouseTarget-transform.position).normalized, Color.magenta);
    //force y to zero to avoid unwanted bullet fall
    lookDirection = new Vector3(lookRay.direction.x, 0.0f, lookRay.direction.z);

    //GAMEPAD VERSION
    if (isGamepad)
    {
        H_LookInput = Input.GetAxis("LookH");
        V_LookInput = Input.GetAxis("LookV");
        if (((H_LookInput >= 1) || (H_LookInput <= -1)
        || 
        (V_LookInput >= 1) || (V_LookInput <= -1))) 
        {
            lookDirection = new Vector3(H_LookInput, 0, V_LookInput);
        }
    }
    else
    {
        //don't change look dir if player released stick
        lookDirection = lastLookDirection;
    }
//Debug.Log("LOOKDIR : " + lookDirection);
}

The “bullet fall” thing is interesting, and leads into the next part: I had a player and a big purple refrigerator (conceptually a bear) and of course my next prototype impulse was to fire some sort of arrow or bullet at the bear. I think the direction this is moving now is into a kind of “isometric twin stick style action panic swarmer”, where the player fends of waves of attackers, but we’ll see where it ends up.

As usual, I wildly underestimated the challenge of deriving a projectile’s trajectory from a Vector3 representing a direction between two objects. Seems like the same thing… but not on a flat plane where the bullet has to come out of the muzzle of a weapon that could be rotated in any arbitrary direction. This was the place for LookRotation, plus the aforementioned Euler Angles.  I won’t pretend to understand any of that linked page, but I was able to find the examples I needed to rough in a working implementation (this lives in the ranged_weapon script attached to the player’s “bow”):

if (canShoot)
{
    //Debug.Log("yes");
    //make bullet
    //Debug.Log("BANG! " + i);
    //Debug.Log("Creating a bullet at " + transform.position);
    Vector3 targetVec = lookscript.lookDirection;
    Quaternion targetRot = Quaternion.LookRotation(targetVec);
    Quaternion flatTargetRot = Quaternion.Euler(new Vector3(90.0f, targetRot.eulerAngles.y, 0.0f));
    bulletClones[i] = Instantiate(bulletTemplate, transform.position, flatTargetRot) as GameObject;
    currentBulletsAlive++;
    //plant a reference to this weapon in the bullet when it is created
    bullet_base bulletscript = bulletClones[i].GetComponent();
    bulletscript.weapon = transform;
    //throw bullet
    bulletPath = lookscript.lookDirection;
    //actually it makes more sense for the bullet to control its own movevemt
    //but will leave this variable in to ref from the bullet script
    //activating cooldown
    canShoot = false;
}

The canShoot bool is to prevent bullet spam, and is made true on GetButtonUp. The bullet itself carries a script which throws it in the right direction (requiring that neat trick just above where we inject a value into a variable owned by something we just created, like inoculating an infant). The “bullet fall” mentioned above happens because for whatever reason the path to the target can sometimes have a y value of -0.1, which will cause it to fall through the ground plane somewhere in its flight time. The hack above led me to really understand the difference between a solution and a hack in a way that I never had before.

 A bug happens when some assumption you have about some data you have is wrong. If you trace the path by which you received the data backwards to where it diverged from your expectations, then re-derive the data from its sources so as to produce the desired result, you have solved the problem. If instead you take the data in your hand and say “well, regardless of what you think you are, you’ll conform to my expectations now so that I can proceed”, you have a applied a hack. It’s obvious why this is dangerous, and it’s equally obvious that there are any number of reasons why you’d do it anyway: maybe the source of the bug is deep within someone else’s code, or the exigencies of time and budget simply don’t allow for a proper solution. Hacking is about picking your battles, knowing when to do surgery and when to just use a bandage and cross your fingers.

Some collider-based debug statements showed the bullet striking the bear, but the game didn't alert the player. I decided to flash the bear red by changing the material color, to my horror this was permanent after I hit the play button to stop the session. Turns out Materials can be instanced too, and a simple co-routinue times the flash effect:

matInstance = Instantiate(baseMat) as Material;
baseColor = baseMat.color;
renderer.material = matInstance; 

[…]

void OnCollisionEnter(Collision collision)
{
    if (collision.collider.tag == "playerBullet")
    {
        Debug.Log ("enemy hit by player bullet");
        StartCoroutine(DamageFlash());
    }
}

IEnumerator DamageFlash()
{
    matInstance.color = Color.red;
    yield return new WaitForSeconds(0.25f);
    matInstance.color = baseColor;
}

So the bear is hit, and everyone knows it. Coming up next:
  • Health, damage, and death
  • GUI enemy health bars
  • A GUI for the player
  • Some proper character models??
  • A proper “world” of tiles? (Maybe procedurally generated???)
The current build of Project Catalan can be played here.

Monday, June 23, 2014

LETTER FROM THE FRONT: WRITING TIPS

I've been writing. I stepped away from Unity and this blog to do a writing project, which is now over.

A writing project is a menacing jungle full of traps and enemies. The enemies may be projected out from behind your eyeballs, but the traps are very real. I've have spent years learning about all of them, and I have the closet full of horrific half-manuscripts to prove it. Lately I've had to pass through some dark places I had hitherto managed to avoid, and now I'm back with some simple tips that may help light your journey through that darkness. Some of these are surely either dead obvious, or so particular to my own process as to be useless, but maybe there's something here you can take with you.

#1. MAP YOUR WAY OUT

No, I don't mean actual drawn maps. I mean that when you dread sitting down to your story, because Mr. Jones has to get to the barber or whatever, and you don't know how the fuck he does it, and your last paragraph is about a bluebird, and jesus christ will this thing ever end, are you going MAD???
Calm down.
Set your actual current draft aside and open a new file called "what_has_to_happen_for_this_chapter_to_be_over.txt" A totally blank file. Now, picturing that awesome ending you've already got basically DONE in your head, step yourself through how you get there, as though you were making a list ahead of going down to the grocery, drug and hardware stores the night before a hurricane. "OK Fred has to get his passport photo taken, Rachel has to go to court and plead no contest.." as you start to really articulate all the details that are holding you back in the story, you realize that some are either readily solvable or non-issues. Some are still problems, of course, but now you have a much clearer idea of where you want to go and how you want to get there, and what you need to spend energy giving to the audience versus what the audience is willing to take on faith.

#2. AS YOU NEAR THE END > START A PROJECT NOTES FILE (IF YOU HAVEN'T ALREADY)

One of the things that will keep you from the finish line is that you'll have a cool idea, but think, "oh, this means I have to go back and restructure some things to make this work, but I like this so much I want to make it work, so let's..." and you pick up the shovel and your enthusiasm falls out of your butt.
Don't stop your forward momentum. If your new idea requires rewrites of earlier material, take a few sentences of notes in the alternate document of "project_revision_ideas.txt", just to get the idea out of your head. Then, continue as you were, with the assumption that the work has already been done, the past has already been corrected. If you know where you are and where you are going, you can trust the past to explain itself later; do not go back to it and kick cans around while you still have work to do in the moment of the story. A great advantage of this technique is that when the time does come for you to gird your loins for the next draft, why look, you already have what's basically a roadmap to the weak spots. As an optional aside to this:

#3. USE COLORS 

You might be amazed at the power of this technique: when something is obviously not quite right, but difficult or impossible to make right at this very moment... write FIX THIS next to it and make it bright pink and bold. Then move on to the next paragraph and keep going. If you move far enough ahead, the next time you open the manuscript and see that, you'll be like, oh, right, and do a sentence or two that writes out your original half-assed flailing at an idea and replaces it with an actual idea that you worked out below in the meantime. This is preferable to spending hours banging your head on this one part because it had to be just right just then. Colors, shapes, pictures or links to pictures: if you can't the words you want on paper, it's OK to just put down a signpost or a reference, as long its clear enough that you'll know what it means later. This is a technique stolen from programming, where early code is studded with TODO and HACK FIX THIS. Don't let contemplation of tomorrow's work keep you from doing today's.

#4. AS YOU NEAR THE END > ANTICTIPATE AND EMBRACE "POST-PRODUCTION"

Making a complete first draft is like passing a god damned kidney stone, you definitely don't want to go back into that bathroom for at least a little while. However, whatever indexing, appendixing, formatting, and bow-wrapping details your particular project requires still stand between you and rung zero, which is the first person who is going to read it and tell you it sucks. Don't be passing around raw unformatted files of rambling text. You don't buttonhole people on the street and yell at them unceasingly, do you? Have some manners. Respect the potential person whom you are asking to read your work by presenting them with something that is not visually worse than what they already have to read during the course of the day. Going back over your work in various ways just to make it more visually presentable is a necessary part of finishing, and if you've already adopted a grim death march attitude by three quarters through your first draft, you are just not going to have the stomach for it. As you near the end, anticipate what you are going to need to do so it's not a surprise, and recognize that writing THE END doesn't mean you can run out into the street with it. BUT, heed the corollary:

#5. DON'T DO FORMATTING WORK IN THE MIDDLE OF A DRAFT

More generally: don't do anything during a draft that could potentially result in multiple conflicting versions of a draft. If you catch yourself copying draft text from one program to another, slap yourself. How many problems are you trying to cause for yourself here? Seriously? You want to spend hours reconciling multiple versions of a second or third draft?
You can do pretty stuff between drafts. If you started in a spiral notebook, finish the draft in the damn notebook. If you started on a PC, finish on a PC and do the next draft on your new Mac or whatever. Never split a draft.
The reason this happens is because writing requires you to switch between states of intense concentration and kind of mind-wandering states, and it's gratifying in a masturbatory way to idly reformat your draft. You are walking down the devil's path if you do this. Find something else to do while daydreaming. I hear some people enjoy Sudoku.

#6. GET TO THE PART YOU WANT TO WRITE TODAY (OR TONIGHT) AND WRITE THAT

An example: in your story, Farmer Bob purchases and wrecks a Maserati. In order to do this, he has to fleece some bankers and relatives, and perform various identity sleight-of-hand tricks. You feel compelled to make that part real because this is a realistic story, but the story started in your mind with this dream of Bob hauling ass on a twisty Iowa two-lane, and that's all you can think about as you write him in the banker's office, submitting his loan application and twisting his cap in his hands... The point is, any of your precious god-given time you manage to carve out to sit down to do the work, write the part you want to write. It's the least you can do for yourself. If you feel a need to sketch out some justification for getting to that part, give it a sentence or two. That stuff you write when you are seized by an idea and write what you want is always going to be loved and admired and actually read the most of anything you do, because it has your fire and your heart. If instead you are always having to set up a tedious house of cards to push your characters to where you want them to be, like a desperate Axis general shuffling units around a mock battlefield with one of those little pushbrooms... well, you're fucked, you've lost the thread. If you pursue the part you want to write, one of several things will happen: 1. Once your mind is free of the obsession of the part you wanted to write, it will naturally turn to other thoughts and any necessary exposition will fill that space. Then you write it and you're good. Or 2: if the part you wrote just isn't workable, you gained a deeper and necessary understanding of the story you really wanted to tell. Maybe the Maserati episode happens in a dream Bob has when he falls asleep driving the tractor. Maybe that dream never even makes it to the final draft, but your understanding of it informs Bob's character and makes your work better. Never fear that you are wasting time because you are writing the part you want to write, that's never the case.

#7.YOUR AUDIENCE NEEDS LESS EXPOSITION THAN YOU THINK THEY DO

A scene of two characters speaking about events in the present, if written skillfully and with the intent to do so, can cast strong light and shadow on any character's past, while never insulting the audience with a blunt disclosure that doesn't suit the conversations or the characters. An example: Billy has been in prison for five years. When his mother and his fiancee meet for the first time, for lunch, don't feel compelled to have either of them trumpet this fact just because it's the most important fact in their relationship. For this very reason, have them act like real people would, and tiptoe around the particulars of the subject, until the audience is wondering "what happened to this guy, did he get sick, did he go visit a guru in Tibet?" This segues nicely into:

#8. YOUR AUDIENCE WANTS TO DO SOME (EASY) WORK (THAT MAKES THEM FEEL CLEVER)

Your audience did not come to your entertainment to have every question they might consider answered immediately. By the same token they probably did not come to sit through some inscrutable outpouring of free assosciations. They probably came to participate in a give-and-take with you, that is enetrtaining, intellectually stimulating, and emotionally rewarding. They want to leave your work feeling like they know the world a little better, and they can't do this if you don't give them anything to think about. Conceal and reveal. Exposition and (ugh) "world-building" are not things you do at the beginning of a story, like the yellow Star Wars text crawling up the screen, to ground your audience in the self-imposed rules of your fiction, unless you are the worst kind of hack. If your fictional world (be it Castle Azgoth or 1973 Jersey City) has boundaries, and common knowledge, and things that mean certain death, let the reader learn about those things alongside the characters that they have become invested with (if you reach page 2, you are probably invested with a character). Don't profess: let characters experience the world, and bring the reader along. The same goes for realism: don't tell us the husband suspects infiedlity, show us late nights alone while the wife is at the office, and callers that hang up when they hear a man's voice. Trust the reader a little bit and the reader will be more interested. Treat the reader like a moron and they will hang up on your story.

#9 EMBRACE GENRE, REJECT GENRE, COMMENT ON GENRE 

Cliches get a bad rap. cliches are the Jungian archetypes of colloquial speech. Don't be afraid of an idea because it seems too familiar. There is nothing new under the sun... except you and your perspective on the stories we've all heard a thousand times already. If you have a new way to tell it, the whole world might listen.

Wednesday, January 15, 2014

The Terrible Twos


I think level two is looking pretty good, and I'm only about a month and a half behind schedule and have just a few major features to implement, and I have plenty of time and mental energy after my psychically non-demanding job to pour into all my portfolio projects...

Well I do think it looks alright, compared to the opening level. I'm learning. When designing level one, I had just discovered some tutorials on making grids of tiles in Unity, and was enraptured by this idea of a "tile engine" and all the games I was going to make with it, and somehow got it into my head that the various buildings all had to be made of tiles, and somehow all the tiles had to draw from a single 256x256 sheet, so all those brick buildings in the first level are made up of instances of like BRICK_BLDG_LOWER_LEFT_WINDOW tiles and it's horrible. The great joke is that I thought this was somehow saving me memory as I blithely constructed fifty different materials all drawing from the same tile sheet. In the end I don't think it matters much but I made a lot of extra work for myself to produce something that could have looked better.

In a way, though, I did make a bit of a tile engine, because when it was time for level two, I duplicated level one and just took everything out, save for the backgrounds and a single tile for the player to land on when I pressed start. I wanted to sculpt out a shape for the walkable areas of the level, and I started duplicating that tile and moving it around. Soon, I found I wanted images of the mid-ground scenery, I think of these in my mind as "flats", the is from theater, where it means a large frame built from plywood, with canvas stretched over it, on which is painted something like a castle battlement, or a storefront, or a brick wall.

A flat here is just a gameObject with a Mesh Filter and Mesh Renderer components. The Mesh is a Quad, and the renderer's material is made to point at a Texture of X by X (powers of two, please) and you have onscreen whatever it is you drew in your favorite "draw stuff" program. Just place these further away on the z-axis than your player and the ground he or she must collide with, and you have 2d scenery.

Glossing quickly over the quality of the art itself (yyyyeah), we come to the matter of the ghost, who presented a particular problem. Enemies in WAFHGame execute a function called "Patrol", and enemies are a sub-species of character, that is to say the script WafhEnenmy.cs is a class which inherits from WafhChar.cs. The problem is that WafhChar only executes the Patrol function during its update if the Char in question is Grounded. 

Being Grounded in Unity is a particular state, like being flat-footed in D&D. (if you get that reference, I'm sorry). The Character Controller is Unity's answer to one of the common beginner game dev problems: "I need some object that represents the player than can listen for all sorts of input, and respond naturally to all sorts of things, and inteact with both the environment and anyone else around, in all possible types of games." A lot of people seem wary of the Character Controller, but for a lot of us it's a godsend and we wouldn't be here without it, honest to Bob. Code low-level game controller input systems? Are you out of your mind?

So here we had a ghost who would not Patrol, because since I set his character's gravity to 0, to keep him from falling, he never acquired the property of being Grounded, so he would never Patrol. First thought was to allow Patrol to fire when not Grounded. Now, as I'm writing this, I wonder "why didn't I just remove the Patrol check from the conditional of being Grounded? Let falling skeletons Patrol in the air for a few fractions of a second when they fall off a platform, they're not hurting anyone." A noble thought, and yet my baser natures won out. My memory grows dim. I can say for sure I ended up extending WAFHGhost from WAFHChar: 


public class wafhGhost : WafhEnemy {
 //ghostly vars:
 float waverYVariance = 16.0f; //how spooky do we get
 float maxY;      //calcd from current position
 float minY;      //calcd from current position
 Vector3 currentPos;
 float InitialY;     //source for calcs
 float currentY;     //source for calcs
 float targetY;     //where we are going
 float targetDistanceDelta = 1.0f; //dunno
 CapsuleCollider capsule;
 Vector3 vertTarget;
 Vector3 myCenter;
 Vector3 ghostVelocity;
 float ghostYSpeed;
 
 //public GameObject debugCubePrefab;
 //GameObject debugCubeClone;
 
 public override void Start () {
  
  base.Start();
  gravity = 0.0f;
  InitialY = transform.position.y;
  maxY = InitialY + waverYVariance;
  minY = InitialY - waverYVariance;
  capsule = transform.GetComponent();
  //debugCubeClone = Instantiate (debugCubePrefab, transform.position, transform.rotation) as GameObject;
  ghostYSpeed = 50.0f;
  deathOffset = new Vector2(0, 0);
 }
 

 public override void Update () {
  base.Update();
  myCenter = new Vector3(transform.position.x + (controller.center.x), transform.position.y + (controller.center.y), transform.position.z + (controller.center.z));
  GhostlyShenanigans();
  ghostPatrol(patrolLimit);
  //Debug.DrawRay(myCenter, debugCubeClone.transform.position, Color.green, 0.1f);
  
 }
 
 void GhostlyShenanigans()
 {
  currentY = transform.position.y;
  AdjustGhostVelocity();
  GhostFloat(transform.position.y);
 }
 
 public override void Patrol(float patrolLimit)
 {
  base.Patrol(patrolLimit);
 }
 void AdjustGhostVelocity()
 {
  if (transform.position.y > maxY)
  {
   //Debug.Log("broke max, moving down");
   ghostYSpeed = -ghostYSpeed;
   
  }
  if (transform.position.y < minY)
  {
   //Debug.Log("broke min, moving up");
   ghostYSpeed = -ghostYSpeed;
  }
  ghostVelocity = new Vector3(0.0f, ghostYSpeed, 0.0f);
 }
  
 void GhostFloat(float currentY)
 {
  //transform.position = Vector3.MoveTowards(transform.position, vertTarget, targetDistanceDelta);
  controller.Move( ghostVelocity * Time.deltaTime );
 }
 


 void ghostPatrol(float patrolLimit)
 {
  state = CharacterState.Walking;
  patrolTime += Time.deltaTime;
  //print ("patrol time " + patrolTime);
  if (patrolTime < patrolLimit)
  {
   //the ifs in here are to handle enemies with flipped textures cause I suck at art asset generation
   if (facing == 1)
   {
    velocity.x = walkSpeed; 
    if (gameObject.tag == "enemy")
    {
     ragePixel.SetHorizontalFlip(true);       //texture flip
    }
    else
    {
     ragePixel.SetHorizontalFlip(false);
    }
    ragePixel.PlayNamedAnimation("WALK", false);    //texture animation
   }
   if (facing == -1)
    {
     velocity.x = -walkSpeed;
     if (gameObject.tag == "enemy")
    {
     ragePixel.SetHorizontalFlip(false);       //texture flip
    }
    else
    {
     ragePixel.SetHorizontalFlip(true);
    }
     ragePixel.PlayNamedAnimation("WALK", false);    //texture animation
   }
  }
  else
  {
   //print ("FLIP FUCKER");
   patrolTime = 0.0f;
   facing = -facing;
  }
 }
}



We are Patrolling every Update, but this is really the same RagePixel code we use in the main Patrol function, it's a copy/paste. This, as far as I have gathered, is one of the sadder and more shameful sins you can commit writing code: having to write something out in more than one place. It is an invariable sign that you have failed to optimize, misaligned your architecture, fucked up in general.

None of this is what I was meaning to write a post about. I meant to write about a particular revelation during the last phase, the placing of the bus transfers, the deciding which branches should have enemies walking (or floating) back and forth on them: I sat down to the business of level design and realized I had already made most of the important decisions already.

"Level Designer" is the cap I like to picture myself wearing, and it's a role I've made a decent living holding before, and I've often thought of the level design "parts" of making WAFHGame as satanically delicious treats to gorge on when I had finished the Volga Boatman gruntwork of asset preparation. Well, as it turns out, when I decided the size of the house and store flats, that was level design, because that, combined with the speed of the player (also level design) determines how fast the scenery moves by, which affects how your eye registers it and both how much attention you pay to it and at least part of your emotional response. Drawing the trees, and deciding how far apart branches should be, that was level design, so is the scroll speed on the parallax skyscrapers. Anything that happens to you in the level is by definition a result of level design, at some level.

Of course for tiny projects, level and gameplay design are inseparable, but I think it's an easy thing to lose sight of as projects get bigger. The size of the tile and the length of the jump are bigger level design factors than anything else in WAFHGane, and it's impossibl to make any level design decisions that don't depend omn those. I keep trying to adjust  the jump as I go, and it often feels unsalvageable and floaty and tedious, and I want to start over, but of course that's insanity. It just has to get done, but every decision, even the most frivolous-seeming art decision (sorry artists) has direct effects on gameplay and are a core component of level design. As someone like Timothy Leary might have said: "The more I get into it, the more it's all one thing".

Three levels, with different art. Each level has a pair of enemy types. Some enemy types repeat, but pairs don't. There are a few unlocks you can get by beating levels in particular ways. The experience flows smoothly, from menu to gameplay, with appropriate UI popups, without crashing.

That's it, not even a leaderboard, no points even! How hard could it be. And yet here I sit, blogging. Not working! Not drawing skeletons! Shame on me for reals. I'm 2/3 done.    
       






Sunday, December 15, 2013

Better


I'm now controlling the layer collision by use of a raycast, and the results are better but not perfect. I cast from about knee level down to a bit past foot level, and if there's a collision there I turn the branches on, otherwise they are off. This does neatly solve the problem of the player banging into the sides of colliders on the down arc of a jump, but it introduces another problem: some of the branches are close enough together vertically that when the player jumps, his head hits the branch above before the ray leaves the branch below, and thus the overhead branch doesn't get turned off. I've tried tweaking the length of the ray but it has to be at least a certain length, otherwise certain slanted platforms have trouble registering and the player falls through.

The best thing to do here is probably to raise the problem branches so that they don't cause as much head-bumpage. It's an interesting lesson in that everything has to react to everything else, the movement mechanisms and the environment design are totally interdependent. Well, it was about time for an art push on this level anyway, so I guess it's not too much trouble to move some tree branches around. Here's the final version of the raycast script:


using UnityEngine;
using System.Collections;

public class footShooter : MonoBehaviour {
 RaycastHit info;
 CharacterController controller;
 Vector3 center;
 float floorDist;
 CapsuleCollider cap;

 Vector3 lowCenter;
 void Start () 
 { 
  cap = gameObject.GetComponent();
  controller = gameObject.GetComponent(); 
  floorDist =  controller.height/3;
 }

 void Update () {
  center = new Vector3(transform.position.x + (controller.center.x), transform.position.y + (controller.center.y), transform.position.z + (controller.center.z));
  lowCenter = new Vector3(center.x, center.y - (controller.bounds.size.y/3), center.z);
  Ray footRay = new Ray(lowCenter, Vector3.down);

  if ((controller != null) && (cap != null))
  {
   if (!controller.isGrounded)
   { 
    Debug.Log("centre = " + center);
    if(Physics.Raycast(footRay, out info, floorDist))
    {
     Debug.Log("red ray");
     Debug.DrawRay(footRay.origin, footRay.direction*floorDist, Color.red);
     Debug.Log("hitting branches");
     Physics.IgnoreLayerCollision(10, 13, false);
    }
    else
    {
     Debug.Log("blue ray");
     Debug.DrawRay(footRay.origin, footRay.direction*floorDist, Color.blue);
     Debug.Log("ignoring branches");
     Physics.IgnoreLayerCollision(10, 13, true);
    }
   }
  }
  else
  {
   Debug.Log("controller is NULL");
  }
  
 }
}


Sunday, December 8, 2013

The Cult Of Ray


Raycasting is a common, essential technique in modern game making that I had until now more or less avoided. I'd need it in order to make my one-way platforms work as intended, but I was having trouble in the context of the platformer so I decided to back up and go to a blank project, and to kill two birds it seemed like a good moment to set up something I've had in my notes for awhile: a template for experimenting with FPS gameplay in Unity.

As laid out by this tutorial, a basic fps setup is no further away than a plane, a camera, and a First Person Controller dragged out of the Standard Assets folder and into scene view. Before I could get to the raycasting though I needed to scratch a different itch: I had become spoiled by modern PC FPS titles into expecting gamepad support as a seamless option to mouselook. 

Before you invite me to turn in my PC gamer badge and graphics card, consider a game like the excellent Metro: Last Light, which I'm currently playing through thanks to the fall Steam sale. I've experimented with both control schemes, and while, yes, you can't beat a mouse for combat turning and aiming speed, when you're involved in an "adventure FPS" with a lot of different player verbs, it just feels really natural to have something like "wipe condensation from gas mask" on a shoulder button. Maybe this goes back to my lack of skill as a typist, but unless we're talking about WASD I'm never quite certain of my keyboard execution in a twitch situation. The controller is also just more interesting to me for whatever reason. 

So I had to have my 360 controller, and I did it by replacing the script MouseLook (part of that Standard Assets character package) with StickAndMouseLook, which goes something like this:

using UnityEngine;
using System.Collections;

[AddComponentMenu("Camera-Control/Stick and Mouse Look")]
public class StickandMouseLook : MonoBehaviour {

 public float sensitivityX = 15F;
 public float sensitivityY = 15F;

 public float minimumX = -360F;
 public float maximumX = 360F;

 public float minimumY = -60F;
 public float maximumY = 60F;

 float rotationY = 0F;
 string[] jNames;
 
 bool isGamepad;
 
 void Update ()
 {
  jNames = Input.GetJoystickNames();
  if (jNames.Length > 0)
  {
   //Debug.Log(jNames[0]);
   isGamepad = true;
  }
  else
  {
   //Debug.Log("no gamepad");
   isGamepad = false;
  }
  
  if (isGamepad)
  { 
   float rotationX = transform.localEulerAngles.y + Input.GetAxis("rightStickX") * sensitivityX;
    
   rotationY += Input.GetAxis("rightStickY") * sensitivityY;
   rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
    
   transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
  }
  else
  {
   float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;
    
   rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
   rotationY = Mathf.Clamp (rotationY, minimumY, maximumY);
    
   transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);   
  }
 }
 
 void Start ()
 {
  // Make the rigid body not change rotation
  if (rigidbody)
   rigidbody.freezeRotation = true;
 }
}

Of course you need for those axes to actually exist, so you set them up in the Input settings like this:
Now you can use the mouse, plug in a gamepad, play that way, unplug it and you're back to mouselook. Movement gets handled automatically by the character motor because it uses the horizontal / vertical input axes, which the sticks already do as well. Interesting to note that the triggers are read as axes themselves rather than buttons, requiring some fiddling elsewhere to get semi-auto behavior, and that the Invert checkbox is required to get "move up to look up" behavior (you know, Normal Person style) out of the Y stick. Either I set something up backwards or one of the coders behind this is one of those sickos who thinks Inverted Y controls should be the status quo. I'll give them the benefit of the doubt and assume the mistake is mine.

So, raycasts. The vexing stumbling block for me was always this: rays are invisible. Physics.Raycast takes as parameters an origin, a direction, and a distance. Debug.Ray can be used to draw rays, but its parameters only have an origin and a direction, no distance. The reason behind this involves some of that spooky math stuff, wherein a vector can contain both a direction and a distance. There's some normalization math that could be involved here but of course once I saw that I ran in the opposite direction.

As it turns out, if you have the ray you have all the info you need to draw it. Take this ray:

Ray shotRay = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));

Since that's just specifying a point on the main camera, from which it will travel until it hits something, it was far from clear initially how I would get the position and direction/distance information. Luckily, the Ray object itself contains some information, so shotRay.origin can be used as the originating point. The second variable can be got by subtracting the Vector3 from which the shot came from the Vector3 at which the shot hit. So, assuming this script lives on the shooter, you can do this:

Ray shotRay = Camera.main.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0.0f));
    RaycastHit info;
    if (Physics.Raycast(shotRay, out info))
    {
     Debug.DrawRay (shotRay.origin, info.point-transform.position, Color.blue, 3.0f);
      
    }

And for three seconds you'll get a visual image of your raycast in scene view. I was emboldened enough by this to wonder if I could send hit particles out at an angle relative to the incoming angle, and sure enough there's a Vector3.Reflect. the RaycastHit info variable above comes back into play as \you can get the incoming hit direction like this:

inDir = info.point - player.transform.position;

and that same handy info variable contains the normal I need for the reflection, that is to say a line straight out of the plane we hit. Since I don't care where this line ends I was able to cheat in a magnitude for the debug line by multiplying it with an int, which is a little crazy but I'm just gonna go with it:

Vector3 reflectionDirection = Vector3.Reflect(inDir, info.normal);
Debug.DrawRay(info.point, reflectionDirection*100, Color.cyan, 3);


This gives us the rays depicted at the top of this post. I'm thinking (hoping) that armed with this I can turn back to the platformer and easily get the collision behavior I want. As soon as I'm done with this other idea I have about making these big blocks destructible. Shouldn't take but a few minutes...

Friday, November 29, 2013

In The Trees, In The Weeds


I've entered some impossible place where every task takes twice as long as the previous task. The goal was and is still three playable levels, with a few neat unlocks and a couple more enemies. Level 2 is supposed to represent Seattle's Queen Anne neighborhood, with its imposing hill spreading up the right side of the screen. There's not much platformer action to be had on a single steep hill, so what to make platforms out of?

Pioneer Square had the easy visual metaphor of that big iron lattice pergola (yeah I had to look up what the hell that thing's called), but nothing so obvious exists in QA. Trees were an obvious solution, I remember planning to have a few in one area or another, and they are about as classic a platform-disguise trope as you can get. One problem that arose quickly is that I can't draw a convincing tree.

The method I ended up with is far from ideal but somehow the appearance was able to barely pass my internal editor. After all, I had to come up with something. I drew out the trunk and each branch, as well as four squiggly bare "sub-branches". I flipped each of the sub-branches for a total of 8, then took a green 32x32 "leaf" and used it as a stamp across all of those, as shown here:



Then each individual branch of the tree gets stamped with a selection of these sub-branches and attached to the trunk. I made each branch its own gameObject because I had this idea of scripting them all to sway gently in the breeze, which I may still do but whenever I picture it now it looks like it would be unsettling, which is maybe a point for and not against. I've thought also about doing a lighter green semi-transparent globe of leaves behind each tree to give them a more traditional tree-like appearance, but I'm not sure I could really get it right.

The tree branches also presented an opportunity for varied routes through the level, something more interesting than flat planes, so I rigged up the hinged box colliders shown at the top. Now, to do this kind of platforming right, you need for the player to be able to pass through these colliders when jumping from beneath. You can't make them go to the end of each branch and then try to reach the one above, it wouldn't work. There are many ways to do this.

One important point is that each face of a collider only works in one direction. So theoretically the easiest solution would be to use, instead of box colliders, mesh colliders with a single quad sprite mesh, facing up. Player passes through from the bottom, collides on the way down.

I didn't go with this, because some early experiences and research led me to understand that single plane collision with a 3d object in a 3d environment is inherently just a bad idea. You're subject to "tunneling", where the surface area that records a hit is so narrow that your colliding object can pass through it between the high-speed snapshots your physics simulation is taking of the game state. This Unity Amswers user sums it up. 

Another solution, likely quite easy for many, would be to take the standard Unity box collider, import into Blender or what have you, remove the bottom, and export back to Unity. Custom collision mesh, very nice. Problem is I don't have any skill points in 3D modeling.

"It's free, there are tutorials, you could learn to do that much in an afternoon!" Yes but I have a series of goals here and I can't be endlessly sidetracked. Maybe my next game will involve custom 3D models but this one doesn't and I need to finish it with the tools at hand. That's the theory anyway: when everything is taking twice as long as you thought, don't go looking for hours of work to put between you and the next thing, just find a better way to solve the immediate problem. You spec the talent tree you're working with the XP you have and you play your class, you don't try to be All Things At Once.

So it turns out Unity has a feature called Layer-Based Collision Detection that's actually more or less perfect for this. The tree branches go on one layer, the player goes on another, then we ask a question, is the player moving up?
 
void CheckForPassPlatform()
{
 if (!controller.isGrounded)
 {
  jumpThisPos = transform.position;
 
  if (jumpThisPos.y > jumpLastPos.y)
  {
   Debug.Log("ignoring branches");
   Physics.IgnoreLayerCollision(10, 13, true);
  }
  else
  {
   Debug.Log("hitting branches");
   Physics.IgnoreLayerCollision(10, 13, false);
  }  
  jumpLastPos = jumpThisPos;
 }
}

I probably don't need that isGrounded really. Like I said it's more or less perfect, but the less happens becuase of my hinged collider platforms. There are occasionally cases when the player is coming down from the apex of a jump that took them halfway through the platform above. The player won't hit the thing they are already in the middle of, but if the player is also moving sideways they will bump into the next piece of collider at the hinge. The player is heading down so the collision layers are reading each other, which we would want if the player were above the collider, but since the player is to the side, we don't want this.

Well, I know there's an answer here, and I know it involves raycasting, so I've been investigating that, but I find raycasting difficult to use. The ray is invisible, so you have to draw it using Debug.DrawRay, but Debug.DrawRay takes a different set of arguments than Phsyics.Raycast, so how do you know your debug line is really the same as your raycast line?

I guess when the player is coming down from a jump, we raycast from the player's center to a point just beneath the player's feet. If there is a collision there, we allow the layers to collide, otherwise we don't. This should allow the player to pass through side collisions on the way down.

I really hope I don't get any cool ideas like this for level 3.