Sunday, August 17, 2014

Hero Worship - Now You See Me...

There's no fog of war in Actraiser.  You can see everything that's happening on the map at all times. I wanted to mess around with it for Hero Worship, but I've never attempted anything remotely like it before.  I could have researched the "best" solution or sent out a plea on the numerous coding forums, but sometimes it's fun figuring stuff out by yourself.  And sure enough, I came up with a working system that ain't fancy, but it does get the job done in the way I imagined.

It's really very simple.  So simple I call it the "Poor Man's Fog of War".

First, here's what I wanted:

  • Monsters and enemy buildings are unseen unless a villager or village building is near.
  • If monsters move further away, they become unseen.
  • Once monster buildings have been "scouted" they stay visible on the map.
  • Terrain is not affected by any of this.  It's always viable.

And here's what I knew how to do:

  • Get nearest instance of any object or category of objects.
  • Determine the distance between a monsters (or building) and any near object.
  • Adjust alpha of the sprite based on distance.

And that's it.

It works the same way with enemy buildings.  In fact, the code only exists on the enemy units and structures because those are the only ones that need to know if they can be seen.  The Villager AI doesn't know or care either way.  But that's ok, because they're reaction to enemy proximity is based on their own "sight" radius.

Here's the script.  It's in the step event of the monster:

This will hold the friendly object that's closest to the monster.
var alphaMod;  


Gather our data
person = instance_nearest(x,y, obj_walkers);
personDist = distance_to_object(person);
personDist = floor(personDist);

place = instance_nearest(x,y, obj_buildings);
placeDist = distance_to_object(place);
placeDist = floor(placeDist);

This determines if it's a building or a villager.
if(personDist < placeDist) 
    {
    alphaMod = personDist;
    }
    else
    {
    alphaMod = placeDist; 
    }

Here's where it will adjust the alpha based on distance.
The formula "(alphaMod - 300)*(-.01)" makes the transition smooth.  It looks pretty neat.
    
if(alphaMod >= 300)
    {
    image_alpha = 0;
    }
else if(alphaMod < 300 && alphaMod > 201)
    {
    image_alpha = (alphaMod - 300)*(-.01);
    }
else if(alphaMod <= 200)
    {
    image_alpha = 1;
    }


The only difference between the script on the monster and the one on the monster building is an additional "Detected" boolean.  This flags true once any villager object gets within 200px of it.  If it's true, it sets the alpha to 1 and then stops checking for distances (since it's been located).

There are still some things to consider:

  • If I introduce creeping corruption, should that be affected by fog of war?  Right now I think so.  If players can see the corruption spreading they will be able to figure out the location of the source and I don't think we want that.
  • What about line of sight?  Mountains, forests, etc.  Should that have an effect.  I don't know how much value it will add the to the game.  The interactions aren't really about the tactics of unit position or movement.  It's more of an economic / exploration thing, so I'm going to table it unless it becomes something I absolutely have to deal with.
For now, we soldier on.


1 comment:

Mr. T. W. Pasley said...

You are a coding foo. Nice.