Making a Game in 2 Weeks: Day 5

Day 5 of my Game in Two Weeks is the a simple front-end scene, configuring the game with the front end, and transitioning into the game while keeping the game settings intact.

Day 5. Front End Choices

In yesterday’s post I discussed the difference between permanent code and scaffolding. When it comes to the simple front-end, at this point I don’t have any of the assets to fill it out. I need to add character selection and course selection and number of opponents and number of laps and type of race, and much more. But none of those things exist yet.

In Unity when you switch scenes, by default everything gets destroyed and the new scene replaces it. This means that by default, no matter what options they set the player’s choices will be lost. This is something that needs to be modified, and shouldn’t be scaffolding.

But I do have choices about how to display it. I want to display previews of the actual final models, previews of the actual courses, and previews of the other settings, but I am not far enough along to provide those. So while I can provide a backdrop on the scene, the UI elements can (and probably should) be scaffolding for now, until I hit first playable.

So first, what data do I need for my race? For one thing, my first playable is going to include a regular circuit mode, a time trial mode, and a sprint mode. So that option goes in. I need to have the number of players. So I create my RaceSettings class and add the public data.

    public enum RaceType : int
    {
        Circuit,
        TimeTrial,
        Sprint        
    }
    public RaceType mRaceType = RaceType.Circuit;
    public int mNumPlayers = 1;

Next I need to figure out exactly how I am going to keep my data available. I have a few options available, and each one has their own pros and cons. The easiest choice is to create a shared static instance of the class. Note that this is not quite the same thing as a singleton. The singleton pattern enforces that only one instance of the class can exist. I don’t want that; I want the ability to replace the class and potentially have multiple instances. The biggest downsides of shared instances is that other locations can modify the instance underneath you, that it introduces hidden dependencies, and that it can be difficult to track down issues. In this case the game design only ever calls for a single instance but I don’t want to enforce it as a policy. For now I’ll keep my race settings as a shared instance.

I create my basic scene with a big cube in the middle. Later I will want actual player characters and stuff, but for now a big cube is enough. Also since I am just using scaffolding for the GUI, I can use the OnGUI  functionality to handle it.

    void OnGUI()
    {
		GUILayout.BeginArea (new Rect (mBorder,mBorder, Screen.width - mBorder*2,Screen.height - mBorder*2));

        // Begin the singular Horizontal Group
		GUILayout.BeginVertical();

        if(mRaceSettings == null)
        {
            GUILayout.Label(“Race Settings are null!”);
        }
        else
        {
            GUILayout.Label(“Type of race:”);
            string[] raceNames = Enum.GetNames(typeof(RaceSettings.RaceType));
            mRaceSettings.mRaceType = (RaceSettings.RaceType)GUILayout.SelectionGrid((int)mRaceSettings.mRaceType, raceNames, raceNames.Length);


            GUILayout.Label(“Number of racers: “+mRaceSettings.mNumPlayers);
            mRaceSettings.mNumPlayers = Mathf.RoundToInt(GUILayout.HorizontalSlider((int)mRaceSettings.mNumPlayers, 1, 6));

            GUILayout.FlexibleSpace();
            if(GUILayout.Button(“START”))
            {
                StartGame();
            }
        }
        GUILayout.EndVertical();
		GUILayout.EndArea();
    }

    void StartGame()
    {
        DontDestroyOnLoad(mRaceSettings);
        mRaceSettings.TransitionToRaceWorld();
    }

And to finish it off, the race settings have a transition to the race world

    public void TransitionToRaceWorld()
    {
        Application.LoadLevel(“LakeValley”);
    }

I added the scenes to the build settings (otherwise LoadLevel won’t work) and try it out in game. Everything works, and after the transition my scripts can still access the race settings.

Day 5. Starting Projectiles

None of the other tasks fit in the remaining time today, so the next thing on my to do list is missiles and self-guided missiles. Because they are fairies, we call them spells.

There will be many different types of missiles so I start with the base class.

I know that each missile (both straight fire and homing) will have a velocity and a maximum distance they can travel. They will also have the option to detonate at the end of the line, and to detonate when they collide. They also travel strait forward by default, but since the function is virtual I will have the opportunity to override them later as needed. The collision and detonation functions are also virtual, since I know I will need to override them as new spell missiles are created.

    public float Velocity = 10;
    public float MaxDistanceBeforeSelfDestruct = 30f;
    public bool ShouldDetonateOnMaxDistance = false;
    public virtual void Update()
    {
        if (mController != null)
        {
            mController.Move(transform.forward * Velocity * Time.deltaTime);
        }
        mTotalDistance += Velocity * Time.deltaTime;

        if (mTotalDistance >= MaxDistanceBeforeSelfDestruct)
        {
            if (ShouldDetonateOnMaxDistance)
                Detonate();
            else
                Destroy(gameObject);
        }
    }

    public virtual void OnControllerColliderHit()
    {
        Detonate();
    }

    public virtual void Detonate()
    {
        Destroy(gameObject);
    }

I assigned the script to a prefab, adjusted the controller to create a missile when the right joystick was tapped, and everything worked just fine.

shootingice

With that done, I can make a subclass for homing missiles. Then I can make subclasses of either the regular missile or homing missile for any new objects I will need in the near future.

    public override void Update()
    {
        // Homing missiles attempt to turn toward the target
        if (Target != null)
        {
            Vector3 direction = Target.transform.position - transform.position;
            direction.Normalize();
            Quaternion directionToTarget = new Quaternion(direction.x, direction.y, direction.z, 0f);
            transform.rotation = Quaternion.RotateTowards(transform.rotation, directionToTarget, TurnAngleDegreesPerSecond * Time.deltaTime);
        }

        base.Update();
    }

It is a bit of a trick to find the target for the missile, but if a target exists it will lock on, turn and twist, and attempt to hit the target.

And that’s it for today. Tomorrow is modeling, so I’m not sure how much I can write.

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.

This site uses Akismet to reduce spam. Learn how your comment data is processed.