changing image to gif after event - c#

i have created a game, and im trying to get the image of the enemies once they have been shot to chnage to a explosion gif before they dissapear but i cant seem to get it to work, you can see the code below where it is meant to change to gif but when you pay the gamethe nemies just dissapear without the gif showing
lasers.RemoveAll(laser => laser.isDisposed);
foreach (Laser laser in lasers)
{
laser.MoveLaser(this);
foreach (Invader ship in invaders)
{
if (laser.laser.Bounds.IntersectsWith(ship.ship.Bounds))
{
laser.isDisposed = true;
laser.laser.Dispose();
ship.ship.Image = SpaceInvaders.Properties.Resources.explosionGIF1;
ship.isDisposed = true;
ship.ship.Dispose();
score = score + 2; //adds 2 points to players score if enemy is hit
lblScore.Text = score.ToString(); //updates the score label

As #jimi explained
Well, you set an Image to the property of an object, then dispose of the object that should show it. Btw, don't try to set [object].isDisposed = true;, it's read-only. Just dipose of an object when needed. Btw2, you need to assign Properties.Resources.[Some Image] to a reusable Image object: right now you're generating a new Image each time.
You're disposing the ship and with that the image.
An example solution would be to create a new GIF object that self-disposes after it has been played once. When the ship is destroyed, a new GIF object is created in the same place the ship was.

Related

How to move a UI GameObject using Mouse Position in 3D World Space?

I have been trying to experiment with moving UI Elements using the position of the mouse, Trying to make it behave like a cursor. I was able to move the Element when the Canvas Render Mode was set to "Screen Space". I was able to clamp it within the Canvas as well.
But I want it to work when the Canvas Render Mode is "World Space" as well. If I use the same code that I used for the Screen Space, the Element leaves its boundaries and gets messed up as the angles are being varied.
I really need help. Any clue how to do it?
You can view how the scene looks in this image below. : https://img.techpowerup.org/200624/screen.png
If Raycasting is the solution, can someone please help me out and provide a snippet of code or something.
What you are looking for is probably RectTransformUtility.ScreenPointToWorldPointInRectangle
Transform a screen space point to a position in world space that is on
the plane of the given RectTransform.
The cam parameter should be the camera associated with the screen
point. For a RectTransform in a Canvas set to Screen Space - Overlay
mode, the cam parameter should be null.
When ScreenPointToWorldPointInRectangle is used from within an event
handler that provides a PointerEventData object, the correct camera
can be obtained by using PointerEventData.enterEventData (for hover
functionality) or PointerEventData.pressEventCamera (for click
functionality). This will automatically use the correct camera (or
null) for the given event.
You didn't post your code but you could probably use it in a GraphicRaycaster.Raycast. Something like
GraphicRaycaster m_Raycaster;
PointerEventData m_PointerEventData;
EventSystem m_EventSystem;
Canvas canvas;
void Start()
{
//Fetch the Raycaster from the GameObject (the Canvas)
m_Raycaster = GetComponent<GraphicRaycaster>();
//Fetch the Event System from the Scene
m_EventSystem = GetComponent<EventSystem>();
canvas = GetComponnet<Canvas>();
//Set up the new Pointer Event
m_PointerEventData = new PointerEventData(m_EventSystem);
}
void Update()
{
//Check if the left Mouse button is clicked
if (Input.GetKey(KeyCode.Mouse0))
{
//Set the Pointer Event Position to that of the mouse position
m_PointerEventData.position = Input.mousePosition;
//Create a list of Raycast Results
List<RaycastResult> results = new List<RaycastResult>();
//Raycast using the Graphics Raycaster and mouse click position
m_Raycaster.Raycast(m_PointerEventData, results);
//For every result returned, output the name of the GameObject on the Canvas hit by the Ray
foreach (RaycastResult result in results)
{
Debug.Log("Hit " + result.gameObject.name);
// until here it was the API example for GraphicRaycaster.Raycast
// Now get the first hit object
var rect = result.gameObject.GetComponent<RectTransform>();
if(rect)
{
// check which camera to get (main or null for ScreenSpace Overlay)
var camera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : Camera.main;
if(RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, result.screenPosition, camera, out var worldPosition))
{
cursor3D.transform.position = worldPosition;
cursor3D.transform.rotation = result.gameObject.transform.rotation;
break;
}
}
}
}
}
Especially note also
Attach this script to your Canvas GameObject.
Also attach a GraphicsRaycaster component to your canvas by clicking the Add Component button in the Inspector window.
Also make sure you have an EventSystem in your hierarchy.

FindObjectsWithTag bringing back objects in random order in Unity?

I'm attempting to make a level select that requires as little upkeep as possible as I intend on adding updates to add more levels (Unity Scenes) in unity.
To account for this I'm attempting to get the level select to create buttons for each level in the Unity Build settings, and then create a template object from a prefab in which it can map buttons it creates onto.
I have it mostly working, but for some reason, it's mapping the buttons in the wrong order, I'm trying to go down to up and Unity appears to be grabbing the Gameobjects is a random order.
Here is my code:
private Scene[] levels;
private int currentButtonId = 1;
public Transform buttonsHolder;
public GameObject buttonPrefab;
public GameObject buttonSlotsPrefab;
private GameObject[] levelButtonSlots;
private int currentLevelSlot = 0;
private int numSlotsToMove = 0;
private void Start()
{
var sceneCount = SceneManager.sceneCountInBuildSettings;
levels = new Scene[sceneCount];
for (var i = 0; i < sceneCount; i++)
{
// Beginning Setup
levels[i] = SceneManager.GetSceneByBuildIndex(i);
// Look for Level Placement Slots
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot");
// If there aren't enough Level Placement Slots make more by creating a template
if(levelButtonSlots.Length < levels.Length)
{
GameObject buttonSlots = Instantiate(buttonSlotsPrefab);
buttonSlots.transform.position = new Vector2(0, 10 * numSlotsToMove);
numSlotsToMove++;
}
// Go get those new placement slots
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot");
// Create Button
GameObject currentButton = Instantiate(buttonPrefab, buttonsHolder);
// Move it to the next slot
currentButton.transform.position = levelButtonSlots[currentLevelSlot].transform.position;
currentLevelSlot++;
// Add Text to a new button
TextMeshProUGUI buttonText = currentButton.GetComponentInChildren<TextMeshProUGUI>();
buttonText.text = (currentButtonId.ToString());
// Setup what which scene clicking a button will do
ButtonManager buttonScript = currentButton.GetComponentInChildren<ButtonManager>();
buttonScript.sceneToLoad = currentButtonId;
currentButtonId++;
}
}
The buttonsHolder variable is set in the editor and is the canvas.
The buttonPrefab is a TextMeshPro button prefab I set in the editor, it has the level Buttons tag and a simple script that loads the specified scene when clicked.
And the buttonSlotsPrefab is a gameobject prefab that I set in the editor, it has the Button Placement Slot tag and it contains 8 other empty gameobjects each with the level slot tag, I use these 8 objects as the guides as to where the buttons should be placed on runtime.
Again, my goal is to place the buttons going from bottom to top, but instead, Unity spits out this on runtime for no apparent reason:
I'm sorry about the naming convention some variables have, I'm tired and stressed as I've been at this 2 two days straight. I will fix those up once I get things working.
After further testing, I have noticed that when I first create buttonSlotPrefab, everything works perfectly, however, after restarting Unity (Not changing any files) when I run the game again after a restart the order gets randomized. Could this be a bug in the Unity Engine?
If i understant your problem, you have a problem between number of button and slot: you have slot spaced on axis y and you havent always the levelsolt[0] at the bottom of screen, so
you could order (ascending or descending i dunno) the levelslot on y axis before creating button: i am using Linq so add using System.Linq;
if (levelButtonSlots.Any())//Same thing than levelButtonSlots.Length > 0
{
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot").OrderBy(go => go.transform.position.y).ToArray();
}
or
levelButtonSlots = GameObject.FindGameObjectsWithTag("Level Slot").OrderByDescending(go => go.transform.position.y).ToArray();
I have added a test if no value in array, but maybe the error doesnt exist, i havent tested that

Unity: AnimationClip generated with code not playing, Manual created AnimationClip does

I'm working on an augmented Reality project in Unity where the user will be able to see an animated sprite on their phone when pointing the camera at a certain image.
The Sprite will be created by a belgian comic book artist and will be quite lengthy. To make my life easier I wanted to create an editor script that takes all the sprites from the Resources/Sprite folder and creates an AnimationClip.
Sprite[] sprites = Resources.LoadAll<Sprite>("sprite");
AnimationClip animClip = new AnimationClip();
animClip.frameRate = 25; // fps
EditorCurveBinding spriteBinding = new EditorCurveBinding();
spriteBinding.type = typeof(SpriteRenderer);
spriteBinding.path = "";
spriteBinding.propertyName = "m_Sprite";
ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[sprites.Length];
for (int i = 0; i < (sprites.Length); i++)
{
spriteKeyFrames[i] = new ObjectReferenceKeyframe();
spriteKeyFrames[i].time = i / animClip.frameRate;
spriteKeyFrames[i].value = sprites[i];
}
AnimationUtility.SetObjectReferenceCurve(animClip, spriteBinding, spriteKeyFrames);
AnimationClipSettings animClipSett = new AnimationClipSettings();
animClipSett.loopTime = true;
AnimationUtility.SetAnimationClipSettings(animClip, animClipSett);
AssetDatabase.CreateAsset(animClip, "assets/generated.anim");
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
This works, an AnimationClip is created but when using it in the Animation Panel nothing happens.
I made the same Animation manually to see if that would work and it does.
The blue bar in the animation panel moves though
Animator Panel showing the generated AnimationClip:
The only noticable difference I've found (besides one of them playing and the other one doesn't) is that the generated clip's Length changes to 0 after trying to run it's animation
The Sprite Object and inspector:
I'be been trying to find what I'm doing wrong for half a day now without getting a single step closer.
I'd like to thank who answers on this question in advance.
Greetings,
Maethorian

C# Picturebox not loading that is added in code

I have a procedure which draws in the player picture box, as below:
public static PictureBox drawPlayer(Engine.Tile location, Image looks)
{
PictureBox player = new PictureBox();
player.Location = location.img.Location;
player.BackColor = Color.Yellow;
player.Size = new Size(50, 50);
player.Name = "Player";
player.Visible = true;
player.BringToFront();
return player;
}
However, it is not working, it is called as such:
t.Controls.Add(drawPlayer(location, image));
Any help with this would be great or an answer as to why this doesn't work, I have temporarily set the colour of the box to yellow just to make it really stand out when it does finally decide to load.
Thanks,
Laurence
You need to use player.BringToFront(); after the control has been added into the form, as it does not exist on the form when you call this in the method that is making the PictureBox.

Enemy audio and sprite sheet won't start/change when player is seen

For my program, I'm generating randomly placed enemies on a windows form and have them wander around when the player is not in sight. When the player gets within range of the player, they will follow and attack the player until the player gets out of range again.
Now, all that code works perfectly fine, but what I'm having trouble with is that when the enemy sees the player, I want to change the enemy's sprite sheet (a black eyed worm-thing, in this case), to a different sprite sheet showing that it is 'hostile'. At the same time, an audio cue will start playing and will not stop until the player is out of range.
Also, I'm not sure if this is relevant or not, but after a certain interval, a new enemy will appear, so there is multiple enemies on the screen
I'm not sure why, but the enemy sprites won't switch sprite sheets and the audio won't start playing when the player's in view with the code I have. What am I doing wrong?
Here's the code:
//The timer to determine direction, the current sprite sheet for the enemies, and whether or not the audio is enabled
private void wander_Tick(object sender, EventArgs e)
{
int count = 0;
List<bool> seenOrNot = new List<bool>(); // a List of bools
//Iterates through a list of enemies
foreach (Enemies en in enemyList)
{
Enemies enemy = en;
if (CurrentPosition.Hostile[count])
{
//The 'hostile' sprite sheet for the enemy
enemy = new Enemies(Properties.Resources.WormSheet, CurrentPosition.enemyX[count], CurrentPosition.enemyY[count], Sapling.ReturnWidth(), Sapling.ReturnHeight());
seenOrNot.Add(true); //The player has been seen
}
else
{
//The 'neutral' sprite sheet for the enemy
enemy = new Enemies(Properties.Resources.WormSheetNeutral, CurrentPosition.enemyX[count], CurrentPosition.enemyY[count], Sapling.ReturnWidth(), Sapling.ReturnHeight());
seenOrNot.Add(false); //The player hasn't been seen
}
en.Direction(); //Generates a random number every tick of the timer
count++;
}
//This foreach loop will play audio when any of the enemies sees the player
foreach (Boolean b in seenOrNot)
{
if (seenOrNot.Contains(true))
{
wplayer.controls.play();//Plays music when player is in view
}
else
{
wplayer.controls.stop();//Stops the music
}
}
}
Any help is appreciated, as always :)
So I have this code so far for the function to change the sprite sheet:
public void ChangeSpriteSheet()
{
if (Hostile)
{
enemySprite = Properties.Resources.WormSheet;
CurrentPosition.seen = true;
}
else
{
enemySprite = Properties.Resources.WormSheetNeutral;
}
}
And I changed the wander timer to this:
private void wander_Tick(object sender, EventArgs e)
{
CurrentPosition.seen = false;
int count = 0;
foreach (Enemies en in enemyList)
{
en.ChangeSpriteSheet(); //Changes the sprite sheet for the current enemy
en.Direction(); //Generates a random number every tick of the timer
count++;
}
//This foreach loop will play audio when any of the enemies sees the player
if (CurrentPosition.seen)
{
wplayer.controls.play();//Plays music when player is in view
}
else
{
wplayer.controls.stop();//Stops the music
}
}
The function to change the sprite sheet is called in this 'wander' timer, and it should iterate through every enemy to check whether or not the sprite sheet should be changed.
With this, the audio works fine, it'll start when the player is in range, and stop when they're out of it.
But I'm still not too sure how I would go about changing the sprite sheet for the enemies. I changed the code so that the actual image/sprite sheet is set in the Enemies class rather than the Windows Form, so it's all in the same place, but I'm not sure where to go from there.
In response to the comments, do you guys mean something like this?
public Image NeutralHostile() //Returns the current sprite sheet
{
return enemySprite;
}
public void ChangeSpriteSheet(Image image)
{
if (Hostile)
{
image= Properties.Resources.WormSheet;
CurrentPosition.seen = true;
}
else
{
image = Properties.Resources.WormSheetNeutral;
}
}
Then in the timer I'd reference to the NeutralHostile function as a parameter for the ChangeSpriteSheet. Am I going in the right direction, or am I completely off?
enemy = new Enemies( ...
This line is not doing what you think it does. It creates a new Enemy and lets your enemyvariable point at it. Note: the en variable or the instance of the enemy in your list has not changed.
You need to write a method that let's an existing enemy change it's spritesheet and then call it on your en variable.
As for the sound: you don't need a list of bools. You need a single bool starting as false that is only set to true when one is seen. Then you need a simple if. Your loop is not making any sense to me. Try to simplify it down to the single bool.

Categories

Resources