PlayKit.ai

Image Generation

Generate AI images using PlayKit_AIImageClient and integrate them into Unity games

Image Generation

PlayKit_AIImageClient allows you to generate images from natural language descriptions, ideal for dynamic content generation, prototyping, or temporary art assets in games.

For example, you can generate different character portraits based on player choices, or create unique textures for procedurally generated dungeons.

Before You Begin

  • Make sure you've completed SDK initialization
  • Understand that image generation may take longer (typically 5-30 seconds)
  • Generated images are in Base64-encoded PNG format

Create an Image Client

Use the factory method to create an image generation client:

// Use default model
var imageClient = PlayKitSDK.Factory.CreateImageClient();

// Specify model
var imageClient = PlayKitSDK.Factory.CreateImageClient("dall-e-3");

Generate a Single Image

Use the GenerateImageAsync() method to generate a single image:

using Cysharp.Threading.Tasks;
using PlayKit_SDK;
using PlayKit_SDK.Public;
using UnityEngine;
using UnityEngine.UI;

public class SimpleImageGeneration : MonoBehaviour
{
    [SerializeField] private Image displayImage;
    [SerializeField] private Button generateButton;

    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
        generateButton.onClick.AddListener(() => GenerateImage().Forget());
    }

    async UniTaskVoid GenerateImage()
    {
        generateButton.interactable = false;

        // Generate image
        PlayKit_GeneratedImage result = await imageClient.GenerateImageAsync(
            prompt: "a futuristic sci-fi city at sunset, digital art",
            size: "1024x1024",
            seed: null, // Random seed
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            // Convert to Sprite and display
            Sprite sprite = result.ToSprite();
            displayImage.sprite = sprite;

            Debug.Log($"Original prompt: {result.OriginalPrompt}");
            Debug.Log($"Revised prompt: {result.RevisedPrompt}");
        }
        else
        {
            Debug.LogError("Image generation failed");
        }

        generateButton.interactable = true;
    }
}

Image Sizes

The SDK supports multiple image sizes:

Standard Sizes

  • "256x256" - Small, fast generation
  • "512x512" - Medium size
  • "1024x1024" - High quality square images

Widescreen Sizes

  • "1792x1024" - Widescreen landscape
  • "1024x1792" - Widescreen portrait
// Generate widescreen image
var wideImage = await imageClient.GenerateImageAsync(
    prompt: "a vast landscape with mountains",
    size: "1792x1024",
    seed: null,
    cancellationToken: this.GetCancellationTokenOnDestroy()
);

Different sizes may have different generation times and credit costs. Larger images typically take longer and cost more credits.

Generate Multiple Images

Use the GenerateImagesAsync() method to generate multiple images at once:

using System.Collections.Generic;

public class BatchImageGeneration : MonoBehaviour
{
    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask GenerateMultipleImages()
    {
        // Generate 4 images
        List<PlayKit_GeneratedImage> images = await imageClient.GenerateImagesAsync(
            prompt: "fantasy character portrait, digital art",
            count: 4,
            size: "512x512",
            aspectRatio: null,
            seed: null,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (images != null && images.Count > 0)
        {
            Debug.Log($"Successfully generated {images.Count} images");

            for (int i = 0; i < images.Count; i++)
            {
                Sprite sprite = images[i].ToSprite();
                // Display or save image
                DisplayImage(sprite, i);
            }
        }
    }

    void DisplayImage(Sprite sprite, int index)
    {
        // Implement image display logic
    }
}

Using Seed Values

Seed values can generate reproducible images. Using the same prompt and seed produces similar images:

public class SeededImageGeneration : MonoBehaviour
{
    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask GenerateWithSeed()
    {
        int seed = 12345;

        // First generation
        var image1 = await imageClient.GenerateImageAsync(
            prompt: "a red dragon",
            size: "1024x1024",
            seed: seed,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        // Generate again with same seed
        var image2 = await imageClient.GenerateImageAsync(
            prompt: "a red dragon",
            size: "1024x1024",
            seed: seed,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        // image1 and image2 should be very similar
    }

    public async UniTask GenerateRandomImages()
    {
        // Passing null seed generates random images
        var randomImage = await imageClient.GenerateImageAsync(
            prompt: "a blue crystal",
            size: "1024x1024",
            seed: null, // Random
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );
    }
}

Image Conversion

The SDK provides multiple ways to convert and use generated images.

Convert to Texture2D

PlayKit_GeneratedImage generatedImage = await imageClient.GenerateImageAsync(/*...*/);

if (generatedImage != null)
{
    // Convert to Texture2D
    Texture2D texture = generatedImage.ToTexture2D();

    // Use the texture
    GetComponent<Renderer>().material.mainTexture = texture;
}

Convert to Sprite

PlayKit_GeneratedImage generatedImage = await imageClient.GenerateImageAsync(/*...*/);

if (generatedImage != null)
{
    // Convert to Sprite
    Sprite sprite = generatedImage.ToSprite();

    // Display in UI
    GetComponent<Image>().sprite = sprite;
}

Using Static Conversion Methods

If you already have a Base64 string, use the static methods:

// Convert Base64 to Texture2D
Texture2D texture = PlayKit_AIImageClient.Base64ToTexture2D(base64String);

// Convert Texture2D to Sprite
Sprite sprite = PlayKit_AIImageClient.Texture2DToSprite(texture);

Save Generated Images

Save generated images to disk:

using System.IO;

public class ImageSaver : MonoBehaviour
{
    public async UniTask GenerateAndSaveImage(string prompt, string filename)
    {
        var imageClient = PlayKitSDK.Factory.CreateImageClient();

        var result = await imageClient.GenerateImageAsync(
            prompt: prompt,
            size: "1024x1024",
            seed: null,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            Texture2D texture = result.ToTexture2D();

            // Encode texture to PNG
            byte[] bytes = texture.EncodeToPNG();

            // Save to file
            string path = Path.Combine(Application.persistentDataPath, filename);
            File.WriteAllBytes(path, bytes);

            Debug.Log($"Image saved to: {path}");
        }
    }
}

Prompt Optimization

AI models may optimize your prompts for better results. You can view the original and revised prompts:

var result = await imageClient.GenerateImageAsync(
    prompt: "dragon",
    size: "1024x1024",
    seed: null,
    cancellationToken: this.GetCancellationTokenOnDestroy()
);

if (result != null)
{
    Debug.Log($"Your prompt: {result.OriginalPrompt}");
    Debug.Log($"AI optimized: {result.RevisedPrompt}");
    // Possible output:
    // Your prompt: dragon
    // AI optimized: A majestic red dragon with scales gleaming in the sunlight,
    //               perched on a mountain peak, digital art, highly detailed
}

Practical Examples

Character Portrait Generator

public class CharacterPortraitGenerator : MonoBehaviour
{
    [SerializeField] private Image portraitImage;
    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask GenerateCharacterPortrait(
        string race,
        string characterClass,
        string gender
    )
    {
        string prompt = $"fantasy {race} {characterClass} character portrait, " +
                       $"{gender}, detailed face, professional digital art, " +
                       $"heroic pose, dramatic lighting";

        Debug.Log($"Generating portrait: {prompt}");

        var result = await imageClient.GenerateImageAsync(
            prompt: prompt,
            size: "512x512",
            seed: null,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            portraitImage.sprite = result.ToSprite();
            Debug.Log("Portrait generated successfully");
        }
    }
}

// Usage examples
// await GenerateCharacterPortrait("elf", "mage", "female");
// await GenerateCharacterPortrait("dwarf", "warrior", "male");

Item Icon Generator

public class ItemIconGenerator : MonoBehaviour
{
    private PlayKit_AIImageClient imageClient;
    private Dictionary<string, Sprite> iconCache = new Dictionary<string, Sprite>();

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask<Sprite> GetOrGenerateIcon(string itemName, string itemType)
    {
        // Check cache
        string cacheKey = $"{itemName}_{itemType}";
        if (iconCache.ContainsKey(cacheKey))
        {
            return iconCache[cacheKey];
        }

        // Generate new icon
        string prompt = $"{itemName}, {itemType}, game item icon, " +
                       $"clean background, detailed, high quality, centered";

        var result = await imageClient.GenerateImageAsync(
            prompt: prompt,
            size: "256x256",
            seed: null,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            Sprite icon = result.ToSprite();
            iconCache[cacheKey] = icon;
            return icon;
        }

        return null;
    }
}

Scene Background Generator

public class SceneBackgroundGenerator : MonoBehaviour
{
    [SerializeField] private Image backgroundImage;
    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask GenerateSceneBackground(string sceneName, string mood)
    {
        string prompt = $"{sceneName} scene, {mood} atmosphere, " +
                       $"wide angle, cinematic, detailed environment art, " +
                       $"no characters";

        var result = await imageClient.GenerateImageAsync(
            prompt: prompt,
            size: "1792x1024", // Widescreen
            seed: null,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            backgroundImage.sprite = result.ToSprite();
        }
    }
}

// Usage examples
// await GenerateSceneBackground("ancient temple ruins", "mysterious and foggy");
// await GenerateSceneBackground("bustling medieval market", "bright and cheerful");

Performance Optimization

Show Loading State

Image generation takes time - show loading state to users:

public class ImageGenerationWithLoading : MonoBehaviour
{
    [SerializeField] private Image resultImage;
    [SerializeField] private GameObject loadingPanel;
    [SerializeField] private Text loadingText;

    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask GenerateWithLoading(string prompt)
    {
        // Show loading UI
        loadingPanel.SetActive(true);
        loadingText.text = "Generating image...";

        try
        {
            var result = await imageClient.GenerateImageAsync(
                prompt: prompt,
                size: "1024x1024",
                seed: null,
                cancellationToken: this.GetCancellationTokenOnDestroy()
            );

            if (result != null)
            {
                resultImage.sprite = result.ToSprite();
                loadingText.text = "Generation complete!";
                await UniTask.Delay(1000);
            }
            else
            {
                loadingText.text = "Generation failed";
                await UniTask.Delay(2000);
            }
        }
        catch (System.Exception ex)
        {
            loadingText.text = $"Error: {ex.Message}";
            await UniTask.Delay(2000);
        }
        finally
        {
            // Hide loading UI
            loadingPanel.SetActive(false);
        }
    }
}

Cache Generated Images

Avoid regenerating the same images:

public class ImageCache : MonoBehaviour
{
    private Dictionary<string, Sprite> cache = new Dictionary<string, Sprite>();
    private PlayKit_AIImageClient imageClient;

    void Start()
    {
        imageClient = PlayKitSDK.Factory.CreateImageClient();
    }

    public async UniTask<Sprite> GetOrGenerateImage(string prompt, int? seed = null)
    {
        // Create cache key
        string cacheKey = $"{prompt}_{seed?.ToString() ?? "random"}";

        // Check cache
        if (cache.ContainsKey(cacheKey))
        {
            Debug.Log("Returning image from cache");
            return cache[cacheKey];
        }

        // Generate new image
        Debug.Log("Generating new image");
        var result = await imageClient.GenerateImageAsync(
            prompt: prompt,
            size: "1024x1024",
            seed: seed,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            Sprite sprite = result.ToSprite();
            cache[cacheKey] = sprite;
            return sprite;
        }

        return null;
    }

    public void ClearCache()
    {
        cache.Clear();
        Debug.Log("Image cache cleared");
    }
}

Error Handling

public async UniTask GenerateImageSafely(string prompt)
{
    var imageClient = PlayKitSDK.Factory.CreateImageClient();

    try
    {
        var result = await imageClient.GenerateImageAsync(
            prompt: prompt,
            size: "1024x1024",
            seed: null,
            cancellationToken: this.GetCancellationTokenOnDestroy()
        );

        if (result != null)
        {
            Sprite sprite = result.ToSprite();
            // Use image
        }
        else
        {
            Debug.LogError("Image generation returned null");
            ShowErrorMessage("Image generation failed, please try again");
        }
    }
    catch (PlayKitImageSizeValidationException ex)
    {
        Debug.LogError($"Invalid image size: {ex.Message}");
        ShowErrorMessage("Please use a valid image size");
    }
    catch (System.Exception ex)
    {
        Debug.LogError($"Error generating image: {ex.Message}");
        ShowErrorMessage("Generation failed, please check network connection");
    }
}

void ShowErrorMessage(string message)
{
    // Show error message to user
}

Prompt Best Practices

Effective Prompt Structure

// Good prompt: specific, descriptive
string goodPrompt = "a wise old wizard with a long white beard, " +
                   "wearing blue robes with star patterns, " +
                   "holding a glowing staff, " +
                   "fantasy art, detailed, dramatic lighting";

// Okay prompt: too simple
string okayPrompt = "wizard";

// Bad prompt: vague, contradictory
string badPrompt = "wizard that is also a robot and a tree";

Prompt Templates for Different Types

public class PromptTemplates
{
    public static string CharacterPortrait(string description)
    {
        return $"{description}, character portrait, " +
               $"detailed face, professional digital art, " +
               $"front view, neutral background";
    }

    public static string ItemIcon(string itemName, string itemType)
    {
        return $"{itemName}, {itemType}, game item icon, " +
               $"clean background, centered, detailed, high quality";
    }

    public static string Environment(string location, string mood)
    {
        return $"{location}, {mood} atmosphere, " +
               $"detailed environment art, wide angle, cinematic";
    }

    public static string Texture(string material, string pattern)
    {
        return $"{material} texture, {pattern}, " +
               $"seamless, tileable, high resolution, pbr";
    }
}

Best Practices

  1. Use specific prompts: Describe in detail what you want
  2. Add art style: Specify style (e.g., "digital art", "oil painting")
  3. Show loading state: Image generation takes time, show progress to users
  4. Cache images: Avoid regenerating the same images
  5. Choose appropriate sizes: Select image size based on use case - smaller images generate faster
  6. Use seed values: Use fixed seeds when reproducible results are needed
  7. Error handling: Always handle possible error cases
  8. Optimize memory: Release unused Texture2D objects promptly

Next Steps