Related
I'm working on some kind of 2D sandbox game in "Unity". In this game, you can create your battle figure like "robocraft" .
Details;
You can create your battleship on the another interface. if click "play", works "save" and "dontdestroyonload". Main Part is fixed. Other parts are child and in same tag with main part if they are unified eachother and main part. I used for this "collision stay".
And i want to create physics like in this picture;
[1]
[1]: https://i.stack.imgur.com/OhMMk.jpg
long story short; If below or above green part stay still, grey parts stay still because of connection but destroy both of them, all grey part must destroy.
I'm trying to use "flood fill algorithm" but I didn't know how to integrate to my codes.
Do you know any other solutions or can you give any example about "flood fill" for kind of this problems?
Already thanks for the people who trying to help.
My take on flood filled algorithm for your case would look like this:
Determine neighbours for each part. It will be maximum of 4 parts, or 8 if adjacency by corners also counts.
Create a list of neighbours and you can use OnCollisionStay to populate each list with neighbours.
When battleship is hit, this is where algorithm starts.
Create a Queue<Part> (or whatever collection suits you)
For each destroyed part
1.1) For each destroyed part's neighbours
1.1.1) Push its neighbours to the queue
1.1.2) Take the the first element from the queue. Mark it with flag as checked, and push it to the new checkedQueue.
1.1.3) Check if the part in question is a base part. If it is, it means there's a connection from neighbour of the destroyed part to the base, and those parts don't need to be destroyed. Exit the loop.
1.1.4) If it's not, push it's neighbours to the initial queue.
Continue with checking all parts. If you run out parts in the queue without exiting, it means there's no connection to the main part, and all parts on checking queue should be destroyed.
Obviously don't check or push parts that already have checked or destroyed flags. Be careful not to analyze all damaged part's neighbours at once, or you will end up with all parts connected to the core :) Also you might need to clear queues at appropriate times as well as reset flags when needed.
Hope you can read through that pseudo code, formatting on mobile is a challenging task. It probably isn't the most optimised code in the world, but it can serve as a good start.
I am making a turn based hex-grid game. The player selects units and moves them across the hex grid. Each tile in the grid is of a particular terrain type (eg desert, hills, mountains, etc) and each unit type has different abilities when it comes to moving over the terrain (e.g. some can move over mountains easily, some with difficulty and some not at all).
Each unit has a movement value and each tile takes a certain amount of movement based on its terrain type and the unit type. E.g it costs a tank 1 to move over desert, 4 over swamp and cant move at all over mountains. Where as a flying unit moves over everything at a cost of 1.
The issue I have is that when a unit is selected, I want to highlight an area around it showing where it can move, this means working out all the possible paths through the surrounding hexes, how much movement each path will take and lighting up the tiles based on that information.
I got this working with a recursive function and found it took too long to calculate, I moved the function into a thread so that it didn't block the game but still it takes around 2 seconds for the thread to calculate the moveable area for a unit with a move of 8.
Its over a million recursions which obviously is problematic.
I'm wondering if anyone has an clever ideas on how I can optimize this problem.
Here's the recursive function I'm currently using (its C# btw):
private void CalcMoveGridRecursive(int nCenterIndex, int nMoveRemaining)
{
//List of the 6 tiles adjacent to the center tile
int[] anAdjacentTiles = m_ThreadData.m_aHexData[nCenterIndex].m_anAdjacentTiles;
foreach(int tileIndex in anAdjacentTiles)
{
//make sure this adjacent tile exists
if(tileIndex == -1)
continue;
//How much would it cost the unit to move onto this adjacent tile
int nMoveCost = m_ThreadData.m_anTerrainMoveCost[(int)m_ThreadData.m_aHexData[tileIndex].m_eTileType];
if(nMoveCost != -1 && nMoveCost <= nMoveRemaining)
{
//Make sure the adjacent tile isnt already in our list.
if(!m_ThreadData.m_lPassableTiles.Contains(tileIndex))
m_ThreadData.m_lPassableTiles.Add(tileIndex);
//Now check the 6 tiles surrounding the adjacent tile we just checked (it becomes the new center).
CalcMoveGridRecursive(tileIndex, nMoveRemaining - nMoveCost);
}
}
}
At the end of the recursion, m_lPassableTiles contains a list of the indexes of all the tiles that the unit can possibly reach and they are made to glow.
This all works, it just takes too long. Does anyone know a better approach to this?
As you know, with recursive functions you want to make the problem as simple as possible. This still looks like it's trying to bite off too much at once. A couple thoughts:
Try using a HashSet structure to store m_lPassableTiles? You could avoid that Contains condition this way, which is generally an expensive operation.
I haven't tested the logic of this in my head too thoroughly, but could you set a base case before the foreach loop? Namely, that nMoveRemaining == 0?
Without knowing how your program is designed internally, I would expect m_anAdjacentTiles to contain only existing tiles anyway, so you could eliminate that check (tileIndex == -1). Not a huge performance boost, but makes your code simpler.
By the way, I think games which do this, like Civilization V, only calculate movement costs as the user suggests intention to move the unit to a certain spot. In other words, you choose a tile, and it shows how many moves it will take. This is a much more efficient operation.
Of course, when you move a unit, surrounding land is revealed -- but I think it only reveals land as far as the unit can move in one "turn," then more is revealed as it moves. If you choose to move several turns into unknown territory, you better watch it carefully or take it one turn at a time. :)
(Later...)
... wait, a million recursions? Yeah, I suppose that's the right math: 6^8 (8 being the movements available) -- but is your grid really that large? 1000x1000? How many tiles away can that unit actually traverse? Maybe 4 or 5 on average in any given direction, assuming different terrain types?
Correct me if I'm wrong (as I don't know your underlying design), but I think there's some overlap going on... major overlap. It's checking adjacent tiles of adjacent tiles already checked. I think the only thing saving you from infinite recursion is checking the moves remaining.
When a tile is added to m_lPassableTiles, remove it from any list of adjacent tiles received into your function. You're kind of doing something similar in your line with Contains... what if you annexed that if statement to include your recursive call? That should cut your recursive calls down from a million+ to... thousands at most, I imagine.
Thanks for the input everyone. I solved this by replacing the Recursive function with Dijkstra's Algorithm and it works perfectly.
I'm coding a server for a multi-player RPG, and I'm currently struggling with implementing a sight range. Since some maps are rather large, I have to limit what the client sees. My approach:
If I get new coordinates from the client, I save them as the destination, together with a move start time. Once every x ms I go through all creatures in the world, and update their current position, after saving the position they were at the last time I've updated them. Basically I calculate the new position, based on move start time and speed, and write those in the current position variables, while saving the new start time. Once this update is done, I'm going through all creatures which moved, aka those who have a different position than at the last update. In a sub-loop I go through all creatures/clients again, to check if I have to notify them about a (dis)appearing creature. At the moment I'm running this update every 100ms.
This approach is working, but I have a feeling it's not the best way to do this. And I'm not sure what will happen once I have a few thousand creatures (players, monster, etc) in the world, which have to be updated and checked.
Since I weren't able to find resources about this particular problem, I'm asking here.
Is this approach okay? Will I run into problems soon? What's the standard to do this? What's the best way?
Eric Lippert had a really good series of posts on shadowcasting that might be helpful in approaching/solving this.
You may want to consider using quadtrees to split the game world into sections based on the areas that player characters can see. Then you don't need to loop over every creature in the game all the time; you only need to loop over the ones within the section that the player character in question is located in, and any adjacent ones in case something crossed the boundary.
I haven't done this sort of coding personally myself, but I did work with someone who did this in a space combat game for which I was developing a GUI!
I'm writing a piece of simulation software, and need an efficient way to test for collisions along a line.
The simulation is of a train crossing several switches on a track. When a wheel comes within N inches of the switch, the switch turns on, then turns off when the wheel leaves. Since all wheels are the same size, and all switches are the same size, I can represent them as a single coordinate X along the track. Switch distances and wheel distances don't change in relation to each other, once set.
This is a fairly trivial problem when done through brute force by placing the X coordinates in lists, and traversing them, but I need a way to do so efficiently, because it needs to be extremely accurate, even when the train is moving at high speeds. There's a ton of tutorials on 2D collision detection, but I'm not sure the best way to go about this unique 1D scenario.
Apparently there's some confusion about what my data looks like.
I'm simulating a single site, not an entire region. The trains can be of any length, with different types of cars, but there is only ever one train. My train data is in the form {48,96,508,556,626,674,...}, indicating the distances from the front of the train (0) to the center of the axle.
(Train data will more likely come to me in the form of an ordered list of Car objects, each of which has a length and a list of integers representing axle distances from the front of that car, but it all gets aggregated into a single list, since all axles are the same to me.)
My switches are all within several hundred feet, and will often be entirely covered by the train, The switches can be at any interval from hundreds of feet to several inches apart, and is in the same form as the train: {0,8,512,520,...}, indicating the distances from the beginning of the site to the center of the switch.
Finally, I know the distance at which the wheel activates the switch, in inches.
For example, using the above sample data, and a an activation distance of 8 inches, the first switch at X=0 would activate when the train hits X=40, meaning the train is 40 inches into the site. When the train hits X=48, the switch at X=8 is also activated. At X=56, the first switch goes off, and at X=64, the second switch also goes off. Different axles are turning different switches on and off as it crosses the site.
The train is usually running at speeds under 10 mph, but can go much higher. (Right now our simulation is capped at 30 mph, but higher would be great.)
Have a sorted list of all the switches' coordinates and use binary search on the list to find the nearest switch. Then check to see how far it is and whether or not it's a collision.
O(log n)
Another option is to exploit the fact that the train moves along the track and can only ever come close to two switches, one behind and one ahead.
Construct a doubly-linked list of all the switches and position an extra node to represent the train in the correct location in the linked list. Then only check proximity to the switch the train is headed towards.
O(1)
To save memory, store the sorted coordinates in an array and simply keep track of which indexes the train is between.
Pre-process your switch locations and sensitivity range into a list of track segments. Each segment has a length, and between each segment a set of switch 'on' or 'off' events.
switch_on ( 0 ), ( length: 8 ), switch_on ( 1 ), // x = zero here
segment ( length: 8 ), switch_off ( 0 ),
segment ( length: 8 ), switch_off ( 1 ),
segment ( length: 488 ), switch_on ( 2 ),
segment ( length: 8 ), switch_on ( 3 ),
segment ( length: 8 ), switch_off ( 2 ),
segment ( length: 8 ), switch_off ( 3 ),
...
For each axle, have its current location also represented along with the track segment it is on.
If you're doing an event based simulation, the next event should be scheduled for the min value of the distance from an axle to the end of its current track segment. This is independent of the train speed, and accurate (you won't miss switches if the train goes faster). Store the events in a heap if necessary (it's often not worth it for less than 30 or so, profile the event scheduling if necessary).
Processing an event will be O(no-of-axles). Most steps will involve one or two switch state changes and a position update. At each event, one axle will cause one switch to go on or off (switches which would be simultaneous according to the data cause two events, zero time apart), and all axle times to the end of their segments need to be compared. You can either assume that all axles travel at the same speed or not; it doesn't matter as far as processing the events, it only makes the calculation of the time to reach the next switch specific to the axle in question.
If you're on a fixed time step simulation, then process all events which would have occurred up to the time at the end of the step, then one event to move the axles to the point they reach at the end of the step.
Store the switch list as a doubly-linked list as indicated by Ben.
Keep a pointer in the wheel object (or structure, assuming there is one) to the next switch and the previous switch relative to your current position. Intialize these as the wheel is placed on the track.
As you move over each switch, swap out the "next" and "previous" switches in your wheel object for the new "next" and "previous" that can be quickly obtained by examining the doubly-linked list.
This avoids all searches, except possibly initial placement of the wheel.
Additionally, the "switch" structure could be used to hold a proximity pointer back to all of the wheels that list it as "previous" or "next". (There's a mutex here, so be careful of who updates this.) This can provide a quick update of who's approaching any given switch and their distance from it.
Assuming that Axle-to-Axle distances are always larger the activation distance, and that routes don't change frequently after the train enters, you should be able to speed things up with pre-calculation. Basically, for each switch, calculate a list of train travel distances at which it will toggle, then walk through the lists as the train advances.
Pseudocode:
axles = {48,96,508,556,626,674,...}
switches ={0,8,512,520,...}
activate = 8
float toggledist[num_switches]
boolean switchState[num_switches]={false,false,false,...}
int idx[num_switches]
for (i in switches)
n = 0
for (a in axles)
toggledist[n++] = switches[i]+axles[a]-activate
toggledist[n++] = switches[i]+axles[a]+activate
travel= 0.0f;
each (cycle)
travel += TrainVelocity*time;
for (i in switches)
while (trigger>=toggledist[idx[i]])
switchState[i]=!switchState[i];
//additional processing for switch change here, if needed
idx[i]++;
as my personal project i develop a game to which users can join at any time.
I have a tiled worldmap that is created from a simple Bitmap which has resources at random positions all over the map except for oceans.
When a player joins i want to create his starting position at a place that has at least 1 tile of each of the 4 resources in range (circle with a still to decide diameter, i think about 3-4 tiles) but no ocean tiles (Tile.Type != "ocean") and not conflicting with a field belonging to another player (Tile.Owner == null).
The map size can vary, currently it's 600x450 and it's implemented as a simple Array: Tile[][] with Tile.Resource being either null or having Tile.Resource.Type as a string of the resource name (as it's configurable by plaintext files to fit any scenery i want to put it in, so no built-in enums possible).
I currently have a loop that simple goes through every possible position, checks every field in range and counts the number of each resource field and discards it if there are none for one of them or if one of them belongs to a player or is an ocean field.
I would prefer if it finds a random position but thats not a requirement, mono-compatibility however is a requirement.
What would be the best way to implement an algorithm for that in C#?
Edit
The Area of players can and will increase/change and resources can be used up and may even appear randomly (=> "Your prospectors found a new goldmine") so pre-calculated positions will propably not work.
Instead of looping through all your positions, why don't you loop through all your resources? Your resources are likely to be more scant. Then pick one of the sets of resources that meet your clustering criterion.
You might consider simulated annealing ... it's not very complex to implement. You have a set of criteria with certain weight, and randomly "shake" the position at a certain "temperature" (the higher the temp, the greater the radius the position may randomly move within, from it's previous position), then when it "cools" you measure the value of the position based on the total weights and subtract negative things, like spawning too close to where they died, or next to other players, etc..., if the value is not within a certain range, you decrease the temperature, but "shake" the positions again, cool down, check weights and overall value, repeat until you get an acceptable solution.
Simulated annealing is used in map making, to label cities and features with maximum clarity, while staying within range and minimizing overlap. Since it's a heuristic approach there is no guarantee that there will be an optimal solution, so you keep "lowering the temp" and eventually just choose the best result.
Let's suppose that once your map is created you don't have to create a new one often.
Just add the following to each Tile and calculate them once after your map was generated:
-int NrOceanTiles
-int NrResourceA
-int ...
Now when you want to get a tile you can do it quite a bit faster:
IEnumerable<Tiles> goodTiles = tiles.Where(tile => tile.NrResourceA >= 1 && tile.NrResourceB >= 2);
Tile goodTile = goodTiles.ElementAt(randomI);
Predefined data would still be the best way forward.
As modifying the map size, and adding/losing resources would not happen as often, just update this data table when they do happen. Perhaps you could do the map/resource changes once per day, and have everything done in a daily database update.
In this way, finding a valid location would be far faster than any algorithm you implement to search all the tiles around it.
If the game isn't going to be designed for a huge number of players, most games implement "start spots" on the map. You'd hand-pick them and record the positions in your map somehow, probably similar to how you're implementing the map resources (i.e., on that spot, there exists an item you can pick up, but on top of the tile map).
Since the resources spawn at random, you could either not spawn resources on the start spots (which could be visible or not), or simply not spawn a player at a start spot on which there is a resource (or look within a 9-cell box to find a close alternate location).
Certainly you would want to hold the set of possible starting locations and update it as resources are created and consumed.
It seems like your best bet is to calculate open locations at map generation. Have your start location calculation function optionally take grid location and size or rectangle corners.
Have a list for Free locations and Occupied locations. Player occupies territory? Move resources in range to the Occupied list. Player gets crushed mercilessly? Move resources in range to the Free list. Resource eliminated? Delete any locations that used it in your Open/Occupied lists. Resource added? Recalculate using your effect radius to determine effected area. When your map area expands, just run the initial calculations on the new section of your grid + effect radius and add the new locations.
Then you just have to set the events up and pick a random Free value when someone joins.