Just wanted to give some feedback about Grids Library
This is mostly just for @hermantulleken ... I don't think there is a thread about GameLogic's grid library here.
This feedback is quite critical. Just looking at the Unity forums it seems like the people happily using the Grid library are more technical than myself. So please take my feedback with a pinch of salt, I don't think I'm the intended audience.
I was starting to make a prototype today, one which required a tiled world map (like Civilization).
So I thought I would try Grids finally (I've been meaning to use it).
Now I don't know if Grids is intended for this sort of thing, some of the images in the trailer sort of made it looks like it might work, but when I tried it, it turns out to work in a way that I just can't get my head around, or are unappealing for my purposes.
- There's nothing in the scene at the start. i.e. the grid is built through code. This is fine for released game purposes (Broforce levels are read from XML, it wouldn't make sense to save the tens of thousands of objects that comprise them in scenes), but it isn't the sort of rapid prototyping solution I had hoped for. What I mean is that the Grids Library can't assist with level building (I wanted to build the world map visually), it's only suited generated grids (out the box).
- When I move objects in the scene, it doesn't update in the game view unless it is busy playing. One of the scenes even seemed to render the entire scene to a texture. I find this sort of thing invasive, and generally steer clear of plugins that do anything other than the task I need them for (because if I have two or more different plugins that want to dictate the rendering pipeline it'll be a mess and don't want to spend time de-engineering plugins).
- There's no visual editor.
I guess the library is more intended to be a kind of optimized math library than a rapid prototyping tool. And I'm not saying it isn't useful, just that it is quite anathema to the way that I like to use Unity (i.e. as much visual editing as possible, and being able to fiddle with things while playing).
I might also have a funny idea of what a "rapid prototyping tool" is, and how it should function. I use Unity more as a designer than a coder, I'm not sure if that is the problem I'm hitting.
Like I say. I'm not sure if I'm the intended use case. I came in looking for a plugin to help me prototype faster, whereas this plugin seems to be a tool designed to run faster (which is not a bad thing, it's just not the thing I wanted).
This feedback is quite critical. Just looking at the Unity forums it seems like the people happily using the Grid library are more technical than myself. So please take my feedback with a pinch of salt, I don't think I'm the intended audience.
I was starting to make a prototype today, one which required a tiled world map (like Civilization).
So I thought I would try Grids finally (I've been meaning to use it).
Now I don't know if Grids is intended for this sort of thing, some of the images in the trailer sort of made it looks like it might work, but when I tried it, it turns out to work in a way that I just can't get my head around, or are unappealing for my purposes.
- There's nothing in the scene at the start. i.e. the grid is built through code. This is fine for released game purposes (Broforce levels are read from XML, it wouldn't make sense to save the tens of thousands of objects that comprise them in scenes), but it isn't the sort of rapid prototyping solution I had hoped for. What I mean is that the Grids Library can't assist with level building (I wanted to build the world map visually), it's only suited generated grids (out the box).
- When I move objects in the scene, it doesn't update in the game view unless it is busy playing. One of the scenes even seemed to render the entire scene to a texture. I find this sort of thing invasive, and generally steer clear of plugins that do anything other than the task I need them for (because if I have two or more different plugins that want to dictate the rendering pipeline it'll be a mess and don't want to spend time de-engineering plugins).
- There's no visual editor.
I guess the library is more intended to be a kind of optimized math library than a rapid prototyping tool. And I'm not saying it isn't useful, just that it is quite anathema to the way that I like to use Unity (i.e. as much visual editing as possible, and being able to fiddle with things while playing).
I might also have a funny idea of what a "rapid prototyping tool" is, and how it should function. I use Unity more as a designer than a coder, I'm not sure if that is the problem I'm hitting.
Like I say. I'm not sure if I'm the intended use case. I came in looking for a plugin to help me prototype faster, whereas this plugin seems to be a tool designed to run faster (which is not a bad thing, it's just not the thing I wanted).
Comments
First, thanks for giving it a try and taking the time to give some feedback. Your feedback specifically is very valuable to me, because I always have your voice playing in my head when I think about building quick prototypes. :P Indeed, we designed it from a very code-centric point of view, and this is perhaps my funny idea of what a prototyping tool is. Even @rigormortis asked us why we don't let users do things visually; he's a programmer, so you are not alone. I have been thinking about it a lot. There are good reasons that we do not have this, but we may need to re-evaluate. And at the very least make it clearer what it is and is not. This is an NGUI thing (am not sure if there is a workaround, but will look into it.) Our future examples will use Unity's sprites, which I think are better. During development, I rendered all the grids to textures, to make sure mouse clicks and cell placements are aligned exactly. I left that in some examples, because I thought it would be useful to see how maps work and can be used. But I realise it's confusing without explanation. (It most definitely does not do anything with the render pipeline though, it's a simple function that uses SetPixel on the texture based on calculations from the map.)
Based on feedback from @rigormortis, we are actually restructuring our examples completely, putting them in a tutorial-style order, removing confusing things (the rendered texture is but one instance), and making things generally clearer.
(I am a bit surprised by how people use and interpret the examples; I have been horribly naive.)
A big problem we have is that users do not discover all the features, or understand their significance; we hope this restructuring will also help with that.
A another big problem is that we struggle to communicate the separation of data from rendering (the library does not create grids visually in any way), a fact that is confused by the fact that we handle many calculations that you should use for whatever rendering scheme you settle on. The advantage of this is you can use it with anything - any sprite library, or 3D meshes, or Unity's built-in stuff. But this is not what most users expect, and I think just like you, this disappoints some. Moreover, with our own prototyping stint, we discovered ourselves how inconvenient this can be (especially for the grids that don't - or shouldn't - use sprites).
In many ways you are right, it is a math / data structure library, although the intention really is to make production fast, not just the calculations. I think the way it should be used is unusual, and even though it gives (IMHO) you a lot of power, it's not intuitive.
One very tough decisions we face is whether to conform to expectations, or try to better introduce these new ideas. I really do believe the ideas are worth considering - it really does offer important advantages. And it's not even where it ends. Some of our newer features for triangular grids are very weird conceptually, (I have discussed this a bit with @Chippit too), and I have not been able to decide whether we should expose this weirdness to users, and try to show them the advantages it offers, or whether we keep it locked away internally. It definitely is, but based on what you said, not in the way I think you'd like. Most importantly, you have to settle on a way to render the cells, and then place them in code. (The example that is closest to this is actually the 3D example. You'd of course just replace the meshes with sprites.)
Thanks again for this feedback. It help us know where we miss the mark, help us improve, and help us better understand how people want to use our tool. Some of our design decisions preclude some possibilities on a very fundamental level, so I can't promise you it will become what you'd like, but we are definitely taking it to heart.
I think when Grids uses native Sprites it'll be a more sublime experience. I'm not a fan of NGui (for the reasons in my first post, affecting my hierarchy is an unforgivable sin for a sprite class).
When I did look through the code I could start to see how I would use Grids Library. I think you nailed it when you said it's about expectations.
Obviously I've only just tried Grids, so my ideas might be a bit naive, but here's some (possibly naive) suggestions I'd make to better demonstrating the power of Grids:
1) I'm not fond of tutorials, and I'd only use them to determine what the work flow is for the plugin. I expect Unity plugins to be a black box at first... one which I'd like to tinker with later on, but one which can function as a black box with some simple inputs.
What I'd expect is a "Grids" window that can be popped up. It might not be useful to an experienced user, but it could be used to quickly get something up and running and somewhat tweakable. I love that Grids can be built through a few lines of code, but that is useless to me until I know what the possibilities are.
An important thing that can be easily conveyed here is that a gameobject (with appropriate component) can be selected to be the cell. Just having a drop in box labelled "Cell Prefab" with a sentence describing the what a cell is would already explain 50% of the Grids workflow. The the way Grids works with a single prefab that adjusts its image and is managed by the grid is quite powerful and convenient. (We used an similar method in our jam game )
2) I expect the grid dimensions to be exposed in public variables. Having no values to tweak at the start means I can't even experiment with the system until I've read through the source code. Ideally I'd like a custom editor script where I can tweak variables like grid shape. The point isn't so much to have a feature set that encompasses everything every user could ever want, but for users be able to quickly get the Grid system doing something close(ish) to what they need before they start editing the code. (I guess this duplicates a lot of the functionality of point 1)
3) For me anyway, I like to learn via tinkering (just like in games), though I will watch video tutorials sometimes before I dive in. Again, if there was a certain amount of general setup that could happen through a visual interface, then making video tutorials would be easier.
4) If I were designing this I'd have one component arranging the grid (creating the variables and instantiating it) and another one controlling the gameplay. That way the component that builds the grid can be a black box to me (assuming points 1 and/or 2 are adopted) until after I'm comfortable manipulating the grid.
For my personal usage I want to be able to edit the cells on the grid in the scene while the game is not playing, or have some kind of grid editor or grid save format. That's a pretty serious feature to bolt on, and obviously not everyone wants to use Grids to make something with hand-crafted levels, though I don't imagine I'm alone.
Also, I know Grids is out there already. I don't mean to tell you to go and double down on it and build large extra feature sets to cater to my idiosyncratic needs. But maybe this feedback is useful for your next plugin.
Again, I have nearly zero experience designing Unity plugins (and when I have distributed code its always been far more sink or swim for the user), so it might be better to not do what I'm asking for (but instead do the thing I actually need, whatever that is).
Thanks again!
You gave me quite a bit to think about in the previous post, and I thought later that I should ask you about the type off workflow you imagine. And there it is :)
Once I got my mind out of the cage a bit, I realised that a lot of what you say* can be done quite easily**. I spent the afternoon playing around with a proof of concept. It is not exactly what you describe, but I think it is a lot closer. And I like it :)
(* Well, how I re-imagined what you said)
(** The essence is easy, but some work is required to get it to work nicely and make it usable and stable).
If you have a minute, check it out. (It's a self-contained zipped Unity packages. This version uses Grids 1.6-and-a-bit DLL, and the cells use Unity sprites, so you will need Unity 4.3.)
- In the main scene there is a grid. The component on there exposes some properties, including the grid dimensions shape, its alignment, and so on.
- When you right-click on the PointyHexGridComponent, there is a BuildGrid at the bottom of the Context menu. When you click it, it builds the grid to the new specification. (It would be neat if that would just work automatically; and it can!)
- The cells have a drop-down box where you can select "Water", "Sand", "Grass". When you do, it automatically update the sprite. (In this version, it just changes to color, but actually changing the image is possible too).
- Everything is saved as part of your scene.
- You can implement two events that informs you when a cell is clicked. (1) On a component on the grid root, OnCellClicked(PointyHexPoint point), or (2) on a component your cell, OnCellClicked(). You can move the grid root around, and it still works, even during runtime.
It's not perfect.If you rebuild the grid, all your level data is lost. This can be overcome, I think, but I'd have to think about handling the cases where the grid size and shape changes.
Also, if you change level data at runtime, all is lost when you stop playing, as it is with everything. So I think if you want to build levels while playing the game, a feature that saves this is essential.
I forgot to make the grid accessible outside the PointyHexGridComponent (so ATM you cannot manipulate it through code without changing PointyHexGridComponent :/. A quick fix would just to make the grid variable public [for testing].)
---
A note about the approach of using a separate grid-building component:
The idea makes sense. However, I don't think it is necessary. The grid is now (almost) just a self-contained component that manages its own cells' creation; a bit like a dynamic mesh. The entire thing can be a black box; your game would access it just like any other component.
---
Your feedback has set me on a new thought path; I think the ideas may actually be useful for others too, like you said. I'm gonna play with it some more, make a few games, and see where it goes.
Thank you!
:D
Anyone interested to try out this new system can give it a go. We made a page here:
http://gamelogic.co.za/custom-editors-for-grids-and-cells/
and will be updating it as we figure out how it should work. We'd love any feedback!
This version now updates the grid dynamically when you edit the properties, and we implemented the Lights Out game as an example. (So "levels" are puzzles).
To give you an idea of how terse the code is using the visual editor, here is all the code for the entire game:
I'm interested to see what kind of beast my feedback (and that of others) has spawned : )
I'm back to experimenting with grids, but I'm trying to make a spherical world out of hex grids (rather than a flat world). Like this: http://vickijoel.org/hexplanet/ (as the Unity Asset Store doesn't have a tool to do this for me)
I'm not sure if you plan to use the Grids library or not. If you do, the advantages would mostly be that path-finding and other graph algorithms will already work.
The games we built on weird shapes are all topologically equivalent to flat grids that are wrapped in some way. Hence, to get them to work is just a question of generating a visual representation - neighbour relationships and coordination is already there.
The grid-type you linked to is different because of the pentagons. So you would not be able to take advantage of an existing grid for coordinates and neighbour relationships. To be able to take advantage of some of the grids syntax and algorithms, you will need to program a few entities that implement some standard interfaces. This is a fair amount of work: you will need to make your own point, grid, and map. (If you go this route, I can give you more specific information. Below follows a few things to think about whether you use Grids or roll out from scratch).
The first decision you need to make is probably what coordinate system to use (it's helpful in this case to think of coordinates as simple labels; cartesian coordinates are just fancy labels that can be exploited to represent structural information about points). I would probably use a simple integer labelling system, where you arbitrarily assign an integer to each cell. In which case knowing the coordinates of two cells tell you nothing about their relationship - this means structural information needs to be represented in your grid data structure.
Next, you should think about these things:
- how cells will be interacted with (clicking, arrows, drag-selecting)
- what type of algorithms you are likely to need (path finding, range-finding, line-of-sight, coherent noise)
- what geometric "concepts" your grid should support. Is there a concept of a line? A circle? A ring?
This will give you a checklist, which you can use to guide your implementation. Separating calculations for visual representation, and your actual logical container has many advantages. The tricky part of implementing the algorithm in the paper you linked to is keeping track of neighbor relationships while you recursively subdivide, and then constructing the right relationships for the dual grid from these.
I am not sure whether any of this is helpful to you at all. It is an interesting problem; I would like to spend some time with it, and see what I can come up with. I cannot promise a timeline though :--/
I was wondering, with the grid building with the shapes/unions etc have you fiddled with templating grid sections and then stitching them together either on the fly?
I'm also going to experiment tonight with saving and loading of these grids that I want to build from templates as I need to expand.
will give as detailed feedback as I can.
I'm not 100% sure what you mean with templates and stitching them together on the fly.
If you simply mean is it possible to make your own shapes, then yes, you can (very neatly as extension methods, where you have full access to the shape building tech). You can then use the the shape operators to stitch them together just like the built-in shapes. There is an example with the library (see the ShapeConstruction scene and accompanying scripts).
For a scenario with lots of levels with lots of different shapes, where you want to save the shape along with the grid contents, I would use another approach. I'd rather stick with rectangular shapes, and have a bool that says whether the cell is in the grid or not. You may even saperate this bool into another grid (check out grid.CloneStructure). You could even wrap these things neatly in your own grid, so that it grid.Contains and grid.GetNeightbors etc. work with your shape.
Something like this:
You can then use this grid with all the built in functions.
Let me know if I miss your point, or of I can clear anything up.
The basic idea rests on two principles:
- if you go around a major circle on a sphere, you end up where you started;
- you only see half of the the sphere at a time.
These two facts used together can be used to make something that looks like a sphere and feels like a sphere, but is in fact not.To see how this can be implemented requires a bit of a stretch of the imagination.
First, a flat hexagonal grid in a hexagonal shape can be wrapped along three axes (similar to the way a rectangle can be wrapped along two). Amit Patel has a neat interactive demonstration on his site:
http://www.redblobgames.com/grids/hexagons/#wraparound.
This will make up the logical structure of your grid. It's this wrapping that gives you the "going around > end up where you started" effect.
Second, you select a small piece from this to actually render. This part is a bit tricky, but I think still reasonable - it's basically just projecting a section of the grid onto a hemisphere. To enable free rotation, you will need to do just a little bit more than a hemisphere (about a cell extra in all directions).
Third, you need to turn the above rendering thing into a window of the grid, and enable scrolling. Similar to the way scrolling works in platformers, for instance. At first the scrolling needs to snap from cell to cell, and it will be constrained to the three axis of the hex grid.
Fourth, to simulate free scrolling (effectively rotation of the sphere along any axis), you need to break down the free rotation in components of scrolling along the axis, and a rotation about the center of the hemisphere through the axis facing the viewer. This is by far the trickiest part, and it may be quite difficult to derive the right equations. (I can't recall coming across a similar transformation before. It's also in this step where it's most likely that I miss something that makes the thing impossible).\
The scrolling will work a little bit like these GIFs:
http://www.math.ucr.edu/home/baez/golden.html
You will slightly rotate your just-a-bit-bigger-than-hemisphere, and once a certain threshold is reached, snap it back, and move all render data one cell in the opposite direction. (Render data is things such as the textures on the cells, for example).
----
This is clearly quite a technical challenge, and offer little play value above the hex and pent mix of the paper you linked to originally. It's also conceivable that players may be mystified, and the illusion does not work the way I imagine. (Although I doubt that; without making careful topological observations we cannot even tell if we are inside a torus or on a sphere if we can only see the floor (and ignore the curvature)).
There are a few technical advantages though:
Your cells will be totally vectorised (so you can say eastFromHere = here + PointyHexPoint.East).
You have a flat representation that is easy to serialise (you do not need a complicated graph structure).
It would be trivial to draw a minimap.
You can have all the geometric concepts of a normal hex grid, including lines (which will always be "big circles").
You can readily apply "flat" algorithms to your "sphere". For example, you could easily use perlin noise to drive procedural world generation (making land and water masses, for example).
----
Of course, everyone will also wonder how you did something that is impossible :P
This is the grid viewed from the correct angle, with the grid window projected to a sphere (it's actually a fake projection, it merely looks like a sphere). (Normally you would just not render the non-window parts, but I think it helps illustrate how the method works).
Here is the mesh from a different angle.
Six-tri hexes as opposed to 4-tri hexes? It's like you're not even trying, Herman! :P
Here is an interactive example (you need the Unity plugin to run it).
http://gamelogic.co.za/grids/example-algorithms/tiling-a-sphere-with-hexes/
@BlackShipsFilltheSky if you are interested in this solution with Grids, let me know, and I can see if I can get free rotation going. (If you even need it). The code is surprisingly simple, and (if you can live with the odd triangle extra here and there) fairly efficient.
Edit I put in more general rotation now. I will upload some code a bit later if you want to have a look.
Edit Here is the source and an updated demo (you can see properly what is happening by switching off the plane, and toggling to the side camera). http://gamelogic.co.za/grids/example-algorithms/tiling-a-sphere-with-hexes/
This is cool, though. You should include this as an example together with your package, when you do 'rotation' along more than just the vertical axis. Free panning would make this super cool, although strictly speaking it would work differently than if you were rotating an actual sphere, base on my understand of how you're doing this.
The free rotation is in now, it was actually very simple to add. The illusion works quite well, however, with the rotation the illusion's weakness becomes apparent.
(Can you spot it?)
As you say @Chippit, it works a bit differently from actual sphere rotation. (There are a few tricks I think that can be used to improve it; one is to use a better size base grid; that one was chosen somewhat arbitrarily.)
So on to what I did. So I have been eyeing different random generation algorithms and saw one that appealed to me on reddit recently that I figured would suit me perfectly for my game, so I took the time to build it up in grids. The algo is quite simple (I posted it into another thread) but I think there are probably things I am missing that could make it much quicker for me to manipulate data. I believe Herman gave a talk about LINQ for game dev? I'm sad that I missed it and would like to see how that can be applied to the grids library (you will see in the code below that I do a lot of looped code that could be simplified to a great extent through using LINQ).
My end result is this:
Ideally I would want to be able to generate example views of a specific generation algo in the editor, but I have no idea how (or if) this is actually possible in Unity. I would be able to write wrappings myself if someone can point me in the right direction to be honest. My current workflow is change code -> run -> pause -> change code. The visualization could be very useful I feel.
I also have difficulty understanding some of the orientations (and failed to figure out what to use to make a "square-ish" grid using hexes) and terminology, though admittedly I was a few glasses of wine each time I looked at the library, perhaps I missed something?
My favourite part so far is some of the graph-like functionality given out of the box. I am going to happily be using this in many projects to come, as was said, if I could use LINQ queries I could not work out how at this point in time.
My generation code looks like the following for anyone interested (this will be looked at again and changed when I am done implementing the mechanics I want to try out):
Perhaps I am missing some of the intention with some of the functions? I like the solution though and will be using the grids library a lot in the next few months on my projects.
Thanks for the feedback; we really appreciate it!
To answer some of your questions:
You can generate a grid in the editor, although there is a bit of trickery involved. Generating a grid from a cell prefab in the editor is as easy as moving the function to an editor function (I'll send you some code for this if you want to have a look). It's relatively straightforward to update the grid if a field value (such as grid size) change (the easiest is to destroy all the cells and recreate them).
But this is not enough. The grid data structure cannot be serialised*, and hence you will lose your cells' references in the grid when you run the game. A hack is to destroy the cells and recreate them when you run the game too. Solving it properly (and stably) is non-trivial; but it is exactly what we have been doing for the last few weeks. We are still experimenting to decide on the optimal workflow, but plan to have it in Grids 1.8 which is due end of March.
Our idea is to also make it easier to write your own editor components easily. Our working goal (perhaps I should say dream) is, to make it easy to roll out your own level editors for grid-type games. We will provide some defaults, but the power will lie in your ability to quickly mock up your own level editor. We don't know yet whether we will realise this goal/dream with the next release, but that is our guiding light :)
(* Mostly because the shape functions cannot be serialised, and they are part of the underlying grid data. We have also been investigating this.)
----
To get a square-like shape, use
I can't remember what the correct aspect ratio is for width to height to get a squarish shape (I can calculate it for you, but you should be able to find it experimentally quite quickly).
This is FatRectangle:
and ThinRectangle:
In general, you should not use constructors to create grids - always use the static functions (The shape functions, or the BeginShape().....EndShape() "shape builder" chains).
The constructors are merely provided for the lowest level of grid creation; the way they work is quite complicated.
There are three levels of grid creation: the lowest level through constructors, the next level through MakeShape provided in the shape op, and then the highest level through the "Shape Builder" chains. The static methods just wrap common cases of the last so that you don't have to say "BeginShape().Rectangle(width, height).EndShape(). Internally we only use the constructors to implement MakeShape :) The actual shape of the grid is also not guaranteed to stay the same for the constructors, because it depends on how we manage the underlying memory (arrays). For hex grids, they have been changed once already. As we adopt more sophisticated techniques to make it easier to make interesting grids in the future, they may well change again. (But I'm glad you pointed this out, we definitely need to put this in our docs).
----
The MS docs are quite easy to understand when it comes to LINQ; give them a read. The most useful methods are Where, Select, Any, First. Those alone will let your code shrink beyond belief.
Here are a few examples from your code:
If you write your own extension for selecting points randomly, like this...
...you can do the following type of replacement:
This pattern...
...can be replaced with...
...and so on :)
Your longer loops will benefit most, but it will take me a while to understand what you are doing properly. But once you are used to LINQ a bit you should have no trouble doing it yourself :)
----
Hope the above helps you a bit. Thanks again for the feedback!