The map is made by a two dimensional array of a class I made called Tile.
Each tile has smaller tiles inside of it that either collide with units, or don't.
But how can I detect and prevent collision?
Let's say The player is 6x6 smaller(mentioned above) tiles large, and one normal tile is 8x8.
How do I know that when the player is moving to the right that I know a tile is there, and move enough so they won't overlap?
As required by the rules.. I need to show effort, so this is what I have so far:
If the player is 6x6 and one tile is 8x8, then that means the player will either be on one tile, or be between 2 tiles; when he is standing between tiles(Units aren't bound to tiles). So let's say the player is in between two tiles, and wants to move right:
I check the collision of the tile right of the first (of two tiles the player is in) tile, then I check the second. To be able to move right, both must be empty.
But if a unite is say 10x10 large, then It can be in 2 tiles, or 3 max. How do I constantly check collision if I know that sizes of each unit are different, and aren't constant.
Basically, I need help with the stuff above, or a new collision method.
If I understand your question correctly, it is the smaller tiles that cause collisions, not the larger ones. In this case, you can simply iterate through all of the small tiles the unit would cross in a given move, stopping if you encounter one that would halt the unit's progress.
As an example, here is a method that would handle moving a unit right:
void moveUnitRight(Unit unit, int tilesRight)
{
for(int col = unit.Right + 1 ; col <= unit.Right + tilesRight ; col++)
{
for(int row = unit.Top ; row <= unit.Bottom ; row++)
{
if (tiles[row,col].Collides) //stop unit here
{
unit.Right = col - 1; //set position to tile left of collision
return; //search no further
}
}
}
//if you reach this point, no collision was detected
unit.Right += tilesRight; //move the full distance
}
Once you understand this, you could write a more robust method that handles movement in any direction as well as checking for map boundaries.
Related
I want to detect pixel-perfect collisions between 2 sprites.
I use the following function which I have found online, but makes total sense to me.
static bool PerPixelCollision(Sprite a, Sprite b)
{
// Get Color data of each Texture
Color[] bitsA = new Color[a.Width * a.Height];
a.Texture.GetData(0, a.CurrentFrameRectangle, bitsA, 0, a.Width * a.Height);
Color[] bitsB = new Color[b.Width * b.Height];
b.Texture.GetData(0, b.CurrentFrameRectangle, bitsB, 0, b.Width * b.Height);
// Calculate the intersecting rectangle
int x1 = (int)Math.Floor(Math.Max(a.Bounds.X, b.Bounds.X));
int x2 = (int)Math.Floor(Math.Min(a.Bounds.X + a.Bounds.Width, b.Bounds.X + b.Bounds.Width));
int y1 = (int)Math.Floor(Math.Max(a.Bounds.Y, b.Bounds.Y));
int y2 = (int)Math.Floor(Math.Min(a.Bounds.Y + a.Bounds.Height, b.Bounds.Y + b.Bounds.Height));
// For each single pixel in the intersecting rectangle
for (int y = y1; y < y2; ++y)
{
for (int x = x1; x < x2; ++x)
{
// Get the color from each texture
Color colorA = bitsA[(x - (int)Math.Floor(a.Bounds.X)) + (y - (int)Math.Floor(a.Bounds.Y)) * a.Texture.Width];
Color colorB = bitsB[(x - (int)Math.Floor(b.Bounds.X)) + (y - (int)Math.Floor(b.Bounds.Y)) * b.Texture.Width];
if (colorA.A != 0 && colorB.A != 0) // If both colors are not transparent (the alpha channel is not 0), then there is a collision
{
return true;
}
}
}
//If no collision occurred by now, we're clear.
return false;
}
(all the Math.floor are useless, I copied this function from my current code where I'm trying to make it work with floats).
It reads the color of the sprites in the rectangle portion that is common to both sprites.
This actually works fine, when I display the sprites at x/y coordinates where x and y are int's (.Bounds.X and .Bounds.Y):
View an example
The problem with displaying sprites at int's coordinates is that it results in a very jaggy movement in diagonals:
View an example
So ultimately I would like to not cast the sprite position to int's when drawing them, which results in a smooth(er) movement:
View an example
The issue is that the PerPixelCollision works with ints, not floats, so that's why I added all those Math.Floor. As is, it works in most cases, but it's missing one line and one row of checking on the bottom and right (I think) of the common Rectangle because of the rounding induced by Math.Floor:
View an example
When I think about it, I think it makes sense. If x1 is 80 and x2 would actually be 81.5 but is 81 because of the cast, then the loop will only work for x = 80, and therefore miss the last column (in the example gif, the fixed sprite has a transparent column on the left of the visible pixels).
The issue is that no matter how hard I think about this, or no matter what I try (I have tried a lot of things) - I cannot make this work properly. I am almost convinced that x2 and y2 should have Math.Ceiling instead of Math.Floor, so as to "include" the last pixel that otherwise is left out, but then it always gets me an index out of the bitsA or bitsB arrays.
Would anyone be able to adjust this function so that it works when Bounds.X and Bounds.Y are floats?
PS - could the issue possibly come from BoxingViewportAdapter? I am using this (from MonoExtended) to "upscale" my game which is actually 144p.
Remember, there is no such thing as a fractional pixel. For movement purposes, it completely makes sense to use floats for the values and cast them to integer pixels when drawn. The problem is not in the fractional values, but in the way that they are drawn.
The main reason the collisions are not appearing to work correctly is the scaling. The colors for the new pixels in between the diagonals get their colors by averaging* the surrounding pixels. The effect makes the image appear larger than the original, especially on the diagonals.
*there are several methods that may be used for the scaling, bi-cubic and linear are the most common.
The only direct(pixel perfect) solution is to compare the actual output after scaling. This requires rendering the entire screen twice, and requires the scale factor more computations. (not recommended)
Since you are comparing the non-scaled images your collisions appear to be off.
The other issue is movement speed. If you are moving faster than one pixel per Update(), detecting per pixel collisions is not enough, if the movement is to be restricted by the obstacle. You must resolve the collision.
For enemies or environmental hazards your original code is sufficient and collision resolution is not required. It will give the player a minor advantage.
A simple resolution algorithm(see below for a mathematical solution) is to unwind the movement by half, check for collision. If it is still colliding, unwind the movement by a quarter, otherwise advance it by a quarter and check for collision. Repeat until the movement is less than 1 pixel. This runs log of Speed times.
As for the top wall not colliding perfectly: If the starting Y value is not a multiple of the vertical movement speed, you will not land perfectly on zero. I prefer to resolve this by setting the Y = 0, when Y is negative. It is the same for X, and also when X and Y > screen bounds - origin, for the bottom and right of the screen.
I prefer to use mathematical solutions for collision resolution. In your example images, you show a box colliding with a diamond, the diamond shape is represented mathematically as the Manhattan distance(Math.Abs(x1-x2) + Math.Abs(y1-y2)). From this fact, it is easy directly calculate the resolution to the collision.
On optimizations:
Be sure to check that the bounding Rectangles are overlapping before calling this method.
As you have stated, remove all Math.Floors, since, the cast is sufficient. Reduce all calculations inside of the loops not dependent on the loop variable outside of the loop.
The (int)a.Bounds.Y * a.Texture.Width and (int)b.Bounds.Y * b.Texture.Width are not dependent on the x or y variables and should be calculated and stored before the loops. The subtractions 'y-[above variable]` should be stored in the "y" loop.
I would recommend using a bitboard(1 bit per 8 by 8 square) for collisions. It reduces the broad(8x8) collision checks to O(1). For a resolution of 144x144, the entire search space becomes 18x18.
you can wrap your sprite with a rectangle and use its function called Intersect,which detedct collistions.
Intersect - XNA
I want to create a script to automatically click on a moving target on a game.
To do this I want to check colours on the screen to determine where my target is and then click him, repeating this if he moves.
I'm not skilled at programming and there might be an easier solution to what I have proposed below:
1/Split the screen into equal tiles - size of tile should represent the in game object.
2/Loop through each pixel of each tile and create a histogram of the pixel colours.
3/If the most common recorded colour matches what we need, we MIGHT have the correct tile. Save the coords and click the object to complete task
4/Every 0.5 seconds check colour to determine if the object has moved, if it hasnt, keep clicking, if it has repeat steps 1, 2 and 3.
The step I am unsure of how to do technically is step 1. What data structure would I need for a tile? Would a 2D array suffice? Store the value of each colour in this array and then determine if it is the object. Also in pseudo how would I split the screen up into tiles to be searched? The tile issue is my main problem.
EDIT for rayryeng 2:
I will be using Python for this task. This is not my game, I just want to create a macro to automatically perform a task for me in the game. I have no code yet, I am looking more for the ideas behind making this work than actual code.
3rd edit and final code:
#!/usr/bin/python
import win32gui, win32api
#function to take in coords and return colour
def colour_return(x,y):
colours = win32gui.GetPixel(win32gui.GetDC(win32gui.GetActiveWindow()), x,y)
return colours
def click(x,y):
win32api.SetCursorPos((x,y))
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,x,y,0,0)
win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,x,y,0,0)
#variable declaration
x = 1
y = 1
pixel_value = []
colour_found = 0
while x < 1600:
pixel_value = colour_return(x,y)
if pixel_value == 1844766:
click(x,y)
x=x+1
#print x
print y
if x == 1600:
y=y+1
x=1
#print tile
pixel_value = 0
This is the final code that I have produced. It works but it is incredibly slow. It takes 30 seconds seconds to search all 1600 pixels of y=1. I guess it is my method that is not working. Instead of using histograms and tiles I am now just searching for a colour and clicking the coordinates when it matches. What is the fastest method to use when searching an entire screen for a certain colour? I've seen colour detection bots that manage to keep up every second with a moving character.
I'm wondering why the following thing does not work correctly.
Before the nodes are drawn, I analyze if two specific nodes intersect by using:
[[self playerSpriteNode] intersectsNode: [self pSKLabelNode]]
When pSKLabelNode touches desiredSpriteNode it works perfect! (By returning true, or false when it doesn't intersect)
But when it "passes" by a few pixels away from the SKLabel it still intersects and returns true.
Is there some setup that are recommended to fix the frame size of the nodes, or solutions that you think that will fix the problem?
I have the same problem when I try to intersects static node (that located left) with node that have rotation (and flying from the right side). I fix it like this
if ([ninja intersectsNode:node] &&
CGRectGetMinX(node.frame) <= CGRectGetMaxX(ninja.frame) &&
CGRectGetMaxX(node.frame) >= CGRectGetMinX(ninja.frame))
{
//and here I have intersects
}
So I fix it by adding additional parameters
The intersectNode method is optimized for running fast on devices with lots of iterations per second. Due to this, it actually "estimates" collision based on math, which sometimes goes wrong at a margin of a few pixels, specially when we are speaking of square corners of PNGs.
I had this problem once too, and since i used circles I calculated distance between circles as a second verification.
So, what you can do is a custom verification INSIDE the intersectsNode if case. Assuming you handle squares, you could verify wether the x or y collides after the intersectNode. It could be something like like:
if([[self playerSpriteNode] intersectsNode: [self pSKLabelNode]]){
if(distance between x1 and x2 < size1.width/2 + size2.width/2 || distance between y1 y2 < size1.height/2 + size2.height/2){
//Your code goes here
}
}
Note that we compare central x distances with half each widths summed. This is only an example that works with squares, and most generic sprites.
I would like to point out that, while intersectsNode is slightly imprecise, this is NEEDED in order to run your game swiftly, as perfect and precise calculations per update can be very exhaustive to your device.
So, should you do a custom verification, ALWAYS call it after intersectsNode returns true, as a second verification rather than the only one.
The answer provided above by Roman pretty much does what i said, in shorter code; I just wanted to leave an explanation about why.
Swift 2.1:
For increased results do your check in the update( _:) loop, is where things happen before the next drawing:
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
if goodDude.intersectsNode(badDude){
print("bad dude v.s. Ninja")
}else{
print("not dude at all")
}
}
How to traverse the peg through all the squares in a Monopoly type board Game ?
I have written a function for the movepegbutton which on click moves the peg to the destination position which it gets from the random generated number.
This is what I have written so far for the Move peg Button.
(IBAction)movePegButton:(id)sender
{
self.pegDestinationPositionIndex = self.pegCurrentPositionIndex + self.randomNumber;
if (self.pegDestinationPositionIndex > [self.boardCordinatesArray count] - 1)
{
self.pegDestinationPositionIndex = self.pegDestinationPositionIndex - [self.boardCordinatesArray count];
}
[self animatePeg];
self.pegCurrentPositionIndex = self.pegDestinationPositionIndex;
}
This is what I have written to animate the peg.
(void)animatePeg
{
int destinationXCord = [[[self.boardCordinatesArray objectAtIndex:self.pegDestinationPositionIndex] objectForKey:#"x"]intValue];
int destinationYCord = [[[self.boardCordinatesArray objectAtIndex:self.pegDestinationPositionIndex] objectForKey:#"y"]intValue];
[UIView animateWithDuration:1.0 animations:^{
self.peg.center = CGPointMake(destinationXCord, destinationYCord);
}];
}
So far the peg moves correctly to the destination square but it is not traversing through all the squares in its way, for e.g. if it is 8X8 square, for first run dice rolls 6, the peg moves correctly to 6th square, for second run dice rolls 5, the peg moves correctly to the destination square but it directly jumps over to that position diagonally, it doesn't traverse the squares which it has in its way.
I am stuck here, how should i do it ??
So your peg is supposed to walk in a square, ei. follow the edge of the board, but instead cuts corners, am I right?
If I am so, then the answer is very straight forward. To make sure that the peg follows the squares lain on the board, you must make it move to every square in the path from source square to destination square, otherwise it will simply cut the corner and go straight for the destination square.
If the player rolls a 4, and is standing on square 9 and must reach square 13. Then instead of making the peg move directly to square 13, I would force the peg to go first to 10, then 11, then 12 and then at last square 13.
Of course if the squares are aligned in a square manor, that is; four edges, then some optimization could be done, and only split up the path if a corner is in between the source square and the destination square.
And of course this optimization could also be applied even though the squares are not aligned in a square like manor, just as long as it follows some path, and you know where the 'corners' are.
Edit:
To try and test my paint skills and to try and visualize the problem at hand, I have created something within paint.
What you are doing in the presented code is Case 1. You are doing a single animation when moving the peg. What you really want do is Case 2, here your function -(void)animatePeg; should recognize that the destination square is more than 1 square away, and therefore not do a single move animation, but a series of move animations, to be more precise, the number of animations is always indexOfDestinationSquare - indexOfSourceSquare. So in the illustrated case, the peg should do a total of eight move animations instead of only one.
Case 3 shows how this process could be optimized by recognizing the direction of the move, and only split when going around a corner.
I hope this clarifies what approach I would take. To do this approach you need to extend your -(void)animatePeg; function to be able to split up the single move into a series of moves, and then animate the moves one-by-one.
How to make a 2d world with fixed size, which would repeat itself when reached any side of the map?
When you reach a side of a map you see the opposite side of the map which merged togeather with this one. The idea is that if you didn't have a minimap you would not even notice the transition of map repeating itself.
I have a few ideas how to make it:
1) Keeping total of 3x3 world like these all the time which are exactly the same and updated the same way, just the players exists in only one of them.
2) Another way would be to seperate the map into smaller peaces and add them to required place when asked.
Either way it can be complicated to complete it. I remember that more thatn 10 years ago i played some game like that with soldiers following each other in a repeating wold shooting other AI soldiers.
Mostly waned to hear your thoughts about the idea and how it could be achieved. I'm coding in XNA(C#).
Another alternative is to generate noise using libnoise libraries. The beauty of this is that you can generate noise over a theoretical infinite amount of space.
Take a look at the following:
http://libnoise.sourceforge.net/tutorials/tutorial3.html#tile
There is also an XNA port of the above at: http://bigblackblock.com/tools/libnoisexna
If you end up using the XNA port, you can do something like this:
Perlin perlin = new Perlin();
perlin.Frequency = 0.5f; //height
perlin.Lacunarity = 2f; //frequency increase between octaves
perlin.OctaveCount = 5; //Number of passes
perlin.Persistence = 0.45f; //
perlin.Quality = QualityMode.High;
perlin.Seed = 8;
//Create our 2d map
Noise2D _map = new Noise2D(CHUNKSIZE_WIDTH, CHUNKSIZE_HEIGHT, perlin);
//Get a section
_map.GeneratePlanar(left, right, top, down);
GeneratePlanar is the function to call to get the sections in each direction that will connect seamlessly with the rest of your world.
If the game is tile based I think what you should do is:
Keep only one array for the game area.
Determine the visible area using modulo arithmetics over the size of the game area mod w and h where these are the width and height of the table.
E.g. if the table is 80x100 (0,0) top left coordinates with a width of 80 and height of 100 and the rect of the viewport is at (70,90) with a width of 40 and height of 20 you index with [70-79][0-29] for the x coordinate and [90-99][0-9] for the y. This can be achieved by calculating the index with the following formula:
idx = (n+i)%80 (or%100) where n is the top coordinate(x or y) for the rect and i is in the range for the width/height of the viewport.
This assumes that one step of movement moves the camera with non fractional coordinates.
So this is your second alternative in a little bit more detailed way. If you only want to repeat the terrain, you should separate the contents of the tile. In this case the contents will most likely be generated on the fly since you don't store them.
Hope this helped.