How to change Polygon Collider based on my animation in Unity3d? - unity3d

I have a small car game, and when I move up/down and left/right, the sprite becomes different. But the physicsbody remains the same. How do I adjust physicsbody? I added a screenshot of my sprite. At the moment I have Polygon physics body as on the right one.
Here is the code that adjusts animation states:
void FixedUpdate()
{
if (Input.GetKey(KeyCode.W)) {
rb2d.AddForce(Vector2.up * physicsConstant);
animator.CrossFade("CarUpIdle", 0);
} else if (Input.GetKey(KeyCode.S)) {
rb2d.AddForce(-Vector2.up * physicsConstant);
animator.CrossFade("CarDownIdle", 0);
} else if (Input.GetKey(KeyCode.D)) {
rb2d.AddForce(Vector2.right * physicsConstant);
animator.CrossFade("CarRightIdle", 0);
} else if (Input.GetKey(KeyCode.A)) {
rb2d.AddForce(-Vector2.right * physicsConstant);
animator.CrossFade("CarLeftIdle", 0);
}
}

To Change polygon based on sprite first you will need to have Serializefield variables to keep track of all the respective colliders. In this script basically what I do is I am keeping all the polygon colliders in array and iterate the array and enable it depending upon the sprite.
In the script im putting the required sprites along with the respective collider for sprite in sequence. So when I request the sprite to change I enable the respective collider and disables the other colliders. You will require something similer like this :
[SerializeField]
private Sprite[] Sprites;
[SerializeField]
private PolygonCollider2D[] Colliders;
private int index = 0;
private SpriteRenderer sp;
void Start () {
sp = GetComponent<SpriteRenderer>();
sp.sprite = Value[index];
}
void OnGUI() {
if(GUI.Button(new Rect(0,0, 80,35), "ChangeSprite")) {
colliders[index].enabled = false;
index ++;
if(index > Value.Length -1) {
index = 0;
}
sp.sprite = Sprites[index];
colliders[index].enabled = true;
}
}
Also in this tutorial it has been explained how to tackle this kind of problem
Unity Game Tutorial
Another way to proceed is to remove the ploygon collider and recreate it
Destroy(GetComponent<PolygonCollider2D>());
gameObject.AddComponent<PolygonCollider2D>();
though this is very bad programming considering I will be creating collider on every sprite change which is heavy on game.

Related

Sibling sprite doesn't appear to follow main GameObject sprite even when transform.position updates

Following this question How to align sprites of smaller sizes to a moving gameobject sprite?, I'm trying to redraw my sprites to avoid rendering transparent pixels and try to maximize performance, and as I try starting this process with the sword sprites, I need to change the way the Sword game object follows the Player, which before was handled simply by using transform.position = hero.transform.position; because since both objects use sprites that are perfect squares they would have the same pivot point despite their size difference.
At first, it seemed to me the problem lied in how the pivots are different, thus I would need to update the transform position of the Sword every time its attack animation changes sprites. For that, I made a function which updates variables that influence the position as that gets updated:
here, heroTransform is a variable which gets sent the Player's transform property on the script's Start function as heroTransform = hero.transform;, where hero is defined right above it as hero = GameObject.Find("Hero");.
I would have expected this to make the Sword which is equipped with this script, called WieldablePosition to follow the player position, but it seems stuck in the same position as it starts:
I'm not sure, but I don't think I changed anything that would stop the Sword from moving. In what cases could a GameObject remain in a single place even as the transform.position is modified? For reference, please view the script:
using UnityEngine;
public class WieldablePosition : MonoBehaviour {
GameObject hero;
HeroMovement heroMovementScript;
private Transform heroTransform;
protected Animator anim;
private bool isAirAttackSingle;
private bool isFacingLeft;
private float x = 0;
private float y = 0;
void Start() {
hero = GameObject.Find("Hero");
heroTransform = hero.transform;
heroMovementScript = hero.GetComponent<HeroMovement>();
anim = GetComponent<Animator>();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
}
void Update() {
UpdatePosition();
isAirAttackSingle = heroMovementScript.isAirAttackSingle;
isFacingLeft = heroMovementScript.isFacingLeft;
anim.SetBool("isAirAttackSingle", isAirAttackSingle);
if (isFacingLeft) {
transform.localScale = new Vector3(-1, 1, 1);
} else {
transform.localScale = Vector3.one;
}
}
public void SetPosition(AnimationEvent eventParams) {
string[] eventPositions = eventParams.stringParameter.Split(',');
x = float.Parse(eventPositions[0]);
y = float.Parse(eventPositions[1]);
}
private void UpdatePosition() {
transform.position = new Vector2(heroTransform.position.x + x, heroTransform.position.y + y);
}
}

How to move 2d Rigidbody Smoothly to Mouse on Click

Vector2 mousePos = Input.mousePosition;
// motion core
if (GameObject.Find("Camera").GetComponent<room>().playerNum == 1)
{
if (Input.GetMouseButtonDown(0))
{
// move script not working
}
}
So, I have mostly every possible solution I could find but none of them worked. I cannot get it to smoothly move with AddForce because I could not figure out a working algorithm to make the force move toward the MousePosition.
The position you're getting out of Input.mousePosition are the coordinates on the screen, not the position in the world. To transform between the two, you can use Camera.ScreenToWorldPoint().
if (Input.GetMouseButtonDown(0))
{
Vector3 mousePos = Input.mousePosition
mousePos = new Vector3(mousePos.x, mousePos.y, Camera.main.nearClipPlane)
Vector3 worldPos = Camera.main.ScreenToWorldPoint(new Vector3())
// move script
}
You might need to edit the z coordinate in the mousePos to the current transform.position.z of the object you're trying to move, or another value that makes most sense here. It acts as a kind of wall, where it'll create the point exactly that far from the camera on your mouse position. This should be a lot cheaper than raycasting, and still works if there's nothing to hit where you're clicking.
I have a script that did this same movement to the handle of a wrecking ball, but I don't have the code with me at the moment. I can't remember exactly how it worked, but I think the idea was that when the mouse was clicked, drag would be set to a very high number and gravity would be set to 0. Then an extremely strong force would be added to counter the drag so that the object would fly towards the mouse without orbiting. When the mouse was released, the drag and gravity would be set back to normal.
I can't test this at the moment because I'm on a chromebook and my PC with Unity on it is in another building, but this code should do the trick if I don't make any errors.
using UnityEngine;
public class ExampleClass : MonoBehaviour
{
float prevDrag, prevGrav;
bool mousedown;
Plane plane;
Rigidbody2D r;
void Start()
{
r = GetComponent<Rigidbody2D>(); // assuming this script is attached to the object being moved.
plane = new Plane(Vector3.up, Vector3.zero);
}
void Update()
{
if(mousedown)
{
float enter;
if (plane.Raycast(ray, out enter))
{
var hitPoint = ray.GetPoint(enter);
var mouseDir = hitPoint - gameObject.transform.position;
rb.AddForce(mouseDir * 9999999);
}
}
}
void OnMouseDown()
{
mousedown = true;
prevDrag = r.drag;
prevGrav = r.gravity;
r.drag = 99999;
r.gravity = 0;
}
void OnMouseUp()
{
mousedown = false;
r.drag = prevDrag;
r.gravity = prevGrav;
}
}

unity add object on touched place on screen(rotation)

hello guys i have a code that clone an object on the touched area on game and i have a button that change the rotation of the object (the y rotation by 25 deg),i want when i touch the screen that the clone objects will also change by the current rotation of the object. thank you guys
private Rigidbody myrigidbody;
void Start()
{
myrigidbody = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.touchCount > 0)
{
var touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Began)
{
var pos = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 10f));
myrigidbody.MovePosition(new Vector3(pos.x, pos.y, 0f));
}
}
}
Gonna follow up on TEEBQNE here,
you need a way to reference all cubes if you want all of them to rotate. If you are just testing right now, you can tag all cube objects with a certain name like "cube" and use FindGameObjectsWithTag() function to iterate through all of the object types.
So you can change your function from this
public void firstAngle() {
cube.transform.Rotate(0f, 22.5f, 0.0f);
}
To this
public void firstAngle() {
foreach (GameObject obj in FindGameObjectsWithTag("cube")){
obj.transform.Rotate(0f, 22.5f, 0.0f);
}
}
Of course if you want better conventions as suggested in the comments, you can just replace the FindGameObjectsWithTag with a reference to all the cubes in the scene. This can either be an array, list, etc

Can I have two colliders attached to my enemy that do different things and if so how?

Is it possible to have two colliders for one object?
My situation is that I have a CircleCollider2D that causes my enemy to chase the player when it enters. This works well but I want to also have a BoxCollider2D that will switch scene to my scene called "BattleScene" when the player enters.
I want it so that when my player enters the circle collider my enemy will follow him but when the player gets closer and enters the box collider (both attached to the enemy) it will switch scenes to the scene called "BattleScene".
Another alternative I thought of was using a rigid body collision but I don't know how to implement that.
Here is my code
private bool checkContact;
private bool checkTrigger;
public float MoveSpeed;
public Transform target;
public Animator anim;
public Rigidbody2D myRigidBody;
BoxCollider2D boxCollider;
public string levelToLoad;
// Start is called before the first frame update
void Start()
{
target = GameObject.FindGameObjectWithTag("Player").GetComponent<Transform>();//getting the position of our player
anim = GetComponent<Animator>();
myRigidBody = GetComponent<Rigidbody2D>();
boxCollider = gameObject.GetComponent<BoxCollider2D>();
}
// Update is called once per frame
void Update()
{
if (checkTrigger == true)
{
transform.position = Vector2.MoveTowards(transform.position, target.position, MoveSpeed * Time.deltaTime); //move towrds from your position to the position of the player
if (myRigidBody.position.y < target.position.y && Mathf.Abs(target.position.y - myRigidBody.position.y) > Mathf.Abs(target.position.x - myRigidBody.position.x)) //if it is further away from target in x direction than y direction the animation for moving in y is loaded and vice versa
{
anim.SetFloat("MoveY", 1);
anim.SetFloat("MoveX", 0);
}
if (myRigidBody.position.y > target.position.y && Mathf.Abs(target.position.y - myRigidBody.position.y) > Mathf.Abs(target.position.x - myRigidBody.position.x))
{
anim.SetFloat("MoveY", -1);
anim.SetFloat("MoveX", 0);
}
if (myRigidBody.position.x > target.position.x && Mathf.Abs(target.position.y - myRigidBody.position.y) < Mathf.Abs(target.position.x - myRigidBody.position.x))
{
anim.SetFloat("MoveX", -1);
anim.SetFloat("MoveY", 0);
}
if (myRigidBody.position.x < target.position.x && Mathf.Abs(target.position.y -myRigidBody.position.y) < Mathf.Abs(target.position.x - myRigidBody.position.x))
{
anim.SetFloat("MoveX", 1);
anim.SetFloat("MoveY", 0);
}
anim.SetBool("checkTrigger", checkTrigger); //updating if in range
}
}
public void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.name == "Player")
{
checkTrigger = true; //setting our check trigger = true so it will follow if in radius
anim.SetBool("checkTrigger", checkTrigger);
}
}
public void OnTriggerExit2D(Collider2D other)
{
if (other.gameObject.name == "Player")
{
checkTrigger = false; //setting our check trigger = false so it will not follow if not in radius
anim.SetBool("checkTrigger", checkTrigger);
}
EDIT: THIS PROBLEM HAS BEEN RESOLVED
The best way to handle this is by having an empty GameObject with the other collider attached to it, while making sure both GameObjects have a Rigidbody - the child with IsKinematic ticked. Why? Because this will separate the child GameObject from the parent collision structure. Read more about compound colliders.
You should only have more than one collider in one GameObject if they all make part of the same collision structure. If they have different purposes, use different GameObjects with kinematic Rigidbodies, each handling it's own task.
In your specific scenario, I would have the CircleCollider in the enemy itself and the BoxCollider in a child GameObject with a kinematic Rigidbody. This child GameObject can also contain a script with the sole purpose of checking against the Player and loading the BattleScene.

How to add score in Unity2D?

Firstly hi to all! I am just trying to learn unity from basics. I am trying to write a code, shortly explain, golds and bombs dropping from the upside and we are trying to catch.
But in my code, bombs are fully working well but coins not working. Just nothing happening when coins touch my character. Coins have to destroy themselves and they must add +10 to my score.
Updated&Tested
For a 2D game, add a BoxCollider2D and a Rigidbody2D onto your character's GameObject. Set the coin object's BoxCollider's isTrigger bool to true in the inspector.
Add this to your player/character script.
int score = 0;
public UnityEngine.UI.Text scoreText; //in Unity, drag a text component here.
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Coin")
{
score += 10;
scoreText.text = score.toString();
collision.gameObject.SetActive(false);
}
}
For a 3D game, add a standard BoxCollider and a Rigidbody onto your character's GameObject. Set the coin object's BoxCollider's isTrigger bool to true in the inspector.
Add this to your player/character script:
int score = 0;
public UnityEngine.UI.Text scoreText; //in Unity, drag a text component here.
private void OnTriggerEnter2D(Collider collision)
{
if(collision.gameObject.tag=="Coin")
{
score += 10;
scoreText.text = score.toString();
collision.gameObject.SetActive(false);
}
}