/// <summary> Render invader <paramref name="bits"/> into a <see cref="PalettedSprite"/> using the given palette <paramref name="index"/></summary> static void RenderInvaderSprite(PalettedSprite spr, long bits, int index) { int w = spr.Width; int h = spr.Height; bool oddW = w % 2 == 1; int wbits = (oddW ? 1 : 0) + w / 2; for (int yy = 0; yy < h; yy++) { for (int xx = 0; xx < wbits; xx++) { int i = yy * wbits + xx; if (i >= 64) { Console.WriteLine("Early Return!"); return; } long mask = 1L << i; bool bit = (bits & mask) != 0; if (bit) { spr.SetIndex(xx, yy, index); //Mirroring spr.SetIndex(w - 1 - xx, yy, index); } } } }
void UpdatePalette() { // We don't need to change the sprite, just update the palette for it. palette = paletteGens[paletteId](nColors); // Create a new cursor and discard the old one cursor = new PalettedSprite(cursor, palette); }
void Rebuild() { palette = paletteGens[paletteId](nColors); // If we change number of colors in palette, we need to rebuild the sprite as well... // 0 is fixed to be transparent, so with 32 colors we can only use 31 of them. // a new PalettedSprite is initialized to be filled with transparent pixels. cursor = new PalettedSprite(size, size, palette); // Draw two lines into the paletted sprite for (int i = 0; i < size; i++) { // Create two color indexes into the palette // Don't set any zeros into the sprite (zeros are transparent!) int ci1 = 1 + (i % (nColors - 1)); int ci2 = 1 + ((i + nColors / 2) % (nColors - 1)); cursor.SetIndex(size / 2, i, ci1); cursor.SetIndex(i, size / 2, ci2); } // Remove some of the center colors by setting them to be transparent. cursor.SetIndex(size / 2, size / 2, 0); cursor.SetIndex(size / 2 - 1, size / 2, 0); cursor.SetIndex(size / 2 - 2, size / 2, 0); cursor.SetIndex(size / 2 + 1, size / 2, 0); cursor.SetIndex(size / 2 + 2, size / 2, 0); cursor.SetIndex(size / 2, size / 2 - 1, 0); cursor.SetIndex(size / 2, size / 2 - 2, 0); cursor.SetIndex(size / 2, size / 2 + 1, 0); cursor.SetIndex(size / 2, size / 2 + 2, 0); }
static ISprite RenderPlayer(int seed) { Randoms.Seed = seed; Pixel[] palette = new Pixel[4]; float hue, sat, val; hue = Randoms.value; sat = .2f + .3f * Randoms.value; val = .2f + .3f * Randoms.value; Vector4 baseColor = new Vector4(hue, sat, val, 1.0f); palette[1] = Pixel.HSVA(baseColor); hue = -.1f + .2f * Randoms.value; sat = .3f + .2f * Randoms.value; val = .3f + .2f * Randoms.value; Vector4 cockpitColor = baseColor + new Vector4(hue, sat, val, 0f); palette[2] = Pixel.HSVA(cockpitColor); hue = -.05f + .1f * Randoms.value; sat = -.1f - .1f * Randoms.value; val = -.1f - .1f * Randoms.value; Vector4 outlineColor = baseColor + new Vector4(hue, sat, val, 0f); palette[3] = Pixel.HSVA(outlineColor); int spriteSize = 15; PalettedSprite spr = new PalettedSprite(spriteSize, spriteSize, palette); Vector2Int b = new Vector2Int(7, 0); // Begin with outline spr.SetIndex(b.x, b.y, 3); // Draw Triangle int cockpitSize = Randoms.RandomInt(4, 7); int invCockpitSize = (1 + spriteSize) / 2 - cockpitSize; for (int y = 1; y < spriteSize; y++) { int maxOff = (y) / 2; for (int i = 0; i <= maxOff; i++) { byte v = 1; if ((i < spriteSize - 2) && (i - 1 < maxOff - invCockpitSize)) { v = 2; } if (i == maxOff || y == (spriteSize - 1)) { v = 3; } spr.SetIndex(b.x + i, b.y + y, v); spr.SetIndex(b.x - i, b.y + y, v); } } return(spr); }
/// <summary> Render a 'shot' sprite using rotational symmetry. </summary> /// <param name="seed"></param> /// <returns></returns> public static ISprite RenderShot(int seed) { Randoms.Seed = seed; Pixel[] palette = new Pixel[4]; int size = Randoms.Range(7, 20); long mask = -1; long bits = PickBits(mask, size + 4); PalettedSprite spr = new PalettedSprite(15, 15, palette); for (int i = 0; i < 64; i++) { if ((bits & (1 << i)) == 0) { continue; } Vector2Int mid = new Vector2Int(size / 2, size / 2); if (size % 2 == 1) { mid += Vector2Int.one; } Vector2Int delta = new Vector2Int(i % size, i / size); for (int k = 0; k < 8; k++) { Vector2Int start = mid; Vector2Int step = delta; int quad = k / 2; if (size % 2 == 0) { if (quad == 0) { start.x += 1; } else if (quad == 1) { } else if (quad == 2) { start.y += 1; } else if (quad == 3) { start += Vector2Int.one; } } if (k == 0) { step.y *= -1; } } } return(spr); }
/// <summary> Create an invader from a <paramref name="seed"/>, rendering a set of sprites for all of its 'poses' </summary> static ISprite[] RenderInvaderPoses(int seed, InvaderRenderSettings sets = null) { if (sets == null) { sets = InvaderRenderSettings.DEFAULT; } Randoms.Seed = seed; int numFrames = sets.nextFrames; ISprite[] poses = new ISprite[numFrames]; // Sprite spr = new Sprite(); int numLayers = sets.nextLayers; long[] baseFrame = new long[numLayers]; Pixel[] colors = new Pixel[numLayers + 1]; int width = sets.nextSize; int height = sets.nextSize; int fill = (int)Mathf.Sqrt(width * height); int maxBits = height * width - (height * (width / 2)); long bitMask = (1L << (1 + maxBits)) - 1L; Console.WriteLine($"Invader {width:D2}x{height:D2} has {maxBits:D2} bits and mask 0x{bitMask:X16}"); Vector4 baseColor = Pixel.Random().ToHSVA(); baseColor.w = 1.0f; baseFrame[0] = PickBits(bitMask, fill); colors[1] = Pixel.HSVA(baseColor); for (int i = 1; i < numLayers; i++) { int numDeco = sets.nextDeco; baseFrame[i] = PickBits(bitMask, numDeco); Vector4 colorMod = sets.nextHsvChange; colors[i + 1] = Pixel.HSVA(baseColor + colorMod); } for (int k = 0; k < numFrames; k++) { PalettedSprite spr = new PalettedSprite(width, height, colors); for (int i = 0; i < numLayers; i++) { long bits = baseFrame[i]; if (k != 0) { int numFlips = sets.nextAnim; long mask = PickBits(bitMask, numFlips); bits ^= mask; } RenderInvaderSprite(spr, bits, i + 1); } poses[k] = spr; } return(poses); }