How to determine which room a player is in? - algorithm

I am working on a 2D platforming video game. The rooms are divided into areas, which are essentially intangible hitboxes. The camera is bounded by these hitboxes, and will not show what is in the next room until the player transitions into a new one.
If the player walks from one room to another, the camera pans to the new room. Panning the camera pauses the physics engine to ensure the player cannot break the game or die while the camera is in it's animation.
My problem exists in the fact that the player doesn't belong to a single room at a time since the player's hitbox is 2D. When the player moves between rooms, for a short period of time, the hitbox overlaps two rooms at once.
This means, that if I pan the camera when the player enters a new room, the player can partially enter the new room (while still remaining in the old room), then go back into the old room, which doesn't pan the camera back because they never technically entered the old room. How could they have entered it? They never left it!
This also means, that if I pan the camera upon the player leaving a room, the player can partially enter a new room, then leave the new room that they never fully entered. This means that the camera pans to the same room that it was already in (this plays a weird animation, and pauses the physics engine).
How can I determine what room the camera should pan to?
I have access to:
When the player enters a room, and which room.
When the player exits a room, and which room.
All rooms, and the variables of all rooms.
func _on_room_area_2d_body_entered(body): # body enters room
if body.is_in_group("junko"): # is this the player?
player_inside = true
junko.pan_camera(self) # pan the camera
func _on_room_area_2d_body_exited(body): # body exits room
if body.is_in_group("junko"): # is this the player?
player_inside = false

Just because the rooms are big, it does not mean they have to keep track of what is inside of them. Instead, the character can keep track of inside of which rooms it is.
If you want to detect areas, you need an area. So make an area child of your player character… Which I'll call locator. Then set the locator up to detect the areas that make up the rooms. That means that locator must be monitoring, and the rooms must be monitorable. And also the collision layer of the rooms must overlap the collision mask the locator.
Then you can use area_entered and area_exited (notice these signals are called area_* not body_*).
You might find it easier to call get_overlapping_areas on the detector in _physics_process and then from the result pick the rooms.
for entry in $locator.get_overlapping_areas():
prints(entry)
Then perhaps only pan the camera when there is only one room and it is not the one where the camera is currently at, or some similar rule.
In fact, you don't need a detector. You can do what "Yakov Galka" suggested in the comments and ask Godot what areas are in a particular point.
You do that with intersect_point:
var result:Array = get_world().direct_space_state.intersect_point(
global_position,
32,
[],
2147483647,
false,
true
)
And that returns an Array with the results. So you can iterate like this:
for entry in result:
prints(entry.collider)
To explain the parameters:
First you pass the point coordinates global_position.
Second you pass how many result you want at most (32 in this case).
Then you pass an array with elements you want to exclude (none in this case: []).
Then the collision mask (2147483647 is all the bits)
Then if you want bodies (no, so false)
And finally if you want areas (yes, so true).
Please notice that even though this is only checking a single point, it does not guarantee you have a single result (you can have multiple if the areas overlap).

Related

A better way to roll dice

I have a game that requires the player to roll two die. As this is a multiplayer game, the way I currently do this is have 6 animations (1 for each die's outcome). When the player clicks a button, it sends a request to my server code. My server code determines the die's outcome and sends the results to the client. The client then plays the corresponding animations.
This works ok, but has some issues. For instance, if the server sends back two of the same values (two 6's, for example) then the animations don't work correctly. As both animations are the same, they overlay each other, and it looks like only one die was rolled.
Is there a better way to do this? Instead of animations, using "real" dice? If that's the case, I always need to be sure to "pre-determine" the outcome of the dice roll, on the server. I also need to make sure the dice don't fall off the table or jostle any of the other player pieces on the board.
thanks for any ideas.
The server only needs to care about the value result, not running physics calculations.
Set up 12 different rolling animations:
Six for the first die
Six for the second die
Each one should always end with the same modeled face pointing upwards (the starting position isn't relevant, only the ending position). For the latter steps you'll probably want to adjust the model's UV coordinates to use a very tall or very wide texture (or just a slice of a square one). So not like this but rather all in a line 1-2-3-4-5-6.
The next step is picking a random animation to play. You've already got code to run a given animation, just set it to pick randomly instead of based on the die-roll-value from the server:
int animNum = Mathf.Floor(Random.Next()*6);
Finally, the fun bit. Adjusting the texture so that the desired face shows when the animation is done. I'm going to assume that you arrange your faces along the top edge of your square texture. Material.SetTextureOffset().
int showFace = Mathf.Floor(Random.Next()*6); //this value should come from the server
die.renderer.material.SetTextureOffset(1f/6 * showFace,0);
This will set the texture offset such that the desired face will show on top. You'll even be able to see it changing in the inspector. Because of the UVs being arranged such that each face uses the next chunk over and because textures will wrap around when reaching the edge (unless the texture is set to Clamp in its import settings: you don't want this here).
Note that this will cause a new material instance to be instantiated (which is not very performant). If you want to avoid this, you'll have to use a material property block instead.
You could simulate the physics on the server, keep track of the positions and the orientations of the dice for the duration of the animation, and then send the data over to the client. I understand it's a lot of data for something so simple, but that's one way you can get the rolls to appear realistic and synced between all clients.
If only Unity's physics was deterministic that would be a whole lot easier.

Plat former Game - A realistic path-finding algorithm

I am making a game and i have come across a hard part to implement into code. My game is a tile-bases platformer with lots of enemies chasing you. basically, in theory, I want my enemies to be able to, every frame/second/2 seconds, find the realistic, and shortest path to my player. I originally thought of A-star as a solution, but it leads the enemies to paths that defy gravity, which is not good. Also, multiple enemies will be using it every second to get the latest path, and then walk the first few tiles of it. So they will be discarding the rest of the path every second, and just following the first few tiles of it. I know this seems like a lot, to calculate a new path every second, all at the same time, if their is more than one enemy, but I don't know any other way to achieve what i want.
This is a picture of what I want:
Explanation: The green figure is the player, the red one is an enemy. the grey tiles are regular, open, nothing there tiles, the brown tiles being ones that you can stand on. And finally the highlighted yellow tiles represents the path that i want my enemy to be able to find, in order to realistically get to the player.
SO, the question is: What realistic path-finding algorithm can i use to acquire this? While keeping it fast?
EDIT*
I updated the picture to represent the most complicated map that their could be. this map represents what the player of my game actually sees, they just use WASD and can move around and they see themselves move through this 2d plat-former view. Their will be different types of enemies, all with different speeds and jump heights. but all will have enough jump height and speed to make the jumps in this map, and maneuver through it. The maps are generated by simply reading an XML file that has the level data in it. the data is then parsed and different types of tiles are placed in the tile holding sprite, acording to what the XML says. EX( XML node: (type="reg" graphic="grass2" x="5" y="7") and so the x and y are multiplied by the constant gridSize (like 30 or something) and they are placed down accordingly. The enemies get their frame-by-frame instruction from an AI class attached to them. This class is responsible for producing this path and return the first direction to the enemy, this should only happen every second or so, so that the enemies don't follow a old, wrong path. Please let me know if you understand my concept, and you have some thought/ideas or maybe even the answer that i'm looking for.
ALSO: the physics in this game is separate from the pathfinding, they work just fine, using a AABB vs AABB concept (the player and enemies also being AABBs).
The trick with using A* here is how you link tiles together to form available paths. Take for example the first gap the red player would need to cross. The 'link' to the next platform (aka brown tile to the left) is actually a jump action, not a move action. Additionally, it's up to you to determine how the nodes connect together; I'd add a heavy penalty when moving from a gray tile over a brown tile to a gray tile with nothing underneath just for starters (without discouraging jumps that open a shortcut).
There are two routes I see personally: running a quick prediction of how far the player can jump and where they'd jump and adjusting how the algorithm determines node adjacency or accept the path and determine when parts of the path "hang" in the air (no brown tile immediately below) and animate the enemy 'jumping' to the next part of the path. The trick is handling things when the enemy may pass through brown tiles in the even the path isn't a parabola.
I am not versed in either solution; just something I've thought about.
You need to give us the most complicated case of map, player and enemy behaviour (including jumping up and across speed) that you are going to either automatically create or manually create so we can give relevant advice. The given map is so simple, put the map in an 2-dimensional array and then the initial player location as an element of that map and then first test whether lower number column on the same row is occupied by brown if not put player there and repeat until false then same row higher column and so on to move enemy.
Update: from my reading of the stage generation- its sometime you create- not semi-random.
My suggestion is the enemy creates clones of itself with its same AI but invisible and each clone starts going in different direction jump up/left/right/jump diagonal right/left and every time it succeeds it creates a new clone- basically a genetic algorithm. From the map it seems an enemy never need to evaluate one path over another just one way fails to get closer to the player's initial position and other doesn't.

Need algorithm to draw overlapping rectangles

I need help with efficiently drawing/culling a series of opaque rectangles, in other words, this is a stack of index cards on a desk. The specifics are:
no rotations, so everything is simple integer coordinates, axis-aligned
cards are fully opaque
cards can have any integer X,Y position
all cards are the same size
I have a list of the cards in z-order
I think I have (essentially) two choices:
1) brute force painter's approach, where all cards within the desktop viewport are fully drawn, in reverse z-order. Pros: simple. Cons: a) requires an off-screen buffer to avoid flicker, b) potentially lots of time wasted on drawing expensive areas of each card when that area might end up being obscured, worst-case being the entire card getting covered.
2) an algorithm that generates a list of visible (or obscured) rectangles for every card, such that only visible portions are ever drawn.
Choice 2 is where I need advice, especially in terms of algorithms, and pro's and con's of a "smarter" draw cycle.
Any language/platform agnostic advice is appreciated. If it matters, this will be implemented on MS Windows.
Am open to any suggestions, including hybrid approaches. I realize a precise answer is likely very dependent on the particulars of the code, but I'd be happy even with generalized concepts at this point!
Additional notes: It will be possible to have thousands of cards stacked on top of each other, so I'm highly motivated to avoid a purely brute force painter's approach - at least without some sort of pre-processing to cull out fully obscured cards. The same goes for lots of cards that were closely tiled, worse case being only their borders showing - I would like to skip painting the complex innards in those cases, if possible.
What about painting only the contour line of each card from the bottom most to the top most? Then you can do a flood fill to paint inside of the contours. This way you would repaint only a few pixels corresponding to the borders where there are intersections.
Edit: Uploaded images to help me explain the idea.
The first step is mark the borders of the cards assigning their Z-order (top left image). This way, there are overwrites, but only on borders which are a little amount of pixels.
After that, you can paint the texture of the cards (lowest Z-order first) following two rules:
You start from the border and paint the blanks until reach a border;
If the border's Z-order is the current one, you paint it;
If the border's Z-order found is less than the current Z-order, you continue painting as it were a blank one;
Otherwise, you found a border with greater Z-order, so you skip that block;
Next card.
Hope it helps :)
OK, here's some loose pseudo code for how I think this problem can be solved.
Begin with a z-order sorted list of the cards. Each card has a list of visible rects (explained later), that needs to start out with just one rect, set to the card's full bounding box. The loop is begun with the lowest z-order card first.
Cards.SortZOrder();
foreach Card in Cards do
Card.ResetVisibleRects; // VisibleRects.DeleteAll; VisibleRects.Add(BoundingBox);
CurrentCard = Cards.Last;
TestCard = CurrentCard;
The idea here is that we're going to work upwards from our "current" card, and see what effect each higher card has on it. There are 3 possibilities as we test each higher card. It either completely misses, completely obscures, or partially obscures. For a complete miss, we ignore the test card, since it doesn't affect our current card. For a complete obscure, our current card gets culled. A partial overlap is where the list of visible rectangles comes in, since partial overlap can (potentially) split the lower rectangle into two. (It's easy to see how this plays out if you just grab two playing cards, or index cards. The top one causes the bottom one to either adjust one of it's sides, if they share any edge, or it causes the bottom one to split into two rects if they share no edges.)
Caveat: This is VERY unoptimized, unrolled code ... just for talking about the principles. And yes, I'm about to use "goto" ... mock me if you must.
[GetNextCard]
TestCard = Cards.NextHighest(TestCard);
[OverlapTest]
// Test the overlap of TestCard against all our VisibleRects.
// The first time through this test, CurrentCard will have only one
// rect in the VisibleRect list, but that rect may get split up later.
// OverlapTests() checks each rect in the VisibleRects list, and
// creates an Overlap record for any of the rects that do overlap,
// like: Overlap.RectIndex, Overlap.Type. It also summarizes the
// results into the .Summary field.
Result = CurrentCard.OverlapTests(TestCard);
case Result.Summary
none:
goto [GetNextCard];
complete:
CurrentCard.Culled = true;
// we're now done with this CurrentCard, so we move upwards
CurrentCard = TestCard;
goto [GetNextCard]
partial:
// since there was some overlap, we need to adjust,
// split, or delete some or all of our visible rectangles.
// (we won't delete them all, that would have been caught above)
foreach Overlap in Result.Overlaps
R = CurrentCard.VisibleRects[Overlap.RectIndex];
case Overlap.Type
partial: CurrentCard.SplitOrAdjust(R, TestCard);
complete: CurrentCard.Delete(R);
end case
// so we've either added new rects, or deleted some, but either
// way, we're done with this test card. We leave CurrentCard
// where it is and loop to look at the next higher card.
goto [GetNextCard]
The testing is done when CurrentCard = Cards.First since the topmost card is always fully visible.
Just a couple more thoughts here ...
I think this would be fairly straightforward in real code. The most complicated thing about it would be splitting a rectangle into two, and given the fact that it's all integer math, even that is trivial.
Also, this doesn't have to be performed every paint cycle. It only needs to be done when there's any change in contents, position, or z-order.
After a pass up the list, you're left with a paint-ready list of cards, each non-culled card having at least one rectangle that can potentially fall within the display's clipping/dirty region. When you paint a card you can examine its list of visible rectangles, and potentially be able to skip drawing portions of the card that might be expensive to render.

Where Should Collision Detection Code Be?

I'm writing a pong game and I have a ball class that has velocity x, y, positions and all that stuff that every frame is updated by calling #ball.update, this moves the ball forward by its x_vel and Y_vel etc. My question is Should my collision code be in the loop or in the update method of the ball class? Or should it all be in the loop and the ball should not have any control of its position?
The collision detection should not be done in you ball class because it would require the knowledge of all other objects in your game.
Imagine a shooter with many objects and think about what happens if each object would try to calculate the collision on it's own.
There should be a dedicated class that cares about collision detection. This class is notified if any of its supervised objects changed its position. Then it checks for collision and notifies all abjects (not only 2 :) that have a collsion.
Have fun... :)
A Ball class like you described is indeed a good idea. That way you can replicate it if, like in some "breakout" games, you ever want to spawn two or more balls -- or if you want to re-use that code in another game. You can also have a Paddle class with similar X,Y coordinates (or derive both Ball and Paddle from a "ScreenObject" class if they turn out to share many such similar members). Paddle can read a shared variable that gets updated by a thread/event receiving user input.
Simple collisions, such as against walls, can be done in your Ball class based on globally accessible values like the screen dimension extents. Your Update routine can simply reverse one velocity component when that particular wall is hit. You can define and set a delegate/callback in the Ball class to play a sound when the ball bounces. Similarly, Paddle's Update can check the screen size so you can't move the paddle off-screen.
Like TottiW recommended, collision between objects is best done in a parent "manager" class that owns all the objects or has access to their X,Y members or bounding boxes. This is good object-oriented design. Ball and Paddle shouldn't have access to each other's X,Y positions! ...but the manager does. It can also eliminate redundant collision checks. If object A checks to collide with object B, B shouldn't have to subsequently check for collision with A. So really all your manager class needs to do is, for each Paddle, check each Ball's position. This can be further simplified since a Paddle might only move in one direction, say horizontally, at a fixed Y position. Thus your first check can immediately eliminate any Ball.Y < Paddle.Y, for simplistic example (depending on Y's direction).
For games with lots of objects, you don't want to collison-detect every one, just the nearest ones. In that case, the "manager" becomes more of a "scene manager" which keeps linked lists of objects in both X and Y directions. As objects move past other objects, they exchange pointers in the lists, so the lists always stay sorted. That way, for any given object, we know the objects immediately to the left/right/above/below, so we need only do collision checks against those... saving lots of time and making your game run with maximum speed. Maybe you're not to this point, though!
Good luck and like the others have said, have fun with it!
For pong simple matrix operations should be sufficient. A ball class is not needed if there is only one and you use it only for holding a tuple.

How to deal with animating in-between states when the model is discrete

The data model in my program has a number of discrete states, but I want to animate the transition between these states. While the animation is going on, what the user sees on the screen is disconnected from what the underlying data is like. Once the animation is complete, they match up again.
For example, let's say we have a simple game where Snuffles the bunny hops around on a 2D grid. The model of Snuffles contains integer x/y coordinates. When the player tells Snuffles to hop north, his y-coordinate is decremented by one immediately. However, on the screen, Snuffles should at that point still be in his old location. Then, frame by frame, Snuffles proceeds to hop over to his new location, until he is shown in the location his model states.
So usually, when we draw Snuffles, we can just look up his coordinates in his model. But when he's hopping, that coordinate is wrong.
If there is only ever one thing moving on the screen, I can just about get away with freezing the entire game state and not allowing the user to do anything until Snuffles has finished hopping. But what if there is more than one bunny on the screen?
It gets worse if elements interact, merge or split. If Snuffles magically merges with a hat to become a potato, at which point does the data model delete the bunny and the hat, and add the potato? If it does so immediately, the view instantly loses access to information about Snuffles and the potato which it still needs to draw the animation of the magical merger.
I have come across this problem multiple times while implementing animated GUIs, especially games, and have found no satisfactory solution.
Unsatisfactory ones include:
Do the changes immediately, but then suspend any further changes in the model until the animation has resolved. Makes things unresponsive and doesn't work if more than one thing can move or things interact in complex ways.
Merge the model and the view - Snuffles gains floating-point coordinates, and probably a z-coordinate to indicate how far up he is. The model's rules become massively more complex as a result, as the model can no longer make concise statements like "you cannot hop north if there is a wall at (x, y - 1)". Any change to the rules takes much longer, and development slows to a crawl.
Keep what amounts to a duplicate of the data in the view. SnufflesModel has integer coordinates, but SnufflesSprite has floating-point ones. End up duplicating some of the model rules in the view and having to keep them in sync. Spend lots of time debugging to make sure that SnufflesModel and SnufflesSprite don't de-sync under some rare circumstance.
My best bet at the moment is option 3, but it hardly strikes me as elegant. Thoughts?
You would need a stronger model to account for the time component of changes:
Each sprite needs to maintain a queue of animation actions it is supposed to carry out. Adding animations to the queue should be a zero-time action (game time). Queued animations proceed on a frame-by-frame basis when they get a tick from the animation clock. Queuing lets you separate the model from the graphics subsystem and the animations.
Each animation in the queue carries with it a model action to perform when the animation is complete. Some languages make that easier, e.g. with anonymous functions in C# or JavaScript. In other languages, you could use a callback instead. The model action lets you specify how the model would change when the animation completes.
Sprites can carry high resolution coordinates (e.g. floating point), while the model stays with integer ones. Sprites don't need to know anything about the game rules though -- the queued animation-completion model-actions deal with that.
Model entities should be able to account for a transitional states: appearing, disappearing, and moving. This lets you avoid checking the rules for objects in transition.
To implement Snuffle's quest, you could then:
User asked to move Snuffle north? -(1) check that the rules allow the move, (2) queue a move animation on Snuffle's sprite, coupled with a landing model action. Put the bunny's model into a transitional moving state.
Snuffle's landing model action brings the bunny's model back to a normal state, and checks the landing spot and the rules. Finding a hat, it queues a potato appearance animation (the "merger") and two disappearance animations for the bunny and hat.
The model actions for the disappearance animations delete the bunny and hat when complete.

Resources