Read-Only Interface?

My current programming concerns: if something is going to affect the data members of a cube object, the cube class needs to be doing the changes. If something is going to be affecting the data members of a tile object (faces of a cube), the tile class needs to be doing the changes, etc… That’s basic encapsulation rules for OOP.

That said, there are changes that can only occur based on information gathered from multiple objects of the same type simultaneously (if we’re moving a cube, all tile objects attached to it need to be moved, obviously), so essentially, as an example, while the data members of tile objects are changed by an internal function in the tile class like TranslateVertices, that function should only ever be called by a cube class function TranslateCube, which should only ever been called by a map class function TranslateCubes (because moving one cube may collide it with another cube, or move it into a restricted area, for instance).

Keeping that in mind, I’m seriously considering using an interface for my cube and tile objects that would be read-only, and only ever using the editable version when in the scope directly above it. I can’t have the GUI scripts accidentally calling any tile or cube object functions directly, except to get data from them, because it would bypass all sorts of checks and balances the classes responsible for the collections of those objects should be making, if that makes sense.

Having to go through the cube class and manually cast most of the tile object references to “editable” sounds like a pain (and doing the same for cube objects in the map class), but it seems like something that needs to be done.

Any thoughts or better ideas?

One of the fun things you can do when you use an indexing system for “sides of a cube” based on Vector3 directions:

int negIndex = CubeData.DirectionToIndex(-1*(CubeData.IndexToDirection(posIndex)));

Both DirectionToIndex and IndexToDirection are accessors that use an array of Vector3s to determine indices/vector3s for the cube sides. Essentially, I’m iterating over a list of lists, using the index of the side that I’m currently accessing to grab the direction it represents (a Vector3 like Vector3.up (which stands for 0,1,0)), multiplying it by -1 to get the opposite (Vector3.down (which stands for 0,-1,0)), and then getting the index that corresponds to that Vector3 instead.

Original Array Index -> Vector3 -> Opposite Vector3 -> Opposite Array Index.

misk

Unity3D C# Function Logic

*Accidentally posted via the wrong account at first*

Figured I’d give you guys an idea of how I usually do pseudo-code (or, more appropriately in this case, program/function logic). I decided to go through and revamp the “hide the geometry” code for my map editor, which basically just cuts out a lot of the rendering needed for triangles that aren’t actually needing to be displayed because they have their entire areas covered by other geometry.

First, please note that while the editor is designed around Y values being anything you want, the X and Z coordinates use a simple unit grid so that cubes essentially snap together with other cubes. For that reason, there’s a lot of X and Z comparing that I’ve skipped or built into the “grab neighbors” function (which I haven’t included the logic for here).

This function logic is going to be used to compare an origin cube’s faces with the opposite faces of its neighbors, which will have at least SOME overlapping geometry or they wouldn’t have been pulled in as “neighbors”. Cube faces are numbered 0 for the “top”, 1-4 for the “sides” (clockwise starting from the top), and 5 for the “bottom”. Vertices of those faces are numbered 0-3 moving clockwise from the upper-left, so essentially it’s “upper-left”, “upper-right”, “bottom-right”, and “bottom-left”. The direction the face is, well, facing, is irrelevant, so comparing the “top” side to the “bottom” side, the vertices numbers will match up perfectly in position, despite facing opposite directions (zero to zero, one to one, etc…).

My “grab neighbors” function will filter through the cubes in close physical proximity to the cube I’m working with right now, and I separate them into lists based on which side of my cube they’re attached to (using Vector3.direction as shown below). The numbers to the left show which sides I need to compare based on the attachment direction, with the cube I started with always being on the left.

-> Make all faces of the origin visible
-> Iterate through lists of “neighbors” matching the below sides
0<->5 (0, 1, 0) Vector3.up
1<->3 (0, 0, 1) Vector3.forward
2<->4 (1, 0, 0) Vector3.right
3<->1 (0, 0, -1) Vector3.back
4<->2 (-1, 0, 0) Vector3.left
5<->0 (0, -1, 0) Vector3.down

-> Make a “list” of vertices that we may use later, if it gets to that point
-> If all four points match perfectly, hide the face
-> For 0<->5 and 5<->0, if Z doesn’t match for all points in both, exit
-> If either has a missing triangle, exit (a partially-hidden face for either the origin or the comparer means there’s no way for a completely-hidden face to exist for either).

* If it gets to this point, there are SOME overlapping areas at least, but not perfectly, that means we need to compare multiple sections to see if all of the overlapping areas will, together, cover the entire area. Note that with the “match perfectly” and “don’t match perfectly” criteria above, the 0<->5 and 5<->0 comparisons are now finished.

-> If origin is higher for 0<->0, add comparer’s 0 and 1 points to list
-> If origin is lower for 3<->3, add comparer’s 3 and 2 points to list

^ Do this for all “neighbors” that have the same side-relationship

-> Remove all entries that are in the list twice
-> If the list is now empty, hide the face
-> Exit

Be Aware:

Unity’s Script Reference and MonoDevelop’s syntax-suggestions both tell you that creating a Rect is done with Left, Top, Width, Height, but they’re both lying. By “top”, what they really mean is “bottom”. They explain this as being because the Y-coordinates start from the top and go down, but that’s just silly. Even more importantly, if Rect.contains(Input.mousePosition) is supposed to be so common, then why does the coordinate system for the mouse position have the Y coordinate starting from the bottom, if the Rect’s coordinate system starts from the top? It took me 20 minutes to figure out why my “build a rect around the mouse position on mouse-click” function wasn’t working properly. I would say that next time I’m going to use the Rect.MinMaxRect function instead, but that one has the Y coordinates backwards too. Bah!

Small Update:

Made it so that clicking and dragging the cursor on the screen moves the camera but has no effect at all on selected cubes (it won’t select or deselect anything), and won’t create or delete cubes even if the “place cube” or “remove cube” functions are active. The program now uses a system of creating a small rectangle (about 10 pixels in height and width) around the point where a click occur, and unless the click is released within that space, it takes no action at all other than camera movement. That also creates a little lee-way in quick-selecting cubes, so that the click doesn’t have to be perfectly steady to select/deselect/place/remove anything.

I’m in the process of creating semi-visible tiles that will display the boundaries of the build-area-restrictions. You can already choose how far in any of the three positive directions from the map’s origin point that you can place and move cubes, but something visible to go by would be nice, I think. I’m going to be using a pale red half-visible texture for the sides of that space (only updated when cubes are moved or added/removed), and the directions in which there are no limitations (as in the user wants to be able to build “up” infinitely), there will be no tile on that side (and tiles on the sides would end at the current “tallest point” of all of the cubes in the map).

I’m still not 100% sure if I should be doing all of this based on the origin of the map instead of allowing the area restriction to be defined manually in all six directions, but the manual option would be pretty complex for the user (minX, maxX, minY, maxY, minZ, maxZ instead of just maxX, maxY, maxZ as it is now).

They never really told me that the majority of my time would be spent thinking, not really programming. Thirty minutes of asking myself how to best implement a new idea, twenty minutes spent actually writing the code. Maybe there will be less thinking and more coding when I’ve gotten more proficient at the language, or more likely when I’ve a better understanding of program logic, but for now that pretty much sums up my time.

That said, making a mistake or not taking variables into account when thinking up the implementation of a concept means hours can be wasted coding something that won’t actually be used later on. Still, maybe it would be better experience if I coded first and asked questions later- “learn from your mistakes”- or maybe the way that I’m doing it is the best approach- “learn not to make mistakes in the first place” (though it still happens, and often enough to wonder if that thirty minutes of pondering makes any difference at all)- I’m not really sure. I do think that my current approach is probably more dangerous in the “burning yourself out on a project” arena though (as is evident by my recent hiatus), and in fact is thinking up all of the possible future additions a good idea on a project, when those additions aren’t a part of the task at hand and may never come into play? Any thoughts?

keepcalmandprogram: True enough, psuedocode definitely helps, but when you’re able to think up like five different ways of doing something, all with their own benefits and drawbacks, it requires a little thinking on where you may be wanting the project to go sometime in the future (or where the client might) to decide which of those methods might be best. Should I be trying to find a way to do cube movement that’s entirely limited to the cube-scope of the project, or should I let the map-level code handle it since it can already see all of the cubes easily? How much functionality should be built into the default object class structures and how much should be implementational?

It definitely FEELS like I’m over-thinking simple problems, and slows me down a lot, but it also feels like going in the wrong direction might lead to a lot of additional rewrites in the future. When you’re creating a core system that other things are going to be built off of, a misstep early on could be pretty painful later. I feel like I need to read a book not about programming, but about the development process in general and things to keep in mind in project management or something. Or maybe this is just one of those things being clever can’t cover for, and I just need a lot more programming experience.

The Turning Point

The number of lines of code I’ve written now is overwhelming for a program that only serves a single function (building maps). I must admit, I’m just a bit intimidated by my own creation at this point. I’ve been looking into ways of better managing things, making them a bit less confusing to look through and work with, and after several programming projects in C# outside of Unity this past month (and cooling off by spending some time with my hobbies, not working 24/7 on my various jobs as I was for that first month), I think I can get a better handle on things going forward.

I wasn’t an expert in C# to start with, I had never used Unity before diving into this project, and I was a bit too ambitious with my starting goals. That said, I think this project is worth pursuing and will continue to work on it, make it cheaply available when I’m done, and then move on to the next step, as promised.

There will be a couple of changes.

I’m only going to make an update once a week from now on- trying to find things that can be quickly added or updated to make content for a new blog post is quite ridiculous and has left me with a lot of little problems scattered over the whole project, which are time-consuming to fix because they’re time-consuming to locate- no big surprise given how much code I have to sift through.

Next, I’m cutting down on the code commenting and only doing very generalized comments of entire sections of code rather than trying to explain every other line to make it easy to follow for complete amateurs. I went overboard before- it was my own fault obviously (as this is the first large-scale programming project I’m handling entirely on my own), but the comments are conversely getting in the way of legibility rather than helping in any way, so they’re mostly being cut.

Third, the specific usage of the program that I first had in mind is being prioritized. I was going to make this as generalized a level editor as possible- make it usable not only for top-down fixed-camera-angle grid-based levels as I was going to use it for myself, but also make it usable for side-scrolling and other level types as well. I will still try to make it usable for those things, if possible, but not until much later.

The hiatus is over, and I’m back at work on the project. You should expect an update from me sometime later this week, hopefully with some new screenshots and maybe a youtube video demonstration of all of the new features (assuming that I can fix all of the little bugs by then). Given my new goals and the current state of the program, progress is estimated to be at about 70% for the version 1.0 release. Wish me luck!

Programmer’s Log (Moonlight) Week 4, Day 1

Simplified the GUI script a bit- moved some things around and deleted a few functions that can be run in-line easily enough (since I now know I won’t need to access them from many locations in the code). Also added the last few options for the main-menu (it’s 100%!!!), so now that part of the task (the biggest part by far) is complete. I’ve gone back and edited the “1.0 release goals” post to include the recent additions.

Unfortunately, I’ve now run into a bug where the background map layers (which are normally 75% transparent) are becoming opaque when a cube from the currently selected map is being moved through them. I honestly have no idea how/why this is happening, since the maps shouldn’t be interacting with each-other AT ALL in the script, so I fear it may be something more deeply embedded in the Unity system and not something I did myself (at least not directly). It’ll take a lot of experimentation and research to fix most likely, so tomorrow that’ll be my main goal.

I did a bit of hunting around for free high-resolution tiling graphics that can be included in the release with no copyright issues, and in discussions with a few of the artists that had ambiguous licensing details on their websites. I’ve also looked around for simplified one-draw-call GUI-creation assets that can be used in commercial open-source projects, but haven’t found any that both look promising and cost less than a couple hundred dollars. I’ll still use one of the more expensive ones I think, but later on, once the 1.0 release is finished and the money earned from it pays for its own architecture improvements.

Now all I have to do is fix this annoying transparency bug and then move on to the other two menus (much smaller and easier to manage than the main menu, by far), and 1.0 will be reached.

Yeah, it&#8217;s plain white, but it&#8217;s also a good example of what the editor is currently capable of. The edit functions are now entirely complete for 1.0 release, at least internally, but I still need to write some of the GUI menus, which is by and far the most annoying aspect of this project. I could really use a GUI designer if anyone&#8217;s interested. Just shoot an email to ParnassianStudios@gmail.com if you are.

Yeah, it’s plain white, but it’s also a good example of what the editor is currently capable of. The edit functions are now entirely complete for 1.0 release, at least internally, but I still need to write some of the GUI menus, which is by and far the most annoying aspect of this project. I could really use a GUI designer if anyone’s interested. Just shoot an email to ParnassianStudios@gmail.com if you are.

Programmer’s Log (Moonlight) - Week 3, Day 7

I’ve now implemented the “Add Cube” and “Remove Cube” functions. Although it seemed a bit awkward in concept, I’ve made both of these functions toggles rather than buttons, and in practice it works FAR better this way. To create cubes, all you have to do is flip the toggle and then start clicking on an existing map, and based on which side of a cube you’ve clicked, it’ll create a new cube next to the old one. I had to make some tricky normal-detection for the box colliders and I’ve yet to implement it for the mesh-collider rendering method, but it works amazingly well (surprisingly so). Deleting cubes works the same way- just click it and it’ll be destroyed. Obviously this is a dangerous tool to use since there currently isn’t any sort of an “undo” option, but honestly I think ease of use is far more important than safety in a program where it’s quite easy to recreate accidentally-deleted-cubes anyways.

A function to move the map in its entirety (consider it a base offset, if you will) has also been added, as has one for editing existing map names. Added a logic list to the cubes so that it’ll be easy to detect and utilize logic in-game that applies to specific cubes. This includes a “type” that can be used to effect movement speeds or w/e you need, with additional flags for whether it’s liquid, what kind of liquid (water, lava, etc…), and whether it’s a damage-type block or trapped (the “Trap” code is simply an object reference list, so some sort of trap-type class objects would have to be made and added to the list later).

I’ve been preparing for something a little experimental the last few days (why I haven’t been posting updates), and depending on the result it could either simplify the rendering process dramatically or simply waste a lot of time and effort. I’ve been saving the experiment for when things are as far along in the programming process as possible, but not so far that the reliance on the current method increases. Now seems as good a time as any, so I’ll update on the progress later today.

UPDATE: The experiment worked and I was able to remove several internal functions from the design and simplify the rendering process a bit. I’ve also added the map restriction functions (not allowing cubes to move outside of a set area), with zero being a “partially unrestricted” value that allows infinite movement in any one or two directions if desired. If, when setting the restriction, there are cubes that are already set outside of the area specified, a confirmation window will appear to keep any serious damage from occurring unintentionally.

I’ve also added the “reset map” function that removes the current map and rebuilds it using the original values- again this will require passing a confirmation window. There are only two functions left that I want to build before moving on to the secondary menus- the “rotating texture” function and a smoothing function that auto-selects slants and corners for all cubes in the current map based on their neighbors and neighbors-of-neighbors.