I'm making a game in Unity 2D and was wondering if there was any way to do what I need.
Please check the image of Two items with hitting colliders.
When the player is activating both colliders and then the pick up button is pressed, the player equips both items. I want to disable one of the item's colliders when another item is nearby and then re-enable it when its by itself again. How should I go about doing this? I was thinking using a list but since both weapons use the same scripts (they're prefabs) I think that would create two lists that would serve no purpose and probably crash.
My initial check was to see if another item was nearby, and if so disable its collider, but it did that for both the items rendering both useless.
You can put a Boolean flag in the player code
something like :
if(hasWeapon == false)
{
//put pick up code here
}
so that if a weapon is selected, it will not be entered into the pick-up code until you drop the weapon.
Related
I want to have some prefabs already in the scene and then assign the players each one to control. The Input Manager is pretty clear for assigning prefabs when a player joins, but can this be changed later?
I know I can have a parent game object with several inactive prefabs as children and activate as needed, but this won't work with my current situation. Really need to just switch altogether if possible.
I'd like to use the "join manually" option which requires me to drag prefabs into the scene in the editor, then how do I assign players to them once the scene starts?
Something like:
if (GetComponent<PlayerInput>().playerIndex == 0)
{
"the player becomes prefab 1"
}
if (GetComponent<PlayerInput>().playerIndex == 1)
{
"the player becomes prefab 2"
}
I'm not sure how to access this by code (I'm pretty new) The input manager script appears uneditable, but before I realized this I tried adding some additional public game objects.
If i understand correctly your intend is to keep the players on scene while changing who controls them, right?
You should be able to get the player disconnected an reconnected to a new index without deleting the Player object from scene. Make shure you use methods properly using the docs: Player Input Manager Docs.
Otherwise I think you need an extra layer or some twist. Maybe keep the players on their indexes but change whos controlling the Player GameObjects?
By the way you can instantiate Prefabs by code using Instantiate()
You can also use inheritance to extend PlayerInputManager and maybe add some SwitchPlayer() function if really needed.
public class CustomPIM : PlayerInputManager {}
The custom class will inherit all methods from PlayerInputManager plus whatever you add.
I am working on a standard Top-Down 2D RPG. On my Player object, I have two colliders, one is a regular box collider 2D not marked as trigger handling the collisions and it is smaller than the player vertically. I have another box collider 2D which is marked as trigger, working as a hitbox of sort, and it covers the whole player-. While picking up items, I wanted to use the trigger collider so I used this code :
private void OnTriggerEnter2D(Collider2D other)
{
if (other.GetComponent<DroppedItem>() != null && other.isTrigger)
{
Debug.Log("Picked up item.");
DroppedItem item = other.GetComponent<DroppedItem>();
inventory.AddItem(item.item, item.itemAmount);
Destroy(item.gameObject);
}
}
The debug message is triggered twice each time I collide with the dropped item, which also has a trigger collider, even though I destroy the item afterwards. The debug message is also triggered twice if I mark the trigger collider as non trigger, or vice versa. How do I avoid this?
It seems that you need to have the collider on the player, and the trigger on the item. Then, a script needs to be attached to the item which calls a function on the player which adds items, and then in the script you can destroy the item. The only reason I can think of for why this is being called twice is that your script is on both the item and the player.
(Simple diagram with some pseudocode)
I am aware of using Physics.Collision to avoid collision between two certain objects. But I want their box colliders to be active so that it detects that they are in contact. Is there a way to achieve this?
Also after I have disabled collision using Physics.Collision(), can I reactivate the collision between the objects?
Physics.IgnoreCollision(obj2.GetComponent<Collider>(), this.GetComponent<Collider>());
In the Unity menu bar, go to Edit > Project Settings, then select the Physics category to open the Physics window. You will find a Matrix and here you can uncheck the collision between 2 layers. If you put the Player in a layer and the object you don't want to collide into in another layer and in the matrix you uncheck the box, everything will maintain his properties and the player won't collide with it.
See Physics.IgnoreCollision
ignore: Whether or not the collisions between the two colliders should be ignored or not.
Per default it is true.
To re-enable collisions you previously disabled simply pass in false.
Physics.IgnoreCollision(obj2.GetComponent<Collider>(), this.GetComponent<Collider>(), false);
If you don't want the objects to collide but register if they touch each other then make on of them a Trigger.
If the object is a trigger then it doesn't react to the collision but it fires an OnTriggerEnter.
See Colliders -> Triggers
The scripting system can detect when collisions occur and initiate actions using the OnCollisionEnter function. However, you can also use the physics engine
simply to detect when one collider enters the space of another without creating a collision. A collider configured as a Trigger (using the Is Trigger property) does not behave as a solid object and will simply allow other colliders to pass through. When a collider enters its space, a trigger will call the OnTriggerEnter function on the trigger object’s scripts
.
I am currently making a sidescrolling game in Unity 2D where an enemy rises up, and then dives down to the player, but then keeps going until it is off screen, like how this image shows. 1 I can get the enemy to collide with the player but I can't make it keeping in that direction until off screen. How would I be able to do this?
You have to make your collider to trigger (it's a checkbox on your collider)
That means your object will not be affected by physics when it touch another collider, but it can calls functions.
You have to replace OnCollisionEnter/OnCollisionEnter2D, etc by OnTriggerEnter/OnTriggerEnter2D, etc.
Be careful, the parameter of the function may change too (Collision/Collider).
In my game the user can spawn instantiated versions of 2 prefabs with mouse clicks: tiles and balls. The balls can be spawned over the tiles.
The user can also erase objects which have been spawned. This is achieved by placing the following code in a if(Input.GetMouseButtonDown(0))) block of the update method:
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition;
mousePos.z = canvas.transform.position.z;
Vector3 mousePosTrans = Camera.main.ScreenToWorldPoint(mousePos);
RaycastHit2D rayHit = Physics2D.Raycast(mousePosTrans, Vector2.zero);
if (eraserSelected)
{
Destroy(rayHit.collider.gameObject);
}
}
The objects intended for deletion are being deleted, but the problem is that other unrelated and distant objects are sometimes also simultaneously deleted. For example, if I spawn 2 squares and a ball on each square, then delete the first ball, when I go to delete the first square the second ball is simultaneously deleted. Sometimes when an object is deleted another object is simultaneously "un-deleted"!
Objects are spawned with the following code:
TileOrBall obj = (TileOrBall) Instantiate(tileOrBall, pos, Quaternion.identity);
obj.transform.SetParent(canvas.transform);
where TileOrBall is the class of the objects being spawned and tileOrBall is a reference to one of the two prefabs from this class.
So is there something wrong with the approach I'm taking to object spawning or destruction? How can I solve the simultaneous deletion (and sometimes resurrection) of distinct objects when trying to destroy an instance of these objects?
EDIT:
Adding link to zip file of project:
https://drive.google.com/open?id=0B28_MgFRWv97OWxfNE96LXcxZHc
To replicate the issue, click on the square in the side bar and "paint" squares in the grid wherever, then click on the ball in the side bar and "paint" over the squares that have been placed. Finally, click on the eraser icon and start deleting objects by clicking on them. You will see that objects you did not click on are deleted, and you may even see that objects are resurrected when you try deleting objects.
Thanks!
Found few problems in the Project.
1.When you do Destroy(unitAtMouse);, you are not deleting the GameObject from the raycast. You are ONLY deleting the Unit script that is attached to that GameObject.
Because this deletion failed, you will have multiple multiple Square GameObjects in one spot. That makes it harder to delete later on since you have to click delete multiple times until the last Square GameObjects is deleted.
To fix this, replace Destroy(unitAtMouse); with Destroy(unitAtMouse.gameObject);.
2.It is good to have the GameObject you are instantiating to be GameObject instead of script. For example public Unit selectedObject; should be public GameObject selectedObject;
3.Set eraserSelected to false when the square or circle in the side bar is clicked. This fixes problems that even user selects the square while again while in eraserSelected mode, they can delete or even create new square. You want to disable eraserSelected if square or circle in the side bar is clicked. In another word, if setSelectedObject is called.
4.The Erase Button should be under the panel like the other buttons too. Otherwise, it will go missing under some screen resolution.
5.Fixed enum to use the actual enum instead of enum.string.
6.Fix a problem that made the ball invisible which makes it look like it was deleted. What happens is that the ball is sent behind the square. Fixed this by making the ball sortingOrder to the 1 and the square sortingOrder to be 0.
Alternatively, building on #Programmer's response you could create a new script, say DeletableObject, that can be completely empty for the time being and attach this to the ball and square prefabs and any future prefabs you may have. Then in the suggested code above, change:
if (rayHit.collider.CompareTag("ball"))
to
if(rayHit.collider.GetComponent<DeletableObject>())
That way you can attach the script to any future prefabs you make to be able to delete them.
On a side note, if you're adding / deleting lots of objects and performance becomes an issue, look into Object Pooling. In fact, you should look into it anyway as it's a good habit to get into.