在a game中,我们使用名为“colour picking”的技术来选择单位。
这意味着每个可见单元都有一种独特的颜色。
以下是为颜色选择绘制的场景示例:
由于某些用户可能具有16位显示器,因此这些颜色可以在0..64K范围内。
但是,如果我们给单位增加颜色,例如unit0为0,unitN为N,那么人类调试的颜色非常难。单位几乎无法区分。
我们希望为这些单位提供独特而独特的色彩。
我们目前正在使用二叉树(C ++ map
)以固定步骤递增,以存储用过的颜色以检查碰撞。这是低端硬件上的性能问题。即使这是一个哈希表并且避免使用string
,游戏帧中的临时内存分配也是不受欢迎的。因此,我不想优化现有的代码,而是希望发现是否有办法完全避免维护历史。
有没有办法以大步长或随机迭代数字0..64K,以便使用大多数64K可能值,并避免使用已分配颜色的历史来避免碰撞?
(屏幕上不可能有超过64K的可见单元,我们无需处理这种情况!)
答案 0 :(得分:8)
我的尝试:
选择一个“中等范围”原始根( 43062 43067是一个很好的候选者)。
class Sequence
{
public:
uint32_t get() const {return state;}
void advance() { state = (state * k)%p;}
void reset() { state = k; }
private:
uint32_t state = 43067;
const uint32_t k = 43067;
const uint32_t p = 64007;
};
以伪随机方式将范围[1,64007]中的所有数字精确地循环一次。
答案 1 :(得分:1)
您可以简单地将step_size作为总可用颜色除以总单位,然后使用(unit_index * step_size)作为每个单位的颜色吗?
答案 2 :(得分:1)
我真的没有看到问题。正如我在评论中所写,你只需要128K来存储[0..64K]的排列,并且你不需要在主循环中进行任何分配。这是C ++ 11中的有状态颜色存储(在旧版C ++中,使用vector
或new[]
):
class ColorPicker {
std::array<uint16_t, 65536> colors;
uint16_t idx;
public:
ColorPicker() : idx(0)
{
std::iota(colors.begin(), colors.end(), 0);
std::random_shuffle(colors.begin(), colors.end());
}
uint16_t next_color()
{
return colors[idx++];
}
};
您只需要其中一种结构。现在,无论何时创建新单元,请在next_color
上调用ColorPicker
并将其作为属性存储在单元上。
此解决方案将循环显示颜色。如果不需要,请在每次索引回绕到零时执行random_shuffle
。
答案 3 :(得分:1)
在我看来,重要的是彼此接近的单位之间的对比度足够高,即我会试图想出一些方法来考虑单位的接近程度。
例如,您可以考虑单位的X / Y坐标,使得彼此接近的坐标获得具有高对比度的颜色,低对比度仅用于距离足够远的单位。
第一个镜头可能是拥有256种颜色的简单数组a
,因此a[n]
和a[n+1]
之间存在较大的对比度。然后,您可以使用模数为256的X和/或Y坐标作为数组的索引来选择单位的颜色。这样,您将获得的颜色重用于至少256像素(或您可能使用的任何度量标准)的单位,但不同颜色的单位彼此非常接近。
答案 4 :(得分:0)
首先,使用二进制来存储颜色状态(1使用,0使用)。 2 ^ 16 = 65536(状态)。如果我们使用1位作为一种颜色,则需要65536/8 = 8192字节。
下一个问题是如何管理这些字节。我建议树结构:在这8192个字节上,需要另一个(8192/8 =)1024个字节,这些高位字节中的每个位代表8192个字节中的一个字节,如果其中一个低位字节是 ALL 1,其高位为1。
此规则可以扩展上部和上部:8192 - &gt; 1024 - &gt; 128 ...最后,到1个字节(虽然没有完全使用)。
要使用此结构,您可以从根字节多次生成0..7中的随机数,如果其位为1,请再次尝试;如果它的0,低到低字节,重复这些动作,直到达到最低字节。
此外,您可以在一个数组中构建此树:就像堆中的堆一样。 (有一些空单位)。
APPEND:int16需要一种颜色,一旦下到低位字节,你得到一个三位二进制数,从左到右追加颜色编号:int16。 (根字节只代表2个状态,只生成1位二进制数,其形式为111111 ??。