Project Wilderness Introduction

August 18, 2011

My new project is one in which the player takes turns against the computer fighting across a hexagonal grid system. As the player traverses the game world, he/she will hit triggers that reveal the hexagonal grid for a fight, sending the player and nearby enemies to respective positions in the game world.

I quickly realised that creating the hexagonal grid each time would be a chore, because the way I’m doing it currently involves detailing the up to 6 connecting nodes for each node. So today I’ve been focusing on building a simple-ish tool that will automatically generate a hexagonal grid for me that I then merely need to tweak.

All I need to do to create a grid is to set a base name (say TowerFight or BeachFightA, etc.) then the X grid width and Y grid depth/height and click on the terrain (or at the moment, a button) to generate the grid.

Curious about the TorqueScript used to generate the grid? There’s still some small changes I want to make, but oh what the hell:

Note – The simgroup is simply a way of grouping together stuff in a mission file, so in the code below, I’m creating a simgroup to store all the elements that go into creating the hex grid. I can then select that simgroup folder to select everything sub foldered within it. Then I can rotate, move (etc) the whole grid with ease.

It’s more readable here: http://pastebin.com/gQVPVdRN

// concatenation of CombatHexGridNameTextField.text + X Num + Y Num
// X Num and Y Num change depending on if we’re filling the node name or
//connectingNodeNW
//connectingNodeNN
//connectingNodeNE
//connectingNodeSW
//connectingNodeSS
//connectingNodeSE

//xPosTextField.text and yPosTextField.text
//CombatHexGridNameTextField.text

//x = 1
//connectingNodeNW = -1;
//connectingNodeSW = -1;

//x = xPosTextField.text
//connectingNodeNE = -1;
//connectingNodeSE = -1;

//y = 1
//connectingNodeNN = -1;

//y = 1 and x = odd number
//connectingNodeNW = -1;
//connectingNodeNN = -1;
//connectingNodeNE = -1;

function BeginHexCreation()
{
   %simGroupName = CombatHexGridNameTextField.getText();
   %obj = new SimGroup(%simGroupName)
      {
         canSave = “1”;
         canSaveDynamicFields = “1”;
      };
      MissionGroup.add(%obj);

   %xGridMaxPos = xPosTextField.getValue();
   %yGridMaxPos = yPosTextField.getValue();

   %hexOffsetValue = 0;

   %combatNodeXWorldPos = 20;
   %combatNodeYWorldPos = 20;
   %variableCombatNodeYWorldPos = %combatNodeYWorldPos;
   %combatNodeZWorldPos = 240.1;
   %combatNodePosition = %combatNodeXWorldPos SPC %CombatNodeYWorldPos SPC %combatNodeZWorldPos;
   %hexOffset = true;

   %ORIGINcombatNodeXWorldPos = %combatNodeXWorldPos;

   %xGridPos = 1;
   %yGridPos = 1;

   while(%yGridPos<=%yGridMaxPos)
   {
   %hexOffset = true;
   %combatNodeXWorldPos = %ORIGINcombatNodeXWorldPos;

   while(%xGridPos<=%xGridMaxPos)
   {

   %newCombatNodeName = CombatHexGridNameTextField.getValue() @ “X” @ %xGridPos @ “Y” @ %yGridPos;

   //Turns out the connecting node names are different depending on if %xGridPos is odd or even
   if(!((%xGridPos /2)==1))
   {
      %connectingNodeNWName = CombatHexGridNameTextField.text @ “X” @ %xGridPos-1 @ “Y” @ %yGridPos-1;
      %connectingNodeNNName = CombatHexGridNameTextField.text @ “X” @ %xGridPos @ “Y” @ %yGridPos-1;
      %connectingNodeNEName = CombatHexGridNameTextField.text @ “X” @ %xGridPos+1 @ “Y” @ %yGridPos-1;
      %connectingNodeSWName = CombatHexGridNameTextField.text @ “X” @ %xGridPos-1 @ “Y” @ %yGridPos;
      %connectingNodeSSName = CombatHexGridNameTextField.text @ “X” @ %xGridPos @ “Y” @ %yGridPos+1;
      %connectingNodeSEName = CombatHexGridNameTextField.text @ “X” @ %xGridPos+1 @ “Y” @ %yGridPos;
   }
   else
   {
      %connectingNodeNWName = CombatHexGridNameTextField.text @ “X” @ %xGridPos-1 @ “Y” @ %yGridPos;
      %connectingNodeNNName = CombatHexGridNameTextField.text @ “X” @ %xGridPos @ “Y” @ %yGridPos-1;
      %connectingNodeNEName = CombatHexGridNameTextField.text @ “X” @ %xGridPos+1 @ “Y” @ %yGridPos;
      %connectingNodeSWName = CombatHexGridNameTextField.text @ “X” @ %xGridPos-1 @ “Y” @ %yGridPos+1;
      %connectingNodeSSName = CombatHexGridNameTextField.text @ “X” @ %xGridPos @ “Y” @ %yGridPos+1;
      %connectingNodeSEName = CombatHexGridNameTextField.text @ “X” @ %xGridPos+1 @ “Y” @ %yGridPos+1;
   }

   if(%xGridPos==1) //This if prevents the offset triggering when it shouldn’t be due to odd numbered width
   {
      %hexOffsetValue = 0;
   }
   %variableCombatNodeYWorldPos = %combatNodeYWorldPos + %hexOffsetValue;
   %combatNodePosition = %combatNodeXWorldPos SPC %variableCombatNodeYWorldPos SPC %combatNodeZWorldPos;

   new StaticShape(%newCombatNodeName) {
         dataBlock = “CombatNode”;
         parentGroup = %simGroupName;
         position = %combatNodePosition;
         rotation = “1 0 0 0”;
         scale = “1 1 1”;
         canSave = “1”;
         canSaveDynamicFields = “1”;
            connectingNodeNW = %connectingNodeNWName;
            connectingNodeNN = %connectingNodeNNName;
            connectingNodeNE = %connectingNodeNEName;
            connectingNodeSW = %connectingNodeSWName;
            connectingNodeSS = %connectingNodeSSName;
            connectingNodeSE = %connectingNodeSEName;
            occupant = “None”;
      };
   echo(“Created at X: ” @ %combatNodeXWorldPos @ ” Y: ” @ %variableCombatNodeYWorldPos);

   if(%hexOffset$=true)
   {
      %hexOffset = false;
      %hexOffsetValue = -2;
   }
   else
   {
      %hexOffset = true;
      %hexOffsetValue = 0;
   }

   %combatNodeXWorldPos = %combatNodeXWorldPos + 3;
   %xGridPos = %xGridPos +1;

   }
   %combatNodeYWorldPos = %combatNodeYWorldPos -4;   

   %xGridPos = 1;
   %yGridPos = %yGridPos +1;

   }
}

Advertisements

3 Responses to “Project Wilderness Introduction”

  1. Robert Farr Says:

    Had a few questions about this code. Answers:
    QUESTION 1
    I had to do some digging back when I was working on other projects to find where most of the script file execution happens, I found two main places:
    [project_name]/game/core/main.cs and
    [project_name]/game/art/datablocks/datablockExec.cs
    At the bottom of the second one of those I added
    // ROBERT FARR – BEGIN LOADING NEW SCRIPTS FOR TURN BASED HEX GAME
    exec(“./combatNode.cs”); – See question 2
    exec(“./combatManager.cs”); – This is gameplay code, currently for things like combat zone visibility and changing a combat mode variable (etc).

    I have a nasty habit of putting a lot of my early code in the file
    [project_name]/game/art/gui/playgui.gui (where I can just start prototyping without the hassle of new script file execution) which is where I placed both the code for the hexgrid creation gui widget and the hexgrid creation code itself. I’ve pasted the whole of my playgui file to the pastebin URL below so you can check it out.
    http://pastebin.com/m0Fp355J

    QUESTION 2
    The combatNode.cs file simply contains
    datablock StaticShapeData(CombatNode)
    {
    category = “TurnBasedCombat”;
    shapeFile = “art/shapes/Hexagon.cached.dts”;
    isInvincible = true;

    };

    (Also contains this which I can’t remember if it’s even supposed to really do anything.)
    function CombatNode::onAdd(%this, %obj)
    {
    //just a bunch of comments in here
    }

    Richard, if you have any more questions feel free to ask.
    I’ll try my best to help.

  2. Robert Farr Says:

    Oops, so then I finally spot I’ve placed
    exec(“./HexGridGeneration.cs”);
    just after //— OBJECT WRITE END —

    I could just as easily put the BeginHexCreation(%xPosition, %yPosition, %zPosition) function into playgui.gui.

    Current version of HexGridGeneration.cs here:
    http://pastebin.com/pkiHbqdg

  3. Robert Farr Says:

    One last comment regarding the simgroup bit, basically, the gui widget allows me to enter a name field when I go to create a combat zone, partly so that there’s no chance of the individual hex grid pieces not being created due to name duplication. When each hexgrid piece is made, the parent variable is given the simgroup name – by doing this it means that when the combat zone is created all the hex pieces will be automatically grouped together into one folder complete with a ready made trigger box in the scene/level.

    Note that when a grid is created it’s necessary to save the level so that the new grid will still be there when the level is loaded later. The grid generator is mainly built as a tool so I don’t have to painstakingly setup a grid manually from scratch. Once I’ve made one, I can then edit the shape of it as I see fit as long as I remember that any change to one hex means I have to edit its neighbours too.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: