I'm trying to destroy any gameobject that is under some height (let's say -5).
I tried foreach method that takes all gameobjects and than compares it using if. If comparison is TRUE, then there is simple Destroy(go);
public float MinimalYLocation;
GameObject[] Objects;
void Start () {
Scene scena = SceneManager.GetActiveScene();
Objects = scena.GetRootGameObjects();
}
void Update () {
foreach (GameObject gobject in Objects) {
float Height = gobject.transform.position.y;
if (Height < MinimalYLocation){
Destroy(gobject);
}
}
}
I set up a scene that contains 3 cubes in different heights and a camera. Script is in camera. When first cube falls, it is destroyed. Then I get massive spam to console:
MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
And the second and third cubes are not destroyed. Expected response would be that all gameobjects will be destroyed as they touch height -5
This is not going to be a scalable approach. You will find that it has a severe impact on your game's performance as more and more GameObjects are active in the scene.
I recommend you add a plane that extends to all game area bounds, and sits at this "-5" z position. Give the plane a collider trigger and destroy all objects that touch it. Leave the plane without a texture (aka invisible).
This will eliminate what is going to be a massive load in an update that happens every single frame.
Related
I'm developing an enemy AI in a 2D Game that I'm working on. This enemy swims and I wanted to make a "floating effect" animation for the enemy, so I made an animation where the Y Axis of the game object bounces up and down.
I Use transform.Translate() to move the enemies in the game and it worked just fine until I made this animation. But, when the animation is playing, the enemy can't move in any direction.
public virtual void Move(float speed)
{
if (canMove)
{
transform.Translate(new Vector2(speed, 0) * Time.deltaTime);
}
}
Once you have a keyframe in any state of your animator for a certain property the animator will always overrule any changes done in a script because the animation updates are all done after Update. You could try to either move your code to LateUpdate.
Or in your specific case you do not want the x component of your position keyframed at all. Simply remove all the keyframes for the x (and z) component(s) of the position from the animations so only y has keyframes. This should solve your problem.
Alternatively use your movement script on a GameObject on a higher level in the hierachy as your Animator - meaning add a new GameObject, make the animated object a child of it and place your movement script instead on that parant object.
I could really need some help with my GameObjects.
I am working on a game in which I want a pick-up Item to create a Physics Force explosion to blow away the enemies. I made a simple Bomb-Object to test this idea. I added a straightforward code, using a loop to collect all the colliders within its radius, to then addForce to these colliders. Now the code is working properly, but not all my GameObjects are reacting properly.
I looked into why this is, and I noticed that my Collider keeps falling away from the GameObject as soon as I add a RigidBody component to the object. The RigidBody is needed for the AddForce impact. When I remove the rb, the collider stays in place, but the object does not react to the Physics Force.
I added some images to illustrate what I mean:
Image of the Collider of the leaf sinking away..
Example image of objects which DO react to the AddForce.
I already tried to:
Copy/Paste all component settings from the reacting Cube and stone
Gameobjects to the Leaf Gameobject while disabling all other code
such as the c# scripts. The Collider & RB do not fall through the
floor but when Physics Force hits the Collider is blown away while
the GameObject keeps its position.
Try different GameObjects/Collider types.
Removed the water.
Play with amount of force/radius of the bomb.
Edited 'Tag' and 'Layerstyle' of GameObject.
The 'Explosion Code' is added below, however, I don't think the problem is in the code. I added the code to the Main Camera of my scene, and added a simple sphere as the 'bomb' GameObject.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Explosion : MonoBehaviour
{
public GameObject bomb; //set the position of the explosion
public float power = 10.0f;
public float radius = 10.0f;
public float upForce = 0.0f;
private void FixedUpdate()
{
if (Input.GetKeyDown("space"))
{
print("space key was pressed");
Invoke("Detonate", 1);
}
}
void Detonate()
{
Vector3 explosionPosition = bomb.transform.position; //set the position of our explosion to the position of the bomb.
Collider[] colliders = Physics.OverlapSphere(explosionPosition, radius); //collects all colliders within the radius.
foreach (Collider hit in colliders) { //for each individual collider the following code is ran.
Rigidbody rb = hit.GetComponent<Rigidbody>(); //declare'rb' rigidbody. Get rb component from each collider
if (rb != null)
{
print("BOOM!");
rb.AddExplosionForce(power, explosionPosition, radius, upForce, ForceMode.Impulse); //add force to each collider
}
}
}
}
How do I make the Rigidbody, Collider and GameObject of the leaf hold onto each other like the standard 3D object 'cube', so that I can make these blow away with the Physics Force just like the other models?
Thank you for your time, I have been trying things and looking around on the Internet for hours now but can't seem to find any solution.
What happens if you add the rigidbody in stop mode and press play? Does it move away in a similar manner? This may, and is expected to happen, if your colliders intersect with each other. As soon as you add a rigidbody, they find themselves trapped in a serious collision.
If you don't want to modify the scene, you can fiddle with the collision matrix in project settings / physics
I made a moving platform that goes vertically top to bottom and then bottom to top and so on. Platform moves fine but placing my player on it makes my player unstable.
When platform moves from top to bottom, my player kinda bounces on it. When platform moves from bottom to top, it remain stable on the way but when it reaches top point, my player makes a jump by itself.
Its get even worse when i increase the speed of my platform. I don't know if its due to unity 2d physics effect or what. I have tried to use physics material 2D on my player object and platform by setting bounce to 0 and friction to 50 but nothing seems to work. Any one have idea how to disable physics effect of moving platform? Following is my code for moving platform:
public class BrickMoveVErtical : MonoBehaviour {
public Vector3 positionOne;
public Vector3 positiontwo;
public Vector3 nextposition;
/*Empty object is already made on unity editor and its parent of platform(Plank) and other
empty object "pointB". Point "B" is already mapped on editor and platform is set to go from
its original pos to point B */
public Transform plankTranform;
public Transform positionBTransform;
public float speed;
// Use this for initialization
void Start () {
positionOne = plankTranform.localPosition;
positiontwo = positionBTransform.localPosition;
nextposition = positiontwo;
}
// Update is called once per frame
void Update () {
move();
}
private void move() {
plankTranform.localPosition = Vector3.MoveTowards(plankTranform.localPosition,nextposition,Time.deltaTime*speed);
if(Vector3.Distance(plankTranform.localPosition,nextposition)<0.1)
{ changeMovementPlank(); }
}
void changeMovementPlank() {
nextposition = nextposition != positionOne ? positionOne : positiontwo;
}
}
I had similar problems with fast platforms in my game, the character would be left out in the air or slide off, depending on the direction of the platform.
I found a workaround for the problem by simply changing the character transform.parent to the platform it was jumping on, whenever the player exists the platform collider, simply return the players original transform.parent.
Note that this might cause other bugs or problems that will need to optimize, depending on your game that is.
You can use this code to set/unset the parent of a GameObject:
void OnTriggerEnter2D(Collider2D other)
{
if(other.gameObject.tag == "PlatformGroup")
player.SetParent(other.gameObject.transform)
}
void OnTriggerExit2D(Collider2D other)
{
if(other.gameObject.tag == "PlatformGroup")
player.SetParent(null);
}
What you should do is:
Create an empty GameObject, and you make your platform child of this
empty GameObject. Tag it as PlatformGroup.
You add the script to move the platform to this EmptyGame Object,
instead of using it in the platform itself.
Then add a collider to empty gameobject(PlatformGroup) and another to the Player. Set the one of the player as trigger.
Add the code above to your player controller.
Now, when the Player jumps over the Platform if will become a child of the same GameObject of the platform and they will move together without any deformations in the GameObject. Also when the player leaves the platform, walking or jumping out of it, it will stop being child.
I have an animated sprite which has 8 frames of animation. Each frame has a PolygonCollider2D attached as an element of an array thus providing it with accurate collision detection no matter which frame is playing.
When I had only one collider on the sprite and it passed through the "score" object the player's score increased by 1 point.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Point")
{
score++;
scoreText.text = score.ToString();
return;
}
}
Polygon Collider 2D array in Unity inspector
Each collider in the array becomes active in turn...
public void SetColliderForSprite(int spriteNum)
{
colliders[batColliderIndex].enabled = false;
batColliderIndex = spriteNum;
colliders[batColliderIndex].enabled = true;
}
Now that each frame of the animation has its own collider I find that the score is increasing at an alarming rate as each frame plays multiple times whilst inside the "score" game object, triggering the point scoring logic multiple times, before the player leaves said object.
I'm wondering what the ideal programmatic solution is in order to ensure that on entering the "point" collider object the player only gets a score increment once before exiting the area?
Thanks in advance for any suggestions (and my apologies if this has been answered elsewhere).
EDIT: I was thinking about my post below and I think there is a simpler solution. You should be able to animate your collider shape rather than having 1 collider per animation frame. For example, see this question on How to update 2d colliders with sprite animation.
(And as a side note, you can also have multiple polygon colliders on each part of the sprite, and animate the colliders to move accordingly. For example, see this post on Animating Polygon Collider 2D. This alternative approach might make the suggestion I make in my post below simpler.)
One suggestion I have is to only increment the score when the first "Point" trigger is detected and then not incrementing the score again until the object has fully left. This can be implemented by keeping track of how many colliders (or which specific colliders) have entered and exited the object. Something like the following:
private const string PointTag = "Point";
private int _triggerCount;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == PointTag)
{
bool firstCollision = (_triggerCount == 0);
if (firstCollision)
{
score++;
scoreText.text = score.ToString();
}
_triggerCount++;
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.tag == PointTag)
{
_triggerCount--;
}
}
However, once a collision is in progress, you will likely have to change the behaviour so that all colliders stay active until the object has fully left the collision area. This is because if you disable the collider, the OnTriggerExit2D event will not fire.
This solution may not be acceptable depending on how accurately you need to detect that the VampireBat has left the collision area.
If it doesn't need to be very accurate, you can simplify the solution by adding a 9th collider with a unique tag that covers the entire area of the sprite's animation. By using this 9th collider to determine when the player has left the collision area, you would not need to worry about affecting the code related to showing the appropriate collider per animation frame. (But note that the code example here would have to be modified so that the OnTriggerExit2D uses this 9th collider object.)
If it needs to be more accurate, I think there is likely a solution similar to what I suggested based on which colliders are currently active, the details of your collider shapes & animation frames, and OnTrigerEnter2D, OnTriggerStay, and OnTriggerExit2D. But note that you may also need to be careful that a collision is not re-triggered immediately. (For example, the object may have fully left the collision area, but the next animation frame might trigger a collision again immediately.)
Thanks for the response. Your edit got me to thinking about child objects. I added a child collider (with an index value of 9) then checked for a collision with that.
child object in inspector
Referenced the child collider in the collider array.
Collider array in inspector
After that it was just a matter of referencing it in the player controller script.
// Update is called once per frame
void Update () {
//Player input
if (Input.GetMouseButtonDown(0))
{
bat.velocity = new Vector2(0, 4);
//ADD BAT FLAP SOUND LATER!!!
}
scoreText.text = score.ToString();
Debug.Log("SCORE: " + score);
}
//Point increment function
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Point" && batColliderIndex == 9)
{
score++;
return;
}
}
I now have pixel perfect collision detection against obstacles and a score which increments correctly.
Thanks again.
I'm making voxel models, which I love as I love pixelart. The models I want to use in unity are very small humanoids and purely for function.
As I look around for ways to animate these voxel models, all i really see is ways to add bones/rigs, creating a smooth animation which imo belies the voxel style.
I wanted to make these voxels animate in the same way that a 2D sprite is animated. For example my best and so far only technique for jumping animation is to destroy the standing voxel object and instantly instantiate the jumping voxel model object when I press jump. No transition involved, just the old school sprite style animation; like Mario.
My code for this was going to be (obviously not literally, but you get the idea):
if (player presses jump){
destroy.this.gameobject
instantiate prefab (jumpmanvoxelmodel)
}
Is this really the best method for doing this on unity? I'm making every frame of the animation in qubicle (at present), using the standing voxel as the child object and then destroying and instantiating the different prefabs (which serve as frames of animation) relative to user input.
Is anyone animating voxels without rigs? Am I barking up the wrong tree?
Thanks
This is what I mean if it's unclear:
https://www.youtube.com/watch?v=u2e8lfViIxg
I'd suggest you treat the voxel models just the same way as if they were 2D sprites. Have a mesh of each and every animation frame, and just switch the meshes. That way you don't produce garbage objects that have to be collected by the Garbage Collector.
Here is a basic example that just runs from first to last frame over and over.
class MeshAnimation : MonoBehaviour
{
public Mesh[] frames = new Mesh[0];
public float animationSpeed = .1f;
private float animationStartTime;
private int currentFrame;
void Start()
{
currentFrame = 0;
animationStartTime = Time.time;
UpdateMesh();
}
void Update()
{
currentFrame = Mathf.FloorToInt((Time.time - animationStartTime) / animationSpeed);
currentFrame = currentFrame % frames.Length;
UpdateMesh();
}
void UpdateMesh()
{
GetComponent<MeshFilter>().mesh = frames[currentFrame];
}
}