My game has a robot that is able to use a laser to kill zombies. I've been browsing the forums for an answer to this question and some people mention projection as the easiest method. I also heard if you make the line segment an actual infinite line that would be easier. If infinite refers to a laser that is so long, that it reaches from one corner of the screen to the opposite corner, then I can do that. You have to remember this laser is basically a rectangular picture. My robot can also rotate in place so I would want the laser to rotate as well. So basically I want to figure how to detect collision between zombies who will be modeled as circles and my laser which will be modeled as a line segment or infinite line.
The slow method is by "running a point along the laser, check if it's within reach of any zombies".
def distance(x1, y1, x2, y2):
"""Returns the distance between (x1, y1) and (x2, y2)."""
return math.sqrt((x2 - x1) **2 + (y2 - y1) ** 2)
def check_laser_beam(sx, sy, dx, dy, zombies):
"""Runs a point along a laser beam, checking if it hits any zombie."""
# Start the laser at the origin
lx = sx
ly = sy
# run a point along the laser, until we hit the edge of the screen
while onscreen(lx, ly):
for z in zombies:
if distance(lx, ly, z.x, z.y) < ZOMBIE_SIZE:
return z
return None
This is super-inefficient, being essentially proportional to the number of zombies, multiplied by the distance to the screen edge. However, it's simple enough that it can be trivially identified as correct.
It also gives us a hint how to solve this faster. What the above code is doing is to see if the beam intercepts a circle with the radius ZOMBIE_SIZE, centred on any zombie.
We can model the line as a general "ax + by = t" and we can model the perimeter of our circular zombies as "(x - zx) ** 2 + (y - zy) ** 2 = r**2" (only x and y are variables, zx, zy and r are constants). This can be turned into a system of equations, which can be mechanically solved. If you get two solutions, the beam definitely passes through the "circular zombie", if you get one solution, it only tangents the zombie. If you get no solutions, it doesn't intercept the zombie at all.
Related
I first track the path of the ball in the image. The scatter points in the image are the x and y coordinates of the ball.
I want to know the point where the ball hits the ground and the stick.
In D1 the ball hits the ground and in D2 ball to stick
In two cases, the ball changes direction and angle.
How can I find the point where the angle and direction change?
I wrote this code to find the angle between two points, but it does not give the correct output.
v1_theta = math.atan2(y1, x1)
v2_theta = math.atan2(y2, x2)
degree = (v2_theta - v1_theta) * (180.0 / math.pi)
x1, y1 - previous position of the ball
x2, y2 - current position of the ball
How can I find the point where the angle and direction change?
The curve to the right of d1 suggests that you are modelling 2D motion with gravity. If we assume that all of the time intervals are the same, then it looks as if the ball hits the stick first, then the ground.
So we divide the trajectory into three parts: the path before the stick, the path between the stick and the ground, and the path after bouncing off the ground. If we disregard the transitions (i.e. the bounces), the only force is gravity. (It is worth checking for air resistance, but if there is any, it appears to be in the noise and negligible.)
Take the second derivative to measure gravity, then fit parabolae to those three paths. Solve for the intersections. (At each intersection you will have two velocities, so if you want to find the angle between them, you can use atan.)
I'm trying to write a script in python, to automatically force the movement of the mouse pointer without the user's input (it quits through the keyboard), and experimenting with PyAutoGUI, PyUserInput and ctypes, I've been figuring out ways to move the pointer with constant speed, instead of having it teleport across the screen(I need the user to be able to see the path it makes). However, I need it to be able to perform curves, and particularly, circles, and I haven't found a way to do so with the aforementioned libraries. Does anybody know of a way to code them into making the mouse describe circles across the screen at constant speed, instead of just straight lines? Thank you beforehand for any input or help you may provide.
This is my attempt at making circle at the center of the screen of radius R - also note if I don't pass parameter duration then the mouse pointer moves to the next coordinates instantly. So for a circle divided into 360 parts you can set the pace using a modulus.
import pyautogui
import math
# Radius
R = 400
# measuring screen size
(x,y) = pyautogui.size()
# locating center of the screen
(X,Y) = pyautogui.position(x/2,y/2)
# offsetting by radius
pyautogui.moveTo(X+R,Y)
for i in range(360):
# setting pace with a modulus
if i%6==0:
pyautogui.moveTo(X+R*math.cos(math.radians(i)),Y+R*math.sin(math.radians(i)))
There is a way to do this using sin, cos, and tan. (I haven't been able to test this code yet, It might not work.)
Import math
Import pyautogui
def circle(radius = 5, accuracy = 360, xpos=0, ypos=0, speed = 5):
local y
local x
local angle
angle = 360/accuracy
local CurAngle
CurAngle = 0
x = []
y = []
sped = speed/accuracy
for i in range(accuracy):
x.append(xpos + radius*math.sin(math.radians(CurAngle)))
y.append(ypos + radius*math.cos(math.radians(CurAngle)))
CurAngle += angle
for i in len(x):
pyautogui.moveTo(x[i], y[i], duration = sped)
You put this near the top of your script, and pass arguments like this:
circle(radius, accuracy, xpos, ypos, speed)
Radius controls the width of the circle
Accuracy controls how many equi-distant points the circle is to be broken up into, setting accuracy to 4 will put 4 invisible points along the circle for the mouse to travel tom which will make a square, not a circle, 5 makes a pentagon, 6 a hexagon, etc.. the bigger the radius, the bigger you will want the accuracy
Xpos controls the x position of where the circle is centered
Ypos controls the y position of where the circle is centered
Speed controls how many seconds you want it to take to draw the circle.
Hope this helps :) Would you mind elaborating what you are wanting when you say 'curves'
I'm currently working on a project about 3D rendering, and I'm trying to make simplistic program that can display a simple 3D room (static shading, no player movement, only rotation) with pygame
So far I've worked through the theory:
Start with a list of coordinates for the X and Z of each "Node"
Nodes are kept in an order which forms a closed loop, so that a pair of nodes will form either side of a wall
The height of the wall is determined when it is rendered, being relative to distance from the camera
Walls are rendered using painter's algorithm, so closer objects are drawn on top of further ones
For shading "fake contrast", which brightens/darkens walls based on the gradient between it's two nodes
While it seems simple enough, the process behind translating the 3D coordinates into 2D points on the screen is proving the difficult for me to understand.
Googling this topic has so far only yeilded these equations:
screenX = (worldX/worldZ)
screenY = (worldY/worldZ)
Which seem flawed to me, as you would get a divide by zero error if any Z coordinate is 0.
So if anyone could help explain this, I'd be really greatful.
Well the
screenX = (worldX/worldZ)
screenY = (worldY/worldZ)
is not the whole stuff that is just the perspective division by z and it is not meant for DOOM or Wolfenstein techniques.
Well in Doom there is only single angle of viewing (you can turn left/right but cannot look up/down only duck or jump which is not the same). So we need to know our player position and direction px,py,pz,pangle. The z is needed only if you want to implement also z axis movement/looking...
If you are looking in a straight line (Red) all the object that cross that line in the 3D are projected to single x coordinate in the player screen...
So if we are looking at some direction (red) any object/point crossing/touching this red line will be place at the center of screen (in x axis). What is left from it will be rendered on the left and similarly whats on right will be rendered on the right too...
With perspective we need to define how large viewing angle we got...
This limits our view so any point touches the green line will be projected on the edge of view (in x axis). From this we can compute screen x coordinate sx of any point (x,y,z) directly:
// angle of point relative to player direction
sx = point_ang - pangle;
if (sx<-M_PI) sx+=2.0*M_PI;
if (sx>+M_PI) sx-=2.0*M_PI;
// scale to pixels
sx = screen_size_x/2 + sx*screen_size_x/FOVx
where screen_size_x is resolution of our view area and point ang is angle of point x,y,z relative to origin px,py,pz. You can compute it like this:
point_ang = atan2(y-py,x-px)
but if you truly do a DOOM ray-casting then you already got this angle.
Now we need to compute the screen y coordinate sy which is dependent on the distance from player and wall size. We can exploit triangle similarity.
so:
sy = screen_size_y/2 (+/-) wall_height*focal_length/distance
Where focal length is the distance at which wall with 100% height will cover exactly the whole screen in y axis. As you can see we dividing by distance which might be zero. Such state must be avoided so you need to make sure your rays will be evaluated at the next cell if standing directly on cell boundary. Also we need to select the focal length so square wall will be projected as square.
Here a piece of code from mine Doom engine (putted all together):
double divide(double x,double y)
{
if ((y>=-1e-30)&&(y<=+1e-30)) return 0.0;
return x/y;
}
bool Doom3D::cell2screen(int &sx,int &sy,double x,double y,double z)
{
double a,l;
// x,y relative to player
x-=plrx;
y-=plry;
// convert z from [cell] to units
z*=_Doom3D_cell_size;
// angle -> sx
a=atan2(y,x)-plra;
if (a<-pi) a+=pi2;
if (a>+pi) a-=pi2;
sx=double(sxs2)*(1.0+(2.0*a/view_ang));
// perpendicular distance -> sy
l=sqrt((x*x)+(y*y))*cos(a);
sy=sys2+divide((double(plrz+_Doom3D_cell_size)-z-z)*wall,l);
// in front of player?
return (fabs(a)<=0.5*pi);
}
where:
_Doom3D_cell_size=100; // [units] cell cube size
view_ang=60.0*deg; // FOVx
focus=0.25; // [cells] view focal length (uncorrected)
wall=double(sxs)*(1.25+(0.288*a)+(2.04*a*a))*focus/double(_Doom3D_cell_size); // [px] projected wall size ratio size = height*wall/distance
sxs,sys = screen resolution
sxs2,sys2 = screen half resolution
pi=M_PI, pi2=2.0*M_PI
Do not forget to use perpendicular distances (multiplied by cos(a) as I did) otherwise serious fish-eye effect will occur. For more info see:
Ray Casting with different height size
I am new in coding. Now I have a question. I have an object who keep moving in an rectangle area. And I also have a lot of circle in this area too. I want to get all the intersection point between the trajectory and the all the circle. As the object is moving step by step, so was thinking that I can calculate the distance between the position of object and all the centre of each circle and compare the distance with radius of the circle. But I think that this will do a lot of computation as you need to calculate the distance at each step. Do you have any good idea or reference. By the way, I am woking on python. Thank you. As I do not have enough reputation , I can not add a picture about the problem
Let a be a number somewhere between the radius and diameter of the larger circles (if they have different radii).
Generate a grid of square tiles of side length a, so that grid(i,k) is the square from (i*a,k*a) to ((i+1)*a, (k+1)*a).
Each tile of the grid contains a list with pointers to circles or indices into the circle array.
For each circle, register it with each tile that it intersects with. Should be less than 4.
Now to test the point (x,y) of the trajectory for circle intersections resp. containment inside the corresponding disk, you only need to test it against the list of circles in tile ((int)(x/a), (int)(y/a).
Unless your trajectory is already a straight line, you might want to compute a piecewise linear approximation of it. Then for each segment you can compute line-circle intersections using a quadratic equation, and check whether the points of intersection are real (as opposed to complex if the line passes by the circle and the term under the square root becomes negative) and whether they are on the segment (as opposed to the parts of the line beyond the endpoints).
Suppose you have a line segment from (x1,y1) to (x2,y2) and want to intersect that with a circle centered at (xc,yc) with radius r. Then you want to solve the equation
((1 - t)*x1 + t*x2 - xc)² + ((1 - t)*y1 + t*y2 - yc)² = r²
If you collect terms based on the power of t you get the following quadratic equation in t:
((x1 - x2)² + (y1 - y2)²)*t²
+ 2*((x1 - x2)*(xc - x1) + (y1 - y2)*(yc - y1))*t
+ ((xc - x1)² + (yc - y1)² - r²) = 0
So you could write this in Python code as follows (untested):
def circleSegmentIntersections(x1, y1, x2, y2, xc, yc, r):
dx = x1 - x2
dy = y1 - y2
rx = xc - x1
ry = yc - y1
a = dx*dx + dy*dy
b = dx*rx + dy*ry
c = rx*rx + ry*ry - r*r
# Now solve a*t^2 + 2*b*t + c = 0
d = b*b - a*c
if d < 0.:
# no real intersection
return
s = math.sqrt(d)
t1 = (- b - s)/a
t2 = (- b + s)/a
if t1 >= 0. and t1 <= 1.:
yield ((1 - t1)*x1 + t1*x2, (1 - t1)*y1 + t1*y2)
if t2 >= 0. and t2 <= 1.:
yield ((1 - t2)*x1 + t2*x2, (1 - t2)*y1 + t2*y2)
If your trajectory is curved but has some nice mathematical description, like a free-fall parabola or a Bézier curve or something like that, then you might avoid the piecewise linear approximation and try to compute the intersection directly. But chances are that doing so would entail finding roots of some higher-order polynomial, which can only be done numerically.
In general I would recommend to first make your algorithm work and then make it faster if you need to. You would be amazed by how fast Python in combination with a set of carefully selected libraries can be.
So for your problem, I would do the following:
1.) Install a set of libraries that makes your life easier:
- Matplotlib for 2D plotting of the rectangle, the circle and
the trajectory
2.) Numpy for general purpose array manipulation
3.) Optionally Scipy for its KDTree support (nearest neighbor search)
4.) Start implementing your problem
a.) Create a rectangle and visualize it using Matplotlib
b.) Create a set of circles and plot them within the rectangular area of 4a
c.) Create a trajectory and plot them within the rectangular area
Now the more difficult part starts. The way forward depends a little on how your trajectory is defined. For example, if your trajectory consists of line segments, you could calculate the intersection point between a circle and a line segment analytically. Three possible solutions exist, no intersection, 1 intersection (line touches circle) and 2 intersections. If your trajectory is more complex, you could discretize it by generating many points along it and than calculate if this point is on the edge of one of the circles. You have to be a little clever though about how the 3 possible solutions can be identified, because the points along the trajectory are finite.
Another option would be to also discretize the points on the edges of the circles. This would mean that the problem reduces for a large part to nearest neighbor search for which you can use the Scipy KDTree class.
I am writing a game in Python with Pygame.
The co-ords (of my display window) are
( 0 , 0 ) at the top left and
(640,480) at the bottom right.
The angle is
0° when pointing up,
90° when pointing to the right.
I have a player sprite with a centre position and I want the turret on a gun to point towards the player. How do I do it?
Say,
x1,y1 are the turret co-ords
x2,y2 are the player co-ords
a is the angle's measure
First, math has a handy atan2(denominator, numerator) function. Normally, you'd use atan2(dy,dx) but because Pygame flips the y-axis relative to Cartesian coordinates (as you know), you'll need to make dy negative and then avoid negative angles. ("dy" just means "the change in y".)
from math import atan2, degrees, pi
dx = x2 - x1
dy = y2 - y1
rads = atan2(-dy,dx)
rads %= 2*pi
degs = degrees(rads)
degs ought to be what you're looking for.
Considering a triangle
sin(angle)=opposed side / hypotenuse
You'll probably want something like this - you may need to fiddle a bit - I may be off by 180 degrees. You'll also need to special-case the situation where dy==0, which I didn't do for you.
import math
# Compute x/y distance
(dx, dy) = (x2-x1, y2-y1)
# Compute the angle
angle = math.atan(float(dx)/float(dy))
# The angle is in radians (-pi/2 to +pi/2). If you want degrees, you need the following line
angle *= 180/math.pi
# Now you have an angle from -90 to +90. But if the player is below the turret,
# you want to flip it
if dy < 0:
angle += 180
OK, using a combination of your answers and some other websites I have found the working code:
dx,dy = x2-x1,y2-y1
rads = math.atan2(dx/dy)
degs = math.degrees(rads)
The rest of my code isn't fussy about a negative value of degs; anyway, it works now and I'd like to say thanks for your help.