Maxime FRAPPAT

Hum …no thanks ! – Lordinaire

Category: WinRT (Page 1 of 5)

[Unity] Custom build for WP8/W8

If your game target the Windows Phone 8 or Windows Store platform, you probably want to use some specific feature like the share, live tiles, …

This can be done by using some tricks that I already explain in a previous thread (http://blog.lordinaire.fr/2014/09/unity-interact-between-unity-and-windows-phone-8-windows-store-apps/) but I might be pretty cool to build automatically custom files like splashscreen, MainPage or tiles.

Create a specific menu item

The first step is to create a menu item to easily access to our build.

using System.Linq;
using System.Security.Policy;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;

public class AutoBuilderMenu : MonoBehaviour
{
	[MenuItem("AutoBuilder/WP8")]
	private static void PerformBuild()
	{
		// TODO : Build and replace files
	}
}

For more information about MenuItem see http://blog.lordinaire.fr/2014/10/unity-create-custom-menu-items/

Simple build

using System.Linq;
using System.Security.Policy;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;

public class AutoBuilderMenu : MonoBehaviour
{
	[MenuItem("AutoBuilder/WP8")]
	private static void PerformBuild()
	{
		// Save current editor build target
		var currentTarget = EditorUserBuildSettings.activeBuildTarget;
		EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.WP8Player);

		var buildPath = GetBuildPath(target);
		var path = Path.GetDirectoryName(buildPath);

		var folderExists = Directory.Exists(path);
		if (!folderExists)
			Directory.CreateDirectory(path);

		// Create solution folder and project files
		BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);

		// Set saved build target
		EditorUserBuildSettings.SwitchActiveBuildTarget(currentTarget);
	}

	private static string GetProjectName()
	{
		string[] s = Application.dataPath.Split('/');
		return s[s.Length - 2];
	}

	private static string[] GetScenePaths()
	{
		return EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray();
	}

	private static string GetBuildPath(BuildTarget target)
	{
		var extension = String.Empty;

		return String.Format("../Builds/{0}/{1}/{2}/{3}",
			GetProjectName(),
			PlayerSettings.bundleVersion,
			target.ToString(),
			PlayerSettings.bundleIdentifier);
	}
}

The project will be create in the folder ../Builds/{ProjectName}/{BundleVersion}/{TargetPlatform}/{BundleIdentifier} so we have a build for each version of our game in a specific folder.

Custom build

using System.Linq;
using System.Security.Policy;
using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System;

public class AutoBuilderMenu : MonoBehaviour
{
	[MenuItem("AutoBuilder/WP8")]
	private static void PerformBuild()
	{
		// Save current editor build target
		var currentTarget = EditorUserBuildSettings.activeBuildTarget;
		EditorUserBuildSettings.SwitchActiveBuildTarget(BuildTarget.WP8Player);

		var buildPath = GetBuildPath(target);
		var path = Path.GetDirectoryName(buildPath);

		var folderExists = Directory.Exists(path);
		if (!folderExists)
			Directory.CreateDirectory(path);

		// First build to create solution folder and project files
		BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);

		// Replace custom files
		UpdateWP8Settings(buildPath);

		// Rebuild with replacing files
		BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);

		// Set saved editor build target
		EditorUserBuildSettings.SwitchActiveBuildTarget(currentTarget);
	}

	private static void UpdateWP8Settings(string buildPath)
	{
		// SplashScreenImage
		var replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/SplashScreenImage.jpg");
		var current = string.Format("{0}/{1}/SplashScreenImage.jpg", buildPath, PlayerSettings.bundleIdentifier);
		if (File.Exists(replace))
			File.Copy(replace, current, true);

		// MainPage.xaml.cs
		replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/MainPage.xaml.cs");
		current = string.Format("{0}/{1}/MainPage.xaml.cs", buildPath, PlayerSettings.bundleIdentifier);
		if (File.Exists(replace))
			File.Copy(replace, current, true);		

		// ApplicationIcon
		replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/ApplicationIcon.png");
		current = string.Format("{0}/{1}/Assets/ApplicationIcon.png", buildPath, PlayerSettings.bundleIdentifier);
		if (File.Exists(replace))
			File.Copy(replace, current, true);

		// WMAppManifest
		replace = string.Concat(Application.dataPath, "/../BuildSettings/WP8/WMAppManifest.xml");
		current = string.Format("{0}/{1}/Properties/WMAppManifest.xml", buildPath, PlayerSettings.bundleIdentifier);
		if (File.Exists(replace))
			File.Copy(replace, current, true);
	}

	private static string GetProjectName()
	{
		string[] s = Application.dataPath.Split('/');
		return s[s.Length - 2];
	}

	private static string[] GetScenePaths()
	{
		return EditorBuildSettings.scenes.Where(s => s.enabled).Select(s => s.path).ToArray();
	}

	private static string GetBuildPath(BuildTarget target)
	{
		return String.Format("../Builds/{0}/{1}/{2}/{3}",
			GetProjectName(),
			PlayerSettings.bundleVersion,
			target.ToString(),
			PlayerSettings.bundleIdentifier);
	}
}

The trick is to build twice the game. First we build to create all files then we replace our custom files and we rebuild to use these new files.

A more elegant way

private static void PerformBuild(BuildTarget target, bool isBeta = false)
{
	var currentTarget = EditorUserBuildSettings.activeBuildTarget;
	EditorUserBuildSettings.SwitchActiveBuildTarget(target);

	var buildPath = GetBuildPath(target);
	var path = Path.GetDirectoryName(buildPath);

	var folderExists = Directory.Exists(path);
	if (!folderExists)
	{
		Directory.CreateDirectory(path);
	}

	BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);

	if (target == BuildTarget.WP8Player)
	{
		UpdateWP8Settings(buildPath, string.Concat(Application.dataPath, "/../BuildSettings/WP8/"), string.Concat(buildPath, "/"));
		if (isBeta)
		{
			UpdateWP8Settings(buildPath, string.Concat(Application.dataPath, "/../BuildSettings/WP8_Beta/"), string.Concat(buildPath, "/"));

		}
		BuildPipeline.BuildPlayer(GetScenePaths(), buildPath, target, BuildOptions.None);
	}

	EditorUserBuildSettings.SwitchActiveBuildTarget(currentTarget);
}

private static void UpdateWP8Settings(string buildPath, string sourceRootPath, string destinationRootPath = "")
{
	var files = Directory.GetFiles(sourceRootPath);
	foreach (var file in files)
	{
		var replace = file;
		var fileName = replace.Split('/').LastOrDefault().Split('\\').LastOrDefault();
		var current = string.Concat(destinationRootPath, "/" + fileName);
		File.Copy(replace, current, true);
	}

	var directories = Directory.GetDirectories(sourceRootPath);
	foreach (var directory in directories)
	{
		var folderName = directory.Split('/').LastOrDefault().Split('\\').LastOrDefault();
		UpdateWP8Settings(buildPath, directory, destinationRootPath + "/" + folderName);
	}
}

You just need to add all your files in the folder BuildSettings/WP8 and/or BuildSettings/WP8_Beta with the same hierarchy as the project and it’s done ! Thanks Jonathan for the tips ;)

unity_custom_build

It’s the same way with Windows Store apps :)

[Unity] Interact between Unity and Windows Phone 8 / Windows Store apps

In this thread, we will see how to interact between Unity and our WP8 or Windows Store apps.

Introduction

When you work with those platforms with Unity, it will create a Visual Studio solution with all the basics of a new solution for this kind of project (App.xaml, MainPage.xaml, …) adapted to be able  to start your game.

In this new solution, we can have access to all the framework of this platform, it’s platform specific.

Create a gateway

We want to be able to launch a platform specific action, like sharing a picture, in our Unity source code that can be handle by our WP8/Windows Store project.

using System;

/// <summary>
/// Windows specific and interop between Unity and Windows Store or Windows Phone 8
/// </summary>
public static class WindowsGateway
{
	public static Action<string, string, string> OnActionWithParametersRaised = delegate { };

	public static Action OnActionRaised = delegate { };

	static WindowsGateway()
	{
		OnActionWithParametersRaised = delegate { };
		OnActionRaised = delegate { };
	}
}

We use a static class with empty delegates. Those delegates will be handle in our platform specific project, in the MainPage.xaml.cs for example.

namespace MyUnityApp
{
	public partial class MainPage : PhoneApplicationPage
	{
		// [...]

		private void Unity_Loaded()
		{
			// [...]

			WindowsGateway.OnActionWithParametersRaised += OnActionWithParameters;
			WindowsGateway.OnActionRaised += OnAction;
		}

		private void OnAction()
		{

		}

		private void OnActionWithParameters(string url, string title, string message)
		{

		}

		// [...]

	}
}

That’s all :)

Page 1 of 5

Powered by WordPress & Theme by Anders Norén

%d bloggers like this: