I'm working on a project using C#/XNA and I'm having trouble creating water-physics in an top-down hex-based grid.
We're using an hex-tilemap with help of: http://www.redblobgames.com/grids/hexagons.
So I thought I could implement an algoritm for the water flow, but I can't seem to get it right, and it seems to be very performance-heavy.
/// <summary>
/// This method will level all the water to the same height. It does so by looking arround and make them all even
/// </summary>
/// <param name="tiles">The tile array needed to level arround</param>
public void Flow(List<Tile> tiles, Tilemap tileMap)
{
float waterAmountEachTile;
List<Water> waterTiles = new List<Water>(7);
//include self
waterTiles.Add(this);
float waterAmount = (this.waterHeight + this.ZPos);
for (int i = 0; i < tiles.Count; i++)//first loop to get all values
{
if (tiles[i].GetType() == typeof(Water))
{
waterTiles.Add((Water)tiles[i]);//check wich tiles are water and put them in a new array
waterAmount += (waterTiles[waterTiles.Count - 1].waterHeight + waterTiles[waterTiles.Count - 1].ZPos); //Increase the ammount - debuggen later werkt count goed
}
}
waterAmountEachTile = waterAmount / waterTiles.Count; //Calculate how high each tile should be ( we need this for drycheck)
dryCheck(ref waterAmount, waterTiles, waterAmountEachTile, tileMap);
waterAmountEachTile = waterAmount / waterTiles.Count; //recalculate the ammount for each tile
foreach (Water waterTile in waterTiles) //second loop to adjust the tile to the according hight
{
waterTile.waterHeight = (waterAmountEachTile - waterTile.ZPos);
}
}
/// <summary>
/// Checks if the tile should be dry or continue being a water tile.
/// </summary>
/// <param name="waterAmount"> the ammount of water to divide among the tiles</param>
/// <param name="waterTiles">The watertiles list to do the drycheck on</param>
/// <param name="waterAmountEachTile">The height to set each water tile</param>
/// <returns></returns>
private void dryCheck(ref float waterAmount, List<Water> waterTiles, float waterAmountEachTile, Tilemap tileMap)
{
//TODO dit fixen
for (int i = 0; i < waterTiles.Count; i++)
{
if (waterTiles[i].ZPos > waterAmountEachTile) //is grond hoger dan water
{
waterAmount -= waterTiles[i].ZPos;
tileMap.TileMap[waterTiles[i].XPos][waterTiles[i].YPos] = new Ground(this.graphics, waterTiles[i].XPos, waterTiles[i].YPos,
waterTiles[i].ZPos, this.size, Tilemap.HexVertices);
waterTiles.Remove(waterTiles[i]);
i--;
}
}
}
Now for my question, does any of you know of a way to implement water-physics in a top-down environment, preferably with hex-based grids.
I've looked in to several liberaries, and found Smoothed-particle hydrodynamics, but I'm not sure if it's implementable top-down, and I can't seem to find any guides in that direction.
Any help would be great, even some pointers might be enough.
Thanks in advance,
C. Venhuizen
Have you profiled your code to determine what is the slowest part?
I don't quite understand what your code is doing. Do you call Flow once for each tile, or do you call it once, and it runs over all tiles? If I were to guess, I'd say that allocating a new list each tile is going to be pretty slow. But the best way to know is to profile.
The thing that originally led me to write http://www.redblobgames.com/grids/hexagons was a top-down hex game that was all about water flow. I wrote that game in 1995, and I recently ported it to run on the web here. The algorithm I started with is simple. For each hex, traversed in random order:
calculate the water level W + elevation H
calculate the same for each neighbor
make up to half the water flow to the neighbor with the lowest W + H
The random order is so that the loop doesn't cause water to flow many hexes to the right but not many hexes to the left, or other such direction artifacts. Even cleaner would be to use a double buffer for this: write all the new values to a separate array, and then copy them back to the first array at the end (or swap the arrays).
Beyond that, there are tons of heuristics I used for erosion and other features of the (unfinished) game. The code is old and awful but if you want to take a look, you can download it here (ZIP file). See water.cpp. I avoided memory allocations in the water flow loop.
Related
I recently learned about design patterns and wanted to change my code for a small game I had to make. The game is called SpaceTaxi. I've made a parser, parsing a .txt file with ascii content resulting in 4 different lists of entities: taxi, obstacle, exit and platform. Inside the gameloop I call a big collision-method using these entities detecting whether they collide. It's really ugly code. Is there a good design pattern I could use for my collision method? So instead of having a big method then have smaller classes? Currently it looks like this:
/// <summary>
/// Checks for collision with obstacles, platforms and exits.
/// </summary>
private void CollisonCheck() {
var platformCollision = Player.CollisionPlatform(Parser.PlatformEntities,
false);
var obstacleCollision = Player.CollisionObstacle(Parser.ObstacleEntities,
false);
var exitCollision = Player.CollisionObstacle(Parser.ExitEntities,
false);
// Landing on platform
if (platformCollision.Item1 && obstacleCollision) {
// Stand still on platform
if (Math.Abs(Player.Entity.Shape.AsDynamicShape().Direction.Y)
< Constants.COLLISION_DISTANCE) {
Player.Shape.Direction.Y = 0;
Player.Shape.Direction.X = 0;
Player.OnPlatform = true;
// Explode because of too much speed
} else {
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
0.1f, 0.1f);
}
// Be rewarded in case player transports a customer
if (Player.HasCostumer) {
foreach (var customer in pickedUpCustomers) {
if (CorrectDestination(platformCollision.Item2,
customer.DestinationPlatform)) {
score.AddPoint(CurrentCustomer.RewardPoints);
customer.CanRemove = true;
Player.HasCostumer = false;
}
}
}
// Exit map
} else if (exitCollision) {
// Switch from one map to another
if (GameRunning.CurrentMap == "the-beach.txt") {
GameRunning.CurrentMap = "short-n-sweet.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
// Switch from one map to another
} else {
GameRunning.CurrentMap = "the-beach.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
}
GameRunning.Timer.Restart();
Parser.Load(GameRunning.CurrentMap);
allCustomersInMap = new List<Customer>();
foreach (var c in Parser.Customer) {
allCustomersInMap.Add(new Customer(c.Key, c.Value.Item1,
c.Value.Item2, c.Value.Item3, c.Value.Item4,
c.Value.Item5));
}
// Collision with obstacle. Add explosion
} else if (obstacleCollision) {
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
Constants.EXPLOSION_WIDTH, Constants.EXPLOSION_HEIGHT);
TaxiBus.GetBus()
.RegisterEvent(GameEventFactory<object>.CreateGameEventForAllProcessors(
GameEventType.GameStateEvent, this, "CHANGE_STATE",
"MAIN_MENU", ""));
}
// Collision with taxi and customer
// CollisionCustomer returns a bool (item1) and null/customer (item2)
if (Player.CollisionCustomer(allCustomersInMap).Item1 && !Player.HasCostumer) {
var customer = Player.CollisionCustomer(allCustomersInMap).Item2;
TaxiMeterTimer = new Stopwatch();
TaxiMeterTimer.Start();
CurrentCustomer = customer;
pickedUpCustomers.Add(customer);
allCustomersInMap.Remove(customer);
CurrentCustomer.SetPosition(Constants.HIDEPOS_X, Constants.HIDEPOS_Y);
Player.HasCostumer = true;
}
}
Please note that questions like this are better suited for CodeReview as this is pretty much off topic for SO because you do not have a specific problem or exception that you are trying to resolve.
It is good practise in all applications to separate out decision logic from action logic, for a number of reasons:
Removing the implementation of actions from complex logic trees makes it easier to visualise the decision process, you assume that the actions work correctly and debug them separately
Creating single purpose action methods promotes code re-use from different decision logic trees in your program
You can easily test and debug individual actions or logic branches without disrupting or being distracted by the bigger picture.
You can more clearly document your intent with method Doc Comments
Just separating out the actions you have defined results in code similar to this:
/// <summary>
/// Checks for collision with obstacles, platforms and exits.
/// </summary>
private void CollisonCheck()
{
var platformCollision = Player.CollisionPlatform(Parser.PlatformEntities, false);
var obstacleCollision = Player.CollisionObstacle(Parser.ObstacleEntities, false);
var exitCollision = Player.CollisionObstacle(Parser.ExitEntities, false);
// Landing on platform
if (platformCollision.Item1 && obstacleCollision)
DockAtPlatform(); // Stand still on platform
else if (exitCollision)
ExitMap(); // Exit map
else if (obstacleCollision)
CollideWithObject(); // Collision with obstacle. Add explosion
// ??? Player collision can occur at a platform or in general regions in the map
if (Player.CollisionCustomer(allCustomersInMap).Item1 && !Player.HasCostumer)
PickupCustomer();
}
/// <summary>
/// Dock Player with platform as long as they are not approaching too fast.
/// Collect reward if carrying a passenger
/// </summary>
/// <remarks>If too fast, player will explode!</remarks>
private void DockAtPlatform()
{
if (Math.Abs(Player.Entity.Shape.AsDynamicShape().Direction.Y)
< Constants.COLLISION_DISTANCE)
{
Player.Shape.Direction.Y = 0;
Player.Shape.Direction.X = 0;
Player.OnPlatform = true;
// Explode because of too much speed
}
else
{
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
0.1f, 0.1f);
}
// Be rewarded in case player transports a customer
if (Player.HasCostumer)
{
foreach (var customer in pickedUpCustomers)
{
if (CorrectDestination(platformCollision.Item2,
customer.DestinationPlatform))
{
score.AddPoint(CurrentCustomer.RewardPoints);
customer.CanRemove = true;
Player.HasCostumer = false;
}
}
}
}
/// <summary>
/// Switch between Maps
/// </summary>
private void ExitMap()
{
// Switch from one map to another
if (GameRunning.CurrentMap == "the-beach.txt")
{
GameRunning.CurrentMap = "short-n-sweet.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
}
else
{
// Switch the reverse way around
GameRunning.CurrentMap = "the-beach.txt";
Player.SetPosition(Constants.PLAYER_ENTRYPOSITION_X,
Constants.PLAYER_ENTRYPOSITION_Y);
Player.Entity.Shape.AsDynamicShape().Direction.Y = Constants.STILL;
Player.Entity.Shape.AsDynamicShape().Direction.X = Constants.STILL;
}
GameRunning.Timer.Restart();
Parser.Load(GameRunning.CurrentMap);
allCustomersInMap = new List<Customer>();
foreach (var c in Parser.Customer)
{
allCustomersInMap.Add(new Customer(c.Key, c.Value.Item1,
c.Value.Item2, c.Value.Item3, c.Value.Item4,
c.Value.Item5));
}
}
/// <summary>
/// Show explosion because player has collided with an object, then return to the main menu
/// </summary>
private void CollideWithObject()
{
AddExplosion(Player.Shape.Position.X, Player.Shape.Position.Y,
Constants.EXPLOSION_WIDTH, Constants.EXPLOSION_HEIGHT);
TaxiBus.GetBus()
.RegisterEvent(GameEventFactory<object>.CreateGameEventForAllProcessors(
GameEventType.GameStateEvent, this, "CHANGE_STATE",
"MAIN_MENU", ""));
}
/// <summary>
/// Pickup a new customer, start the meter running and remove the customer from the map
/// </summary>
private void PickupCustomer()
{
var customer = Player.CollisionCustomer(allCustomersInMap).Item2;
TaxiMeterTimer = new Stopwatch();
TaxiMeterTimer.Start();
CurrentCustomer = customer;
pickedUpCustomers.Add(customer);
allCustomersInMap.Remove(customer);
CurrentCustomer.SetPosition(Constants.HIDEPOS_X, Constants.HIDEPOS_Y);
Player.HasCostumer = true;
}
Now you can focus on the individual actions and review them to see if there are cleaner ways to code their process.
A few notes to consider:
Add Explosion should accept a point object instead of passing through the X,Y coordinates, it makes the code easier to read and is a natural way to pass coordinates that always go together.
Instead of using Tuples, you should create specific data model classes to use as return values from the collision functions, it feels like over-engineering, but it helps both with documentation of your code and to understand the intent.
Takes little time to define a class to hold the collision response, with minimal documentation, instead of burying inside comments what .Item1 and .Item2 might be in terms of data type and logical meaning
Yes Tuples are awesome, in terms of rapidly smashing code solutions out, but you always have to review the code that creates the values to understand or identify the meaning behind the values, so these are usually the first to be refactored out of my prototyping code when I want to get serious about a solution.
You have a style of placing the comments for the next if block inside the previous branch code, move the comments to inside the affected if branch, or immediately above it
Or move the branch into its own method and you can use Doc comments.
If the Player object itself holds the meter variables, you could accept multiple passengers (up to the capacity of the vehicle) and collect multiple fares on delivery, your action for dropping off a customer at a platform already assumes multiple passengers.
You may have already catered for this in different ways
Final Note (a personal one)
Try to change your method logic into more cause and effect style, you gain a lot of benefits in the overall SDLC if you adopt more functional programming styles into your OO logic. Where you can, and especially for the smallest units of work, pass in the objects that will be operated on as arguments for your methods rather than referencing global objects, in this way you will find it easier to establish unit testing and code review of your individual methods.
Even though in this project you may not implement unit tests, it is a very good habit to evolve, it will make future code examples that you post on SO easier for the rest of us to debug and will allow you to be a more efficient contributor in a team or community development project.
Hi I am practising my coding for my university course and I have built a virtual Aquarium.
I have currently got some sea horses in there and have made a chicken leg to appear when I click. I have written some code to say when the chicken leg appears they move vertically. However I want them to scatter and not go near the chicken leg or at least bump of it. my vertical swim behaviour code is:
` private void VerticalSwimBehaviour() //Verticle Swim scatter
{
Vector3 tokenPosition = this.PossessedToken.Position;
tokenPosition.Y = tokenPosition.Y + mSpeed * mFacingDirection;
if (tokenPosition.Y > 300 || tokenPosition.Y < -300) // Responds if fish goes to the top or bottom of screen
{
mFacingDirection = -mFacingDirection;
}
this.PossessedToken.Orientation = new Vector3(mFacingDirection, this.PossessedToken.Orientation.Y, this.PossessedToken.Orientation.X);
this.PossessedToken.Position = tokenPosition;
}
private void RandomNumberMethod()
{
Random random = new Random();
int randomNumber1 = random.Next(1, 5);
int randomNumber2 = random.Next(1, 150);
}`
I want to make a behaviour that work like this but runs from the chicken leg.
here is my leg calling upon the behaviour when chicken leg appears
public override void Update(ref GameTime pGameTime)
{
Vector3 tokenPosition = this.PossessedToken.Position;
HorizontalSwimBehaviour();
velocidadMax();
if (mAquarium.ChickenLeg != null)
{
VerticalSwimBehaviour();
}
}
Any help is appreciated.
Write a method to check if the seahorses are facing the chicken. If they are, reverse their facing (do this just once). Have them keep a certain distance away from the chicken. Use the distance formula with the origin of the chicken and the origin of each seahorse. If they are within that distance have them run straight in one direction until they hit a wall. When they hit the wall, have them turn 90 degrees right or left and do it again. Do this behavior until they are far enough away from the chicken. I would probably make the distance about 40% of the tank size (as a diameter) to ensure that they can find a corner to hide. Hopefully this helps, I haven't used Unity so I don't know specific methods to call. It should be simple object manipulation though. I would also add some effects to your vertical oscillation, perhaps increasing its frequency with a multiplier based on closeness to the chicken (lower oscilation distance, higher velocity). As for avoiding the running in the the chicken, You can set a minimum distance to the chicken (this one much closer) which will cause your seahorse to turn around if it gets too close, in which case it will resume its running to a wall and turning. All of this checking should run while the chicken leg exists.
I am making use of NAudio in a C# program I've written.
I want to apply a linear fade at a certain position within a piece of audio I'm working with.
In the NAudio example project is a file called FadeInOutSampleProvider.cs (Cached example) which has BeginFadeIn(double fadeDurationInMilliseconds) and BeginFadeOut(double fadeDurationInMilliseconds) methods.
I've reworked these methods to
BeginFadeOut(double fadeDurationInMilliseconds, double beginFadeAtMilliseconds)
and
BeginFadeOut(double fadeDurationInMilliseconds, double beginFadeAtMilliseconds)
However I'm having difficulty implementing the interval logic for these changes to work.
My first thought was to introduce code in the Read() method. When called it would divide the number of bytes being requested by the sample rate, which would give the number of seconds of audio requested.
I could then keep track of this and when the correct amount of auto data had been read, allow the fade to be applied.
However I'm not getting the numbers in my calculations I would expect to see. I'm sure there's a better way to approach this.
Any help would be very much appreciated.
It sounds like you are working along the right lines. As you say the amount of audio being requested can be calculated by dividing number of samples requested by the sample rate. But you must also take into account channels as well. In a stereo file there are twice as many samples per second as the sample rate.
I've put a very basic code sample of a delayed fade out in a GitHub gist here. There are improvements that could be made such as allowing the fade-out to begin part-way through the audio returned from a call to Read but holpefully this gives you a rough idea of how it can be achieved with a few small modifications to FadeInOutSampleProvider.
The main changes are an extra parameter to BeginFadeOut, that sets two new variables (fadeOutDelaySamples, fadeOutDelayPosition):
/// <summary>
/// Requests that a fade-out begins (will start on the next call to Read)
/// </summary>
/// <param name="fadeDurationInMilliseconds">Duration of fade in milliseconds</param>
public void BeginFadeOut(double fadeAfterMilliseconds, double fadeDurationInMilliseconds)
{
lock (lockObject)
{
fadeSamplePosition = 0;
fadeSampleCount = (int)((fadeDurationInMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeOutDelaySamples = (int)((fadeAfterMilliseconds * source.WaveFormat.SampleRate) / 1000);
fadeOutDelayPosition = 0;
//fadeState = FadeState.FadingOut;
}
}
Then in the Read method we can keep track of how far into the delay we are, and if so, we can start the fade-out
public int Read(float[] buffer, int offset, int count)
{
int sourceSamplesRead = source.Read(buffer, offset, count);
lock (lockObject)
{
if (fadeOutDelaySamples > 0)
{
fadeOutDelayPosition += sourceSamplesRead / WaveFormat.Channels;
if (fadeOutDelayPosition >= fadeOutDelaySamples)
{
fadeOutDelaySamples = 0;
fadeState = FadeState.FadingOut;
}
}
if (fadeState == FadeState.FadingIn)
{
FadeIn(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.FadingOut)
{
FadeOut(buffer, offset, sourceSamplesRead);
}
else if (fadeState == FadeState.Silence)
{
ClearBuffer(buffer, offset, count);
}
}
return sourceSamplesRead;
}
I profiled my application (a game), and I noticed that this function is a (the!) bottleneck. In particular, this function is called a lot due to it's meaning: it draws windows of my game's skyscraper. The game is flowing horizontally so, everytime new skyscraper are generated and windows has to be drawn.
The method is simple: I load just one image of a window and then I use it like a "stencil" to draw every window, while I calculate its position on the skyscraper.
position_ is the starting position, based on top-left corner where I want to begin drawing
n_horizontal_windows_ and n_vertical_windows_ is self-explanatory and it is generated in constructor
skipped_lights_ is a matrix of bool that says if that particular light is on or off (off means don't draw the window)
delta_x is like the padding, the distance between a window and another.
w_window is the width of the window (every window has the same)
public override void Draw(SpriteBatch spriteBatch)
{
Vector2 tmp_pos = position_;
float default_pos_y = tmp_pos.Y;
for (int r = 0; r < n_horizontal_windows_; ++r)
{
for (int c = 0; c < n_vertical_windows; ++c)
{
if (skipped_lights_[r, c])
{
spriteBatch.Draw(
window_texture_,
tmp_pos,
overlay_color_);
}
tmp_pos.Y += delta_y_;
}
tmp_pos.X += delta_x_ + w_window_;
tmp_pos.Y = default_pos_y;
}
}
As you can see the position is calculated inside the loop.
Just an example of the result (as you can see I create three layers of skyscrapers):
How can I optimize this function?
You could always render each building to a texture and cache it while it's on screen. That way you only draw the windows once for each building. you will draw the entire building in one call after it's been cached, saving you from building it piece by piece every frame. It should prevent a lot of over-draw that you were getting each frame too. It will have a slight memory cost though.
I am creating a minecraft clone, and whenever I move the camera even a little bit fast there is a big tear between the chunks as shown here:
Each chunk is 32x32x32 cubes and has a single vertex buffer for each kind of cube, in case it matters. I am drawing 2D text on the screen as well, and I learned that I had to set the graphic device state for each kind of drawing. Here is how I'm drawing the cubes:
GraphicsDevice.Clear(Color.LightSkyBlue);
#region 3D
// Set the device
device.BlendState = BlendState.Opaque;
device.DepthStencilState = DepthStencilState.Default;
device.RasterizerState = RasterizerState.CullCounterClockwise;
// Go through each shader and draw the cubes of that style
lock (GeneratedChunks)
{
foreach (KeyValuePair<CubeType, BasicEffect> KVP in CubeType_Effect)
{
// Iterate through each technique in this effect
foreach (EffectPass pass in KVP.Value.CurrentTechnique.Passes)
{
// Go through each chunk in our chunk map, and pluck out the cubetype we care about
foreach (Vector3 ChunkKey in GeneratedChunks)
{
if (ChunkMap[ChunkKey].CubeType_TriangleCounts[KVP.Key] > 0)
{
pass.Apply(); // assign it to the video card
KVP.Value.View = camera.ViewMatrix;
KVP.Value.Projection = camera.ProjectionMatrix;
KVP.Value.World = worldMatrix;
device.SetVertexBuffer(ChunkMap[ChunkKey].CubeType_VertexBuffers[KVP.Key]);
device.DrawPrimitives(PrimitiveType.TriangleList, 0, ChunkMap[ChunkKey].CubeType_TriangleCounts[KVP.Key]);
}
}
}
}
}
#endregion
The world looks fine if I'm standing still. I thought this might be because I'm in windowed mode, but when I toggled full screen the problem persisted. I also assume that XNA is double buffered by itself? Or so google has told me.
I had a similar issue - I found that I had to call pass.Apply() after setting all of the Effect's parameters...
The fix so far has been to use 1 giant vertex buffer. I don't like it, but that's all that seems to work.