Here is my class I made to draw a HUD:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
namespace Sleyser1
{
public class Hud
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
Texture2D tempHUD;
Rectangle viewportRect;
SpriteFont HUD;
Vector2 FontPos;
Vector2 FontPos2;
public void Hud()
{
HUD = Content.Load<SpriteFont>("HUD");
FontPos = new Vector2(40, 20);
FontPos2 = new Vector2(150, 20);
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null);
spriteBatch.Draw(tempHUD, viewportRect, Color.White);
string output = "Health:";
string output2 = "Magic:";
Vector2 FontOrigin = HUD.MeasureString(output) / 2;
spriteBatch.DrawString(HUD, output, FontPos, Color.Red, 0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.DrawString(HUD, output2, FontPos2, Color.Blue, 0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.End();
}
}
}
So how do I call it from here so that it draws.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
base.Draw(gameTime);
}
The question I am asking is how do you call a class from a method?
public void Hud()
is actually the constructor of your class, it should not be responsible for drawing (especially since you draw the same class many times and the purpose of the constructor is to ...construct a class)
So, the first step is to remove this:
spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null);
spriteBatch.Draw(tempHUD, viewportRect, Color.White);
string output = "Health:";
string output2 = "Magic:";
Vector2 FontOrigin = HUD.MeasureString(output) / 2;
spriteBatch.DrawString(HUD, output, FontPos, Color.Red, 0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.DrawString(HUD, output2, FontPos2, Color.Blue, 0, FontOrigin, 1.0f, SpriteEffects.None, 0.5f);
spriteBatch.End();
from the constructor and add it to a new class method, such as Draw().
UPDATE:
XNA provides a Game class which seems to be the main class of the application. It should contain a reference to an object of your class.
The spritebatch is also a member of the Game class so it should be passed to the Draw function of your HUD as a parameter. Then all you need to do is call the HUD's Draw method (of a HUD object which is a reachable from the Game object) from the Game's Draw method.
Agree with the other answers here, but I'd go one further.
Turn your Hud class into a component, specifically one that that implements DrawableGameComponent. This way, you can encapsulate all your Hud logic into one place, and as the name implies, the component is able to draw itself.
So, steps :-
In your LoadContent method, add the following code :-
Services.AddService(typeof(SpriteBatch), spriteBatch);
Create a new game component within Visual Studio 2010
Change the class your component inherits from. To start with, it'll be GameComponent. Change this into DrawableGameComponent
Override the LoadContent method. While you're not specifically loading any additional content in your example, you may wish to add Hud specific content at a later time.
Override the Update method. Any state changes to the Hud ( i.e. changing health or magic values ) should be made here.
Override the Draw method. Anything specific to drawing should go here. Note that you can get a handle to the main SpriteBatch service ( declared earlier on ) by including the following code in this overridden method :-
SpriteBatch spriteBatch =
Game.Services.GetService(typeof(SpriteBatch)) as SpriteBatch;
Finally, in the initialize method of your game class, add the following code:-
Components.Add(new HudComponent(this));
Your component will now be part of the main game loop.
Make an abstract class, for example GameElement, which contains methods Update and Draw.
Then create a (static) list of GameElement List<GameElement> Elements.
Make your class HUD inherit GameElement and implement methods Update (updates logic based on gametime) and Draw (draws the game element to the surface). When you create the HUD add it to to list Elements
In the main Draw method call foreach(var element in Elements) element.Draw().
That way you handle drawing and updating of the HUD and any other game element (Scene, Player, etc), and you never have to change the main drawing and updating loop .
You can even make GameElement an interface IGameElement so that you are not restricted to inheriting GameElement class.
You cant call a class you create an instance of it.
Classname class = new Classname();
class.method();
Related
I'm creating a game in monogame, and I've loaded tiles in my game inside the Draw() function like so:
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(danChar, charPosition, Color.White);
// loop below loads the 'grass' tiles only
// assuming gameworld size of 770x450
for (int i = 0; i < 770; i += 31) // adds 31 to i (per tile)
{
position = new Vector2(i, 392); // places incrementation into vector position
spriteBatch.Draw(gameTile, position, Color.White); // draws the tile each time
if (i == 744)
{
i = i + 26; // fills last space between 744 and 770
position = new Vector2(i, 392);
}
spriteBatch.Draw(gameTile, position, Color.White);
}
// loop below loads the brick tiles only (ones without grass)
spriteBatch.End(); // ends the spriteBatch call
base.Draw(gameTime);
}
However I would prefer that this was a separate class rather than being placed directly into the draw function, however I'm not too sure how to do this and would appreciate any help given.
Thanks in advance!
If you just want to move the code as is to another class, create your class (e.g. something like GameWorld seems to appropriate for your code)
public class GameWorld
{
// You may wish to move your gameTile definition into this class if it is the only
// class that uses it, and handle the content loading for it in here.
// e.g. if you're currently loading the texture in the LoadContent method in your game
// class, create a LoadContent method here and pass in ContentManger as a parameter.
// I've passed in the texture as a parameter to the Draw method in this example to
// simplify as I'm not sure how you're managing your textures.
public void Draw(SpriteBatch spriteBatch, GameTime gameTime, Texture2D gameTile)
{
// loop below loads the 'grass' tiles only
// assuming gameworld size of 770x450
for (int i = 0; i < 770; i += 31) // adds 31 to i (per tile)
{
Vector2 position = new Vector2(i, 392); // places incrementation into vector position
spriteBatch.Draw(gameTile, position, Color.White); // draws the tile each time
if (i == 744)
{
i = i + 26; // fills last space between 744 and 770
position = new Vector2(i, 392);
}
spriteBatch.Draw(gameTile, position, Color.White);
}
// loop below loads the brick tiles only (ones without grass)
}
}
Then the Draw method in your Game class would look like
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
spriteBatch.Begin();
spriteBatch.Draw(danChar, charPosition, Color.White);
// Assuming you've created/loaded an instance of the GameWorld class
// called gameWorld in Initialize/LoadContent
gameWorld.Draw(spriteBatch, gameTime, gameTile);
spriteBatch.End(); // ends the spriteBatch call
base.Draw(gameTime);
}
Just make sure you're calling the Draw methods in the correct order. e.g. you want your player to appear above any background tiles.
I believe the default SpriteSortMode is Deferred which draws in the order the calls are made (i.e. from the back to the front).
You can specify a different SpriteSortMode in your call to spriteBatch.Begin() if you need to but for a simple game just move the Draw calls around.
More info on SpriteSortMode at MSDN if needed.
Similarly you can chain your Update, LoadContent methods into these classes if you wish, making sure to pass in anything you need as arguments.
Update:
To define gameWorld as an instance of the GameWorld class, you define it near the top of your game class, then typically initialize it in the Initialize method.
So your game class will look something like
public class MyGameName : Microsoft.Xna.Framework.Game
{
private SpriteBatch spriteBatch;
// other variable declarations
// Add a declaration for gameWorld
private GameWorld gameWorld;
protected override Initialize()
{
// Add the following line to initialize your gameWorld instance
gameWorld = new GameWorld();
}
// other existing code - your LoadContent, Update, Draw methods etc.
}
Im making a 2d game in XNA. I started off using drawable game components and was quite happy. Every sprite is derived from drawable-game-component and each one has its own begin/end statement (even each tile making up a wall).
Ive since realised after reading around a bit that this is a bad way to do it for performance.
Now I'm wondering what is a good way to do it...
Lets say for each room in my game I do...
_spritebatch.Begin(SpriteSortMode.Deferred,
BlendState.Opaque,
SamplerState.LinearClamp,
DepthStencilState.Default,
RasterizerState.CullNone,
null,
_camera.Transform);
for (each block in Blocklist)
{
_spritebatch.Draw(block._txture,
block._position + block._centerVect,
block.txtrect, block._color,
(float)block.txtrot,
block._centerVect,
1.0f,
SpriteEffects.None,
0f);
}
_spritebatch.End();
the reason I'm asking is I'll have to make loads of the fields in each block public so the Room class can get at them to do its _spritebatch.Draw eg. block._position
I'm assuming this wont really matter and performance will improve but is there any nicer architecture anyone can recommend to do this?
Also since that code is up there, can anyone comment on the SpriteBatch.Begin paramaters I'm using? Are they the fastest ones? All I need in there is the transform
the reason I'm asking is I'll have to make loads of the fields in each
block public so the Room class can get at them to do its
_spritebatch.Draw eg. block._position
Assuming you have many rooms and in each room many blocks, you can give each room and each block a public or protected Draw() method, then all the fields of the block do not need to be public.
class Block
{
... // private fields about Block
...
Public void Draw(GameTime gt, SpriteBatch sb)
{
sb.Draw(private block fields here);
}
}
Then for the Rooms
class Room
{
... // private fields about room
...
List<Block> blocks;
Public void Draw(GameTime gt, SpriteBatch sb)
{
sb.Draw(private room fields here);
foreach(Block b in blocks)
b.Draw(gt, sb)
}
}
Then in the main game class
//fields section
List<Room> rooms;
// in the Draw
spriteBatch.Begin();
foreach(Room r in rooms)
r.Draw(gt, spriteBatch);
spriteBatch.End();
In this scenario, there is a single Begin/End block for the whole frame.
I'm trying to use Window.ClientBounds.Width to check if the sprite is within the windows border. I want to use this in the another class than the Game1.cs. Let's say I have a Car.cs class and inside that class I want to have an own Update method that check if it's inside the borders of the window, but I cant use Window.ClientBounds.Width this!? I have also tested to create a static int gameBorder = Window.ClientBounds.Width; inside Game1.cs and reach the value that way, but this doesn't work either?! Help is preciated! Thanks!
Is there a better way than stackowerflow for XNA questions that is free?
When constructing the Car class I would pass a reference to the Game that the car is supposed to be part of or the GraphicsDevice that it's supposed to be displayed on.
class Car
{
// Keep a reference to the game inside the car class.
Game game;
public Car (Game game)
{
this.game = game;
}
public void Update(.....
{
// You can access the client bounds here.
// the best thing about this method is that
// if the bounds ever changes, you don't have
// to notify the car, it always has the correct
// values.
}
}
There's no need to go to all that work, and waste all that memory.
XNA has a very exact and specific means of testing positions of objects.
You can simply pass in the GraphicsDeviceManager graphics.PreferredBackBufferWidth and Height methods to get the width and height of your window.
From there, you know whether an object is visible in the game window based on whether it is within the rectangle of those positions.
So lets say you set your back buffer width and height to be 640x480.
Then you would simply check to see if the bounds of your texture are within that rectangle.
So, here's your function:
public void CheckIfWithinWindow(int width, int height)
{
Rectangle wndRect = new Rectangle(0, 0, width, height);
Rectangle carRect = new Rectangle(carPos.X, carPos.Y, carTexture.Width, carTexture.Height);
if (wndRect.Intersects(carRect))
{
//carTexture is within currently visible window bounds!
}
else
{
//carTexture is NOT within currently visible window bounds!
}
}
Then you can call this function from your Update Method in your starting XNA class like so.
public void Update(GameTime gameTime)
{
myCar.CheckIfWithinWindow(graphics.PreferredBackBufferWidth, graphics.PreferredBackBufferHeight);
}
Hope that helps. Have fun.
I am trying to draw text on to the screen using a spritefont in XNA.
I can get the text to appear, but no matter what I try there is always something going wrong with something else when I draw the text.
I am trying to display the FPS.
I have tried it in a few different ways and in various different XNA projects I have made.
Some of the things that happen when drawing the text to the screen include -
Vertices being drawn further away and in the wrong spots, vertices not being drawn at all, wire frame mode not being able to be turned on.
Just depending on how I try to render the text I always end up with one of these.
And then if I comment out the part that draws the text, everything will be back to normal.
Here is some code
My variables at the top of the code are -
GraphicsDeviceManager graphics;
SpriteFont font;
SpriteBatch spriteBatch;
In my LoadContent I have
font = Content.Load<SpriteFont>("SpriteFont1");
RasterizerState rs = new RasterizerState();
rs.FillMode = FillMode.WireFrame;
GraphicsDevice.RasterizerState = rs;
spriteBatch = new SpriteBatch(GraphicsDevice);
And here is my entire Draw method -
protected override void Draw(GameTime gameTime)
{
CreateMesh();
GraphicsDevice.Clear(Color.SkyBlue);
effect.Parameters["View"].SetValue(cam.viewMatrix);
effect.Parameters["Projection"].SetValue(projectionMatrix);
effect.CurrentTechnique = effect.Techniques["Technique1"];
effect.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Count, 0, indices.Length / 3);
spriteBatch.Begin();
spriteBatch.DrawString(font, frameRate.ToString(), new Vector2(1, 1), Color.Black);
spriteBatch.End();
frameCounter++;
base.Draw(gameTime);
}
This is the closest way I have foundto working yet, but for some reason it makes wireframe not work no matter what I try to do, and I really need wire frame.
EDIT:
I debugged the fill mode as the program runs and it sets it back to solid on its own for some reason when using the sprite font.
I can reset the the fill mode every frame before the vertices are drawn, but I'd really rather not have to do that.
You should apply your rasterizer state just before drawing somthing win wireframe mode, not only in the load method... because batch.Begin() method will set a default rasterizer state
if you want use other rasterizer state for spritebatch, you should provide one
spritebatch.Begin(SortMode,...,,.., rs );
your code should be changed this way:
static RasterizerState rs = new RasterizerState() { FillMode = FillMode.Wireframe; }
protected override void Draw(GameTime gameTime)
{
CreateMesh();
GraphicsDevice.Clear(Color.SkyBlue);
GraphicsDevice.RasterizerState = rs;
effect.Parameters["View"].SetValue(cam.viewMatrix);
effect.Parameters["Projection"].SetValue(projectionMatrix);
effect.CurrentTechnique = effect.Techniques["Technique1"];
effect.CurrentTechnique.Passes[0].Apply();
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, vertices.Count, 0, indices.Length / 3);
....
Using a SpriteBatch changes the render state to the point that 3D graphics no longer work unless you change the render state back to a 3D-friendly state. See this article for more details.
http://blogs.msdn.com/b/shawnhar/archive/2006/11/13/spritebatch-and-renderstates.aspx
Alright, let's say that I have a tile texture of some floor or something. And I'd like that my player will walk on that.
How can I set this tile to make it a as a floor?
I need this tile texture to be all over the screen width right?
How am I doing it?
Thanks
If you want a really easy way, here it is:
First you create a new Class and name it Tile:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework; // Don't forget those, they will let you
using Microsoft.Xna.Framework.Content; // access some class like:
using Microsoft.Xna.Framework.Graphics; // Texture2D or Vector2
namespace Your_Project _Name
{
class Tile
{
}
{
So far so good, now create the Texture and Position in your class just like this:
namespace Your_Project _Name
{
class Tile
{
Texture2D texture;
Vector2 position;
public void Initialize()
{
}
public void Draw()
{
}
}
{
As you can see I also created two Methods, Initialize and Draw, now we will Initialize our
texture and position for the tile texture in the public void Initialize(),
I don't know how you use your ContentManager but here is a easy way:
public void Initialize(ContentManager Content)
{
texture = Content.Load<Texture2D>("YourfloorTexture"); //it will load your texture.
position = new Vector2(); //the position will be (0,0)
}
Now we need to draw our texture a number of time how will we do that? The way thasc said, the code can be more complex but here is one that you will understand, I will add a SpriteBatch so I can Draw. All this is done in the public void Draw():
public void Draw(SpriteBatch spriteBatch)
{
for (int i=0; i<30;i++) //will do a loop 30 times. Each Time i will =
//a valor from 0 to 30.
{
spriteBatch.Draw(texture, position, Color.White);
//Will draw the texture once, at the position Vector2
//right now position = (0,0)
spriteBatch.Draw(texture, new Vector2((int)i,(int)i), Color.White);
//Will Draw the texture 30 times, the first time on the position (0,0)
//Second Time on (1,1) .. third (2,2) etc...
spriteBatch.Draw(texture, new Vector2((int)position.X + (i * texture.Width), (int)position.Y + (i * texture.Height), Color.White));
//Will Draw the Texture 30 times Spaced by the Width and height
//of the texture (this is the code you need)
}
}
I didn't tried it but it should work, now its just a sample, you can figure out the rest. There is a lot of other methods to do it but this one is really easy. Ok, now the final step is to implement this class so go in your principal class where you have all your code and before this:
public Game1()
Create a new instance of your tile class
Tile tile;
and Initialize it in the protected override void Initialize():
tile = new Tile();
tile.Initialize(Content);
Now you have to draw it on the screen go at the end of the class and find protected override void Draw(GameTime gameTime) and call the draw method of our class:
spriteBatch.Begin();
tile.Draw(spriteBatch);
spriteBatch.End();
This is all the steps to complete a plain simple tile system. As I said there is a lot of others methods you just have to read tutorials about them or create them on your own.
If you don't plan on doing anything extra with the tiled background, I'd recommend thasc's solution and tile the sprite in a single call.
To do that, you create a rectangle as large as your background, and pass SamplerState.LinearWrap to SpriteBatch.Begin, then call Draw on the background rectangle.
Rectangle backgroundRect = new Rectangle(0, 0, backWidth, backHeight);
spriteBatch.Begin(..., ..., SamplerState.LinearWrap, ..., ...);
spriteBatch.Draw(backgroundTexture, backgroundRect, Color.White);
spriteBatch.End();
In case you're curious, what this does is create a single polygon that covers the background area, which will grab coordinates off your texture from 0.0f to backWidth. Textures are usually mapped between (0.0f, 0.0f) and (1.0f, 1.0f), which represent the corners of the given texture. If you go beyond these boundaries, TextureAddressMode defines how these coordinates will be treated:
Clamp will cut down the coordinates back into the 0-1 range.
Wrap will wrap the coordinates back to 0, so 0.0 = 2.0 = 4.0 = etc. and 1.0 = 3.0 = 5.0 = etc.
Mirror will also wrap, but mirroring the texture every other pass, basically going left-to-right-to-left-etc. as the polygon is rendered.