Detect collision with Sprite-Sheet animation - c#

How detect collision with sprite animation?
SpriteManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using System.IO;
namespace Mini
{
public class SpriteManager
{
protected Texture2D Texture;
public Vector2 Position = Vector2.Zero;
protected Dictionary<string, AnimationClass> Animations =
new Dictionary<string, AnimationClass>();
protected int FrameIndex = 0;
protected Vector2 Origin;
private int height;
private int width;
private string animation;
public string Animation
{
get { return animation; }
set
{
animation = value;
FrameIndex = 0;
}
}
public int Height
{
get { return height; }
}
public int Width
{
get { return width; }
}
public Rectangle Rectangle
{
get { return Animations[Animation].Rectangles[FrameIndex]; }
}
public Texture2D Texture2D
{
get { return Texture; }
}
public SpriteManager(Texture2D Texture, int Frames, int animations)
{
this.Texture = Texture;
width = Texture.Width / Frames;
height = Texture.Height / animations;
Origin = new Vector2(width / 2, height / 2);
}
public void AddAnimation(string name, int row,
int frames, AnimationClass animation)
{
Rectangle[] recs = new Rectangle[frames];
Color[][] frameImageData = new Color[frames][];
Texture2D[][] frameImage = new Texture2D[frames][];
for (int i = 0; i < frames; i++)
{
recs[i] = new Rectangle(i * width,
(row - 1) * height, width, height);
frameImageData[i] = new Color[width * height];
}
animation.Frames = frames;
animation.Rectangles = recs;
Animations.Add(name, animation);
}
public void Draw(SpriteBatch spriteBatch)
{
spriteBatch.Draw(Texture, Position,
Animations[Animation].Rectangles[FrameIndex],
Animations[Animation].Color,
Animations[Animation].Rotation, Origin,
Animations[Animation].Scale,
Animations[Animation].SpriteEffect, 0f);
}
public bool IntersectPixels(SpriteManager b)
{
Rectangle rectangleA = this.Rectangle;
Rectangle rectangleB = b.Rectangle;
int top = Math.Max(rectangleA.Top, rectangleB.Top);
int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
int left = Math.Max(rectangleA.Left, rectangleB.Left);
int right = Math.Min(rectangleA.Right, rectangleB.Right);
Color[] dataA = new Color[rectangleA.Width * rectangleA.Height];
this.Texture.GetData(0, rectangleA, dataA, 0, rectangleA.Width * rectangleA.Height);
Color[] dataB = new Color[rectangleB.Width * rectangleB.Height];
b.Texture.GetData(0, rectangleB, dataB, 0, b.Width * b.Height);
Stream s = File.Create("t.png");
b.Texture2D.SaveAsPng(s, rectangleB.Width, rectangleB.Height);
for (int y = top; y < bottom; y++)
{
for (int x = left; x < right; x++)
{
Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];
if (colorA.A != 0 && colorB.A != 0)
{
return true;
}
}
}
return false;
}
}
}
With this code, the collision is detected every few frames of animation anywhere
IntersectPixels is to detect collisions.

Related

Unity Trying to make a chess game but error messages really annoys me

Codes below:
using System;
using UnityEngine;
using UnityEngine.Serialization;
public class Chessboard : MonoBehaviour
{
[Header("Art")]
[SerializeField] private Material tileMaterial;
//Logic
private const int TILE_COUNT_X = 8;
private const int TILE_COUNT_Y = 8;
private GameObject[,] tiles;
private Camera currentCamera;
private Vector2Int currentHover = -Vector2Int.one;
private void Awake()
{
GenerateAllTiles(1, TILE_COUNT_X, TILE_COUNT_Y);
}
private void Update()
{
if (!currentCamera)
{
currentCamera = Camera.current;
return;
}
RaycastHit info;
Ray ray = currentCamera.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out info, 100, LayerMask.GetMask("Tile")))
{
// get the indexes of Tile i've hit
Vector2Int hitPosition = LookupTileIndex(info.transform.gameObject);
//If we are hovering a tile after not hovering any
if (currentHover == -Vector2Int.one)
{
tiles[hitPosition.x, hitPosition.y].layer = LayerMask.NameToLayer("Hover");
currentHover = hitPosition;
}
//If we were already hovering a tile, change the previous one
else if (currentHover != hitPosition)
{
tiles[currentHover.x, currentHover.y].layer = LayerMask.NameToLayer("Tile");
currentHover = hitPosition;
tiles[hitPosition.x, hitPosition.y].layer = LayerMask.NameToLayer("Hover");
}
}
else
{
if (currentHover != -Vector2Int.one)
{
tiles[currentHover.x, currentHover.y].layer = LayerMask.NameToLayer("Tile");
currentHover = -Vector2Int.one;
}
}
}
//Generate the board (useful)
private void GenerateAllTiles(float tileSize, int tileCountX, int tileCountY)
{
tiles = new GameObject[tileCountX, tileCountY];
for (int x = 0; x < tileCountX; x++)
for (int y = 0; y < tileCountY; y++)
tiles[x, y] = generate1tile(tileSize, x, y);
}
private GameObject generate1tile(float tileSize, int x, int y)
{
GameObject tileObject = new GameObject(string.Format("Tile X:{0}, Y:{1}", x, y));
tileObject.transform.parent = transform;
Mesh mesh = new Mesh();
tileObject.AddComponent<MeshFilter>().mesh = mesh;
tileObject.AddComponent<MeshRenderer>().material = tileMaterial;
Vector3[] vertices = new Vector3[4];
vertices[0] = new Vector3(x * tileSize, 0, y * tileSize);
vertices[1] = new Vector3(x * tileSize, 0, (y + 1) * tileSize);
vertices[2] = new Vector3((x + 1) * tileSize, 0, y * tileSize);
vertices[3] = new Vector3((x + 1) * tileSize, 0, (y + 1) * tileSize);
int[] tris = new int[]{0, 2, 1, 1, 2, 3};
mesh.vertices = vertices;
mesh.triangles = tris;
mesh.RecalculateNormals();
tileObject.layer = LayerMask.NameToLayer("Tile");
tileObject.AddComponent<BoxCollider>();
return tileObject;
}
private Vector2Int LookupTileIndex(GameObject hitInfo)
{
for(int x = 0; x < TILE_COUNT_X; x++)
for(int y = 0; y < TILE_COUNT_Y; y++)
if(tiles[x, y] == hitInfo)
return new Vector2Int(x, y);
return new Vector2Int(-1, -1); //Invalid
}
}
Error Message:
A game object can only be in one layer. The layer needs to be in the range [0...31]
UnityEngine.StackTraceUtility:ExtractStackTrace ()
Chessboard:generate1tile (single,int,int) (at Assets/scripts/Chessboard.cs:93)
Chessboard:GenerateAllTiles (single,int,int) (at Assets/scripts/Chessboard.cs:68)
Chessboard:Awake () (at Assets/scripts/Chessboard.cs:20)
I just get into Unity, so I might be missed some parts of it.
I tired using AI to config my problem, but it doesn't work. I am expecting i put my mouse on a tile, the tile change its color.
Here is the link to the tutorial I watched: https://www.youtube.com/watch?v=FtGy7J8XD90&list=PLmcbjnHce7SeAUFouc3X9zqXxiPbCz8Zp&index=2&ab_channel=Epitome

Is there is a way to block mouse hover events outside current focused Editor window rect in Unity Editor?

I am working on custom enum popup with search and facing next problem. When clicking button to show popup list of enums I can hover over that list and select items inside, but also I can as always move mouse outside popup rect and move around. And when I hover over other GUI element it reacts to that movement (hover highlight or so happens). I remembered that default Unity's enum don't have this feature and it blocks all events outside popup's rect exclude outside mouse click to close this popup.
So... My question is: How can I implement this feature in my popup window? I look into Unity's source code and don't find anything related to this. Except one moment when they are using internal function "GUI.GrabMouseControl(id);"
There are this internal function for enum button where they block mouse control somehow:
// A button that returns true on mouse down - like a popup button
internal static bool DropdownButton(int id, Rect position, GUIContent content, GUIStyle style)
{
Event evt = Event.current;
switch (evt.type)
{
case EventType.Repaint:
var hovered = position.Contains(Event.current.mousePosition);
if (showMixedValue)
{
BeginHandleMixedValueContentColor();
style.Draw(position, s_MixedValueContent, id, false, hovered);
EndHandleMixedValueContentColor();
}
else
style.Draw(position, content, id, false, hovered);
break;
case EventType.MouseDown:
if (GUIUtility.HitTest(position, evt) && evt.button == 0)
{
GUI.GrabMouseControl(id);
Event.current.Use();
return true;
}
break;
case EventType.MouseUp:
if (GUI.HasMouseControl(id))
{
GUI.ReleaseMouseControl();
Event.current.Use();
}
break;
case EventType.KeyDown:
if (GUIUtility.keyboardControl == id && evt.character == ' ')
{
Event.current.Use();
return true;
}
break;
}
return false;
}
I think that may be that magic thing to block mouse hovering. Also I think that GUIUtility.hotControll is second canditate to solve my issue. But I dont know how properly use it in my OnGUI() method. I am trying to it and get not correct result,
but I blocked hovering outside popup's rect. But it always spam console with these logs:
Should not grab hot control with an active capture. So I dropped this idea with my implementation, cause of these logs...
There are my code of popup window content:
using System;
using UnityEditor;
using UnityEngine;
public class SearchablePopup : PopupWindowContent
{
#region Popup Properties
private const float SymbolVerticalOffset = 0.75f;
private const int ClearButtonSize = 12;
private const string SearchControl = "searchablePopup_ctrl";
#endregion
public static void Show(Rect from, Type type, int current,
Action<int> onSelectionMade, int elementsToShow, int elementHeight,
int searchHeight, Texture backgroundTexture,
GUIStyle searchStyle, GUIStyle clearButtonStyle, GUIStyle elementStyle,
Color hover, Color selected, Color marker)
{
if (type.IsEnum is false) return;
var window = new SearchablePopup(type, current, onSelectionMade,
(int)from.width, elementsToShow, elementHeight, searchHeight,
backgroundTexture, searchStyle, clearButtonStyle, elementStyle,
hover, selected, marker);
PopupWindow.Show(from, window);
}
private readonly FilteredList _filteredList;
private readonly Action<int> _onSelectionMade;
private readonly int _width;
private readonly int _elementsToShow;
private readonly int _rowHeight;
private readonly int _searchHeight;
private readonly float _clearButtonPadding;
private readonly bool _clearButtonValid;
private readonly GUIStyle _searchStyle;
private readonly GUIStyle _searchTooltipStyle;
private readonly GUIStyle _clearButtonStyle;
private readonly GUIStyle _elementStyle;
private readonly Texture _backgroundTexture;
private readonly Texture _hoverTexture;
private readonly Texture _selectedTexture;
private readonly Texture _selectedCircleTexture;
private int _current;
private int _hover;
private int _keyboardIndex;
private int _scroll;
private int _controlHash = "SearchablePopup".GetHashCode();
private Vector2 _scrollPosition;
private Vector2 _clickPosition;
private bool _clickedThisFrame;
public SearchablePopup(Type enumType, int current, Action<int> onSelectionMade,
int width, int elementsToShow, int rowHeight, int searchHeight, Texture backgroundTexture,
GUIStyle searchStyle, GUIStyle clearButtonStyle, GUIStyle elementStyle,
Color hover, Color selected, Color marker)
{
_filteredList = new FilteredList(enumType, current);
_hoverTexture = SmallTexture(hover);
_selectedTexture = SmallTexture(selected);
_selectedCircleTexture = DrawCircle(4, marker);
_current = current;
_hover = _current;
_scroll = _current;
_keyboardIndex = _filteredList.CurrentIndex;
_onSelectionMade = onSelectionMade;
_elementsToShow = elementsToShow;
_width = width;
_rowHeight = rowHeight;
_searchHeight = searchHeight;
_backgroundTexture = backgroundTexture;
_searchStyle = searchStyle;
_clearButtonValid = clearButtonStyle != null;
_clearButtonStyle = clearButtonStyle;
_clearButtonPadding = _clearButtonValid ? clearButtonStyle.padding.left : 4;
_elementStyle = elementStyle;
if (_clearButtonValid is false)
{
_elementStyle = new GUIStyle(_elementStyle);
_elementStyle.alignment = TextAnchor.MiddleLeft;
}
_searchTooltipStyle = new GUIStyle(_searchStyle);
_searchTooltipStyle.normal.textColor *= 0.75f;
_searchTooltipStyle.hover.textColor = _searchTooltipStyle.normal.textColor;
_searchTooltipStyle.fontSize = (int)(_searchTooltipStyle.fontSize * 0.75f);
}
public override Vector2 GetWindowSize()
{
float height = Mathf.Min(
_filteredList.Entries.Count, _elementsToShow) * _rowHeight
+ _searchHeight;
//Strange hot-fix for Unity's Scrollview:
//We are increasing total height of our window's rect
//to be a litte bigger than actual content because
//if Scrollview's height >= Window's height than scrollbar is displayed
//what we don't want to see if our current count of entires is less than show amount
if (_filteredList.Entries.Count < _elementsToShow)
height += 0.25f;
return new Vector2(_width, height);
}
public override void OnOpen()
{
base.OnOpen();
EditorApplication.update += Repaint;
}
public override void OnClose()
{
base.OnClose();
EditorApplication.update -= Repaint;
}
private void Repaint()
{
EditorWindow.focusedWindow.Repaint();
}
public override void OnGUI(Rect rect)
{
GUI.DrawTexture(rect, _backgroundTexture);
if (Event.current.type == EventType.MouseDown)
{
_clickedThisFrame = true;
_clickPosition = Event.current.mousePosition;
}
Rect search = new Rect(0, 0, rect.width, _searchHeight);
Rect clear = Rect.MinMaxRect(search.xMax - ClearButtonSize - _clearButtonPadding,
search.center.y - ClearButtonSize * 0.5f, rect.xMax - _clearButtonPadding,
search.center.y + ClearButtonSize * 0.5f);
Rect scroll = Rect.MinMaxRect(0, search.yMax, rect.xMax, rect.yMax);
HandleKeyboardInput();
DrawSearch(search, clear);
DrawScroll(scroll);
_clickedThisFrame = false;
}
private void DrawSearch(Rect search, Rect clear)
{
GUI.FocusControl(SearchControl);
GUI.SetNextControlName(SearchControl);
var filter = TextfieldWithTooltip(search, _filteredList.Filter,
"Type to search...", _searchStyle, _searchTooltipStyle);
if (_filteredList.Refresh(filter))
{
_scrollPosition = Vector2.zero;
}
if (string.IsNullOrEmpty(_filteredList.Filter) is false)
{
if (_clearButtonValid)
{
GUI.Box(clear, GUIContent.none, _clearButtonStyle);
}
else
{
GUI.Box(clear, "x", GUI.skin.label);
}
if (_clickedThisFrame && clear.Contains(_clickPosition))
{
_filteredList.Refresh("");
_scrollPosition = Vector2.zero;
}
}
}
private void DrawScroll(Rect scroll)
{
Rect contentRect = new Rect(0, 0,
scroll.width - GUI.skin.verticalScrollbar.fixedWidth,
_filteredList.Entries.Count * _rowHeight);
_scrollPosition = GUI.BeginScrollView(scroll, _scrollPosition, contentRect);
Rect element = new Rect(0, 0, scroll.width, _rowHeight);
var eventType = Event.current.type;
for (int i = 0; i < _filteredList.Entries.Count; i++)
{
if (_scroll == _filteredList.Entries[i].Value && (eventType == EventType.Repaint || eventType == EventType.Layout))
{
GUI.ScrollTo(element);
_scrollPosition.x = 0;
_scroll = -1;
}
if (element.Contains(Event.current.mousePosition))
{
if (Event.current.type == EventType.MouseMove ||
Event.current.type == EventType.ScrollWheel)
{
_hover = _filteredList.Entries[i].Value;
_keyboardIndex = i;
}
if (Event.current.type == EventType.MouseDown)
{
_onSelectionMade(_filteredList.Entries[i].Value);
EditorWindow.focusedWindow.Close();
}
}
DrawElement(element, _filteredList.Entries[i].Value, i);
element.y = element.yMax;
}
GUI.EndScrollView();
}
private void DrawElement(Rect rect, int value, int index)
{
if (value == _current)
{
DrawBox(rect, _selectedTexture, _selectedCircleTexture);
rect.xMin += _selectedCircleTexture.width * 2f;
}
else if (value == _hover)
{
DrawBox(rect, _hoverTexture);
}
GUI.Label(rect, _filteredList.Entries[index].Content, _elementStyle);
}
private void DrawBox(Rect rect, Texture texture, Texture symbol = null)
{
GUI.DrawTexture(rect, texture);
if (symbol == null) return;
rect.xMin += symbol.width * 0.5f;
rect.y = rect.center.y - symbol.height * 0.5f + SymbolVerticalOffset;
rect.width = symbol.width;
rect.height = symbol.height;
GUI.DrawTexture(rect, symbol);
}
private void HandleKeyboardInput()
{
if (Event.current.isKey is false || Event.current.type != EventType.KeyDown) return;
var keyCode = Event.current.keyCode;
if (keyCode == KeyCode.Escape)
{
EditorWindow.focusedWindow.Close();
return;
}
if (keyCode == KeyCode.Return)
{
_onSelectionMade(_filteredList.Entries[_keyboardIndex].Value);
EditorWindow.focusedWindow.Close();
return;
}
if (keyCode == KeyCode.DownArrow)
{
_keyboardIndex = Mathf.Min(_filteredList.Entries.Count - 1, _keyboardIndex + 1);
_hover = _filteredList.Entries[_keyboardIndex].Value;
Event.current.Use();
_scroll = _hover;
}
else if (keyCode == KeyCode.UpArrow)
{
_keyboardIndex = Mathf.Max(0, _keyboardIndex - 1);
_hover = _filteredList.Entries[_keyboardIndex].Value;
GUIUtility.hotControl = 0;
Event.current.Use();
_scroll = _hover;
}
}
#region Helpers
public static Rect Shrink(Rect rect, float amount)
{
return new Rect(rect.x + amount, rect.y + amount, rect.width - amount * 2, rect.height - amount * 2);
}
public static Texture SmallTexture(string hex)
{
Texture2D texture = new Texture2D(4, 4);
var color = HexToRGB(hex);
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
texture.SetPixel(i, j, color);
}
}
texture.Apply();
return texture;
}
public static Texture SmallTexture(Color color)
{
Texture2D texture = new Texture2D(4, 4);
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
texture.SetPixel(i, j, color);
}
}
texture.Apply();
return texture;
}
public static Texture DrawCircle(int radius, string hex)
{
Texture2D texture = new Texture2D(radius * 2, radius * 2);
var color = HexToRGB(hex);
float cX = radius;
float cY = radius;
float sizeSquared = radius * radius;
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
if ((cX - i) * (cX - i) + (cY - j) * (cY - j) < sizeSquared)
{
texture.SetPixel(i, j, color);
}
else texture.SetPixel(i, j, Color.clear);
}
}
texture.Apply();
return texture;
}
public static Texture DrawCircle(int radius, Color color)
{
Texture2D texture = new Texture2D(radius * 2, radius * 2);
float cX = radius;
float cY = radius;
float sizeSquared = radius * radius;
for (int i = 0; i < texture.width; i++)
{
for (int j = 0; j < texture.height; j++)
{
if ((cX - i) * (cX - i) + (cY - j) * (cY - j) < sizeSquared)
{
texture.SetPixel(i, j, color);
}
else texture.SetPixel(i, j, Color.clear);
}
}
texture.Apply();
return texture;
}
public static Color HexToRGB(string hex)
{
hex = hex.TrimStart('#');
if (hex.Length != 6) return Color.black;
int r = Int16.Parse(hex.Substring(0, 2),
System.Globalization.NumberStyles.AllowHexSpecifier);
int g = Int16.Parse(hex.Substring(2, 2),
System.Globalization.NumberStyles.AllowHexSpecifier);
int b = Int16.Parse(hex.Substring(4, 2),
System.Globalization.NumberStyles.AllowHexSpecifier);
return new Color(r / 255f, g / 255f, b / 255f);
}
public static string TextfieldWithTooltip(Rect rect, string text, string tooltip,
GUIStyle textfieldStyle, GUIStyle tooltipStyle)
{
text = GUI.TextField(rect, text, textfieldStyle);
if (text.Length == 0)
GUI.Label(rect, tooltip, tooltipStyle);
return text;
}
#endregion
}
I will be realy glad to see some advices or straight anwsers on this problem is someone can solve it :)
Thank you!

How should I return a list that was previously set without setting it again?

I have two classes, Main and Grid. Grid simply makes a grid of square pixels. In my Main class, I want to get the list that was create in the Grid class. I managed to figure it out, but I'm wondering if there's a way to optimize the code.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Diagnostics;
using System.Collections.Generic;
namespace teeeest
{
public class Grid
{
Texture2D image;
Color color;
int rows;
int columns;
float outerThickness;
float innerThickness;
Vector2 size;
Vector2 origin;
Vector2 dotSize;
List<Pixel> pixels = new List<Pixel>(0);
public Grid(Texture2D image, int rows, int columns, float outerThickness, float innerThickness, Vector2 size, Vector2 origin, Vector2 dotSize, Color color)
{
this.dotSize = dotSize;
this.origin = origin;
this.color = color;
this.image = image;
this.rows = rows;
this.columns = columns;
this.outerThickness = outerThickness;
this.innerThickness = innerThickness;
this.size = size;
}
public void Update()
{
float sizeX = size.X / (columns - 1);
float sizeY = size.Y / (rows - 1);
for (int i = 0; i < rows; i++)
{
for (int g = 0; g < columns; g++)
{
Pixel p = new Pixel(image, 3, new Vector2((g * sizeX) + origin.X, sizeY * i + origin.Y), new Vector2(image.Width / 2, image.Height / 2), color);
pixels.Add(p);
}
}
}
public virtual void Draw(SpriteBatch hspritebatch, List<Grid> grids)
{
foreach (Pixel p in pixels)
{
hspritebatch.Draw(
texture: p.getImage(),
position: p.getPosition(),
sourceRectangle: null,
p.getColor(),
rotation: 0,
origin: new Vector2(image.Width / 2, image.Height),
scale: new Vector2(dotSize.X * .02f, dotSize.Y * .02f),
SpriteEffects.None,
0);
}
}
public Texture2D getImage()
{
return image;
}
public Vector2 getPosition()
{
return origin;
}
public Vector2 getOrigin()
{
return new Vector2(image.Width / 2, image.Height);
}
public Color getColor()
{
return color;
}
public List<Pixel> getList()
{
Update(); # This seems unnecessary. Is it?
return pixels;
}
}
}
The problem lies in the getList() function. In order to return the correct pixel list that was edited in the Update function, my solution there is to call that function right before returning the list. However, this seems costly for no reason. Is there a way around this without calling the Update function, or is this the only way?
I realize there's been posts similar to this, but I just don't understand them. I'm very much a beginner at coding. Here is my Main class.
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Graphics;
namespace teeeest
{
public class Game1 : Game
{
private GraphicsDeviceManager _graphics;
private SpriteBatch _spriteBatch;
private SpriteFont font;
private Texture2D ball;
private Texture2D square;
private Color color = Color.White * .1f;
private Vector2 MouseCoords;
private Vector2 winMiddle;
private Vector2 ballOrigin;
private bool leftDown;
private bool eDown;
private int winWidth;
private int winHeight;
List<Line> lines = new List<Line>(0);
List<Grid> grids = new List<Grid>(0);
List<Pixel> pixels = new List<Pixel>(0);
List<Pixel> test = new List<Pixel>(0);
public Game1()
{
_graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
IsMouseVisible = true;
_graphics.PreferredBackBufferWidth = 800;
_graphics.PreferredBackBufferHeight = 600;
}
protected override void Initialize()
{
base.Initialize();
}
protected override void LoadContent()
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
ball = Content.Load<Texture2D>("ball");
square = Content.Load<Texture2D>("square");
font = Content.Load<SpriteFont>("File");
ballOrigin = new Vector2(ball.Width / 2, ball.Height / 2);
winWidth = _graphics.PreferredBackBufferWidth;
winHeight = _graphics.PreferredBackBufferHeight;
winMiddle = new Vector2(winWidth / 2, winHeight / 2);
}
protected override void Update(GameTime gameTime)
{
lines.Clear();
grids.Clear();
pixels.Clear();
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();
if (Mouse.GetState().LeftButton == ButtonState.Released)
{
leftDown = false;
}
if (Mouse.GetState().LeftButton == ButtonState.Pressed && !leftDown)
{
Pixel g = new Pixel(ball, 5, MouseCoords, new Vector2(ball.Width / 2, ball.Height / 2), Color.Blue);
pixels.Add(g);
}
if (Keyboard.GetState().IsKeyUp(Keys.E))
{
eDown = false;
}
if (Keyboard.GetState().IsKeyDown(Keys.E) && !eDown)
{
color *= 1.1f;
eDown = true;
}
MouseCoords = new Vector2(Mouse.GetState().X, Mouse.GetState().Y);
Grid q = new Grid(ball, 10, 10, 7, 3, new Vector2(500, 500), new Vector2(30, 30), new Vector2(.2f, .2f), Color.White);
grids.Add(q);
# Here is where I'm calling the getList() function.
System.Console.WriteLine(q.getList()[7].getPosition());
# Here is where I'm calling the getList() function.
foreach (Line s in lines)
{
s.Update();
}
foreach (Grid gh in grids)
{
gh.Update();
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
_spriteBatch.Begin(SpriteSortMode.Immediate, BlendState.AlphaBlend);
foreach (Line l in lines)
{
l.Draw(_spriteBatch, lines);
}
foreach (Grid g in grids)
{
g.Draw(_spriteBatch, grids);
}
foreach (Pixel p in pixels)
{
_spriteBatch.Draw(
texture: p.getImage(),
position: p.getPosition(),
sourceRectangle: null,
p.getColor(),
rotation: 0,
origin: p.getOrigin(),
scale: new Vector2(.02f, .02f),
SpriteEffects.None,
0);
}
_spriteBatch.DrawString(font,
MouseCoords.ToString(),
new Vector2 (winWidth - 100, 10),
Color.White,
rotation: 0,
origin: new Vector2(0, 0),
scale: new Vector2(1, 1),
SpriteEffects.None,
0);
_spriteBatch.End();
base.Draw(gameTime);
}
}
}
You could only call Update() when the List is EMPTY?
public List<Pixel> getList()
{
if (pixels.Count == 0)
{
Update(); // now it only gets called when pixels is EMPTY
}
return pixels;
}
This type of check may need to be done in Update() as well if it can be called directly from other places so you don't end up with more Pixel instances in it than you were expecting.

Why does my automatic RPG inventory grid not work?

Here is my situation. I have four classes: Inventory.cs, InventoryTab.cs, ItemDatabase.cs, BaseItem.cs (and a few items that derive from BaseItem such as Weapon, Consumable, etc)
Inventory creates new InventoryTabs (Consumable, Weapon, Armor), and in each InventoryTab there is a list of BaseItems.
Inventory.AddItemByID(int ID, int Amount) is then called, which checks the IDs of ItemDatabase.cs, and has items pre-loaded into a list when the game is started.
Ok, now that you have basic info on how my inventory runs, here my problem:
In the InventoryTab:
int Column, Row; //Declared at the top of the class
for (int i = 0; i < ItemList.Count; i++)
{
Column++;
if (Column > gridSize.X)
{
Column = 0; Row++; //Row is not limited because my inventory will be unlimited in height
}
ItemList[i].gridLocation = new Point(column, row);
}
While I thought this would work, instead it creates one item at the top, and rapidly skips to the right, and then skips down one row, and repeats. If I add more items via a KeyboardState, it flashes a huge list of items, then disappears.
I'm certain it's because it is assigning the value of gridLocation in a loop, but then again I have no idea how I would go about it any other way.
What I need it to do is assign the gridLocation per BaseItem in ItemList only once.
EDIT:
InventoryTab.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
namespace InventoryEngine
{
public class InventoryTab
{
public List<BaseItem> ItemList = new List<BaseItem>();
int itemSize; //In Pixels
Point gridSize = new Point(5, 4);
int LocY, Column, Row;
public float Scale;
//Region Clipping
Rectangle scissorRect;
RasterizerState rState = new RasterizerState()
{
ScissorTestEnable = true
};
Vector2 gridOffset;
Texture2D slot;
SpriteFont sf;
MouseState ms;
public void LoadContent(ContentManager c, GraphicsDevice g)
{
ItemDatabase.LoadItemData(c);
slot = c.Load<Texture2D>("inventory_slot");
sf = c.Load<SpriteFont>("SpriteFont1");
Scale = 4.0f;
itemSize = 32 * (int)Scale;
gridOffset = new Vector2(g.Viewport.Width / 2 - (itemSize * gridSize.X / 2), g.Viewport.Height / 2 - (itemSize * gridSize.Y / 2));
LocY = g.Viewport.Height / 2;
}
public void Update(GameTime gt, GraphicsDevice g)
{
ms = Mouse.GetState();
LocY += ms.ScrollWheelValue / 10;
if (LocY >= g.Viewport.Height / 2 - 252)
LocY = g.Viewport.Height / 2 - 252;
for (int i = 0; i < ItemList.Count / 1; i++)
{
Column++;
if (Column > gridSize.X)
{
Column = 0; Row++;
}
ItemList[i].gridLocation = new Point(Column, Row);
}
foreach (BaseItem item in ItemList)
{
item.UpdateValues(gridSize, itemSize, gridOffset, LocY);
}
}
public void DrawTab(SpriteBatch sb, GraphicsDevice g)
{
scissorRect = new Rectangle((int)gridOffset.X, g.Viewport.Height / 2 - 256, gridSize.X * itemSize, gridSize.Y * itemSize);
sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, rState);
//g.ScissorRectangle = scissorRect;
foreach (BaseItem i in ItemList)
{
sb.Draw(slot, new Vector2(i.itemRect.X, i.itemRect.Y), new Rectangle(0, 0, 32, 32), Color.White, 0, Vector2.Zero, Scale, SpriteEffects.None, .95f);
sb.Draw(i.Icon, new Vector2(i.itemRect.X, i.itemRect.Y), new Rectangle(0, 0, i.Icon.Width, i.Icon.Height), Color.White, 0, Vector2.Zero, Scale, SpriteEffects.None, .95f);
//if (i.currentAmount > 1)
sb.DrawString(sf, "" + i.currentAmount, new Vector2(i.itemRect.X, i.itemRect.Y), Color.White, 0f, Vector2.Zero, Scale, SpriteEffects.None, .95f);
}
sb.End();
}
}
}
BaseItem.cs:
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
namespace InventoryEngine
{
public class BaseItem
{
public Texture2D Icon;
public string name;
string description;
public int id, currentAmount, maxAmount;
public enum TabType { Consumable, Weapon, Armor, Ammo, Jewellery, Resources, Misc }
public TabType tabType;
public bool isSelected, isUsable;
public Vector2 positionOffset;
public Point gridLocation;
public Rectangle itemRect;
public BaseItem(Texture2D IconName, int ID, string Name, string Description, int MaxAmount, TabType TabType)
{
Icon = IconName;
id = ID;
name = Name;
description = Description;
maxAmount = MaxAmount;
tabType = TabType;
}
public void UpdateValues(Point GridSize, int itemSize, Vector2 GridOffset, int OffsetY)
{
currentAmount = (int)MathHelper.Clamp(currentAmount, 0, maxAmount);
itemRect = new Rectangle(gridLocation.X * itemSize + (int)GridOffset.X, gridLocation.Y * itemSize + OffsetY, itemSize, itemSize);
}
}
}
Going with #deathismyfriend you could run a nested for loop going through each position:
int pos; //Declared at the top of the class
pos = 0;
for (int x = 0; x < gridsize.X; x++) // x represents column
{
for (int y = 0; y < ItemList.Count / gridsize.X; y++) // y represents row
{
// In the above (ItemList.count / gridsize.X) = number of rows needed
ItemList[pos].gridLocation = new Point(x, y);
pos++;
}
}
And that SHOULD do what you want it to.
Mona

XNA C# Why is my string not drawing?

When you click on the top most button it is suppose to draw a string to the screen, but it's no showing up. I moved mainMenu.UpdateButtons(); to the Draw method in Main.cs but the string is drawn then the background image is drawn again. Making it appear as the string appears for a split second and disappear. Why is it doing this?
Main.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;
using TestGame.Controls;
using TestGame.GameStates;
namespace TestGame
{
public class Main : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
InputHandler inputHandler;
public SpriteBatch spriteBatch;
public SpriteFont spriteFont;
MainMenu mainMenu;
Vector2 position;
public Main()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
inputHandler = new InputHandler();
mainMenu = new MainMenu(this);
graphics.PreferredBackBufferWidth = 1280;
graphics.PreferredBackBufferHeight = 720;
}
protected override void Initialize()
{
this.IsMouseVisible = true;
base.Initialize();
mainMenu.MenuInitialize();
}
protected override void LoadContent()
{
spriteBatch = new SpriteBatch(GraphicsDevice);
spriteFont = Content.Load<SpriteFont>(#"Fonts\MainFont");
mainMenu.MenuLoadContent();
}
protected override void UnloadContent()
{
}
protected override void Update(GameTime gameTime)
{
inputHandler.Update();
if (inputHandler.currentKeyState.IsKeyDown(Keys.Escape))
this.Exit();
mainMenu.frameTime = gameTime.ElapsedGameTime.Milliseconds / 1000;
MouseState mouseState = Mouse.GetState();
mainMenu.mouseX = mouseState.X;
mainMenu.mouseY = mouseState.Y;
mainMenu.previouslyPressed = mainMenu.mousePressed;
mainMenu.mousePressed = mouseState.LeftButton == ButtonState.Pressed;
mainMenu.UpdateButtons();
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
mainMenu.MenuDraw();
spriteBatch.End();
base.Draw(gameTime);
}
}
}
MainMenu.cs
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace TestGame.GameStates
{
public class MainMenu
{
enum buttonState { hover, up, released, down }
const int numberOfButtons = 4, newGameButtonIndex = 0, loadGameButtonIndex = 1, optionsButtonIndex = 2, quitButtonIndex = 3, buttonHeight = 48, buttonWidth = 80;
Color[] buttonColor = new Color[numberOfButtons];
Rectangle[] buttonRect = new Rectangle[numberOfButtons];
buttonState[] buttonSt = new buttonState[numberOfButtons];
Texture2D[] buttonTexture = new Texture2D[numberOfButtons];
double[] buttonTimer = new double[numberOfButtons];
public bool mousePressed, previouslyPressed = false;
public int mouseX, mouseY;
public double frameTime;
int buttonPadding;
Main main;
Texture2D backgroundImage;
Texture2D backgroundImageFade;
public MainMenu(Game game)
{
main = (Main)game;
}
public void MenuInitialize()
{
for (int i = 0; i < numberOfButtons; i++)
{
buttonSt[i] = buttonState.up;
buttonColor[i] = Color.White;
buttonTimer[i] = 0.0;
buttonRect[i] = new Rectangle(0, buttonPadding, buttonWidth, buttonHeight);
buttonPadding += buttonHeight;
}
}
public void MenuLoadContent()
{
backgroundImage = main.Content.Load<Texture2D>(#"Backgrounds\titlescreen");
backgroundImageFade = main.Content.Load<Texture2D>(#"Backgrounds\titlescreenfade");
buttonTexture[newGameButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
buttonTexture[loadGameButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
buttonTexture[optionsButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
buttonTexture[quitButtonIndex] = main.Content.Load<Texture2D>(#"Sprites\desktop");
}
public void MenuDraw()
{
main.spriteBatch.Draw(backgroundImage, new Vector2(0, 0), Color.White);
for (int i = 0; i < numberOfButtons; i++)
{
main.spriteBatch.Draw(buttonTexture[i], buttonRect[i], buttonColor[i]);
}
}
Boolean targetImageAlpha(Rectangle rect, Texture2D texture, int x, int y)
{
return targetImageAlpha(0, 0, texture, texture.Width * (x - rect.X) / rect.Width, texture.Height * (y - rect.Y) / rect.Height);
}
Boolean targetImageAlpha(float tx, float ty, Texture2D texture, int x, int y)
{
if (targetImage(tx, ty, texture, x, y))
{
uint[] data = new uint[texture.Width * texture.Height];
texture.GetData<uint>(data);
if ((x - (int)tx) + (y - (int)ty) * texture.Width < texture.Width * texture.Height)
{
return ((data[(x - (int)tx) + (y - (int)ty) * texture.Width] & 0xFF000000) >> 24) > 20;
}
}
return false;
}
Boolean targetImage(float tx, float ty, Texture2D texture, int x, int y)
{
return (x >= tx && x <= tx + texture.Width && y >= ty && y <= ty + texture.Height);
}
public void UpdateButtons()
{
for (int i = 0; i < numberOfButtons; i++)
{
if (targetImageAlpha(buttonRect[i], buttonTexture[i], mouseX, mouseY))
{
buttonTimer[i] = 0.0;
if (mousePressed)
{
buttonSt[i] = buttonState.down;
buttonColor[i] = Color.Blue;
}
else if (!mousePressed && previouslyPressed)
{
if (buttonSt[i] == buttonState.down)
{
buttonSt[i] = buttonState.released;
}
}
else
{
buttonSt[i] = buttonState.hover;
buttonColor[i] = Color.LightBlue;
}
}
else
{
buttonSt[i] = buttonState.up;
if (buttonTimer[i] > 0)
{
buttonTimer[i] = buttonTimer[i] - frameTime;
}
else
{
buttonColor[i] = Color.White;
}
}
if (buttonSt[i] == buttonState.released)
{
onButtonClick(i);
}
}
}
void onButtonClick(int i)
{
switch (i)
{
case newGameButtonIndex:
main.spriteBatch.Begin();
//main.spriteBatch.DrawString(main.spriteFont, "Creating new game", new Vector2(100, 200), Color.White);
main.spriteBatch.Draw(backgroundImageFade, new Vector2(0, 0), Color.White);
main.spriteBatch.End();
break;
default:
break;
}
}
}
}
It is being drawn, but then you proceed to erase it in your Draw method. That's the issue you'll get when you start to mix your drawing code in with your updating code.
So here's an example of what's happening in your game right now.
Update Main Game
Update Buttons
Draw Main Game
Draw Buttons
Then a click occurs and here's what happens.
Update Main Game
Update Buttons
onButtonClick -> this is where you draw your text
Draw Main Game -> the screen now clears and your draw your buttons
Draw Buttons
So it's all "working" just not how you really intended it. You're going to want to separate your drawing code so that you're drawing from Draw method calls. Basically check to see if the buttonState has become "released" in your Draw method and THEN draw the text you want.

Categories