如何在pygame中从一种颜色淡入另一种颜色?

时间:2018-08-22 18:56:16

标签: python colors pygame

我如何在pygame中从一种颜色淡入另一种颜色?我要慢慢将圆圈的颜色从绿色变为蓝色,从紫色变为粉红色,再由红色变为橙色,再从黄色变为绿色。我该怎么做?目前,我正在使用

def colour():
    switcher = {
        0: 0x2FD596,
        1: 0x2FC3D5,
        2: 0x2F6BD5,
        3: 0x432FD5,
        4: 0x702FD5,
        5: 0xBC2FD5,
        6: 0xD52F91,
        7: 0xD52F43,
        8: 0xD57F2F,
        9: 0xD5D52F,
        10: 0x64D52F,
        11: 0x2FD557,
    }
    return switcher.get(round((datetime.datetime.now() - starting_time).total_seconds()%11))

但是在颜色之间确实有很大的跨度,而且看上去笨拙。

7 个答案:

答案 0 :(得分:4)

关键是要简单地计算每个步骤中每个通道(a,r,g和b)的更改量。 Pygame的import React from 'react'; import ReactDOM from 'react-dom'; import HouseFull from '../HouseFull'; import {shallow} from 'enzyme'; test('check HouseFull Render', () => { const div = document.createElement('div'); ReactDOM.render(<HouseFull />, div); }); it('Check for prop = true', () => { const wrapper = shallow(<HouseFull hasSeat={true}/>); expect(wrapper.text().toLowerCase()).toEqual('vacant'); }); it('Check for prop = false', () => { const wrapper = shallow(<HouseFull hasSeat={false}/>); expect(wrapper.text().toLowerCase()).toEqual('housefull'); //expect(wrapper.contains(<div>HouseFull</div>)).toEqual(true); }); 类非常方便,因为它允许在每个通道上进行迭代,并且输入灵活,因此您可以更改例如在下面的示例中,从Color'blue',它将仍然运行。

这是一个简单的示例:

0x2FD596

enter image description here


如果您不想依赖于帧速率,而是使用基于时间的方法,则可以将代码更改为:

import pygame
import itertools

pygame.init()

screen = pygame.display.set_mode((800, 600))

colors = itertools.cycle(['green', 'blue', 'purple', 'pink', 'red', 'orange'])

clock = pygame.time.Clock()

base_color = next(colors)
next_color = next(colors)
current_color = base_color

FPS = 60
change_every_x_seconds = 3.
number_of_steps = change_every_x_seconds * FPS
step = 1

font = pygame.font.SysFont('Arial', 50)

running = True
while running:

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    text = font.render('fading {a} to {b}'.format(a=base_color, b=next_color), True, pygame.color.Color('black'))

    step += 1
    if step < number_of_steps:
        # (y-x)/number_of_steps calculates the amount of change per step required to 
        # fade one channel of the old color to the new color
        # We multiply it with the current step counter
        current_color = [x + (((y-x)/number_of_steps)*step) for x, y in zip(pygame.color.Color(base_color), pygame.color.Color(next_color))]
    else:
        step = 1
        base_color = next_color
        next_color = next(colors)

    screen.fill(pygame.color.Color('white'))
    pygame.draw.circle(screen, current_color, screen.get_rect().center, 100)
    screen.blit(text, (230, 100))
    pygame.display.update()
    clock.tick(FPS)

答案 1 :(得分:3)

您可以将所有颜色从一种颜色转换为另一种颜色,方法是将其转换为int,增加数字,然后将其转换回十六进制。然后循环,直到达到下一个值,如下所示:

value1 = 0xff00ff
value2 = 0xffffff
increment = 1 # amount to decrease or increase the hex value by
while value1 != value2:
    if value1 > value2:
        if int(value1)-increment < int(value2): # failsafe if the increment is greater than 1 and it skips being the value
            value1 = value2
        else:
            value1 = hex(int(value1)-increment)
    else:
        if int(value1)+increment > int(value2):
            value1 = value2
        else:
            value1 = hex(int(value1)+increment)
    code_to_change_colour(value1)

有关此实现的更优雅的实现,请参见Prune的编辑。请注意,code_to_change_colour(value1)应该更改为,但是您要在程序中更改颜色。增量将使您更改跳过的颜色数。显然,此代码需要以易于使用的方式进行编辑:例如类似def fade(value1, value2)的函数。


通过@Prune编辑-因为代码在注释中无法正常工作。

请注意,您编写的大部分内容都是“仅”循环控制。您已经知道了起始值和终止值以及固定的增量。这建议使用for循环而不是while。考虑一下:

value1 = int(0xff00ff)
value2 = int(0xffffff)
increment = 1 if value1 < value2 else -1

for current in range(value1, value2, increment):
    code_to_change_colour(hex(value1))

value1 = value2        

答案 2 :(得分:2)

如果您只想计算颜色(不使用任何表面),则可以执行以下操作:

首先,您需要确定溶解所需的时间。您还需要存储原始和最终颜色。最后,计算混合。我将为此创建一个类:

import pygame
import time

class color_blend:
    def __init__(self, start_color, end_color, duration=1000):
        self.start_color = pygame.Color(start_color.r, start_color.g, start_color.b)
        self.current_color = pygame.Color(start_color.r, start_color.g, start_color.b)
        self.end_color = end_color
        self.duration = float(duration)
        self.start_time = color_blend.millis()

    # Return current time in ms
    @staticmethod
    def millis():
        return (int)(round(time.time() * 1000))

    # Blend any 2 colors
    # 0 <= amount <= 1 (0 is all initial_color, 1 is all final_color)
    @staticmethod
    def blend_colors(initial_color, final_color, amount):
        # Calc how much to add or subtract from start color
        r_diff = (final_color.r - initial_color.r) * amount
        g_diff = (final_color.g - initial_color.g) * amount
        b_diff = (final_color.b - initial_color.b) * amount

        # Create and return new color
        return pygame.Color((int)(round(initial_color.r + r_diff)),
                            (int)(round(initial_color.g + g_diff)),
                            (int)(round(initial_color.b + b_diff)))

    def get_next_color(self):
        # Elapsed time in ms
        elapsed_ms = color_blend.millis() - self.start_time

        # Calculate percentage done (0 <= pcnt_done <= 1)
        pcnt_done = min(1.0, elapsed_ms / self.duration)

        # Store new color
        self.current_color = color_blend.blend_colors(self.start_color, self.end_color, pcnt_done)
        return self.current_color

    def is_finished(self):
        return self.current_color == self.end_color

# Blend red to green in .3 seconds
c = color_blend(pygame.Color(255, 0, 0), pygame.Color(0, 255, 0), 300)
while not c.is_finished():
    print(c.get_next_color())

您可以轻松地对此进行修改以进行非线性混合。例如,在blend_colors中:amount = math.sin(amount * math.pi)

(我不是Pygame专家-可能已经有内置功能了。)

答案 3 :(得分:1)

在新颜色的背景上,将前景色设置为旧颜色。使用set_alpha()执行淡入淡出。一旦您完全采用了新颜色,就可以使该表面成为前景,并为您的第三种颜色创建新背景。根据需要重复。

This question和其他对“ fade”和set_alpha()的引用应该可以使您完成工作。

就足以让您动起来吗?

答案 4 :(得分:1)

我犹豫要发布答案,因为我想出了与Sloth几乎相同的答案,但我只想提及linear interpolation(简称lerp,在英文中也称为mix OpenGL / GLSL)。它通常用于两种颜色之间的混合,但是不幸的是pygame的Color类没有lerp方法,因此您必须定义自己的lerp函数并使用列表推导来内插RGBA值。

这是Wikipedia移植到Python的lerp函数(t是权重,必须在0到1之间):

def lerp(v0, v1, t):
    return (1 - t) * v0 + t * v1

现在,您可以通过列表理解来掌握两种颜色的RGBA值。

color = [lerp(v0, v1, t) for v0, v1 in zip(color1, color2)]

例如:

>>> [lerp(v0, v1, .5) for v0, v1 in zip((0, 0, 0), (255, 255, 255))]
[127.5, 127.5, 127.5]
>>> [lerp(v0, v1, .25) for v0, v1 in zip((0, 0, 0), (255, 255, 255))]
[63.75, 63.75, 63.75]

如果不需要Alpha通道,还可以使用pygame的Vector3类,该类具有lerp方法来设置颜色,那么您只需要编写:{{1} }。

color = color1.lerp(color2, t)

答案 5 :(得分:0)

不久前我遇到了类似的问题,我走了一条疯狂的路线,学习一些微积分来做到这一点 R = X,G = Y,B = Z

然后编写了一个程序来计算R0和R1(X0和X1)等之间的差。

#Nick Poling
#Fade Test V2

import random
#import mpmath
#import sympy
import time
import pygame
import shelve
import sys
from pygame.locals import *

#Always Initialize
pygame.init()

#sympy contains function line_3d?
#top level?
#formated string?

#Change Name Displayed in Corner
MY_FONT = 'freesansbold.ttf'
FONTSIZE_1 = 20
pygame.display.set_caption('Fade Test V2')
GAME_NAME = pygame.font.Font(MY_FONT, FONTSIZE_1)

#Boards
GAME_SCREEN_WIDTH = 900
GAME_SCREEN_HEIGHT = 600

Main_Game_Loop = 1

def get_close_out():
    #Save_Game = get_Save_Game()
    pygame.quit()
    sys.exit()

def get_Save_Game():
    #Save
    global Main_Game_Loop
    global GAME_SCREEN_COLOR
    global GAME_SCREEN_WIDTH
    global GAME_SCREEN_HEIGHT
    saveGameShelfFile = shelve.open('Fade Test V1')
    saveGameShelfFile['GAME_SCREEN_WIDTH'] = GAME_SCREEN_WIDTH
    saveGameShelfFile['GAME_SCREEN_HEIGHT'] = GAME_SCREEN_HEIGHT

def get_Load_Game():
    global Main_Game_Loop
    global GAME_SCREEN_COLOR
    global GAME_SCREEN_WIDTH
    global GAME_SCREEN_HEIGHT
    try:
        #Load
        saveGameShelfFile = shelve.open('Fade Test V1')
        GAME_SCREEN_WIDTH = saveGameShelfFile['GAME_SCREEN_WIDTH']
        GAME_SCREEN_HEIGHT = saveGameShelfFile['GAME_SCREEN_HEIGHT']
    except:
        #Save
        #Save_Game = get_Save_Game()
        #Load
        saveGameShelfFile = shelve.open('Fade Test V1')
        GAME_SCREEN_WIDTH = saveGameShelfFile['GAME_SCREEN_WIDTH']
        GAME_SCREEN_HEIGHT = saveGameShelfFile['GAME_SCREEN_HEIGHT']
    GAME_SCREEN = pygame.display.set_mode((GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT),pygame.RESIZABLE)
    #By putting the GAME_SCREEN here you can make the resize doable with the press of a button
    #Does need to be un "#" to work when press "L"

def get_Colors():
    #Colors
    global BLACK
    global WHITE
    BLACK = [0, 0, 0]
    WHITE = [255,255,255]

def get_Main_Game():
    global Main_Game_Loop
    global GAME_SCREEN_COLOR
    global GAME_SCREEN_WIDTH
    global GAME_SCREEN_HEIGHT
    global BLACK
    global WHITE
    global Point_1
    global Point_2
    global Vector_1
    global Vector_2
    Colors = get_Colors()
    GAME_SCREEN_COLOR = BLACK
    #Load_Game = get_Load_Game()
    GAME_SCREEN = pygame.display.set_mode((GAME_SCREEN_WIDTH, GAME_SCREEN_HEIGHT),pygame.RESIZABLE)
    while Main_Game_Loop == 1:
        GAME_SCREEN.fill(GAME_SCREEN_COLOR)
        Equation_Of_Lines_in_3D_Space = get_Equation_Of_Lines_in_3D_Space()
        for t in range(0,255):
            XYZ_1 = [Point_1[0] + (Vector_1[0] * t), Point_1[1] + (Vector_1[1] * t), Point_1[2] + (Vector_1[2] * t)]
            XYZ_2 = [Point_2[0] + (Vector_2[0] * t), Point_2[1] + (Vector_2[1] * t), Point_2[2] + (Vector_2[2] * t)]
            GAME_SCREEN_COLOR = XYZ_1
            GAME_SCREEN.fill(GAME_SCREEN_COLOR)
            ticks = pygame.time.delay(5)
            pygame.display.update()
            for event in pygame.event.get():
                if event.type == QUIT:
                    close_out = get_close_out()
                elif event.type == pygame.VIDEORESIZE:
                    # There's some code to add back window content here.
                    surface = pygame.display.set_mode((event.w, event.h),pygame.RESIZABLE)
                    GAME_SCREEN_HEIGHT = event.h
                    GAME_SCREEN_WIDTH = event.w
        pygame.display.update()

def get_Equation_Of_Lines_in_3D_Space():
    global Point_1
    global Point_2
    global BLACK
    global WHITE
    global Vector_1
    global Vector_2
    global LCM_X1
    global LCM_X2
    global LCM_Y1
    global LCM_Y2
    global LCM_Z1
    global LCM_Z2
    Point_1 = BLACK
    Point_2 = WHITE
    Vector_1 = []
    Vector_2 = []
    LCM_X1 = []
    LCM_X2 = []
    LCM_Y1 = [] 
    LCM_Y2 = [] 
    LCM_Z1 = []
    LCM_Z2 = []
    for i in range(0,3):
        #
        Delta_XYZ_1 = Point_2[i] - Point_1[i]
        Vector_1.append(Delta_XYZ_1)
        Delta_XYZ_2 = Point_1[i] - Point_2[i]
        Vector_2.append(Delta_XYZ_2)
    factors = get_factors()

def get_factors():
    global num_1
    global num_2
    global Vector_1
    global Vector_2
    global LCM_XYZ_1
    global LCM_XYZ_2
    for i in range(1,7):
        if i == 1:
            num_1 = Vector_1[0]
            num_2 = 1
        elif i == 2:
            num_1 = Vector_2[0]
            num_2 = 2
        elif i == 3:
            num_1 = Vector_1[1]
            num_2 = 3
        elif i == 4:
            num_1 = Vector_2[1]
            num_2 = 4
        elif i == 5:
            num_1 = Vector_1[2]
            num_2 = 5
        elif i == 6:
            num_1 = Vector_2[2]
            num_2 = 6
        get_largest_and_lowest_common_factors(num_1)
    get_LCM_XYZ()
    Vector_1[0] = Vector_1[0] / LCM_XYZ_1[0]
    Vector_1[1] = Vector_1[1] / LCM_XYZ_1[0]
    Vector_1[2] = Vector_1[2] / LCM_XYZ_1[0]
    #
    Vector_2[0] = Vector_2[0] / LCM_XYZ_2[0]
    Vector_2[1] = Vector_2[1] / LCM_XYZ_2[0]
    Vector_2[2] = Vector_2[2] / LCM_XYZ_2[0]

def get_largest_and_lowest_common_factors(x):
    global num_1
    global num_2
    global Vector_1
    global Vector_2
    global LCM_X1
    global LCM_X2
    global LCM_Y1
    global LCM_Y2
    global LCM_Z1
    global LCM_Z2
    #This function takes a number and puts its factor into a list
    for i in range(1, x + 1) or range(-x, x - 1, -1):
        try:
            if x % i == 0:
                if num_1 == Vector_1[0] and num_2 == 1:
                    LCM_X1.append(i)
                elif num_1 == Vector_1[1] and num_2 == 3:
                    LCM_Y1.append(i)
                elif num_1 == Vector_1[2] and num_2 == 5:
                    LCM_Z1.append(i)
                elif num_1 == Vector_2[0] and num_2 == 2:
                    LCM_X2.append(i)
                elif num_1 == Vector_2[1] and num_2 == 4:
                    LCM_Y2.append(i)
                elif num_1 == Vector_2[2] and num_2 == 6:
                    LCM_Z2.append(i)
        except  ZeroDivisionError:
            return 0

def get_LCM_XYZ():
    global LCM_X1
    global LCM_Y1
    global LCM_Z1
    global LCM_X2
    global LCM_Y2
    global LCM_Z2
    global LCM_XYZ_1
    global LCM_XYZ_2
    #If 1 is 0
    check_1 = 0
    check_2 = 0
    check_3 = 0
    for i in range(0,3):
        if i == 0:
            if LCM_X1 == [] and LCM_X2 == []:
                check_1 = 1
        elif i == 1:
            if LCM_Y1 == [] and LCM_Y2 == []:
                check_2 = 2
        elif i == 2:
            if LCM_Z1 == [] and LCM_Z2 == []:
                check_3 = 3
    F_check = check_1 + check_2 + check_3
    if F_check == 1:
        LCM_X1.extend(LCM_Y1)
        LCM_X2.extend(LCM_Y2)
    elif F_check == 2:
        LCM_Y1.extend(LCM_X1)
        LCM_Y2.extend(LCM_X2)
    elif F_check == 3:
        if check_2 == 0:
            LCM_Z1.extend(LCM_Y1)
            LCM_Z2.extend(LCM_Y2)
        elif check_2 != 0:
            LCM_X1.extend(LCM_Z1)
            LCM_X2.extend(LCM_Z2)
            LCM_Y1.extend(LCM_Z1)
            LCM_Y2.extend(LCM_Z2)
    elif F_check == 4:
        LCM_X1.extend(LCM_Y1)
        LCM_X2.extend(LCM_Y2)
        LCM_Z1.extend(LCM_Y1)
        LCM_Z2.extend(LCM_Y2)
    elif F_check == 5:
        LCM_Y1.extend(LCM_X1)
        LCM_Y2.extend(LCM_X2)
        LCM_Z1.extend(LCM_X1)
        LCM_Z2.extend(LCM_X2)
    elif F_check == 6:
        LCM_X1.append(1)
        LCM_X2.append(1)
        LCM_Y1.append(1)
        LCM_Y2.append(1)
        LCM_Z1.append(1)
        LCM_Z2.append(1)
    LCM_X1 = set(LCM_X1)
    LCM_Y1 = set(LCM_Y1)
    LCM_Z1 = set(LCM_Z1)
    LCM_X2 = set(LCM_X2)
    LCM_Y2 = set(LCM_Y2)
    LCM_Z2 = set(LCM_Z2)
    LCM_XYZ_1 = list(set.intersection(LCM_X1,LCM_Y1,LCM_Z1))
    LCM_XYZ_2 = list(set.intersection(LCM_X2,LCM_Y2,LCM_Z2))
    LCM_XYZ_1.sort(reverse = True)
    LCM_XYZ_2.sort(reverse = True)


Main_Game = get_Main_Game()

答案 6 :(得分:0)

Pygame 提供 pygame.Color 对象。该对象可以从各种参数(例如 RGBA 颜色通道、十六进制数字、字符串等)构造颜色。
它还提供了方便的方法 lerp,可以插入 2 种颜色:

<块引用>

返回一个颜色,它是自身和 RGBA 空间中给定颜色之间的线性插值

使用 pygame.Color 对象和 lerp 方法从颜色列表中插入颜色:

def lerp_color(colors, value):
    fract, index = math.modf(value)
    color1 = pygame.Color(colors[int(index) % len(colors)])
    color2 = pygame.Color(colors[int(index + 1) % len(colors)])
    return color1.lerp(color2, fract)

插值值必须随时间变化。使用 pygame.time.get_ticks 以毫秒为单位获取当前时间:

colors = ["green", "blue", "purple", "pink", "red", "orange", "yellow"]
value = (pygame.time.get_ticks() - start_time) / 1000
current_color = lerp_color(colors, value)

另见Color - Lerp


最小示例:

import pygame, math

def lerp_color(colors, value):
    fract, index = math.modf(value)
    color1 = pygame.Color(colors[int(index) % len(colors)])
    color2 = pygame.Color(colors[int(index + 1) % len(colors)])
    return color1.lerp(color2, fract)

pygame.init()
window = pygame.display.set_mode((400, 300))
clock = pygame.time.Clock()
start_time = pygame.time.get_ticks()
run = True
while run:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False
        if event.type == pygame.KEYDOWN:
            start_time = pygame.time.get_ticks()

    colors = ["green", "blue", "purple", "pink", "red", "orange", "yellow"]
    value = (pygame.time.get_ticks() - start_time) / 1000
    current_color = lerp_color(colors, value)

    window.fill((255, 255, 255))
    pygame.draw.circle(window, current_color, window.get_rect().center, 100)
    pygame.display.flip()

pygame.quit()
exit()
相关问题