So I created this window editor in WPF that helps me create Forms quickly. Now, one feature I've worked on was create a guideline tool. At its core it's just creates lines to help keep my UI elements organized on the screen. I will show you an example. The long black lines are the guidelines I spoke about earlier.
Now, I noticed that in a lot of art programs (i.e Photoshop) and popular IDEs that implement Forms that they have a "snap-to" feature where a UI element will snap to a line UI or to another UI element in order to maintain alignment. Something like this:
I already have the guidelines showing up in my editor. Now, what I would like help understanding is, how would I go about implementing the "snap to" feature? I'n not asking for code, just a breakdown (a visual breakdown will be most welcomed).
These are my questions:
How does an object know if one of its edges (top, bottom, left, right) touched a line?
How would I know how to unsnap the UI element if the user keeps moving the mouse past the guideline?
If I have (say) 10 lines how do I make sure that the object attaches to the nearest line(s)?
UPDATE
When an object moves or is resized, keep track of its actual size/location relative to the mouse, and separately keep track of a snapped version of the same information. If a given actual edge is within some arbitrary distance of a line -- say 4 pixels (arbitrary WPF units, really). If it's within that distance, set it to the value for the line it's close to. You still have the actual mouse-relative values as well, so you know to unsnap it if the the user keeps on dragging it and it leaves that 4-unit zone.
When an object is being resized, at most two edges of the bounding box will be changing position (assuming you can drag corners as well as edges). When you're moving an object, all four edges of the bounding box will move.
So you need to keep track of which edges are moving, and only do snap-line proximity testing on those edges. When you're moving an object, snapping the left or top edge to a line is easy. That's just the position of the object. But if you snap the right or top edge to a line, you're setting
snappedPos.X = nearestVerticalSnapLine.X - draggedObject.Width;
or
snappedPos.Y = nearestHorizontalSnapLine.Y - draggedObject.Height;
You may also have cases where opposite edges will both be in proximity to lines: Say you're dragging a seven-unit square across a ten-unit grid. When it's inside a grid box, all four sides will be in proximity to a grid line. Which wins? The closer one.
Locating the snap lines is easy -- %.
Related
I'm making what is essentially a board game within Unity 2D. The player will be able to move their pieces along a grid (see below). The larger circular sprites are the pieces, which the player can click on, then click a gridPoint (the small squares) to move to it.
I've created the grid by using empty gameobjects (I've rendered a sprite on them for visual help) at each intersection. These are the points where players can move between. The distance between the points varies, though the horizontal distance is always 1.
The full functionality would be...
A player clicks on a piece,
A preview area of where the piece can move to is shown.
Player clicks on a valid grid point where the piece should move to.
Grid piece moves to new point.
First of all, have I created this in the right way? I need the grid to be accurate, as it will be populated with an accurate sky map. Currently this grid is accurate.
Assuming this is the right way of doing it, how do I, when a piece is selected, work out which grid points are within range? Say a piece can move 4 spaces, then any space 4 grid points away from origin (horizontally, vertically and diagonally) can be moved to. I'd also need to count how many spaces the piece has moved.
I also need to make the piece travel from it's original position, to the new grid point, via grid points using the shortest route.
Any help is appreciated.
OK, there are many solution for this, but let's keep it simple!!
simple overview of your solution step!!
If your grid is fixes size(i.e fix height and width unity length), then put custom placeholder (empty gameobject)in intersection point
detect the swipe detection(assuming you working with this mechanism) from current tapping piece to direction.
using any tween library(i suggest DoTween library from unity asset store, it's free and absolutely amazing.)move your piece to that placeholder.
Now bit more in depth Understanding!!
please refer the below reference.
initial condition of any type of grid
after creating the grid, you can put empty gameobject as an placeholder in between grid(you can make it invisible- i.e make it alpha 0 of image property!)
placeholder in between gap of grid
you can make you piece(player) child of any of these placeholder.
you will detect the swipe or even tap mechanism and check weather in what ever direction you swapping or in which invisible placeholder you tapping, has any child??
if yes, that means that placeholder is already occupied with other piece(player). so no logic to move your current piece. so ignore the swipe.
if no, that means placeholder is empty, so its valid move.
using any tween library, from current placeholder position to desired placeholder, move your piece(player).
after reaching to desired placeholder, make that piece the child of that desired placeholder(using setparent(desiredplaceholder.gameobject.transform.position) kinda code)
and you done!!
hope you find this helpful!!
I am currently working on a game, and i've run into the following problem:
I want to draw some results as a graph on top of my Canvas and so far i've found out that my Canvas needs to be in Screenspace-Camera for this to work, as the LineRenderer is a 3D-Object and will be covered by Screenspace-Overlay otherwise.
And i've actually got it to work with this, looks like the following:
But the problem i've encountered is that if i increase the screen size, e.g. by stretching the GameView or maximizing it, the line disappears, even though it has a negative z compared to all my UI elements and therefore appears in front of them in the EditorView:
If i try to fix this by applying a greater negative z-Value relative to the screen size the lines get distorted, as they are getting closer and closer to the camera, and changing their alignment from view to z-Axis didn't help either.
What makes this even more confusing is that this happen to lines that are drawn lower (smaller y-value) first, meaning a line at the bottom of my graph disappears earlier. I really don't know why this is happening. Any help would be appreciated.
For 3D objects mixed with UI elements I recommend using a separate camera with greater depth than the camera drawing standard ui elements. This way your 3D objects will always be rendered on top of the UI elements and you wont have to worry about Z positions.
I need to arrange tooltips for points that are located on a complex 2D shape.
The tooltips have different sizes
They must not obscure the shape itself
The lines that connect the tooltip to the points should not cross one each other.
The tooltip should be as mush closer to the point it belongs to.
I've tried several searches in google but nothing was close enough to what I need.
You've asked quite a doozy. I haven't personally worked on something like this, another SO member will likely be able to give you a complete solution. However, here are some points to consider when finding your solution.
1. The tooltips have different sizes
You will need a way determining this independently of your shape location algorythm. Performing the re-size as part of step 2 would make things much more complicated and may result in inconsistent behavior. So firstly, look into generating the dimensions of your tooltips.
2. They must not obscure the shape itself
In principle, you want a solution where the tooltip is not 'colliding' 'inside' the complex shape. Looking up '2d shape collision detection' would help here. You will need to know the dimensions of the shape of interest. You can't use a picture of a shape (unless you use a map of some sort). Most algorythms will require the following information for shapes containing concave points:
The points (2d vectors) that make up the complex shape
The points from which tooltips "spawn"
The tooltip dimensions (see point 1)
3. The lines that that connect the tooltip to a point should not cross eachover
This makes the problem significantly more complicated because it implies that multiple tooltips generated by #2 may be visible at the same time which will introduce alot of complexity.
Now you have N tooltips which need N locations occupying different areas which may not overlap, collide with the complex shape, or, when a line is drawn from them to point x, does not intersect any other lines from the remaining (N-1) shapes. It means the algorthm must be performed on the entire set and find the correct locations for all of them, a kind of three body problem.
4. The tooltip must be as close as possible to its associated point
This adds another small caveat which, because of stipulations set in #3 may not be able to be met 'ideally' (what if two shapes are colliding near two close points, which one 'wins out'?).
Again, these are some points to consider as you generate a solution. The result is that you have mathematically 'ideal' locations for your tooltips. However, with these considerations in mind, you may want to look into where realistic concessions may be made. If it's for a design project where the complex shape is unlikely to change then semimanual solutions may be better. If it's for a complex piece of software that will require automatically generated locations you may be able to redesign the UI to give the user the necessary feedback without such a complex solution.
A heuristic:
Compute the centroid of the points.
Place a circle, centered at the centroid, fully enclosing the shape.
Find the places on the circle, where a line form the center through each point
intersects the circle, i.e. project the points on the the circle.
These locations would serve as corners for the tooltip, depending on the which quadrant the point on the circle is, relative to the circle center.
You may increase the circle radius a bit, for aesthetic purposes :)
If I'm not mistaken, this should cover requirements (1), (2) and (3). For (4) you can refine the initial place by moving the tooltip towards the sphere center and checking for intersection with the shape, e.g. using binary search.
Something like this:
There are problems with this approach, of course, but nevertheless it may turn out to be a good starting point for refinement :)
So I am working on a Risk type game in XNA/C#. I have a map, similar this one, and I need to be able to detect mouseovers on each territory (number). If these areas were squares, it would be easy, as they could each be represented by a rectangle. However, they are different size polygons. Is there a polygon shape that behaves similar to a square? If there isn't, how would I go about doing this?
I sugest this:attach color to each number, recreate your picture in these colors: every shape will be in its particular color. Dont draw it onscreen, use it only as reference map. And when the user clicks or moves mouse over your original map, you just simply project mouse coordinates into the color map, check the color of pixel laying under the mouse and because you have each color associated to number of territory...
This is not c# specific (as I've never written anything in the language, so no idea of what apis there are), though there are 2 algorithms that come to mind for detecting if a point is inside a polygon (which can be used to detect if a mouse point is over another polygon/map shape).
One is based on raycasting, where you cast a ray in 1 direction from the (mouse) point to "infinity" (edge of the board in this case) and count the number of times it crosses the polygon's edges. If it is odd, then the point is inside the polygon, if it is even, then the point is outside of the polygon.
A wiki link to it: http://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm
The other algorithm that comes to mind works only for triangles I think but it can be more simple to implement I think (taking a quick glance at your shapes, I think they can easily be broken down into triangles and some are already triangles). It is to do with checking if the point is on the same (internal) "side" of all the edges in the triangle. To find out what "side" a point is on vs an edge, you'd take create 2 vectors, the first vector would be the edge itself (made up of 2 points) and the other vector would be the first point of that edge to the input point, then calculate the cross product of those 2 vectors. The result will be negative or positive, which can be used to determine the "direction".
A link to it: http://www.blackpawn.com/texts/pointinpoly/default.html
(On that page is another algorithm that can also work for triangles)
Hit testing on a polygon is not so difficult to do in real time. You could use a KD-Tree for optimisation if the map is huge. Otherwise find a simple Contains method for a polygon and use that. I have one on another computer. Let me know if you'd like it.
I am trying to write a card game, where a player is able to stack cards. E.g. Ace, Two, Three.
I would like to visualize a stack of cards, where the Ace card is partially covered by the Two card, and the Two card is partially covered by the Three card. The Three card is completely visible.
Easy, I thought. I make a user control where I add my cards: Controls.Add(ace); Controls.Add(two); etc.
Then I need something that is able to lay-out my Controls, so I wrote my custom LayoutEngine (derives from LayoutEngine). My first test does nothing more then shift the control 50 pixels.
After running the solution I noticed that the Z-ordering was wrong. Instead of the Three card being on top, the Ace card was on top looking like this:
Ace Card > Two card > Three card where:
Ace Card is on top
Two Card is under the Ace Card
Three Card is under the Two Card.
So I started looking for a way to change the Z order in WinForms and found out that it is simply "not available". Like.. Huh?!
The alternative (provided by MS) is that the Z order can be altered, by setting the ChildIndex for the Controls. Jikes, that means that poking around in a list, change the behaviour of my application. Way to go MS...
Anyway, I tried all kind of things, but it seems impossible to write a layout engine that does the trick.
I've google-d all day, and found nothing useful. I am no GUI expert, so I run stuck on this lame issue. Who can help me out?
Much appreciated!
Bas
Your best bet is to avoid the use of controls entirely. They will A) result in poor(er) performance and B) complicate hit testing/drawing.
Simply create objects to represent the state of the table (I use a CardContainer object) and use Graphics.DrawImage to draw all of the cards where they lie during the paint event. You can use a single control for the entire table if you need to also add other UI elements.
This will also make animating card movement simpler should you decide to add animation.
Updated
I meant to expand this answer but was called away and simply posted what I had. Here are some details you may find useful. I created a "solitaire game engine". The engine hosts one solitaire game at a time (klondike, spider, strategy, etc.). It tracks statistics for each game and allows both playing and editing of the individual games. The games are IronPython scripts which makes adding new games relatively easy.
My CardContainer is an object that holds zero or more cards.
It has a LieDirection (None, Up, Down, Left, Right) which determains how its cards are laid out.
It has a MaximumDepth that clamps the number of cards drawn in the LieDirection. This is handy for games like Klondike where you only want to show the top 3 cards of the waste.
It has properties for spacing the cards. There are separate spacing values for cards that are face up and face down. It can auto-pack cards into an area defined by MaximumLength. And it has an 'extra pad' value, one for each card--whether there is a card at that index or not. The latter is used during a simulated mouse hover to 'uncover' the card pointed to so that the user can clearly see a card that might be obscured by cards on top of it. This is accomplished by setting the 'extra pad' of the card on top of the hover card. This could have been simplified by having a "hover card" and "hover spacing" property, but having extra padding per-card allows for odd kinds of solitaire games that highlight a particular 'row' in the tableau piles with spacing.
It has a HitTest method to return a Card from a given X,Y location.
All of that means that the Card object has no notion of where it is drawn on the table. I have a complex animation system and so a card's location ultimately comes from the animation engine. If a card is not currently animating, the animation system gets its location from its container.
Note that the card's location referred to above is strictly for drawing. All cards are always attached to exactly one CardContainer and are simply moved from one to another. There is one 'special' container called the Deck which initially contains every card. It is positioned off of the table initially. A container has a Visible property. Animations play only if moving a card from a Visible container to another Visible container. This allows you to move cards around without animation when necessary and cards can "fly out" to/from containers positioned off the table.
The engine also has a rudamentary layout system for positioning CardContainers relative to each other. One very handy thing I did was to use a card-size-relative coordinate system. The 'width' of the table is exactly 11 card widths. No matter how big the user sizes the table, the width is always 11 card widths. This means that the card sizes (as viewed by the user) grow and shrink. The height is variable, but is determained by a fixed card-sized ratio (determained from the card bitmaps). If you give a CardContainer an X value of 1.0, that means it will be located one card-width from the left of the table. The values are floating points so you can specify 1/2 a card-width with 0.5. This makes it very easy to position elements in the script without having to worry about screen coordinates. No matter how the user alters the size of the screen, your game will be laid out exactly the same way.
The engine also has unlimited undo and redo. This means that not only do card moves (from one container to another) have to be recorded, but all property changes are recorded as well (both card and container properties). Undo and redo can be difficult to implement if not planned for from the start. The scripts have access to a Game.LogVariableChange method so that they can alter the value of a global variable through the recording mechanism. This is necessary for something like Klondike's "three redeals" feature. The script has to store the number of redeals used, but if the user undid a redeal, that variable's value change has to be undone too.
This works very well for Solitaire, but could work for just about any kind of card game. Obviously you don't have to go and implement all of this your first time out. I present the information just to give you some ideas.