Projectile bouncing off curved surface - Pygame, Python 3 -


i working on (top-down) game requires code bounce projectile off of circular surface.

the way work when projectile hits surface enter image description here

a hypothetical line drawn center of circleenter image description here

which used normal calculate angle of reflection of new trajectory.enter image description here

physics (such gravity) unnecessary. there more or less simple way of doing that?

reflect line segment off circle.

this reflexed line segment off circle. length of reflected line segment , incoming line segment circle intercept equal length of original line segment. if want reflected ray stop calculations when reflected vector has been worked out. assumes incoming line segment starts outside circle. if line starts inside line fails. can check if line starts inside circle getting distance circle center line start if less circle radius line starts inside circle.

this in pseudo code don't php. sqrt() function sqrt of number.

the incoming ray line segment. line.x1, line.y1 start , x2,y2 end

line x1,y1,x2,y2 

the circle x,y position , r radius

circle x,y,r 

first need line segment circle intercept if any. find closest point on line circle center , see if distance point circle center less circle radius.if line segment might intercept. if distance greater there no intercept.

convert line segment vector

vx = line.x2 - line.x1; vy = line.y2 - line.y1; 

get length of line segment squared

len2 = (vx * vx + vy * vy); 

get normalised distance start of line point closest circle center

unitdist =  ((circle.x - x1) * vx + (circle.y - y1) * vy) / len2; 

then using normalised distance point closest circle in absolute position.

x = x1 + vx * unitdist; y = y1 + vy * unitdist; 

now distance point circle center

dist =  sqrt((x - circle.x)*(x - circle.x)+ (y - circle.y)*(y - circle.y));     

if distance less circle radius there possibility of intercept. if not there no intercept exit there no reflection.

if( dist > circle.r) exit; 

now know line intercept circle, need check if line segment intercepts, find intercept point towards line start , see if point on line segment or not.

thus closest point on line circle center length `dist' worked out out there intercept point length circle.r , distance closest point unknown, know triangle 3 lengths make right triangle missing side

lentointercept = sqrt(circle.r * circle.r - dist * dist); 

this gives distance closest point on line circle center, along line toward start intercept point. convenience convert distance unit scaled distance (normalised) dividing length of line segment

lentointercept = lentointercept / sqrt(len2) 

subtract normalised length normalised distance start of incoming line closest point on line circle center.

unitdist = unitdist - lentointercept; 

if new unitdist intercept point >= 0 , <= 1 know line segment has intercepted circle, otherwise the line segment has not intercepted circle , can exit.

if(unitdist < 0 or unitdist > 1) exit; // no intercept 

now can calculate absolute position of intercept point adding vector multiplied normalised distance start of incoming line intercept point

x = line.x1 + unitdist * vx; y = line.y1 + unitdist * vy; 

now can work out reflection.

get vector circle center intercept point

cx = x - circle.x; cy = y - circle.y; 

we need tangent make calculations easier tangent rotating clockwise 90 deg

tx = -cy; ty = cx; 

normalise tangent vector. know same length circle radius because rotated line circle center intercept point can normalise tangent vector using circle radius

tx = tx / circle.r; ty = ty / circle.r; 

we need normalise incoming line vector divide length

vx = vx / sqrt(len2); vy = vy / sqrt(len2); 

now dot product of tangent , line seg. distance incoming vector end tangent line, squared

dot = vx * tx + vy * ty; 

double because want reflection on other side of tangent line.

dot = dot * 2; 

now lengthen normalised tangent vector dot amount

tx = tx * dot; ty = ty * dot; 

and subtract incoming line vector give vector of outgoing line

reflectedx = tx - vx; reflectedy = ty - vy; 

normalise vector getting length

lengr = sqrt(reflectedx * reflectedx + reflectedy * reflectedy); 

and dividing reflected line length

reflectedx = reflectedx / lengr; reflectedy = reflectedy / lengr; 

now calculate reflected part of line distance form circle intercept point end of incoming line. have normalised distance along line intercept point remaining distance

remaindist = 1-unitdist; 

multiply normalised distance incoming line length

remaindist = remaindist * sqrt(len2); 

now multiply reflected normalised vector length

reflectedx = reflectedx * remaindist; reflectedy = reflectedy * remaindist; 

a lastly create new reflected line segment line intercept point point plus reflected vector

reflectedline.x1 = x; reflectedline.y1 = y; reflectedline.x2 = x + reflectedx; reflectedline.y2 = y + reflectedy; 

Comments

Popular posts from this blog

ruby - Trying to change last to "x"s to 23 -

jquery - Clone last and append item to closest class -

css - Can I use the :after pseudo-element on an input field? -