Scale simulation real-time
The concept is simple enough. You have a scale that adds up the total weights on each side, and tilts accordingly. On the top corner is a weight. If you drag the weight, a new one appears in its place, giving you infinite weights. You can choose the weight for each weight, and always change it again when needed.
Here is a demonstration:
Here is the entire code:
import pygame
from random import randint as rt
pygame.init()
wn = pygame.display.set_mode((600, 500))
font = pygame.font.SysFont('Arial', 22)
class TextBox():
def __init__(self, x, y, w, h, color=(0, 0, 0), default=''):
self.input_box = pygame.Rect(x, y, w, h)
self.w = w
self.h = h
self.color_inactive = color
self.color_active = (200, 0, 0)
self.color = self.color_inactive
self.default = default
self.text = ''
self.active = False
def draw(self):
if not self.text:
self.text = '0'
txt = font.render(self.text, True, self.color)
width = max(self.w, txt.get_width()+10)
self.input_box.w = width
wn.blit(txt, (self.input_box.x+5, self.input_box.y+3))
pygame.draw.rect(wn, self.color, self.input_box, 2)
def check_status(self, pos):
if self.input_box.collidepoint(pos):
self.active = not self.active
else:
self.active = False
self.color = self.color_active if self.active else self.color_inactive
def type(self, event):
if self.active:
if event.key == pygame.K_RETURN:
pass
elif event.key == pygame.K_BACKSPACE:
if len(self.text) == 1:
self.text = '0'
else:
self.text = self.text[:-1]
else:
if self.text[0] == '0':
self.text = ''
self.text += event.unicode
objs = []
class Obj():
def __init__(self, color, x, y, w, h):
self.w = w
self.h = h
self.color = color
self.rect = pygame.rect.Rect(x, y, w, h)
self.dragging = False
self.offset_x = 0
self.offset_y = 0
self.offset_x2 = 0
self.offset_y2 = 0
self.weight1 = 0
self.weight2 = 0
self.txt_box = TextBox(x+10, x+10, w-20, h-20, default='0')
self.new = True
objs.append(self)
def clicked(self, pos):
return self.rect.collidepoint(pos)
def offset_click(self, pos):
self.dragging = True
self.offset_x = self.rect.x - pos[0]
self.offset_y = self.rect.y - pos[1]
self.offset_x2 = self.txt_box.input_box.x - pos[0]
self.offset_y2 = self.txt_box.input_box.y - pos[1]
def offset_drag(self, pos):
self.new = False
self.rect.x = self.offset_x + pos[0]
self.rect.y = self.offset_y + pos[1]
self.txt_box.input_box.x = self.offset_x2 + pos[0]
self.txt_box.input_box.y = self.offset_y2 + pos[1]
def draw(self):
pygame.draw.rect(wn, self.color, self.rect)
self.txt_box.draw()
class Scale():
def __init__(self, x1, x2, y, w, h):
self.rect1 = pygame.Rect(x1, y, w, h)
self.rect2 = pygame.Rect(x2, y, w, h)
self.w = w
self.h = h
self.hand1 = []
self.hand2 = []
self.tilted = 0
def move(self, n):
for o in self.hand1:
o.rect.y += n
o.txt_box.input_box.y += n
self.rect1.y += n
for o in self.hand2:
o.rect.y -= n
o.txt_box.input_box.y -= n
self.rect2.y -= n
def tilt(self):
self.weight1 = sum([int(o.txt_box.text) for o in self.hand1]) if o.txt_box.text else 0
self.weight2 = sum([int(o.txt_box.text) for o in self.hand2]) if o.txt_box.text else 0
if self.weight1 > self.weight2:
if not self.tilted:
self.move(80)
elif self.tilted == 'nag':
self.move(160)
self.tilted = 'pos'
elif self.weight1 < self.weight2:
if not self.tilted:
self.move(-80)
elif self.tilted == 'pos':
self.move(-160)
self.tilted = 'nag'
else:
if self.tilted == 'pos':
self.move(-80)
elif self.tilted == 'nag':
self.move(80)
self.tilted = False
def draw(self):
x1, y1 = self.rect1.x + self.w//2, self.rect1.y + self.h//2
x2, y2 = self.rect2.x + self.w//2, self.rect2.y + self.h//2
x, y_u, y_d = (x2-x1)//2 + x1, 240, 400
pygame.draw.line(wn, (150, 0, 150), (x1, y1), (x2, y2), 20)
pygame.draw.line(wn, (150, 0, 150), (x, y_u), (x, y_d), 20)
pygame.draw.rect(wn, (0, 0, 100), self.rect2)
pygame.draw.rect(wn, (0, 0, 100), self.rect1)
txt1 = font.render(str(self.weight1), True, (0, 0, 0))
txt2 = font.render(str(self.weight2), True, (0, 0, 0))
wn.blit(txt1, (self.rect1.x+30, self.rect1.y-30))
wn.blit(txt2, (self.rect2.x+30, self.rect2.y-30))
obj = Obj((rt(160, 255), rt(160, 255), rt(160, 255)), 30, 30, 50, 50)
sca = Scale(50, 350, 200, 200, 80)
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
for o in objs:
o.txt_box.check_status(event.pos)
if o.clicked(event.pos):
o.offset_click(event.pos)
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1:
for o in objs:
o.dragging = False
sca.hand1 = [o for o in objs if sca.rect1.collidepoint(o.rect.x, o.rect.y)]
sca.hand2 = [o for o in objs if sca.rect2.collidepoint(o.rect.x, o.rect.y)]
elif event.type == pygame.MOUSEMOTION:
for o in objs:
if o.dragging:
if o.new:
o.new = False
obj = Obj((rt(160, 255), rt(160, 255), rt(160, 255)), 30, 30, 50, 50)
o.offset_drag(event.pos)
if event.type == pygame.KEYDOWN:
if (event.unicode.isdigit() or event.key == pygame.K_BACKSPACE) or event.key == pygame.K_BACKSPACE:
for o in objs:
o.txt_box.type(event)
sca.tilt()
wn.fill((255, 255, 255))
sca.draw()
for o in objs:
o.draw()
pygame.display.flip()
If you scroll down you will see
obj = Obj((rt(160, 255), rt(160, 255), rt(160, 255)), 30, 30, 50, 50)
sca = Scale(50, 350, 200, 200, 80)
There you can change the color, position and size of the scale and weight.
Note that the obj
is only the first weight, you need to look inside the while
loop to see the generator,
which is
if o.new:
o.new = False
obj = Obj((rt(160, 255), rt(160, 255), rt(160, 255)), 30, 30, 50, 50)