zoukankan      html  css  js  c++  java
  • 使用 Button 类在 XNA 中创建图形按钮(九)

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

    按钮

    在游戏当中,我们可能需要创建一些图形按钮,平方创建了 Button 类来完成这个任务。

    首先,我们需要在按钮中定义了一个 Movie,使用这个 Movie 来控制图形,他可以播放按钮各种状态时的动画。

    protected readonly Movie backgroundMovie;
    
    protected string upMovieSequenceName = "up";
    protected string downMovieSequenceName = "down";
    protected string disableMovieSequenceName = "disable";
    
    internal Button ( string name, string resourceName, string command, Vector2 location, int width, int height, bool isSole, Point upFrameIndex, Point downFrameIndex, Point disableFrameIndex, params MovieSequence[] movieSequences )
        : base ( name, resourceName )
    {
        // ...
    
        List<MovieSequence> sequences = new List<MovieSequence> ( );
        sequences.Add ( new MovieSequence ( this.upMovieSequenceName, upFrameIndex ) );
        sequences.Add ( new MovieSequence ( this.downMovieSequenceName, downFrameIndex ) );
        sequences.Add ( new MovieSequence ( this.disableMovieSequenceName, disableFrameIndex ) );
    
        if ( null != movieSequences && movieSequences.Length != 0 )
            sequences.AddRange ( movieSequences );
    
        this.backgroundMovie = new Movie ( "background", resourceName, location, width, height, 0, 1f, this.upMovieSequenceName,
            sequences.ToArray ( )
            );
    
        // ...
    }
    
    internal override void Init ( Scene scene )
    {
        base.Init ( scene );
    
        this.backgroundMovie.Init ( scene );
    }
    
    internal override void InitResource ( ResourceManager resourceManager )
    {
        base.InitResource ( resourceManager );
    
        this.backgroundMovie.InitResource ( resourceManager );
    }
    
    public override void Dispose ( )
    {
        this.backgroundMovie.Dispose ( );
    
        base.Dispose ( );
    }

    在构造函数中,参数 resourceName 表示按钮图形的资源名称,字段 backgroundMovie 是控制按钮背景的电影,默认电影序列的名称为 up,down,disable,分别对应了按钮松开,按钮按下,按钮不可用。

    你可以指定不同电影序列对应的帧,也可以使用默认的值。默认情况下,up 右边的是 down,down 右边是 disable,就像下面的图形:

    由于 backgroundMovie 是被 Button 创建的,所以 backgroundMovie 需要被 Button 管理。在方法 Init,InitResource 中,我们会初始化 backgroundMovie,在方法 Dispose 中,我们销毁了 backgroundMovie。

    internal event EventHandler<ButtonEventArgs> Pressing;
    internal event EventHandler<ButtonEventArgs> Pressed;
    
    internal static void Press ( Button button )
    {
        button.IsPressing = true;
    
        button.press ( );
    
        if ( null != button.Pressing )
            button.Pressing ( button, new ButtonEventArgs ( button.command ) );
    
    }
    
    internal static void Unpress ( Button button )
    {
    
        if ( !button.IsPressing )
            return;
    
        button.IsPressing = false;
    
        button.unpress ( );
    
        if ( null != button.Pressed )
            button.Pressed ( button, new ButtonEventArgs ( button.command ) );
    
    }
    
    internal static bool PressTest ( Button button, IList<Motion> motions )
    {
    
        if ( !button.isEnabled || !button.isVisible )
            return false;
    
        foreach ( Motion motion in motions )
            if ( motion.Type == MotionType.Down || motion.Type == MotionType.Press )
            {
                Point location = new Point ( ( int ) motion.Position.X, ( int ) motion.Position.Y );
    
                if ( button.bound.Contains ( location ) )
                {
                    Press ( button );
                    return true;
                }
    
            }
    
        Unpress ( button );
        return false;
    }

    方法 Press 将使按钮进入按下状态,并触发 Pressing 事件。方法 Unpress 将使按钮离开按下状态,并触发 Pressed 事件。你并不需要直接调用上面的两个方法,而只需要调用 PressTest,这个方法将检测某一个按钮的按下状态。

    internal event EventHandler<ButtonEventArgs> Selected;
    
    internal static void Select ( Button button )
    {
    
        if ( !button.isEnabled )
            return;
    
        button.select ( );
    
        if ( null != button.Selected )
            button.Selected ( button, new ButtonEventArgs ( button.command ) );
    
    }
    
    internal static bool ClickTest ( Button button, IList<Motion> motions )
    {
    
        if ( !button.isEnabled || !button.isVisible )
            return false;
    
    
        foreach ( Motion motion in motions )
            if ( motion.Type == MotionType.Up )
            {
                Point location = new Point ( ( int ) motion.Position.X, ( int ) motion.Position.Y );
    
                if ( button.bound.Contains ( location ) )
                {
                    Select ( button );
                    return true;
                }
    
            }
    
        return false;
    }

    方法 Select 和 Press 方法类似,并可以通过方法 ClickTest 来测试用户是否选择了按钮。

    protected virtual void select ( )
    { this.scene.AudioManager.PlaySound ( "click.s" ); }
    
    protected virtual void press ( )
    {
    
        if ( this.backgroundMovie.CurrentSequenceName != this.downMovieSequenceName )
            Movie.Play ( this.backgroundMovie, this.downMovieSequenceName );
    
    }
    
    protected virtual void unpress ( )
    {
    
        if ( this.backgroundMovie.CurrentSequenceName != this.upMovieSequenceName )
            Movie.Play ( this.backgroundMovie, this.upMovieSequenceName );
    
    }
    
    internal virtual void Draw ( SpriteBatch batch )
    {
    
        if ( !this.isVisible )
            return;
    
        Movie.Draw ( this.backgroundMovie, null, batch );
    }

    Button 的 select 方法中将播放资源名称为 click.s 的声音,press 和 unpress 方法中将播放相关的动画。派生类可以修改这些方法来执行自己的操作。在 Draw 方法中,我们将绘制按钮。

    protected string command;
    
    internal bool IsPressing = false;
    
    private bool isEnabled = true;
    internal virtual bool IsEnabled
    {
        get { return this.isEnabled; }
        set
        {
            Movie.Play ( this.backgroundMovie, value ? this.upMovieSequenceName : this.disableMovieSequenceName );
    
            this.isEnabled = value;
        }
    }
    
    protected Vector2 location;
    public virtual Vector2 Location
    {
        get { return this.location; }
        set {
            this.location = value;
            
            this.backgroundMovie.Location = value;
            
            this.bound = new Rectangle (
                ( int ) ( value.X ),
                ( int ) ( value.Y ),
                this.Width,
                this.Height
                );
        }
    }
    
    internal override bool IsVisible
    {
        set
        {
            base.IsVisible = value;
    
            this.backgroundMovie.IsVisible = value;
        }
    }

    字段 command 表示按钮的命令,字段 IsPressing 表示的按钮是否被按下,属性 IsEnabled 表示按钮是否可用,属性 Location 表示按钮的位置,属性 IsVisible 表示按钮是否可见。

    一个例子

    internal sealed class SceneT10
        : Scene
    {
        private readonly Button buttonPlay;
    
        internal SceneT10 ( )
            : base ( Vector2.Zero, GestureType.None,
            new Resource[] {
                new Resource ( "play.image", ResourceType.Image, @"imageutton1" ),
                new Resource ( "click.s", ResourceType.Sound, @"soundclick" ),
            },
            new Making[] {
                new Button ( "b.play", "play.image", "PLAY", new Vector2 ( 100, 100 ), 100, 50, new Point ( 1, 1 ) )
            }
            )
        {
            this.buttonPlay = this.makings[ "b.play" ] as Button;
            //this.buttonPlay.IsEnabled = false;
    
            this.buttonPlay.Pressing += this.buttonPlayPressing;
            this.buttonPlay.Pressed += this.buttonPlayPressed;
        }
    
        protected override void inputing ( Controller controller )
        {
            base.inputing ( controller );
    
            Button.PressTest ( this.buttonPlay, controller.Motions );
        }
    
        protected override void drawing ( GameTime time, SpriteBatch batch )
        {
            base.drawing ( time, batch );
    
            this.buttonPlay.Draw ( batch );
        }
    
        private void buttonPlayPressing ( object sender, ButtonEventArgs e )
        { Debug.WriteLine ( "play button pressing" ); }
        private void buttonPlayPressed ( object sender, ButtonEventArgs e )
        { Debug.WriteLine ( "play button pressed" ); }
    
        public override void Dispose ( )
        {
            this.buttonPlay.Pressing -= this.buttonPlayPressing;
            this.buttonPlay.Pressed -= this.buttonPlayPressed;
    
            base.Dispose ( );
        }
    
    }

    在场景 SceneT10 中,我们载入按钮所需要的资源,包括:图像,声音。并定义一个按钮。

    在场景 SceneT10 的 inputing 方法中,我们使用 Button 的 PressTest 方法测试用户是否按下了按钮。

    在构造函数中,我们会 Button 设置了事件 Pressing 和 Pressed,在 buttonPlayPressing 和 buttonPlayPressed 方法中,我们打印了一些文字。

    protected override void OnNavigatedTo ( NavigationEventArgs e )
    {
        // ...
        
        this.appendScene ( new mygame.test.SceneT10 ( ), null, false );
        
        // ...
    }

    最后,我们在 World 的 OnNavigatedTo 方法中,使用 appendScene 方法添加了场景 SceneT10。

    本期视频 http://v.youku.com/v_show/id_XNTc0MDY3ODQw.html
    项目地址 http://wp-xna.googlecode.com/

    更多内容 WPXNA
    平方开发的游戏 http://zoyobar.lofter.com/
    QQ 群 213685539

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

  • 相关阅读:
    Tomcat启动流程简析
    Tomcat的启停脚本源码解析
    Servlet规范
    CCNA
    CCNA-Part 6
    MYSQL 使用基础
    CCNA-Part5
    CCNA-Part4 -网络层
    MySQL 字符串索引优化方案
    CCNA-Part3
  • 原文地址:https://www.cnblogs.com/zoyobar/p/wpxna9.html
Copyright © 2011-2022 走看看