如何正确添加对象之间逐渐增加/减少的空间?

Posted

技术标签:

【中文标题】如何正确添加对象之间逐渐增加/减少的空间?【英文标题】:How to properly add gradually increasing/decreasing space between objects? 【发布时间】:2021-02-24 05:07:59 【问题描述】:

我试图实现从一定量空间到另一个类似于加速和减速的转换,除了我失败了,我唯一得到的就是这个无限的混乱堆栈,这是一个显示这个的屏幕截图实际操作:

你可以在这里看到一个非常黑的圆圈,实际上是 100 或 200 个圆圈堆叠在一起

我使用这段代码达到了这个结果:

def Place_circles(curve, circle_space, cs, draw=True, screen=None):
    curve_acceleration = []
    if type(curve) == tuple:
        curve_acceleration = curve[1][0]
        curve_intensity = curve[1][1]
        curve = curve[0]
        #print(curve_intensity)
        #print(curve_acceleration)
    Circle_list = []
    idx = [0,0]
    for c in reversed(range(0,len(curve))):
        for p in reversed(range(0,len(curve[c]))):
            user_dist = circle_space[curve_intensity[c]] + curve_acceleration[c] * p
            dist = math.sqrt(math.pow(curve[c][p][0] - curve[idx[0]][idx[1]][0],2)+math.pow(curve [c][p][1] - curve[idx[0]][idx[1]][1],2))
            if dist > user_dist:
                idx = [c,p]
                Circle_list.append(circles.circles(round(curve[c][p][0]), round(curve[c][p][1]), cs, draw, screen))

这个地方的圆圈取决于当前曲线的强度(0 到 2 之间的数字,随机),它等于空间量(假设在 20 到 30 之间,20 是索引 0,30 是索引 2并且这两个之间的数字是索引 1)。

这会创建您在上面看到的堆栈,这不是我想要的,我还得出结论,我不能使用加速度,因为在 2 点之间移动的时间取决于我需要点击的圈数,知道每个点之间有多个圆,但无法确定有多少导致我无法使用经典的加速度公式。

所以我在这里没有选择余地,也没有关于如何从一定数量的空间过渡到另一个空间的想法。 有什么想法吗?

PS:我放弃了上面的想法并切换回我的主分支,但是我在这里创建的分支中仍然可以使用此代码 https://github.com/Mrcubix/Osu-StreamGenerator/tree/acceleration 。 所以现在我回到了不具备加速或减速的正常代码。

TL:DR 我不能使用加速度,因为我不知道要在 2 点之间放置的圈数并使行进时间不同(我需要以 180 bpm 的速度单击圈子的示例每 0.333 秒一个圆圈),所以我正在寻找另一种方法来生成逐渐变化的空间。

【问题讨论】:

你的问题不是很清楚。对于加速部分,请尝试按顺序对一组随机数进行排序。依次将每个数字添加到速度,直到到达终点。然后返回数组,从速度中减去每个数字。这给出了在中间以最大速度加速和减速的外观。 除了我不知道如何利用它,因为这也不清楚,我不知道我应该在每条曲线上放多少圈,因为它们有不同的距离等等,我不想放置太多,否则它会创建一个堆栈,我不想放置太少,或者它只是创建一个应该在 0.6 秒内点击的间隙 也许您需要将大问题分解为一系列小问题,并在需要帮助解决其中一个小问题时在这里询问? 问题就在标题中,如何在不知道要放置的对象数量的情况下逐渐添加或删除对象之间的间距(使用算法或我不使用的数学/物理函数)不知道吗?) 【参考方案1】:

首先,我使用了为 [0 中的每条曲线生成强度的函数; 2] 然后我放弃了加速公式,因为它无法使用。 现在我正在使用一种基本算法来确定我可以在曲线上放置的最大圆数。

现在我的脚本工作方式如下: 我首先生成一个流(需要以高 bpm 点击的多个圆圈) 这样我就获得了折线的每条曲线(或线段)的长度。 我使用以下函数为每条曲线生成强度:

def generate_intensity(Circle_list: list = None, circle_space: int = None, Args: list = None):
    curve_intensity = []
    if not Args or Args[0] == "NewProfile":
        prompt = True
        while prompt:
            max_duration_intensity = input("Choose the maximum amount of curve the change in intensity will occur for: ")
            if max_duration_intensity.isdigit():
                max_duration_intensity = int(max_duration_intensity)
                prompt = False
        prompt = True
        while prompt:
            intensity_change_odds = input("Choose the odds of occurence for changes in intensity (1-100): ")
            if intensity_change_odds.isdigit():
                intensity_change_odds = int(intensity_change_odds)
                if 0 < intensity_change_odds <= 100:
                    prompt = False      
        prompt = True
        while prompt:
            min_intensity = input("Choose the lowest amount of spacing a circle will have: ")
            if min_intensity.isdigit():
                min_intensity = float(min_intensity)
                if min_intensity < circle_space:
                    prompt = False 
        prompt = True
        while prompt:
            max_intensity = input("Choose the highest amount of spacing a circle will have: ")
            if max_intensity.isdigit():
                max_intensity = float(max_intensity)
                if max_intensity > circle_space:
                    prompt = False
        prompt = True
        if Args:
            if Args[0] == "NewProfile":
                return [max_duration_intensity, intensity_change_odds,  min_intensity, max_intensity]
    elif Args[0] == "GenMap":
        max_duration_intensity = Args[1]  
        intensity_change_odds = Args[2]
        min_intensity = Args[3]
        max_intensity = Args[4]
    circle_space = ([min_intensity, circle_space, max_intensity] if not Args else [Args[0][3],circle_space,Args[0][4]])
    count = 0
    for idx, i in enumerate(Circle_list):
        if idx == len(Circle_list) - 1:
            if random.randint(0,100) < intensity_change_odds:
                if random.randint(0,100) > 50:
                    curve_intensity.append(2)
                else:
                    curve_intensity.append(0)
            else:
                 curve_intensity.append(1)
        if random.randint(0,100) < intensity_change_odds:
                if random.randint(0,100) > 50:
                    curve_intensity.append(2)
                    count += 1
                else:
                    curve_intensity.append(0)
                    count += 1
        else:
            if curve_intensity:
                if curve_intensity[-1] == 2 and not count+1 > max_duration_intensity:
                    curve_intensity.append(2)
                    count += 1
                    continue
                elif curve_intensity[-1] == 0 and not count+1 > max_duration_intensity:
                    curve_intensity.append(0)
                    count += 1
                    continue
                elif count+1 > 2:
                    curve_intensity.append(1)
                    count = 0
                    continue
                else:
                    curve_intensity.append(1)   
            else:
                curve_intensity.append(1)
    curve_intensity.reverse()
    if curve_intensity.count(curve_intensity[0]) == len(curve_intensity):
        print("Intensity didn't change")
        return circle_space[1]
    print("\n")
    return [circle_space, curve_intensity]

这样,我得到了 2 个列表,一个具有我指定的间距,第二个是随机生成的强度列表。 从那里我调用另一个函数,将折线、先前指定的间距和生成的强度作为参数:

def acceleration_algorithm(polyline, circle_space, curve_intensity):
    new_circle_spacing = []
    for idx in range(len(polyline)): #repeat 4 times
        spacing = []
        Length = 0
        best_spacing = 0
        for p_idx in range(len(polyline[idx])-1): #repeat 1000 times / p_idx in [0 ; 1000]
            # Create multiple list containing spacing going from circle_space[curve_intensity[idx-1]] to circle_space[curve_intensity[idx]]
            spacing.append(np.linspace(circle_space[curve_intensity[idx]],circle_space[curve_intensity[idx+1]], p_idx).tolist())
            # Sum distance to find length of curve
            Length += abs(math.sqrt((polyline[idx][p_idx+1][0] - polyline[idx][p_idx][0]) ** 2 + (polyline [idx][p_idx+1][1] - polyline[idx][p_idx][1]) ** 2))
        for s in range(len(spacing)): # probably has 1000 list in 1 list
            length_left = Length # Make sure to reset length for each iteration
            for dist in spacing[s]: # substract the specified int in spacing[s]
                length_left -= dist 
            if length_left > 0: 
                best_spacing = s
            else: # Since length < 0, use previous working index (best_spacing), could also jsut do `s-1`
                if spacing[best_spacing] == []:
                    new_circle_spacing.append([circle_space[1]])
                    continue
                new_circle_spacing.append(spacing[best_spacing])
                break
    return new_circle_spacing

有了这个,我获得了一个列表,其中包含要放置的每个圆圈之间的空间, 从那里,我可以再次调用 Place_circles(),并获取新的流:

def Place_circles(polyline, circle_space, cs, DoDrawCircle=True, surface=None):
    Circle_list = []
    curve = []
    next_circle_space = None
    dist = 0
    for c in reversed(range(0, len(polyline))):
        curve = []
        if type(circle_space) == list:
            iter_circle_space = iter(circle_space[c])
            next_circle_space = next(iter_circle_space, circle_space[c][-1])     
        for p in reversed(range(len(polyline[c])-1)):
            dist += math.sqrt((polyline[c][p+1][0] - polyline[c][p][0]) ** 2 + (polyline [c][p+1][1] - polyline[c][p][1]) ** 2)
            if dist > (circle_space if type(circle_space) == int else next_circle_space):
                dist = 0
                curve.append(circles.circles(round(polyline[c][p][0]), round(polyline[c][p][1]), cs, DoDrawCircle, surface))
                if type(circle_space) == list:
                    next_circle_space = next(iter_circle_space, circle_space[c][-1])
        Circle_list.append(curve)
    return Circle_list

结果是圆圈之间的空间不同(因此加速或减速)的流,唯一需要解决的问题是 pygame 在我调用 Place_circles() 后没有用新的圆圈集更新屏幕,但这是一个问题我要么尝试修复自己,要么在另一个帖子中提问

此功能的最终代码可以在我的仓库中找到:https://github.com/Mrcubix/Osu-StreamGenerator/tree/Acceleration_v02

【讨论】:

以上是关于如何正确添加对象之间逐渐增加/减少的空间?的主要内容,如果未能解决你的问题,请参考以下文章

解决渠道产品增加

增加 UIPageControl 指示点之间的间距

如何减少仓库,增加存货点

如何增加ggplot2中分组条之间的空间?

压力测试时从高负载开始降低,或者逐渐增加负载哪个更好

s-s-rS 嵌套 Tablix 动态增加/减少行高