I have a 2D top-down 45 degree game like pokemon or Zelda. Since the y value of an object determines it's depth, objects need to be drawn in order of their y value. So when your standing behind a tree for example, the tree is drawn on top of your player to look like you are standing behind the tree.
My current design would be to draw a row of tiles, and then draw any players standing on that row, then draw the next row, and then draw any players standing on that. This way any tile that has a higher y value than the player is drawn in front of them to simulate depth.
However, my players are currently a std::vector of objects that is simply iterated and drawn after all the tiles are drawn. For my method to work, I would have to either iterate the vector for every row of tiles, and only render if they are on the current row, OR sort every player by y value somehow each frame. Both these methods seem quite CPU intensive, and maybe I am over thinking it and there is a simpler way of simulating depth in this type of game.
Edit:
This game is an MMORPG type game, so there could potentially be many players/NPC's walking around which is why I need a very efficient method.
And ideas or comments would be appreciated!
Thanks
You could use std::set or std::map instead of vector to keep your objects in sorted order. Unfortunately you wouldn't be able to simply modify their position, you would have to remove/insert each time you needed to change the y coordinate.
(Disgregard my original suggestion, if you read it; it was daft.)
As far as I can tell, you basically have to iterate over a sorted container each time you render a frame; there will be a computational penalty for this, and having to do a copy and sort each time will not be that bad (O(N log N) sorting time, I'd guess).
A clever data structure might help you here; an array containing a vector of game objects as each element, for example. Each element of the array represents a row of your tiled grid, and you iterate over your vector of objects and bin them into your depth buffer array (which will take approximately O(N) time). Then just iterate over the vector representing each row and draw each object in turn, again O(N).
There are probably cleverer z-buffering techniques, but I'll leave those as an exercise for the reader.
As long as you aren't also attempting to sort your players according to other criteria then you can get away with just sorting your players by y-coordinate every time you want to iterate through them. As long as you use a sort that runs in linear time when the input is mostly sorted then you will probably not even incur O(n log n) time for this step. I'm making the assumption here that your set of players changes slowly and that their y-coordinates will also change slowly. If this is the case then every time you need to sort the vector it will already be mostly-sorted, and something like Smooth sort or Tim sort will run in linear time.
For c++ it looks like you can find an implementation of Tim sort here.
If you have space, another option would be to create an array of lists of players, with the index of the array being the row number, and the array containing a collection of the players in that row.
As I mentioned, this will require a bit of extra memory, and some bookeeping every time a player moves to a different row, but then drawing is simply a matter of iterating through the rows, and drawing the players that are present in that row.
Related
I'm programming my first game and I have one last problem to solve. I need an algorithm to check if I can move a chosen ball to a chosen place.
Look at this picture:
The rule is, if I picked up the blue ball on the white background (in the very middle) I can move it to all the green spaces and I can't move it to the purple ones, cause they are sort of fenced by other balls. I naturally can't move it to the places taken by other balls. The ball can only move up, down, left and right.
Now I am aware that there is two already existing algorithms: A* and Dijkstra's algorithm that might be helpful, but they seem too complex for what I need (both using vectors or stuff that I weren't taught yet, I'm quite new to programming and this is my semester project). I don't need to find the shortest way, I just need to know whether the chosen destination place is fenced by other balls or not.
My board in the game is 9x9 array simply filled with '/' if it's an empty place or one of the 7 letters if it's taken.
Is there a way I can code the algorithm in a simple way?
[I went for the flood fill and it works just fine, thank you for all your help and if someone has a similar problem - I recommend using flood fill, it's really simple and quick]
I suggest using Flood fill algorithm:
Flood fill, also called seed fill, is an algorithm that determines the
area connected to a given node in a multi-dimensional array. It is
used in the "bucket" fill tool of paint programs to fill connected,
similarly-colored areas with a different color, and in games such as
Go and Minesweeper for determining which pieces are cleared. When
applied on an image to fill a particular bounded area with color, it
is also known as boundary fill.
In terms of complexity time, this algorithm will be equals the recursive one: O(N×M), where N and M are the dimensions of the input matrix. The key idea is that in both algorithms each node is processed at most once.
In this link you can find a guide to the implementation of the algorithm.
More specifically, as Martin Bonner suggested, there are some key concepts for the implementation:
Mark all empty cells as unknown (all full cells are unreachable)
Add the source cell to a set of routable cells
While the set is not empty:
pop an element from the set;
mark all adjacent unknown cells as "reachable" and add them to the set
All remaining unknown cells are unreachable.
PS: You may want to read Flood fill vs DFS.
You can do this very simply using the BFS(Breadth First Search) algorithm.
For this you need to study the Graph data structure. Its pretty simple to implement, once you understand it.
Key Idea
Your cells will act as vertices, whereas the edges will tell whether or not you will be able to move from one cell to another.
Once you have implemented you graph using an adjacency list or adjacency matrix representation, you are good to go and use the BFS algorithm to do what you are trying to do.
In my SFML bomberman clone I have a tilemap that consists of tiles.
Tiles can overlap, so those tiles that are farther down will be drawn over those tiles farther up. The same goes for all other entities like the player.
In order to draw all entities in the correct order, I thought about giving each entity some sort of z-coordinate (entities whose z-coord is lower will be drawn first).
My plan was to have one vector with ALL entities (tiles, player, bombs, power-ups, etc.) and whenever an element is added, the vector's elements are sorted from lowest to highest z-coord so they are drawn in the correct order.
My idea was to assign the following z-coords to the entities:
0: tiles in the 1st row
2: tiles in the 2nd row
4: tiles in the 3rd row
etc.
Entities that are for example on the 1st row of tiles will have a coord of 1. Those on the 2nd row will have a coord of 3, etc.
Does using a std::vector make sense for this? Maybe a list, or a map (z would be the key)? I'm struggling to find the best and easiest-to-use container for this.
I know this post lacks code, but I'm really lost and would be so grateful if someone could give me some hints.
Actually, you don't need vector for static tiles.
You can just create a normal 2D array of tiles.
It's faster and you don't need to use Z-buffer:Instead, you should just write for loop in a such way that tiles are rendered from top to bottom.
I have a collection of object with a position (x, y)
These objects randomly move
Could have thousands of it
At any moment I would have the list of object in a (constant) radius RAD from a position POS.
Edit - Context : It's for a gameserver, which would (utopically) have thousands of players. When a player moves/[makes an action], I want to send the update to others players in the radius.
The easy way, every time I need the list :
near_objects;
foreach( objects o ) {
if( o.distance( POS ) < RAD )
near_objects.add( o )
}
I guess there are better/faster methods, but I don't know what to search.
Here are two suggestions.
Usually you compute distance using sqrt( (a.x-b.x)^2 + (a.y-b.y)^2 ) and the expensive part is computing sqrt(), if you compute RAD^2 once outside the loop and compare it to the inside of the sqrt() you can avoid computing sqrt() in the loop.
If most of the objects are far away, you can eliminate them by using
if( abs(a.x-b.x) > RAD ) continue;
if( abs(a.y-b.y) > RAD ) continue;
I assume this is for some kind of MMO - can't imagine 'thousands' of players in any other scenario. So your problem is actually more complex - you need to determine which players should receive the update about each player, so it turns into O(n^2) problem and we're dealing with millions. First thing to consider is do you really want to send updates based only on distance? You could divide your world into zones and keep separate lists of players for each zone and check it only for these lists, so for m zones we have O(m * (n/m)^2) = O(n^2/m). Obviously you also want to send updates to players in the same party and allow players near zone transition spots to know about each other(but make sure to keep that area small and unattractive for players so they don't just stand there). Also considering huge world and relatively slow player speed you don't have to update that info all that often.
Also keep in mind that memory/cache usage is extremely important for performance and I was referring to list as an abstract term - you should keep data accessed in tight loops in arrays, but make sure elements aren't too big. In this case consider making a simple class containing basic player data for those intensive loops and keep a pointer to a bigger class containing other data.
And on a total side note - your question seems to be quite basic, yet you are trying to build an MMO, which is not only technically complicated, but also requires a ton of work. I believe, that pursuing a smaller, less ambitious project, that you will be actually able to complete would be more beneficial.
You could put your objects into an ordered data structure, indexed by their distance from POS. This is similar to a priority queue, but you don't want to push/pop items all the time.
You'd have to update an object's key whenever it moves to the new position. To iterate over the items within a given radius RAD, you'd simply iterate over the items of this ordered data structure as long as the distance (the key) is less than RAD.
I'm trying to determine from a large set of positions how to narrow my list down significantly.
Right now I have around 3000 positions (x, y, z) and I want to basically keep the positions that are furthest apart from each other (I don't need to keep 100 positions that are all within a 2 yard radius from each other).
Besides doing a brute force method and literally doing 3000^2 comparisons, does anyone have any ideas how I can narrow this list down further?
I'm a bit confused on how I should approach this from a math perspective.
Well, I can't remember the name for this algorithm, but I'll tell you a fun technique for handling this. I'll assume that there is a semi-random scattering of points in a 3D environment.
Simple Version: Divide and Conquer
Divide your space into a 3D grid of cubes. Each cube will be X yards on each side.
Declare a multi-dimensional array [x,y,z] such that you have an element for each cube in your grid.
Every element of the array should either be a vertex or reference to a vertex (x,y,z) structure, and each should default to NULL
Iterate through each vertex in your dataset, determine which cube the vertex falls in.
How? Well, you might assume that the (5.5, 8.2, 9.1) vertex belongs in MyCubes[5,8,9], assuming X (cube-side-length) is of size 1. Note: I just truncated the decimals/floats to determine which cube.
Check to see if that relevant cube is already taken by a vertex. Check: If MyCubes[5,8,9] == NULL then (inject my vertex) else (do nothing, toss it out! spot taken, buddy)
Let's save some memory
This will give you a nicely simplified dataset in one pass, but at the cost of a potentially large amount of memory.
So, how do you do it without using too much memory?
I'd use a hashtable such that my key is the Grid-Cube coordinate (5,8,9) in my sample above.
If MyHashTable.contains({5,8,9}) then DoNothing else InsertCurrentVertex(...)
Now, you will have a one-pass solution with minimal memory usage (no gigantic array with a potentially large number of empty cubes. What is the cost? Well, the programming time to setup your structure/class so that you can perform the .contains action in a HashTable (or your language-equivalent)
Hey, my results are chunky!
That's right, because we took the first result that fit in any cube. On average, we will have achieved X-separation between vertices, but as you can figure out by now, some vertices will still be close to one another (at the edges of the cubes).
So, how do we handle it? Well, let's go back to the array method at the top (memory-intensive!).
Instead of ONLY checking to see if a vertex is already in the cube-in-question, also perform this other check:
If Not ThisCubeIsTaken()
For each SurroundingCube
If not Is_Your_Vertex_Sufficiently_Far_Away_From_Me()
exit_loop_and_outer_if_statement()
end if
Next
//Ok, we got here, we can add the vertex to the current cube because the cube is not only available, but the neighbors are far enough away from me
End If
I think you can probably see the beauty of this, as it is really easy to get neighboring cubes if you have a 3D array.
If you do some smoothing like this, you can probably enforce a 'don't add if it's with 0.25X' policy or something. You won't have to be too strict to achieve a noticeable smoothing effect.
Still too chunky, I want it smooth
In this variation, we will change the qualifying action for whether a vertex is permitted to take residence in a cube.
If TheCube is empty OR if ThisVertex is closer to the center of TheCube than the Cube's current vertex
InsertVertex (overwrite any existing vertex in the cube
End If
Note, we don't have to perform neighbor detection for this one. We just optimize towards the center of each cube.
If you like, you can merge this variation with the previous variation.
Cheat Mode
For some people in this situation, you can simply take a 10% random selection of your dataset and that will be a good-enough simplification. However, it will be very chunky with some points very close together. On the bright side, it takes a few minutes max. I don't recommend it unless you are prototyping.
I need an algorithm which can parse a 2D array and return the largest continuous rectangle. For reference, look at the image I made demonstrating my question.
Generally you solve these sorts of problems using what are called scan line algorithms. They examine the data one row (or scan line) at a time building up the answer you are looking for, in your case candidate rectangles.
Here's a rough outline of how it would work.
Number all the rows in your image from 0..6, I'll work from the bottom up.
Examining row 0 you have the beginnings of two rectangles (I am assuming you are only interested in the black square). I'll refer to rectangles using (x, y, width, height). The two active rectangles are (1,0,2,1) and (4,0,6,1). You add these to a list of active rectangles. This list is sorted by increasing x coordinate.
You are now done with scan line 0, so you increment your scan line.
Examining row 1 you work along the row seeing if you have any of the following:
new active rectangles
space for existing rectangles to grow
obstacles which split existing rectangles
obstacles which require you to remove a rectangle from the active list
As you work along the row you will see that you have a new active rect (0,1,8,1), we can grow one of existing active ones to (1,0,2,2) and we need to remove the active (4,0,6,1) replacing it with two narrower ones. We need to remember this one. It is the largest we have seen to far. It is replaced with two new active ones: (4,0,4,2) and (9,0,1,2)
So at the send of scan line 1 we have:
Active List: (0,1,8,1), (1,0,2,2), (4,0,4,2), (9, 0, 1, 2)
Biggest so far: (4,0,6,1)
You continue in this manner until you run out of scan lines.
The tricky part is coding up the routine that runs along the scan line updating the active list. If you do it correctly you will consider each pixel only once.
Hope this helps. It is a little tricky to describe.
I like a region growing approach for this.
For each open point in ARRAY
grow EAST as far as possible
grow WEST as far as possible
grow NORTH as far as possible by adding rows
grow SOUTH as far as possible by adding rows
save the resulting area for the seed pixel used
After looping through each point in ARRAY, pick the seed pixel with the largest area result
...would be a thorough, but maybe not-the-most-efficient way to go about it.
I suppose you need to answer the philosophical question "Is a line of points a skinny rectangle?" If a line == a thin rectangle, you could optimize further by:
Create a second array of integers called LINES that has the same dimensions as ARRAY
Loop through each point in ARRAY
Determine the longest valid line to the EAST that begins at each point and save its length in the corresponding cell of LINES.
After doing this for each point in ARRAY, loop through LINES
For each point in LINES, determine how many neighbors SOUTH have the same length value or less.
Accept a SOUTHERN neighbor with a smaller length if doing so will increase the area of the rectangle.
The largest rectangle using that seed point is (Number_of_acceptable_southern_neighbors*the_length_of_longest_accepted_line)
As the largest rectangular area for each seed is calculated, check to see if you have a new max value and save the result if you do.
And... you could do this without allocating an array LINES, but I thought using it in my explanation made the description simpler.
And... I think you need to do this same sort of thing with VERTICAL_LINES and EASTERN_NEIGHBORS, or some cases might miss big rectangles that are tall and skinny. So maybe this second algorithm isn't so optimized after all.
Use the first method to check your work. I think Knuth said "...premature optimization is the root of all evil."
HTH,
Perry
ADDENDUM:Several edits later, I think this answer deserves a group upvote.
A straight forward approach would be to do a loop through all the potential rectangles in the grid, figure out their area, and if it is greater than the current highest area, select it as the highest:
var biggestFound
for each potential rectangle:
if area(this potential rectangle) > area(biggestFound)
biggestFound = this potential rectangle
Then you simply need to find the potential rectangles.
for each square in grid:
recursive loop 1:
if not occupied:
grow right until occupied, and return a rectangle
grow down one and recurse (call loop 1)
This will duplicate a lot of work (for example you will re-evaluate a lot of sub-rectangles), but it should give you an answer.
Edit
An alternate approach might be to start with a single square the size of the grid, and "subtract" occupied squares to end up with a final set of potential rectangles. There might be optimization opportunities here using quadtrees, and in ensuring that you keep split rectangles "in order", top to bottom, left to right, in case you need to re-combine rectangles farther down in the algorithm.
If you are actually starting out with rectangular data (for your "populated grid" set), instead of a loose pixel grid, then you could easily get better perf out of a rectangle/region subtracting algorithm.
I'm not going to post pseudo-code for this because the idea is completely experimental, and I have no idea if the perf will be any better for a loose pixel grid ;)
Windows system "regions" and "dirty rectangles", as well as general "temporal caching" might be good inspiration here for more efficiency. There are also a lot of z-buffer tricks if this is for a graphics algorithm...
Use dynamic programming approach. Consider a function S(x,y) such that S(x,y) holds the area of the largest rectangle where (x,y) are the lowest-right-most corner cell of the rectangle; x is the row co-ordinate and y is the column co-ordinate of the rectangle.
For example, in your figure, S(1,1) = 1, S(1,2)=2, S(2,1)=2, and S(2,2) = 4. But, S(3,1)=0, because this cell is filled. S(8,5)=40, which says that the largest rectangle for which the lowest-right cell is (8,5) has the area 40, which happens to be the optimum solution in this example.
You can easily write a dynamic programming equation of S(x,y) from the value of S(x-1,y), S(x,y-1) and S(x-1,y-1). Using that you can obtain the values of all S(x,y) in O(mn) time, where m and n are the row and column dimension of the given table. Once, S(x,y) are know for all 1<=x <= m, and for all 1 <= y <= n, we simply need to find the x, and y for which S(x,y) is the largest; this step also takes O(mn) time. By keeping addition data, you can also find the side-length of the largest rectangle.
The overall complexity is O(mn). To understand more on this, Read Chapter 15 or Cormen's algorithm book, specifically Section 15.4.