Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

[RELEASED] Turn Based Strategy Framework

Discussion in 'Assets and Asset Store' started by michal-zetkowski, Jul 2, 2019.

  1. tsoguojia

    tsoguojia

    Joined:
    Nov 17, 2020
    Posts:
    4
    I have been trying to modifying generator script. but I don't understand the formula for calculating of position to generate a Rectangle hex grid of pointy style.
    Code (CSharp):
    1. hexagon.transform.position = new Vector3((j * hexSize.x * 0.75f), (i * hexSize.y) + (j % 2 == 0 ? 0 : hexSize.y * 0.5f), 0);
     
  2. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    You identified the relevant piece of code correctly. I understand that this line may seem confusing, but it corresponds nicely to "size and spacing" paragraph in the resource that you linked. Take a look at the picture that you can find there and then check out the code again. Lets's split it up:
    • (j * hexSize.x * 0.75f) - this part is responsible for horizontal spacing. In flat-top style, centers of each hexagon are 0.75 of their width apart. This is what this code says and this is what you can see in the picture on the linked page
    • (i * hexSize.y) + (j % 2 == 0 ? 0 : hexSize.y * 0.5f) - this part is responsible for vertical spacing. It means that every other hexagon needs to have an offset equal to half of its height.
    I hope it cleared it up a bit. In the linked page you can change the picture to pointy-top style to get the spacing information. That should be sufficient for you to change the code
     
  3. tsoguojia

    tsoguojia

    Joined:
    Nov 17, 2020
    Posts:
    4
    thank you very much,
    now, I can do but I want to give you a check on my hexagon script.
    It's correct? I seem confusing with convert offset coordinate.

    OffsetCoordinate To Cube
    Code (CSharp):
    1.  case HexGridType.odd_r:
    2.                     {
    3.                         ret.x = OffsetCoord.x - (OffsetCoord.y + (Mathf.Abs(OffsetCoord.y) % 2)) / 2;
    4.                         ret.z = OffsetCoord.y;
    5.                         ret.y = -ret.x - ret.z;
    6.                         break;
    7.                     }
    8.  
    9. case HexGridType.even_r:
    10.                     {
    11.                         ret.x = OffsetCoord.x - (OffsetCoord.y - (Mathf.Abs(OffsetCoord.y) % 2)) / 2;
    12.                         ret.z = OffsetCoord.y;
    13.                         ret.y = -ret.x - ret.z;
    14.                         break;
    15.                     }
    CubeToCoordinate
    Code (CSharp):
    1.  case HexGridType.odd_r:
    2.                 {
    3.                     ret.y = CubeCoord.z;
    4.                     ret.x = CubeCoord.x + (CubeCoord.z + (Mathf.Abs(cubeCoords.z)) % 2) / 2;
    5.                         break;
    6.                     }
    7.  
    8. case HexGridType.even_r:
    9.                 {
    10.                     ret.y = cubeCoords.z;
    11.                     ret.x = cubeCoords.x + (cubeCoords.z - (Mathf.Abs(CubeCoord.z) % 2)) / 2;
    12.                     break;
    13.                 }
     
  4. Untrustedlife

    Untrustedlife

    Joined:
    Apr 21, 2020
    Posts:
    78
    I am sure it can be optimized further
     
  5. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Nice work, I'm glad you made it work.

    I'm out of town for a few days so I can't look at my code right now. The snippets that you shared are as confusing for me now as they are for you, I coded it a few years back. The implementation is also based on the page from before, check out "coordinate systems" and "coordinate conversion" paragraphs and try to work it out. I should be back around next weekend so if you can't do it by then maybe I'll be able to help
     
  6. Lord_Eniac

    Lord_Eniac

    Joined:
    Jan 28, 2020
    Posts:
    50
    I'm confused with the naming convention of the HexGridType enumeration. Can you please explain odd_q, even_q, odd_r, and even_r?
     
  7. TheBleachDoctor

    TheBleachDoctor

    Joined:
    Nov 20, 2020
    Posts:
    1
    Hi there! In my current project using TBS Framework, I'm getting this error message:
    "Assets\TBS Framework\Editor\GridHelper.cs(569,48): error CS0118: 'CameraController' is a namespace but is used like a type"

    Was hoping that you might know why this is appearing! Thanks for any help you can offer.
     
  8. tsoguojia

    tsoguojia

    Joined:
    Nov 17, 2020
    Posts:
    4
    Determine which type of offset system you use; *-r are pointy top; *-q are flat top.

    Odd_q and Even_q are return value offset coordinate and cube coordinate is even and odd of flat orientations or Flat-topped, odd_r and even_r are return value offset coordinate and cube coordinate is even and odd of pointy orientations or Pointy topped
     
  9. GoldenSun

    GoldenSun

    Joined:
    Jan 4, 2013
    Posts:
    1
    This is a great product! I looked through a couple of the comment pages and found some helpful comments about dynamically adding units. However, I could not find anything for dynamically adding obstacles (maybe its buried in the comments).

    I wrote the following code, which does add the obstacle, but does not treat it as an obstacle and allows the units to go over it. What am I doing wrong here? Is this the correct way to add obstacles:

    public class TestSceneStartup : MonoBehaviour
    {
    public GameObject Obstacle;
    private static bool IsFirstUpdate { get; set; }

    // Start is called before the first frame update
    void Start()
    {
    IsFirstUpdate = true;
    }

    // Update is called once per frame
    void Update()
    {
    if (IsFirstUpdate)
    {
    var cellGridArray = GameObject.FindObjectsOfType(typeof(CellGrid));
    if (cellGridArray != null)
    {
    var cellGrid = (CellGrid)cellGridArray[0];
    var square = PrefabUtility.InstantiatePrefab(Obstacle) as GameObject;

    var squareSize = square.GetComponent<Cell>().GetCellDimensions();

    square.transform.position = new Vector3(0,0,0);
    square.GetComponent<Cell>().OffsetCoord = new Vector2(0,0);
    square.GetComponent<Cell>().MovementCost = 1;
    square.GetComponent<Cell>().IsTaken = true;
    cellGrid.Cells.Add(square.GetComponent<Cell>());
    //square.transform.parent = CellsParent;
    }

    IsFirstUpdate = false;
    }

    }
    }


    Do you have a wiki for FAQs like these? Also, is there any documentation on how to do grid manipulation dynamically (adding players, units, changing cells, etc.)?
     
  10. Panhypersebastos

    Panhypersebastos

    Joined:
    Feb 21, 2017
    Posts:
    44
    Hey,

    Is there a good way to set things up with this framework so that UI elements block you from highlighting/clicking on cells that are behind them? My usual standby of setting the UI as a raycast target doesn't seem to work here.
     
  11. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hey everyone, sorry for not replying, I've been traveling for the last few days. I'll write you all back as soon as I can.
     
  12. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    These terms regard grid layout, please read through the article linked below, it explains it better than I ever could.
    https://www.redblobgames.com/grids/hexagons/
     
  13. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hmm, did you copy some of my code? Changed namespaces?

    I would advice to reimport the framework (if it won't break your project) or just delete the code related to CameraController from GridHelper script. If you want movable camera you can just add CameraController script to your main camera manually
     
  14. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hey, you are spawning a new cell instead just an obstacle. I guess it is spawned on top of existing cell and is not taken into consideration.

    If you want to make a cell impasssable, just set IsTaken field on this cell to true and optionally you can instantiate your obstacle on top of that cell.

    You can find links to FAQ and documentation on the framework page on Asset Store :)
     
    GoldenSun likes this.
  15. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Not sure about that, but maybe this link will help? https://forum.unity.com/threads/blocking-physics-raycasts-with-the-ui.300157/
     
  16. ShaunBartoo

    ShaunBartoo

    Joined:
    May 23, 2019
    Posts:
    3
    Hi, I'm just getting started with this framework, and I hit a small issue. When I generate a grid with the GridHelper, my assets are rotated 90 degrees. If there isn't an easy solution within the framework here, I can just rotate my geometry before I export if from my modeling software to have Z as its up axis, but before I start rotating all my assets, I was wondering if theres a way to have the framework generate the grid on the XZ axis. I see the option for XZ generation in the GridHelper, but it seems to still generate it on XY and then make it XZ by rotating the cellgrid object 90 degrees, which is causing my rotation issue. Images below for clarity.

    Note that 'Cube' is essentially just a default cube that was scaled down in the y axis and given a bevel on the top face. The top face of the asset is facing the +y direction.

    The issue:

    GridHelper settings:


    How I want it to look:

    What I have to do currently to make it look like this (note the rotation):
     
    Last edited: Nov 30, 2020
  17. Dimich_Sky

    Dimich_Sky

    Joined:
    Feb 2, 2020
    Posts:
    3
    Hi, very impressive framework, I have one question though. Is there any way to customize the movement of the units, like for instance I want my units to move just in a straight line x amount of tiles? I searched through the code but did not find such options, thank you in advance.
     
  18. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hey,

    Sorry to say it, but for now you'll have to rotate your assets :(. I am aware that this is an issue, but I don't have any other quick fix for you at the moment.
     
    asaarashi likes this.
  19. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Sure, you will have to override IsCellTraversable method in your unit class. The code below will make the unit move only in straight lines:
    Code (CSharp):
    1. public override bool IsCellTraversable(Cell cell)
    2. {
    3.     return base.IsCellTraversable(cell) && (cell.OffsetCoord.x == Cell.OffsetCoord.x || cell.OffsetCoord.y == Cell.OffsetCoord.y);
    4. }
     
    Dimich_Sky likes this.
  20. ShaunBartoo

    ShaunBartoo

    Joined:
    May 23, 2019
    Posts:
    3
    Ok, no worries. Not a big deal. It might be helpful to note this in the documentation for other people who trip over this.
     
  21. Panhypersebastos

    Panhypersebastos

    Joined:
    Feb 21, 2017
    Posts:
    44
    That seems to do it, I changed all the oncellclicked, onunitclicket, etc... to the below and now everything is working as I intend it to.

    Code (CSharp):
    1. private void OnCellClicked(object sender, EventArgs e)
    2.         {
    3.             if(!EventSystem.current.IsPointerOverGameObject())
    4.             {
    5.                 CellGridState.OnCellClicked(sender as Cell);
    6.             }          
    7.         }
     
  22. xcombeta

    xcombeta

    Joined:
    Nov 28, 2020
    Posts:
    5
    Hey, thanks for your asset, it really helps me a lot.
    But there is one question. After I adapt GetNeighbours to recognize diagonal square as neighbours, how can I make a 1.5 times movement cost for diagonal movement on a square grid? I tried to use a getMovementCost(Cell otherCell) to Cell class like you said before, but I don't know how to write it. Can you give me a hand?
     
  23. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hey,

    How about this? I don't have access to my computer at the moment, so I can't test it:
    Code (CSharp):
    1. if(Mathf.Abs(this.offsetCoord.x - otherCell.offsetCoord.x) == 1 &&
    2.    Mathf.Abs(this.offsetCoord.y - otherCell.offsetCoord.y) == 1)
    3. {
    4.    //otherCell is diagonal
    5.    return otherCell.MovementCost * 1.5f;
    6. }
    7. else
    8. {
    9.    //otherCell is not diagonal, return normal value
    10.    return otherCell.MovementCost;
    11. }
    You might also need to override GetDistance method, but let's fix these issues one at a time. Let me know if that code helped you
     
  24. xcombeta

    xcombeta

    Joined:
    Nov 28, 2020
    Posts:
    5
    Thanks for your reply, but unfortunately the code doesn't work. The diagonal movement cost is still equal to the orginal movement cost.
     
  25. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    I see. I'll try it out on Sunday evening or Monday when I'm back, ok?
     
  26. xcombeta

    xcombeta

    Joined:
    Nov 28, 2020
    Posts:
    5
    Ok,Thanks
     
  27. Untrustedlife

    Untrustedlife

    Joined:
    Apr 21, 2020
    Posts:
    78
    Ive been making alot of progress, its a very fun and addicting little lightweight 4x/wargame game now upload_2020-12-6_1-54-45.png


    Ill let you know when a demo is available so you can try it out!
     
    Last edited: Dec 6, 2020
  28. Untrustedlife

    Untrustedlife

    Joined:
    Apr 21, 2020
    Posts:
    78
    upload_2020-12-6_1-57-30.png And another screenshot, of me recruiting some rangers at a town bordering a purple AI player
     
    LordDooms likes this.
  29. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    My bad, there is no getMovementCost method to override in Cell class. Reference to MovementCost field is used directly.

    You must add this method to Cell yourself, look at the code that references MovementCost and use the new method where appropriate. The code that I posted before should work fine.

    I checked the references and he most important part to change is line 446 in Unit.cs:

    Code (CSharp):
    1. ret[cell][neighbour] = neighbour.MovementCost;
    Change it to

    Code (CSharp):
    1. ret[cell][neighbour] = neighbour.getMovementCost(cell);
    Let me know if that helped
     
  30. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Nice, let us know when demo is available :)
     
  31. xcombeta

    xcombeta

    Joined:
    Nov 28, 2020
    Posts:
    5
    Thanks for your reply. Actually, I have already changed the code in Unit.cs and added getMovementCost method in Cell class just like you said, but it still doesn't work. The diagonal movement cost is still equal to the orginal movement cost:(
     
  32. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    We'll figure it out. Could you export your project and send it to me by email to crookedhead@outlook.com?
     
  33. archelunch14

    archelunch14

    Joined:
    Oct 1, 2019
    Posts:
    3
    Hi! I have 2 questions.
    1. How can I make order of unit's turns based on their initiative parameter?
    2. Is it possible to make passive skills for unit? For example I want to make attack of opportunity - if unit1 leaves cell near unit2, unit2 can hit unit1.
     
  34. xcombeta

    xcombeta

    Joined:
    Nov 28, 2020
    Posts:
    5
    Thanks. But actually I just used the Example3 in your framework to test the code,and my project haven't used the code yet. So you could use Example3 to see if it works.
     
  35. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    It would be more convenient for me to work with what you've done so far. Otherwise I need to code all of this myself.
     
  36. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hey,

    The features you ask for are not possible to achieve through simple customisation, you would need to add these features. Here are some tips:

    1. You will need to modify EndTurn method in CellGrid class to autimatically select the correct unit to use. You can do that by assigning CellGridStateUnitSelected object with the unit as parameter to CellGrid.GridState field. Also, you would have to block selecting other friendly units in CellGridStateUnitSelected.UnitClicked method. This way you will force the user to use the correct unit.

    2. The problem is taht there is no method that can be used when the unit reaches each of the cells along the path. You would need to add such function, probably somewhere in MovementAnimation method, and from there you should be able to implement a skill that you described
     
  37. archelunch14

    archelunch14

    Joined:
    Oct 1, 2019
    Posts:
    3
    But can I make unit1 attack unit2 at the moment when unit2 leave cell? This attack should be before movement is started.
     
  38. archelunch14

    archelunch14

    Joined:
    Oct 1, 2019
    Posts:
    3
    Also, is it possible to reduce attack range when enemy's unit in neighboring cell?
    It is the script that I wrote. I can check if cell is taken, but how can I check if cell is taken by enemy's unit?

    Code (CSharp):
    1.             var neighbours = Cell.GetNeighbours(cells);
    2.  
    3.             foreach (var neighbour in neighbours)
    4.             {
    5.                 Debug.Log(neighbour.gameObject);
    6.                 if (neighbour.IsTaken)
    7.                 {
    8.                     AttackRange = 1;
    9.                     break;
    10.                 }
    11.                 else
    12.                 {
    13.                     AttackRange = maxAttackRange;
    14.                 }
     
  39. Dimich_Sky

    Dimich_Sky

    Joined:
    Feb 2, 2020
    Posts:
    3
    Hi, Sorry for this question but is it possible to make the units face towards their movement when moving and also at the end of the units turn you chose which direction you want it to face, its in a 3D grid based game, not hexgrid. Thanks.
     
  40. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    If the attack should occur before the unit moves, you could try to code at the beggining of Unit.Move method. Again, it is not available iout of the box, you will have to implement it yourself.
     
  41. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Cell has a reference to the unit that is standing on it - Cell.CurrentUnit. Using this reference you can check which player the unit belongs to (CurrentUnit.PlayerNumber).
     
  42. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Well, there is an issue with rotating units while moving in framework v2.0. If you look through 2 previous pages of this thread you will fin more information on that topic.

    Regarind your second question, just add an enum to unit that would indicate where it is facing. Where exactly you put rotation code is secondary issue, I would put it in the same controller that would handle selecting facing direction.
     
  43. Dimich_Sky

    Dimich_Sky

    Joined:
    Feb 2, 2020
    Posts:
    3
    Yeah I looked at the solution proposed for the rotation but it only works on a hexgrid, guess I have to modify for it to work on a normal grid.
     
  44. GameMarshal

    GameMarshal

    Joined:
    Nov 9, 2020
    Posts:
    8
    Hi,

    I bought your asset (thanks for making it affordable) and plan to develop a wargame, but quite with the spirit of a RTS.
    It is my first game even if I have some experience as a web developer.

    Is all this possible with your framework, have you any advice for:

    - Having buildings producing units? Once produced, the unit is set on an adjacent cell.
    - Blocked line of sight, for example a unit on each cell with an hexagonal grid?
    - Multiplayer on top of your framework?
    - Not usable cells, for example a river?
    - Isometric view with 3d model? So a 2d grid and 3d units and buildings?
    Do you advice a way or an asset to build the map. I was thinking about 2d images the same form as a cell for the terrain, still an object to handle some code (cover for forest, etc) and 3d objects for the units and buildings.
    Several units on a cell is not possible according to the FAQ, but can you have 2 objects (one for the terrain tile, one for the real unit) on the same cell, and so put some code for a forest, a lake...

    Thank you ;)
     
    Last edited: Dec 11, 2020
  45. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Hey, thanks for buying :)

    1. Out of the box, there is no building support in the framework. If you read through the last page of this thread you will find a clever solution to this problem that someone came up with (basically using units as cities / buildings). Once you have it, spawning units on runtime is just a matter of calling CellGrid.AddUnit method with correct parameter.

    2. You can have multiple pieces of data (like resources) on the same cell with no issue. Multiple units on a single cell is another problem. You can unlock it by changing condition in Unit.IsCellMoveableTo method (remove the condition that says that the cell can't be taken)

    3. The problem is that the method that handles attacking (Unit.AttackHandler) only has reference to the attacked unit. You would need to add relevant parameters to the function to be able to deal area of effect damage.

    4. You can either use raycasting to determine if something is blocking the view, or use line drawing algorithm (https://www.redblobgames.com/grids/line-drawing.html) and check if there is an obstruction on any of the cells along the line. Either way, I would code it in Unit.IsUnitAttackable (you might need to add some more parameters to the method though)

    5. Sorry, but I have no experience with online multiplayer in Unity

    6. You only need to edit grit generation scripts to get isometric tiles to work. Spacing between isometric tiles is different thatn between normal tiles.
     
  46. GameMarshal

    GameMarshal

    Joined:
    Nov 9, 2020
    Posts:
    8
    Thanks for the useful answer. I have other questions ^^
    Need to know what I can do with your framework.

    About the grid, I was more thinking about setting the camera to an orthographic view (like isometric in Blender), so a 2.5d game, with your grid viewed on top (2d) and models in 3d (to highlight the important part of the game which are the units and buildings).
    I hope I was clear. What do you think of it?

    About the TBS part. What is the speed of the game? Might sound a noob question sorry.
    Is it possible to use the grid to make a real-time game, or is there a limit in speed, a fixed interval in your framework handling the different states?

    Finally, what max grid size do you think is possible for a PC game?
    Knowing I doesn't have the knowledge to optimize my game and would like it to run correctly on non-gamer configurations.

    Now, I will dive into the code :D
     
  47. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282
    Could you post a screenshot example with this 2.5D view?

    The game is as fast as frequently you change turns. You could make turns change automatically to simulate real-time game. You would probably need to synchronise unit movement with turn transitioning. Not sure about that, I never considered using it for real-time games :)

    It seems to me that @Untrustedlife uses quite a big maps, you could ask him :). I just tried 100x50 hexgrid and it worked fine.
     
  48. GameMarshal

    GameMarshal

    Joined:
    Nov 9, 2020
    Posts:
    8
    100*50 seems good ;)

    About the 2.5d, I was thinking about an aesthetic like Mobius Front '83.



    Is it possible to add a condition in your framework to handle that two objects can be on the same cell if only they are not of the same type. I would have 2 different types, Terrain and Army. So two Army objects (two real units) couldn't be on the same cell, but an Army object could be on the same celle as a Terrain (forest, plain, bridge...)?

    If not possible to have this kind of condition, is there a way for the Unit object to get some info from the cell terrain. If I add images to represent the terrain, is there an easy way to give info depending upon the image and gives some data to the Unit object on the cell?
     
  49. PopRockLex

    PopRockLex

    Joined:
    Sep 13, 2018
    Posts:
    17
    Hey guys, I'm really new to this. I'm trying to figure out how to make a unit take damage back when they attack based on the receiving unit's "AttackFactor". Would I do this in the "Unit" script?
     
  50. michal-zetkowski

    michal-zetkowski

    Joined:
    Mar 11, 2015
    Posts:
    282

    I see no issue with this kind of 2.5D setup.

    Well, terrein type should be property of your cell, it has nothing to do with units / army. If you want to add different kind of terrains, you should subclass Cell class like this:

    Code (CSharp):
    1. class CustomCell : Cell
    2. {
    3.      public TerrainType terrain; // Where terrain type is enum with different values
    4. }
    You could then use this terrain information in Unit script to add defence bonus, make certain terrain types impassable to different units etc
     
    GameMarshal likes this.