Tuesday, February 2, 2016

How to make a Health Bar in Unity

One of the bonus lectures in The Complete Unity Developer Class hosted by Udemy, involves the creation of a healthbar prefab, with the intent to publish the health bar to the Unity store. While I was able to submit my entry, I was not able to successful get it published, probably because it was too easy. However, I still learned a lot by this task, including one key thing, included below, that I have used in my upcoming untitled game, which you can see more about at my Google Group KD7UIY.
I had in mind that I wanted to have a transparent background, a custom foreground, the ability to choose colors for both, and customize the size as well. I then started to think about what other related items could be managed using the prefab. The most logical thing was to also include the Health script, as that would allow me to manage both quite simply. I chose to work with Glitch Garden because it seemed the easiest to work with, but I could have just as easily used any other project.

In the Zombie Runner project, we are introduced to messages. This seemed a logical approach to making the project simpler. I set up a hierarchy as follows, with the intent to pass messages between objects to loosely couple the system. As there are few objects, a Broadcast Message doesn't seem too resource intensive.
Next was a prototype script. As previously mentioned, I wanted to use the Health script previously used, in addition to a Health Bar script. I wanted to be able to set multiple colors, one for foreground and another for background. My inspector panel looks like this:
The most difficult part of this challenge for me was how to paint the colors. What I settled on was using a Texture2D specified at run time. Here is an example of such a texture. This texture is 1 pixel, which means when you apply it to an object, the object will all be one color. I'm interested to continue to play with textures, likely working on procedural textures made by code for the future.

        mainTexture = new Texture2D(1, 1);
        mainTexture.SetPixel(0, 0, mainColor);
        mainTexture.wrapMode = TextureWrapMode.Repeat;
        mainTexture.Apply();

Given the texture, one simply needs to attach it to the SpriteRenderer. This was done as follows:

        Rect unit = new Rect(0, 0, 1, 1);
        SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
        sr.sprite = Sprite.Create(backgroundTexture, unit, Vector3.zero);

Beyond that, I drew the background first. Then I drew the foreground as a child of the background. Finally, I updated the scale based on the health, making sure to clamp between 0 and 1.

To inform the object that it was dead, I used SendMessageUpwards("Die");. The object informed the Health that it was hit by using BroadcastMessage("SubtractHealth",10); And that was it. I did some testing, tweaking, and produced my final version, which I intend to use for other purposes.

Picture

Monday, January 25, 2016

How to make your own dialogs in Unity

Prior to programming in Unity, I did a lot of Android programming. One of the features I came to love was the Alert Dialog, where a simple popup is displayed which allows a user to make choices, enter and see data, and otherwise do things that just aren't a part of the main screen. In making simple UI displays, I wished to have a similar effect as these dialogs, but Unity doesn't have the same interface. Instead, I found I had to make my own, which turned out to be simple, but not completely intuitive. Here is an example of one such dialog
Note two things of some distinction. The first is that the dialog appears, with a series of buttons common for each situation. Some of the buttons are enabled, others are not. This dialog appears when a ship (Currently represented by a sphere) docks with a city. The right hand side shows options to buy goods, the left to sell. As I don't have any goods, I can't sell anything. I also have a button that appears at the bottom to dismiss the dialog, should I no longer be required to enter anything. Less obvious is that I have a background that darkens everything behind the dialog, so it doesn't interfere. One could even have a blurry shader, although I haven't done such a thing yet.

There are basically two ways I have found to make dialogs. The first is to have the dialogs in the scene, but either off screen or set to disable themselves in Awake (If they aren't enabled to start with, you can't select them). Then one either moves the dialog in to place, or enables it, depending on the options. The second option is to make the dialog, save it as a prefab, and initialize it when you are ready. I have chosen to do the second path, as it allows for a cleaner screen.

The background is a panel that covers the entire screen, but is disabled on startup. I simply enable this when I have a dialog present. The panel is semi-transparent black, with no sprite. The code follows a singleton pattern, allowing me to easily find it, with code as follows:

public class BackgroundPanel : MonoBehaviour {
    private static BackgroundPanel _instance;
    public static BackgroundPanel Instance { get { return _instance; } }

    private void Awake() {
        if (_instance != null && _instance != this) {
            Destroy(this.gameObject);
        }
        _instance = this;
       ShowPanel(false);
    }
    public void ShowPanel(bool val)
    {
        if (val) {
            gameObject.SetActive(true);
        } else {
            gameObject.SetActive(false);
        }
    }
}

As I am writing this, I am working on a new dialog, to show places in a city where one might go. I will show you the process I am using to make this work. The first thing of note is that I don't actually know how many buildings I will include in a city. First let's specify the area for the panel. See below, which shows the the panel's layout.
  I want something flexible, that allows me to add new fields without thinking too much. To do that, I've decided to use a Grid Layout Group, as follows. It's worth mentioning as well that there are horizontal and vertical layout groups as well, and that some customization can be achieve for each item using a LayoutElement component, which I will not cover in this post, but feel free to experiment with them yourself. Note that I've added padding, which is the outside edge of the layout, and spacing, which is the space between elements, to give it a less crowded look.
In the spirit of a Minimal Viable Product, I'm going to start with simple buttons. Eventually I'll probably do something more specific, but buttons will work for now. See how this appears when I add them, as below
Eventually I'll get to a place where I pre-fab the CityPanel, and instantiate it when required, using a DialogController script. It is important that I set the parent to Canvas. Here's an example of a different dialog being displayed. Note that holdChooseSelector is the prefab, and canvas is set to the canvas in the Start function for thid DialogController script. If I want to create such a dialog, I simply pass the parameters the dialog needs, and I can easily set up everything required.

    public HoldChooserDialog holdChooserSelector;
    private Canvas canvas;
    public void ShowHoldChooserDialog(Good good, Ship ship, Good.Action action) {
        HoldChooserDialog dialog = Instantiate<HoldChooserDialog>(holdChooserSelector);
        dialog.transform.SetParent(canvas.transform, false);
        dialog.ShowDialog(good,ship, action,holdItemSelector);
    }

I hope this has helped to make dialog creation a bit simpler. If you are interested to see the progress of my game, currently called Project Ahoy (Until I come up with a better name...), feel free to join my Google Group.

Wednesday, January 20, 2016

Minimum Viable Product

In starting my first from scratch game, I've been thinking a lot about overall game design, and doing research. Among them, one idea in particular stuck with me, and that is the concept of a "Minimum Viable Product", or MVP.

A MVP is the minimum that a game needs to be to in order to be playable. It doesn't require any graphics to speak of, most items of the game, etc. All it really requires is the essence of the game. Think of a game that you know well. What would be the minimum required to play it? Let's take a few well known games, and see what we can do to break them down.
Super Mario is a game that most of us are familiar with. With the recent advent of Super Mario Maker, designing Mario levels is easier than ever before. But what at it's fundamental root is Mario? The coins don't really matter, nor does the pipes, swimming, enemies, or even blocks. Fundamentally, it is a guy moving down a pathway to a goal, the end of the level. A MVP for this game would simply be a block for Mario, simple blocks showing the floor, with the ability to jump and move around. Not a particularly interesting game, but it would be a start.
Tetris is a classic game, having been around for over 30 years. The game itself is already pretty minimal, but let's see how we could simplify it even further. To start with, you could simply have one type of block that can move left or right. Don't include the down motion. Don't worry about distinguishing the blocks. Just keep it very simple. Don't show the score, level, etc. Once that is done, then slowly add features until you get to a more complete product.
This is my version of a MVP for my game. I learned that almost every major game has some kind of a working prototype in a few weeks. I challenged myself to do the same. My game is fundamentally a sea trading game. Instead of an actual ship, I used a sphere. Instead of fancy water tiles, I used a blue material, for land I used brown. I have 4 cities that are squares. The game is built in 3d, using 3d graphics, but is fundamentally 2d in nature. There is a very minimal UI, just enough to actually play the game. Feel free to take a look at this state at Gamebucket.io. Even as it is, I probably added a few things that aren't strictly minimal, namely a wind system, and an optimal path-finding algorithm (A*). What is the future of this? I'm not sure yet.

Having this minimal product will allow me to test out several ideas that are floating in my head before I have a much larger game to contend with. The biggest changes should always be made when the cost to effect them is the least. At this point in time, I've invested about 2 weeks, or about 25 hours of time, and making small changes is quite easy. I can then test out the ideas, see what seems to work best, and keep moving to the best solution for my game. If you want to stay abreast of how the game is coming, feel free to join my Google Group.

The bottom line is, starting with the minimal game, and slowly adding graphics, mechanics, UI, and rules, is the best way to design a game. It allows for maximal flexibility, and is very motivating to have something running quickly. Even major production companies use this approach!

Tuesday, January 12, 2016

Working towards my first Unity game

At the conclusion of the Bowlmaster Section in the Complete Unity Developer Class provided by Udemy, we were challenged to take the basic bowling game, and make it something of a polished product. I decided to take on that challenge, to the point that I submitted the game to the Google Play store. Here's a few of the things that I did to make it a unique, publishable game.


The first thing to note is that the bowling pins don't really look like pins at all! In fact, they look somewhat like upside down. I created these in the Blender course, and used them here.

Next, note that when the the ball moves, there are a couple of items of note. The first is that there is a flame trailing the movement of the bowling ball. In fact, this comes by a "Trail Renderer". This renderer is a bit difficult with a rotating object, so I had to create a separate object that follows the ball in a similar manner to the Ball Camera. In fact, the code is quite similar, I only specify an offset and the object to follow. I'll leave that up as an exercise for the user.

The second item of note on the second chart is the red line that appears. It's a bit difficult to tell from a still photo, but this line follows the touch of a user. This was actually quite a difficult thing to achieve, there are a couple of important things. The first is to have a function that tracks the drag mid-drag. It is set up in the Drag Launcher, and is very similar to the Start and End drag functions. The second key is to set the floor up in a unique layer, and ray trace that layer. The following code assumes that the floor is the only object on the default layer, the 0x1 could be changed to the appropriate max if that is not the case. I put the pins, swiper, and ball in the "Ignore Raycast" layer. Note that this code relies on having the camera, which I passed into the class as is commonly done. "lastLoc" is the last valid position.

    private Vector3 GetWorldMouseLocation()
    {
        Ray ray = theCamera.ScreenPointToRay(Input.mousePosition);
        Vector3 loc=new Vector3();
        foreach (RaycastHit vHit in Physics.RaycastAll(ray, 30, 0x1))
        {
            loc = vHit.point;
            loc.y = 0.1f;
            lastLoc = loc;
        }
        return loc;
    }

Beyond that, it's a matter of moving an object with a Trail Renderer component, similar to above.

There are several other features used, such as sound effects, rocket launch effects,  explosions, and star skybox, all which add an element of additional fun to the game. I will point those interested in free custom sound effects to an awesome random free sound effect generator, sfxr. To see the final product, please download Missile Bowl from Google Play.

Tuesday, April 22, 2014

A Trusted QSL library for Java

As long time blog readers are no doubt familiar, I do quite a bit of tinkering with Android. Ham Finder is written in Android. I have wanted for some time to have a way of uploading QSLs to Logbook of the World from Ham Finder, mostly because it makes mobile logging for LOTW go from extremely difficult to a snap.

For your information, here's what I've had to do to make this work in the past:

1. Divide up my QSOs by location where they were made.
2. Sign each of these with a custom created Station identification with Trusted QSL.
3. Upload each of them.

This was a royal pain, and I want to make all of this seamless, using Ham Finder. I think I've almost got all of the pieces figured out, and so here I present them:

  1. The key piece to make this all work is a java library that runs Trusted QSL. I'm making this open sources, the code I have so far is available at GitHub.
  2. Right now Ham Finder doesn't provide ITU zones, nor CQ Zones. I'm working on adding those features. It will be most difficult for those countries (Outside of the US) which have multiple CQ/ITU zones, but I'll get something to work most of the time for now.
  3. Upload them to LOTW as needed, including corrections. This should be easy enough to manage, as all of the contacts are stored in a database already. It just involves making sure they are only sent once.
Trusted QSL is an open source bit of software written in C++. I wanted a natively coded bit of software, for a number of reasons, mostly because it's easier to maintain. I don't care about a lot of the functionality provided by Trusted QSL either, I just want to sign and upload them.

Through reading documentation, reverse engineering the TQ8 files, and even emailing the Trusted Qsl staff, I've learned a number of things. First of all, TQ8 files are GZipped files of the Global Amateur Interchange (GAbbI) file format. The latest specifications on LOTW can be found at Rick Murphy's website. In fact, there are a few key differences from the web site specification and what is actually used. The key differences are as follows:

  1. All of the data for signing is upper case.
  2. The order of fields for the signed data is: CA_PROVINCE, CQZ, GRIDSQUARE, IOTA, ITUZ, US_COUNTY, US_STATE, BAND, BAND_RX, CALL, FREQ, FREQ_RX, MODE, PROP_MODE, QSO_DATE, QSO_TIME, SAT_NAME. Note that station comes first, then QSO data. 
  3. There are several undocumented fields, including CA_PROVINCE, US_STATE, SIGNDATA, and SIGN_LOTW_V1.0. SIGNDATA is the data signed for the LOTW signature, SIGN_LOTW_V1.0 is the LOTW signature itself. CA__PROVINCE and US_STATE are the Canadian Province and US state.
  4. SIGN_LOTW_V1.0 has a :6 after the number of digits. I can't actually figure out what this means...
  5. The max space per row is actually 64, not 72 as specified.
  6. The character count includes line breaks, and if there is any line breaks, it also counts the last line break. For a single line, it doesn't count the final line break.
  7. The signature format is SHA1withRSA.
As of right now, I have the library published, have had Logbook of the World accept it, and am working on integrating the library into Ham Finder. Hopefully it will work great!

Sunday, March 2, 2014

How to Manage with no Power.

Does your family have a plan in case of a power outage? Power outages can be cause by a variety of things, including storms, mistakes, and even birds. They can last for minutes, or even days. Does your family know what to do if the power goes out? Here's a few questions to consider.

1. Do you have a plan for cooking food? A propane grill, nice for summer grilling, can be used to cook a variety of foods. If you don't believe me, ask the scouts! Make sure you can cook in a way that doesn't require electricity. Even better if it is portable.
2. Do you have a way to stay warm without electricity? A few extra blankets are great. Many homes in our area have gas fireplaces which can be used without electricity in our homes.
3. Do you have water? For those of you on city water, you should be a be to use city water. If you have a well, you might need a different solution.
4. Do you have adequate lighting? Make sure you have flashlights and spare batteries. Check this periodically.

Test out you plan periodically. Pick an evening, and test out your plan, see if it works. Make sure everyone knows what to do in the event of a power outage.

Saturday, February 22, 2014

Version 1.6 of Ham Finder

It's been a while since I've done an update on Ham Finder here, let me give you some basic. First of all, the app is doing great, thanks to all of you who have already downloaded it! There have been over 1000 downloads, which makes this competing for my most popular app of all time, and already I can tell you there's more actual users of Ham Finder than any other app I've developed. You guys rock!

Some features that have been released, in versions 1.3 to 1.5, include some call sign help, frequency monitoring, improved logbook, tablet versions, and in general I'm working towards ADIF exporting.

Version 1.6 will include the following:

1. Users can now specify their location, useful for those devices without a GPS.
2. Working on putting things on the map to indicate where you have been.
3. Improvements in how frequency is managed.

The next big version, I am excited to announce, will contain ADIF support! I should be able to export the log to ADIF format, and I'll work on other fun stuff as well!

Bottom line, the app's coming great, and I owe it all to my awesome audience! Thanks, and keep letting me know what you want!