This python code is made to show the animation of 3D solar system with 2d projection.I make two file named solar_system_3d.py and simple_solar_system.py to write the code.But it cannot show properly due to the error:
raceback (most recent call last):
File ~/simple_solar_system.py:14 in
sun = Sun(solar_system)
File ~/solar_system_3d.py:143 in init
super(Sun, self).init(solar_system, mass, position, velocity)
File ~/solar_system_3d.py:89 in init
self.velocity = Vector(*velocity)
TypeError: Vector() takes no arguments
Here is the code from "solar_system_3d.py":
updated version:
# solar_system_3d.py
import itertools
import math
import matplotlib.pyplot as plt
from vectors import Vector
class SolarSystem:
def __init__(self, size, projection_2d=False):
self.size = size
self.projection_2d = projection_2d
self.bodies = []
self.fig, self.ax = plt.subplots(
1,
1,
subplot_kw={"projection": "3d"},
figsize=(self.size / 50, self.size / 50),
)
self.fig.tight_layout()
if self.projection_2d:
self.ax.view_init(10, 0)
else:
self.ax.view_init(0, 0)
def add_body(self, body):
self.bodies.append(body)
def update_all(self):
self.bodies.sort(key=lambda item: item.position[0])
for body in self.bodies:
body.move()
body.draw()
def draw_all(self):
self.ax.set_xlim((-self.size / 2, self.size / 2))
self.ax.set_ylim((-self.size / 2, self.size / 2))
self.ax.set_zlim((-self.size / 2, self.size / 2))
if self.projection_2d:
self.ax.xaxis.set_ticklabels([])
self.ax.yaxis.set_ticklabels([])
self.ax.zaxis.set_ticklabels([])
else:
self.ax.axis(False)
plt.pause(0.001)
self.ax.clear()
def calculate_all_body_interactions(self):
bodies_copy = self.bodies.copy()
for idx, first in enumerate(bodies_copy):
for second in bodies_copy[idx + 1:]:
first.accelerate_due_to_gravity(second)
class SolarSystemBody:
min_display_size = 10
display_log_base = 1.3
def __init__(
self,
solar_system,
mass,
position=(0, 0, 0),
velocity=(0, 0, 0),
):
self.solar_system = solar_system
self.mass = mass
self.position = position
self.velocity = Vector(*velocity)
self.display_size = max(
math.log(self.mass, self.display_log_base),
self.min_display_size,
)
self.colour = "black"
self.solar_system.add_body(self)
def move(self):
self.position = (
self.position[0] + self.velocity[0],
self.position[1] + self.velocity[1],
self.position[2] + self.velocity[2],
)
def draw(self):
self.solar_system.ax.plot(
*self.position,
marker="o",
markersize=self.display_size + self.position[0] / 30,
color=self.colour
)
if self.solar_system.projection_2d:
self.solar_system.ax.plot(
self.position[0],
self.position[1],
-self.solar_system.size / 2,
marker="o",
markersize=self.display_size / 2,
color=(.5, .5, .5),
)
def accelerate_due_to_gravity(self, other):
distance = Vector(*other.position) - Vector(*self.position)
distance_mag = distance.get_magnitude()
force_mag = self.mass * other.mass / (distance_mag ** 2)
force = distance.normalize() * force_mag
reverse = 1
for body in self, other:
acceleration = force / body.mass
body.velocity += acceleration * reverse
reverse = -1
class Vector:
def __sub__(self, vec):
return Vector(self.x - vec.x)
class Sun(SolarSystemBody):
def __init__(
self,
solar_system,
mass=10_000,
position=(0, 0, 0),
velocity=(0, 0, 0),
):
super(Sun, self).__init__(solar_system, mass, position, velocity)
self.colour = "yellow"
class Planet(SolarSystemBody):
colours = itertools.cycle([(1, 0, 0), (0, 1, 0), (0, 0, 1)])
def __init__(
self,
solar_system,
mass=10,
position=(0, 0, 0),
velocity=(0, 0, 0),
):
super(Planet, self).__init__(solar_system, mass, position, velocity)
self.colour = next(Planet.colours)
here is the code from simple_solar_system.py:
# simple_solar_system.py
from solar_system_3d import SolarSystem, Sun, Planet
solar_system = SolarSystem(400, projection_2d=True)
sun = Sun(solar_system)
planets = (
Planet(
solar_system,
position=(150, 50, 0),
velocity=(0, 5, 5),
),
Planet(
solar_system,
mass=20,
position=(100, -50, 150),
velocity=(5, 0, 0)
)
)
while True:
solar_system.calculate_all_body_interactions()
solar_system.update_all()
solar_system.draw_all()
Plz help me, thx a lot!
Python objects have what's called dunder methods, or double underscore. aka magic methods.
Heres what some look like
__lt__(), __le__(), __gt__(), or __ge__()
class Vector:
def __add__(self, vec):
return Vector(self.x + vec.x)
I could say something like and then my Vector classes could be added with the + operator
Heres a better example docs.python - datamodel
I assume you are using this vectors library.
Say you have two vectors:
from vectors import Vector
a = Vector(1, 1, 1)
b = Vector(2, 2, 2)
The Vector class from the vectors library has a function substract(other). You can then use this function to substract vectors in the following way:
a_minus_b = b.substract(a) # a - b
b_minus_a = a.substract(b) # b - a
You could replace all vector minuses in your code with the above code. However, you can also define the __sub__() function on the Vector class like this:
class Vector(Vector):
def __sub__(self, other):
return other.substract(self)
That way a - b will implicitly call the __sub()__ function.
Now you can substract vectors simply as:
a_minus_b = a - b
b_minus_a = b - a
Related
I've been following the Raytracing in one weekend tutorial series (which is coded in C++), but I've run into a problem. I know Python is not really the language for raytracing, and it shows. Rendering 4 spheres with 100 samples per pixel at 600x300px with multithreading took a little over an quarter of an hour.
I figured that multithreading wasn't really doing anything. I needed multiprocessing. I tried to implement it, but it gave me the error that pygame.Surface wasn't serializable. Is there a solution for this, or maybe even a better way of implementing this? Or is the best way forward to recreate this in C#/C++?
The render:
Multithreaded code:
vec3.py
import math
import random
class vec3:
def __init__(self, x, y, z):
self.x = x
self.y = y
self.z = z
def __add__(self, other):
return vec3(
self.x + other.x,
self.y + other.y,
self.z + other.z
)
def __sub__(self, other):
return vec3(
self.x - other.x,
self.y - other.y,
self.z - other.z
)
def __mul__(self, val):
if type(val) == vec3:
return vec3(
self.x * val.x,
self.y * val.y,
self.z * val.z
)
else:
return vec3(
self.x * val,
self.y * val,
self.z * val
)
def __truediv__(self, val):
return vec3(
self.x / val,
self.y / val,
self.z / val
)
def __pow__(self, pow):
return vec3(
self.x ** pow,
self.y ** pow,
self.z ** pow
)
def __rshift__(self, val):
return vec3(
self.x >> val,
self.y >> val,
self.z >> val
)
def __repr__(self):
return "vec3({}, {}, {})".format(self.x, self.y, self.z)
def __str__(self):
return "({}, {}, {})".format(self.x, self.y, self.z)
def dot(self, other):
return (
self.x * other.x +
self.y * other.y +
self.z * other.z
)
def cross(self, other):
return vec3(
(self.y * other.z) - (self.z * other.y),
-(self.x * other.z) - (self.z * other.x),
(self.x * other.y) - (self.y * other.x)
)
def length(self):
return math.sqrt(
(self.x ** 2) +
(self.y ** 2) +
(self.z ** 2)
)
def squared_length(self):
return (
(self.x ** 2) +
(self.y ** 2) +
(self.z ** 2))
def make_unit_vector(self):
return self / (self.length() + 0.0001)
def reflect(self, normal):
return self - normal * (self.dot(normal) * 2)
Raytracing.py
import uuid
import math
import pygame
from random import random
from vec3 import vec3
from threading import Thread
#import time
imprecision = 0.00000001
mindist = 0.001
maxdist = 999999999
class Material:
def random_in_unit_sphere():
p = vec3(random(), random(), random())*2 - vec3(1, 1, 1)
while p.squared_length() >= 1:
p = vec3(random(), random(), random())*2 - vec3(1, 1, 1)
return p
class Matte:
def __init__(self, albedo):
self.albedo = albedo
def scatter(self, ray, rec, scattered):
target = rec.p + rec.normal + Material.random_in_unit_sphere()
scattered.origin = rec.p
scattered.direction = target - rec.p
return True, self.albedo
class Metal:
def __init__(self, albedo, fuzz = 0):
self.albedo = albedo
self.fuzz = fuzz
def scatter(self, ray, rec, scattered):
reflected = ray.direction.make_unit_vector().reflect(rec.normal)
scattered.origin = rec.p
scattered.direction = reflected + (Material.random_in_unit_sphere() * self.fuzz)
return (scattered.direction.dot(rec.normal) > 0), self.albedo
class Transparent:
def __init__(self, refractive_index):
self.ri = refractive_index
def refract(self, v, normal, ni_over_nt):
uv = v.make_unit_vector()
dt = uv.dot(normal)
discriminant = 1 - (ni_over_nt * ni_over_nt * (1-dt*dt))
if discriminant > 0:
refracted = (uv - normal*dt) * ni_over_nt - (normal * math.sqrt(discriminant))
return True, refracted
else:
return False, None
def scatter(self, ray, rec, scattered):
reflected = ray.direction.reflect(rec.normal)
if ray.direction.dot(rec.normal) > 0:
outward_normal = 0 - rec.normal
ni_over_nt = self.ri
else:
outward_normal = rec.normal
ni_over_nt = 1 / self.ri
refracted = self.refract(ray.direction, outward_normal, ni_over_nt)
return bool(refracted[0]), vec3(1, 1, 1)
class Object:
class Sphere:
def __init__(self, pos, r, material=Material.Matte(0.5)):
self.center = pos
self.r = r
self.material = material
def hit(self, ray, t_min, t_max, rec):
oc = ray.origin - self.center
a = ray.direction.dot(ray.direction)
b = oc.dot(ray.direction)
c = oc.dot(oc) - (self.r * self.r)
discriminant = (b*b) - (a*c)
if discriminant < 0:
return False
else:
t = (-b - math.sqrt(discriminant)) / (a + imprecision)
if (t_min < t < t_max):
rec.t = t
rec.p = ray.point_at_parameter(t)
rec.normal = (rec.p - self.center) / self.r
rec.material = self.material
return True
t = (-b + math.sqrt(discriminant)) / (a + imprecision)
if (t_min < t < t_max):
rec.t = t
rec.p = ray.point_at_parameter(t)
rec.normal = (rec.p - self.center) / self.r
rec.material = self.material
return True
class Scene:
def genUUID(self):
id = uuid.uuid4()
while id in self.objects.keys():
id = uuid.uuid4()
return id
def __init__(self):
self.objects = {}
def add(self, object):
id = self.genUUID()
self.objects[id] = object
return id
def hit(self, ray, t_min, t_max, hit_record):
tmp_hit_record = Camera.HitRec()
hit_any = False
closest = maxdist
for object in self.objects.keys():
if self.objects[object].hit(ray, t_min, closest, tmp_hit_record):
hit_any = True
closest = tmp_hit_record.t
hit_record.t = tmp_hit_record.t
hit_record.p = tmp_hit_record.p
hit_record.normal = tmp_hit_record.normal
hit_record.material = tmp_hit_record.material
return hit_any
class Camera:
class Ray:
def __init__(self, A, B):
self.origin = A
self.direction = B
def point_at_parameter(self, t):
return self.origin + (self.direction * t)
class HitRec:
def __init__(self):
self.t = 0
self.p = vec3(0, 0, 0)
self.normal = vec3(0, 0, 0)
def __init__(self, w, screen, scene = Scene(), screen_ratio = 16/9, focal_length = 1):
self.w = w
self.h = int(w / screen_ratio)
self.screen = screen
self.scene = scene
self.screen_ratio = screen_ratio
self.screen_unit_width = 4
self.focal_length = focal_length
self.sampels_per_pixel = 1
self.max_hit_depth = 5
self.max_block_size = 100
# self.depthT = pygame.Surface((w, self.h))
self.origin = vec3(0, 0, 0)
self.horizontal = vec3(self.screen_unit_width, 0, 0)
self.vertical = vec3(0, (-self.screen_unit_width / self.screen_ratio), 0)
self.top_left_corner = \
self.origin - (self.horizontal/2) - (self.vertical/2) - vec3(0, 0, self.focal_length)
def color(self, ray, depth=0):
# Check for sphere hit
rec = self.HitRec()
if self.scene.hit(ray, mindist, maxdist, rec):
scattered = self.Ray(vec3(0, 0, 0), vec3(0, 0, 0))
hit = rec.material.scatter(ray, rec, scattered) # Scattered is the output ray
if depth < self.max_hit_depth and hit[0]:
return self.color(scattered, depth + 1) * hit[1]
else:
return hit[1]
# target = rec.p + rec.normal + self.random_in_unit_sphere()
# return self.color(self.Ray(rec.p, target - rec.p)) * 0.5
## return vec3(rec.normal.x + 1, rec.normal.y + 1, rec.normal.z + 1) * 0.5, rec.t
# Background if nothing's hit
unit_dir = ray.direction.make_unit_vector()
t = 0.5 * (unit_dir.y + 1)
return (vec3(1, 1, 1) * (1 - t)) + (vec3(0.5, 0.7, 1) * t)#, maxdist
def getRay(self, u, v):
return self.Ray(
self.origin,
self.top_left_corner + (self.horizontal * (u + imprecision)) + (self.vertical * (v + imprecision))
)
def renderSquare(self, xoff, yoff, w, h):
pygame.draw.rect(self.screen, (255, 255, 255), (xoff, yoff, w, h))
pygame.display.update()
for y in range(h):
for x in range(w):
col = vec3(0, 0, 0)
for n in range(self.sampels_per_pixel):
u = (x + xoff + random()-0.5) / self.w
v = (y + yoff + random()-0.5) / self.h
r = self.getRay(u, v)
col += (self.color(r) / self.sampels_per_pixel)
col = vec3(math.sqrt(col.x), math.sqrt(col.y), math.sqrt(col.z))
self.screen.set_at((x + xoff, y + yoff), (col.x * 255, col.y * 255, col.z * 255))
pygame.display.update()
def render(self):
blocks = []
for i in range(math.ceil(self.w / self.max_block_size)):
for j in range(math.ceil(self.h / self.max_block_size)):
blocks.append(Thread( target = self.renderSquare, args=(
i * self.max_block_size,
j * self.max_block_size,
self.max_block_size,
self.max_block_size
)))
for job in blocks:
job.start()
for job in blocks:
job.join()
if __name__ == '__main__':
from Raytracing import Camera, Scene, Object
import pygame
pygame.init()
WIDTH, HEIGHT = 600, 300
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption('Multithreaded raytracer')
scene = Scene()
scene.add(Object.Sphere(vec3( 0, 0, -1), 0.5, Material.Matte(vec3(0, 0.3, 0.8))))
scene.add(Object.Sphere(vec3(-1, 0, -1), 0.5, Material.Metal(vec3(0.8, 0.8, 0.8), 0.1)))
scene.add(Object.Sphere(vec3( 1, 0, -1), 0.5, Material.Metal(vec3(0.8, 0.6, 0.2), 1)))
scene.add(Object.Sphere(vec3(0, -100.5, -1), 100, Material.Matte(vec3(0.8, 0.8, 0))))
tracer = Camera(WIDTH, screen, scene, screen_ratio=2 / 1)
# tracer.render()
tracer.sampels_per_pixel = 100
tracer.render()
loop = True
while loop:
for event in pygame.event.get():
if event.type==pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
loop = False
if event.type==pygame.QUIT:
loop = False
pygame.display.update()
pygame.quit()
I have written a class MyPoint:
import math
class MyPoint:
def __init__(self,x=0,y=0):
self.x,self.y = x,y
def __str__(self,x=0,y=0):
return "{}".format((self.x,self.y))
def move(self, dx, dy):
self.x += dx
self.y += dy
def move_to(self, new_x, new_y):
self.x = new_x
self.y = new_y
def get_distance(self, other_point):
distance = math.sqrt(((other_point.x - self.x)**2)+((other_point.y - self.y)**2))
return distance
def is_near_by(self, other_point):
distance = MyPoint.get_distance(self, other_point)
if distance < 5.0:
return True
else:
return False
Now I need to write the MyLine class.
Define a class named MyLine by using the MyPoint class. A line is composed of two points. The MyLine class contains the following:
A data field named start_point of type MyPoint that defines the start point.
A data field named end_point of type MyPoint that defines the end point.
A constructor/initializer which takes 4 integers as parameters (start_x, start_y, end_x, end_y) and creates a line with two MyPoint objects or creates a line with the default values. The default value for each coordinate is 0.
This is the code I have written to use the __repr__(self) method to represent it as follows:
c1 = MyLine(10, 20, 20, 30)
print(repr(c1))
produces
MyLine(10, 20, 20, 30)
My code:
class MyLine:
def __init__(self,start_x=0, start_y=0, end_x=0, end_y=0):
self.start_x, self.start_y, self.end_x, self.end_y = start_x, start_y, end_x, end_y
start_point = MyPoint(start_x, start_y)
self.start_point = start_point
end_point = MyPoint(end_x, end_y)
self.end_point = end_point
def __str__(self):
return "{} to {}".format(self.start_point, self.end_point)
def __repr__(self):
return "MyLine({}, {}, {}, {})".format(self.start_x, self.start_y, self.end_x, self.end_y)
My issue is in the __repr(self)__.
Test1:
line1 = MyLine(10, 20, 20, 30)
print(repr(line1))
line2 = MyLine()
print(repr(line2))
print(type(line1.start_point))
Expected Output1:
MyLine(10, 20, 20, 30)
MyLine(0, 0, 0, 0)
<class '__main__.MyPoint'>
Received Output1:
MyLine(10, 20, 20, 30)
MyLine(0, 0, 0, 0)
<class '__main__.MyPoint'>
Test2:
line1 = MyLine()
line1.start_point = MyPoint(100, 200)
line1.end_point = MyPoint(-100, 40)
print(repr(line1))
Expected Output2:
MyLine(100, 200, -100, 40)
Received Output2:
MyLine(0, 0, 0, 0)
Where am I going wrong? I know there is an issue with what I'm doing in the .format() part but not sure what's the issue.
There are 2 ways.
First is to change
def __repr__(self):
return "MyLine({}, {}, {}, {})".format(self.start_point.x, self.start_point.y, self.end_point.x, self.end_point.y)
2nd, is to use attribute getters and setters.
class MyLine:
def __init__(self,start_x=0, start_y=0, end_x=0, end_y=0):
self.start_x, self.start_y, self.end_x, self.end_y = start_x, start_y, end_x, end_y
start_point = MyPoint(start_x, start_y)
self._start_point = start_point
end_point = MyPoint(end_x, end_y)
self._end_point = end_point
def __str__(self):
return "{} to {}".format(self._start_point, self._end_point)
#property
def start_point(self):
return self._start_point
#start_point.setter
def start_point(self, point):
self._start_point = point
self.start_x = point.x
self.start_y = point.y
#property
def end_point(self):
return self._end_point
#end_point.setter
def end_point(self, point):
self._end_point = point
self.end_x = point.x
self.end_y = point.y
def __repr__(self):
return "MyLine({}, {}, {}, {})".format(self.start_x, self.start_y, self.end_x, self.end_y)
So I created this parabola class which can be instantiated with 3 parameters (a, b and c) or with 3 points belonging to the parabola. The punti() function returns all the points belonging to the parabola in a range defined by n and m. Here's the code (Most of this is in Italian, sorry):
class Parabola:
def __init__(self, tipo=0, *params):
'''
Il tipo รจ 0 per costruire la parabola con a, b, c; 1 per costruire la parabola con
tre punti per la quale passa
'''
if tipo == 0:
self.__a = params[0]
self.__b = params[1]
self.__c = params[2]
self.__delta = self.__b ** 2 - (4 * self.__a * self.__c)
elif tipo == 1:
matrix_a = np.array([
[params[0][0]**2, params[0][0], 1],
[params[1][0]**2, params[1][0], 1],
[params[2][0]**2, params[2][0], 1]
])
matrix_b = np.array([params[0][1], params[1][1], params[2][1]])
matrix_c = np.linalg.solve(matrix_a, matrix_b)
self.__a = round(matrix_c[0], 2)
self.__b = round(matrix_c[1], 2)
self.__c = round(matrix_c[2], 2)
self.__delta = self.__b ** 2 - (4 * self.__a * self.__c)
def trovaY(self, x):
y = self.__a * x ** 2 + self.__b * x + self.__c
return y
def punti(self, n, m, step=1):
output = []
for x in range(int(min(n, m)), int(max(n, m)) + 1, step):
output.append((x, self.trovaY(x)))
return output
Now my little game is about shooting targets with a bow and i have to use the parabola for the trajectory and it passes by 3 points:
The player center
A point with the cursor's x and player's y
A point in the middle with the cursors's y
The trajectory is represented by a black line but it clearly doesn't work and I can't understand why. Here's the code of the game (Don't mind about the bow's rotation, I still have to make it function properly):
import os
import sys
import pygame
from random import randint
sys.path.insert(
1, __file__.replace("pygame-prototype\\" + os.path.basename(__file__), "coniche\\")
)
import parabola
# Initialization
pygame.init()
WIDTH, HEIGHT = 1024, 576
screen = pygame.display.set_mode((WIDTH, HEIGHT))
# Function to rotate without losing quality
def rot_from_zero(surface, angle):
rotated_surface = pygame.transform.rotozoom(surface, angle, 1)
rotated_rect = rotated_surface.get_rect()
return rotated_surface, rotated_rect
# Function to map a range of values to another
def map_range(value, leftMin, leftMax, rightMin, rightMax):
# Figure out how 'wide' each range is
leftSpan = leftMax - leftMin
rightSpan = rightMax - rightMin
# Convert the left range into a 0-1 range (float)
valueScaled = float(value - leftMin) / float(leftSpan)
# Convert the 0-1 range into a value in the right range.
return rightMin + (valueScaled * rightSpan)
# Player class
class Player:
def __init__(self, x, y, width=64, height=64):
self.rect = pygame.Rect(x, y, width, height)
self.dirx = 0
self.diry = 0
def draw(self):
rectangle = pygame.draw.rect(screen, (255, 0, 0), self.rect)
# Target class
class Target:
def __init__(self, x, y, acceleration=0.25):
self.x, self.y = x, y
self.image = pygame.image.load(
__file__.replace(os.path.basename(__file__), "target.png")
)
self.speed = 0
self.acceleration = acceleration
def draw(self):
screen.blit(self.image, (self.x, self.y))
def update(self):
self.speed -= self.acceleration
self.x += int(self.speed)
if self.speed < -1:
self.speed = 0
player = Player(64, HEIGHT - 128)
# Targets init
targets = []
targets_spawn_time = 3000
previous_ticks = pygame.time.get_ticks()
# Ground animation init
ground_frames = []
for i in os.listdir(__file__.replace(os.path.basename(__file__), "ground_frames")):
ground_frames.append(
pygame.image.load(
__file__.replace(os.path.basename(__file__), "ground_frames\\" + i)
)
) # Load all ground frames
ground_frame_counter = 0 # Keep track of the current ground frame
frame_counter = 0
# Bow
bow = pygame.image.load(__file__.replace(os.path.basename(__file__), "bow.png"))
angle = 0
while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
# Spawning the targets
current_ticks = pygame.time.get_ticks()
if current_ticks - previous_ticks >= targets_spawn_time:
targets.append(Target(WIDTH, randint(0, HEIGHT - 110)))
previous_ticks = current_ticks
screen.fill((101, 203, 214))
player.draw()
for i, e in list(enumerate(targets))[::-1]:
e.draw()
e.update()
if e.x <= -e.image.get_rect().width:
del targets[i]
# Calculating the angle of the bow
mouse_pos = pygame.Vector2(pygame.mouse.get_pos())
angle = map_range(mouse_pos.x, 0, WIDTH, 90, 0)
# Rotate the bow
rotated_bow, rotated_bow_rect = rot_from_zero(bow, angle)
rotated_bow_rect.center = player.rect.center
screen.blit(rotated_bow, rotated_bow_rect)
# Animate the ground
if frame_counter % 24 == 0:
ground_frame_counter += 1
if ground_frame_counter >= len(ground_frames):
ground_frame_counter = 0
for i in range(round(WIDTH / ground_frames[ground_frame_counter].get_rect().width)):
screen.blit(
ground_frames[ground_frame_counter],
(
ground_frames[ground_frame_counter].get_rect().width * i,
HEIGHT - ground_frames[ground_frame_counter].get_rect().height,
),
)
# Calculating the trajectory
mouse_pos.x = (
mouse_pos.x if mouse_pos.x != rotated_bow_rect.centerx else mouse_pos.x + 1
)
# print(mouse_pos, rotated_bow_rect.center)
v_x = rotated_bow_rect.centerx + ((mouse_pos.x - rotated_bow_rect.centerx) / 2)
trajectory_parabola = parabola.Parabola(
1,
rotated_bow_rect.center,
(mouse_pos.x, rotated_bow_rect.centery),
(v_x, mouse_pos.y),
)
trajectory = [(i[0], int(i[1])) for i in trajectory_parabola.punti(0, WIDTH)]
pygame.draw.lines(screen, (0, 0, 0), False, trajectory)
pygame.draw.ellipse(
screen, (128, 128, 128), pygame.Rect(v_x - 15, mouse_pos.y - 15, 30, 30)
)
pygame.draw.ellipse(
screen,
(128, 128, 128),
pygame.Rect(mouse_pos.x - 15, rotated_bow_rect.centery - 15, 30, 30),
)
pygame.display.update()
if frame_counter == 120:
for i in trajectory:
print(i)
frame_counter += 1
You can run all of this and understand what's wrong with it, help?
You round the values of a, b and c to 2 decimal places. This is too inaccurate for this application:
self.__a = round(matrix_c[0], 2)
self.__b = round(matrix_c[1], 2)
self.__c = round(matrix_c[2], 2)
self.__a = matrix_c[0]
self.__b = matrix_c[1]
self.__c = matrix_c[2]
Similar to answer above... rounding is the issue here. This is magnified when the scale of the coordinates gets bigger.
However, disagree with other solution: It does not matter what order you pass the coordinates into your parabola construction. Any order works fine. points are points.
Here is a pic of your original parabola function "drooping" because of rounding error:
p1 = (0, 10) # left
p2 = (100, 10) # right
p3 = (50, 100) # apex
p = Parabola(1, p3, p2, p1)
traj = p.punti(0, 100)
xs, ys = zip(*traj)
plt.scatter(xs, ys)
plt.plot([0, 100], [10, 10], color='r')
plt.show()
I'm new baby in Python and having the following error can you guys look into it........................................
AttributeError: 'area' object has no attribute 'radius'. So, I'm facing error in any cases. Thank for help
import math, random
class area:
def __init__(self, radius, length, breath, height, base):
if radius == 0 and breath != 0:
self.radius = random.uniform(1.1, 9.5)
self.length = random.uniform(10.5, 15.5)
self.breath = random.uniform(15, 20)
self.height = random.uniform(20, 25)
self.base = random.uniform(26, 32)
elif length == 0 and heigh != 0:
self.radius = random.uniform(1.1, 9.5)
self.length = length
self.breath = random.uniform(15, 20)
self.height = height
self.base = base
elif height == 0 and base != 0:
self.radius = radius
self.length = random.uniform(1.1, 9.5)
self.breath = breath
self.height = random.uniform(1.1, 9.5)
self.base = base
def areaofcircle(self):
return (self.radius ** 2) * math.pi
def areaoftriangl(self):
return 0.5 * (self.height) * (self.base)
def areaofrectangle(self):
return (self.length) * (self.breath)
areas = []
for i in range(0, 10):
v = area(1, 3, 5, 0, 0)
areas.append(v)
for v in areas:
print(
"Area of Circle:",
v.areaofcircle(),
"Area of Triangle:",
v.areaoftriangl(),
"Area of Rectangle:",
v.areaofrectangle(),
)
You may need to remove radius from this function arguments
def areaofcircle(self, radius):
return (self.radius ** 2) * math.pi
to be:
def areaofcircle(self):
return (self.radius ** 2) * math.pi
By defining the function as
def areaofcircle(self, radius)
Your function expect two inputs, but in your case you only give one. As far as I understand 'radius' is a datafield of the area class. Therefore, you can call it with "self.radius". In this case if you remove the radius parameter from the function, it should all work out.
def areaofcircle(self)
this code needs to take in a x, y, and radius for 2 circles that is input by me and see if it collides. i'm confused on the circle class part on the collision and distance methods. i already typed in the formula which i think is correct to find the distance but i don't know how to call c1 and c2 coordinates so that part i know is wrong. as for the collision i was planning to write a if statement checking if the sum of c1 and c2 radius is equal or greater than the distance, that i also don't know how to do. so if anyone could help it is very much appreciated. also my professor gave us main class part and i don't understand why he put a for loop there so i don't know what that loop is for
class Shape:
"""Shape class: has methods move(), location(), and __init__().
Complete the location() method."""
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, deltaX, deltaY):
self.x = self.x + deltaX
self.y = self.y + deltaY
def location(self):
'''Returns a tuple containing the ~x,y~ coordinates of an object.
return "Circle at coordinates (%d, %d)"\ % (self.x, self.y)
pass
class Circle(Shape):
"""Circle is a sub-class of shape and inherits the move() and location() methods."""
pi = 3.14159
def __init__(self, x=0, y=0, r=1):
Shape.__init__(self, x, y)
self.radius = r
def area(self):
return self.radius * self.radius * self.pi
def __str__(self):
return "Circle of radius %s at coordinates (%d, %d)"\ % (self.radius, self.x, self.y)
# Class methods
#classmethod
def is_collision(Circle, c1, c2):
'''Return True or None'''
if c1.r + c2.r >= dist:
pass # fill this in
else:
not
#classmethod
def distance(Circle, c1, c2):
"""calculate distance between two circles"""
dist = math.sqrt(((c1.x-c2.x)**2)+((c1.y-c2.y)**2))
pass
from shape import Shape
from circle import Circle
c1 = Circle(100, 100, 100)
c2 = Circle(150, 150, 100)
c1_xdelta = 2
c1_ydelta = 3
c2_xdelta = 1
c2_ydelta = -1
for i in range(1,20):
c1.move(c1_xdelta, c1_ydelta)
c2.move(c2_xdelta, c2_ydelta)
# Print c1.__str__()
print(c1)
# Print c2.__str__()
print(c2)
# Print collision True or None
print("Collision: {collision}".format(collision = Circle.is_collision())
Example Output:
~Circle~ 1: Circle: x,y; coordinates: 0, 0; radius: 5.
~Circle~ 2: Circle: x,y; coordinates: 0, 0; radius: 5.
Collision: True
~Circle~ 1: Circle: x,y; coordinates: 16, 16; radius: 5.
~Circle~ 2: Circle: x,y; coordinates: 16, 136; radius: 5.
Collision: None
After correcting the collision() and distance() methods, your code should look something like:
import math
class Shape:
"""Shape class: has methods move(), location(), and __init__()."""
def __init__(self, x, y):
self.x = x
self.y = y
def move(self, deltaX, deltaY):
self.x = self.x + deltaX
self.y = self.y + deltaY
def location(self):
return "Circle at coordinates (%d, %d)" % (self.x, self.y)
class Circle(Shape):
"""Circle is a sub-class of shape and inherits the move() and location() methods."""
pi = 3.14159
def __init__(self, x=0, y=0, r=1):
Shape.__init__(self, x, y)
self.radius = r
def area(self):
return self.radius * self.radius * self.pi
def __str__(self):
return "Circle of radius %s at coordinates (%d, %d)" % (self.radius, self.x, self.y)
# Class methods
#classmethod
def is_collision(Circle, c1, c2):
'''Return True or False'''
return c1.radius + c2.radius >= Circle.distance(c1, c2)
#classmethod
def distance(Circle, c1, c2):
"""calculate distance between two circles"""
return math.sqrt(((c1.x-c2.x)**2)+((c1.y-c2.y)**2))
Example use:
from circle import Circle
c1 = Circle(0, 0, 5)
c2 = Circle(0, 0, 5)
print(c1)
print(c2)
print("Collision: {collision}".format(collision = Circle.is_collision(c1, c2)))
c1.move(16, 16)
c2.move(16, 136)
print(c1)
print(c2)
print("Collision: {}".format(Circle.is_collision(c1, c2)))
Example output:
Circle of radius 5 at coordinates (0, 0)
Circle of radius 5 at coordinates (0, 0)
Collision: True
Circle of radius 5 at coordinates (16, 16)
Circle of radius 5 at coordinates (16, 136)
Collision: False