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.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.