zoukankan      html  css  js  c++  java
  • [翻译]XNA外文博客文章精选之fourteen


    PS:自己翻译的,转载请著明出处

                                                                在XNA中创建一个In-Game的奖励
                                                                                                  Nick Gravelyn
    导言
                                       一个共同的点在Xbox LIVE Arcade和零售Xbox360游戏是熟悉的声音和sight of unlocking achievenments(译者:看到解锁的成就).这个成就是一个很大的方式来增加你游戏的游戏时间,通过给玩家额外的挑战设法去完成它。这个成就可以得到任何东西:完成的水平,在Xbox LIVE打败一个对手,或者刚刚找到一个愚蠢的复活节彩蛋。
                                       不幸的是,Xbox LIVE社区游戏不能得到官方的成就系统。但是,这也不是说你的游戏不能有这些额外的挑战而去努力。在这篇文章中,我将显示给你如何去创建你自己的完成奖励系统,以一条消息显示和声音效果来表示。

    Creating an Award System(创建一个奖励系统)
                                       为了开始我们需要去定义什么是真实的奖励。对于我们的目的来说,它是一个有名字和纹理的一个对象。所以我们将创建我们的Award类如下:

     1 public class Award
     2 {
     3     public string Name { getset; }
     4     public string TextureAssetName { getset; }
     5     public Texture2D Texture { getprivate set; }
     6     public void LoadTexture(ContentManager content)
     7     {
     8         Texture = content.Load<Texture2D>(TextureAssetName);
     9     }
    10 }
                                       我们包含一个TextureAssetName属性和一个LoadTexture方法去使它很容易去创建一个对象在开始和后来加载需要的纹理。
                                       我们准备使用一个事件去通报给奖励的监听者,因为他们没有被锁定。为了这个我们将使用一个自定义的事件参数类:
    1 public class AwardUnlockedEventArgs : EventArgs
    2 {
    3     public Award Award { getprivate set; }
    4     public AwardUnlockedEventArgs(Award award) 
    5     {
    6         Award = award; 
    7     }
    8 }
                                      
    Award Componet(奖励部分)
                                       下一步,我们将开始我们的AwardsComponent,它将会是主要的工作work-horse(驮马)为这个系统。这个组件将会管理奖励的表单,以及采取任何消息的显示提示。让我们开始通过创建我们准备使用的成分和某些基础的文件,属性,和事件。这里内在解释的行,所以我不想再多说每条数据的代表什么。
     1 public class AwardsComponent : DrawableGameComponent
     2 {
     3     // 我门保留一个没有锁的奖励列表
     4     private readonly List<Award> unlockedAwards = new List<Award>();
     5     // 我们需要声明一个近期没有锁的奖励队列
     6     private readonly Queue<Award> justUnlocked = new Queue<Award>();
     7     // the length of time spent fading in and out announcements
     8     private const float AnnouncementFadeLength = .25f;
     9     // the length of time the announcement 
    10     // is at full opacity on the screen
    11     private const float AnnouncementLength = 2f;
    12     // sets the offset (in pixels from the top-left corner) 
    13     // of where to place the award icon relative 
    14     // to the background texture
    15     private const int IconOffsetX = 11;
    16     private const int IconOffsetY = 8;
    17     // sets the location of the center of the 
    18     // award name in the announcement
    19     private const int TextCenterX = 161;
    20     private const int TextCenterY = 25;
    21     // a timer for announcements
    22     private float announcementTimer;
    23     // the background to use for the announcement
    24     private Texture2D announcementBackground;
    25     // a sound effect to play when a new announcement is going up
    26     private SoundEffect announcementSound;
    27     // a SpriteBatch used to draw everything
    28     private SpriteBatch spriteBatch;
    29     // the font used for rendering award names over the background
    30     private SpriteFont announcementFont;
    31     // whether or not to draw the announcement
    32     private bool showAnnouncement;
    33     /// Gets the list of all awards in the game.
    34     public List<Award> Awards { getprivate set; }
    35     /// Raised when an award is unlocked.
    36     /// The event is useful for games that unlock special content when awards
    37     /// are unlocked. This allows games to unlock awards from anywhere and have
    38     /// a single location listen for the events to respond accordingly.
    39     public event EventHandler<AwardUnlockedEventArgs> AwardUnlocked;
    40     /// Creates a new AwardsComponent for the given game.;
    41     public AwardsComponent(Game game): base(game)
    42     {
    43         Awards = new List<Award>();
    44         // we want awards to draw absolutely last 
    45         // so we set the draw order to max
    46         DrawOrder = int.MaxV
    alu
    e;
    47     }
    48 }
     
    Managing The Awards(管理奖励)                                    
                                     希望你已经熟悉你自己的这个类,现在我们将继续添加功能性,它将允许我们去管理这个奖励。首先我们需要一些帮助方法:
     1 public Award GetAwardByName(string name)
     2 {
     3     return Awards.Find(a => a.Name == name);
     4 }
     5 public bool IsAwardUnlocked(Award award)
     6 {
     7     return unlockedAwards.Contains(award);
     8 }
     9 public void UnlockAward(Award award)
    10 {
    11     if (Awards.Contains(award) && !IsAwardUnlocked(award))
    12     {
    13         unlockedAwards.Add(award);
    14         justUnlocked.Enqueue(award);
    15         if (AwardUnlocked != null)
    16             AwardUnlocked(thisnew AwardUnlockedEventArgs(award));
    17     }
    18 }

                                      这些方法相当的简单,但是我们要回顾下我们所使用的。GetAwardBy名字简单,使用Find的方法以一个lamda表达式,为了去找到一个基于它自己的一个奖励。IsAwardUnlocked只检查去看看,这个奖励是否在unlockedAwards表单里面。UnlockAward首先确保这个奖励是在这个系统中并且一直没有被锁,然后移动它到解锁的表单中,声明排列它,并且引发该事件。

    Updateing(更新)
                                     在这点上我们准备有一个功能性的奖励管理系统,不幸的是,它仍然缺少介绍。让我们从我们的Update方法开始添加,视觉和声音flair(译者:能力)到奖励中。同样,我将留下注释行,因为它很容易去解释每一行:

     1 public override void Update(GameTime gameTime)
     2 {
     3     // if there are unlocked awards left to announce
     4     if (justUnlocked.Count > 0)
     5     {
     6         // if we're not currently showing an announcement
     7         if (!showAnnouncement)
     8         {
     9             // reset the timer and show the announcement
    10             announcementTimer = 0f;
    11             showAnnouncement = true;
    12             // play our sound effect
    13             announcementSound.Play();
    14         }
    15         // otherwise if we are showing an announcement
    16         else
    17         {
    18             // add to the timer
    19             announcementTimer += (float)gameTime.ElapsedGameTime.TotalSeconds;
    20             // if the timer is past the announcement period 
    21             //(fade in, on screen, fade out)
    22             if (announcementTimer >= (AnnouncementFadeLength * 2+ AnnouncementLength)
    23             {
    24                 // hide the announcement
    25                 showAnnouncement = false;
    26                 // dequeue the award since it has been announced
    27                 justUnlocked.Dequeue();
    28             }
    29         }
    30     }
    31 }

                                     正如你看的Update十分的简单。它只处理计时器以及播放声音,当一个新的announcement(译者:通知或者宣告)被显示出来时。

    Drawing the Award(绘制奖励)
                                     现在,我们将移动到Draw方法中。这个方法十分的简单明了,依赖少数的帮助方法去使事情变的很整洁。也同样有注释。

     1 public override void Draw(GameTime gameTime)
     2 {
     3     // if an announcement is being shown
     4     if (showAnnouncement)
     5     {
     6         // default to full opacity
     7         float opacity = 1f;
     8         // figure out if we're fading in or out 
     9         // and set the opacity accordingly
    10         if (announcementTimer < AnnouncementFadeLength)
    11         {
    12             opacity = announcementTimer / AnnouncementFadeLength;
    13         }
    14         else if (announcementTimer > 
    15                     AnnouncementFadeLength + AnnouncementLength)
    16         {
    17             opacity = 1.0f - ((announcementTimer - AnnouncementLength - AnnouncementFadeLength) / AnnouncementFadeLength);
    18         }
    19         // figure out the bounds based on the 
    20         // texture size and the Guide.NotificationPosition
    21         Rectangle announcementBounds = CalculateAnnouncementBounds();
    22         // make the colors
    23         Color color = new Color(Color.White, opacity);
    24         Color fontColor = new Color(Color.Black, opacity);
    25         // start drawing. we use SaveState in case you have 
    26         // 3D rendering so it won't go bad
    27         spriteBatch.Begin(SpriteBlendMode.AlphaBlend, SpriteSortMode.Deferred, SaveStateMode.SaveState);
    28         // draw the background
    29         spriteBatch.Draw(announcementBackground, announcementBounds, color);
    30         // draw the icon
    31         spriteBatch.Draw(justUnlocked.Peek().Texture, GetIconBounds(announcementBounds), color);
    32         // draw the award name
    33         spriteBatch.DrawString(announcementFont, justUnlocked.Peek().Name, GetNamePosition(announcementBounds), fontColor);
    34         // done drawing
    35         spriteBatch.End();
    36     }
    37     base.Draw(gameTime);
    38 }

                                  绘制是相当的简单。我们声明我们的不透明性,然后绘制我们的背景,图标,和使用一些帮助方法去放置这些项目。

    Helper Methods(帮助方法)
                                  现在让我们看下帮助方法。这里同样十分简单明了,同样也有注释行:

     1 private Vector2 GetNamePosition(Rectangle announcementBounds)
     2 {
     3     // get the center position of the text using our 
     4     // TextCenterX and TextCenterY offsets
     5     Vector2 position = new Vector2(announcementBounds.X + TextCenterX, announcementBounds.Y + TextCenterY);
     6     // measure the text we'll be drawing
     7     Vector2 stringSize = announcementFont.MeasureString(justUnlocked.Peek().Name);
     8     // subtract half of the size from the position to center it
     9     position -= stringSize / 2f;
    10     // return the position, 
    11     // but cast the X and Y to integers to avoid filtering
    12     return new Vector2((int)position.X, (int)position.Y);
    13 }
    14 private Rectangle GetIconBounds(Rectangle announcementBounds)
    15 {
    16     // simply offset the announcement bounds position 
    17     // by the icon offsets and set the width and height to 64
    18     return new Rectangle(announcementBounds.X + IconOffsetX, announcementBounds.Y + IconOffsetY, 6464);
    19 }
    20 private Rectangle CalculateAnnouncementBounds()
    21 {
    22     // the amount of the screen to buffer 
    23     // on the sides for the safe zone
    24     const float safeZoneBuffer = .1f;
    25     PresentationParameters pp = GraphicsDevice.PresentationParameters;
    26     // the actual buffer sizes for the width and height
    27     int widthBuffer = (int)(pp.BackBufferWidth * safeZoneBuffer);
    28     int heightBuffer =(int)(pp.BackBufferHeight * safeZoneBuffer);
    29     // start with a basic rectangle the size of our texture
    30     Rectangle announcementBounds = new Rectangle(00, announcementBackground.Width, announcementBackground.Height);
    31     // figure out all six of our values now to 
    32     // make our switch statement cleaner
    33     int topY = heightBuffer;
    34     int centerY = pp.BackBufferHeight / 2 - announcementBounds.Height / 2;
    35     int bottomY = pp.BackBufferHeight - heightBuffer - announcementBounds.Height;
    36     int leftX = widthBuffer;
    37     int centerX = pp.BackBufferWidth / 2 - announcementBounds.Width / 2;
    38     int rightX =pp.BackBufferWidth - widthBuffer - announcementBounds.Width;
    39     // set the bounds X and Y based on the notification position
    40     switch (Guide.NotificationPosition)
    41     {
    42         case NotificationPosition.BottomCenter:
    43             announcementBounds.X = centerX;
    44             announcementBounds.Y = bottomY;
    45             break;
    46         case NotificationPosition.BottomLeft:
    47             announcementBounds.X = leftX;
    48             announcementBounds.Y = bottomY;
    49             break;
    50         case NotificationPosition.BottomRight:
    51             announcementBounds.X = rightX;
    52             announcementBounds.Y = bottomY;
    53             break;
    54         case NotificationPosition.Center:
    55             announcementBounds.X = centerX;
    56             announcementBounds.Y = centerY;
    57             break;
    58         case NotificationPosition.CenterLeft:
    59             announcementBounds.X = leftX;
    60             announcementBounds.Y = centerY;
    61             break;
    62         case NotificationPosition.CenterRight:
    63             announcementBounds.X = rightX;
    64             announcementBounds.Y = centerY;
    65             break;
    66         case NotificationPosition.TopCenter:
    67             announcementBounds.X = centerX;
    68             announcementBounds.Y = topY;
    69             break;
    70         case NotificationPosition.TopLeft:
    71             announcementBounds.X = leftX;
    72             announcementBounds.Y = topY;
    73             break;
    74         case NotificationPosition.TopRight:
    75             announcementBounds.X = rightX;
    76             announcementBounds.Y = topY;
    77             break;
    78     }
    79     return announcementBounds;
    80 }


    Saving and Loading(保存和加载)
                                     这就是它的介绍。现在我们解锁成就可以突然出现,让游戏知道它们做的很好。最后一件事,我们的系统需要一个方法去保存被解锁的achievementts(译者:成就),这样用户不用每一次他们玩游戏时,必须解锁他们所有。为此,我们实行一个非常基本的保存和加载系统:

     1 public void SaveUnlockedAwards(string file)
     2 {
     3     // delete the file if it exists
     4     if (File.Exists(file))File.Delete(file);
     5     // use a StreamWriter to write the name of 
     6     // each unlocked award to the file
     7     using (StreamWriter writer = new StreamWriter(file))
     8     {
     9         unlockedAwards.ForEach(a => writer.WriteLine(a.Name));
    10     }
    11 }
    12 public void LoadUnlockedAwards(string file)
    13 {
    14     // clear the list of unlocked awards
    15     unlockedAwards.Clear();
    16     // use a StreamReader to read in the data
    17     using (StreamReader reader = new StreamReader(file))
    18     {
    19         // loop while we're not at the end of the stream
    20         while (!reader.EndOfStream)
    21         {
    22             // get an award by name where each line is an award
    23             Award award = GetAwardByName(reader.ReadLine());
    24             // if the award is not null, add it to our unlocked awards list
    25             if (award != null)
    26                 unlockedAwards.Add(award);
    27         }
    28     }
    29 }     

    结论
                                        现在我们真的可以完成了。你的游戏现在有一个有能力给为你想要给你的玩家的任何的数目的奖励。现在你必须想出所有这些奖励,并且提出好听的名字和漂亮的图标。

                                        下载例子包含所有的资源代码(通过行注释和智能感知XML注释)以及样例游戏,它会
    向你显示你的游戏可以使用这些奖励。
    源代码:http://www.ziggyware.com/readarticle.php?article_id=217
    (完)

  • 相关阅读:
    双主双写、只备份某些表且要在建表ID自增
    我的系统资源呢?php-fpm你知道吗?
    apache常用的两种工作模式 prefork和worker
    Binlog的三种模式
    Tomcat
    JVM初识、调优
    httpclient 3.1跳过https请求SSL的验证
    POM报错Failure to transfer org.apache.maven.plugins:maven-resources-plugin:pom:2.6 from
    eclipse快捷键,移动和复制一段代码
    org.codehaus.jettison.json.JSONObject使用方法
  • 原文地址:https://www.cnblogs.com/315358525/p/1564153.html
Copyright © 2011-2022 走看看