I want a commet in pygame to shoot across the screen. Here is my commet class
class Commet:
def __init__(self):
self.x = -10
self.y = 10
self.radius = 20
self.commet = pygame.image.load(r"C:\Users\me\OneDrive\Documents\A level python codes\final game\commet.png")
self.commet = pygame.transform.scale(self.commet, (self.radius, self.radius))
self.drop = 0.0000009
self.speed = 2
self.pos = 0
self.commets = []
Then i added 20 commets to the self.commets list.
def tail(self, n): # n is a variable used to denote the length of the self.commets
for i in range(n):
if len(self.commets) <= n - 1:
self.commets.append(Commet())
I am having two problems. The first problem being moving the commet. To move it i did this
def move_tail(self):
for c in self.commets:
c.x += self.speed
for i in range(len(self.commets) - 1):
self.commets[i].y += ((self.commets[i + 1].x) ** 2) * self.drop
For x- coordinate i just added 2 to its value every frame. However, for the yvalue of the commet, i want it to produce a tail-like following effect. I tried assigning the y value of the commet to the square of x value of the commet in the index position one above the commet we are referring to in the list self.commets.I expected the commets to follow each other along a general x = y **2 quadradic curve. They do follow the curve but all at the same rate(i expected them to follow at different rate because all the commets have different x values), which dosent give me the tail-like effect. How would i be able to produce this tail-like effect?
The second part of my question is that i want the commets following the first one get smaller and smaller. I tried decreasing the radius value, which is used to scale the image i imported. The code looks like this
# Decrease radius
for i in range(n):
self.commets[i].radius = i + 1
When i print out the values of radius of the commets on the console, they range from 1 to 20, as i expect them to, but the size of the image that appears on the screen is the same for all the commets in the list.The following code is how i blit the commet
for i in range(n):
self.commets[i].pos = i * 10 # This line maintains a certain x- distance between commets
for c in self.tails:
D.blit(c.commet, (c.x - c.pos, c.y))
if self.pos >= n:
self.pos = n
Given you want your comet to fly from left to right on a FullHD screen.
The comet shall start at the left side at a y coordinate of 900, then reach its highest point at x=1400 and y = 100 and then fall to 600 at the right side of the screen.
A parabola is generally y = ax²+bx+c.
To be independent of the screen resolution, you would of course calculate those values from some percentage, say 900 ~ screen height * 83%, 600 ~ screen height * 55%, 1400 ~ screen width * 73%, 100 ~ screen height * 9%
With three points given, you can calculate a parabola:
class ParabolaFrom3Points:
def __init__(self, points: list):
self.a = (points[0][0] * (points[1][1] - points[2][1]) + points[1][0] * (
points[2][1] - points[0][1]) + points[2][0] * (points[0][1] - points[1][1])) / (
(points[0][0] - points[1][0]) * (points[0][0] - points[2][0]) * (
points[2][0] - points[1][0]))
self.b = (points[0][0] ** 2 * (points[1][1] - points[2][1]) + points[1][0] ** 2 * (
points[2][1] - points[0][1]) + points[2][0] ** 2 * (points[0][1] - points[1][1])) / (
(points[0][0] - points[1][0]) * (points[0][0] - points[2][0]) * (
points[1][0] - points[2][0]))
self.c = (points[0][0] ** 2 * (points[1][0] * points[2][1] - points[2][0] * points[1][1]) +
points[0][0] * (points[2][0] ** 2 * points[1][1] - points[1][0] ** 2 * points[2][1]) +
points[1][0] * points[2][0] * points[0][1] * (points[1][0] - points[2][0])) / (
(points[0][0] - points[1][0]) * (points[0][0] - points[2][0]) * (
points[1][0] - points[2][0]))
def y(self, x: int) -> int:
return int(self.a * x ** 2 + self.b * x + self.c)
The Comet is quite simple then. It just needs to know its parabola function and can then calculate the y from the x.
class Comet:
def __init__(self, radius: int, para: ParabolaFrom3Points):
self.x = -radius # Be invisible at the beginning
self.radius = radius
self.para = para
def move(self, x):
self.x = x
def paint(self, screen):
x = self.x
radius = self.radius
for tail in range(20):
pygame.draw.circle(screen, [255, 255, 255], (int(x), self.para.y(x)), radius)
x = x - radius / 2
radius -= 1
Test code:
import pygame
pygame.init()
pygame.fastevent.init()
clock = pygame.time.Clock()
window = pygame.display.set_mode((1920, 1080))
pygame.display.set_caption('Comet example')
comet = Comet(20, ParabolaFrom3Points([(0, 1080 * 0.83), (1920 * 0.73, 1080 * 0.12), (1920, 1080 * 0.55)]))
for x in range(-20, 1920 + 200, 3):
comet.move(x)
comet.paint(window)
clock.tick(90)
pygame.display.flip()
window.fill([0, 0, 0])
pygame.quit()
Related
I am writing a script to store movements over a hexgrid using Tkinter. As part of this I want to use a mouse-click on a Tkinter canvas to first identify the click location, and then draw a line between this point and the location previously clicked.
Generally this works, except that after I've drawn a line, it become an object that qualifies for future calls off the find_closest method. This means I can still draw lines between points, but selecting the underlying Hex in the Hexgrid over times becomes nearly impossible. I was wondering if someone could help me find a solution to exclude particular objects (lines) from the find_closest method.
edit: I hope this code example is minimal enough.
import tkinter
from tkinter import *
from math import radians, cos, sin, sqrt
class App:
def __init__(self, parent):
self.parent = parent
self.c1 = Canvas(self.parent, width=int(1.5*340), height=int(1.5*270), bg='white')
self.c1.grid(column=0, row=0, sticky='nsew')
self.clickcount = 0
self.clicks = [(0,0)]
self.startx = int(20*1.5)
self.starty = int(20*1.5)
self.radius = int(20*1.5) # length of a side
self.hexagons = []
self.columns = 10
self.initGrid(self.startx, self.starty, self.radius, self.columns)
self.c1.bind("<Button-1>", self.click)
def initGrid(self, x, y, radius, cols):
"""
2d grid of hexagons
"""
radius = radius
column = 0
for j in range(cols):
startx = x
starty = y
for i in range(6):
breadth = column * (1.5 * radius)
if column % 2 == 0:
offset = 0
else:
offset = radius * sqrt(3) / 2
self.draw(startx + breadth, starty + offset, radius)
starty = starty + 2 * (radius * sqrt(3) / 2)
column = column + 1
def draw(self, x, y, radius):
start_x = x
start_y = y
angle = 60
coords = []
for i in range(6):
end_x = start_x + radius * cos(radians(angle * i))
end_y = start_y + radius * sin(radians(angle * i))
coords.append([start_x, start_y])
start_x = end_x
start_y = end_y
hex = self.c1.create_polygon(coords[0][0], coords[0][1], coords[1][0], coords[1][1], coords[2][0],
coords[2][1], coords[3][0], coords[3][1], coords[4][0], coords[4][1],
coords[5][0], coords[5][1], fill='black')
self.hexagons.append(hex)
def click(self, evt):
self.clickcount = self.clickcount + 1
x, y = evt.x, evt.y
tuple_alfa = (evt.x, evt.y)
self.clicks.append(tuple_alfa)
if self.clickcount >= 2:
start = self.clicks[self.clickcount - 1]
startx = start[0]
starty = start[1]
self.c1.create_line(evt.x, evt.y, startx, starty, fill='white')
clicked = self.c1.find_closest(x, y)[0]
print(clicked)
root = tkinter.Tk()
App(root)
root.mainloop()
I am trying to generate and draw a sin waves. I am using this formulae that I found online y = Amp * sin(2 * PI * frequency * time + shift)
import pygame
import math
import time
window = pygame.display.set_mode((600, 600))
class Point:
def __init__(self):
self.x = 0
self.y = 0
class Line:
def __init__(self):
self.points = []
def generateLine(startX, nPoints, length, y):
line = Line()
for i in range(nPoints):
p = Point()
p.x = startX + ((i / nPoints) * length)
p.y = y
line.points.append(p)
return line;
nPoints = 100
line = generateLine(10, nPoints, 590, 300)
start = time.time()
accNPoints = 0
frequency = 100
amplitude = 30
overallY = 300
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
window.fill((255, 255, 255))
keys = pygame.key.get_pressed()
if (keys[pygame.K_a]): frequency -= 0.002
if (keys[pygame.K_d]): frequency += 0.002
if (keys[pygame.K_s]): amplitude -= 0.05
if (keys[pygame.K_w]): amplitude += 0.05
if (keys[pygame.K_q]): overallY += 0.5
if (keys[pygame.K_e]): overallY -= 0.5
if (keys[pygame.K_p]): accNPoints += 0.5
if (keys[pygame.K_o]): accNPoints -= 0.5
if accNPoints > 50:
line = generateLine(10, nPoints, 590, 300)
accNPoints = 0
nPoints += 1
elif accNPoints < -50:
line = generateLine(10, nPoints, 590, 300)
accNPoints = 0
nPoints -= 1
for i in range(1, len(line.points)):
#calculate y based on x
#y = A * sin(2 * PI * f * t + shift)
#yStart = (amplitude * math.sin(2 * math.pi * frequency * ((time.time() - start) * 0.01) + line.points[i].x)) + overallY
#yEnd = (amplitude * math.sin(2 * math.pi * frequency * ((time.time() - start) * 0.01) + line.points[i - 1].x)) + overallY
yStart = (amplitude * math.sin(2 * math.pi * frequency + line.points[i].x)) + overallY
yEnd = (amplitude * math.sin(2 * math.pi * frequency + line.points[i - 1].x)) + overallY
pygame.draw.circle(window, (255, 0, 0), (line.points[i].x, yStart), 1)
pygame.draw.circle(window, (255, 0, 0), (line.points[i - 1].x, yEnd), 1)
pygame.draw.aaline(
window,
(0, 0, 0),
(line.points[i].x, yStart),
(line.points[i - 1].x, yEnd)
)
pygame.display.flip()
There seems to be two problems. Changing frequency value does not really seem to change the frequency of the wave. Frequency seems to be dependent on the nPoints variable which is in the function that generates line i.e. def generateLine(startX, nPoints, length, y):.
The formula is wrong. The x-coordinate depends on the control variable of the loop (i). The y-coordinate needs to depend on the x-coordinate:
e.g.: Frequency 5 (5 waves)
frequency = 5
amplitude = 50
overallY = 300
while True:
# [...]
no_pts = window.get_width()
for i in range(no_pts):
x = i/no_pts * 2 * math.pi
y = (amplitude * math.cos(x * frequency)) + overallY
if i > 0:
pygame.draw.aaline(window, (0, 0, 0), prev_pt, (i, y))
prev_pt = (i, y)
# [...]
I wrote this function that draw a grid of triangles:
def create_triangles(side_length):
result = []
half_width = int(side_length / 2)
# height = int(side_length * math.sqrt(3) / 2)
height = side_length
max_width = 15 * side_length
max_height = 10 * height
for i in range(0, max_height, height):
if (i / height) % 2 == 0:
for j in range(0, max_width-half_width, half_width):
if j % side_length == 0:
triangle = (i-height/2, j-half_width, i+height/2, j, i-height/2, j+half_width)
else:
triangle = (i-height/2, j, i+height/2, j+half_width, i+height/2, j-half_width)
result.append(triangle)
else:
for j in range(half_width, max_width, half_width):
if j % side_length == 0:
triangle = (i-height/2, j-2*half_width, i+height/2, j-half_width+2, i-height/2, j)
else:
triangle = (i-height/2, j-half_width, i+height/2, j, i+height/2, j-2*half_width)
result.append(triangle)
return result
The current output is this:
As you can see some triangles are misaligned but I don't understand why.
As mentioned in the comments, floating points give you incorrect results; You want to make sure that the shared points representing the vertices of two adjacent triangles are concurrent. A simple approach is to reduce the points coordinates to ints, and organize the calculations so errors do not add up.
In the following examples, the misalignment is corrected, every triangle on the canvas is represented by a polygon, and individually drawn; each triangle can therefore be referenced when moused over, or addressed via an index, or a mapping (not implemented).
import tkinter as tk
import math
WIDTH, HEIGHT = 500, 500
class Point:
"""convenience for point arithmetic
"""
def __init__(self, x, y):
self.x, self.y = x, y
def __add__(self, other):
return Point(self.x + other.x, self.y + other.y)
def __iter__(self):
yield self.x
yield self.y
def tile_with_triangles(canvas, side_length=50):
"""tiles the entire surface of the canvas with triangular polygons
"""
triangle_height = int(side_length * math.sqrt(3) / 2)
half_side = side_length // 2
p0 = Point(0, 0)
p1 = Point(0, side_length)
p2 = Point(triangle_height, half_side)
for idx, x in enumerate(range(-triangle_height, WIDTH+1, triangle_height)):
for y in range(-side_length, HEIGHT+1, side_length):
y += half_side * (idx%2 + 1)
offset = Point(x, y)
pa, pb, pc = p0 + offset, p1 + offset,p2 + offset
canvas.create_polygon(*pa, *pb, *pc, outline='black', fill='', activefill='red')
p2 = Point(-triangle_height, half_side) # flip the model triangle
for idx, x in enumerate(range(-triangle_height, WIDTH+triangle_height+1, triangle_height)):
for y in range(-side_length, HEIGHT+1, side_length):
y += half_side * (idx%2 + 1)
offset = Point(x, y)
pa, pb, pc = p0 + offset, p1 + offset,p2 + offset
canvas.create_polygon(*pa, *pb, *pc, outline='black', fill='', activefill='blue')
root = tk.Tk()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg='cyan')
canvas.pack()
tile_with_triangles(canvas) #, side_length=10)
root.mainloop()
I added an active fill property that will change the colors of each triangle when you mouse over.
So I've been attempting to make some dots not only come towards a circle but also to make them orbit it. To do this I am using cosine and sine, however I'm running into issues with getting the dots to move forward as well as setting their distance. With the code below the dots are able to form a circle around the bigger dot, as well as follow it, but they don't approach the dot nor do they, when having the coordinates scaled by their distance from t1, come to that location, but instead do funky stuff. This is referring specifically to the line
t2.goto(2 * (t1.xcor() + math.degrees(math.cos(math.radians(t1.towards(t2)))) // 1), 2 * (t1.ycor() + math.degrees(math.sin(math.radians(t1.towards(t2)))) // 1))
which I had replaced with:
t2.goto(dist * (t1.xcor() + math.degrees(math.cos(math.radians(t1.towards(t2)))) // 1), dist * (t1.ycor() + math.degrees(math.sin(math.radians(t1.towards(t2)))) // 1))
and that gave me the sporadic view of the dots attempting to follow the bigger dot.
This line is found in the follow() function. Create() makes the smaller dots, move() moves the bigger dot and grow() grows the bigger dot on collision with the smaller dots. Produce() and redraw() are supposed to be a stage 2 of the program, but those functions are irrelevant to the question. Finally, quit() just exits the Screen() and quits the program.
Thanks to cdlane for help with organizing data and updating the screen more efficiently.
Code as of now:
from turtle import Turtle, Screen
import sys
import math
CURSOR_SIZE = 20
def move(x, y):
""" has it follow cursor """
t1.ondrag(None)
t1.goto(x, y)
screen.update()
t1.ondrag(move)
def grow():
""" grows t1 shape """
global t1_size, g
t1_size += 0.1
t1.shapesize(t1_size / CURSOR_SIZE)
g -= .1
t1.color((r/255, g/255, b/255))
screen.update()
def follow():
""" has create()'d dots follow t1 """
global circles, dist
new_circles = []
for (x, y), stamp in circles:
t2.clearstamp(stamp)
t2.goto(x, y)
dist = t2.distance(t1) / 57.29577951308232 // 1
t2.goto(2 * (t1.xcor() + math.degrees(math.cos(math.radians(t1.towards(t2)))) // 1), 2 * (t1.ycor() + math.degrees(math.sin(math.radians(t1.towards(t2)))) // 1))
t2.setheading(t2.towards(t1))
if t2.distance(t1) < t1_size // 1:
if t2.distance(t1) > t1_size * 1.2:
t2.forward(500/t2.distance(t1)//1)
else:
t2.forward(3)
if t2.distance(t1) > t1_size // 2:
new_circles.append((t2.position(), t2.stamp()))
else:
grow() # we ate one, make t1 fatter
screen.update()
circles = new_circles
if circles:
screen.ontimer(follow, 10)
else:
phase = 1
produce()
def create():
""" create()'s dots with t2 """
count = 0
nux, nuy = -400, 300
while nuy > -400:
t2.goto(nux, nuy)
if t2.distance(t1) > t1_size // 2:
circles.append((t2.position(), t2.stamp()))
nux += 20
count += 1
if count == 40:
nuy -= 50
nux = -400
count = 0
screen.update()
def quit():
screen.bye()
sys.exit(0)
def redraw():
t2.color("black")
t2.shapesize((t2_size + 4) / CURSOR_SIZE)
t2.stamp()
t2.shapesize((t2_size + 2) / CURSOR_SIZE)
t2.color("white")
t2.stamp()
def produce():
#create boundary of star
global t2_size, ironmax
t1.ondrag(None)
t1.ht()
t2.goto(t1.xcor(), t1.ycor())
t2.color("black")
t2.shapesize((t1_size + 4) / CURSOR_SIZE)
t2.stamp()
t2.shapesize((t1_size + 2) / CURSOR_SIZE)
t2.color("white")
t2.stamp()
#start producing helium
while t2_size < t1_size:
t2.color("#ffff00")
t2.shapesize(t2_size / 20)
t2.stamp()
t2_size += .1
redraw()
screen.update()
ironmax = t2_size
t2_size = 4
while t2_size < ironmax:
t2.shapesize(t2_size / 20)
t2.color("grey")
t2.stamp()
t2_size += .1
screen.update()
# variables
t1_size = 6
circles = []
phase = 0
screen = Screen()
screen.screensize(900, 900)
#screen.mode("standard")
t2 = Turtle('circle', visible=False)
t2.shapesize(4 / CURSOR_SIZE)
t2.speed('fastest')
t2.color('purple')
t2.penup()
t2_size = 4
t1 = Turtle('circle')
t1.shapesize(t1_size / CURSOR_SIZE)
t1.speed('fastest')
r = 190
g = 100
b = 190
t1.color((r/255, g/255, b/255))
t1.penup()
t1.ondrag(move)
screen.tracer(False)
screen.listen()
screen.onkeypress(quit, "Escape")
create()
follow()
#print(phase)
screen.mainloop()
I took another crack at this, just looking at the problem of meteors swarming around a planet. Or in this case, moon as I chose Deimos as my model. I attempted to work at scale making the coordinate system 1 pixel = 1 kilometer. At the start, Deimos sits in a field of meteors each of which has a random heading but they all have the same size and velocity:
from turtle import Turtle, Screen
from random import random
METEOR_VELOCITY = 0.011 # kilometers per second
METEOR_RADIUS = 0.5 # kilometers
SECONDS_PER_FRAME = 1000 # each updates represents this many seconds passed
UPDATES_PER_SECOND = 100
DEIMOS_RADIUS = 6.2 # kilometers
G = 0.000003 # Deimos gravitational constant in kilometers per second squared
CURSOR_SIZE = 20
def follow():
global meteors
new_meteors = []
t = SECONDS_PER_FRAME
for (x, y), velocity, heading, stamp in meteors:
meteor.clearstamp(stamp)
meteor.goto(x, y)
meteor.setheading(heading)
meteor.forward(velocity * t)
meteor.setheading(meteor.towards(deimos))
meteor.forward(G * t * t)
meteor.setheading(180 + meteor.towards(x, y))
if meteor.distance(deimos) > DEIMOS_RADIUS * 2:
new_meteors.append((meteor.position(), velocity, meteor.heading(), meteor.stamp()))
screen.update()
meteors = new_meteors
if meteors:
screen.ontimer(follow, 1000 // UPDATES_PER_SECOND)
def create():
""" create()'s dots with meteor """
count = 0
nux, nuy = -400, 300
while nuy > -400:
meteor.goto(nux, nuy)
if meteor.distance(deimos) > DEIMOS_RADIUS * 2:
heading = random() * 360
meteor.setheading(heading) # all meteors have random heading but fixed velocity
meteors.append((meteor.position(), METEOR_VELOCITY, meteor.heading(), meteor.stamp()))
nux += 20
count += 1
if count % 40 == 0:
nuy -= 50
nux = -400
screen.update()
meteors = []
screen = Screen()
screen.screensize(1000, 1000)
screen.setworldcoordinates(-500, -500, 499, 499) # 1 pixel = 1 kilometer
meteor = Turtle('circle', visible=False)
meteor.shapesize(2 * METEOR_RADIUS / CURSOR_SIZE)
meteor.speed('fastest')
meteor.color('purple')
meteor.penup()
deimos = Turtle('circle')
deimos.shapesize(2 * DEIMOS_RADIUS / CURSOR_SIZE)
deimos.color("orange")
deimos.penup()
screen.tracer(False)
create()
follow()
screen.mainloop()
The first variable to investigate is METEOR_VELOCITY. At the setting provided, most meteors will crash into the moon but a few obtain orbital velocity. If you halve its value, all meteors will crash into the moon. If you double its value, a few meteors obtain escape velocity, leaving the window; a few may crash into the moon; most will form an orbiting cloud that gets smaller and tighter.
I tossed the trigonometric stuff and reverted back to degrees instead of radians. I use vector addition logic to work out the motion.
In the end, it's just a crude model.
By changing 180 to some other offsets, for example 195, in the def follow() in cdlane's code,
meteor.setheading(195 + meteor.towards(x, y))
then the metors would not go straight (180 degree) towards the Deimos, but instead would show some spiral movement towards the center.
Great example provided!
I am attempting to draw a speedometer using a Tkinter Canvas in Python and am having a few problems with my code that I can't seem to figure out. First off, here is what I have written:
import tkinter as tk
from tkinter import ttk
import math
class DrawMeter(tk.Canvas):
def __init__(self, parent, *args, **kwargs):
tk.Canvas.__init__(self, parent, *args, **kwargs)
self.config(bg = "grey")
if (int(self['height']) * 2 > int(self['width'])):
boxSide = int(self['width'])
else:
boxSide = int(self['height']) * 2
self.boxX = boxSide / 2
self.boxY = boxSide / 2
self.boxRadius = int(0.40 * float(boxSide))
self.start = 0
self.end = 1
self.drawBackground()
self.drawTicks()
self.drawNeedle()
def drawBackground(self):
bgColour = "black"
self.create_arc((self.boxX - self.boxRadius,
self.boxY - self.boxRadius,
self.boxX * 4,
self.boxY * 4),
fill = bgColour, start = 90)
def drawTicks(self):
length = self.boxRadius / 8
for deg in range(5, 85, 6):
rad = math.radians(deg)
self.Tick(rad, length)
for deg in range(5, 91, 18):
rad = math.radians(deg)
self.Tick(rad, length * 2)
def Tick(self, angle, length):
cos = math.cos(angle)
sin = math.sin(angle)
radius = self.boxRadius * 2
X = self.boxX * 2
Y = self.boxY * 2
self.create_line((X - radius * cos,
Y - radius * sin,
X - (radius - length) * cos,
Y - (radius - length) * sin),
fill = "white", width = 2)
def drawText(self, start = 0, end = 100):
interval = end / 5
value = start
length = self.boxRadius / 2
for deg in range(5, 91, 18):
rad = math.radians(deg)
cos = math.cos(rad)
sin = math.sin(rad)
radius = self.boxRadius * 2
self.create_text(self.boxX * 2 - (radius - length - 1) * cos,
self.boxY * 2 - (radius - length - 1) * sin,
text = str("{0:.1f}".format(value)),
fill = "white",
font = ("Arial", 12, "bold"))
value = value + interval
def setRange(self, start, end):
self.start = start
self.end = end
self.drawText(start, end)
def drawNeedle(self):
X = self.boxX * 2
Y = self.boxY * 2
length = self.boxRadius - (self.boxRadius / 4)
self.meterHand = self.create_line(X / 2, Y / 2, X + length, Y + length,
fill = "red", width = 4)
self.create_arc(X - 30, Y - 30, X + 30, Y + 30,
fill = "#c0c0c0", outline = "#c0c0c0", start = 90)
def updateNeedle(self, value):
length = self.boxRadius - (self.boxRadius / 4)
deg = 80 * (value - self.start) / self.end - 180
rad = math.radians(deg)
self.coords(self.meterHand, self.boxX * 2, self.boxY * 2,
self.boxX + length * math.cos(rad),
self.boxY + length * math.sin(rad))
value = 0
def update_frame():
global value
if value < 1:
value = value + 0.01
print(value)
meter.updateNeedle(value)
container.after(200, update_frame)
root = tk.Tk()
container = tk.Frame(root)
container.pack()
meter = DrawMeter(container, height = 200, width = 200, bg = "red")
meter.setRange(0, 1)
meter.pack()
update_frame()
root.mainloop()
So the problem is I am having is that my needle is drawing and updating properly on the screen. When I start the program, the needle starts at around 0.2ish, and goes until about 0.6 and then stop. I feel like my formula for calculating the needle's position is wrong, but I am not sure what about it is wrong.
The way I have it set up, is it takes the the percentage of the total the value is (value = self.start) / self.end) and multiplies it by 80 degrees (because my speedometer starts at the 5 degree marks and ends at 85) and them subtracts 180 so that the number makes the number go clockwise, not counter clockwise.
My placement of the canvas objects could also be off. My attempt was to set up a Speedometer that is a quarter circle at the bottom of the Canvas. However when you use the Canvas create_arc function, it draws the bottom right corner of your arc, in the center of the bounding box, meaning you make it the bottom right corner, I need to make by bounding box double the width and height of the canvas. I'm thinking maybe that threw me off a bit as well.
My problem was that I needed to create an offset value and add it to all four points in the Canvas.coords call.