I am trying to set up a health bar for a 2D game using OnGUI. I have an outside texture and an inside texture for the meter. The set up I have now works partially. I am able to change the scale of the inside meter so it looks like it is depleting, however the position along the x is changing as well. This causes an awkward effect as well as the meter moving outside its container.
void Update ()
{
score = EnemyScript.killCount * 100;
powerScale -= 1;
}
void OnGUI()
{
//Score and Power Containter
GUILayout.BeginArea(new Rect(Screen.width/8, Screen.height/8, 500, 200));
GUILayout.Label("Score: " + score, style);
GUI.DrawTexture(new Rect(-10,20,200,80),powerBoundry);
GUILayout.EndArea();
//Power Meter
GUILayout.BeginArea(new Rect(Screen.width/8, Screen.height/8, 450, 200));
GUI.DrawTexture(new Rect(-10,20,powerScale,80),powerFill, ScaleMode.ScaleAndCrop);
GUILayout.EndArea();
}
Is it possible to anchor it in place? Or perhaps make it a child of a game object to anchor it?
try using DrawTextureWithTexCoords.
void OnGUI()
{
GUILayout.BeginArea(new Rect(Screen.width / 8, Screen.height / 8, 500, 200));
GUI.DrawTexture(new Rect(-10, 20, 200, 80), powerBoundry);
GUI.DrawTextureWithTexCoords(new Rect(-10, 20, powerScale, 80), powerFill, new Rect(0f, 0f, (float)powerScale / 200f, 1f));
GUILayout.EndArea();
}
Related
Solved
I'm working with monogame to make a basic 2D platformer. So far haven't had many problems, drawing the entire spritesheet was no problem.
I wanted to add the running animation, knowing each sprite is 41 pixels wide and 54 pixels high I passed a source rectangle of those dimensions with the correct position to the draw function. For some reason it now does not draw anything anymore.
This is my original Draw function that did work:
public virtual void Draw()
{
if(sprite != null)
{
Globals.spriteBatch.Draw(sprite, new Rectangle((int)pos.X, (int)pos.Y, (int)dims.X, (int)dims.Y), null, Color.White, 0.0f, new Vector2(sprite.Bounds.Width / 2, sprite.Bounds.Height / 2), SpriteEffects.None, 0);
}
}
And this is the one with a source rectangle that doesn't work:
public virtual void Draw(Rectangle frame)
{
if (sprite != null)
{
Globals.spriteBatch.Draw(sprite, new Rectangle((int)pos.X, (int)pos.Y, (int)dims.X, (int)dims.Y), frame, Color.White, 0.0f, new Vector2(sprite.Bounds.Width / 2, sprite.Bounds.Height / 2), SpriteEffects.None, 0);
}
}
It's called by a overwritten draw function in the player class:
public override void Draw()
{
base.Draw(new Rectangle(frame * 41, 0, 41, 54));
}
The frame variable is updated each frame with this formula:
frame = (frame + 1) % 4;
I had forgotten to update the dimensions of the rectangle. It had nothing to do with the source rectangle itself.
This question got marked as duplicate as it involves creating dynamically named variables.
But the thing that I'm after is to create a number of dynamic sliders, so those .net answers aren't helping me.
The sliders are the same physical size and their names are held within an array, and their number is known. However, it could be one it could be twent, hence the need for dynamic slider creation.
This doesn't work:
for (int i = 0; i < numOfCheeseMonkeys; i++)
{
slider + i = GUI.HorizontalSlider(new Rect(25, 50 + (i * 30), 150, 25), slider + i, 0.0F, 100.0F);
}
...this will, but it's stoopid:
sliderA = GUI.HorizontalSlider(new Rect(25, 50 + (i * 30), 150, 25), sliderA, 0.0F, 100.0F);
sliderB = GUI.HorizontalSlider(new Rect(25, 50 + (i * 30), 150, 25), sliderB, 0.0F, 100.0F);
Use an array or some kind of collection. It would look something like this:
Slider[] sliders = new Slider[numOfCheeseMonkeys];
for (int i =0; i < numOfCheeseMonkeys; i++)
{
sliders[i] = GUI.HorizontalSlider(new Rect(25, 50+(i*30), 150, 25), slider[i], 0.0F, 100.0F); // yeah, this doesn't work
}
I currently have an asteroid texture loaded as my "test player" for the game I'm writing. What I'm trying to figure out how to do is get a triangle to shoot from the center of the asteroid, and keep going until it hits the top of the screen. What happens in my case (as you'll see from the code I've posted), is that the triangle will show, however it will either be a long line, or it will just be a single triangle which stays in the same location as the asteroid moving around (that disappears when I stop pressing the space bar), or it simply won't appear at all. I've tried many different methods, but I could use a formula here.
All I'm trying to do is write a space invaders clone for my final in C#. I know how to code fairly well, my formulas just need work is all.
So far, this is what I have:
Main Logic Code
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(ClearOptions.Target, Color.Black, 1, 1);
mAsteroid.Draw(mSpriteBatch);
if (mIsFired)
{
mPositions.Add(mAsteroid.LastPosition);
mRay.Fire(mPositions);
mIsFired = false;
mRay.Bullets.Clear();
mPositions.Clear();
}
base.Draw(gameTime);
}
Draw Code
public void Draw()
{
VertexPositionColor[] vertices = new VertexPositionColor[3];
int stopDrawing = mGraphicsDevice.Viewport.Width / mGraphicsDevice.Viewport.Height;
for (int i = 0; i < mRayPos.Length(); ++i)
{
vertices[0].Position = new Vector3(mRayPos.X, mRayPos.Y + 5f, 10);
vertices[0].Color = Color.Blue;
vertices[1].Position = new Vector3(mRayPos.X - 5f, mRayPos.Y - 5f, 10);
vertices[1].Color = Color.White;
vertices[2].Position = new Vector3(mRayPos.X + 5f, mRayPos.Y - 5f, 10);
vertices[2].Color = Color.Red;
mShader.CurrentTechnique.Passes[0].Apply();
mGraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.TriangleStrip, vertices, 0, 1);
mRayPos += new Vector2(0, 1f);
mGraphicsDevice.ReferenceStencil = 1;
}
}
This isn't quite how you're supposed to be manipulating the location of a model in world space and since you're creating a new vertex array every single draw frame you'll find that it performs pretty badly when you come to draw more than a few triangles.
declare the vertices and index list for your triangle just once in the LoadContent method.
VertexBuffer triangleVertexBuffer;
IndexBuffer triangleIndexBuffer;
protected override void LoadContent()
{
// Setup a basic effect to draw the triangles with.
mEffect = new BasicEffect(GraphicsDevice);
// setup the triangle vertext buffer and load up it's content.
triangleVertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), 3, BufferUsage.WriteOnly);
triangleVertexBuffer.SetData<VertexPositionColor>(new VertexPositionColor[]
{
new VertexPositionColor (new Vector3 (0f, -1f, 0.0f), Color.Blue), // Top Point
new VertexPositionColor (new Vector3 (-1f, 1f, 0.0f), Color.White), // Bottom Left
new VertexPositionColor (new Vector3 (1f, 1f, 0.0f), Color.Red), // Bottom Right
});
// setup an index buffer to join the dots!
triangleIndexBuffer = new IndexBuffer(GraphicsDevice, IndexElementSize.SixteenBits, 3, BufferUsage.WriteOnly);
triangleIndexBuffer.SetData<short>(new short[]
{
0,
1,
2,
});
}
After this assuming your effect takes in to account a world transformation (basic effect does) you can use that parameter to move the triangle.
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.CornflowerBlue);
for (int i = 0; i < mRayPos.Length ; i++)
{
// This is the line that moves the triangle along your ray.
mEffect.World = Matrix.CreateTranslation(new Vector3(mRayPos[i].X, mRayPos[i].Y, mRayPos[i].Z));
mEffect.Techniques[0].Passes[0].Apply();
// These lines tell the graphics card that you want to draw your triangle.
GraphicsDevice.SetVertexBuffer(triangleVertexBuffer);
GraphicsDevice.Indices = triangleIndexBuffer;
GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, 3, 0, 1);
}
base.Draw(gameTime);
}
If you use this method it becomes a very simple operation to rotate or scale your trangle using Matrix.CreateRotation and Matrix.CreateScale.
I have a controllable character that when you fall off map, a GUI will be created with a respawn button
void OnGUI() {
if(died==true){
GUI.Label(new Rect(daX, daY, 200, 40), "You died!!");
GUI.Label(new Rect(daX, daY-40, 200, 40), whyDie);
if (GUI.Button(new Rect(daX-75, daY+50, 150, 30), "Respawn!!!")){
transform.position = new Vector3(-5,20,5);
}
if (GUI.Button(new Rect(daX-75, daY+100, 150, 30), "Screw This!!!")){
Debug.Log("Back to menu");
}
}
}
The respawn and stuff works, is just that I don't know how to get rid of the GUI, so the respawn button stays there after you respawned. Does anyone know how to remove GUI objects? Thanks in advance
*EDIT: died, daX, daY, whyDie are variables I created and are valid
Just set your died variable back to false, and the GUI calls wont be made.
void OnGUI()
{
if(died)
{
GUI.Label(new Rect(daX, daY, 200, 40), "You died!!");
GUI.Label(new Rect(daX, daY-40, 200, 40), whyDie);
if (GUI.Button(new Rect(daX-75, daY+50, 150, 30), "Respawn!!!"))
{
transform.position = new Vector3(-5,20,5);
died = false; //Stop drawing died interface
}
if (GUI.Button(new Rect(daX-75, daY+100, 150, 30), "Screw This!!!"))
{
Debug.Log("Back to menu");
Application.LoadLevel(0); //Load your first scene, where the menu is.
}
}
}
Alternatively, you could disable the component/gameobject. That way your whole OnGUI method wont be called anymore.
I was wondering how to approach creating a HUD.
I currently have health, mana, and experience bar drawn to the screen at set coordinates. Downside of this is that when the camera pans the bars stay at their set coordinates, I want them to adjust to the viewport or not be influenced by positions but just simply drawn to the screen.
Edit
I managed to get the HUD to adjust using the camera's x and y coordinates.
I've created a separate class for drawing the HUD, but now they don't adjust.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using GameOne.Components;
namespace GameOne.GameScreens
{
public class HUD : BaseGameState
{
Player player;
Texture2D HealthBar;
Texture2D HealthBarPositive;
Texture2D HealthBarNegative;
Texture2D ManaBar;
Texture2D ManaBarPositive;
Texture2D ManaBarNegative;
Texture2D ExpBar;
Texture2D ExpBarPositive;
int CurrentHealth = 100;
int CurrentMana = 45;
int CurrentExp = 0;
public HUD(Game game, GameStateManager manager)
: base(game, manager)
{
player = new Player(game);
}
public void LoadContent()
{
base.LoadContent();
HealthBar = Game.Content.Load<Texture2D>(#"GUI\healthBar");
HealthBarPositive = Game.Content.Load<Texture2D>(#"GUI\healthBarPositive");
HealthBarNegative = Game.Content.Load<Texture2D>(#"GUI\healthBarNegative");
ManaBar = Game.Content.Load<Texture2D>(#"GUI\manaBar");
ManaBarPositive = Game.Content.Load<Texture2D>(#"GUI\manaBarPositive");
ManaBarNegative = Game.Content.Load<Texture2D>(#"GUI\manaBarNegative");
ExpBar = Game.Content.Load<Texture2D>(#"GUI\expBar");
ExpBarPositive = Game.Content.Load<Texture2D>(#"GUI\expBarPositive");
}
public void Update(GameTime gameTime)
{
if (InputHandler.KeyDown(Keys.F1))
{
CurrentHealth += 1;
}
if (InputHandler.KeyDown(Keys.F2))
{
CurrentHealth -= 1;
}
if (InputHandler.KeyDown(Keys.F3))
{
CurrentMana += 1;
}
if (InputHandler.KeyDown(Keys.F4))
{
CurrentMana -= 1;
}
if (InputHandler.KeyDown(Keys.F5))
{
CurrentExp += 1;
}
if (InputHandler.KeyDown(Keys.F6))
{
CurrentExp -= 1;
}
CurrentHealth = (int)MathHelper.Clamp(CurrentHealth, 0, 100);
CurrentMana = (int)MathHelper.Clamp(CurrentMana, 0, 45);
CurrentExp = (int)MathHelper.Clamp(CurrentExp, 0, 500);
}
public void Draw(GameTime gameTime)
{
GameRef.SpriteBatch.Draw(
HealthBarNegative,
new Rectangle((int)player.Camera.Position.X + 150, (int)player.Camera.Position.Y + 630, 150, 15),
Color.White);
GameRef.SpriteBatch.Draw(
HealthBarPositive,
new Rectangle((int)player.Camera.Position.X + 150, (int)player.Camera.Position.Y + 630, 150 * (int)CurrentHealth / 100, 15),
Color.White);
GameRef.SpriteBatch.Draw(
HealthBar,
new Rectangle((int)player.Camera.Position.X + 150, (int)player.Camera.Position.Y + 630, 150, 15),
Color.White);
GameRef.SpriteBatch.Draw(
ManaBarNegative,
new Rectangle((int)player.Camera.Position.X + 150, (int)player.Camera.Position.Y + 650, 150, 15),
Color.White);
GameRef.SpriteBatch.Draw(
ManaBarPositive,
new Rectangle((int)player.Camera.Position.X + 150, (int)player.Camera.Position.Y + 650, 150 * (int)CurrentMana / 45, 15),
Color.White);
GameRef.SpriteBatch.Draw(
ManaBar,
new Rectangle((int)player.Camera.Position.X + 150, (int)player.Camera.Position.Y + 650, 150, 15),
Color.White);
GameRef.SpriteBatch.Draw(
ExpBarPositive,
new Rectangle((int)player.Camera.Position.X + 10, (int)player.Camera.Position.Y + 680, 1260 * (int)CurrentExp / 500, 15),
Color.White);
GameRef.SpriteBatch.Draw(
ExpBar,
new Rectangle((int)player.Camera.Position.X + 10, (int)player.Camera.Position.Y + 680, 1260, 15),
Color.White);
}
}
}
When you are drawing your Health bars, is it inside a Spritebatch.Begin( ... ) where you specify your camera matrix?
If you draw it in its own Spritebatch.Begin, without the camera, the position of the health bars will stay relative to the screen.
When you extend you class with DrawableGameComponent, you can use the property DrawOrder to set it topmost.
The class will be a bit different, you have to overload Update, draw and LoadContent, but it will be all the same.
This is only usefull if you use a HUD with SpriteBatch.