I've spent many frustrating hours and cannot figure this out, i understand collision and have it working until i try to implement gravity, i cant seem to set the player position after it hits the tile map, falling through the ground is my problem, x axis a variation of the following code works fine
if (background.colMap[tiles[i].y][tiles[i].x] == 1)
{
playerSpeed.y = -0.f;
playerSprite.setPosition(playerSprite.getPosition().x, playerSprite.getPosition().y - 1);
inAir = false;
}
I though by reducing the speed to 0 and bumping the player back 1 pixel would work, but all it does is the player sprite bounces up and down
Given the above information, I assume you're making a side-scrolling game, and your character is colliding with the top of a tile.
That said, the first thing you need to understand is that you're not supposed to adjust the position of the character after it moved but before it moved. The character is never supposed to be in a position that is "illegal" in your game. Even for a fraction of a second.
You have the power to see the future (at least in your own game), use it at will! Always be one step ahead.
How to find the right place?
Basic algebra!
Here's the situation.
The goal here is to find where the green and red dotted line cross the small blue dotted line (which represent the ground).
First, we need to find the equation of our character (black dot) trajectory, which should looks like: y = ax + b.
Where the slope a = (Y2 - Y1)/(X2 - X1) and b = y - ax.
In our example case, the equation is y = -2x + 10. We just need to know what is the value of X when Y = 3, which we can find with x = (y - b) / a and in our case, x = (3 - 10) / (-2) = 3.5.
So we now know that our character will be intersecting with the floor at (3.5, 3) and that's where we will put the character.
Flaws of your current technique
When you collide, you put the character up 1 pixel if I understand correctly your code.
Imagine that your character is going really fast and in one update of his position, he gets from a valid position to an invalid one, 25 pixels below the ground. With your current technique, it will take at least 25 position updates to get back on the ground or maybe just 25 collision detection loops, but still, it's not very efficient.
Another thing, you seem to be looping every possible tiles in the level, so that's probably mostly empty tiles and/or full ground (inaccessible) tiles, which is a big overhead on what you really need.
The best option would be to store the coordinates of collidable tiles and just iterate those tiles.
If you have a screen of, let's say 50 x 50 tiles, and there are only 25 collidable tiles, you're still checking 50 * 50 - 25 = 2475 tiles, and these are 2475 unnecessary checks. But obviously, that's not the reason why you are having trouble, even those 2475 unnecessary checks won't break the logic.
And just to play with the numbers, since our character is 25 pixels below, we'll loop 25 times 2500 tiles, which is 62500 checks, instead of 25 * 25 = 625 with a collidable tile collection, or just 25 checks with the math stuff.
Related
I have two curves. One handdrawn and one is a smoothed version of the handdrawn.
The data of each curve is stored in 2 seperate vector arrays.
Time Delta is also stored in the handdrawn curve vector, so i can replay the drawing process and so that it looks natural.
Now i need to transfer the Time Delta from Curve 1 (Raw input) to Curve 2 (already smoothed curve).
Sometimes the size of the first vector is larger and sometimes smaller than the second vector.
(Depends on the input draw speed)
So my question is: How do i fill vector PenSmoot.time with the correct values?
Case 1: Input vector is larger
PenInput.time[0] = 0 PenSmoot.time[0] = 0
PenInput.time[1] = 5 PenSmoot.time[1] = ?
PenInput.time[2] = 12 PenSmoot.time[2] = ?
PenInput.time[3] = 2 PenSmoot.time[3] = ?
PenInput.time[4] = 50 PenSmoot.time[4] = ?
PenInput.time[5] = 100
PenInput.time[6] = 20
PenInput.time[7] = 3
PenInput.time[8] = 9
PenInput.time[9] = 33
Case 2: Input vector is smaller
PenInput.time[0] = 0 PenSmoot.time[0] = 0
PenInput.time[1] = 5 PenSmoot.time[1] = ?
PenInput.time[2] = 12 PenSmoot.time[2] = ?
PenInput.time[3] = 2 PenSmoot.time[3] = ?
PenInput.time[4] = 50 PenSmoot.time[4] = ?
PenSmoot.time[5] = ?
PenSmoot.time[6] = ?
PenSmoot.time[7] = ?
PenSmoot.time[8] = ?
PenSmoot.time[9] = ?
Simplyfied representation:
PenInput holds the whole data of a drawn curve (Raw Input)
PenInput.x // X coordinate)
PenInput.y // Y coordinate)
PenInput.pressure // The pressure of the pen)
PenInput.timetotl // Total elapsed time)
PenInput.timepart // Time fragments)
PenSmoot holds the data of the massaged (smoothed,evenly distributed) curve of PenInput
PenSmoot.x // X coordinate)
PenSmoot.y // Y coordinate)
PenSmoot.pressure // Unknown - The pressure of the pen)
PenSmoot.timetotl // Unknown - Total elapsed time)
PenSmoot.timepart // Unknown - Time fragments)
This is the struct that i have.
struct Pencil
{
sf::VertexArray vertices;
std::vector<int> pressure;
std::vector<sf::Int32> timetotl;
std::vector<sf::Int32> timepart;
};
[This answer has been extensively revised based on editing to the question.]
Okay, it seems to me that you just about need to interpolate the time stamps in parallel with the points.
I'm going to guess that the incoming data is something on the order of an array of points (e.g., X, Y coordinates) and an array of time deltas with the same number of each, so time-delta N tells you the time it took to get from point N-1 to point N.
When you interpolate the points, you're probably going to want to do it intelligently. For example, in the shape shown in the question, we have what look like two nearly straight lines, one with positive slope, and the other with negative slope. According to the picture, that's composed of 263 points. We could reduce that to three points and still have a fairly reasonable representation of the original shape by choosing the two end-points plus one point where the two lines meet.
We probably don't need to go quite that far though. Especially taking time into account, we'd probably want to use at least 7 points for the output--one for each end-point of each colored segment. That would give us 6 straight line segments. Let's say those are at points 0, 30, 140, 180, 200, 250, and 263.
We'd then use exactly the same segmentation on the time deltas. Add up the deltas from 0 to 30 to get an average speed for the first segment. Add up the deltas for 31 through 140 to get an average speed for the second segment (and so on to the end).
Increasing the number of points works out roughly the same way. We need to look at exactly which input points were used to create a pair of output points. For a simplistic example, let's assume we produced output that was precisely double the number of input points. We'd then interpolate time deltas exactly halfway between each pair of input points.
In the case shown in the question, we start with unevenly distributed inputs, but produce evenly distributed outputs. So the second output point might be an average of the first four input points. The next output point might be an average of three input points (and so on). In many cases, it's likely that neither end-point of a segment in the output corresponds precisely to any point in the input.
That's fine too. We interpolate between two points of the input to figure out the time hack for the starting point of the output segment. Likewise for the ending point. Then we can compute the total time it should have taken to travel between them based on the time delta between the points.
If you want to get fancy, you could use a higher order interpolation instead of linear. That does require more input points per interpolation, but it looks like you probably have plenty to do something like a quadratic or cubic interpolation (in most cases). This is likely to make the most differences at transitions--places the "pen" was accelerating or decelerating quickly. In such an place, linear interpolation can give somewhat misleading results (though, given the number of points you seem to be working with, it may not make enough difference to notice).
As an illustration, let's consider a straight line. We're going to start from 5 input points, and produce 7 output points.
So, the input points are [0, 2, 7, 10, 15], and the associated time deltas are [0, 1, 4, 8, 3].
So, out total distance traveled is 16, and we want our output points to be evenly distributed. So, the distance between output points will be 16/7 = (roughly) 2.29.
So, obviously the first output point and time are both 0. The second output point is 2.29. To compute the output time, we take the entirety of the time to the first input point (0->2), plus .29 / (7-2) * (4-1). That interpolated section gives 1.37, so our first output time delta is 2.37.
The next output point should be at a distance of 4.58. Since the second input segment goes from 2 to 7, our entire second output segment will lie within the second input segment. So, we take 2.29 / (7-2), telling use that this output segment occupies .458 of the input segment. We then multiply that by the time for the second input segment to get the time delta for the second output segment: .458 * (4-1) = 1.374.
[...and it continues on the same way until we reach the end.]
hell-o guys!
well, I'm playing with random walks. Midpoint displacement gives some nice results, but I would like a random walk without walk loops, like the ones (in yellow) on this screen-hot :
My first idea to deal with that problem is to check for each segment if there is an intersection with all others segments, then to delete the walk loop between the both segments and bind at the interesection point. But for some walks, it would give a strange result, like that one :
where the yellow part is a loop, and we can see that a big part of the walk would be deleted if I do what I said.
Maybe another method would be to check, when the displacement of the midpoint is made, if the segments are interesecting. In case of there is an intersection, get another displacment. But it looks to become very time consuming quickly when the number of subdivisions rises...
So I would like to know if there is a way to avoid these loops
so... it's seems playing with the amplitudes of the random numbers is a good way to avoid overlaps :
the path without displacement is drawn in cyan. I didn't get overlaps with these displacments :
do{
dx = (D>0)? 0.5*sqrt((double)(rand()%D)) - sqrt((double)D)/2. : 0 ;
dz = (D>0)? 0.5*sqrt((double)(rand()%D)) - sqrt((double)D)/2. : 0 ;
}while(dx*dx+dz*dz>D);
where D is the squared distance between the two neibourers of the point we want to displace. The (D>0)? is needed to avoid some Floating Point Exception.
I am creating a menu system for my game engine and want to know how to be able to detect when the mouse is over a button. This is simple enough to do when the button is a square, rectangle or circle but I was wondering how to handle irregular shaped buttons.
Is this possible and if it is, does the complexity mean that it is better to simply use a bounding area (square or circle)?
Make a bitmask out of the texture or surface data. Decide on a rule; for example where the image is 100% transparent or a certain color the bitmask pixel is set to 0 otherwise set it to 1. Do the same for your cursor. When you check for collision simply check if the bitmask bits set to 1 overlap.
First what comes to my mind is to use mathematical functions. If you know the equation of the curve you can calculate if the point is under or over it by simply checking if right side of the equation is greater or less than the "y".
So if you have simple y = x*x and want to check point (2,1), you substitute it and check:
y = 2
x = 1*1 = 1
y > 1, point is over the curve. For opposite situation, taking the point (1,2), we get:
y = 1
x = 2*2 = 4
y < x, point is under the curve.
Ok so I have a 2d vector of chars that I call a grid. Lets just say its 70 x 30. When the grid is created, it automatically fills each position with 'x'
I have a function that displays the grid. So I call this function and a 70x30 grid of x's is displayed to the console.
I have another function that I want to call to essentially replace the char at certain x,y coordinates of the grid with a different char. The points aren't exactly random/scattered. I'm basically starting from a point on the edge of the grid, and drawing zigzagged lines to another edge. All points are predetermined. Theres a lot of points to plot, so manually doing it seems inefficient.
Here's how I was thinking to do it:
Create a double for loop, width and height, calling them i and j
If i = (a || b || c || d...) && j = (e || f || g..)
And essentially do that tedious process for each possible scenario..
Surely there is a much easier and simpler way lol. Any suggestions will be greatly appreciated. Thanks!
If the points can be pre-determined by having a map (as in for a level editor or otherwised fixed pattern), then make a dictionary of x/y co-ordinates to what the tile becomes. Iterate over the dictionary and do each replacement.
If the points aren't pre-determined but follow a pattern, such as lines or blobs, then write a method that draws the line/blob/whatever and call it over and over. The method decides which tiles to replace and replaces those.
Btw, there's a trick when doing 2D checking and processing like this which is called having a 'delta', for instance xdelta=-1, ydelta=0 is west and xdelta=1, ydelta=1 is northeast. By having a delta you can run a function two, four or eight times with different deltas and it'll move in different directions by just using the delta's directions instead of needing to try all eight directions on its own - the delta can also be used to drive the bounds checking if you want, as you can't go out of bounds in a direction you're not proceeding in for example. Then you can go further and have an enumeration of all directions, functions that invert a direction, that turn a direction 90/45 degrees (if it's enumerated it's very simple, you just add 2 or 1 to the enumeration and return the new direction), etc, making processing very easy now.
So I might have something like
function drawLine(int xstart, int ystart, int xdelta, intydelta)
that starts at xstart,ystart, replaces the tile with O, adds xdelta to x, adds ydelta to y, replaces the tile with O, etc until it falls off the edge.
I'm trying to figure out the best way to approach the following:
Say I have a flat representation of the earth. I would like to create a grid that overlays this with each square on the grid corresponding to about 3 square kilometers. Each square would have a unique region id. This grid would just be stored in a database table that would have a region id and then probably the long/lat coordinates of the four corners of the region, right? Any suggestions on how to generate this table easily? I know I would first need to find out the width and height of this "flattened earth" in kms, calculate the number of regions, and then somehow assign the long/lats to each intersection of vertical/horizontal line; however, this sounds like a lot of manual work.
Secondly, once I have that grid table created, I need to design a fxn that takes a long/lat pair and then determines which logical "region" it is in. I'm not sure how to go about this.
Any help would be appreciated.
Thanks.
Assume the Earth is a sphere with radius R = 6371 km.
Start at (lat, long) = (0, 0) deg. Around the equator, 3km corresponds to a change in longitude of
dlong = 3 / (2 * pi * R) * 360
= 0.0269796482 degrees
If we walk around the equator and put a marker every 3km, there will be about (2 * pi * R) / 3 = 13343.3912 of them. "About" because it's your decision how to handle the extra 0.3912.
From (0, 0), we walk North 3 km to (lat, long) (0.0269796482, 0). We will walk around the Earth again on a path that is locally parallel to the first path we walked. Because it is a little closer to the N Pole, the radius of this circle is a bit smaller than that of the first circle we walked. Let's use lower case r for this radius
r = R * cos(lat)
= 6371 * cos(0.0269796482)
= 6 368.68141 km
We calculate dlong again using the smaller radius,
dlong = 3 / (2 * pi * r) * 360
= 0.0269894704 deg
We put down the second set of flags. This time there are about (2 * pi * r) / 3 = 13 338.5352 of them. There were 13,343 before, but now there are 13,338. What's that? five less.
How do we draw a ribbon of squares when there are five less corners in the top line? In fact, as we walked around the Earth, we'd find that we started off with pretty good squares, but that the shape of the regions sheared out into pretty extreme parallelograms.
We need a different strategy that gives us the same number of corners above and below. If the lower boundary (SW-SE) is 3 km long, then the top should be a little shorter, to make a ribbon of trapeziums.
There are many ways to craft a compromise that approximates your ideal square grid. This wikipedia article on map projections that preserve a metric property, links to several dozen such strategies.
The specifics of your app may allow you to simplify things considerably, especially if you don't really need to map the entire globe.
Microsoft has been investing in spatial data types in their SQL Server 2008 offering. It could help you out here. Because it has data types to represent your flattened earth regions, operators to determine when a set of coordinates is inside a geometry, etc. Even if you choose not to use this, consider checking out the following links. The second one in particular has a lot of good background information on the problem and a discussion on some of the industry standard data formats for spatial data.
http://www.microsoft.com/sqlserver/2008/en/us/spatial-data.aspx
http://jasonfollas.com/blog/archive/2008/03/14/sql-server-2008-spatial-data-part-1.aspx
First, Paul is right. Unfortunately the earth is round which really complicates the heck out of this stuff.
I created a grid similar to this for a topographical mapping server many years ago. I just recoreded the coordinates of the upper left coder of each region. I also used UTM coordinates instead of lat/long. If you know that each region covers 3 square kilometers and since UTM is based on meters, it is straight forward to do a range query to discover the right region.
You do realize that because the earth is a sphere that "3 square km" is going to be a different number of degrees near the poles than near the equator, right? And that at the top and bottom of the map your grid squares will actually represent pie-shaped parts of the world, right?
I've done something similar with my database - I've broken it up into quad cells. So what I did was divide the earth into four quarters (-180,-90)-(0,0), (-180,0)-(0,90) and so on. As I added point entities to my database, if the "cell" got more than X entries, I split the cell into 4. That means that in areas of the world with lots of point entities, I have a lot of quad cells, but in other parts of the world I have very few.
My database for the quad tree looks like:
\d areaids;
Table "public.areaids"
Column | Type | Modifiers
--------------+-----------------------------+-----------
areaid | integer | not null
supercededon | timestamp without time zone |
supercedes | integer |
numpoints | integer | not null
rectangle | geometry |
Indexes:
"areaids_pk" PRIMARY KEY, btree (areaid)
"areaids_rect_idx" gist (rectangle)
Check constraints:
"enforce_dims_rectangle" CHECK (ndims(rectangle) = 2)
"enforce_geotype_rectangle" CHECK (geometrytype(rectangle) = 'POLYGON'::text OR rectangle IS NULL)
"enforce_srid_rectangle" CHECK (srid(rectangle) = 4326)
I'm using PostGIS to help find points in a cell. If I look at a cell, I can tell if it's been split because supercededon is not null. I can find its children by looking for ones that have supercedes equal to its id. And I can dig down from top to bottom until I find the ones that cover the area I'm concerned about by looking for ones with supercedeson null and whose rectangle overlaps my area of interest (using the PostGIS '&' operator).
There's no way you'll be able to do this with rectangular cells, but I've just finished an R package dggridR which would make this easy to do using a grid of hexagonal cells. However, the 3km cell requirement might yield so many cells as to overload your machine.
You can use R to generate the grid:
install.packages('devtools')
install.packages('rgdal')
library(devtools)
devools.install_github('r-barnes/dggridR')
library(dggridR)
library(rgdal)
#Construct a discrete global grid (geodesic) with cells of ~3 km^2
dggs <- dgconstruct(area=100000, metric=FALSE, resround='nearest')
#Get a hexagonal grid for the whole earth based on this dggs
grid <- dgearthgrid(dggs,frame=FALSE)
#Save the grid
writeOGR(grid, "grid_3km_cells.kml", "cells", "KML")
The KML file then contains the ids and edge vertex coordinates of every cell.
The grid looks a little like this:
My package is based on Kevin Sahr's DGGRID which can generate this same grid to KML directly, though you'll need to figure out how to compile it yourself.