top of page
Search
  • Writer's pictureEthan Toney

Simple Prototype RTS (Part 1)

Updated: Dec 17, 2021

I've always been interested in the rts genre. Games like Age of Empires and Age of Mythology are embedded as childhood memories. So, I decided that for a game jam I would aim to create a simple rts prototype. I gave myself three days to work on it. It took me three days for the initial code with a fourth and fifth day of fixing bugs and pulling features that didn't work as expected.


How I made it


First off, I watched this video:



Yes, I started with a tutorial. However, once I figured out building placement, I started on the work myself. (This will not end in tutorial hell, I promise.) Here are some lines of code I started with.


public class Blueprint : MonoBehaviour
{
    RaycastHit hit;
    public GameObject prefab;

    void Update()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        if (Physics.Raycast(ray, out hit, 300.0f))
        {
            transform.position = hit.point;

        }
        if (Input.GetMouseButton(0))
        {

            if (hit.transform.gameObject.layer == 7)
            {
                Instantiate(prefab, transform.position, transform.rotation);
                Destroy(gameObject);
            }

        }
    }

}

Basic rundown of the script is:

  1. Send a raycast from the main camera to mouse position

  2. The blueprint object's position is where the hit position (the mouse position)

  3. If clicked on, checked to make sure the clicked on layer is empty (layer 7 was the ground on my Unity project)

  4. Spawn the object and destroy blueprint object.

Of course, at this point, I'm only spawning solid buildings. I want to spawn ghost buildings first. To fix that, I added a second script:


public class Build_Objects : MonoBehaviour
{
    public GameObject barracks_obj;
    public GameObject house_obj;
    public GameObject button_barracks;

    [SerializeField] private ResourceInv resourceInv;

    public void SpawnBarracks()
    {
        if (resourceInv.wood >= 10 && resourceInv.stone >= 20)
        {
            Instantiate(barracks_obj);
            resourceInv.wood -= 10;
            resourceInv.stone -= 20;
            Destroy(button_barracks);
        }
    }

    public void SpawnHouse()
    {
        if (resourceInv.wood >= 6 && resourceInv.stone >= 4)
        {
            Instantiate(house_obj);
            resourceInv.wood -= 6;
            resourceInv.stone -= 4;
            resourceInv.maxUnit += 3;
        }

    }

}

Typically, I aim to use "[SerializeField} private" over "public", but since I was trying to go as fast as possible, I used public more often than I'd care to admit. This script should be pretty easy to read:

  1. Get models and resources

  2. Depending on which button you clicked, spawn a ghost building

These two scripts together work to create the building placement mechanic. Now, I can spawn ghost building blueprints. Once I click, the ghost building will destroy itself and leave a solid building behind.


You may have noticed that Build_Objects references the ResourceInv script.


public class ResourceInv : MonoBehaviour
{

    public int wood = 10;
    public int food = 20;
    public int stone = 10;
    public int maxUnit = 3;
    public int amountUnit = 0;
  
}

Yep! These little lines of code are our inventory. While it may not seem like much, This script will determine whether units and buildings can be created. Note, I could've used C# properties aka getters and setters. While that would've worked, it would've added a little more time required, which is why I used the global "public" instead.


I did come across an issue from Unity Learn that I think is worth mentioning.


 public float timer = 5; //easy to change for testing

    void Update()
    {
        if (isAtPOS == true)
        {
           StartCoroutine(Production());
        }
    }
    
    IEnumerator Production()
    {
        timer -= Time.deltaTime;
        if (timer <= 0)
        {
            if (tagType == "Wood")
            {
                inv.wood += resourceObj.wood;
            }
            if (tagType == "Stone")
            {
                inv.stone += resourceObj.stone;
            }
            if (tagType == "Food")
            {
                inv.food += resourceObj.food;
            }
            timer = 5;
        }       

        yield return new WaitForSeconds(2);
    }

Most people throw coroutines into Start(). I tried that and the coroutine would only run once, even with a timer. Someone on the Unity forums mentioned having a null variable might be the issue. While I cannot say for sure that a null variable caused the issue, by placing the coroutine into the Update() method, the code works as expected. (Others claimed that the instance would delete itself causing that issue, the code here is on workers, who certainly existed.)


If you liked this brief article, let me know! I may continue posting more code and breaking it down.



6 views0 comments

Recent Posts

See All

Back To Web Development

I've been building games and prototypes for the past few years now. I've gotten pretty good with C#. I had originally started in web...

The Gaming Industry Worsens

As we see more layoffs, the sacking of union workers, and more within the industry, now is the time to be reminded: corporate capitalism...

New Year News

I've started two projects this year that I plan on sticking with (alongside various smaller side projects I may or may not complete)....

Commenti


bottom of page