I am writing a number of difficulties for my Pong clone I am writing to familiarize myself with SFML and Xcode. For the hardest difficulty, I would like to create an AI level where the computer knows instantly where the ball will go. So, if I had my xVelocity and my yVelocity, I could effectively have the slope. The thing is, every time the ball hits the top or bottom, the yVelocity reverses. So essentially, I have an algebra slope problem which does the opposite every time the walls are hit.
Now, my screen height is 600 pixels and the hit detection is 5 pixels on the top and bottom making the space 590 pixels.
My question: Is there are sort of formula which would encompass all of these factors. Say for instance, the ball is hit at x = 30 and y = 240 with a slope of 1.45, I want to get the y value at which it will hit when x = 770.
Let me know if I can simplify this. Again, I know how I could figure it out by calculating it say 4 times if the ball bounces 4 times but I was wondering if there was a way to figure it out taking in y velocity switch at the boundaries.
Thanks!
Edit: Just read your screen is actually 590 pixels high, this changes the math but not the formulas
Calculate where the ball would hit ignoring the collisions. If (0,0) is the top left of your arena, take y = mx + b, where b is your y offset (ball was hit at y = 240) and m is your slope (1.45)
Now we want to know what y will equal when x is 770-30 places further, so do the math:
y = (1.45)(740) + (240) = 1313
This is obviously outside of your range. It will have reflected
y/height = floor(1313/590) = 2 times
meaning the slope is still moving upward, and it will hit at
y mod height = 1313 mod 590 or 133
If it had reflected an odd number of times (floor(y/2) %2 == 1) then you would have to use the following to calculate it
MAX_HEIGHT - (y mod height) = 590 - (1903 mod 590) = 590 - 133 = 457
You can visualize this by stacking multiple 590 height fields on top of each other, with one being where you started:
--------------------------------------------------------------------
|
|
|
| ball ends up here (*)
| *
| *
| *
------------------------(reflection two)------------*---------------
| *
| *
| *
| *
| *
| *
| *
---------------------*---------(reflection 1)------------------------------
| *
| *
| *
| *
|*ball hit here
|
|
-----------------------------------------------------------------------
The same ideas should apply for going downward. Calculate position, figure out number of reflections, use mod or 590 - mod to determine where it should be.
I haven't tried this but if you know where on the "y-axis" it was hit from and the slope, you'd have a slope intercept formula. Plug in the distance to the opposite side and you can tell if it will above, below or inside the screen. If it will go above or below, calculate what the x will be when y hits the top or bottom, subtract from the total x and repeat.
If the math is getting to you here is a programmatic less elegant
(and slower, not that that matter in most implementations of pong) solution:
tempX = ball.x;
tempY = ball.y;
tempXVel = ball.hspeed;
tempYVel = ball.vspeed;
while(tempX < x) //Assumes ball is traveling at you and you are right paddle
{ //in a X = 0 = left hand side scenario
tempX += tempXVel;
tempY += tempYVel;
if (tempY > 480 or tempY < 0)
tempYVel *= -1; //Y Velocity Switch at boundaries
}
target_Y = tempY;
Basically just do the same logic you do on the ball in a loop and then set that as your target.
Related
I'm creating a game that takes place on a map, and the player should be able to scroll around the map. I'm using real-world data from NASA as a 5700 by 2700 pixel image split into 4 smaller ones, each corresponding to a hemisphere:
How I split up the image:
The player will be viewing the world through a camera, which is currently in a 4:3 aspect ratio, which can be moved around. Its height and width can be described as two variables x and y, currently at 480 and 360 respectively.
Model of the camera:
In practice, the camera is "fixed" and instead the tiles move. The camera's center is described as two variables: xcam and ycam.
Currently, the 4 tiles move and hide flawlessly. The problem arises when the camera passes over the "edge" at 180 degrees latitude. What should happen is that the tiles on one side should show and move as if the world was a cylinder without any noticeable gaps. I update xcam by doing this equation to it:
xcam = ((xcam + (2700 - x) mod (5400 - x)) - (2700 - x)
And the tiles' centers update according to these equations (I will focus only on tiles 1 and 2 for simplicity):
tile1_x = xcam - 1350
tile1_y = ycam + 650
tile2_x = xcam + 1350
tile2_y = ycam + 650
Using this, whenever the camera moves past the leftmost edge of tile 1, it "skips" and instead of tile 1 still being visible with tile 2 in view, it moves enough so that tile 2's rightmost edge is in the camera's rightmost edge.
Here's what happens in reality: ,
and here's what I want to happen: .
So, is there any way to update the equations I'm using (or even completely redo everything) so that I can get smooth wrapping?
I think you unnecessarily hard-code a number of tiles and their sizes, and thus bind your code to those data. In my opinion it would be better to store them in some variables, so that they can be easily modified in one place if data ever changes. This also allows us to write a more flexible code.
So, let's assume we have variables:
// logical size of the whole Earth's map,
// currently 2 and 2
int ncols, nrows;
// single tile's size, currently 2700 and 1350
int wtile, htile;
// the whole Earth map's size
// always ncols*wtile and nrows*htile
int wmap, hmap;
Tile tiles[nrows][ncols];
// viewport's center in map coordinates
int xcam, ycam;
// viewport's size in map coordinates, currently 480 and 360
int wcam, hcam;
Whenever we update the player's position, we need to make sure the position falls within an allowed range. But, we need to establish the coordinates system first in order to define the allowed range. For example, if x values span from 0 to wmap-1, increasing rightwards (towards East), and y values span from 0 to hmap-1, increasing downwards (toward South), then:
// player's displacement
int dx, dy;
xcam = (xcam + dx) mod wmap
ycam = (ycam + dy) mod hmap
assures the camera position is always within the map. (Assumed the mod operator always returns non-negative value. Should it work like the C language % operator, which returns negative result for negative dividend, one needs to add a divisor first to make sure the first argument is non-negative: xcam = (xcam + dx + wmap) mod wmap, etc.)
If you'd rather like to have xcam,ycam = 0,0 at the center of a map (that is, at the Greenwich meridian and the equator), then the allowed range would be -wmap/2 through wmap/2-1 for x and -hmap/2 through hmap/2 - 1 for y. Then:
xcam = (xcam + dx + wmap/2) mod wmap - wmap/2
ycam = (ycam + dy + hmap/2) mod hmap - hmap/2
More generally, let x0, y0 denote the 'zero' position of camera relative to the upper-left corner of the map. Then we can update the camera position by transforming it to the map's coordinates, then shifting and wrapping, and finally transforming back to camera's coordinates:
xmap = xcam + x0
ymap = ycam + y0
xmap = (xmap + dx) mod wmap
ymap = (ymap + dy) mod hmap
xcam = xmap - x0
ycam = ymap - y0
or, more compactly:
xcam = (xcam + dx + x0) mod wmap - x0
ycam = (ycam + dy + y0) mod hmap - y0
Now, when we know the position of the viewport (camera) relative to the map, we need to fill it with the map tiles. And a new decision must be made here.
When we travel from Anchorage, Alaska (western hemisphere) to the North, we eventually reach the North Pole and then we'll find ourselves in the eastern hemisphere, headin South. If we proceed in the same direction, we'll get to Kuusamo, Norway, then Sankt Petersburg, Russia, then Kiev, Ukraine... But that would be a travel to the South! We usually do not describe it as a next part of the initial North route. Consequently, we do not show the part 'past the pole' as an upside-down extension of a map. Hence the map should never show tiles above row number 0 or below row nrows-1.
On the other hand, when we travel along circles of latitude, we smoothly cross the 0 and 180 meridians and switch between the eastern and western hemisphere. So if the camera view covers area on both sides of the left or right edge of the map, we need to continue filling the view with tiles from the other end of the tiles array. If we use a map scaled down, so that it is smaller than the viewport, we may even need to iterate that more than once!
The left edge of a camera view corresponds to the 'longitude' of xleft = xcam - wcam/2 and the right one to xrght = xcam + wcam/2. So we can step across the viewport by the tile's width to find out appropriate columns and show them:
x = xleft
repeat
show a column at x
x = x + wtile
until x >= xrght
The 'show a column at x' part requires finding appropriate column, then iterating across the column to show corresponding tiles. Let's find out which tiles fit the camera view:
ytop = ycam - hcam/2
ybot = ycam + hcam/2
y=ytop
repeat
show a tile at x,y
y = y + htile
until y >= ybot
To show the tile we need to locate appropriate tile and then send it to appropriate position in the camera view.
However, we treat column number differently from the row number: columns wrap while rows do not:
row = y/htile
if (0 <= row) and (row < nrows) then
col = (x/wtile) mod ncols
xtile = x - (x mod wtile)
ytile = y - (y mod htile)
display tile[row][col] at xtile,ytile
endif
Of course xtile and ytile are our map-scale longitude and latitude, so the 'display tile at' routine must transform them to the camera view coordinates by subtracting the camera position from them:
xinwiev = xtile - xcam
yinview = ytile - ycam
and then apply the resulting values relative to the camera view's center at the displaying device (screen).
Another level of complication will appear if you want to implement zooming in and out the view, that is dynamic scaling of the map, but I'm sure you'll find out yourself which calculations will need applying the zoom factor for correct results. :)
I'm building a game in Lua for fun (even if you don't know Lua, you can probably help me with this as it applies to any programming language). My problem is I have an x and y variable defined in a table for the player:
player = {}
player.x = 10
player.y = 10
player.velocity = 50
My goal is to have the player move towards the mouses position on the screen. I have it currently set up to increase/decrease the x value and y value for every update depending on the mouse position. My code looks something like this:
function update(delta_time) -- delta_time is time in milliseconds since last update
if mouse.x > screen.width and mouse.y < screen.height then
player.x = player.x + player.velocity * delta_time
player.y = player.y + player.velocity * delta_time
end
That was just one example of a direction that I would define. My problem is that I don't want to have gigantic blocks of flow controls checking for what quadrant the x and y position of the mouse are in, and adjusting the players x and y position accordingly. I would rather have a fluid 360 degree detection that can move the player towards the angle the mouse is positioned from the center.
Another problem I have is when I move the player to the right of the screen, I will simply increase the x value, but when I move the player to the northeast side of the screen, I increase the x AND y value. This means that the player will go 2 TIMES faster depending on how fine the angle of movement is. When I make north east east angles and north west west, the player now goes 3 TIMES faster because I increase/decrease y by 2 and x by 1. I have no idea how to fix this. I am really good with math and trig, but I am bad at applying it to my game. All I need is someone to switch the lights on for me and I will understand. Thank you for your time if you actually read all this.
Compute a vector from the player position to the mouse position. Normalize this vector (i.e., divide it by its length), then multiply by player.velocity, and then add it to player.x and player.y. This way, the speed is constant, and you get smooth movement in all directions.
-- define the difference vector
vec = {}
vec.x = mouse.x - player.x
vec.y = mouse.y - player.y
-- compute its length, to normalize
vec_len = math.pow(math.pow(vec.x, 2) + math.pow(vec.y, 2), 0.5)
-- normalize
vec.x = vec.x / vec_len
vec.y = vec.y / vec_len
-- move the player
player.x = player.x + vec.x * player.velocity * delta_time
player.y = player.y + vec.y * player.velocity * delta_time
So the formula is basically:
xd = x2-x1
yd = y2-y1
Distance = sqrt(xd * xd + yd * yd)
But surely the formula has to be different depending on whether something is above, below, left, or right of the other object?
Like, if I have a sprite in the middle of the screen, and an enemy somewhere below, would that require changing the "x2-x1" (Let's just say the player sprite is x1, enemy is x2) the other way around if the enemy was above instead?
Distance in the sense you describe above will always be a positive value. The sum of the square of real numbers will always be positive, and the square root of a positive number will also always be positive. So, it doesn't matter whether you define xd = x2-x1 or xd = x1-x2. They only differ by their sign and so both have the same absolute value which means they both square to the same value.
So, there aren't really any special cases here. The formulation of the distance measure accommodates all of the concerns you raise.
Math.Sqrt(Math.Pow (a.X-b.X, 2) + Math.Pow (a.Y-b.Y, 2));
Try this. It should work!
yes, you are very right. In my case, I have to calculate distance between two points in 2D. I put x1 for swarm,x2 for intruder along X-Axis and y1 for intruder and y2 for swarm along Y-Axis.
d=sqrt((swarm(de,1) - (intruderX)).^2 + (swarm(de,2)-intruderY).^2);
[Distance is not calculated accurately, I want when intruder comes inside the circle of any swarm particle, it must be detected][1], some times, intruder comes inside the circle but not be detected. This is my problem. Anyone, who solve my problem, will be very grateful to them.
for de = 1:Ndrones
d = sqrt((swarm(de,1) - (intruderX)).^2 + (swarm(de,2)-intruderY).^2);
if(d<=rad) % intruder has been detected
x = intruderX;
y = intruderY;
title('Intruder Detected');
text(x,y+5,sprintf('Intruder'));
text(500,900,sprintf('Iterations: %.2f',iter));
plot(swarm(:,1),swarm(:,2));
for i=1:Ndrones
swarm(:, 9) = 100; %restart the minimum calculation
end
return;
end
end % end of de loop
[1]: http://i.stack.imgur.com/SBP27.png
I'm trying to implement a simple ray-tracing algorithm
so the first step is to convert pixel coordinates into uvw coordinates system
iam using those two equations that i found in a book
where l,r,b,t are the view frustum points , (i,j) are the pixel indexes , (nx,ny) are the scene width and height
then to calculate canonical coordinate i use
i want to understand the previous equations and why they give uwv coordinates for perspective projection not for orthogonal projection (when i use orthogonal projection the equation still gives the result as if perspective projection is used)
Let's assume your camera is some sort of a pyramid. It has a bottom face which I'll refer to as the "camera screen", and the height of the pyramid, also known as the focal length, will be marked as F (or in your equations, Ws).
T(op)
*---------*
|\ /|
| \ / |
| \ / |
| \ / |
L(eft) | *E(ye| R(ight)
| / \ |
| / \ |
| / \ |
|/ \|
*---------*
B(ottom)
Let's assume j goes from the bottom to the top (from -Ny/2 to +Ny/2 in steps of 1/Ny), and i goes from left to right (from -Nx/2 to +Nx/2 in steps of 1/Nx). Note that if Ny is even, j goes up to Nx/2-1 (and similar when Nx is even).
As you go from bottom to top in the image, on the screen, you move from the B value to the T value. At the fraction d (between 0=bottom and 1=top) of your way from bottom to top, your height is
Vs = T + (B-T) * d
A bit of messing around shows that the fraction d is actually:
d = (j + 0.5) / Ny
So:
Vs = T + (B-T) * (j + 0.5) / Ny
And similarly:
Us = L + (R-L) * (i + 0.5) / Nx
Now, let's denote U as the vector going from left to right, V from bottom to top, 'W' going from the eye forward. All these vectors are normalized.
Now, assume the eye is located directly above (0,0) where that is exactly above the center of the rectangular face of the pyramid.
To go from the eye directly to (0,0) you would go:
Ws * W
And then to go from that point to another point on the screen at indexes (i,j) you would go:
Us * U + Vs * V
You will be able to see that Us = 0 for i = 0 and Vs = 0 for j = 0 (since B = -T and L = -R, as the eye is directly above the center of the rectangle).
And finally, if we compose it together, a point on the screen at indexes (i,j) is
S = E + Us * U + Vs * V + Ws * W
Enjoy!
Given four points in the plane, A,B,X,Y, I wish to determine which of the following two angles is smaller ∢ABX or ∢ABY.
The angle ∢ABX is defined as the angle of BX, when AB is translated to lie on the open segment (-∞,0]. Intuitively when saying ∢ABX I mean the angle you get when you turn left after visiting vertex B.
I'd rather not use cos or sqrt, in order to preserve accuracy, and to minimize performance (the code would run on an embedded system).
In the case where A=(-1,0),B=(0,0), I can compare the two angles ∢ABX and ∢ABY, by calculating the dot product of the vectors X,Y, and watch its sign.
What I can do in this case is:
Determine whether or not ABX turns right or left
If ABX turns left check whether or not Y and A are on the same side of the line on segment BX. If they are - ∢ABX is a smaller than ABY.
If ABX turns right, then Y and A on the same side of BX means that ∢ABX is larger than ∢ABY.
But this seems too complicated to me.
Any simpler approach?
Here's some pseudocode. Doesn't detect the case when both angles are the same. Also doesn't deal with angle orientation, e.g. assumes all angles are <= 180 degrees.
v0 = A-B
v1 = X-B
v2 = Y-B
dot1 = dot(v0, v1)
dot2 = dot(v0, v2)
if(dot1 > 0)
if(dot2 < 0)
// ABX is smaller
if(dot1 * dot1 / dot(v1,v1) > dot2 * dot2 / dot(v2, v2) )
// ABX is smaller
// ABY is smaller
if(dot2 > 0)
// ABY is smaller
if(dot1 * dot1 / dot(v1,v1) > dot2 * dot2 / dot(v2,v2) )
// ABY is smaller
// ABX is smaller
Note that much of this agonizing pain goes away if you allow taking two square roots.
Center the origin on B by doing
X = X - B
Y = Y - B
A = A - B
EDIT: you also need to normalise the 3 vectors
A = A / |A|
X = X / |X|
Y = Y / |Y|
Find the two angles by doing
acos(A dot X)
acos(A dot Y)
===
I don't understand the point of the loss of precision. You are just comparing, not modifying in any way the coordinates of the points...
You might want to check out Rational Trigonometry. The ideas of distance and angle are replaced by quadrance and spread, which don't involve sqrt and cos. See the bottom of that webpage to see how spread between two lines is calculated. The subject has its own website and even a youtube channel.
I'd rather not use cos or sqrt, in order to preserve accuracy.
This makes no sense whatsoever.
But this seems too complicated to me.
This seems utterly wrong headed to me.
Take the difference between two vectors and look at the signs of the components.
The thing you'll have to be careful about is what "smaller" means. That idea isn't very precise as stated. For example, if one point A is in quadrant 4 (x-component > 0 and y-component < 0) and the other point B is in quadrant 1 (x-component > 0 and y-component > 0), what does "smaller" mean? The angle of the vector from the origin to A is between zero and π/2; the angle of the vector from the origin to B is between 3π/4 and 2π. Which one is "smaller"?
I am not sure if you can get away without using sqrt.
Simple:
AB = A-B/|A-B|
XB = X-B/|X-B|
YB = Y-B/|Y-B|
if(dot(XB,AB) > dot (YB,AB)){
//<ABY is grater
}
else
{
...
}
Use the law of cosines: a**2 + b**2 - 2*a*b*cos(phi) = c**2
where a = |ax|, b =|bx| (|by|), c=|ab| (|ay|) and phi is your angle ABX (ABY)