zoukankan      html  css  js  c++  java
  • 使用 Anime 类在 XNA 中创建小动画(十一)

    平方已经开发了一些 Windows Phone 上的一些游戏,算不上什么技术大牛。在这里分享一下经验,仅为了和各位朋友交流经验。平方会逐步将自己编写的类上传到托管项目中,没有什么好名字,就叫 WPXNA 吧,最后请高手绕道而行吧,以免浪费时间。(为了突出重点和减少篇幅,有些示例代码可能不够严谨。)

    Anime

    Anime 类继承自 Movie 类,唯一的区别在于,Anime 类将包含一些动作,这些动作将说明 Anime 的运动方式,你可以使用 Anime 类来表示页面上移动的白云。Anime 的字段 actions 表示所有动作,其中 AnimeAction 是一个基类,之后我们会说明他。

    private readonly List<AnimeAction> actions = new List<AnimeAction> ( );
    
    internal Anime ( string name, string resourceName, Vector2 location, int width, int height, int rate, string defaultSequenceName, MovieSequence[] sequences, params AnimeAction[] actions )
        : base ( name, resourceName, location, width, height, rate,
        0f,
        defaultSequenceName, sequences )
    {
    
        if ( null != actions )
            foreach ( AnimeAction action in actions )
                if ( null != action )
                {
                    action.Anime = this;
                    this.actions.Add ( action );
                }
    
    }

    在 Anime 的构造函数中,我们将参数 actions 中的 AnimeAction 保存到字段 actions 中。而其余的参数和 Movie 所使用的参数类似,这里不再说明。

    internal void Update ( GameTime time )
    {
    
        foreach ( AnimeAction action in this.actions )
            action.Update ( time );
    
        Movie.NextFrame ( this );
    }

    在 Anime 的 Update 方法中,我们将调用每一个 AnimeAction 的 Update 方法,这样 AnimeAction 就能够控制 Anime 的状态,比如:位置,速度等。此外,我们还需要调用 Movie 类的 NextFrame 方法,这样动画才能被播放。

    internal static void Draw ( Anime anime, GameTime time, SpriteBatch batch )
    { Movie.Draw ( anime, time, batch ); }

    在 Anime 的 Draw 方法中,我们直接简单的调用 Movie 的 Draw 方法来绘制动画。

    AnimeAction

    AnimeAction 是所有动画动作的基类,他本身很简单,代码如下:

    internal abstract class AnimeAction
    {
        internal Anime Anime; 
    
        protected AnimeAction ( )
        { }
    
        internal abstract void Update ( GameTime time );
    
    }

    字段 Anime 被用来控制 Anime,比如:移动 Anime 的位置。他是在 Anime 的构造函数中被设置的,而 AnimeAction 类并不会修改它。

    所有从 Anime 继承的类都必须实现方法 Update,在这个方法中,我们将使用字段 Anime 来调整 Anime 的状态。

    AnimeMovementAction

    AnimeMovementAction 是一个继承自 AnimeAction 的类,用来控制 Anime 的位置,他可以实现 Anime 的左右移动,下面是 AnimeMovementAction 中的字段。

    private readonly Rectangle area;
    
    private float xSpeed;
    private float ySpeed;
    
    private readonly long xTurnFrameCount;
    private readonly long yTurnFrameCount;
    
    private long xTurnFrameIndex;
    private long yTurnFrameIndex;

    字段 area 表示一个区域,用来限制 Anime 的移动,比如:如果 Anime 移动到了区域的右边,则他将在区域的左边出现。

    字段 xSpeed,ySpeed 表示 Anime 在 x,y 轴上移动速度。字段 xTurnFrameCount,yTurnFrameCount,xTurnFrameIndex,yTurnFrameIndex 用来记录在合适 Anime 的速度将被反转。

    在 AnimeMovementAction 的构造函数中,我们设置了这些字段,其中还使用了 World 的 ToFrameCount 函数。在 Update 方法中,我们根据字段设置了 Anime 的位置。

    internal AnimeMovementAction ( float xSpeed, float ySpeed, float xTurnSecond, float yTurnSecond, float xCurrentSecond, float yCurrentSecond, Rectangle area )
        : base ( )
    {
        this.xTurnFrameCount = World.ToFrameCount ( xTurnSecond );
        this.yTurnFrameCount = World.ToFrameCount ( yTurnSecond );
        this.xSpeed = xSpeed;
        this.ySpeed = ySpeed;
    
        this.xTurnFrameIndex = World.ToFrameCount ( xCurrentSecond );
        this.yTurnFrameIndex = World.ToFrameCount ( yCurrentSecond );
    
        this.area = area;
    }
    
    internal override void Update ( GameTime time )
    {
    
        if ( this.xTurnFrameCount > 0 && this.xTurnFrameIndex++ > this.xTurnFrameCount )
        {
            this.xTurnFrameIndex = 0;
            this.xSpeed = -this.xSpeed;
        }
    
        if ( this.yTurnFrameCount > 0 && this.yTurnFrameIndex++ > this.yTurnFrameCount )
        {
            this.yTurnFrameIndex = 0;
            this.ySpeed = -this.ySpeed;
        }
    
        this.Anime.Location += new Vector2 ( this.xSpeed, this.ySpeed );
    
        if ( !this.area.IsEmpty )
        {
            Vector2 location = this.Anime.Location;
    
            if ( this.xSpeed > 0 )
            {
    
                if ( location.X - this.Anime.Width > this.area.Right )
                    this.Anime.Location = new Vector2 ( this.area.Left, location.Y );
    
            }
            else if ( this.xSpeed < 0 )
                if ( location.X < this.area.Left )
                    this.Anime.Location = new Vector2 ( this.area.Right + this.Anime.Width, location.Y );
    
            if ( this.ySpeed > 0 )
            {
    
                if ( location.Y > this.area.Bottom )
                    this.Anime.Location = new Vector2 ( location.X, this.area.Top - this.Anime.Height );
    
            }
            else if ( this.ySpeed < 0 )
                if ( location.Y + this.Anime.Height < this.area.Top )
                    this.Anime.Location = new Vector2 ( location.X, this.area.Bottom );
    
        }
    
    }

    ToFrameCount,FrameRate

    World 类的 FrameRate 属性表示在游戏中每一秒的帧数,方法 ToFrameCount 可以返回指定时间内执行的帧数。

    private static int frameRate = 30;
    internal static int FrameRate
    {
        get { return frameRate; }
        set { frameRate = value <= 0 ? 30 : value; }
    }
            
    internal static long ToFrameCount ( double second )
    { return ( long ) ( second * World.FrameRate ); }
    internal static long ToFrameCount ( float second )
    { return ( long ) ( second * World.FrameRate ); }

    示例

    场景 SceneT12 包含两个小鸟的动画,bird1 可以从左到右飞行并不断重复,bird2 可以垂直移动。

    在 drawing 方法中,我们需要调用 Anime 的 Draw 方法来绘制小鸟。而在 updating 方法中,我们需要调用 Anime 的 Update 方法来更新位置。

    internal sealed class SceneT12
        : Scene
    {
        private readonly Anime bird1;
        private readonly Anime bird2;
    
        internal SceneT12 ( )
            : base ( Vector2.Zero, GestureType.None,
            new Resource[] {
                new Resource ( "bird2.image", ResourceType.Image, @"imageird2" ),
            },
            new Making[] {
                new Anime ( "b1", "bird2.image", new Vector2 ( 100, 100 ), 80, 80, 5, "a",
                    new MovieSequence[] { new MovieSequence ( "a", true, new Point ( 1, 1 ), new Point ( 2, 1 ) ) },
                    new AnimeMovementAction ( 4, 0, new Rectangle ( -80, 0, 480, 0 ) )
                    ),
                new Anime ( "b2", "bird2.image", new Vector2 ( 300, 300 ), 80, 80, 5, "a",
                    new MovieSequence[] { new MovieSequence ( "a", true, new Point ( 2, 1 ), new Point ( 3, 1 ) ) },
                    new AnimeMovementAction ( 0, 2, 0, 2 )
                    ),
    
            }
            )
        {
            this.bird1 = this.makings[ "b1" ] as Anime;
            this.bird2 = this.makings[ "b2" ] as Anime;
        }
    
        protected override void drawing ( GameTime time, SpriteBatch batch )
        {
            base.drawing ( time, batch );
    
            Anime.Draw ( this.bird1, time, batch );
            Anime.Draw ( this.bird2, time, batch );
        }
    
        protected override void updating ( GameTime time )
        {
            this.bird1.Update ( time );
            this.bird2.Update ( time );
    
            base.updating ( time );
        }
    
    }

    在 World 的 OnNavigatedTo 方法中,我们添加了新的 SceneT12。

    protected override void OnNavigatedTo ( NavigationEventArgs e )
    {
        // ...
    
        this.appendScene ( new Scene[] { new mygame.test.SceneT12 ( ) } );
    
        base.OnNavigatedTo ( e );
    }

    本期视频 http://v.youku.com/v_show/id_XNTc3NTI1OTYw.html

    项目地址 http://wp-xna.googlecode.com/
    更多内容 WPXNA

    平方开发的游戏 http://zoyobar.lofter.com/

    QQ 群 213685539

    欢迎访问我在其他位置发布的同一文章:http://www.wpgame.info/post/decc4_7122b5



  • 相关阅读:
    Android View 的绘制流程
    Android Studio 注释模板
    Flutter https://flutter.cn/docs学习之 工作原理
    Android 手机兼容差异
    Flutter plugin的两种方式
    本周总结
    mapreduce程序开发简单实例 WordCount
    《需求工程——软件建模与分析》阅读笔记之一
    本周总结
    本周总结
  • 原文地址:https://www.cnblogs.com/zoyobar/p/wpxna11.html
Copyright © 2011-2022 走看看