Scrolling Combat Text Tricks for Unity using NGUI HUDText


Straight to the details, I have been working on a new project, basically a FPS RPG hybrid. I had previously used NGUI HUD Text for Unity on a project and loved the overall look and feel, having played games like World of Warcraft and enjoyed seeing those rolling numbers. I finally got it working for my new project after bashing my head against the wall for awhile, so I thought I would post a few neat additions to really clean up the overall look of the scrolling numbers.

  • Example 1 – HUD Text Vanilla

As you can see there is no logic for distance or visibility. Let’s change that.

  • Example 2 – HUD Text with Sight Restrictions

Now we implement camera sight restrictions. In this case if the renderer is off the screen we disable the HUD Text. The code is pretty basic, best described by http://wiki.unity3d.com/index.php?title=IsVisibleFrom. Create that function as something globally accessible. In this case I used a generic GlobalStatics class with public static functions, then I call it via the code below.

if(!GlobalStatics.IsVisibleFrom(this.GetComponentInChildren<Renderer>()))
{
mText.enabled=false;
}
else
{
mText.enabled=true;
}

  • Example 3 – HUD Text with Distance Scaling

Now we add some basic distance scaling. Set a max and a min size and a scale factor (which is 20 here).

float distance = Mathf.Abs(Vector3.Distance (this.transform.position, GlobalStatics.MainPlayer.transform.position));
float scale = (1/distance*20);
if(scale >2)
{
scale = 2;
}
else if(scale <0.05)
{
scale=0;
}
mText.transform.localScale=new Vector3(scale,scale,scale);

  • Example 4 – HUD Text with Ray Casting

Last step is to do some raycasting to ensure that when you can’t see any enemy you don’t continue to see status updates. I added a Debug ray just to make sure it was going the right way. Some of this code isn’t entirely necessary, such as multiplying the distance by 2.0f, but it worked more accurately for me so I left it in for now. I place this in the Player’s update function as the player’s positioning will determine what health bars they can see. (Updated to include layer masking)

RaycastHit hit;
int layerEnemy = 14;
int layerEnemyWeapon = 15;
int layerEnemyMask = 1 << layerEnemy;
int layerEnemyWeaponMask = 1 << layerEnemyWeapon;
int combinedMask = layerEnemyMask | layerEnemyWeaponMask;

Physics.Raycast(new Vector3(this.transform.position.x,this.transform.position.y+0.1f,this.transform.position.z),-(this.transform.position – e.transform.position), out hit, combinedMask);
if(hit.collider!=null)
{
if(!GlobalStatics.IsVisibleFrom(e.GetComponentInChildren<Renderer>()))
{
e.mText.enabled=false;
}
else
{
e.mText.enabled=true;
}
}
else
{
e.mText.enabled=false;
}

That’s pretty much it for a fully functional scrolling combat text. The only other words of wisdom, study the scene examples and copy them exactly. Any minor changes in how you layout the objects can cause odd behavior (like my enemies following through the world for some reason).

Advertisements

New Project – Monster Dash (Working Title)


Just a quick update. After minor success and lots of failure on the 360 chatpad implementation, I moved on to a new game using the Unity framework. Well long story short, I need to aim for something a little more simple for my first Unity effort. I learned a lot but my game design was way too complex for my skills 🙂

So I moved on to what I am effectively calling Monster Dash. Here’s an early clip of the first build:

Obviously lots to fix, but the main goal is to build something fast that is easy to pick up. I’m mostly posting this to motivate myself. Things have been busy here (all good stuff, just busy), so I just need to not give in to my ADD urge to jump to another project.

Target mobile platforms for the first release, hopefully early next year. Lots to do, but I’m happy with what a weeks worth of progress and a lot of purchased Unity Assets can do. The asset store really is amazing for prototyping quickly (though not always cheaply).

One quick hit on the code:

Tracing a path and following it is pretty straightforward.

if(isMouseDown)
{
  RaycastHit hit;
  if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition),out hit))
  {
   //Game is isometric so ignore Y domain as it is just used for layering/height.
    if(myPoints.size>0 && Mathf.Abs(Vector3.Distance(new Vector3(myPoints[index].x,0.0f,myPoints[index].z),new Vector3(hit.point.x,0.0f,hit.point.z)))>0.3f)
    {
      myLineRenderer.SetVertexCount(index+1);
      myLineRenderer.SetPosition(index,hit.point);
      myPoints.Add(hit.point);
      index++;
    }
  }
}
This is the draw code. It basically acts on mouse down, does a raycast, and if the point is larger than .3f away add the point to a LineRenderer.
Then you just LERP from your player position to the points. The hard part is controlling speed, which I haven’t perfected yet, but I will post that solution later.
That’s almost all of the code it took to get this working, so far so good.

Joysticks on the Brain


If you tried to install the alpha build of my controller driver, you probably noticed it mostly stinks. Sure it can emulate keystrokes well, but it can’t emulate the joystick very well because it relies on a virtual joystick that provides DirectInput data. What would be great, and what everyone would love, is if I could send XInput data, and that’s where the topic of my rant… er, post comes in.

Let’s look start by looking at the options.

Extend Current Functionality

This option would be the easiest, but falls on its face quickly. It’s a simple enough question. Why not just enhance the current driver to add chatpad support? The driver already does a good job implementing controller state and joystick controls, so just add the chatpad… well the driver is provided by Microsoft, so it’s not open source, and you can’t have two drivers handle data from the same device, 1 driver per device. So extending? Not possible.

You can’t really fault Microsoft’s driver team for this omission because they implemented the XInput protocol, which hasn’t been extended for the chatpad. At the same time it works on the 360, I would guess through a custom, non-XInput method. It is still sad though, because mapping the chatpad and translating values took all of two days, with no prior knowledge of their protocal, just trial and error, so this could be so simple.

Virtualize a Physical Joystick

This is where I ended up next. It seems pretty easy, implement a generic driver that gives you control over the device (libusb). So that gives you the data from the device, no problem. But then you need to send something back to the system, so you need something that emulates a joystick driver (or you use keyboard input, but that is a horrible solution for analog positions). Enter a virtual joystick driver (vJoy). So now you have two drivers installed to give you control and send data back.

The worst part is this method works great for the chatpad, because you can send virtual keystrokes easily in Windows, but you can’t sent virtual joystick commands. So now we solved our main problem and created a bigger problem, as we basically broke the joystick.

This solution is fragile, surely we can do better?

Redirect Input

Next up let’s look at some DirectX control frameworks, DirectInput and XInput. It seems like a great idea, if you could just redirect input from your driver to one of these two frameworks programs would see joystick input. Let’s start with XInput. This is a great protocol for implementing controls, if you are trying to receive input, but if you want to send input you need a different SDK, which isn’t publicly available… so if I wanted to write an XInput compatible controller I can’t. This is made even worse because Microsoft has stopped updating the DirectInput framework. Wait what? That can’t be right.

DirectInput has been around awhile, and is pretty well supported, but many of the recent games for windows are only implementing XInput. Its okay though, that degrades to DirectInput. The problem is, you still need some kind of driver, you can’t just send DirectInput commands (as far as I can tell). I hate developing drivers, so this was my last resort, but I guess now I have no choice.

Develop a Driver

Okay, you have given up and decide to develop a driver. First choice, kernel level or user mode? Well, my preference would be to develop using the Windows Development Kit 8 (WDK8), and since I hate C++, my preference is user mode, which gives me a little less control, but let’s me write less direct access code. But wait, WDK8 only works with Visual Studio Professional 2012, which runs $500, ugh.

Why make it so painful to develop for your systems? If you want a healthy ecosystem you can’t kill everything that wants to grow.

No point to all this really, just ranting and forming thoughts on how best to proceed next. I’m not sure everything I said above is 100% correct, but its the best research I have come up with so far.

It looks like if I want to make progress, I will have to drop down to C++. I don’t care if I’m not a real developer for avoiding C++ like the plague, but I program for fun and stress relief, that is all, so I work in the languages I like and on the projects I want. It’s just so much more cathartic that way 🙂

My memory leaks enough in real life, I don’t need my code doing the same.

Alpha Build of Xbox 360 Wireless Controller with Chatpad App


Image

Well the first build is here. This is a WPF app running a number of drivers to make this all work.

This project came from me being upset that my new chatpad wouldn’t control my htpc, because the winder driver byMicrosoft doesn’t send the chat pad data to the PC (what?). After a little digging, I found this was a common complaint:

MP3 Car Contest and Wired Driver

Here are the install instructions:

  1. Head on over to my github page and download the entire project as a zip (sorry it isn’t packaged yet)
  2. Extract the zip file to a directory on your computer.
  3. Download and Install libusb (verson 1.2.6)
  4. In order for this step to work, you need to run install-filter-win to select the Xbox Wireless Receiver and the inf-wizard to install the driver
  5. Download and Install vJoy (version 2.0.2)
  6. Run the vJoy Configuration Program and select the choices below:

Image

Currently I only support one joystick with no rumble or voice, but the multiple joysticks will be easy and it doesn’t look like voice/rumble will take much more effort. I also may be missing a configuration step in libusb, I think you just select the wireless receiver, but I’m not positive. It has been awhile and I don’t want to pull it off my PC yet.

Once you have completed this step you can run my app. Just drill into the bin\release folder and run the exe.  This is an alpha build, so expect some crashes 🙂

XboxApp

Please let me know if you have any problems!

Thanks!

The Developer Blues


Have you ever been stuck on a frustrating problem as a developer?  I mean a really tough problem.  Days evaporate with little progress.  Debug statements return what seem to be contradictory values.  You Google search and Google search and Google search, until your fingers bleed.  You implement the same code one time, then again with different objects, then again with a different conversion, then again the same as the first time, but you forget you already tried it.  But nothing works.

You start questioning your worth as a developer.  You read examples and exclaim “my code does that exact thing and fails. @!$#$!!@#!!!!”

Then you squint… your eyes focus a little.  You look at a variable and start to question your sanity.  Then it hits you… you can’t believe how easy it was, how stupid you have been.  You know every developer has been there, but in that moment it is just your stupid and you, hanging out together.

Well my friends I just had one of these stupid moments.  4 days of coding lost because my mind was unfocused.

So what did I do? 

In short used the wrong variable.

My goal?

Parse an xml file into two arrays.  Turn those arrays into coordinates.  Display coordinates.  Simple eh?

Well basically I created two arrays of latitude and longitude.  And instead of converting those to coordinates, I reached back into the parsed xml, pulled the latitude and longitude again without noticing.  This meant I pulled the same 10 points over and over.  The problem was, everywhere else in the code (including my logging) I used the correct arrays instead of the xml… Which means I thought the debugger was crazy, but really everything was working.  It was just displaying a single point instead of a complex polygon, which I couldn’t see.

Not sure why I am posting this, mostly out of frustration and happiness that this is solved.

If anyone is curious I have more coming from my XNA game series but I have taken a side track, I have mad scientist mind get use to it, to work on a mobile app that sounded really fun.  I will post about that more as it takes shape.

Google Maps + Jquery Mobile Display Frustrations


This will be quick, and my first entry discussing mobile app development.  Basically I am creating an app that leverages jQuery mobile and the Google Maps v3 JavaScript API.  But adding jQuery mobile to the default Google code created a layout that had a 10ish pixel map.  Nothing made this layout work, except fixed width styles on the map canvas.  I searched and searched and found nothing but fixed width styles, so I just started trying some random css (sometimes it is better to be lucky than good).  Below is the working template:

<body>
<div data-role=”page” style=”width:100%; height:100%;position:absolute;top:0;left:0; right:0; bottom:0;overflow:hidden”>
<div data-role=”header” data-position=”fixed” style=”width:100%; height:10%;”></div>
<div data-role=”content” style=”width:100%; height:80%; padding:0;”>
<div id=”map_canvas” style=”width:100%; height:100%;”></div>
</div>
<div data-role=”footer” style=”width:100%; height:10%;”></div>
</div>
</body>

The magic is in the page styles.  Forcing the page to be absolute with 0 pixels from each edge forces the entire page to stretch (I think).  Of course the standard Google header sections apply.

I know there isn’t much detail, but this is a quick hit intended to solve a very specific problem.  If you need more insight either comment or send me an email 🙂

And good luck!

 

 

Flaming fire balls


So in my last post I gave a brief overview of how a physics engine like Farseer can be quickly implemented to make collisions detection and movement easier.  I didn’t go too much into this so let’s jump into a good example of the flexibility that a physics framework can give you.  Everyone loves magic. No not that magic, I mean real magic and, of course, by real magic I mean the imaginary magic.  You might be saying to yourself “I want to do real imaginary magic in a real video game.”  To that I say, I have the two step program to help you out.  Step one, read this blog.  Step two, profit.

Today we will look at three quick magic types.

1) Magic that disappears on contact

2) Magic that bounces off of objects

3) Magic that goes boom.

Let’s start with a look at our typical collision method.  Remember you subscribed to this event in the last blog.

public bool MyOnCollision(Fixture f1, Fixture f2, Contact contact)
{
return true;
}

Right now it does nothing different then the default code.  Remember f1 is the initiator, f2 is the contacted object and contact is the contact point of the collision (it is a little more complex but let’s keep it simple).  Let’s focus on the first two.  You have a few options when implementing this event.  You can implement it in a base object that all objects inherit from or you can give each object a specific collision function.  The first allows all collision code to reside in one place, which is nice, but you do spend much of your time determining what type of objects collided.  In the latter approach you always know what the initiating object is.  How?  Well as I said f1 is always the initiating object and if your method is running in, let’s say your character object, then you know your character initiated the collision.  Then you just need to determine what object it hit and handle the event, i.e. friend, foe, or inanimate object.

Now the easiest to implement is the 2nd type.  In fact the physics engine does this for you.  It calculates the angle of impact and velocity then provides the movement necessary to make the collisions realistic.  This means the ball of magic will bounce off realistically and then continue on its path (assuming you continue to update its path in the original direction, otherwise it will fly in the opposite direction of the collision).  Below is an example with four characters on screen.  Notice how in this case the magic bounces off and continues to strike other characters.  This requires no extra code.

Now an example of the magic that disappears on contact:

Assuming you have a collision handler on each object you can simply add

if (magicType == MagicType.Dissipate)
{
  f1.Body.Dispose();
 Global.MagicsToRemove.Add(this);
}

That is it, just dispose the body, it takes the fixture with it and you are good.  In this case you probably have a magic object as well that is unrelated to the physics engine.  Well we need to remove that object as well, but I wouldn’t do that until you exit the current Update() loop.  So I just add it to a collection that will be removed once the update is complete.  Before all of this you are probably applying an impulse on the target character and changing their life.  This part is up to you.

Now the final example which is the exploding magic:

else if (magicType == MagicType.Explode)
{
  Body.BodyType = BodyType.Static;
  disposeTimeStart = Global.gameTime.TotalGameTime.TotalMilliseconds;
}

Turn it static, which will allow it to continue interacting with the dynamic objects (causing them to be struck by the explosion) and also prevents the object from reacting to the collisions.  Objects that explode on impact aren’t great examples of elastic collisions so stop their motion and let them explode!  Then display the animation graphic.  You can simulate an explosion easily enough by simply expanding the CircleShape that we defined for collisions in the last blog post.  I set a timer here so that I can quickly expand the explosion and the image for the explosion.  Don’t worry too much about getting this exact, refine later, get the first 3/4 of the game working as quickly as possible and then worry about particle effects and more realistic explosions if you feel they add to the game.

Now we grow the exploding object

if (disposeTimeStart != double.MaxValue)
{
  Width+=(float)(disposeTime/Global.gameTime.ElapsedGameTime.TotalMilliseconds);
  Height += (float)(disposeTime / Global.gameTime.ElapsedGameTime.TotalMilliseconds);
  foreach (Fixture f in Body.FixtureList)
  {
    f.Shape.Radius += ConvertUnits.ToSimUnits((float)(disposeTime / Global.gameTime.ElapsedGameTime.TotalMilliseconds));
   }
 }

I won’t explain all the objects but I basically grow the local height and width of the magic object and the grow each fixture attached to the magic body in the physics engine.  Simple and easy to understand.  There is no magic in this code, as the object expands quickly it impacts more dynamic characters and the physics engine takes care of all the collisions.

The explosion is the tricky one, and you will find many people who call this too simplistic.  That’s right, it is, because 99% of games would work just fine with simple explosion code.  Add some effects, maybe check for distance from the focal point to determine damage, or cap the damage the explosion can cause to stop game imbalance issues (Area of Effect farming tactics).  There are more accurate explosion engines out there, and some good Box2D implementations, but get it up and running and test a simple version before you buy the Cadillac.

If you feel explosions are a core component of the game, then create a better representation of the true physics of an explosion, but most people won’t notice or care.  The goal is to get you up and running quickly so you can focus on gameplay.

Alright, feels like time to actually make some progress on my game.  I will be back to discuss weld joints and physical attacks.  Also it looks like my camera needs a few tweaks to better handle collisions.

Until then, stay saucy…

Advertisements