Need help improving my Flow Field and Unit Avoidance code so that the units can properly surround a unit instead of getting stuck

My setup is like this. Every update my movement system moves all of the units on the field. They use some Boid logic to avoid eachother, and a flow field that directs them towards each other. This is the result. https://imgur.com/a/CaUpfT7

My general setup is to calculate 2 flow fields, one for each player. From every field on the map (32×32 fields) I calculate the vector that points towards the closest enemy. Now this is a fine approach but I’d like to somehow take into consideration obstacles somehow (without another round of for loops)? Or should I handle that in my movement system avoidance? I was maybe thinking of doing A* once a unit is close enough to the enemy but all of these systems together seem rather hacky and overkill.

There are no obstacles currently, maybe a spell will generate it in the future. For now there are only units on the battleground without terrain or obstacles (besides units fighting eachother)

Here is some code. Firstly how I create the flowfields (kinda costly, will look into a way to optimize it further, don’t really need every single tile, can probably merge 2 or 3 together)

func (g *Grid) Update() {     g.entityPositions[0] = g.entityPositions[0][:0]     g.entityPositions[1] = g.entityPositions[1][:0]     entities := g.world.GetEntityManager().GetEntities()     posComps := g.world.GetObjectPool().Components["PositionComponent"]      for _, ent := range entities {         g.entityPositions[ent.PlayerTag] = append(g.entityPositions[ent.PlayerTag], posComps[ent.Index].(components.PositionComponent).Position)     }      for x := 0; x <= g.MaxWidth/FlowTileSize; x++ {         for y := 0; y <= g.MaxHeight/FlowTileSize; y++ {              curPosVector := engine.Vector{X: float32(x * 32), Y: float32(y * 32)}             // find closest tile to this one for both players             minDist := float32(100000.0)             minIndx := -1             for indx, pos := range g.entityPositions[0] {                 d := engine.GetDistanceIncludingDiagonal(pos, curPosVector)                 if d < minDist {                     minIndx = indx                     minDist = d                 }             }              //  fmt.Printf("CurPos : %v, enemyPos : %v,  direction %v \n", curPosVector, g.entityPositions[0][minIndx], g.entityPositions[0][minIndx].Subtract(curPosVector).Normalize())             g.flowTiles[1][x][y].Direction = g.entityPositions[0][minIndx].Subtract(curPosVector).Normalize()              minDist1 := float32(100000.0)             minIndx1 := -1             for indx, pos := range g.entityPositions[1] {                 d := engine.GetDistanceIncludingDiagonal(pos, curPosVector)                 if d < minDist1 {                     minIndx1 = indx                     minDist1 = d                 }             }              g.flowTiles[0][x][y].Direction = g.entityPositions[1][minIndx1].Subtract(curPosVector).Normalize()         }     } }  

And my movement code. A lot of code but just basic allignnment cohesion/ separation. With added 2 look ahead vectors to steer away from the collision.

        desiredDirection := world.Grid.GetDesiredDirectionAt(positionComp.Position, tag)         direction := movementComp.Direction         maxSpeed = movementComp.MovementSpeed          //Avoidance         nearbyEntities := helper.GetNearbyEntities(100, world, index)          avoidance := engine.Zero()         avoidance = avoidance.Add(alignment(world, nearbyEntities, direction).MultiplyScalar(alignmentCoef))         avoidance = avoidance.Add(cohesion(world, nearbyEntities, direction, positionComp.Position).MultiplyScalar(cohesionCoef))         avoidance = avoidance.Add(separation(world, nearbyEntities, direction, positionComp.Position).MultiplyScalar(separationCoef))           //Checking ahead of us whether or not we'll encounter something         lookAheadVectorLong := direction.Add(desiredDirection).MultiplyScalar(maxSpeed * 2.5)         lookAheadVectorShort := direction.Add(desiredDirection).MultiplyScalar(maxSpeed)         maxAvoidanceForce := float32(1.0)          checkPosShort := positionComp.Position.Add(lookAheadVectorShort)         checkPosLong := positionComp.Position.Add(lookAheadVectorLong)          collidedIndexShort := world.Grid.IsPositionFree(index, checkPosShort, positionComp.BoundingBox)         collidedIndexLong := world.Grid.IsPositionFree(index, checkPosLong, positionComp.BoundingBox)          if collidedIndexShort != -1 {             direction = engine.Zero()             avoidance = checkPosShort.Subtract(world.ObjectPool.Components["PositionComponent"][collidedIndexShort].(components.PositionComponent).Position).Normalize()             avoidance = avoidance.MultiplyScalar(maxAvoidanceForce * 1.5)         } else if collidedIndexLong != -1 {             direction = direction.MultiplyScalar(breakingForce)             avoidance = checkPosShort.Subtract(world.ObjectPool.Components["PositionComponent"][collidedIndexLong].(components.PositionComponent).Position).Normalize()             avoidance = avoidance.MultiplyScalar(maxAvoidanceForce * 1.2)         }          direction = desiredDirection         direction = direction.Add(avoidance).Normalize()          positionComp.Position = positionComp.Position.Add(direction.MultiplyScalar(maxSpeed))          positionComp.Position.X = engine.Constraint(positionComp.Position.X, 0, 799)         positionComp.Position.Y = engine.Constraint(positionComp.Position.Y, 0, 511)          movementComp.Direction = direction.Normalize()          world.ObjectPool.Components["PositionComponent"][index] = positionComp         world.ObjectPool.Components["MovementComponent"][index] = movementComp          fmt.Printf("I %d am at %v\n", index, positionComp.Position)     }  }  func limit(p engine.Vector, lim float32) engine.Vector {     if p.X > lim {         p.X = lim     } else if p.X < -lim {         p.X = -lim     }     if p.Y > lim {         p.Y = lim     } else if p.Y < -lim {         p.Y = -lim     }     return p } func alignment(world *game.World, siblings []int, velocity engine.Vector) engine.Vector {     avg := engine.Vector{X: 0, Y: 0}     total := float32(0.0)      for _, siblingIndex := range siblings {         avg = avg.Add(world.ObjectPool.Components["MovementComponent"][siblingIndex].(components.MovementComponent).Direction)         total++     }     if total > 0 {         avg = avg.DivideScalar(total)         avg = avg.Normalize().MultiplyScalar(maxSpeed)         avg = avg.Subtract(velocity)         avg = limit(avg, maxForce)         return avg     }     return engine.Vector{X: 0.0, Y: 0.0}  }  func cohesion(world *game.World, siblings []int, velocity engine.Vector, position engine.Vector) engine.Vector {     avg := engine.Vector{X: 0, Y: 0}     total := float32(0)      for _, siblingindex := range siblings {          avg = avg.Add(world.ObjectPool.Components["PositionComponent"][siblingIndex].(components.PositionComponent).Position)         total++      }     if total > 0 {         avg = avg.MultiplyScalar(1.0 / total * cohesionCoef)         avg = avg.Subtract(position)         avg = avg.Normalize().MultiplyScalar(maxSpeed)         avg = avg.Subtract(velocity)         avg = limit(avg, maxForce)         return avg     }     return engine.Vector{X: 0.0, Y: 0.0} }  func separation(world *game.World, siblings []int, velocity engine.Vector, position engine.Vector) engine.Vector {     avg := engine.Vector{X: 0, Y: 0}     total := float32(0)      for _, siblingIndex := range siblings {         siblingPos := world.ObjectPool.Components["PositionComponent"][siblingIndex].(components.PositionComponent).Position         d := position.Distance(siblingPos)         if d < desiredSeperation {             diff := position.Subtract(siblingPos)             diff = diff.Normalize()             diff = diff.DivideScalar(d)             avg = avg.Add(diff)             total++         }     }     if total > 0 {         avg.DivideScalar(total)     }      if total > 0 {         avg = avg.MultiplyScalar(1.0 / total * separationCoef)         avg = avg.Normalize().MultiplyScalar(maxSpeed)         avg = avg.Subtract(velocity)         avg = limit(avg, maxForce)     }     return avg } 

What I am trying to achieve is:

Units not mashing into each other and just positioning themselves in a free spot around their target.

What are my problems :

  1. Make the flow field direct them away from collision rather than just towards closest unit.
  2. Make it work with the current system without adding too many nested loops and awful checks.
  3. I am doing the avoidance correctly? I have a desired direction that I get from the flow field (that directs me towards closest enemy), then I add avoidance to it to avoid any other units in the area.

My units move really well up untill the point of collision/ going to a spot next to a target. I am not sure how to implemenent that behaviour yet.

(This is my forth iteration of the movement system. I went from pure boid, to grid based, to A*, to this. So I tried a lot of variations and this going surrounding behaviour has been bugging me every time.)

Custom engine (server) written in Golang and then dispatched to Godot for the visuals. Performance is not my concern, but this is a server, so I am more mindful of that, I could probably brute force it but I’d rather hear some better take on it.

Any suggestion/article/ video is greatly appreciated !!

Edit: Thinking about it, flow field is currently useless. I can basically just have a vector pointing to the closest enemy for each unit… Would be less costly as well. But the problem of them clumping and not knowing how to surround still stands.

Table scan instead of index seeks happening when where clause filters across multiple tables in join using OR

We have an application generated query using a view that has two tables joined on a LEFT OUTER join. When filtering by fields from just one table (either table) an index seek happens and it’s reasonably fast. When the where clause includes conditions for fields from both tables using an OR the query plan switches to a table scan and doesn’t utilize any of the indexes.

All four fields that are being filtered on are indexed on their respective tables.

Fast query plan where I filter on 3 fields from one table: https://www.brentozar.com/pastetheplan/?id=Hym_4PRSO

Slow query plan where I filter on four fields…three from one table and one from another table: https://www.brentozar.com/pastetheplan/?id=r1dVNDRHO

Ideally I would like to understand why this is happening and how to nudge the query engine to utilize all the indexes.

GraphicsGrid $\to$ Beep “The shared stylesheet “Stylesheet-review-topics.nb” could not be \ found. The default stylesheet will be used instead.”

12.0.0 for Microsoft Windows (64-bit) (April 6, 2019)

I have a notebook in which using GraphicsGrid causes a beep "The shared stylesheet "Stylesheet-review-topics.nb" could not be found. The default stylesheet will be used instead."

I copied the entire content of the notebook to a new one, set the style sheet to the one shown, and saved over the original notebook. Same thing happens. I created a new notebook and set the style sheet to the one shown, and it does not beep. My notebooks are fairly large, and I really don’t want to spend a lot of time untangling what amounts to a nuisance. I also doing like being annoyed.

This kind of think happens from time to time, and I’m never sure why. Any ideas?

Users (erroneously) type a short URL in the Google search box instead of the address bar. How to make it navigate instead of showing search results?

I’m using a URL shortener to publish pronounceable URLs for my pages so I can tell people something like, "Visit mydomain.com/slug to solve that problem." If people go to the address bar of their browser and enter mydomain.com/slug URL there, then the shortened URL works, and it redirects them to the intended destination page. But if a non-technical user goes to the Google search page and enters mydomain.com/slug into the search box there, apparently, Google apparently isn’t smart enough to recognize that they typed in a URL. It tries instead to search for the URL as keywords and comes back with a list of search results.

When I click "New Tab" in my browser, I know the difference between the address bar and the search box, but many non-technical users don’t, and Google gives the same instructions in both places. Both locations claim to accept both search terms and URLs, but apparently they have different logic for determining which is which. For them to behave differently and not follow the URL when it’s typed into the search box instead of the browser address bar seems to be a fatal flaw in the entire concept of shortened URLs – unless there’s something else I can do to make them work regardless of which field someone types them into. Certainly I can’t be the only one facing this.

What can I do to teach Google that my shortened URL is indeed a URL and when someone types it in the search box, it should go to the place where that URL redirects to?

Can you foresee any balance issue with a Stars Druid using the Cleric spell list instead of the Druid’s?

Homebrewed campaign where tinkering with class mechanics is encouraged to suit your character, I just want to make sure it isn’t horribly unbalanced.

I have an idea for a divination/stars/universe/fate obsessed character, lumbering, slow, strong, wise, warm. Heavy armour melee/mid-field support. However, I don’t really like the Twilight Domain’s Channel Divinity.

The Stars Druid subclass abilities seem like a good match but the spell list leans towards the terrestrial/battlefield control/summoning rather than astral/divination and I don’t see this character ever using wildshape.

Ideas:

  • make a Stars Druid that uses the Cleric spell list and loses wildshape etc

  • make a Twilight Cleric and swap the Channel Divinity (twice per rest resource for most of the game) for one of the Stars Druids abilities?

  • your idea?

Any input and ideas welcome. When homebrew is encouraged I like to troubleshoot for balance.

Can I just hold my Spellcasting Focus, instead of a material (with a price) that I own, to cast a spell?

Let’s say that I want to cast Soul Cage. I know that I need the tiny silver cage worth 100gp. Can I just have it attached to my belt and cast the spell using my Spellcasting focus, or do I need to hold specifically the tiny silver cage?

I’m a Hexblade Warlock with a glaive and the Improved Pact Weapon feature, wich makes my summoned glaive my Spellcasting Focus. I wonder if there’s a way to kill an enemy with my glaive then use my reaction to cast Soul Cage.

Can my Primal Companion roll initiative instead of my character?

In Tasha’s Primal Companion feature it doesn’t say that the beast doesn’t roll initiative, just that it acts during the player’s turn. Is that enough to mean that it’s the player that has to roll initiative?

I assume the answer is yes, but it would be nice if you were playing a strength build ranger, or to take advantage of the Primal Bond.

Should a high elf wizard use weapons instead of cantrips?

As a new DM I’m running my first adventure for my kids (LMoP). My daughter took the high elf wizard and she was wondering whether she should use weapons instead of her cantrips when she runs out of spell slots.

Indeed, high elf being proficient with weapons, she could use a bow who does 1d8+2, adding also the modifier to the attack roll, or a sword instead of shocking grasp for example… When cantrips don’t get any modifiers.

Not really sure what to answer her. Thanks ahead!

My website is showing today’s date instead of published date since db migration to a new wordpress

I exported my database and content to a new WordPress. Everything works fine, except that every post is showing under today’s date, instead of the published date like it should be (the actual published date is the good one in the dashboard though).

It was working correctly in my last WordPress (5.0.11). The new one is 5.6.1. Here’s the PHP related to the date in my theme :

<span class="post-date">     <?php     $  date = date_i18n( get_option( 'date_format' ), strtotime( get_the_date( 'r' ) ) );     printf( esc_html_x( 'PubliƩ le %s', 'PubliƩ le DATE', 'chosen' ), $  date );     ?> </span> 

Any idea what happened?