Creating a 2D billiard ball game, Ball velocity problem - python

I am trying to create a simple program for a billiard game where two balls (a) and (b) having radius (R) collides. I created a python program and its like this.
from math import sqrt, atan2, sin, cos, pi, inf
from numpy import array
W = 600 # width of the table
H = 300 # height of the table
R = 10 # the radius of the ball
A = 0 # deceleration constant
dt = 10 ** -3
ma = mb = 1 # masses of the particles a and b
def vec_magnitude(V1):
return sqrt(V1[0]**2 + V1[1]**2)
def collision_test(V1, V2):
if vec_magnitude(V1 - V2) <= 2 * R:
return True
def dot_product(V1, V2):
return sum(V1 * V2)
def after_collision_velocity(Va, Vb, Ra, Rb):
''' the equation that produces the velocity of the objects after the collision'''
Va_new = Va - ((2 * mb * dot_product(Va - Vb, Ra - Rb)) /
((ma + mb) * (vec_magnitude(Ra - Rb))**2) * (Ra - Rb))
Vb_new = Vb - ((2 * ma * dot_product(Vb - Va, Rb - Ra)) /
((ma + mb) * (vec_magnitude(Rb - Ra))**2) * (Rb - Ra))
return Va_new, Vb_new
def motion(P, V_mag, angle, V):
'''describes the motion of the ball'''
if P[1] < R: #reflection from top
P += array([0, 2 * (R - P[1])])
angle *= -1 #reflection from the angular perspective
return P, V_mag, angle, V
if P[0] < R: # reflection from left
P += array([2 * (R - P[0]), 0])
angle = pi - angle
return P, V_mag, angle, V
if P[1] > H - R: #reflection from bottom
P += array([0, 2 * (H - R - P[1])])
angle *= -1
return P, V_mag, angle, V
if P[0] > W - R: #reflection from right
P += array([2 * (W - R - P[0]), 0])
angle = pi - angle
return P, V_mag, angle, V
else:
V_mag -= A * dt
Vx = V_mag * cos(angle)
Vy = V_mag * sin(angle)
P += array([Vx * dt, Vy * dt])
V = array([Vx, Vy])
return P, V_mag, angle, V
file = open("test_drawing.txt", "w")
for line in open("tex.txt", "r"):
t = 0 # starting time
Xa, Ya, Xb, Yb, Vxa, Vya, Vxb, Vyb = [
int(i) for i in (line.rstrip()).split(" ")]
Pa = array([Xa, Ya], dtype=float) #position vector of the ball a
Pb = array([Xb, Yb], dtype=float) #position vector of the ball b
Va = array([Vxa, Vya], dtype=float) #velocity vvector of the ball a
Vb = array([Vxb, Vyb], dtype=float) #velocity vector of the ball b
Va_mag = vec_magnitude(Va)
Vb_mag = vec_magnitude(Vb)
if Vxa == 0: #these steps are necessarry to eliminate error on the angle process
Vxa = inf
angle_a = atan2(Vya, Vxa) # angle between velocity components of the ball a
if Vxb == 0:
Vxb = inf
angle_b = atan2(Vyb, Vxb) # angle between velocity components of the ball b
while t <= 10:
Pa, Va_mag, angle_a, Va = motion(Pa, Va_mag, angle_a, Va) #moving the ball a
Pb, Vb_mag, angle_b, Vb = motion(Pb, Vb_mag, angle_b, Vb) #moving the ball b
if collision_test(Pa, Pb) == True: #checking the collision validity
Va, Vb = after_collision_velocity(Va, Vb, Pa, Pb)
Va_mag = vec_magnitude(Va) #restating the velocities
Vb_mag = vec_magnitude(Vb)
if Va[0] == 0:
Va[0] = inf
angla_a = atan2(Va[1], Va[0]) #restating the angles
if Vb[0] == 0:
Vb[0] = inf
angle_b = atan2(Vb[1], Vb[0])
t += dt #incrementing time
file.write(str(Pa[0]) + " " + str(Pa[1]) + " " + str(Pb[0]) + " " + str(Pb[1]) + "\n")
print(Pa[0], Pa[1], Pb[0], Pb[1])
file.close()
when I draw a picture for a simple collision, which the data file would contain, (the input data)
100 200 140 200 4 4 -4 4 Values,
I get something like
I used this program to draw
from pylab import plot, show
Xa = [100] #X component of the ball a
Ya = [200] #Y component of the ball a
Xb = [140] #X compnonent of the ball b
Yb = [200] $ Y component of the ball b
for line in open("test_drawing.txt", "r"):
data = [float(i) for i in line.split(" ")]
Xa.append(data[0])
Ya.append(data[1])
Xb.append(data[2])
Yb.append(data[3])
plot(Xa, Ya, "-r")
plot(Xb, Yb, "-.g")
show()
As you can see, ball (b) bounces but not the ball (a). To determine the velocity I used the equation in wikipedia page of the elastic collision.
https://en.wikipedia.org/wiki/Elastic_collision
Can anyone understand why this happens ?

You have a typo.
angla_a = atan2(Va[1], Va[0]) #restating the angles
should say angle_a. You are never actually updating angle_a after a collision.

Related

Calculate eccentricity vector of planetary ring particles

I wish to set-up an initially circular (e=0) system of planetary rings which I can later perturb over time and see how the eccentricity changes. However, my calculation of the eccentricity vector returns -1 as the value of my initial ring, rather than zero.
The eccentricity vector equation takes this form
import numpy as np
import matplotlib.pyplot as plt
G = 6.674e-20 # km^3 kg^-1 s^-2
day = 60.0 * 60.0 * 24.0
dt = day / 10.0
Mass = 5.683e26
N = 30000
delta = np.random.random(1) * 2.0 * np.pi / N
angles = np.linspace(0.0, 2.0 * np.pi, N) + delta
radius = np.random.uniform(low = 1e6, high = 2e6, size = (N)) # ring radius
xrings, yrings = radius * np.cos(angles), radius * np.sin(angles) # positions
vxrings, vyrings = np.sqrt((G * Mass) / radius) * -np.sin(angles), np.sqrt((G * Mass) / radius) * np.cos(angles) # velocities
dist = np.hypot(xrings, yrings) # distance between particles
# update positions
xrings += (vxrings * dt)
yrings += (vyrings * dt)
#update velocities
vxrings -= (G * Mass * xrings / (dist ** 3.0 + 1.0e6) * dt)
vyrings -= (G * Mass * yrings / (dist ** 3.0 + 1.0e6) * dt)
v = np.hypot(vxrings, vyrings)
mu = G*Mass
e = (((abs(v)**2) / mu) - (1/abs(dist)))*radius - (((radius*v) / mu)*v)
plt.plot(e, radius)
plt.show()
I have tried interchanging dist and radius in various ways within the equation as I know the radius needs to be with respect to the central mass, but to no avail.
I think the problem is arising due to the fact that it is a vector equation and when you have implemented it, you've used the magnitudes of radius and velocity when you should have used their vectors.
Implementing either equation from the wiki (with the vectors for r and v) gives the expected result of e being 0 when dt is 0:
import numpy as np
import matplotlib.pyplot as plt
G = 6.674e-20 # km^3 kg^-1 s^-2
day = 60.0 * 60.0 * 24.0
dt = day / 10.0
Mass = 5.683e26
mu = G*Mass
dt = 0
N = 30000
delta = np.random.random(1) * 2.0 * np.pi / N
angles = np.linspace(0.0, 2.0 * np.pi, N) + delta
radius = np.random.uniform(low = 1e6, high = 2e6, size = (N)) # ring radius
xrings, yrings = radius * np.cos(angles), radius * np.sin(angles) # positions
vxrings, vyrings = np.sqrt((G * Mass) / radius) * -np.sin(angles), np.sqrt((G * Mass) / radius) * np.cos(angles) # velocities
dist = np.hypot(xrings, yrings) # distance between particles
# update positions
xrings += (vxrings * dt)
yrings += (vyrings * dt)
# #update velocities
vxrings -= (G * Mass * xrings / (dist ** 3.0 + 1.0e6) * dt)
vyrings -= (G * Mass * yrings / (dist ** 3.0 + 1.0e6) * dt)
# Convert to array of vectors assuming there is no motion out of the plane
r_vector = np.array([[i, j, 0 ] for i, j in zip(xrings, yrings)])
v_vector = np.array([[i, j, 0] for i, j in zip(vxrings, vyrings)])
# Implement the equation as given in the wiki page
# Cross product method
h = [np.cross(i, j) for i, j in zip(r_vector, v_vector)] # r cross v
v_h = [np.cross(i, j)/mu for i, j in zip(v_vector, h)] # v cross h over mu
r_normalised = [i/np.linalg.norm(i) for i in r_vector]
e_vector_cross = [i-j for i,j in zip(v_h, r_normalised)]
absolute_e_cross = [np.linalg.norm(i) for i in e_vector_cross]
plt.figure()
plt.title('Cross product method')
plt.xlabel('Eccentricity')
plt.ylabel('Radius')
plt.plot(absolute_e_cross, radius)
# Dot product method
first_factor = [np.linalg.norm(i)**2/mu -1/np.linalg.norm(j) for i, j in zip(v_vector, r_vector)]
first = [i*j for i, j in zip(first_factor, r_vector)]
second_factor = [np.dot(i, j)/mu for i, j in zip(r_vector, v_vector)]
second = [i*j for i, j in zip(second_factor, v_vector)]
e_vector_dot = [i-j for i, j in zip(first, second)]
absolute_e_dot = [np.linalg.norm(i) for i in e_vector_dot]
plt.figure()
plt.title('Dot product method')
plt.xlabel('Eccentricity')
plt.ylabel('Radius')
plt.plot(absolute_e_dot, radius)
Output:

How to increase FPS in ursina python

I want to create survival games with infinite block terrain(like Minecraft). So i using ursina python game engine, you can see it here
So i using perlin noise to create the terrain with build-in ursina block model. I test for first 25 block and it work pretty good with above 100 FPS, so i start increase to 250 block and more because I want a infinite terrain. But i ran to some problem, when i increase to 100 block or more, my FPS start to decrease below 30 FPS (With i create just one layer).
Here is my code:
#-------------------------------Noise.py(I got on the github)-------------------------
# Copyright (c) 2008, Casey Duncan (casey dot duncan at gmail dot com)
# see LICENSE.txt for details
"""Perlin noise -- pure python implementation"""
__version__ = '$Id: perlin.py 521 2008-12-15 03:03:52Z casey.duncan $'
from math import floor, fmod, sqrt
from random import randint
# 3D Gradient vectors
_GRAD3 = ((1,1,0),(-1,1,0),(1,-1,0),(-1,-1,0),
(1,0,1),(-1,0,1),(1,0,-1),(-1,0,-1),
(0,1,1),(0,-1,1),(0,1,-1),(0,-1,-1),
(1,1,0),(0,-1,1),(-1,1,0),(0,-1,-1),
)
# 4D Gradient vectors
_GRAD4 = ((0,1,1,1), (0,1,1,-1), (0,1,-1,1), (0,1,-1,-1),
(0,-1,1,1), (0,-1,1,-1), (0,-1,-1,1), (0,-1,-1,-1),
(1,0,1,1), (1,0,1,-1), (1,0,-1,1), (1,0,-1,-1),
(-1,0,1,1), (-1,0,1,-1), (-1,0,-1,1), (-1,0,-1,-1),
(1,1,0,1), (1,1,0,-1), (1,-1,0,1), (1,-1,0,-1),
(-1,1,0,1), (-1,1,0,-1), (-1,-1,0,1), (-1,-1,0,-1),
(1,1,1,0), (1,1,-1,0), (1,-1,1,0), (1,-1,-1,0),
(-1,1,1,0), (-1,1,-1,0), (-1,-1,1,0), (-1,-1,-1,0))
# A lookup table to traverse the simplex around a given point in 4D.
# Details can be found where this table is used, in the 4D noise method.
_SIMPLEX = (
(0,1,2,3),(0,1,3,2),(0,0,0,0),(0,2,3,1),(0,0,0,0),(0,0,0,0),(0,0,0,0),(1,2,3,0),
(0,2,1,3),(0,0,0,0),(0,3,1,2),(0,3,2,1),(0,0,0,0),(0,0,0,0),(0,0,0,0),(1,3,2,0),
(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),
(1,2,0,3),(0,0,0,0),(1,3,0,2),(0,0,0,0),(0,0,0,0),(0,0,0,0),(2,3,0,1),(2,3,1,0),
(1,0,2,3),(1,0,3,2),(0,0,0,0),(0,0,0,0),(0,0,0,0),(2,0,3,1),(0,0,0,0),(2,1,3,0),
(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),(0,0,0,0),
(2,0,1,3),(0,0,0,0),(0,0,0,0),(0,0,0,0),(3,0,1,2),(3,0,2,1),(0,0,0,0),(3,1,2,0),
(2,1,0,3),(0,0,0,0),(0,0,0,0),(0,0,0,0),(3,1,0,2),(0,0,0,0),(3,2,0,1),(3,2,1,0))
# Simplex skew constants
_F2 = 0.5 * (sqrt(3.0) - 1.0)
_G2 = (3.0 - sqrt(3.0)) / 6.0
_F3 = 1.0 / 3.0
_G3 = 1.0 / 6.0
class BaseNoise:
"""Noise abstract base class"""
permutation = (151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,
129,22,39,253,9,98,108,110,79,113,224,232,178,185,112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180)
period = len(permutation)
# Double permutation array so we don't need to wrap
permutation = permutation * 2
randint_function = randint
def __init__(self, period=None, permutation_table=None, randint_function=None):
"""Initialize the noise generator. With no arguments, the default
period and permutation table are used (256). The default permutation
table generates the exact same noise pattern each time.
An integer period can be specified, to generate a random permutation
table with period elements. The period determines the (integer)
interval that the noise repeats, which is useful for creating tiled
textures. period should be a power-of-two, though this is not
enforced. Note that the speed of the noise algorithm is indpendent of
the period size, though larger periods mean a larger table, which
consume more memory.
A permutation table consisting of an iterable sequence of whole
numbers can be specified directly. This should have a power-of-two
length. Typical permutation tables are a sequnce of unique integers in
the range [0,period) in random order, though other arrangements could
prove useful, they will not be "pure" simplex noise. The largest
element in the sequence must be no larger than period-1.
period and permutation_table may not be specified together.
A substitute for the method random.randint(a, b) can be chosen. The
method must take two integer parameters a and b and return an integer N
such that a <= N <= b.
"""
if randint_function is not None: # do this before calling randomize()
if not hasattr(randint_function, '__call__'):
raise TypeError(
'randint_function has to be a function')
self.randint_function = randint_function
if period is None:
period = self.period # enforce actually calling randomize()
if period is not None and permutation_table is not None:
raise ValueError(
'Can specify either period or permutation_table, not both')
if period is not None:
self.randomize(period)
elif permutation_table is not None:
self.permutation = tuple(permutation_table) * 2
self.period = len(permutation_table)
def randomize(self, period=None):
"""Randomize the permutation table used by the noise functions. This
makes them generate a different noise pattern for the same inputs.
"""
if period is not None:
self.period = period
perm = list(range(self.period))
perm_right = self.period - 1
for i in list(perm):
j = self.randint_function(0, perm_right)
perm[i], perm[j] = perm[j], perm[i]
self.permutation = tuple(perm) * 2
class SimplexNoise(BaseNoise):
"""Perlin simplex noise generator
Adapted from Stefan Gustavson's Java implementation described here:
http://staffwww.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
To summarize:
"In 2001, Ken Perlin presented 'simplex noise', a replacement for his classic
noise algorithm. Classic 'Perlin noise' won him an academy award and has
become an ubiquitous procedural primitive for computer graphics over the
years, but in hindsight it has quite a few limitations. Ken Perlin himself
designed simplex noise specifically to overcome those limitations, and he
spent a lot of good thinking on it. Therefore, it is a better idea than his
original algorithm. A few of the more prominent advantages are:
* Simplex noise has a lower computational complexity and requires fewer
multiplications.
* Simplex noise scales to higher dimensions (4D, 5D and up) with much less
computational cost, the complexity is O(N) for N dimensions instead of
the O(2^N) of classic Noise.
* Simplex noise has no noticeable directional artifacts. Simplex noise has
a well-defined and continuous gradient everywhere that can be computed
quite cheaply.
* Simplex noise is easy to implement in hardware."
"""
def noise2(self, x, y):
"""2D Perlin simplex noise.
Return a floating point value from -1 to 1 for the given x, y coordinate.
The same value is always returned for a given x, y pair unless the
permutation table changes (see randomize above).
"""
# Skew input space to determine which simplex (triangle) we are in
s = (x + y) * _F2
i = floor(x + s)
j = floor(y + s)
t = (i + j) * _G2
x0 = x - (i - t) # "Unskewed" distances from cell origin
y0 = y - (j - t)
if x0 > y0:
i1 = 1; j1 = 0 # Lower triangle, XY order: (0,0)->(1,0)->(1,1)
else:
i1 = 0; j1 = 1 # Upper triangle, YX order: (0,0)->(0,1)->(1,1)
x1 = x0 - i1 + _G2 # Offsets for middle corner in (x,y) unskewed coords
y1 = y0 - j1 + _G2
x2 = x0 + _G2 * 2.0 - 1.0 # Offsets for last corner in (x,y) unskewed coords
y2 = y0 + _G2 * 2.0 - 1.0
# Determine hashed gradient indices of the three simplex corners
perm = self.permutation
ii = int(i) % self.period
jj = int(j) % self.period
gi0 = perm[ii + perm[jj]] % 12
gi1 = perm[ii + i1 + perm[jj + j1]] % 12
gi2 = perm[ii + 1 + perm[jj + 1]] % 12
# Calculate the contribution from the three corners
tt = 0.5 - x0**2 - y0**2
if tt > 0:
g = _GRAD3[gi0]
noise = tt**4 * (g[0] * x0 + g[1] * y0)
else:
noise = 0.0
tt = 0.5 - x1**2 - y1**2
if tt > 0:
g = _GRAD3[gi1]
noise += tt**4 * (g[0] * x1 + g[1] * y1)
tt = 0.5 - x2**2 - y2**2
if tt > 0:
g = _GRAD3[gi2]
noise += tt**4 * (g[0] * x2 + g[1] * y2)
return noise * 70.0 # scale noise to [-1, 1]
def noise3(self, x, y, z):
"""3D Perlin simplex noise.
Return a floating point value from -1 to 1 for the given x, y, z coordinate.
The same value is always returned for a given x, y, z pair unless the
permutation table changes (see randomize above).
"""
# Skew the input space to determine which simplex cell we're in
s = (x + y + z) * _F3
i = floor(x + s)
j = floor(y + s)
k = floor(z + s)
t = (i + j + k) * _G3
x0 = x - (i - t) # "Unskewed" distances from cell origin
y0 = y - (j - t)
z0 = z - (k - t)
# For the 3D case, the simplex shape is a slightly irregular tetrahedron.
# Determine which simplex we are in.
if x0 >= y0:
if y0 >= z0:
i1 = 1; j1 = 0; k1 = 0
i2 = 1; j2 = 1; k2 = 0
elif x0 >= z0:
i1 = 1; j1 = 0; k1 = 0
i2 = 1; j2 = 0; k2 = 1
else:
i1 = 0; j1 = 0; k1 = 1
i2 = 1; j2 = 0; k2 = 1
else: # x0 < y0
if y0 < z0:
i1 = 0; j1 = 0; k1 = 1
i2 = 0; j2 = 1; k2 = 1
elif x0 < z0:
i1 = 0; j1 = 1; k1 = 0
i2 = 0; j2 = 1; k2 = 1
else:
i1 = 0; j1 = 1; k1 = 0
i2 = 1; j2 = 1; k2 = 0
# Offsets for remaining corners
x1 = x0 - i1 + _G3
y1 = y0 - j1 + _G3
z1 = z0 - k1 + _G3
x2 = x0 - i2 + 2.0 * _G3
y2 = y0 - j2 + 2.0 * _G3
z2 = z0 - k2 + 2.0 * _G3
x3 = x0 - 1.0 + 3.0 * _G3
y3 = y0 - 1.0 + 3.0 * _G3
z3 = z0 - 1.0 + 3.0 * _G3
# Calculate the hashed gradient indices of the four simplex corners
perm = self.permutation
ii = int(i) % self.period
jj = int(j) % self.period
kk = int(k) % self.period
gi0 = perm[ii + perm[jj + perm[kk]]] % 12
gi1 = perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]] % 12
gi2 = perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]] % 12
gi3 = perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]] % 12
# Calculate the contribution from the four corners
noise = 0.0
tt = 0.6 - x0**2 - y0**2 - z0**2
if tt > 0:
g = _GRAD3[gi0]
noise = tt**4 * (g[0] * x0 + g[1] * y0 + g[2] * z0)
else:
noise = 0.0
tt = 0.6 - x1**2 - y1**2 - z1**2
if tt > 0:
g = _GRAD3[gi1]
noise += tt**4 * (g[0] * x1 + g[1] * y1 + g[2] * z1)
tt = 0.6 - x2**2 - y2**2 - z2**2
if tt > 0:
g = _GRAD3[gi2]
noise += tt**4 * (g[0] * x2 + g[1] * y2 + g[2] * z2)
tt = 0.6 - x3**2 - y3**2 - z3**2
if tt > 0:
g = _GRAD3[gi3]
noise += tt**4 * (g[0] * x3 + g[1] * y3 + g[2] * z3)
return noise * 32.0
def lerp(t, a, b):
return a + t * (b - a)
def grad3(hash, x, y, z):
g = _GRAD3[hash % 16]
return x*g[0] + y*g[1] + z*g[2]
class TileableNoise(BaseNoise):
"""Tileable implemention of Perlin "improved" noise. This
is based on the reference implementation published here:
http://mrl.nyu.edu/~perlin/noise/
"""
def noise3(self, x, y, z, repeat, base=0.0):
"""Tileable 3D noise.
repeat specifies the integer interval in each dimension
when the noise pattern repeats.
base allows a different texture to be generated for
the same repeat interval.
"""
i = int(fmod(floor(x), repeat))
j = int(fmod(floor(y), repeat))
k = int(fmod(floor(z), repeat))
ii = (i + 1) % repeat
jj = (j + 1) % repeat
kk = (k + 1) % repeat
if base:
i += base; j += base; k += base
ii += base; jj += base; kk += base
x -= floor(x); y -= floor(y); z -= floor(z)
fx = x**3 * (x * (x * 6 - 15) + 10)
fy = y**3 * (y * (y * 6 - 15) + 10)
fz = z**3 * (z * (z * 6 - 15) + 10)
perm = self.permutation
A = perm[i]
AA = perm[A + j]
AB = perm[A + jj]
B = perm[ii]
BA = perm[B + j]
BB = perm[B + jj]
return lerp(fz, lerp(fy, lerp(fx, grad3(perm[AA + k], x, y, z),
grad3(perm[BA + k], x - 1, y, z)),
lerp(fx, grad3(perm[AB + k], x, y - 1, z),
grad3(perm[BB + k], x - 1, y - 1, z))),
lerp(fy, lerp(fx, grad3(perm[AA + kk], x, y, z - 1),
grad3(perm[BA + kk], x - 1, y, z - 1)),
lerp(fx, grad3(perm[AB + kk], x, y - 1, z - 1),
grad3(perm[BB + kk], x - 1, y - 1, z - 1))))
#--------------------------Math.py(For InverseLefp)--------------------------------
def Clamp(t: float, minimum: float, maximum: float):
"""Float result between a min and max values."""
value = t
if t < minimum:
value = minimum
elif t > maximum:
value = maximum
return value
def InverseLefp(a: float, b: float, value: float):
if a != b:
return Clamp((value - a) / (b - a), 0, 1)
return 0
#-----------------------------Game.py(Main code)----------------------
from ursina import *
from ursina.prefabs import *
from ursina.prefabs.first_person_controller import *
from Math import InverseLefp
import Noise
app = Ursina()
#The maximum height of the terrain
maxHeight = 10
#Control the width and height of the map
mapWidth = 10
mapHeight = 10
#A class that create a block
class Voxel(Button):
def __init__(self, position=(0,0,0)):
super().__init__(
parent = scene,
position = position,
model = 'cube',
origin_y = .5,
texture = 'white_cube',
color = color.color(0, 0, random.uniform(.9, 1.0)),
highlight_color = color.lime,
)
#Detect user key input
def input(self, key):
if self.hovered:
if key == 'right mouse down':
#Place block if user right click
voxel = Voxel(position=self.position + mouse.normal)
if key == 'left mouse down':
#Break block if user left click
destroy(self)
if key == 'escape':
#Exit the game if user press the esc key
app.userExit()
#Return perlin noise value between 0 and 1 with x, y position with scale = noiseScale
def GeneratedNoiseMap(y: int, x: int, noiseScale: float):
#Check if the noise scale was invalid or not
if noiseScale <= 0:
noiseScale = 0.001
sampleX = x / noiseScale
sampleY = y / noiseScale
#The Noise.SimplexNoise().noise2 will return the value between -1 and 1
perlinValue = Noise.SimplexNoise().noise2(sampleX, sampleY)
#The InverseLefp will make the value scale to between 0 and 1
perlinValue = InverseLefp(-1, 1, perlinValue)
return perlinValue
for z in range(mapHeight):
for x in range(mapWidth):
#Calculating the height of the block and round it to integer
height = round(GeneratedNoiseMap(z, x, 20) * maxHeight)
#Place the block and make it always below the player
block = Voxel(position=(x, height - maxHeight - 1, z))
#Set the collider of the block
block.collider = 'mesh'
#Character movement
player = FirstPersonController()
#Run the game
app.run()
All file in same folder.
It was working fine but the FPS is very low, so can anyone help?
I'm not able to test this code at the moment but this should serve as a starting point:
level_parent = Entity(model=Mesh(vertices=[], uvs=[]))
for z in range(mapHeight):
for x in range(mapWidth):
height = round(GeneratedNoiseMap(z, x, 20) * maxHeight)
block = Voxel(position=(x, height - maxHeight - 1, z))
level_parent.model.vertices.extend(block.model.vertices)
level_parent.collider = 'mesh' # call this only once after all vertices are set up
For texturing, you might have to add the block.uvs from each block to level_parent.model.uvs as well. Alternatively, call level_parent.model.project_uvs() after setting up the vertices.
On my version of ursina engine (5.0.0) only this code:
`
level_parent = Entity(model=Mesh(vertices=[], uvs=[]))
for z in range(mapHeight):
for x in range(mapWidth):
height = round(GeneratedNoiseMap(z, x, 20) * maxHeight)
block = Voxel(position=(x, height - maxHeight - 1, z))
#level_parent.model.vertices.extend(block.model.vertices)
level_parent.combine().vertices.extend(block.combine().vertices)
level_parent.collider = 'mesh'
`
is working.

Finding X and Y axis line intercept points of a Circle - Python

Hey trying to learn how to code and I cant figure this exercise out.
Specifically getting the precise y axis intercept points.
The formula given works for getting the x axis points but I cant figure out how to get the y axis points.
Exercise :
Input : Radius of circle and the y - intercept of the line.
Output : Circle drawn with a horizontal line across the window with the given y intercept. Mark two points of the intersection.
Print the x values of the points of intersection *Formula : x = ± √r^2 - y^2
Code::
from graphics import *
from math import *
def main():
# enter radius and the y intercept of the line
radius = eval(input("Put in radius:: "))
yinter = eval(input("Put in y intersec:: "))
#Draw window + circle + line
win = GraphWin()
win.setCoords(-10.0, -10.0, 10.0, 10.0)
circle = Circle(Point(0.0,0.0), radius)
mcircle = Circle(Point(0.0,0.0), 0.5)
circle.draw(win)
mcircle.draw(win)
line = Line(Point(-10, 0), Point(10, yinter))
line.draw(win)
#Calculate x axis points of intersept
xroot1 = sqrt(radius * radius - yinter * yinter)
xroot2 = -abs(xroot1)
print("Xroot 1 : ", xroot1)
print("Xroot 2 : ", xroot2)
x = 0
yroot1 = sqrt(radius * radius - x * x)
yroot2 = -abs(yroot1)
print("Yroot 1 : ", yroot1)
print("Yroot 2 : ", yroot2)
#mark two points of intersept in red
sc1 = Circle(Point(xroot1, yroot1), 0.3)
sc1.setFill('red')
sc2 = Circle(Point(xroot2, yroot2), 0.3)
sc2.setFill('red')
sc1.draw(win)
sc2.draw(win)
main()
Answer - With Radius of 8 and Y intersect point of 2
Yroot1 = 7.75
Yroot2 = -7.75
Xroot1 = 8.0
Xroot2 = -8.0
I just came up with a subroutine to find intersection points while solving another Zelle-graphics related SO question. There may be ways to simplify the math but I'm going the long way around:
from graphics import *
def intersection(center, radius, p1, p2):
""" find the two points where a secant intersects a circle """
dx, dy = p2.x - p1.x, p2.y - p1.y
a = dx**2 + dy**2
b = 2 * (dx * (p1.x - center.x) + dy * (p1.y - center.y))
c = (p1.x - center.x)**2 + (p1.y - center.y)**2 - radius**2
discriminant = b**2 - 4 * a * c
assert (discriminant > 0), 'Not a secant!'
t1 = (-b + discriminant**0.5) / (2 * a)
t2 = (-b - discriminant**0.5) / (2 * a)
return Point(dx * t1 + p1.x, dy * t1 + p1.y), Point(dx * t2 + p1.x, dy * t2 + p1.y)
def main(win):
center = Point(0.0, 0.0)
# Enter radius
radius = float(input("Put in radius: "))
# Draw circle and center dot
Circle(center, radius).draw(win)
Circle(center, 0.3).draw(win)
# Enter the y intercept of the line
yinter = float(input("Put in y intercept: "))
# Draw line
p1, p2 = Point(-10.0, 0.0), Point(10.0, yinter)
Line(p1, p2).draw(win)
# Mark two points of intercept in red
for i, root in enumerate(intersection(center, radius, p1, p2), start=1):
print("Root {}:".format(i), root)
dot = Circle(root, 0.3)
dot.setFill('red')
dot.draw(win)
win = GraphWin()
win.setCoords(-10.0, -10.0, 10.0, 10.0)
main(win)
win.getMouse()
OUTPUT
NOTE
You can get values input that do not produce a secant, e.g. a radius of 2 and an intercept of 8. Your code doesn't account for this -- the above will simply throw an assertion error if it occurs. But you can upgrade that to an error you can catch and fix.
For the y coordinates you can use a similar formula:
y = ± sqrt(r^2 - x^2)
and the do everything the same with marking the roots.
You should write the code like this:
x = sqrt(r ** 2 - y ** 2)
line = Line(Point(-10, 0), Point(10, yinter))
line.draw(win)
Line(Point(-10,0) is wrong, it should read:
Line(Point(-10,yinter).
Also set Xroot1 and Xroot2 = 0 or -x=0, x=0
def intersection(center, radius, p1, p2):
dx, dy = p2[0] - p1[0], p2[1] - p1[1]
a = dx**2 + dy**2
b = 2 * (dx * (p1[0]- center[0]) + dy * (p1[1] - center[1]))
c = (p1[0] - center[0])**2 + (p1[1] - center[1])**2 - radius**2
K = b**2 - 4 * a * c
return True if K>0 else False
if __name__ == "__main__":
p1 = 10,50
p2 = 100,50
center= 50,150
radius = 600
print(intersection(center, radius, p1, p2))

Circle and line collision detection in python tkinter

I writing a python program in which a circle bounces off of user drawn lines. There are multiple circles that bounce off the wall. For each one, the shortest distance from the center of the circle and the ball should be calculated. I would prefer if this code was very efficient because my current algorithm lags the computer a lot. If point a is the starting point ,and point b is the end point, and point c is the center, and r is the radius, how would I calculate the shortest distance between the ball? This algorithm should also work if the X coordinate of the ball is out of range of x coordinates in segment AB.
Please post python code
Any help would be appreciated!
Here's what I have so far:
lineList is a list with 4 values that contains beginning and end coordinates of the user drawn lines
center is the center of the ball
global lineList, numobjects
if not(0 in lineList):
beginCoord = [lineList[0],lineList[1]]
endCoord = [lineList[2]-500,lineList[3]-500]
center = [xCoordinate[i],yCoordinate[i]+15]
distance1 = math.sqrt((lineList[1] - center[1])**2 + (lineList[0] - center[0])**2)
slope1 = math.tan((lineList[1] - lineList[3]) / (lineList[0] - lineList[2]))
try:
slope2 = math.tan((center[1] - beginCoord[1])/(center[0]-beginCoord[0]))
angle1 = slope2 + slope1
circleDistance = distance1 * math.sin(angle1)
except:
#If the circle is directly above beginCoord
circleDistance = center[1] - lineList[1]
global numbounces
if circleDistance < 2 and circleDistance > -2:
print(circleDistance)
b = False
b2=False
if xCoordinate[i] < 0:
xCoordinate[i] += 1
speed1[i] *= -1
b=True
elif xCoordinate[i] > 0:
xCoordinate[i] -= 1
speed1[i] *= -1
b=True
if yCoordinate[i] < 0:
yCoordinate[i] += 1
speed2[i] *= -1
b2=True
elif yCoordinate[i] > 0:
yCoordinate[i] -= 1
speed2[i] *= -1
b2=True
if b and b2:
#Only delete the line if the ball reversed directions
numbounces += 1
#Add a ball after 5 bounces
if numbounces % 5 == 0 and numbounces != 0:
numobjects = 1
getData(numobjects)
canvas.delete("line")
lineList = [0,0,0,0]
I don't know what is the mean of shortest distance between the ball, but if you want to calculation the point where the circle will contact the line you can use sympy to figure the formula:
from sympy import *
from sympy.geometry import *
x1, y1, x2, y2, xc, yc = symbols("x1,y1,x2,y2,xc,yc")
p1 = Point(x1, y1)
p2 = Point(x2, y2)
pc = Point(xc, yc)
line = Line(p1, p2)
pline = line.perpendicular_line(pc)
p = line.intersection(pline)[0]
cse(p, symbols=numbered_symbols("t"))
the output is :
([(t0, x1 - x2), (t1, y1 - y2), (t2, x1*y2 - x2*y1), (t3, t0**2 + t1**2)],
[Point((t0**2*xc + t0*t1*yc - t1*t2)/t3, (t0*t1*xc + t0*t2 + t1**2*yc)/t3)])
this means that you can calculate the perpendicular point as:
t0 = x1 - x2
t1 = y1 - y2
t2 = x1*y2 - x2*y1
t3 = t0**2 + t1**2
xp = (t0**2*xc + t0*t1*yc - t1*t2)/t3
yp = (t0*t1*xc + t0*t2 + t1**2*yc)/t3

Simplex Noise Function: Unexpected Results

I'm trying to adapt this noise module to a project I'm working on but I'm not getting the results I was expecting:
https://pypi.python.org/pypi/noise/
Instead of a varied height-map, each row tends to have the exact same value. If I create something 250x250 it will generate the same value 250 times and then generate a new value 250 times until it ends.
Here is the function I'm currently using. I understand this function fairly well but I'm just not sure how to get more "interesting" results. Thank you for your help.
class SimplexNoise(BaseNoise):
def noise2(self, x, y):
"""2D Perlin simplex noise.
Return a floating point value from -1 to 1 for the given x, y coordinate.
The same value is always returned for a given x, y pair unless the
permutation table changes (see randomize above).
"""
# Skew input space to determine which simplex (triangle) we are in
s = (x + y) * _F2
i = floor(x + s)
j = floor(y + s)
t = (i + j) * _G2
x0 = x - (i - t) # "Unskewed" distances from cell origin
y0 = y - (j - t)
if x0 > y0:
i1 = 1; j1 = 0 # Lower triangle, XY order: (0,0)->(1,0)->(1,1)
else:
i1 = 0; j1 = 1 # Upper triangle, YX order: (0,0)->(0,1)->(1,1)
x1 = x0 - i1 + _G2 # Offsets for middle corner in (x,y) unskewed coords
y1 = y0 - j1 + _G2
x2 = x0 + _G2 * 2.0 - 1.0 # Offsets for last corner in (x,y) unskewed coords
y2 = y0 + _G2 * 2.0 - 1.0
# Determine hashed gradient indices of the three simplex corners
perm = BaseNoise.permutation
ii = int(i) % BaseNoise.period
jj = int(j) % BaseNoise.period
gi0 = perm[ii + perm[jj]] % 12
gi1 = perm[ii + i1 + perm[jj + j1]] % 12
gi2 = perm[ii + 1 + perm[jj + 1]] % 12
# Calculate the contribution from the three corners
tt = 0.5 - x0**2 - y0**2
if tt > 0:
g = _GRAD3[gi0]
noise = tt**4 * (g[0] * x0 + g[1] * y0)
else:
noise = 0.0
tt = 0.5 - x1**2 - y1**2
if tt > 0:
g = _GRAD3[gi1]
noise += tt**4 * (g[0] * x1 + g[1] * y1)
tt = 0.5 - x2**2 - y2**2
if tt > 0:
g = _GRAD3[gi2]
noise += tt**4 * (g[0] * x2 + g[1] * y2)
return noise * 70.0 # scale noise to [-1, 1]
win = pygcurse.PygcurseWindow(85, 70, 'Generate')
octaves = 2
ysize = 150
xsize = 150
freq = 32.0 * octaves
for y in range(ysize):
for x in range(xsize):
tile = SimplexNoise.noise2(x / freq, y / freq, octaves)
win.write(str(tile) + "\n")

Categories

Resources