Universal Windows Platform – Emoji Game

Emoji Game demonstrates how to create a game where you can pick from selection of Emoji to identify which one is the correct one out of a set of three Emoji, get one wrong though and you lose!

Step 1

If not already, follow Setup and Start on how to Install and get Started with Visual Studio 2017 or in Windows 10 choose Start, and then from the Start Menu find and select Visual Studio 2017.

vs2017

Step 2

Once Visual Studio Community 2017 has started, from the Menu choose File, then New then Project…

vs2017-file-new-project

Step 3

From New Project choose Visual C# from Installed, Templates then choose Blank App (Universal Windows) and then type in the Name as EmojiGame and select a Location and then select Ok to create the Project
vs2017-new-project-emoji-game

Step 4

Then in New Universal Windows Project you need to select the Target Version this should be at least the Windows 10, version 1803 (10.0; Build 17134) which is the April 2018 Update and the Minimum Version to be the same.

vs2017-target-platform

The Target Version will control what features your application can use in Windows 10 so by picking the most recent version you’ll be able to take advantage of those features. To make sure you always have the most recent version, in Visual Studio 2017 select Tools Extensions and Updates… then and then see if there are any Updates

Step 5

Once done select from the Menu, Project, then Add New Item…

vs2017-project-add-new-item

Step 6

From the Add New Item window select Visual C#, then Code from Installed then select Code File from the list, then type in the Name as Library.cs before selecting Add to add the file to the Project

vs2017-add-new-item-emoji-game

Step 7

Once in the Code View for Library.cs the following should be entered:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Windows.Foundation;
using Windows.UI;
using Windows.UI.Popups;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Media;

namespace EmojiGame
{
    public enum EmojiType
    {
        [Description("\U0001F600")]
        Grinning,
        [Description("\U0001F601")]
        Beaming,
        [Description("\U0001F602")]
        TearsOfJoy,
        [Description("\U0001F606")]
        Squinting,
        [Description("\U0001F609")]
        Winking,
        [Description("\U0001F60B")]
        Savouring,
        [Description("\U0000263A")]
        Smiling,
        [Description("\U0001F917")]
        Hugging,
        [Description("\U0001F914")]
        Thinking,
        [Description("\U0001F928")]
        RaisedEyebrow,
        [Description("\U0001F610")]
        Neutral,
        [Description("\U0001F611")]
        Expressionless,
        [Description("\U0001F644")]
        RollingEyes,
        [Description("\U0001F623")]
        Persevering,
        [Description("\U0001F62E")]
        OpenMouth,
        [Description("\U0001F62F")]
        Hushed,
        [Description("\U0001F62A")]
        Sleepy,
        [Description("\U0001F62B")]
        Tired,
        [Description("\U0001F634")]
        Sleeping,
        [Description("\U0001F60C")]
        Relieved,
        [Description("\U0001F612")]
        Unamused,
        [Description("\U0001F614")]
        Pensive,
        [Description("\U0001F615")]
        Confused,
        [Description("\U0001F632")]
        Astonished,
        [Description("\U00002639")]
        Frowning,
        [Description("\U0001F616")]
        Confounded,
        [Description("\U0001F61E")]
        Disappointed,
        [Description("\U0001F61F")]
        Worried,
        [Description("\U0001F624")]
        Triumph,
        [Description("\U0001F627")]
        Anguished,
        [Description("\U0001F628")]
        Fearful,
        [Description("\U0001F633")]
        Flushed,
        [Description("\U0001F92A")]
        Zany,
        [Description("\U0001F635")]
        Dizzy,
        [Description("\U0001F620")]
        Angry,
        [Description("\U0001F913")]
        Nerdy
    }

    public enum EmojiState
    {
        None, Correct, Incorrect
    }

    public class BindableBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected bool SetProperty<T>(ref T field, T value,
        [CallerMemberName] string propertyName = null)
        {
            if (EqualityComparer<T>.Default.Equals(field, value)) return false;
            field = value;
            OnPropertyChanged(propertyName);
            return true;
        }

        public void OnPropertyChanged(string name)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }

    public class EmojiItem : BindableBase
    {
        private EmojiType _type;
        private EmojiState _state;
        private bool _correct;

        public EmojiType Type
        {
            get { return _type; }
            set { SetProperty(ref _type, value); }
        }

        public EmojiState State
        {
            get { return _state; }
            set { SetProperty(ref _state, value); }
        }

        public bool Correct
        {
            get { return _correct; }
            set { SetProperty(ref _correct, value); }
        }

        public EmojiItem(EmojiType type, bool correct)
        {
            Type = type;
            Correct = correct;
            State = EmojiState.None;
        }
    }

    public class EmojiBoard : BindableBase
    {
        public const int Rounds = 12;
        public const int Columns = 3;

        private readonly List<EmojiType> types =
        Enum.GetValues(typeof(EmojiType)).Cast<EmojiType>().ToList();
        private readonly Random random = new Random((int)DateTime.Now.Ticks);

        private List<EmojiType> _selected = new List<EmojiType>();
        private List<EmojiType> _options = new List<EmojiType>();
        private int _current = 0;

        private List<EmojiType> ChooseTypes()
        {
            EmojiType selected;
            List<EmojiType> types = new List<EmojiType>();
            while ((types.Count < Rounds))
            {
                selected = (EmojiType)random.Next(0, this.types.Count - 1);
                if ((!types.Contains(selected)) || (types.Count < 1))
                {
                    types.Add(selected);
                }
            }
            return types;
        }

        private List<int> ChooseOptions(List<EmojiType> source)
        {
            int selected;
            List<int> target = new List<int>();
            while ((target.Count < Columns))
            {
                selected = random.Next(0, source.Count - 1);
                if ((!target.Contains(selected)) || (target.Count < 1))
                {
                    target.Add(selected);
                }
            }
            return target;
        }

        private void Shuffle(List<EmojiItem> list)
        {
            int count = list.Count;
            while (count > 1)
            {
                count--;
                int index = random.Next(count + 1);
                EmojiItem value = list[index];
                list[index] = list[count];
                list[count] = value;
            }
        }

        private IEnumerable<string> SplitCapital(string text)
        {
            Regex regex = new Regex(@"\p{Lu}\p{Ll}*");
            foreach (Match match in regex.Matches(text))
            {
                yield return match.Value;
            }
        }

        private string GetText(EmojiType type)
        {
            return string.Join(" ", SplitCapital(Enum.GetName(typeof(EmojiType), type)));
        }

        private string _text;
        private ObservableCollection<EmojiItem> _items = new ObservableCollection<EmojiItem>();

        public string Text
        {
            get { return _text; }
            set { SetProperty(ref _text, value); }
        }

        public ObservableCollection<EmojiItem> Items
        {
            get { return _items; }
            set { SetProperty(ref _items, value); }
        }

        public EmojiBoard()
        {
            _selected = ChooseTypes();
            _options = types.Where(types => !_selected.Any(selected => selected == types)).ToList();
        }

        public bool Next()
        {
            if (_current < Rounds)
            {
                Items.Clear();
                EmojiType answer = _selected[_current];
                List<EmojiItem> selections = new List<EmojiItem>
                {
                    new EmojiItem(answer, true)
                };
                Text = GetText(answer);
                List<int> indexes = ChooseOptions(_options);
                int indexOne = indexes[0];
                int indexTwo = indexes[1];
                EmojiType one = _options[indexOne];
                EmojiType two = _options[indexTwo];
                _options.RemoveAt(indexOne);
                _options.RemoveAt(indexTwo);
                selections.Add(new EmojiItem(one, false));
                selections.Add(new EmojiItem(two, false));
                Shuffle(selections);
                foreach (EmojiItem item in selections)
                {
                    Items.Add(item);
                }
                _current++;
                return true;
            }
            return false;
        }

        public void SetState(EmojiItem selected)
        {
            foreach (EmojiItem item in Items)
            {
                if (selected.Type == item.Type)
                {
                    item.Correct = selected.Correct;
                    item.State = item.Correct ?
                    EmojiState.Correct : EmojiState.Incorrect;
                }
            }
        }
    }

    public class EmojiTypeToGlyphConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (value is EmojiType type)
            {
                FieldInfo info = type.GetType().GetField(type.ToString());
                DescriptionAttribute[] attr =
                    (DescriptionAttribute[])info.GetCustomAttributes(typeof(DescriptionAttribute), false);
                return attr[0].Description;
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

    public class EmojiStateToBrushConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            if (value is EmojiState state)
            {
                Color[] colors = new Color[] { Colors.Transparent, Colors.ForestGreen, Colors.IndianRed };
                return new SolidColorBrush(colors[(int)state]);
            }
            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }

    public class Library
    {
        private const string app_title = "Emoji Game";

        private bool _gameOver = false;
        private EmojiItem _selected = null;
        private IAsyncOperation<IUICommand> _dialogCommand;

        private async Task<bool> ShowDialogAsync(string content, string title = app_title)
        {
            try
            {
                if (_dialogCommand != null)
                {
                    _dialogCommand.Cancel();
                    _dialogCommand = null;
                }
                _dialogCommand = new MessageDialog(content, title).ShowAsync();
                await _dialogCommand;
                return true;
            }
            catch (TaskCanceledException)
            {
                return false;
            }
        }

        public EmojiBoard Board { get; set; } = new EmojiBoard();

        public void Init(ref ItemsControl display, ref TextBlock text)
        {
            text.SetBinding(TextBlock.TextProperty, new Binding()
            {
                Source = Board,
                Path = new PropertyPath("Text"),
                Mode = BindingMode.OneWay
            });
            _gameOver = false;
            Board.Next();
            display.ItemsSource = Board.Items;
        }

        public async void Tapped(Button button)
        {
            if (!_gameOver)
            {
                _selected = (EmojiItem)button.Tag;
                Board.SetState(_selected);
                if (_selected.Correct)
                {
                    if (!Board.Next())
                    {
                        await ShowDialogAsync("Game Over, You Won!");
                        _gameOver = true;
                    }
                }
                else
                {
                    await ShowDialogAsync("Incorrect, You Lost!");
                    _gameOver = true;
                }
            }
            else
            {
                await ShowDialogAsync("Game Over!");
            }
        }

        public void New(ref ItemsControl display, ref TextBlock text)
        {
            Board = new EmojiBoard();
            Init(ref display, ref text);
            Board.Next();
        }
    }
}

In the Code File for Library there are using statements to include the necessary functionality. There are enum values for the Game such as EmojiType which contains all the possible Emoji values using the Description Attribute to encode their appearance and there is an EmojiState for the States of the Game.

There is a BindableBase Class which implements INotifyPropertyChanged there are SetProperty and OnPropertyChanged Methods. The EmojiItem Class Inherits from BindableBase and has Properties for EmojiType, EmojiState and bool for Correct.

The EmojoBoard Class represents the Board for the Game and has const and readonly Values such as for List of EmojiType which for these also for _selected and _options. The ChooseTypes Method is used to select a randomised set of EmojiType and ChooseOptions is used to select a randomised set of int. The Shuffle Method us used to randomise a List of EmojiItem. SplitCapital and GetText are used to get the Display Name of the EmojiType.

There are Properties for string and ObservableCollection of EmojiItem and a Constructor to call ChooseTypes for _selected and put the remainder in _options. The Next Method will pick set of three EmojiItem which is comprised of two wrong answers and one correct answer and will then randomise this subset. The SetState Method will be used to update the appearance of an EmojiItem.

The EmojiTypeToGlyphConverter Class is used to Convert the EmojiType to then get the Description Attribute to return the Content of the Emoji and the EmojiStateToBrushConverter Class is used to Convert the EmojiState to a SolidColorBrush.

The Library Class has a Member for the Selected EmojiItem and a ShowDialogAsync Method to display a MessageDialog and a Property for the EmojiBoard. There is an Init Method which is used to help with the look-and-feel of the Game the Tapped Method will be used to handle when the Button for an EmojiItem has been tapped and will indicate an incorrect answer with a Message or if the Game is Over and there is a New Method to start a new Game.

Step 8

In the Solution Explorer select MainPage.xaml

vs2017-mainpage-emoji-game

Step 9

From the Menu choose View and then Designer

vs2017-view-designer

Step 10

The Design View will be displayed along with the XAML View and in this above the Grid element, enter the following XAML:

<Page.Resources>
	<local:EmojiTypeToGlyphConverter x:Key="EmojiTypeToGlyphConverter"/>
	<local:EmojiStateToBrushConverter x:Key="EmojiStateToBrushConverter"/>
	<DataTemplate x:Key="EmojiTemplate" x:DataType="local:EmojiItem">
		<Button Height="130" Width="130" HorizontalAlignment="Center" VerticalAlignment="Center" 
		Background="{x:Bind State, Mode=OneWay, Converter={StaticResource EmojiStateToBrushConverter}}" 
		Tag="{x:Bind}" Tapped="Display_Tapped">
			<Viewbox>
				<TextBlock IsColorFontEnabled="True" FontFamily="Segoe UI Emoji" VerticalAlignment="Center"                           
					Text="{x:Bind Type, Mode=OneWay, Converter={StaticResource EmojiTypeToGlyphConverter}}"/>
			</Viewbox>
		</Button>
	</DataTemplate>
</Page.Resources>

Then while still in the XAML View between the Grid and /Grid elements, enter the following XAML:

<Viewbox Margin="50">
	<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
		<TextBlock Name="Label" TextAlignment="Center" HorizontalAlignment="Center"
		Style="{StaticResource SubtitleTextBlockStyle}" Width="400"/>
		<ItemsControl Name="Display" HorizontalAlignment="Center" Height="400" Width="400" 
			ItemTemplate="{StaticResource EmojiTemplate}">
			<ItemsControl.ItemsPanel>
				<ItemsPanelTemplate>
					<StackPanel HorizontalAlignment="Center" Orientation="Horizontal"/>
				</ItemsPanelTemplate>
			</ItemsControl.ItemsPanel>
		</ItemsControl>
	</StackPanel>
</Viewbox>
<CommandBar VerticalAlignment="Bottom">
	<AppBarButton Icon="Page2" Label="New" Click="New_Click"/>
</CommandBar>

Within the Page.Resources block of XAML above the Grid Element contains a EmojiTypeToGlyphConverter and EmojiStateToBrushConverter. There is a DataTemplate which is for a EmojiItem which is a Button with its Background Databound to State using the EmojiStateToBrushConverter and with its Content set to a Viewbox with a TextBlock with its Text Databound to the Type using the EmojiTypeToGlyphConverter.

Within the main Grid Element, the first block of XAML is a Viewbox Control which contains an StackPanel which is where the Board will be displayed using the given ItemTemplate. The second block of XAML is a CommandBar with AppBarButton for New which calls New_Click.

Step 11

From the Menu choose View and then Code

vs2017-view-code

Step 12

Once in the Code View, below the end of public MainPage() { … } the following Code should be entered:

Library library = new Library();

protected override void OnNavigatedTo(NavigationEventArgs e)
{
	library.Init(ref Display, ref Label);
}

private void Display_Tapped(object sender, TappedRoutedEventArgs e)
{
	library.Tapped((Button)sender);
}

private void New_Click(object sender, RoutedEventArgs e)
{
	library.New(ref Display, ref Label);
}

There is an OnNavigatedTo Event Handler which will call the Init Method from the Library Class, the Display_Tapped Event Handler which will handle when a Button has been Tapped and New_Click which will call the New Method of the Library Class and Play_Click will call the Play Method of the Library Class.

Step 13

That completes the Universal Windows Platform Application so Save the Project then in Visual Studio select the Local Machine to run the Application

vs2017-local-machine

Step 14

Once the Application has started running you can tap on an Emoji that you think is the one being asked for, if you get it right you progress to the next set of three Emoji to pick from – get all nine rounds and you Win, but get any wrong and you Lose the Game

uwp-ran-emoji-game

Step 15

To Exit the Application select the Close button in the top right of the Application

vs2017-close

Emoji Game is a simple game that produces a Random set of Emoji that then can be placed into a set of three to choose from, with nine rounds each one must be correct to win the game, it demonstrates how to use the Description Attribute to store the encoded Emoji Characters, it is a simple game but could be used to create other games such as Trivia and many more!

Creative Commons License

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s