Post

Age Of Empires

Working on creating a simple AOE clone!

Play on itch IO here: AOE or below!

Age Of Empires


The prompt for this idea was all the adds on TikTok of small games with lots of moving pieces on the screen. They are all money sinks where to make any real progress you just need to keep swiping ur card. So I thought I’d just make my own.

The current idea is to have some villagers who can collect resources, hardest part currently is getting a view/perspective that would allow fine control while showing everything on the screen.

Currently, I have two collectable resources that Upgrade the Humans. Wood allows for the Humans to move fast, logic? None. Ore allows them to Interact faster. Recently implemented a simple particle system when they Interact so I can actually tell things are happening. I am going to use some place holder object’s but this could also be an opportunity to learn some more simple Blender so I can quickly whip together temp objects when I need to.

UI is a still a work in progress:
AOE UI

Things I am practicing:

  1. Inheritance: I have the base Resources class which all interactable resources will inherit from. This is useful as I can put all the boilerplate code in the base class which all children will require. I have used this a few times, but never anything in depth.
  2. Object Orientated programming: I can confirm I am not doing this well. There is a bit of spaghetti code going on, but things are slightly modular. I am trying to look forward when implementing solutions. The best examples of this is the ResourceUI
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    public void IncrementResource(Dictionary<ResourceType, float> returnResources)
    {
     // Pass over returned resources
     for (int i = 0; i < (int)ResourceType.MAX; i++)
     {
         mTotalResources[(ResourceType)i] += returnResources[(ResourceType)i];
    
    
         // Get rid of this once I have all the UI set up
         // Bandaid to stop out of bounds error
         if (i < mResourceCountUI.Count)
         {
             mResourceCountUI[i].text = mTotalResources[(ResourceType)i].ToString();
         }
     }
    
     CheckUpgradeAvailability();
    }
    

    Here I am using two lists, mTotalResources and mResourceCountUI. As long as I add the UI in the correct order, then I will be able to add un infinite amount of resources and UI without having to touch this code. I am quite happy with it.

  3. Naming Conventions and Getters and Setters: I am using the m prefix for my member variables. I normally do not use this as I find it annoying when used in conjunction with Intlisense. As I will be thinking of ore so I type ore but of course I do not have ore I have mOre. However, it has been useful I have found in functions where I cannot come up with better names that what the member variable is called. But that is now fine as I can just use mOre = ore! In terms of Getters and Setters an example is
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    private Resource mTarget = null;
    public Resource Target
    {
     set
     {
         if (value != null)
         {
             mTarget = value;
    
             mAgent.SetDestination(mTarget.transform.position);
    
             mArrived = false;
         }
     }
    
     get { return mTarget; }
    }
    

    Here I can do error checking on the passed in value if (value != null) then followed by some code. This is very cool, I have never used this before and it has so far been super helpful.

Issues

I found an issue! Can you figure it out?

1
2
3
4
5
6
7
8
9
10
11
12
13
// Check again all the current existing resource positions
for (int y = 0; y < mResourcePositions.Count; y++)
{
    float dist = Vector3.Distance(newPos, mResourcePositions[y]);
    // While the distance is less than desired
    while (dist < mSpawnDistance)
    {
        // Keep looking for a new position till one is found
        newPos = new Vector3(UnityEngine.Random.Range(-x, x), yHeight, UnityEngine.Random.Range(-z, z));
        dist = Vector3.Distance(newPos, mResourcePositions[y]);
    }
}
mResourcePositions.Add(newPos);

The issue with the original function was, when a resource found it was too close to another. It would simply just be moved on top of another. Found a solution Physics.OverlapSphere(). Simple right? WRONG. So many issue, with my new Trees and Rocks being complex shapes that might have broken the check? The instantiate function not actually placing the objects? Unity not actually being able to keep up with placing the objects and checking if they are overlapping? No clue. But I did find a solution in the end.

  1. I instantiate all the Resources at Vector3(100,100,100).
  2. Using an Enumerator to implement a delay between resource placement.
  3. This seems to work?

This is the new function:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
private Vector3 GetFreePosition(Bounds spawnBounds, float yHeight)
{
    float x = spawnBounds.extents.x;
    float z = spawnBounds.extents.z;
    // To stop resources spawning on top of each other
    //  First we give it a position
    Vector3 newPos = new Vector3(UnityEngine.Random.Range(-x, x), yHeight, UnityEngine.Random.Range(-z, z));

    // Trying a new method for spawning objects.
    // Rather than going through a list of position, I will shpere cast at the spawn location a check if there is anything other than the ground there.
    var checkResult = Physics.OverlapSphere(newPos, mSpawnDistance);

    // Recursion keep checking till we find a free stop.
    // Hopefully this will help with the debugging.
    if (checkResult.Length > 1)
    {
        newPos = GetFreePosition(spawnBounds, yHeight);
    }

    Debug.Log(checkResult.Length.ToString());
    // Assign the free position
    return newPos;
}

IEnumerator PlaceObjects()
{
    //Print the time of when the function is first called.
    Debug.Log("Started Coroutine at timestamp : " + Time.time);

    //yield on a new YieldInstruction that waits for 5 seconds.

    for (int i = 0; i < mObjects.Count; i++)
    {
        MeshCollider groundMesh = mGround.GetComponent<MeshCollider>();
        Bounds bounds = groundMesh.bounds;
        mObjects[i].transform.position = GetFreePosition(bounds, 0.0f);
        yield return new WaitForSeconds(0.125f);
    }
    //After we have waited 5 seconds print the time again.
    Debug.Log("Finished Coroutine at timestamp : " + Time.time);
}

Fun Stuff

The fun stuff that I did do today was create a Tree and Rock in Blender! It is a good first attempt, I can put a lot more detail into the trees and add some actual ore lumps in the rocks but they are good for now!
Tree rock

GitHub Actions

I set up a GitHub actions like I did for Balls. Which means that the game is being updated on the build branch and posted to Itch.

Github

CommitsMessage
1Initial commit
2Adding Unity proj
3Beginning work.
Added:
1. Game Manager
2. Tree
3. Prefabs for each
Need to work on:
Everything else
4TREES!
Currently I am spawning 100 tree which are placed randomly on the ground. A single brave human is being spawned with them, he can currently walk up to any of the trees and merge with them (Not intended behavior).
Things to do:
Some how update the nav mesh when the trees are added to agent’s avoid them.
Spawn more humans
Better trees
Better humans.
PROGRESS
5Good work!
The human can now interact with a tree and cut it down! When it has been cut down, it will disappear and the human will return to the house. Have some UI now which will let you know when you have correctly selected a human, need to add trees and other objects. There is HitPoints UI but it is very basic.
Very very spaghetti code right now, which is not great. But it currently works.
Things to do:
Improve UI
Look into refactoring early
Animations
Improve current assets
6Improvments,
I made some improvements to the UI. But, it is still very spaghetti and it has very little room for expansion. Will still need to look into inheritance again.
But making progress!
7The great refactoring has begun!
It is always easier to reactor as you go rather than doing it at the end. If any of my previous projects are to go by. Anyway, created inheritance for resource objects as it will improve expandability and I need to work on it. Removed a lot of the functionality for now but it will still be easer starting again. Lots to come!
8More work on Resources
Back to being able to chop down trees and return them to the TownCentre. Started setting up the UI for resource count, however the hitpoints are still not working as expected. Good work though.
9THE SPAGHETTI
So, I am not sure if things are getting better or worse lol.
Changed the Resource class to an Abstract class which I have never used before. I believe the benefit is that I can have empty functions?
I will continue to work on making things more modular which would be nice, but making good progress.
Implemented some nicer UI for when resources have been retrieved. Next it to use the retrieved resources to improve the Town Centre/Humans.
Looking good so far.
10RAYS
I have improved the way Humans return Home as I noticed they kept returning to the same point and it looked funny. Kinda like they were trying to que. Now they will raycast from their current position to the house so that they all get a different point to return to, makes it feel a lot better.
11SPACING
Implemented a spacing system for random tree spawning to prevent them from occupying the same space. Will need to to some clean up soon. Added some code comments.
12Code clean up and Uniqueness
Lots of clean up, using the private/public names of vars to reduce the number of functions and make things a bit easier to read.
Added a bit more uniqueness to the humans created. Their materials and icons will not have a different color assigned at creation to it is a bit easier to see which Human you have selected at any time.
I want to now work on the first improvement: movement speed! You will need 50 wood to increase the human move speed.
13SPEED
Implemented the first upgrade, SPEED. When the humans return 50 wood, it is possible to increase their speed. There is absolutely 0 juice. Maybe I could use some sort of sprite on each of the Humans when the upgrade is applied.
Things to investigate:
- Why when you increase the movement speed of the NavMeshAgents do they start to overshoot their destinations!??! Such fun.
14Movement improvements.
So the NavMesh Agent is dumb. So I spent some time fixing that. Spawning the humans before the trees so they are higher in the Unity hierarchy and easier to find for debugging.
15ORE!
Added a new collectable Ore! I think this will improve Interaction time, reducing the time it takes to collect resources. Also improved the villager icon, but it looks a bit funky with the colour matching. Implemented a mResourcePositions for spawning checking rather than going through each resource list to make sure everything is spawning correctly. Did some more code clean up and added some more functions for boiler plate code. Happy with the progress!
16MORE UPGRADES!
The interaction speed can be improved after gathering ore! Improved the upgrade function, cleaned up some redundant functions and improved checking if upgrades are even available.
17Improving Nav Agent Values
18Pain!
Cools things first!
Created Trees and Rocks in Blender to replace the terrible Unity objects I was using before, which has greatly improved the look of the game already.
The not so cool stuff.
So, I found an issue with the Resource placement. The issue with the original function was, when a resource found it was too close to another. It would simply just be moved on top of another. Found a solution Physics.OverlapShere(). Simple right? WRONG. So many issue, with my new Trees and Rocks being complex shapes that might have broken the check? The instantiate function not actually placing the objects? Unity not actually being able to keep up with placing the objects and checking if they are overlapping? No clue.
But I did find a solution in the end.
1. I instantiate all the Resources at Vector3(100,100,100)
2. Using an Enumerator to implement a delay between resource placement.
3. This seems to work?
This was very annoying but I got it working in the end!
Good stuff!
19Create activation.yml
20Create main.yml
21Testing WebGL build and set up Build action
22Correcting branch name
23Correcting project path
24Testing Itchio Upload
25Correcting caching path
26Trying to find correct build location
27Trying to fix caching
28Testing cache and build locaiton
29Trying a different restore key
30Trying a new path
31Trying new build path
32Download the artifacts duh
33Uploading to the correct itch page
34Improvements
Improved camera placement, humans spawning and some code clean up.
35State of the game
I am happy wit the current state of the game.
You are now able to spawn humans when you have 150 of each resource. Might leave it here for a while.
36Fixing UI issue
37Updating actions as suggested
38Chat improvements and camera movement on PC
39Trying to implement some Unit testing
40Beautifying the game
This post is licensed under CC BY 4.0 by the author.