I have a class named Ball (for pong project) and I need to pass the Texture2D through the Main Constructor as so:
Ball.cs
public class Ball
{
Texture2D _ballSprite;
private float _ballSpeed;
private Vector2 _ballMovement;
private Vector2 _ballPosition;
private const int WINDOW_WIDTH = 800;
private const int WINDOW_HEIGHT = 600;
public Ball(Texture2D sprite)
{
_ballSprite = sprite;
}
and then in the Main
Game1.cs
Ball ball = new Ball();
What should I pass though the parameters in Main to have the Texture2D appear?
You shouldn't pass Texture2D in constructor. Graphic resources like Texture2D can become disposed while game is running in event of graphic device being reset. And you will need a new instances of all Texture2D objects each time that happens.
Therefore in XNA all content loading of graphical resources should be done inside LoadContent() method. Your Game class overrides LoadContent() method. There you can load your texture like this: byBall.BallSprite = Content.Load<Texture2D>("balltexture"); (you need to make BallSprite property public in that case)
Or you could create a method for loading inside Ball class
public void LoadContent(Content content)
{
_ballSprite = content.Load<Texture2D>("balltexture");
}
and then call myBall.LoadContent(Content) from overriden Game class LoadContent() method.
Note that that Content object is ContentManager and will in case you load same texture multiple times, load that texture in memory only once (first time load is called). For all subsequent calls same Texture2D instance will be returned.
Game.LoadContent() method is called by XNA before first update and each time graphic device is reset (that can happen for number of reasons at any time). So you need to be careful what you do inside LoadContent() method. If you would for instance try to create Ball class instance inside LoadContent(), that ball instance could be replaced by new ball instance at any time mid game and _ballSpeed, _ballMovement, _ballPosition values would be lost.
Related
I am creating a simple game that need to capture a photo from the webcam every time the user click on some object. To avoid lag issues because of the task of convert the Texture2D to PNG and write the image on the disk, I am trying to store one List of Texture2D from the captures, and after the game ends, write all on the disk.
The problem is, when I capture one Texture2D texture from the webcam and try to do a List.Add(texture), all the elements of the list are updated because it store the reference of texture, not the Texture itself. Can anyone please, suggest me one alternative to store all the textures?
Edit: inserting code.
public class GetPhoto : MonoBehaviour
{
WebCamTexture webcam;
Texture2D photo;
List<Texture2D> photos;
IEnumerator TakePhoto()
{
//run when user click on object.
yield return new WaitForEndOfFrame();
photo.SetPixels(webcam.GetPixels());
photo.Apply();
photos.Add(photo);
}
}
As said rather use a new Texture2D instance for every press like e.g.
IEnumerator TakePhoto()
{
//run when user click on object.
yield return new WaitForEndOfFrame();
var photo = new Texture2D(yourTextureWidth, yourTextureHeight);
photo.SetPixels(webcam.GetPixels());
photo.Apply();
photos.Add(photo);
}
otherwise every entry in your list refers to the exact same Texture2D instance => everytime you overwrite the content of that instance.
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.
}
My scene has basic game objects (camera, canvas with two child image and button).
I make a prefab of a button, now the prefab is on the project view, I want to instantiate this prefab button from within the script, and I want it to be drawn inside the canvas.
For that, I make a script file, attach it to the canvas as a script component. Here is my script implementation:
using UnityEngine;
public class QuizManager : MonoBehaviour {
public Transform suggestionBtn;
// Use this for initialization
void Start () {
Instantiate (suggestionBtn, new Vector3 (100, 400, 0), Quaternion.identity);
}
// Update is called once per frame
void Update () {
}
}
Of course, the suggestionBtn is the prefab, that's why I make a reference of it to the script variable (drag the prefab from the project view to the script component).
Now when I run the game, I noticed the clone of the prefab is added above all game objects in the hierarchy view (I am expecting to get it added inside the canvas):
And also it has wrong dimension (very very small, it is barely visible), here how it looks after I zoom it in
So my question is how can I instantiate the prefab correctly with its normal size and position it correctly relatively to the canvas (child of the canvas) ?
Thanks
You can correctly initialize the transform (under correct game object hierarchy) by assigning the instance to a variable and then changing its parent.
public class QuizManager : MonoBehaviour {
public Transform suggestionBtn;
// Use this for initialization
void Start () {
Transform clone = (Transform)Instantiate (suggestionBtn,
new Vector3 (100, 400, 0), Quaternion.identity);
// make instance the child of current object
clone.parent = gameObject.transform;
// adjust the scale
clone.transform.localScale = new Vector3(Xval, Yval, Zval);
}
}
You can change the localScale from the assigned clone variable after instantiation.
From your screenshot of the hierarchy view at runtime, your instantiated button is not nested under the Canvas, therefore it will not be rendered by the Canvas Renderer.
When you instantiate it, you need to set the transform.parent to the canvas gameobject's transform.
var newButton = Instantiate (suggestionBtn, new Vector3 (100, 400, 0), Quaternion.identity) as GameObject;
newButton.transform.parent = GameObject.Find("Canvas").transform;
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.
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();