C# XNA - Klicka på en SpriteFont
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)
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);
}
}
}
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.
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);
}
}
}
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.
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.
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;
}
}
}
SomeRandomClass är bara för att man ska hierarkiskt uppdatera alla objekt av den nya "spritefonten".
- Igår Nvidia: "Energieffektiva RTX 4060 sparar hundralappar" 36
- Igår MSI Geforce RTX 4060 Ventus 2X OC – bra prestanda vid 1080p men medioker kylare 45
- Igår Noctua släpper monteringsram för "deliddade" Ryzen 7000-processorer 15
- Igår Nvidias nästa arkitektur för Geforce kommer år 2025 58
- 27 / 6 Afox släpper kompakt Geforce RTX 4090 36
- Igår Veckans fråga: Vilket operativsystem föredrar du? 77
- Igår Bilar med smarta inslag ger fler dumma fel 58
- 27 / 6 Telekombranschen: "Smarta glasögon ersätter telefoner inom fem år" 88
- 26 / 6 Lastpass-användare rasar – kan inte logga in 59
- 26 / 6 Inet frågar SweClockers – Vad skulle du vilja förbättra på Inet.se? 53
- Fel post (dödsbo)8
- Bildvisnings program5
- PSVR2 - diskussionstråd444
- Kommer flytta till stan och mitt wifi kommer säkert synas av hundratals människor varje dag. Vilken router ska jag köpa och hur ska den ställas in?6
- Solfilm till fönster för sommarvärmen. Behöver råd.30
- Hjälp angående gammal psu och "nytt" grafikkort2
- Ert dyraste ” datormisstag”?402
- Vad lyssnar du på just nu?12615
- Fästingar.2
- Starfield utvecklas med AMD:s välsignelse148
- Säljes LG 27'' UltraGear 27GP950 4K Nano IPS 160 Hz HDMI 2.1
- Säljes Star Wars Jedi AMD kod
- Säljes Trasig Xiaomi Mi Electric Scooter (M365) Svart
- Säljes 5800x3D + x570 Meg Unify + be quiet! Dark Rock Slim
- Säljes AMD ASUS DUAL RX6700XT
- Säljes Dell OptiPlex 7010
- Säljes Datordelar: i5 9600k + 1070 GTX mm.
- Säljes 1080 TI | Vattenblock | 1TB SSD | Apple Watch 4 Stainless | Hörlurar | Mikrofon
- Säljes Intressekoll: Xbox Series S 512Gb samt Switch Oled 64Gb Vit
- Säljes Gamingdator RTX 3090, i9-10900K, 32GB ram
- Nvidia: "Energieffektiva RTX 4060 sparar hundralappar"36
- MSI Geforce RTX 4060 Ventus 2X OC – bra prestanda vid 1080p men medioker kylare45
- Veckans fråga: Vilket operativsystem föredrar du?78
- Bilar med smarta inslag ger fler dumma fel58
- Noctua släpper monteringsram för "deliddade" Ryzen 7000-processorer15
- Nvidias nästa arkitektur för Geforce kommer år 202558
- Microsoft vill strömma Windows från molnet71
- Starfield utvecklas med AMD:s välsignelse148
- Telekombranschen: "Smarta glasögon ersätter telefoner inom fem år"88
- En av tre svenskar använder annonsblockerare79
Externa nyheter
Spelnyheter från FZ
- Alan Wake och CoD: Kallt krig snart på PS Plus, enligt läcka igår
- Red Dead Redemption åldersmärkt igen i Korea – det spekuleras i remaster igår
- Fallout London flyttas för att slippa Starfield-konkurrensen igår
- Minecraft-filmen kan ha hittat sin Steve – Pedro "The Last of Us-Joel" Pascal igår
- Stor Diablo IV-patch släppt, mer XP och ombalanserade klasser igår