Gamemaker: Ball won't bounce off wall on its own - collision

The initial idea is to have the ball reflect off the wall object and carry the same speed once it bounces off. Thanks in advance.
if (place_meeting(x,y + vsp,o_wall))
{
while (!place_meeting(x,y-sign(vsp),o_wall))
{
y = y * sign(vsp);
}
vsp = -vsp;
}
y = y + vsp;
if (place_meeting(x + hsp,y,o_wall))
{
while (!place_meeting(x+sign(hsp),y,o_wall))
{
x = x * sign(hsp);
}
hsp = -hsp;
}
x = x + hsp;

There's a few points that my be letting you down, I'll try and cover them all below.
The first is that in your first while loop when checking vertical position, you'll want to change:
while(place_meeting(x, y-sign(vsp), o_wall))
to
while(place_meeting(x, y+sign(vsp), o_wall))
Bye checking y-sign(vsp) you're actually checking the position behind the ball in the y axis.
The second thing that will certainly be causing some weird behaviour are the two lines of code inside of your while loops, both for the X and Y axis. You'll want to change them to:
y += sign(vsp); and x += sign(hsp);
The code you've written at the moment will be flipping the balls position between its actual value and the same value but negative - depending upon the value of vsp and hsp. Swapping your code out for the code above will cause the ball to move closer to the surface it was going to collide with until it can be no closer which, I'm assuming, is the intended behaviour.
Those are the only things I can see that may be hindering the Ball's behaviour.
Just to note though, you can replace y = y + vsp; and x = x + hsp; with their shorthand versions y += vsp; and x += hsp;.
Hope this helps!

Related

How do I get my bullets move in the direction of the mouse cursor with always the same speed?

I got a problem with a game of mine. It is a top down shooter and if I am pressing the mouse a bullet should shoot in the direction of where the mouse was.
The problem is that with my attempt the bullet would be faster when the distance between player and mouse is bigger and slower when the distance is smaller. I want that speed to be constant no matter what.
This is what my logic looks like so far:
In the constructor I give the bullet a xDir and a yDir:
b.xDir = (float64(mouseX) - b.x)
b.yDir = (float64(mouseY) - b.y)
Then in the update function I multiply it with deltaTime and the bullets movementSpeed and add it to the corresponding position axis:
b.x += b.movementSpeed * dt * b.xDir
b.y += b.movementSpeed * dt * b.yDir
With that logic the bullet speed is depending on the distance between mouse and player. I would appreciate an answer which would not mess with the speed but would still go in the direction of the mouse click.
Thanks in advance :)
The problem is that your b.xDir and b.yDir values are directly calculated from the distance, so the farther the mouse click from the player, the higher the values will be. When they are multiplied by dt, it makes them move faster.
What you need is to normalize your vector, so you only have a direction and not a magnitude carried over from the original click distance. You probably want to use a vector library, but if you're going to do it by scratch, it would look like this:
magnitude := math.Sqrt(b.XDir * b.xDir + y.xDir * y.xDir)
b.xDir /= magnitude
b.yDir /= magnitude
At that point the value of your variables is purely a direction, and multiplying by speed and dt will have the expected effects.
Does something like this work? The idea is to create a 0 to 1 value for the direction. To do that you divide both values by the greatest of the two. You can then multiply this by the speed of the bullet. I've not detailed the playerPosition function but hopefully you can infer what it would do.
func Max(x, y float64) float64 {
if x < y {
return y
}
return x
}
type Bullet struct {
x, y, xDir, yDir float64
}
func getDirection(b *Bullet) {
directionX = float64(mouseX) - playerPosition().x
directionY = float64(mouseY) - playerPosition().y
greatest = Max(mouseX, mouseY)
b.xDir = directionX / greatest
b.yDir = directionY / greatest
}
Syntax might be off a bit, I'm mostly a js dev ;(

How to remove whitespace in mesh plot?

The plot results in a white space which I need to remove.
clc
clear all
x = -60:.5:150;
y = -60:.5:150;
[X,Y] = meshgrid(x,y);
Z = (90-X) + (120-Y);
fileIDAngles = fopen('E:\Capstone\Simple_Neural_1\IO Files\gena.txt','r');
angle1 = fscanf(fileIDAngles,'%f');
fileIDAngles = fopen('E:\Capstone\Simple_Neural_1\IO Files\genb.txt','r');
angle2 = fscanf(fileIDAngles,'%f');
fclose(fileIDAngles);
ans = (90-angle1) + (120-angle2);
hold on
mesh(X,Y,Z);
plot3(angle1,angle2,ans,'-o','LineWidth',1.1,'MarkerEdgeColor','k','MarkerFaceColor',[.49 1 .63],'MarkerSize',4);
You just need to set your axis mins and maxes (add this line to the end of your code):
axis([min(x) max(x) min(y) max(y)])
You can also use axis tight to bound the window within only non-zero areas of your data. This way you don't have to explicitly use min and/or max as axis tight does this for you internally. As with the other answer, place axis tight at the end of your code.

How much do two rectangles overlap?

I have two rectangles a and b with their sides parallel to the axes of the coordinate system. I have their co-ordinates as x1,y1,x2,y2.
I'm trying to determine, not only do they overlap, but HOW MUCH do they overlap? I'm trying to figure out if they're really the same rectangle give or take a bit of wiggle room. So is their area 95% the same?
Any help in calculating the % of overlap?
Compute the area of the intersection, which is a rectangle too:
SI = Max(0, Min(XA2, XB2) - Max(XA1, XB1)) * Max(0, Min(YA2, YB2) - Max(YA1, YB1))
From there you compute the area of the union:
SU = SA + SB - SI
And you can consider the ratio
SI / SU
(100% in case of a perfect overlap, down to 0%).
While the accepted answer is correct, I think it's worth exploring this answer in a way that will make the rationale for the answer completely obvious. This is too common an algorithm to have an incomplete (or worse, controversial) answer. Furthermore, with only a passing glance at the given formula, you may miss the beauty and extensibility of the algorithm, and the implicit decisions that are being made.
We're going to build our way up to making these formulas intuitive:
intersecting_area =
max(0,
min(orange.circle.x, blue.circle.x)
- max(orange.triangle.x, blue.triangle.x)
)
* max(0,
min(orange.circle.y, blue.circle.y)
- max(orange.triangle.y, blue.triangle.y)
)
percent_coverage = intersecting_area
/ (orange_area + blue_area - intersecting_area)
First, consider one way to define a two dimensional box is with:
(x, y) for the top left point
(x, y) for the bottom right point
This might look like:
I indicate the top left with a triangle and the bottom right with a circle. This is to avoid opaque syntax like x1, x2 for this example.
Two overlapping rectangles might look like this:
Notice that to find the overlap you're looking for the place where the orange and the blue collide:
Once you recognize this, it becomes obvious that overlap is the result of finding and multiplying these two darkened lines:
The length of each line is the minimum value of the two circle points, minus the maximum value of the two triangle points.
Here, I'm using a two-toned triangle (and circle) to show that the orange and the blue points are compared with each other. The small letter 'y' after the two-toned triangle indicates that the triangles are compared along the y axis, the small 'x' means they are compared along the x axis.
For example, to find the length of the darkened blue line you can see the triangles are compared to look for the maximum value between the two. The attribute that is compared is the x attribute. The maximum x value between the triangles is 210.
Another way to say the same thing is:
The length of the new line that fits onto both the orange and blue lines is found by subtracting the furthest point on the closest side of the line from the closest point on the furthest side of the line.
Finding those lines gives complete information about the overlapping areas.
Once you have this, finding the percentage of overlap is trivial:
But wait, if the orange rectangle does not overlap with the blue one then you're going to have a problem:
With this example, you get a -850 for our overlapping area, that can't be right. Even worse, if a detection doesn't overlap with either dimension (neither on the x or y axis) then you will still get a positive number because both dimensions are negative. This is why you see the Max(0, ...) * Max(0, ...) as part of the solution; it ensures that if any of the overlaps are negative you'll get a 0 back from your function.
The final formula in keeping with our symbology:
It's worth noting that using the max(0, ...) function may not be necessary. You may want to know if something overlaps along one of its dimensions rather than all of them; if you use max then you will obliterate that information. For that reason, consider how you want to deal with non-overlapping bounding boxes. Normally, the max function is fine to use, but it's worth being aware what it's doing.
Finally, notice that since this comparison is only concerned with linear measurements it can be scaled to arbitrary dimensions or arbitrary overlapping quadrilaterals.
To summarize:
intersecting_area =
max(0,
min(orange.circle.x, blue.circle.x)
- max(orange.triangle.x, blue.triangle.x)
)
* max(0,
min(orange.circle.y, blue.circle.y)
- max(orange.triangle.y, blue.triangle.y)
)
percent_coverage = intersecting_area
/ (orange_area + blue_area - intersecting_area)
I recently ran into this problem as well and applied Yves' answer, but somehow that led to the wrong area size, so I rewrote it.
Assuming two rectangles A and B, find out how much they overlap and if so, return the area size:
IF A.right < B.left OR A.left > B.right
OR A.bottom < B.top OR A.top > B.bottom THEN RETURN 0
width := IF A.right > B.right THEN B.right - A.left ELSE A.right - B.left
height := IF A.bottom > B.bottom THEN B.bottom - A.top ELSE A.bottom - B.top
RETURN width * height
Just fixing previous answers so that the ratio is between 0 and 1 (using Python):
# (x1,y1) top-left coord, (x2,y2) bottom-right coord, (w,h) size
A = {'x1': 0, 'y1': 0, 'x2': 99, 'y2': 99, 'w': 100, 'h': 100}
B = {'x1': 0, 'y1': 0, 'x2': 49, 'y2': 49, 'w': 50, 'h': 50}
# overlap between A and B
SA = A['w']*A['h']
SB = B['w']*B['h']
SI = np.max([ 0, 1 + np.min([A['x2'],B['x2']]) - np.max([A['x1'],B['x1']]) ]) * np.max([ 0, 1 + np.min([A['y2'],B['y2']]) - np.max([A['y1'],B['y1']]) ])
SU = SA + SB - SI
overlap_AB = float(SI) / float(SU)
print 'overlap between A and B: %f' % overlap_AB
# overlap between A and A
B = A
SB = B['w']*B['h']
SI = np.max([ 0, 1 + np.min([A['x2'],B['x2']]) - np.max([A['x1'],B['x1']]) ]) * np.max([ 0, 1 + np.min([A['y2'],B['y2']]) - np.max([A['y1'],B['y1']]) ])
SU = SA + SB - SI
overlap_AA = float(SI) / float(SU)
print 'overlap between A and A: %f' % overlap_AA
The output will be:
overlap between A and B: 0.250000
overlap between A and A: 1.000000
Assuming that the rectangle must be parallel to x and y axis as that seems to be the situation from the previous comments and answers.
I cannot post comment yet, but I would like to point out that both previous answers seem to ignore the case when one side rectangle is totally within the side of the other rectangle. Please correct me if I am wrong.
Consider the case
a: (1,1), (4,4)
b: (2,2), (5,3)
In this case, we see that for the intersection, height must be bTop - bBottom because the vertical part of b is wholly contained in a.
We just need to add more cases as follows: (The code can be shorted if you treat top and bottom as the same thing as right and left, so that you do not need to duplicate the conditional chunk twice, but this should do.)
if aRight <= bLeft or bRight <= aLeft or aTop <= bBottom or bTop <= aBottom:
# There is no intersection in these cases
return 0
else:
# There is some intersection
if aRight >= bRight and aLeft <= bLeft:
# From x axis point of view, b is wholly contained in a
width = bRight - bLeft
elif bRight >= aRight and bLeft <= aLeft:
# From x axis point of view, a is wholly contained in b
width = aRight - aLeft
elif aRight >= bRight:
width = bRight - aLeft
else:
width = aRight - bLeft
if aTop >= bTop and aBottom <= bBottom:
# From y axis point of view, b is wholly contained in a
height = bTop - bBottom
elif bTop >= aTop and bBottom <= aBottom:
# From y axis point of view, a is wholly contained in b
height = aTop - aBottom
elif aTop >= bTop:
height = bTop - aBottom
else:
height = aTop - bBottom
return width * height
Here is a working Function in C#:
public double calculateOverlapPercentage(Rectangle A, Rectangle B)
{
double result = 0.0;
//trivial cases
if (!A.IntersectsWith(B)) return 0.0;
if (A.X == B.X && A.Y == B.Y && A.Width == B.Width && A.Height == B.Height) return 100.0;
//# overlap between A and B
double SA = A.Width * A.Height;
double SB = B.Width * B.Height;
double SI = Math.Max(0, Math.Min(A.Right, B.Right) - Math.Max(A.Left, B.Left)) *
Math.Max(0, Math.Min(A.Bottom, B.Bottom) - Math.Max(A.Top, B.Top));
double SU = SA + SB - SI;
result = SI / SU; //ratio
result *= 100.0; //percentage
return result;
}
[ymin_a, xmin_a, ymax_a, xmax_a] = list(bbox_a)
[ymin_b, xmin_b, ymax_b, xmax_b] = list(bbox_b)
x_intersection = min(xmax_a, xmax_b) - max(xmin_a, xmin_b) + 1
y_intersection = min(ymax_a, ymax_b) - max(ymin_a, ymin_b) + 1
if x_intersection <= 0 or y_intersection <= 0:
return 0
else:
return x_intersection * y_intersection
#User3025064 is correct and is the simplest solution, though, exclusivity must be checked first for rectangles that do not intersect e.g., for rectangles A & B (in Visual Basic):
If A.Top =< B.Bottom or A.Bottom => B.Top or A.Right =< B.Left or A.Left => B.Right then
Exit sub 'No intersection
else
width = ABS(Min(XA2, XB2) - Max(XA1, XB1))
height = ABS(Min(YA2, YB2) - Max(YA1, YB1))
Area = width * height 'Total intersection area.
End if
The answer of #user3025064 is the right answer. The accepted answer inadvertently flips the inner MAX and MIN calls.
We also don't need to check first if they intersect or not if we use the presented formula, MAX(0,x) as opposed to ABS(x). If they do not intersect, MAX(0,x) returns zero which makes the intersection area 0 (i.e. disjoint).
I suggest that #Yves Daoust fixes his answer because it is the accepted one that pops up to anyone who searches for that problem. Once again, here is the right formula for intersection:
SI = Max(0, Min(XA2, XB2) - Max(XA1, XB1)) * Max(0, Min(YA2, YB2) - Max(YA1, YB1))
The rest as usual. Union:
SU = SA + SB - SI
and ratio:
SI/SU

Math/programming: How to make an object go through a path made from a line

Now I am doing this in VB6 but I don't think it matters what I do it in, does it? I believe it has to do with math.
Here is the problem, have a look at this picture
As you can see in this image, there is a black line and a grey circle. I want the circle to move from the bottom left to the bottom right, but I also want it to stay along the path of the line so it reaches our second picture like this:
Now how can I accomplish this? Again, using VB6.
There are various ways of accomplishing this I think, but here's the first that comes to my mind. It makes some assumptions... like that your line goes in a positive direction and it starts at 0,0. If either of these things aren't true then you've got more code to write to adjust for that.
=================================================
Psuedocode:
'To track current coordinates of the center of the circle
dim x as float, y as float
x = 0: y = 0
'Coordinates for the line
dim x1 as float, y1 as float, x2 as float, y2 as float
x1=0: y1=0: x2=50: y2=75
'How much we're going to move the circle at a time
dim xStep as float, yStep as float, stepSize as float
stepSize = 100
xStep = x2 / stepSize
yStep = y2 / stepSize
Do
'Draw circle here with x, y for coordinates
x = x + xStep
y = y + yStep
Loop Until xStep > x2
Ok, I don't know VBA6 but, since you said:
I don't think it matters what I do it in
I will give a generic solution that involves you having the center of the circles coordinates, and the lines endpoints.
This line can be treated as a vector:
(line.x2-line.x1, line.y2-line.y1)
You don't need to write this in your program or anything just saying it is a vector.
What you do need to is get the magnitude of the vector and assign it to a variable:
unitSize = sqrt((line.x2-line.x1)^2 + (line.y2-line.y1)^2)
Now make it into unit vector components and get the separate components:
unitX = (line.x2-line.x1)/unitSize
unitY = (line.y2-line.y1)/unitSize
Now how ever you update the circle:
do {
circle.x = circle.x + unitX * incrementSize //incrementSize scales how big the movement is assign it to whatever you seem fit.
circle.y = circle.y + unitY * incrementSize
until (circle.x >= line.x2) //Or <= line.x2 depends which way you are going.
Hopefully this helps.

Bouncing Card Algorithm

What's a good algorithm for "bouncing cards" like the ones you see in solitaire games?
What's the coolest card animation you've seen?
Edit - Any besides the Windows game?
The x-axis velocity is constant. The y-velocity is incremented by some value every frame. Each frame, the current x and y positions are incremented by the respective velocities. If the card would end up below the window, y-velocity is multiplied by something like -0.9. (negative number > -1) This produces the series of descending bounces.
Two parts:
motion in the vertical direction is
governed by a second order equation,
like d=1/2at². For Earth, of
course, a= 32 ft/sec² but
you'll have to twiddle the
constants.
When the card hits the edge, as
"recursive" says, the velocity
vector is multiplied by -1 times the
component normal to the surface. If
you want it to bounce nicely to a
stop, make the -1 some slightly
smaller value, like -0.9.
Animate it by updating and redrawing the card some number of times a second, changing the position of the card each time. The easy way is to compute something like (pseudo-Python):
vel_x = # some value, units/sec
vel_y = # some value, units/sec
acc_x = # some value in units/sec^2
acc_y = # some value in units/sec^2
while not_stopped():
x = x+vel_x
y = y+vel_y
# redraw the card here at new position
if card_collided():
# do the bounce calculation
vel_x = x + (0.5 * acc_x) # 1st derivative, gives units/sec
vel_y = y + (0.5 * acc_y)
As long as the cards are staying four-square with the sides, then you collide with the sides when the distance between the card center and the wall is 1/2 the width or hieght as appropriate.
After struggling with the code Charlie provided for an hour or so, I came up with the proper algorithm (after reading recursive's response thoroughly). In real Python:
def bouncing_cards():
x = 0.0
y = 0.0
vel_x = 3.0
vel_y = 4.0
while x < windowWidth:
drawImage(img, x, y)
x += vel_x
y += vel_y
vel_y += 1.0
if y + cardHeight >= windowHeight:
y = windowHeight - cardHeight
vel_y *= -0.9
Gives the following using wxPython: http://i.imgur.com/t51SXVC.png :)

Resources