Skip to main content
Post Made Community Wiki by risky mysteries
Source Link

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:

enter image description here

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)