• 开发WP版本的大菠萝英雄榜


    前言

    想当年Team有无数人在玩大菠萝,我被忽悠进来做肉盾,选了蛮子,从1.0开始,经历了103、105、108、2.0、2.1。这个游戏对我最大的帮助是学习了不同的技术,比如XAML、比如xcode开发、比如WP的开发。

    这篇文章不会step by step的介绍如何从0开始做WP开发,我会重点记录开发过程中要注意的坑,以及一些发布上架时的注意事项。

    文中大部分内容对于熟悉XAML的人来讲,可能过于简单。放在这里,希望对初学者有个帮助,尤其是如我这样做winform开发的人。

    先上几张图,

    wp_ss_20141024_0001wp_ss_20141024_0002wp_ss_20141024_0005wp_ss_20141024_0006wp_ss_20141024_0007wp_ss_20141024_0008 wp_ss_20141024_0009       

    官方API

    玻璃渣现在有两套API在并行运行,官方文档老版本的地址:https://github.com/blizzard/d3-api-docs,新版本的地址:https://dev.battle.net/io-docs

    两者的区别是,前者不包含诸如坚韧、圣教军等资料片中出现的内容,当然也不包括天梯、附魔等内容。后者不包含每个装备的item tooltip html。同时,后者必须要注册一个开发者账号(免费的)。

    XAML绑定

    Appbar的写法

    <phone:PhoneApplicationPage.ApplicationBar>
    
        <shell:ApplicationBar BackgroundColor="Black" ForegroundColor="White"  Mode="Default"  Opacity="1.0" IsMenuEnabled="True" IsVisible="True"> 
            <shell:ApplicationBar.MenuItems> 
                <shell:ApplicationBarMenuItem Text="Feedback" Click="Email_Click"/> 
                <shell:ApplicationBarMenuItem Text="Share" Click="Share_Click"/> 
                <shell:ApplicationBarMenuItem Text="Score" Click="Score_Click"/> 
                <shell:ApplicationBarMenuItem Text="Clear Cache" Click="ClearCache_Click"/> 
                <!--<shell:ApplicationBarMenuItem Text="Server Status" Click="ServerStatus_Click"/>--> 
            </shell:ApplicationBar.MenuItems> 
    
            <shell:ApplicationBarIconButton IconUri="/assets/appbar/search.png" Text="Search Friend" Click="AppbarAddFriend_Click"/> 
    
        </shell:ApplicationBar> 
    </phone:PhoneApplicationPage.ApplicationBar>
    View Code

    这里分为两部分,MenuItems是右下角三个点对应的菜单项,IconButton对应的是图标按钮。前者无对应图标,如果是英文,则全部小写字母;后者可以指定是否只显示图标,或者同时显示图标与文字。

    画线

    <Line X2="300" Stroke="White" Height="1" StrokeThickness="3"></Line>

    这段XAML画一条白色的线,注意颜色及线宽都是用Stroke***属性指定的。

    指定格式绑定数字

    <TextBlock HorizontalAlignment="Right" Text="{Binding Toughness, Converter={StaticResource IntConverter}}">Toughness</TextBlock>

    这个文本框绑定资料片中英雄的坚韧属性,如果想按照千分位(或者你自己别的格式显示),则再指定Converter的class信息。

    如,千分位的Convert代码如下:

    复制代码
    public class IntConverter : IValueConverter 
        { 
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
            { 
                return String.Format("{0:N0}", value); 
            }
    复制代码

    而如果显示小数点后两位的浮点数,则对应代码为:

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
            { 
    
                return String.Format("{0:f2}", value); 
            }

    属性的嵌套绑定

    复制代码
    <Border BorderThickness="1" Height="130" Canvas.Left="72" Canvas.Top="515" Width="68" BorderBrush="{Binding ItemList[mainhand].BorderBrush]}"  Tap="MainHand_Tap"> 
        <Border.Background> 
            <ImageBrush ImageSource="{Binding ItemList[mainhand].BorderBackGround}"/> 
        </Border.Background> 
        <Image Source="{Binding ItemList[mainhand].ItemImage}" Stretch="None" Height="128" Width="64" Margin="0,0,0,0"/> 
    </Border>
    复制代码

    这个page的DataContext是Hero hero,而Hero的部分结构如下:

    复制代码
    public class Hero 
    { 
        private int id; 
        private string name; 
    //。。。
    
        private Dictionary<string, Item> itemList = new Dictionary<string, Item>();
    复制代码

    主手武器的图片,如果用code behind方式写,对应代码中的hero.ItemList[“mainhand”].ItemImage。XAML方式则对应为:"{Binding ItemList[mainhand].ItemImage}" 。注意mainhand属性在xaml中没有了双引号。

    属性的嵌套绑定2

    <Image Canvas.Left="254" Canvas.Top="38" Source="{Binding SkillList[1].SkillImage}" Stretch="None" Tap="Skill1_Tap"></Image>

    这是Skill中的鼠标右键技能,大菠萝目前一共有2个鼠标技能,4个Action技能,4个被动技能(资料片之前是3个),代码中简单的用SkillList包含了这10个技能。所以对于鼠标右键技能,绑定的Xaml就变成了"{Binding SkillList[1].SkillImage}" ,同理,对于第一个被动技能,则对应的是="{Binding SkillList[6].SkillImage}"

    代码相关

    Unix时间的转换

    D3中的last updated是Unix时间,是一个ulong类型的值,转换为DateTime的代码如下:

    DateTime unix = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); 
    DateTime last = unix.AddSeconds(lastUpdated);

    文件名过长

    为了提高效率,对于装备的图片,代码中进行了缓存,保存在该应用的IsolatedStorage目录下。D3中的tooltip名字都很长,Windows系统中,路径+文件名长度不能超过260个字节。所以简单的做法,是对文件名做了一个Hash,来作为缓存文件名称。(当然,会有偶尔的冲突,这个代码没有做处理)

    localfile = Math.Abs(localfile.GetHashCode()).ToString();//localfile就是本地缓存的文件名。

    手机可用空间

    复制代码
    string free = String.Empty; 
    
    long freeSize=IsolatedStorageFile.GetUserStoreForApplication().AvailableFreeSpace;
    
    if (freeSize >> 30 >= 1) free = String.Format("{0:N0}GB", (freeSize >> 30)); 
    else if (freeSize >> 20 >= 1) free = String.Format("{0:N0}MB", (freeSize >> 20)); 
    else if (freeSize >> 10 >= 1) free = String.Format("{0:N0}KB", (freeSize >> 10)); 
    else free = String.Format("{0:N0}", freeSize);
    复制代码

    读取本地资源

    复制代码
    public BitmapImage BackGround 
            { 
                get 
                { 
                    return new BitmapImage(new Uri("/assets/background/" + this._class.Replace("-", "").ToLower() + this.male + "_background.jpg", UriKind.Relative)); 
    
                } 
            }
    复制代码

    注意Uri的路径写法。

    展示适配WP屏幕的HTML信息

    wp_ss_20141024_0009

    这是优化过的利用内置WebBrowser展示的我左手华戒的tooltip信息。如果直接用WebBrowser展示,该html会非常小,基本不可读。

    对于这个问题,可以通过设置viewport来解决。官方很有价值的一篇文章,请戳这里:http://blogs.msdn.com/b/iemobile/archive/2011/01/21/managing-the-browser-viewport-in-windows-phone-7.aspx

    放代码如下:

    复制代码
    StringBuilder sb = new StringBuilder(); 
    
    sb.AppendLine("<html>"); 
    sb.AppendLine("<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-us">"); 
    sb.AppendLine("<head xmlns:og="http://ogp.me/ns#" xmlns:fb="http://ogp.me/ns/fb#">"); 
    sb.AppendLine("<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />");//这行很重要 
    sb.AppendLine("<meta name="viewport" content="width=370,minimum-scale=1" />");//这行也很重要
    
    sb.AppendLine("</head>"); 
    sb.AppendLine("<body style=""); 
    sb.AppendLine(lines); //这就是D3返回给我的华戒的html描述信息
    
    sb.AppendLine("</body>"); 
    sb.AppendLine("</html>");
    复制代码

    并行获取数据

    每个英雄有14个装备,每个装备的信息都要单独获取对应的图片及tooltip。如果采用await GetItemByKey的方式,则14个装备的图片全部读完,读取时间至少在8秒之上。

    利用Task的并行处理方式,我们的处理效率则大大提高了。

    性能差的方式

    list.Add("head", await GetItemByKey(person, "head")); 
    list.Add("torso", await GetItemByKey(person, "torso")); 
    list.Add("feet", await GetItemByKey(person, "feet")); 
    list.Add("hands", await GetItemByKey(person, "hands")); 
    list.Add("shoulders", await GetItemByKey(person, "shoulders")); 
    list.Add("legs", await GetItemByKey(person, "legs")); 
    list.Add("bracers", await GetItemByKey(person, "bracers")); 
    list.Add("mainhand", await GetItemByKey(person, "mainHand")); 
    list.Add("offhand", await GetItemByKey(person, "offHand")); 
    list.Add("waist", await GetItemByKey(person, "waist")); 
    list.Add("rightfinger", await GetItemByKey(person, "rightFinger")); 
    list.Add("leftfinger", await GetItemByKey(person, "leftFinger")); 
    list.Add("neck", await GetItemByKey(person, "neck")); 
    list.Add("special", await GetItemByKey(person, "special"));
    View Code

    高性能的方式

    Task<Item> head = GetItemByKey(person, "head"); 
    Task<Item> torso = GetItemByKey(person, "torso"); 
    Task<Item> feet = GetItemByKey(person, "feet"); 
    Task<Item> hands = GetItemByKey(person, "hands"); 
    Task<Item> shoulders = GetItemByKey(person, "shoulders"); 
    Task<Item> legs = GetItemByKey(person, "legs"); 
    Task<Item> bracers = GetItemByKey(person, "bracers"); 
    Task<Item> mainhand = GetItemByKey(person, "mainHand"); 
    Task<Item> offhand = GetItemByKey(person, "offHand"); 
    Task<Item> waist = GetItemByKey(person, "waist"); 
    Task<Item> rightfinger = GetItemByKey(person, "rightFinger"); 
    Task<Item> leftfinger = GetItemByKey(person, "leftFinger"); 
    Task<Item> neck = GetItemByKey(person, "neck"); 
    Task<Item> special = GetItemByKey(person, "special");
    View Code

    //上面代码会立刻返回,只是定义了task而已。

    await Task.WhenAll(head, torso, feet, hands, shoulders, legs, bracers, mainhand, offhand, waist, rightfinger, leftfinger, neck, special);

    //这行代码会并行执行这14个任务,等待所有信息完成。

    list.Add("head", head.Result); 
    list.Add("torso", torso.Result); 
    list.Add("feet", feet.Result); 
    list.Add("hands", hands.Result); 
    list.Add("shoulders", shoulders.Result); 
    list.Add("legs", legs.Result); 
    list.Add("bracers", bracers.Result); 
    list.Add("mainhand", mainhand.Result); 
    list.Add("offhand", offhand.Result); 
    list.Add("waist", waist.Result); 
    list.Add("rightfinger", rightfinger.Result); 
    list.Add("leftfinger", leftfinger.Result); 
    list.Add("neck", neck.Result); 
    list.Add("special", special.Result);
    View Code

    //14个任务的结果加入到list中。

    判断Json片段是否为空

    private async Task<List<Skill>> GetSkillList(dynamic skills) 
    { 
        List<Skill> skillList = new List<Skill>(); 
        foreach (var skill in skills) 
        { 
            if (skill.ToString()!="{}")//skill不是null,如果不存在,则对应{}

    发布到商店

    WebBrowser的权限

    如果应用中用了WebBrowser,则需要指定相关权限。具体位置在:project-Properties-WMAppManifest.xml-Capabilities中,要check上ID_CAP_WEBBROWSERCOMPONENT

    SL8.1版本的发布

    对于SL8.1版本的WP应用,Package.appxmanifest文件的内容,要做修改。我这个程序是从8.0升级上来的,所以还是SL内核的版本,如果是一个新建的8.1WP应用,则无需做下面的修改。

    • <publisherDiaplsyName>与开发商名字一致
    • <Identity>下面的Name要与你在dev center中预留的名字一致
    • <Publisher>与dev center中的开发商GUID一致

    Deploy error: Package could not be registered

    官方论坛上有这个解答:https://social.msdn.microsoft.com/Forums/en-US/da89f2ee-03b6-43ed-aa21-97ef091798c9/deploy-error-package-could-not-be-registered?forum=WindowsPhonePreviewSDK

    8.1的系列官方blog

    http://blogs.msdn.com/b/thunbrynt/archive/2014/03/31/windows-phone-8-1-for-developers-overview.aspx

    FQQ

  • 相关阅读:
    直线的中点Bresenham算法的实现
    使用git 将自己的本地文件git到github上面的完整过程
    利用Microsoft VC++6.0 的MFC 的绘图工具实现简单图形的绘制
    github常见操作和常见错误及其解决办法
    浅谈软件配置管理工具(github & SVN)
    为Github 托管项目的访问添加SSH keys
    jQuery:用 lightTreeview 实现树形分类菜单的功能 展开收缩分类代码
    程序设计7大面向对象设计原则
    计算机组成原理实验之模拟整机实验考核试题
    计算机组成原理实验之CPU组成与指令周期实验
  • 原文地址:https://www.cnblogs.com/symphonygcr/p/4058308.html
Copyright © 2020-2023  润新知