Преобразование значений оси джойстика в шестнадцатеричные коды

Используя контроллер PS4 в Pygame, я уже выяснил, как захватить вращение оси, которое может варьироваться до -1 или 1, но я не знаю, как преобразовать эти числа в шкалу, подобную цветному кольцу, чтобы превратить его в шестнадцатеричный номер триплета.
Значения, имитирующие цветовое кольцо, важнее всего, поскольку я не хочу, чтобы джойстик захватывал цвет, пока он не находится в движении. Картина
(Поскольку это немного сбивало с толку, по сути, я хочу иметь возможность перемещать мой джойстик и фиксировать точное шестнадцатеричное число в зависимости от того, где он двигался)

Это мой код до сих пор:

import pygame

# Define some colors
BLACK    = (   0,   0,   0)
WHITE    = ( 62, 210, 255)

# This is a simple class that will help us print to the screen
# It has nothing to do with the joysticks, just outputting the
# information.
class TextPrint:
    def __init__(self):
        self.reset()
        self.font = pygame.font.Font(None, 25)

    def print(self, screen, textString):
        textBitmap = self.font.render(textString, True, BLACK)
        screen.blit(textBitmap, [self.x, self.y])
        self.y += self.line_height

    def reset(self):
        self.x = 25
        self.y = 25
        self.line_height = 30

    def indent(self):
        self.x += 10

    def unindent(self):
        self.x -= 10


pygame.init()

# Set the width and height of the screen [width,height]
size = [900, 1080]
screen = pygame.display.set_mode(size)

pygame.display.set_caption("PS4Testing")

#Loop until the user clicks the close button.
done = False

# Used to manage how fast the screen updates
clock = pygame.time.Clock()

# Initialize the joysticks
pygame.joystick.init()

# Get ready to print
textPrint = TextPrint()

# -------- Main Program Loop -----------
while done==False:
    # EVENT PROCESSING STEP
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop




    screen.fill(WHITE)
    textPrint.reset()

    # Get count of joysticks
    joystick_count = pygame.joystick.get_count()


    # For each joystick:
    for i in range(joystick_count):
        joystick = pygame.joystick.Joystick(i)
        joystick.init()

        # Usually axis run in pairs, up/down for one, and left/right for
        # the other.
        axes = joystick.get_numaxes()


        for i in range( axes ):
            axis = joystick.get_axis( i )
            textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )
        textPrint.unindent()



    # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT

    # Go ahead and update the screen with what we've drawn.
    pygame.display.flip()

    # Limit to 20 frames per second
    clock.tick(20)

# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit ()

Модифицированный код из официальной документации Pygame
Любая помощь будет принята с благодарностью

1 ответ

Решение

Мой план:

  1. Найти угол наклона джойстика
  2. Получить значение RGB, используя HSV и угол наклона палки
  3. Конвертировать в HEX

Нахождение угла джойстика

Для начала нам нужно найти угол наклона джойстика. Мы можем сделать это, используя закон косинусов и осевые операторы как длины сторон треугольника (потому что они находятся в одной точке / центре).

Сохраните операторы осей в этом блоке:

for i in range( axes ):
        axis = joystick.get_axis( i )
        #Storing axis statement
        if i == 0:
            Xaxis = axis
        elif i == 1:
            Yaxis = axis

        textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )

Мы храним их, потому что в цикле for мы можем принимать только один оператор за раз.

Затем определите функцию, которая будет возвращать угол клюшки. Нам нужно использовать math модуль для pi а также acos,

def get_angle(Xaxis,Yaxis):
    #To avoid ZeroDivisionError
    #P.S. - you can improve it a bit.
    if Xaxis == 0:
        Xaxis = 0.001
    if Yaxis == 0:
        Yaxis = 0.001
    #defining the third side of a triangle using the Pythagorean theorem
    b = ((Xaxis)**2 + (Yaxis)**2)**0.5
    c = Xaxis
    a = Yaxis
    #Using law of cosines we'll find angle using arccos of cos
    #math.acos returns angles in radians, so we need to multiply it by 180/math.pi
    angle =  math.acos((b**2 + c**2 - a**2) / (2*b*c)) * 180/math.pi
    #It'll fix angles to be in range of 0 to 360
    if Yaxis > 0:
        angle = 360 - angle
    return angle

Сейчас get_angle(Xaxis,Yaxis) вернет угол палки. Восток 0°, север 90°, запад 180°, юг 270°.

Получение HSV и конвертация в RGB

У нас есть угол наклона палки, и мы можем использовать его для создания цвета HSV, а затем преобразовать его в RGB, потому что цветовое колесо основано на оттенке цветов.

Оттенок имеет тот же диапазон, что и угол палки, поэтому мы можем использовать угол палки как оттенок.

Используя формулы из Википедии, определите функцию, которая конвертирует HSV в RGB.

def hsv_to_rgb(H,S,V):
    #0 <= H <= 360
    #0 <= S <= 1
    #0 <= V <= 1
    C = V * S
    h = H/60
    X = C * (1 - abs(h % 2 -1))

    #Yes, Python can compare like "0 <= 2 > 1"
    if 0 <= h <= 1:
        r = C; g = X; b = 0
    elif 1 <= h <= 2:
        r = X; g = C; b = 0
    elif 2 <= h <= 3:
        r = 0; g = C; b = X
    elif 3 <= h <= 4:
        r = 0; g = X; b = C
    elif 4 <= h <= 5:
        r = X; g = 0; b = C
    elif 5 <= h < 6:
        r = C; g = 0; b = X

    m = V - C

    #Final computing and converting from 0 - 1 to 0 - 255 
    R = int((r+m)*255)
    G = int((g+m)*255)
    B = int((b+m)*255)

    return [R,G,B]

Сейчас hsv_to_rgb(get_angle(Xaxis,Yaxis),1,1) вернет список красного, зеленого и синего в диапазоне от 0 до 255 (для более удобного преобразования в гекс). Насыщенность и значение не нужны в этом случае.

Преобразование в HEX

Самая простая часть. Нам нужно получить список RGB и преобразовать значения в шестнадцатеричные.

colors = hsv_to_rgb(get_angle(Xaxis,Yaxis),1,1)
#Converting to hex
lst = list(map(hex,colors))
#Cutting the "0x" part
for i in range(len(lst)):
    lst[i] = lst[i][2:]
    #If one of the colors has only one digit, extra 0 will be added for a better look
    if len(lst[i]) == 1:
        lst[i] = "0"+str(lst[i])
print(get_angle(Xaxis,Yaxis))

Что-то вроде #ff0000, #00ff00, а также #0000ff будет напечатан.

Вы также можете сделать свою программу, чтобы показать изменение цвета в режиме реального времени, просто добавив WHITE = colors в этом блоке. НЕ используйте его, если у вас светочувствительная эпилепсия.

Слияние всего

Поместите обе функции из первой и второй точек где-то в начале.

Добавить запоминание из первой точки в блок

for i in range( axes ):
    axis = joystick.get_axis( i )
    textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )

Добавьте преобразование из третьей точки после блока. Я рекомендую сделать функцию зоны смерти.

death_zone = 0.1
if abs(Xaxis) > death_zone or abs(Yaxis) > death_zone:
    #If you prefer HSV color wheel, use hsv_to_rgb(get_angle(Xaxis,Yaxis),1,1)
    #Else if you prefer RGB color wheel, use hsv_to_rgb(360-get_angle(Xaxis,Yaxis),1,1)
    colors = hsv_to_rgb(get_angle(Xaxis,Yaxis),1,1)
    #Converting to hex
    lst = list(map(hex,colors))
    #Cutting the "0x" part
    for i in range(len(lst)):
        lst[i] = lst[i][2:]
        #If one of the colors has only one digit, extra 0 will be added for a better look
        if len(lst[i]) == 1:
            lst[i] = "0"+str(lst[i])
    print("#"+"".join(lst))

Вот так может выглядеть ваш код:

PS - вам, вероятно, придется изменить какой-то код, потому что я думаю, что ось моего джойстика не была правильно зафиксирована.

import pygame
import math

# Define some colors
BLACK    = (   0,   0,   0)
WHITE    = ( 62, 210, 255)

def hsv_to_rgb(H,S,V):
    #Accirding to https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
    #0 <= H <= 360
    #0 <= S <= 1
    #0 <= V <= 1
    C = V * S
    h = H/60
    X = C * (1 - abs(h % 2 -1))

    #Yes, Python can compare like "0 <= 2 > 1"
    if 0 <= h <= 1:
        r = C; g = X; b = 0
    elif 1 <= h <= 2:
        r = X; g = C; b = 0
    elif 2 <= h <= 3:
        r = 0; g = C; b = X
    elif 3 <= h <= 4:
        r = 0; g = X; b = C
    elif 4 <= h <= 5:
        r = X; g = 0; b = C
    elif 5 <= h < 6:
        r = C; g = 0; b = X

    m = V - C

    #Final computing and converting from 0 - 1 to 0 - 255 
    R = int((r+m)*255)
    G = int((g+m)*255)
    B = int((b+m)*255)

    return [R,G,B]

def get_angle(Xaxis,Yaxis):
    #To avoid ZeroDivisionError
    #P.S. - you can improve it a bit.
    if Xaxis == 0:
        Xaxis = 0.001
    if Yaxis == 0:
        Yaxis = 0.001
    #defining the third side of a triangle using the Pythagorean theorem
    b = ((Xaxis)**2 + (Yaxis)**2)**0.5
    c = Xaxis
    a = Yaxis
    #Using law of cosines we'll fing angle using arccos of cos
    #math.acos returns angles in radians, so we need to multiply it by 180/math.pi
    angle =  math.acos((b**2 + c**2 - a**2) / (2*b*c)) * 180/math.pi
    #It'll fix angles to be in range of 0 to 360
    if Yaxis > 0:
        angle = 360 - angle
    return angle

# This is a simple class that will help us print to the screen
# It has nothing to do with the joysticks, just outputting the
# information.
class TextPrint:
    def __init__(self):
        self.reset()
        self.font = pygame.font.Font(None, 25)

    def print(self, screen, textString):
        textBitmap = self.font.render(textString, True, BLACK)
        screen.blit(textBitmap, [self.x, self.y])
        self.y += self.line_height

    def reset(self):
        self.x = 25
        self.y = 25
        self.line_height = 30

    def indent(self):
        self.x += 10

    def unindent(self):
        self.x -= 10


pygame.init()

# Set the width and height of the screen [width,height]
size = [900, 1080]
screen = pygame.display.set_mode(size)

pygame.display.set_caption("PS4Testing")

#Loop until the user clicks the close button.
done = False

# Used to manage how fast the screen updates
clock = pygame.time.Clock()

# Initialize the joysticks
pygame.joystick.init()

# Get ready to print
textPrint = TextPrint()

# -------- Main Program Loop -----------
while done==False:
    # EVENT PROCESSING STEP
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop




    screen.fill(WHITE)
    textPrint.reset()

    # Get count of joysticks
    joystick_count = pygame.joystick.get_count()


    # For each joystick:
    for i in range(joystick_count):
        joystick = pygame.joystick.Joystick(i)
        joystick.init()

        # Usually axis run in pairs, up/down for one, and left/right for
        # the other.
        axes = joystick.get_numaxes()


        for i in range( axes ):
            axis = joystick.get_axis( i )
            #Storing axis statement
            if i == 0:
                Xaxis = axis
            elif i == 1:
                Yaxis = axis

            textPrint.print(screen, "Axis {} value: {:>6.3f}".format(i, axis) )
        textPrint.unindent()

        #If joystick is not in the center
        #Death zone is used to not capture joystick if it's very close to the center
        death_zone = 0.1
        if abs(Xaxis) > death_zone or abs(Yaxis) > death_zone:
            #If you prefer HSV color wheel, use hsv_to_rgb(get_angle(Xaxis,Yaxis),1,1)
            #Else if you prefer RGB color wheel, use hsv_to_rgb(360-get_angle(Xaxis,Yaxis),1,1)
            colors = hsv_to_rgb(get_angle(Xaxis,Yaxis),1,1)
            #Converting to hex
            lst = list(map(hex,colors))
            #Cutting the "0x" part
            for i in range(len(lst)):
                lst[i] = lst[i][2:]
                #If one of the colors has only one digit, extra 0 will be added for a better look
                if len(lst[i]) == 1:
                    lst[i] = "0"+str(lst[i])
            print("#"+"".join(lst))
            #You can use it to see color change in real time.
            #But I don't recomend to use it if you have photosensitive epilepsy.
            #WHITE = colors

    # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT

    # Go ahead and update the screen with what we've drawn.
    pygame.display.flip()

    # Limit to 20 frames per second
    clock.tick(20)

# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit ()
Другие вопросы по тегам