how to destroy an object in unity?
I know you have to type the command
Destroy();
but what I'm saying is that I don't know what to put between brackets.
I have tried many different ways:
public GameObject motor;
Destroy(motor);
but it does not work
using System.Collections;
using UnityEngine;
public class LogRotation : MonoBehaviour
{
[System.Serializable] //this will allow us to edit it in the editor
//a custom class representing a single rotation "element" of the log's rotation pattern
private class RotationElement
{
//to get rid of an obnoxious warning about these fields not being initialized
#pragma warning disable 0649
public float Speed;
public float Duration;
#pragma warning restore 0649
}
[SerializeField] //attribute making private fields editable in the Unity Editor
//the aforemention full rotation pattern of the log
private RotationElement[] rotationPattern;
//this will be set to the Wheel Joint 2D from the LogMotor object
private WheelJoint2D wheelJoint;
//something has to actually apply a force to the log through the Wheel Joint 2D
private JointMotor2D motor;
private void Awake()
{
//setting fields
wheelJoint = GetComponent<WheelJoint2D>();
motor = new JointMotor2D();
//starting an infinitely looping coroutine defined below right when this script loads (awakes)
StartCoroutine("PlayRotationPattern");
}
private IEnumerator PlayRotationPattern()
{
int rotationIndex = 0;
//infinite coroutine loop
while (true)
{
//working with physics, executing as if this was running in a FixedUpdate method
yield return new WaitForFixedUpdate();
motor.motorSpeed = rotationPattern[rotationIndex].Speed;
//hard coded 10000, feel free to experiment with other torques if you wish
motor.maxMotorTorque = 10000;
//set the updated motor to be the motor "sitting" on the Wheel Joint 2D
wheelJoint.motor = motor;
//let the motor do its thing for the specified duration
yield return new WaitForSecondsRealtime(rotationPattern[rotationIndex].Duration);
rotationIndex++;
//infinite loop through the rotationPattern
rotationIndex = rotationIndex < rotationPattern.Length ? rotationIndex : 0;
}
}
}
TLDR; Destroy(motor.gameObject), but it will not work if JointMotor2D doesn't inherit MonoBehaviour.
Destroy(obj) can be used to destroy a component too.You need reference it to the game-object to destroy it.
Destroy(GetComponent<RigidBody>()) would remove the RigidBody out of the game-object, rather than removing the object itself.
Destroy(motor.gameObject) should do the trick.
But upon seeing your code, it may not.As it seems like JointMotor2D isn't a MonoBehaviour, aka it doesn't exists in the game-world, hence you can't destroy it.
Depending on what your trying to destroy, you have to find a reference to it.
Simplest way is to reference it in the inspector. Or destroy itself if that is already the object you want to destroy:
// Drag-drop the object in the inspector
[SerializeField]
private GameObject toDestroyLater;
private void DestroyObject() {
Destroy(toDestroyLater);
// Destroys self
// (Aka, whatever game-object this script is attached to)
Destroy(this.gameObject);
}
Related
I have 3(Three) BoxCollider2D components where 2(two) have OnTrigger checked in my Object and both have different functions. Due to having OnTrigger on both, the projectiles I am casting collide with the wrong collider and instead activate that function. Is there a way to ignore 1(one) OnTrigger collider?
I have already tried Layer-based collision detection and set up a layer. Unfortunately, the object now collides with the collider which eliminates the player on collision
However, there are several ways to solve this problem. All kinds of physics.checks as well as raycasts but this code helps you to ignore the obstacle collider.
public Collider2D playerCollider;
public Collider2D obstacleCollider;
public void Start() => Physics2D.IgnoreCollision(playerCollider, obstacleCollider);
I have a very simple script I use to handle collisions in my games.
It's very easy to setup because it makes everything drop and draggable, which is a much easier way to program.
Below is the script and below that is instructions on how to use. Note it is a layer based system, but you can select multiple layers.
[System.Serializable]
public class TriggerEvent : UnityEvent<Collider> { }
[System.Serializable]
public class CollisionEvent : UnityEvent<Collision>{ }
public class EnterEvent: MonoBehaviour
{
public TriggerEvent TriggerEnteredEvent;
public CollisionEvent CollisionEnteredEvent;
[SerializedField]private LayerMask validLayers;
// Initalize Event System
void Awake()
{
if (OnTriggerEnter == null)
{
TriggerEnteredEvent = new TriggerEvent();
}
if (OnCollisionEnter == null)
{
CollisionEnteredEvent = new CollisionEvent();
}
}
// Called if transform is a trigger
void OnTriggerEnter(Collider collider)
{
if (validLayers == (validLayers | 1 << collider.gameObject.layer))
{
TriggerEnteredEvent?.Invoke(collider);
}
}
// Called if transform is not a trigger
void OnCollisionEnter(Collision collision)
{
if (validLayers == (validLayers | 1 << collision.gameObject.layer))
{
CollisionEnteredEvent?.Invoke(collision);
}
}
}
This is how it would work, and in this example I will be "coding" it from the perspective of a Bullet.
Basically I want to check if I (The Bullet) hits either the terrain or an enemy then call the relevent funcitons in the Bullet class respectively.
Obviously if I hit an enemy I want to deal damage.
So this will be my example bullet class
public class Bullet : MonoBehaviour
{
public int BulletDamage = 10;
public int BulletSpeed = 5;
void FixedUpdate() => transform.position = Vector3.Lerp(transform.position, transform.position + transform.forward * speed * Time.deltaTime, 1f);
public void OnEnemyHit(Collision collision)
{
// Try to get the enemy script
Enemy enemy = collision.gameObject.transform.GetComponent<Enemy>();
if (enemy != null)
{
enemy.DealDamage(this.BulletDamage);
}
}
public void OnTerrainHit(Collision collision)
{
Destroy(this.gameObject);
}
}
Add the EnterEvent script to the bullet.
Add the Bullet Script to the bullet.
There will be a space on the Inspecter where you can add your events. It should have a Plus and Minus in the top right corner. Press the plus.
From the inspector drag the bullet in game GameObject to the open space provider.
In the dropdown to the right, click on it, look for the Bullet Script, and select the OnEnemyHit function from it.
Create another event, do the exact same, but this time select the OnTerrainHit funciton instead - now but would be called in the order you added them.
Just underneath the event system should be the be able to see a dropdown for the Layers. Select all the layers you want your bullet to interact with. In this case it will be the Enemy and Terrain.
Finally remember to setup your layers properly. Ensure the Enemy has an Enemy Layer, the Terrain has a Terrain Layer, Bullet bullet layer and Player has a Player Layer
my code is pretty simple, but im quite new to unity... im trying to make it so i can drop my items on the ground when i drag the out of my inventory, but cant quite manage to do so, with a few consistent errors. I have a prefab (just learned of those today), which im trying to change its sprite renderer and spawn it. Heres my code:
public class ItemWorld : MonoBehaviour
{
private Transform prefab;
private Item item;
private SpriteRenderer spriteRenderer;
void Start()
{
prefab = Resources.Load("Prefabs/pfItemWorld") as GameObject;
//myPrefab = Resources.Load("Prefabs/pfItemWorld");
}
public static ItemWorld spawnItemWorld(Vector3 position, Item item)
{
Transform transform = Instantiate(prefab, position, Quaternion.identity);
ItemWorld itemWorld = transform.GetComponent<ItemWorld>();
itemWorld.SetItem(item);
return itemWorld;
}
private void Awake()
{
spriteRenderer = GetComponent<SpriteRenderer>();
}
public void SetItem(Item item)
{
this.item = item;
Rect spriteRect = new Rect(0, 0, item.itemIcon.width, item.itemIcon.height);
Sprite mySprite = Sprite.Create(item.itemIcon, spriteRect, new Vector2(0.5f, 0.5f));
spriteRenderer.sprite = mySprite;
}
}
My problem is i cant manage to load my prefab and use it in Instantiate without many errors...
What is wrong with my code?
Here are the errors:
(1) Assets\Scripts\ItemWorld.cs(12,18): error CS0029: Cannot implicitly convert type 'UnityEngine.GameObject' to 'UnityEngine.Transform' (yes, i know what this means, but how can i use a prefab without transform)
(2)Assets\Scripts\ItemWorld.cs(17,43): error CS0120: An object reference is required for the non-static field, method, or property 'ItemWorld.prefab'
I have tried to research but this is my last hope xd
Ill be happy for ANY help,
thanks ahead,
Gambizon
Prefabs are GameObjects and need to be instantiated and declared as such. private transform prefab should be private GameObject prefab.
After you've instantiated the object with
GameObject prefabObject = Instantiate(prefab, position, Quaternion.identity);
You can then use Transform transform = prefabObject.transform; to get the transform component of your newly instantiated prefab.
Also, if you make the prefab reference in the script public, and have this script attached to a GameObject, you can drag the prefab into the inspector so that you don't need Resources.Load("Prefabs/pfItemWorld") as GameObject, as the reference will already be there before run time.
I want to have 3 objects doing different things, so I want to get the source of the caller.
I am using lambda for that, and I am not using key frame, the animation is the same and cyclic so I don't need to specify different behavior for a different key frame.
Maybe I am doing something wrong with the lambda?
this is my code:
class MyClock extends ClockPane //clockpane extends pane
{
Timeline animation;
int id;
EventHandler<ActionEvent> eventHandler = e ->
{//startAnimationById();
System.out.println(e.getSource()==clockControl1.myclock.animation);
};
public MyClock(int c,int id)
{
super(c);
this.id=id;
animation = new Timeline(new KeyFrame(Duration.millis(1000),eventHandler));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play();
}
the startanimationbyid method works using the id I defined to avoid this problem, but it surely does bug me.
I have 3 different objects of this type, each one is nested ina clockcontrol class
(in other words I have clockcontrol1 clockcontrol2 and 3 each one of these having a MyClock myclock in them)
The print I have there returns false for all the the clocks I have (total of 3) while as it is currently written I'd expect to get true for the first clock...I tried different variations of this, the one I post here is only the last variation, but I got false for all of my attempts.
Where did I mess things up?
The API for KeyFrame doesn't specify what the source of the ActionEvent will be. You could just do System.out.println(e.getSource()) to see (it seems that the source of the event is the KeyFrame object, not the animation), but there's no real guarantee it would always be what you expect.
If you want different instances of MyClock to behave differently, you can provide a parameter for the different behavior. In this case, you could use a Runnable to execute different code in the event handler:
class MyClock extends ClockPane //clockpane extends pane
{
Timeline animation;
// int id;
public MyClock(int c, Runnable handler)
{
super(c);
EventHandler<ActionEvent> eventHandler = e -> handler.run() ;
animation = new Timeline(new KeyFrame(Duration.millis(1000),eventHandler));
animation.setCycleCount(Timeline.INDEFINITE);
animation.play();
}
}
Then you can instantiate these as you need:
public class Controller1 {
// ...
MyClock clock = new MyClock(..., () -> {
// code to execute for this clock
});
}
and
public class Controller2 {
// ...
MyClock clock = new MyClock(..., () -> {
// code to execute for this clock
});
}
so I'm developing a game for android in LibGDX and I've stumbled upon a problem: I have a scene with an image in it and I want to be able to click/touch the image and make stuff happen after doing so.
I've been trying to google a solution for the past day but I keep on missing something vital. Here's my code:
public class ScreenSplash implements Screen {
private Texture textureGlobe = new Texture(Gdx.files.internal("graphics/splash.png"));
private Image imageGlobe = new Image((new TextureRegion(textureGlobe)));
public ScreenSplash() {
imageGlobe.addListener(new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
Gdx.app.log(Game.LOG, "image clicked");
return true;
}
});
stageGame.addActor(imageGlobe);
}
...
}
I've also heard that I'm supposed to put this somewhere:
Gdx.input.setInputProcessor(inputProcessor);
But I don't really know what to do with it.
Your Stage is your InputProcessor so do something like Gdx.input.setInputProcessor(stageGame);. The Stage will route the events to the actors.
Ah, I've found out what the problem was.
I imported java.awt.event.InputEvent instead of com.badlogic.gdx.scenes.scene2d.InputEvent and the touchDown function wasn't properly overriden because of this.
I wrote a wxPython program that I am translating to wxWidgets. The program has a scrolled window that displays an image. Following Rappin, wxPython In Action (Listing 12.1), I used a StaticBitmap within a panel. While surfing the latest wxWidgets documentation, I found a dire warning that wxStaticBitmap should only be used for very small images. It says, "... you should use your own control if you want to display larger images portably." Okay. Show me. I don't have my "own control."
Was Rappin wrong, or is the documentation out of date?
The question - a newbie one, no doubt - is what is the right way to do a simple image-view window in wxWidgets? A drop-in replacement for wxStaticBitmap would be nice. I looked into the "image" program in the wxWidgets "samples" directory. It's as long a War and Peace. Surely there must be a canned class or a simple recipe.
Don't let the size of the "image" sample fool you, only a few lines of code are necessary to do what you want.
Search for the MyImageFrame class in the image.cpp file, it is nothing more than a class with a private bitmap field, a custom constructor to set the bitmap and the window client size, and an event handler for EVT_PAINT:
void OnPaint(wxPaintEvent& WXUNUSED(event))
{
wxPaintDC dc( this );
dc.DrawBitmap( m_bitmap, 0, 0, true /* use mask */ );
}
Since you don't want a frame class here's your recipe: You create a simple descendant of wxWindow that has a similar constructor, paint handler and duplicates the methods of wxStaticBitmap that you use in your code. Maybe simply one method to set a new bitmap and resize the control to the new bitmap dimensions.
// A scrolled window for showing an image.
class PictureFrame: public wxScrolledWindow
{
public:
PictureFrame()
: wxScrolledWindow()
, bitmap(0,0)
{;}
void Create(wxWindow *parent, wxWindowID id = -1)
{
wxScrolledWindow::Create(parent, id);
}
void LoadImage(wxImage &image) {
bitmap = wxBitmap(image);
SetVirtualSize(bitmap.GetWidth(), bitmap.GetHeight());
wxClientDC dc(this);
PrepareDC(dc);
dc.DrawBitmap(bitmap, 0, 0);
}
protected:
wxBitmap bitmap;
void OnMouse(wxMouseEvent &event) {
int xx,yy;
CalcUnscrolledPosition(event.GetX(), event.GetY(), &xx, &yy);
event.m_x = xx; event.m_y = yy;
event.ResumePropagation(1); // Pass along mouse events (e.g. to parent)
event.Skip();
}
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
PrepareDC(dc);
dc.DrawBitmap(bitmap, 0,0, true);
}
private:
DECLARE_EVENT_TABLE()
};
BEGIN_EVENT_TABLE(PictureFrame,wxScrolledWindow)
EVT_PAINT(PictureFrame::OnPaint)
EVT_MOUSE_EVENTS(PictureFrame::OnMouse)
END_EVENT_TABLE()