Backstory:
I'm making a simple maze game, where the maze is procedurally generated. I represent the maze as a 2D array of rooms, with 4 booleans storing whether or not each corner of a room has a wall. (if Room.south_wall == false, than the room is connected to the room to its south.) Each room and can have an arbitrary length and width. For simplicity's sake, I set it so that the length and width is determined at the beginning of generation and applied to all rooms. The position of the player is stored using 2 floats, one is their x coordinates, one is their y coordinates. The maze looks something like this (Thick black lines are the visible walls, thin red lines represent the 2d array):
As you can see, each room has a length and width of 3. What I want to be able to do is determine what room the player is in, given their position. So for example, in this instance:
The player is in room (1,0) (I've marked the origin and the center of room (1,0) to help see this)
I know this should be a simple question, but I've been unable to come up with anything for a few days now. Any suggestions would be greatly appreciated. Let me know if this isn't enough information.
If you have the player position px,py and your rooms are aligned so that room(0,0) is centred at (0.0, 0.0) then the index of the room would be
#include<cmath>
ix = int(std::round(px / room_width));
iy = int(std::round(py / room_height));
Also, as a general rule it's best to make room_width and room_height a constant rather than use a 'bare' (aka magic) number just in case you want to change it later.
Related
I am stuck on a question regarding obtaining the centerpiece(s) from a board.
For example, if the board was a 3x3, then I would only return "center" if the tile number was "5". If the board was a 2x2, then I would return "center" for every single tile. I am having a problem due to me hard coding this problem. So far I have:
def getMiddle(width, height, tile):
width = width
height = height
tile = tile
while width*height == 1 or 2 or 4:
return "center"
while width*height == 9:
if tile == 5:
return "center"
else:
return "not center"
This has been my general approach but I've been told that this is hard-coding.
I later found out I'm supposed to have these functions at the top of my code and use them within my code. Ex. if row==0: etc etc
row = (tile - 1) // width
col = (tile - 1) % width
I am really lost on how to begin coding this using the above functions to create a general solution so that I am not hard coding. Would greatly appreciate it!
I won't create a solution for you, but try to help you with creating it.
To find a general solution, you need to generalize the problem description (not like board can be 2x2 or 3x3, but in some general terms). So. You have two options: side of board is even or it is odd. And you have two sides, which leads to four possibilities:
Both width and height are odd. This one is the simpliest: center tile is width*(height/2)+width/2+1 (hope it's clear why).
Only width is odd, center tiles would be one in the middle of row height/2-1 and one in the middle of row height/2 (not too difficult to calculate from this point on).
Only height is odd, center tiles are width/2-1 and width/2 in row height/2.
Both width and height are even, there would be four center tiles: width/2-1 and width/2 in rows height/2-1 and height/2.
Having this in mind, I believe you can easily create for if-branches (one for each case) and write a check for a tile being center tile for each case.
Also, in current code, you have width = width, etc, these lines don't do anything useful, so you should probably remove them. And your method name looks like the method should return number of central tile, or something. Better to rename it to something like is_tile_central (note the snake-case, that's not a real mistake, but it is the way we name things in Python)
And fix the indentation please. I guess you have it correct in your actual code, but as indents are essential in Python, you should keep them in order even in questions.
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.
This is quite complicated to explain, so I will do my best, sorry if there is anything I missed out, let me know and I will rectify it.
My question is, I have been tasked to draw this shape,
(source: learnersdictionary.com)
This is to be done using C++ to write code that will calculate the points on this shape.
Important details.
User Input - Centre Point (X, Y), number of points to be shown, Font Size (influences radius)
Output - List of co-ordinates on the shape.
The overall aim once I have the points is to put them into a graph on Excel and it will hopefully draw it for me, at the user inputted size!
I know that the maximum Radius is 165mm and the minimum is 35mm. I have decided that my base [Font Size][1] shall be 20. I then did some thinking and came up with the equation.
Radius = (Chosen Font Size/20)*130. This is just an estimation, I realise it probably not right, but I thought it could work at least as a template.
I then decided that I should create two different circles, with two different centre points, then link them together to create the shape. I thought that the INSIDE line will have to have a larger Radius and a centre point further along the X-Axis (Y staying constant), as then it could cut into the outside line.*
*(I know this is not what it looks like on the picture, just my chain of thought as it will still give the same shape)
So I defined 2nd Centre point as (X+4, Y). (Again, just estimation, thought it doesn't really matter how far apart they are).
I then decided Radius 2 = (Chosen Font Size/20)*165 (max radius)
So, I have my 2 Radii, and two centre points.
This is my code so far (it works, and everything is declared/inputted above)
for(int i=0; i<=n; i++) //output displayed to user
{
Xnew = -i*(Y+R1)/n; //calculate x coordinate
Ynew = pow((((Y+R1)*(Y+R1)) - (Xnew*Xnew)), 0.5); //calculate y coordinate
AND
for(int j=0; j<=n; j++)//calculation for angles and output displayed to user
{
Xnew2 = -j*(Y+R2)/((n)+((0.00001)*(n==0))); //calculate x coordinate
Ynew2 = Y*(pow(abs(1-(pow((Xnew2/X),2))),0.5));
if(abs(Ynew2) <= R1)
cout<<"\n("<<Xnew2<<", "<<Ynew2<<")"<<endl;
I am having the problem drawing the crescent moon that I cannot get the two circles to have the same starting point?
I have managed to get the results to Excel. Everything in that regard works. But when i plot the points on a graph on Excel, they do not have the same starting points. Its essentially just two half circles, one smaller than the other (Stops at the Y axis, giving the half doughnut shape).
If this makes sense, I am trying to get two parts of circles to draw the shape as such that they have the same start and end points.
If anyone has any suggestions on how to do this, it would be great, currently all I am getting more a 'half doughnut' shape, due to the circles not being connected.
So. Does anyone have any hints/tips/links they can share with me on how to fix this exactly?
Thanks again, any problems with the question, sorry will do my best to rectify if you let me know.
Cheers
Formular for points on a circle:
(x-h)^2+(y-k)^2=r^2
The center of the circle is at (h/k)
Solving for y
2y1 = k +/- sqrt( -x^2 + 2hx +r^2 - h^2)
So now if the inner circle has its center # h/k , the half-moon will begin # h and will stretch to h - r2
Now you need to solve the endpoint formular for the inner circle and the outter circle and plot it. Per x you should receive 4 points (solve the equation two times, each with two solutions)
I did not implement it, but this would be my train of thought...
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.