Posts Tagged ‘Strat Souls’

How I Structured My Code in Strat Souls #7dRTS

Posted by (twitter: @AnomalusUndrdog)
Tuesday, July 30th, 2013 10:38 am

So how do you manage something as complex as a real-time strategy game? Especially if you’re a single programmer doing the whole thing? I did mine with standard software engineering principles.

The idea is to segregate your classes from low-level details to high-level concepts.

I’d usually explain this by terminologies like modularity, encapsulation, abstraction, loose coupling, etc. but I’ll explain by example.

Here are the set of classes just for a unit. You’ll see there are quite a lot of them.

 

 

Lowest Level

These classes deal directly with the Unity system (the game engine that I use). One class does one thing only.

Generally, no other classes should directly call Unity’s innards except these (but there are exceptions).

UnitMovement class: Deals with moving and rotating the unit. The only class that directly controls the unit’s rigidbody. Also handles collisions and obstacle avoidance.
UnitAnimation class: The only class that controls Mecanim (via the Animator class). Mecanim is Unity’s animation system.
UnitNetwork class: The only class that deals with NetworkView and Network. Sends and receives network data for the unit. For the unit, this is the only class that has RPC’s and state syncs.
Health class: Manages this unit’s health, very basic piece of code.
etc.

The idea is that these classes are the bridge between Unity’s systems and my code. That means my code more or less doesn’t directly access Unity classes (except the aforementioned ones).

 

 

Basic Problem-Domain Level

Note: the names of these levels are just something I made up

On top of the Lowest Level is the Basic Problem-Domain Level. It makes use of the classes of the Lowest Level (specifically, via the public functions they provide) to create higher-level convenience functions. All levels above this continue to deal in terms of the problem domain.

Ok, but what the hell does problem-domain mean? It means since my game is an RTS, my functions are now structured in terms of TurnToTargetUnit(), instead of RotateToVector().

I now think in terms of an RTS game, not as a basic 3d system. That’s because my problem-domain is real-time strategy. So my code deals in terms of real-time strategy concepts. It provide functions where the caller doesn’t need to know the underlying 3d world and physics system, or at least, lessen the need to know that.

This level contains only one class, the Unit, which acts as the façade class to the various Lowest Level classes. There is no inheritance here. Unit simply has variables to the existing UnitMovement, UnitAnimation, UnitNetwork, etc.

 

The Unit class has public functions such as:

MoveToPosition or MoveToUnit: uses UnitMovement to actually move, and UnitAnimation to play the move animation for you

DoMeleeAttack: plays melee attack animation (via UnitAnimation), and turns on melee collisions. It also ensures this action is replicated across the network when in a multiplayer game (via UnitNetwork)

IsNearPosition or IsNearUnit: uses UnitMovement to check if this unit is near enough a position or another unit

IsFacingUnit: uses UnitMovement to check if this unit is facing another unit

IsNearAndFacingUnit: convenience function that combines the two

IsDead/IsAlive: uses Health class to check if unit is alive or dead

GetAllEnemiesNearMe: returns an array of enemy units that are within specified radius, sorted by proximity

etc.

 

As you can see, Unit merely defers the actual work to the Lowest Level classes. Unit is like the conductor in an orchestra, he doesn’t really play any instruments, but he coordinates the ones who do. He tells them what to do, and at what time.

 

 

 

Medium Level

Adds basic behaviour on top of the Basic Problem-Domain Level.

The Medium Level now directly corresponds to what actions a unit does when you right-click on something. Since I want different unit types to do different things, I separated this per class.

So I have different types of Actions that the unit can do. I created an abstract base class Action, and the Unit class has two variables of these, one it uses when you right-click the ground, and one it uses when you right-click an enemy.

 

Then I have different subclasses of Action:

ActionMove

Will simply move to the requested destination (using Unit.MoveToPosition).

Take note that the Unit class handles both the physics of moving, and playing the move animation for us with that single function call.

 

ActionMelee

Will move near enough the targeted enemy (calls Unit.MoveToUnit), and once it reaches it (continually checking the return value of Unit.IsNearAndFacingUnit), will keep attacking it (calls Unit.DoMeleeAttack) until the target dies (checks return value of Unit.IsDead)

Again, take note that calling all those functions ensure that the animations are played properly for us, and that movement and attacks are synced across the network without us needing to worry about it, because the Lowest Level handles that for us. At this level, we only care about designing the behaviour of our unit, not low-level details like setting the speed, or blending between two animations.

 

There would be other things, like ActionRangedAttack, or ActionDashAttack (the one that Bone Wheel uses in my game), perhaps an ActionBuffAlly, etc.

 

So now I provide higher-level behaviours by combining the use of public functions that the Unit class provides. The code in my Action classes is like a MacGyver that combines different low-level tools to finally do useful stuff.

Also, I can assign different Actions to units. This means I can turn a melee unit into a ranged unit by swapping what Action it uses.

(How those Action classes can get what the requested destination or target is, is handled by my Order singleton class. It simply gets the 3d x,y,z position of where the mouse cursor is, or the actual Unit that is under the mouse, if there is any. It communicates with my UnitSelector singleton to tell all currently selected units that a command was issued (when a right-click is detected). But what each unit exactly does when such command is issued, is determined by which Action subclass it uses.)

 

 

Highest Level

Adds behaviours that players normally expect. I actually did not have time to implement this for the #7dRTS. Here are some ideas:

 

Aggressive stance

Go to the nearest enemy it can find, attack until it dies. Then go to the next nearest enemy again, and kill it. Repeat the whole process, until it can’t find any more enemies.

Sounds complicated to code, but really, all it does is keep on using ActionMelee on every enemy it sees, until it can’t find any more enemies in its vicinity.

 

Hold Position stance

Retaliate against any enemy that engages it, but do not pursue if the enemy retreats or goes out of range of my attacks. I would have to create a Unit.OnBeingAttacked(Unit attacker) for this.

 

Cautious stance

(for ranged units only) Maintain farthest distance possible from any enemy and attack it from afar. This means it will move backwards if it is too close the target, or move forward if it gets too far.

 

 

Caveats

Maybe I should have combined my Medium Level and the planned Highest Level into one, actually. I also probably should have coded it so that I can use my behaviour tree plugin to implement such high-level behaviours, but of course, I only had 7 days for this, and time is running out, so there is also merit to hard-coding the behaviours into those Action classes in the meantime.

There are actually a few more fundamental things lacking here, like ranged attacks, unit formations, special abilities (i.e. spells), and perhaps more depending on what design I want Strat Souls to move towards.

I also have not added structures/buildings in the game yet, and I imagine I may need to change the code once more to accommodate that.

I should also have made a separate UnitAttack class as part of the Lowest Level. It would deal with melee collisions and launching of projectiles. I did not have time to implement proper ranged attacks though, so I left it at that.

 

 

So, that’s it

The idea is each level provides convenience functions to the one above it.

There are two benefits to this:

Minimize the impact of change: Changing code in one level, shields the other levels from needing to be changed too much (sometimes, not at all), minimizing re-writes, human mistakes, and bugs. And with the nature of game development being iterative (you keep on refining the prototype), you will deal with having to change code constantly.

For example, what if you decided you want to switch to CharacterController instead of Rigidbody? You’d know that the only class that needs to be changed is the UnitMovement class; it’s the only one that handles the physics system. So you don’t need to worry if your other classes need to be changed. What if you want to switch to the Photon networking library? You’d only change the UnitNetwork class. And so on.

This makes it easy to swap out different sub-systems for your game. Heck, if you really need to, you can port your code to a 2d game engine and only the low-level classes need to have drastic changes.

Manages complexity: Structures like this allow you to think easier because you usually only need to deal with one level at a time. When you’re coding, say, a patrol behaviour, you don’t need to worry about rigidbody.velocity or OnCollisionEnter or anything like that. You just use the convenience functions that you made in the Unit class.

In case you need to create new convenience functions, then likewise you don’t need to worry (too much) about higher-level behaviours while you deal with changing the low-level ones.

There will be times where you need to zip back-and-forth changing code in all levels, most likely when your system isn’t stable yet (when you’re still iterating on ideas). But once you’re definite with how you want things to work, you’d usually only deal with one level at a time. And that is a huge load off your brain.

 

 

Aren’t these too much classes just for your game’s units?

Why not? Units are the central feature of the game, so it makes sense to devote a big system around it.

 

 

But doesn’t all this make my game slow???

Generally, no. The concept itself shouldn’t impact your game’s framerate, but if you do your particular implementation where, for example, you’re doing an expensive calculation in a tight loop, then obviously you’ll see some slowness.

As with anything, measure your code’s performance first, before you start pointing fingers anywhere. And even then, remember, you structured your code where things are segregated by levels. When you find the bottleneck, you can optimize that problematic part without impacting the other levels of your code too much.

 

 

This all sounds too complicated and will just get in my way!

Oh, you’ll learn to see why this is worth it.

Oh yes.

Just like I did.

Anyone care to share any programmer horror stories?

 

In any case, the code I explained is only one way of achieving a clean structure for your game’s system. It could be that your design for your game is simpler, and you’d arrive with a far more simple implementation.

But whichever particular implementation you make, the underlying concepts should always stay the same: loose-coupling & modularity (the idea that you can easily swap one sub-system for another), abstraction (hiding low-level details by the use of convenience functions), and encapsulation (disallowing your high-level classes from directly messing with the variables of low-level classes).

 

Disclaimer: I actually have no formal education on software engineering, and I’m still learning. I got all that I know from the Internet, discussions with friends, and really good books. I recommend Code Complete.

Strat Souls #7dRTS Postmortem

Posted by (twitter: @AnomalusUndrdog)
Monday, July 29th, 2013 6:39 pm

I’m not going to bombard you with paragraphs so here are quick points for a postmortem:

 

 

SOSO

SO SO: I used old base code from my turn-based strategy game experiments. It was not the best fit. There were some few unused pieces of code that I had to clean up (“I don’t think I’m using this function, I should delete it, it’s distracting me… but is this part really not used? I have to check…”).

 

 

GOOD

GOOD: Clearly define the scope of what you’ll do. That goes without saying, and yet some people don’t get this. When I see others saying “I’m gonna add this and this and this, I think it’s ambitious for the time-alloted, but I think I can pull it off LOL” that’s already a red flag right there. Do you even have a concrete plan to do all that?

I put it out there that I can create either a singleplayer game or a multiplayer game, but not both. At least, not within the 7 days. So I asked in the Ludum Dare website which they want first. Of course I want to add both eventually, but I have to choose what to finish within the 7 days.

 

 

GOOD

GOOD: Create a “testbed” level to quickly prototype ideas. A sort of playground level without victory/defeat conditions so you can test things quickly. I do this all the time. Shigeru Miyamoto does this, so why wouldn’t you? Don’t you love Miyamoto-san?

 

 

GOOD

GOOD: Sound software engineering practices. Abstract low-level details with high-level convenience functions! Reduces clutter, makes it easier for you to think! I’m going to write a separate article about this.

  (more…)

Strat Souls: WIP 13. End of #7dRTS. YOU RECOVERED.

Posted by (twitter: @AnomalusUndrdog)
Monday, July 29th, 2013 5:25 pm

Hi guys,

Well, that was one hell of a ride.

To facilitate my testing better, I divided my web builds into two: Release, and Experimental version.

This is pretty much the same idea with stable, and development versions: the Release version is the latest that has no (showstopper) bugs, while Experimental is the bleeding edge version with new features for testing.

Right now, the Experimental version is the one that has the Bone Wheel unit.

 

Here’s me and my friend doing a playtest:

 

I’d appreciate if you gather some friends and test the Experimental version if it runs ok! Send me messages on my Twitter, or comment in this page.

You can check out my entry here.

Strat Souls: WIP 12

Posted by (twitter: @AnomalusUndrdog)
Monday, July 29th, 2013 3:54 am

OH HO, LOOK WHAT I HAVE OVER HERE

This land is peaceful, its inhabitants kind.

Strat Souls: WIP 11

Posted by (twitter: @AnomalusUndrdog)
Monday, July 29th, 2013 1:20 am
0 days 15 hours 40 minutes 13 seconds left!

 

So I got obstacle avoidance working, with thanks to some pseudocode explanations on boids here.

Units will still get stuck occasionally however, as there’s no escaping the need for pathfinding.

Now I’m wondering if my old code for influence maps will help with this. Although influence maps are used for tactical reasoning, they are very similar to potential fields (which is the one used as an alternative or supplement to traditional pathfinding, i.e. A*), so I think I can use the same code.

I shared my simple test implementation of Influence Maps in Unity. You guys can check out the source code here. Here’s my forum thread on the Unity forums.

 

I think you need a combination of both obstacle avoidance and pathfinding to get good AI movement.

Anyway, I would consider this tolerable for now, so I’ll move on to making a few more units.

Strat Souls: WIP 10, Internal Brainstorming 2

Posted by (twitter: @AnomalusUndrdog)
Sunday, July 28th, 2013 9:02 pm
0 days 19 hours 57 minutes 36 seconds left!

 

Ok, so I got soul consumption working. Meaning, summoning units now require souls. Each unit type has a soul cost and you are (for now) given 1,000 souls at the start.

As we discussed before in Internal Brainstorming 1, people don’t seem to like the traditional RTS type where you have base-building and resource-gathering, so I didn’t do that.

You have a fixed amount of souls at the start (like every other player in the map) and summon units to compose whatever army you want, as long as you can afford it. You also probably shouldn’t be allowed to attack enemies while everyone hasn’t finished summoning their initial army yet. But I haven’t added that in for now.

 

Be wary of rushing.

Be wary of rushing.

I probably can’t add anything that significant now; there’s not enough time (still fixing a few bugs here and there).

But I wanted to add mainly better movement (pathfinding, obstacle avoidance, lockstep marching, whatnot), and a few more units (bonewheel, pyromancer, guitarmancer, etc.).

 

Here’s the thing about the initial design:

“When you defeat an enemy, you gain souls equivalent to 50% of the unit type you killed (i.e. dwindling economy). You can use this to summon reinforcements in the middle of battle or upgrade your existing units.”

We got this idea from the multiplayer in Total War, as described to me by my friend (actually haven’t tried it myself so I don’t know how it works) my friend’s suggestion, he just happened to mention Total War as an aside, so I got confused.

Now, what strikes me as odd is, why would you reward the player who’s winning? If he’s winning already, he doesn’t need more help.

Understandably, I believe this comes from the basic idea that people should be rewarded for their hard efforts.

In the context of the game, it makes sense to reward the winning side if players are in a stalemate and we need tip the scales of battle quickly.

But once someone has the upper hand, you don’t need to bother watching what’ll happen next; the winning guy will just steamroll through everything for sure. Every character he kills means his army will grow bigger and the opponent will have his back to the wall.

So that was where I thought of the size growth idea. Whenever you lose a unit, all your remaining units gain size (someone suggested that only your units that are close enough to the killed one should be affected), until you are left with one unit who’s a giant boss kind of guy.

My proposition was, is it possible to give the losing side a second chance while still keeping it fair for the winning side?

 

Here’s also something I was thinking about: Factions. Something like this:

  1. Undead (Lordran)
  2. Phantoms (Boletaria)
  3. Demons (Capra demon, Taurus demon, etc.)
  4. Dragons (?)
  5. Chaos Witches

Maybe each faction has a particular passive bonus to its units somehow. I’m also thinking of sub-factions, like the Covenants for Undead, or the White/Black Tendency for Phantoms.

 

Web Build WIP

Strat Souls: WIP 9

Posted by (twitter: @AnomalusUndrdog)
Sunday, July 28th, 2013 12:22 am

Here’s us doing a playtest to make sure the bugs are fixed.

And one thing we immediately noticed is the poor movement handling.

I don’t have any pathfinding or obstacle avoidance yet. Also, no formations. Boid movement can be worth a try here.

Also summoning cost isn’t implemented yet so we had too many units (we were goofing off), I was envisioning something like 10-20 units only per player.

To the two guys who joined us, sorry I think you got disconnected. Blame it on my country’s ISP.

 

Web Build WIP

Strat Souls: WIP 8

Posted by (twitter: @AnomalusUndrdog)
Saturday, July 27th, 2013 8:46 pm

Finally got attacking and damaging working over the network. Some bugs I’m still fixing though.

 

I also noticed goffmog said, “There had better be guitars in this.”, so I made this:

Strat Souls: WIP 7 now with blurry video!

Posted by (twitter: @AnomalusUndrdog)
Saturday, July 27th, 2013 1:08 pm

I have some basic network code in, players can summon in units and move them, though things like attacking and playing animations aren’t “network-aware” yet.

I also added in the master server because, well, it’s already there. I’m using Unity’s built-in network library so it was relatively a breeze to put in.

Now here’s a blurry video of testing the multiplayer:

Web Demo WIP

Strat Souls: WIP 6

Posted by (twitter: @AnomalusUndrdog)
Friday, July 26th, 2013 9:33 pm

Today marks the start of the final 48-hours of the #7dRTS in my timezone. No distractions!

Absolutely no getting distracted with minor things such as the house burning down! This is important.

Absolutely no getting distracted with minor things, like the house burning down! This is important.

 

Got a lobby semi-working. You can chat but stuff like server settings or player list isn’t there yet.

Will put this off for now and work on the meat of the network code.

In other news, we had a power outage for the last half of yesterday, so I am extending my #7dRTS to #7.5dRTS.

Strat Souls: WIP 5

Posted by (twitter: @AnomalusUndrdog)
Friday, July 26th, 2013 12:11 am

Got spawning working although it’s offline for now. Working on network code next.

That minimap isn’t working yet.

 

Web Demo WIP

 

Strat Souls: WIP 4

Posted by (twitter: @AnomalusUndrdog)
Wednesday, July 24th, 2013 5:29 pm

After wrestling with Git subtree commands overnight, I’ve integrated my AI system into the game. Not much right now though, just the dummy units following you.

I took this time to add a new unit and re-enable an old one.

The shielder is a tank unit that can’t attack. However, it is the only unit that can push units by just moving through them.

Since the zweihander guy moves so slow, you can actually use shielders to push him and move faster!

The shooter is actually from the old SloweRTS experiment. It will be replaced with the sorcerer: a ranged unit whose projectiles are homing.

I took this time to integrate NGUI into the project as well. The box on the lower right will serve as a context-sensitive quick help. The art assets are a combination of the free Necromancer GUI in the Unity Asset Store, and the Moderna Graphical Interface from OpenGameArt.org.

 

Web Demo WIP

Strat Souls: WIP 3

Posted by (twitter: @AnomalusUndrdog)
Wednesday, July 24th, 2013 6:54 am

Only under the hood stuff changes today.

 

2013-07-24-21_30_43-Greenshot

Over the course of doing this so many times, I think I’ve ended up with a really good façade class for my units.

It pays well to name and design your functions in the problem domain! Thinking in terms of FaceOtherUnit() is easier than RotateToTargetDirection(). Abstract those low level details with your façade!

Preview of my Behaviour Tree Plugin, currently codenamed "INTLord"

Preview of my Behaviour Tree plugin, currently codenamed “INTLord”

I’m doing some quick work to bring my half-baked Behaviour Tree plugin into the game. Should get something up within the day.

 

Man, it feels good to refactor some code.

Oh yeah…

Strat Souls: Internal Brainstorming 1: Play Modes

Posted by (twitter: @AnomalusUndrdog)
Tuesday, July 23rd, 2013 6:01 am

 

So I’m at a point where I’m wondering how the whole game will work. Will it have harvester units? Worker units? Are units upgradeable?

Here are multiple ideas that I’ve come up with:

 

Traditional RTS Type

  1. You have harvester units who gather souls from corpses in the map. (like Tiberium fields in C&C)
  2. You have a nexus which is your base. If it gets destroyed, you lose.
  3. You create units by summoning them into the map, costs souls.
  4. Summoning takes a long time to complete, and the enemy can attack the summoning point to prevent that unit from appearing.
  5. You can only summon near your nexus, near other units, or at summoning fields that you can construct. Summoning fields can be destroyed by the enemy.
  6. When your units kill enemies, they level up automatically (i.e. veterancy in C&C).
  7. You upgrade your nexus to gain access to better units. You can purchase upgrades also in your nexus.

 

Tactics Type

  1. There is no base-building, no resource-gathering.
  2. Instead of an army, you have a party of heroes. Your enemy has likewise.
  3. Tries to capture the Dark Souls vibe, just that instead of controlling one character only, you control maybe 2-5.
  4. Controls are much more micromanage-intensive.
  5. May be more suited for a single-player experience.

 

Epic Battle Type

  1. Inspired from the multiplayer mode in Total War games.
  2. There is no base-building.
  3. Each player has fixed number of souls at the start to purchase units.
  4. When you kill enemy units, you gain souls equivalent to half its cost (i.e. dwindling economy).
  5. You can summon reinforcements in the middle of battle. Summonings are almost instantaneous.
  6. If you don’t want more units, you can use souls to upgrade your units instead.
  7. When your unit dies, all the rest of your remaining units gain size, until you are left with one unit who is a giant boss that you control.
  8. This ensures that an “epic battle” at the end of a match always happens: between the winning side who has so many units, and the losing side who has a giant boss.
  9. It’s also possible that both sides end up with giant bosses too.

 

I could eventually try implementing all of them but I have to consider which I will make first.

I’m also wondering whether I devote my efforts into creating a single-player mode first, or a multiplayer mode first. Of course I want to add both but I’m wondering what I prioritize for the 7 days.

Single-player means I make AI, multiplayer means I do networking code.

Feel free to give suggestions!

Web demo WIP

Strat Souls: WIP 2

Posted by (twitter: @AnomalusUndrdog)
Monday, July 22nd, 2013 9:29 pm

I think lightning zweihander is pretty imba.

  1. Melee damaging has been added.
  2. New unit: Zweihander guy. Zweihander guy is slow but his attacks are powerful. His weapon also has a large reach.
  3. Smoothed camera rotations.

Web demo WIP

Clarification on my entry “Strat Souls”

Posted by (twitter: @AnomalusUndrdog)
Monday, July 22nd, 2013 3:44 am

Hi guys,

 

Just a clarification. I saw the submit entry button for #7dRTS, and I thought it was used for submitting your entry at the start. So I went ahead and made one.

Turns out it’s for submitting final builds.

Whoops.

I guess you can chalk it up to staying up too late. This is also my first time participating in anything that is Ludum Dare.

Well, there’s no option to delete the entry, so I renamed it “work-in-progress”.

 

In any case, I’ll still continue working on it even if I get disqualified or anything like that. And you can use that to always see the latest build of the game while it’s in-progress.

[cache: storing page]