XNA NullReference Exception, when loading a Texture in Array - c#

Alright I'm stumped here, I can usually figure out most bugs, through use of Google or common sense but this one has me stumped!
I'm trying to load textures to an array of enemies (Like a row in space invaders) within my struct, however when I go to debug it throws a Null Reference, I know this means that I'm trying to access something that isn't there, I believe it's because i am calling this:
Inside Initialize I call my method:
Targets.setupSprite(this);
This is the actual method from inside the struct:
public void setupSprite(Game1 g)
{
widthFactor = 0.05f;
rowSize = 15;
spriteSpacingY = spriteRectangle.Height + 5;
for (int i = 0; i < rowSize; i++)
{
if (i < 15)
spriteSpacing = 10;
sprites[i].spriteTexture = g.texture;
x = 0 + (i * spriteSpacing);
y = spriteSpacingY;
visible = true;
}
}
Before the Textures can be setup by Content Loader.
It recommends using 'new' but I'm not sure how to use it here.
The line that throws the error as you may have guessed is:
sprites[i].spriteTexture = g.texture;
g.texture is the texture for the enemy and is located in load content.
Any help would be greatly appreciated!
Additional Code:
protected override void Initialize()
{
displayHeight = GraphicsDevice.Viewport.Height;
displayWidth = GraphicsDevice.Viewport.Width;
new TargetRowStruct();
BreadBat.setupSprite(this);
CheeseBall.setupSprite(this);
Targets.setupSprite(this);
base.Initialize();
}
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
texture = this.Content.Load<Texture2D>("Handsome");
swag = this.Content.Load<Texture2D>("swag");
back = this.Content.Load<Texture2D>("Backdrop");
font = this.Content.Load<SpriteFont>("FontA");
backRect.Width = (int)displayWidth;
backRect.Height = (int)displayHeight;
BreadBat.loadTexture(this);
CheeseBall.loadTexture(this);
Targets.loadTexture(this);
BreadBat.scaleSprites(this);
CheeseBall.scaleSprites(this);
Targets.scaleSprites(this);
}
Relevant Code within Targets Struct:
public void scaleSprites(Game1 g)
{
for (int i = 0; i < rowSize; i++)
{
sprites[i].spriteRectangle.Width = (int)((g.displayWidth * sprites[i].widthFactor) + .25f);
sprites[i].aspectRatio = (int)(sprites[i].spriteTexture.Width / sprites[i].spriteTexture.Height);
sprites[i].spriteRectangle.Height = sprites[i].spriteRectangle.Width;
}
}
public void loadTexture(Game1 g)
{
for (int i = 0; i < rowSize; i++)
{
sprites[i].spriteTexture = g.texture;
}
}
public void drawSprite(Game1 g)
{
g.spriteBatch.Draw(spriteTexture, spriteRectangle, Color.White);
for (int i = 0; i < rowSize; i++)
{
if (sprites[i].visible)
{
g.spriteBatch.Draw(sprites[i].spriteTexture, sprites[i].spriteRectangle, Color.White);
}
}
}
public void setupSprite(Game1 g)
{
widthFactor = 0.05f;
rowSize = 15;
spriteSpacingY = spriteRectangle.Height + 5;
for (int i = 0; i < rowSize; i++)
{
if (i < 15)
spriteSpacing = 10;
x = 0 + (i * spriteSpacing);
y = spriteSpacingY;
visible = true;
}
}
P.s It should be noted that the bread and cheese struct which are almost identical (except for being one sprite instead of an array) work fine.

I still suspect, that inside Target struct You don't initialize this sprites[] array;
So, either at the execution time sprites == null or sprites[i] = null;
As I can see, there are three methods invoked on Targets, one is Targets.setupSprite(this); called inside Initialize.
Targets.loadTexture(this); Targets.scaleSprites(this); => those two are called inside LoadContent.
Now, as msdn states, Initialize method is "Called after the Game and GraphicsDevice are created, but before LoadContent."
If, after removing problematic line (which I see You did in the code You added in edit), NullPointerException isn't thrown in relation to sprites[] array, it means, the array is initialized but somewhere after Targets.setupSprite(this);.
If it is thrown, it's probably that You didn't initialize it at all.

The exception is pretty clear, sprites is null. Instantiate it using sprites = new Sprite[100] (or whatever class and size you require) and you're good to go.

Related

How delete clone GameObjects in Unity

So I didn't find something useful, to solve my problem. My script is downloading an JSON Array from my Server and fills some text with that informations.
Thats the part of code:
void DrawUI()
{
GameObject buttonObj = transform.GetChild (0).gameObject; //Gets button to clone it
GameObject g;
int N = allCars.Length;
for (int i = 0; i < N; i++)
{
g = Instantiate(buttonObj, transform);
g.transform.Find("name").GetComponent<Text>().text = allCars[i].carName;
g.transform.Find("type").GetComponent<Text>().text = allCars[i].type;
g.transform.Find("price").GetComponent<Text>().text = allCars[i].price+ "€";
if(balance < int.Parse(allCars[i].price))
{
g.transform.Find("price").GetComponent<Text>().color = Color.red;
} else if (balance >= int.Parse(allCars[i].price))
{
g.transform.Find("price").GetComponent<Text>().color = new Color32(53, 140, 3, 255);
}
g.GetComponent<Button>().AddEventListener(i, OpenBuyDialog);
itemIndex = i;
}
Destroy(prefab);
}
This code loops and creates clones of my buttons, all fine. When user confirms the Buy Dialog, it should reload/refresh the list, but for that I have to delete the old clones. I can't find how to do that properly.
Assume the transform has only one child (buttonObj) at the beginning, then you can delete the clones with this code.
var count = transform.childCount;
for (var i = 1; i != count; ++i)
Destroy(transform.GetChild(i).gameObject);
Add your instantiates objects to a member:
private List<GameObject> buttons;
On refresh, iterate through buttons and call Destroy on each GameObject.
Since you said:
g = Instantiate(buttonObj, transform);
Your clone object is = g.
So you can basically say:
Destroy(g.gameObject);

How can I compare two lists inside Editor script to make a for loop only one time each time the lists are not the same size?

using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
[CustomEditor(typeof(DialogueTrigger))]
public class DialogueTriggerEditor : Editor
{
private SerializedProperty _dialogues;
private SerializedProperty _conversations;
private SerializedProperty old_Conversations;
private void OnEnable()
{
_conversations = serializedObject.FindProperty("conversations");
old_Conversations.arraySize = _conversations.arraySize;
}
public override void OnInspectorGUI()
{
//base.OnInspectorGUI();
serializedObject.Update();
_conversations.arraySize = EditorGUILayout.IntField("Conversations Size", _conversations.arraySize);
if (old_Conversations.arraySize != _conversations.arraySize)
{
for (int x = 0; x < _conversations.arraySize; x++)
{
var conversation = _conversations.GetArrayElementAtIndex(x);
var Id = conversation.FindPropertyRelative("conversationName");
EditorGUILayout.PropertyField(Id);
_dialogues = conversation.FindPropertyRelative("Dialogues");
_dialogues.arraySize = EditorGUILayout.IntField("Dialogues size", _dialogues.arraySize);
for (int i = 0; i < _dialogues.arraySize; i++)
{
var dialogue = _dialogues.GetArrayElementAtIndex(i);
EditorGUILayout.PropertyField(dialogue, new GUIContent("Dialogue " + i), true);
}
}
}
old_Conversations.arraySize = _conversations.arraySize;
serializedObject.ApplyModifiedProperties();
}
}
Everything inside the OnInspectorGUI is call over and over again very fast.
So it's doing the loops nonstop.
I added a old copy of the _conversations:
private SerializedProperty old_Conversations;
I tried first time to assign it to the original _conversations inside the OnEnable:
old_Conversations.arraySize = _conversations.arraySize;
But I used a break point and the OnEnable never called.
Then before the loops I'm doing the check:
if (old_Conversations.arraySize != _conversations.arraySize)
In the bottom I'm making both equal again.
But it's not working. When changing the size of the _conversations it's all the time change it back to 1 and does nothing after it.
My main goal is somehow to call the loops only once each time the size changed.
It's working good if the size is 1 or 5 or 10 but if I change the size to 100 everything get slow almost freeze.
You can use BeginChangeCheck / EndChangeCheck to detect the modification.
EditorGUI.BeginChangeCheck();
_conversations.arraySize = EditorGUILayout.IntField("Conversations Size", _conversations.arraySize);
if(EditorGUI.EndChangeCheck()) {
for ...
}
Page view
page = EditorGUILayout.IntField("Page", page);
int index = page * countPerPage;
for(int x = index; i < Mathf.Min(_conversations.arraySize, index + countPerPage); ++i)
{
...
}
You can try to save just the array size of the old conversations in an integer and not saving a second array. But there is a chance, that this wont work because i think the onInspectorGui code has to be executed in every call(But not sure about that).

Playing sprite animation sequence slow on first loop

I just made a png animation sequence that fires when the object is found but on the first loop it takes a lot to load, is there a way to load it faster?
The animation consist of 500 pngs loaded in a sprite the total size of all is about 180Mb, and the code that I am using is very simple:
DefaultTrackableEventHandler.cs:
public SpriteRenderer sr;
public int i = 0;
void Update ()
{
i++;
i = (i > 100) ? 0 : i;
sr.sprite = Resources.Load<Sprite> ("fractal/03_" + i.ToString ("D5"));
}
btw i'm a complete noob on unity programming so please forgive me if i'm missing something obvious, thanks
The problem is that you are loading sprite every frame. It will effect performance. Do the loading once in the Start function and store the result in an array. You can then use that array in the Update function.
const int ANIM_SIZE = 500;
Sprite[] animSprites;
public SpriteRenderer sr;
public int i = 0;
void Start()
{
for (int i = 0; i < ANIM_SIZE; i++)
{
animSprites[i] = Resources.Load<Sprite>("fractal/03_" + i.ToString("D5")) as Sprite;
}
}
void Update()
{
i++;
i = (i > 100) ? 0 : i;
sr.sprite = animSprites[i];
}
Since you are loading many files, you should use Resources.LoadAsync instead. That will let you load the data over frame and prevent any possible freezing when loading the sprites.
const int ANIM_SIZE = 500;
Sprite[] animSprites;
public SpriteRenderer sr;
public int i = 0;
bool isDoneLoading = false;
IEnumerable Start()
{
for (int i = 0; i < ANIM_SIZE; i++)
{
ResourceRequest rs = Resources.LoadAsync<Sprite>("fractal/03_" + i.ToString("D5"));
yield return rs;
animSprites[i] = rs.asset as Sprite;
}
isDoneLoading = true;
}
void Update()
{
if (isDoneLoading)
{
i++;
i = (i > 100) ? 0 : i;
sr.sprite = animSprites[i];
}
}
Finally, don't use any of these solutions mentioned above. They are just there because that's what you asked for. Use the Unity's Animation/Animator's tool to do this. You can learn more about this here.

Movement Loop in Unity

I have 4 objects each located in a corner of a square. I wish to move these objects clockwise, 1 position per method call.
With the code I have atm, they all just complete the entire loop on 1 method call instead of moving only one position...
My code so far:
void SwitchPositions()
{
tempPosition1 = parent.transform.GetChild(0).GetComponent<Transform>().position;
tempPosition2 = parent.transform.GetChild(1).GetComponent<Transform>().position;
tempPosition3 = parent.transform.GetChild(2).GetComponent<Transform>().position;
tempPosition4 = parent.transform.GetChild(3).GetComponent<Transform>().position;
parent.transform.GetChild (0).GetComponent<Transform> ().position = tempPosition2;
parent.transform.GetChild (1).GetComponent<Transform> ().position = tempPosition3;
parent.transform.GetChild (2).GetComponent<Transform> ().position = tempPosition4;
parent.transform.GetChild (3).GetComponent<Transform> ().position = tempPosition1;
Debug.Log (tempPosition1);
}
If anyone has any ideas how to fix this or at least explain to me why it-s completing the entire loop in 1 method call...
Thank you!
I am really not sure how your timer works or for that matter anything wrong with your code. But I have used the coroutine where after every two seconds the blocks get switched and it happens continuously. I think this should be somewhere close to what you need.
//Predefined positions where objects to place
public Transform[] Position;
//The objects that will will be swapped in coroutines
public Transform[] ObjectsToMove;
private int ObjectIndex = 0;
private bool startupdate = true;
void Update () {
if(startupdate)
StartCoroutine(SwitchBlocks());
}
IEnumerator SwitchBlocks() {
startupdate = false;
int tempIndex = ObjectIndex;
for(int i = 0; i < ObjectsToMove.Length; i++) {
tempIndex = ObjectIndex + i;
if(tempIndex > ObjectsToMove.Length - 1)
tempIndex -= ObjectsToMove.Length;
ObjectsToMove[i].position = Position[tempIndex].position;
}
ObjectIndex++;
if(ObjectIndex > ObjectsToMove.Length - 1) {
ObjectIndex = 0;
}
yield return new WaitForSeconds(2.0f);
startupdate = true;
yield return null;
}
Hope this helps.

Program 'for loop' is changing multiple values in the array in one instance

I was working line by line in the debugger option (red dot) in express 2010 visual c#.
This loop was assiging creatures[2].sprite.position and creatures[3].sprite.position to the same vector (100,320) at the same instance, when i equaled 2.
Further testing showed that when i = 3 the same would happen, then on i = 4, all 2,3, and 4 were changed at the same time to the same vector.
any suggestions on whats causing this, it feels like a bug, thinking about it now, I should try a different variable than i, maybe its being used some where else.
public class GameImages
{
//Image Diminsions
public Texture2D texture;
//Images position on the Viewport
public Vector2 position = new Vector2(0,0);
//Color
public Microsoft.Xna.Framework.Color color = Microsoft.Xna.Framework.Color.White;
}
public class CreaturesAttributes
{
//Image
public GameImages sprite;
//Level
public double Level;
}
CreaturesAttributes[] creatures = new CreaturesAttributes[100];
public void LoadTeam()
{
int j = 0;
for (int i = 1; i < creatures.Length; i++)
{
if (creatures[i].Color1 != null)
{
creatures[i].sprite.position = new Vector2(j, 320);
j += 100;
}
else
{
i = creatures.Length;
}
}
}
protected override void Initialize()
{
for (int i = 0; i < creatures.Length; i++)
{
creatures[i] = new CreaturesAttributes();
creatures[i].sprite = new GameImages();
}
}
This happens because you probably initialized all your array elements to point to a single instance:
var newCreature = new Creature(/* ... */);
for (int i = 0; i < creatures.Length; i++) {
creatures[i] = newCreature;
}
Or perhaps you created multiple creatures, but with the same "sprite":
var defaultSprite = new Sprite(/* ... */);
for (int i = 0; i < creatures.Length; i++) {
creatures[i] = new Creature();
creatures[i].sprite = defaultSprite;
}
or maybe sprite or position are static fields:
static Sprite sprite;
//or
static Vector2 position;
All the above will cause all your mutations and accesses to happen to the same instance, so it looks like changing one is changing all of them (while there in reality is just a single creature/sprite/position that you're referencing from multiple places).
The solution is to ensure that the fields are not static, and make sure to create a new creature and creature.sprite for each:
// No static fields, and new instances for each index
for (int i = 0; i < creatures.Length; i++) {
creatures[i] = new Creature();
creatures[i].sprite = new Sprite();
}

Categories

Resources