Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Using Button Class to Create Graphic Buttons in XNA, WPXNA (9)

0.00/5 (No votes)
24 Jun 2013 1  
How to use the Button class to create Graphic buttons in XNA, WPXNA

The original post can be found here.

Introduction/Catalog

I have developed some games on Windows Phone. Here, I'll share my experiences and gradually to upload some classes, no good name, I just call it WPXNA. (Some example code may not be stringent enough.)

Button

In game, we may need to create some graphic buttons, so I created a Button class to complete the task.

First of all, we need to define a Movie for the button, this Movie is used to control the graphics.

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 ( );
}

In the constructor, resourceName parameter represents the button graphic resource name, backgroundMovie is a field control button background movie.

You can specify a different movie sequence corresponding to the frame, you can also use the default values, as the following graphic:

Since backgroundMovie was created by Button, so the backgroundMovie need to be managed by Button. In the method Init, InitResource, we'll initialize backgroundMovie, the Dispose method, we will eliminate 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;
}

The method Press makes the button enter pressed state and trigger Pressing event. The method Unpress makes the button come out of the pressed state and triggers the Pressed event. You do not need to directly call the two methods above, just call 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;
}

Method ClickTest can be used to test whether the user selected the button.

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 );
}

In select method of Button, we play sound that resource name is click.s, and play the animation in press and unpress method. Derived class can modify the methods to perform their operations. In the Draw method, we will draw the button.

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;
 }
}

Field command represents command name of button, the field IsPressing indicates whether the button is pressed, property IsEnabled indicates whether the button is available, the property Location represents the button's location, property IsVisible indicates whether the button is visible.

Example

internal sealed class SceneT10
 : Scene
{
 private readonly Button buttonPlay;

 internal SceneT10 ( )
  : base ( Vector2.Zero, GestureType.None,
  new Resource[] {
   new Resource ( "play.image", 
   ResourceType.Image, @"image\button1" ),
   new Resource ( "click.s", 
   ResourceType.Sound, @"sound\click" ),
  },
  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 ( );
 }

}

In SceneT10, we need to load resources, including: graphics, sound.

In the inputing method, we use the PressTest method to test whether the user pressed the button.

In the constructor, we will set event Pressing and Pressed, in the buttonPlayPressing and buttonPlayPressed methods, we will print some text.

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

Finally, in our OnNavigatedTo method, we use the appendScene method to add a new SceneT10.

Get the code from here. For more contents, please visit WPXNA.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here