C# XNA - Klicka på en SpriteFont

Permalänk
Medlem

C# XNA - Klicka på en SpriteFont

Vad är det bästa sättet att få spelet att känna av när någon trycker på en SpriteFont? Med en vanlig sprite så skulle jag se om musen är inuti kollisionsrektangeln och om knappen är nedtryckt, med jag vet inte riktigt hur man gör med en SpriteFont.

Hoppas på att det finns någon kunnig inom XNA på Sweclockers.

Permalänk

Höjden på din kollisionsrektangel bör vara font storleken, och bredden ska vara textens längd multiplicerat med font storleken.(Antar jag skulle fungera iallafall)

Permalänk
Medlem
Skrivet av Murloc:

Vad är det bästa sättet att få spelet att känna av när någon trycker på en SpriteFont? Med en vanlig sprite så skulle jag se om musen är inuti kollisionsrektangeln och om knappen är nedtryckt, med jag vet inte riktigt hur man gör med en SpriteFont.

Hoppas på att det finns någon kunnig inom XNA på Sweclockers.

Varför inte bara kolla om musens Vector2 position (förmodat att det är det du använder) och musens position är detsamma?
Exempelvis:

(deklareras i klassen) SpriteFont Font; Vector2 FontPos; (definieras i Load) Font = this.Content.Load<SpriteFont>("..\\Stats"); FontPos = new Vector2(20f, 20f); (Draw) spriteBatch.DrawString(Font, "Ett test", FontPos, Color.White); (bör ligga i Update) if (Mouse.GetState().X == FontPos.Position.X && Mouse.GetState().Y == FontPos.Position.Y) { //här sker koden }

Precisionen är inte perfekt men det bör ge dig en uppskattning om hur man gör det.

using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace CollisionTextTest { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont font; Vector2 FontPos; private int _characterFeet; private string _MoreText = "Jag ar en text"; private int _pixelWidth; private bool _displayWarning; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here FontPos = new Vector2(20f, 20f); this.IsMouseVisible = true; this._displayWarning = false; this._characterFeet = 0; base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load<SpriteFont>("Text"); // TODO: use this.Content to load your game content here } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); _pixelWidth = (this._MoreText.Length * 14) - Convert.ToInt32(FontPos.X) ; _characterFeet = 14 + Convert.ToInt32(FontPos.Y); if (Mouse.GetState().Y >= FontPos.Y && Mouse.GetState().Y <= _characterFeet && Mouse.GetState().X > FontPos.X && Mouse.GetState().X < this._pixelWidth) { _displayWarning = true; } else { _displayWarning = false; } // TODO: Add your update logic here base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); spriteBatch.DrawString(this.font, this._MoreText, FontPos, Color.White); spriteBatch.DrawString(this.font, string.Format("{0}f X, {1}f Y\nAssumed width: {2}f X\nAssumed height: {3} and {4}", Mouse.GetState().X, Mouse.GetState().Y, _pixelWidth, _characterFeet, FontPos.Y), new Vector2(20f, 120f), Color.White); if (this._displayWarning) { spriteBatch.DrawString(this.font, "Collision detected", new Vector2(this.graphics.PreferredBackBufferHeight / 2, this.graphics.PreferredBackBufferWidth / 2), Color.Red); } spriteBatch.End(); // TODO: Add your drawing code here base.Draw(gameTime); } } }

Dold text

Jag kodar utan skandinaviska tecken för jag lärde mig så, men allt är ganska enkelt att förstå hoppas jag.
Hör av dig om problem uppstår.

Visa signatur

Citera om du vill ha svar, hjälpte jag dig, gilla svaret!
AzireVPN - Felkod40

Permalänk

Har gjort ett litet exempel på hur du kan göra för att se om musen är på texten, det är nog en bra idé att göra en egen klass av detta om du använder det.

Variablar

SpriteFont font; Vector2 position; Rectangle collision; Color color; String message;

LoadContent

font = Content.Load<SpriteFont>("Font"); position = new Vector2(10, 10); message = "Kalle Anka"; color = Color.Orange; collision = new Rectangle((int)position.X, (int)position.Y, (int)font.MeasureString(message).X, (int)font.MeasureString(message).Y);

Update

Rectangle rect = new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 1, 1); if (collision.Intersects(rect)) color = Color.Red; else color = Color.Orange;

Draw

spriteBatch.Begin(); spriteBatch.DrawString(font, message, position, color); spriteBatch.End();

Texten ändrar färg till röd när musen är över den, och tillbaka till orange när den inte är över.

Game1.cs

using System; using System.Collections.Generic; using System.Linq; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Audio; using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Media; namespace SpriteFontCollision { /// <summary> /// This is the main type for your game /// </summary> public class Game1 : Microsoft.Xna.Framework.Game { GraphicsDeviceManager graphics; SpriteBatch spriteBatch; SpriteFont font; Vector2 position; Rectangle collision; Color color; String message; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } /// <summary> /// Allows the game to perform any initialization it needs to before starting to run. /// This is where it can query for any required services and load any non-graphic /// related content. Calling base.Initialize will enumerate through any components /// and initialize them as well. /// </summary> protected override void Initialize() { // TODO: Add your initialization logic here IsMouseVisible = true; base.Initialize(); } /// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { // Create a new SpriteBatch, which can be used to draw textures. spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load<SpriteFont>("Font"); position = new Vector2(10, 10); message = "Kalle Anka"; color = Color.Orange; collision = new Rectangle((int)position.X, (int)position.Y, (int)font.MeasureString(message).X, (int)font.MeasureString(message).Y); // TODO: use this.Content to load your game content here } /// <summary> /// UnloadContent will be called once per game and is the place to unload /// all content. /// </summary> protected override void UnloadContent() { // TODO: Unload any non ContentManager content here } /// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { // Allows the game to exit if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); // TODO: Add your update logic here Rectangle rect = new Rectangle(Mouse.GetState().X, Mouse.GetState().Y, 1, 1); if (collision.Intersects(rect)) color = Color.Red; else color = Color.Orange; base.Update(gameTime); } /// <summary> /// This is called when the game should draw itself. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); // TODO: Add your drawing code here spriteBatch.Begin(); spriteBatch.DrawString(font, message, position, color); spriteBatch.End(); base.Draw(gameTime); } } }

Dold text
Permalänk
Medlem

Glömde lägga till en sak, frågan var ju "klicka på" och inte enbart kollisionshantering, men lägg isåfall bara till detta i if-frågan:

&& Mouse.GetState().LeftButton == ButtonState.Pressed

Det kollar helt enkelt om musens vänstra knapp är nedtryckt, såfort du lyfter på den så nekas kollisionen.

Visa signatur

Citera om du vill ha svar, hjälpte jag dig, gilla svaret!
AzireVPN - Felkod40

Permalänk
Medlem

Tack, jag förstår hur man fixar collision till SpriteFont, men nu undrar jag hur jag gör en egen klass som räknas som SpriteFont. Om jag gör en SpriteFont genom att klicka på "Add >> New Item... >> Sprite Font" så har jag ingen tillgång till klassen och kan inte skriva in variabler för position etc till klassen.

Permalänk
Medlem
Skrivet av Murloc:

Tack, jag förstår hur man fixar collision till SpriteFont, men nu undrar jag hur jag gör en egen klass som räknas som SpriteFont. Om jag gör en SpriteFont genom att klicka på "Add >> New Item... >> Sprite Font" så har jag ingen tillgång till klassen och kan inte skriva in variabler för position etc till klassen.

Du kan inte designa en ny klass som heter "SpriteFont" eftersom det är ett reserverat namn. Skapa snarare en klass med valfritt namn <SpriteFontKlassen> som har metoden public bool Collision(Vector2 pos). Tror inte du kommer få skapa ett objekt som påstår sig vara en SpriteFont heller eftersom den inte kommer kunna konverteras till det som ges via Framework.

Varför inte bara skapa en klass som nyttjar ett SpriteFont objekt utan att man måste instansiera objektet utifrån?

Den nya draw funktionen bör ju då se ut typ såhär:

public class NågotSexigtKlassnamn { public void Draw(SpriteBatch batch) { batch.Begin(); //utför nödvändig kod här batch.End(); } }

Oavsett, här har du en hel lösning på ditt skolprojekt eller projekt.

using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.Input; namespace CollisionTextTest { public class Game1 : Microsoft.Xna.Framework.Game { private SomeRandomClass operations = new SomeRandomClass(); GraphicsDeviceManager graphics; SpriteBatch spriteBatch; private SpriteFont font; public Game1() { graphics = new GraphicsDeviceManager(this); Content.RootDirectory = "Content"; } protected override void Initialize() { this.IsMouseVisible = true; base.Initialize(); } protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); font = Content.Load<SpriteFont>("Text"); operations.Add(new MyAlternateSpriteFontClass{ Font = font, Color = Color.White, Position = new Vector2(20f, 20f), Text = "Bara testar" }); } protected void UnloadContents() { } protected override void Update(GameTime gameTime) { operations.Update(); base.Update(gameTime); } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.CornflowerBlue); spriteBatch.Begin(); operations.Draw(spriteBatch); spriteBatch.End(); base.Draw(gameTime); } } } public class SomeRandomClass { private List<MyAlternateSpriteFontClass> FontCollection = new List<MyAlternateSpriteFontClass>(); public void Add(MyAlternateSpriteFontClass newObj) { FontCollection.Add(newObj); } public void Draw(SpriteBatch batch) { foreach (MyAlternateSpriteFontClass spriteFont in this.FontCollection) { spriteFont.Draw(batch); } } public void Update() { foreach (MyAlternateSpriteFontClass spriteFont in this.FontCollection) { spriteFont.Update(); } } } public class MyAlternateSpriteFontClass { /// <summary> /// SpriteFont /// </summary> public SpriteFont Font { private get; set; } /// <summary> /// Text som du vill ska synas /// </summary> public string Text { private get; set; } /// <summary> /// Textfärg /// </summary> public Color Color { private get; set; } /// <summary> /// Position för att placera text på skärmen /// </summary> public Vector2 Position { private get; set; } /// <summary> /// Avgör om kollision mellan mus och text har skett /// </summary> private bool Intersected { get; set; } /// <summary> /// Kontrollerar kollisionshanteringen /// Kollisionskrav: Mustryckning på och mouse-hover på texten /// </summary> public void Update() { if (Mouse.GetState().Y >= Position.Y && Mouse.GetState().Y <= (Font.MeasureString(this.Text).Y + this.Position.Y) && Mouse.GetState().X >= Position.X && Mouse.GetState().X <= (this.Font.MeasureString(this.Text).X + this.Position.X) && Mouse.GetState().LeftButton == ButtonState.Pressed) { this.Intersected = true; } else { this.Intersected = false; } } /// <summary> /// Skriver ut texten till klienten /// </summary> /// <param name="batch">SpriteBatch</param> public void Draw(SpriteBatch batch) { try { //kolla om röd text ska skrivas (vi har kolliderat eller inte) if (this.Intersected) { batch.DrawString(this.Font, this.Text, this.Position, Color.Red); } //Om inte skriv den vanliga definierade färgen else { batch.DrawString(this.Font, this.Text, this.Position, this.Color); } } catch (InvalidOperationException) { throw; } catch (Exception) { throw; } } }

Dold text

SomeRandomClass är bara för att man ska hierarkiskt uppdatera alla objekt av den nya "spritefonten".

Visa signatur

Citera om du vill ha svar, hjälpte jag dig, gilla svaret!
AzireVPN - Felkod40