Search code examples
c#unity-game-enginerotationprojectiletopdown

Projectiles not moving, and not starting from the player (Unity 2D / C#)


INFO
So I am trying to make a top-down endless arena battle game, where your shield acts also as your means of offense. The shield should spawn infront of the player, and stay infront as the player moves and rotates (while holding down mouse1 (which it does)). Once mouse1 is released, the shield should shoot forward as a projectile.

PROBLEM
However, when mouse1 is let go of, the shield moves forward a small bit and then freezes, but no matter where the player is, they move as if the player is at 0, 0.

( I know this is a bit confusing so here is a photo: ) Projectiles moving from 0, 0 instead of player's position
( The triangle is the player )

CODE
This is my player controller script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public Rigidbody2D rb;

    public GameObject Shield;

    public float moveSpeed = 4.3f;
    public float sheildSpeed = 2f;
    
    Vector2 movement;

    bool isDead = false;

    void Update()
    {
        movement.x = Input.GetAxisRaw("Horizontal");
        movement.y = Input.GetAxisRaw("Vertical");

        Vector3 mouseScreen = Input.mousePosition;
        Vector3 mouse = Camera.main.ScreenToWorldPoint(mouseScreen);

        transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(mouse.y - transform.position.y, mouse.x - transform.position.x) * Mathf.Rad2Deg - 90); 

        if (Input.GetMouseButtonDown(0)) {
            Shield = Instantiate(Shield, transform.position + transform.forward + transform.up, transform.rotation);
            Shield.transform.parent = transform;
        }

        if (Input.GetMouseButtonUp(0)) {
            Shield.transform.parent = null;
        } 
    }

    void FixedUpdate() {
        if (!isDead) {
            rb.MovePosition(rb.position + movement * moveSpeed * Time.fixedDeltaTime);
        }
    }
}

and this is the sheild script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ShieldController : MonoBehaviour
{
    public float sheildSpeed = 2f;

    void FixedUpdate()
    {
        this.GetComponent<Rigidbody2D>().MovePosition(this.transform.up * sheildSpeed);       
    }
}

NOTE
I hope have provided enough information for you to be able to help me, but if you need / want more details just leave aaa comment and I will hopefully reply with whatever you need :)


Solution

  • Hey I tested this in my own project and got it working

    Change this

    void FixedUpdate()
    {
        this.GetComponent<Rigidbody2D>().MovePosition(this.transform.up * sheildSpeed);       
    }
    

    Into this

    public void LaunchForward(float speed)
    {
        this.GetComponent<Rigidbody2D>().velocity = transform.up * speed;
    }   
    

    I also edited the spawning a bit into this

    public GameObject Shield;
    public GameObject ShieldInstance;
    
    if (Input.GetMouseButtonDown(0))
        {
            if (ShieldInstance != null) { return; }
            ShieldInstance = Instantiate(Shield, transform.position + transform.forward + transform.up, transform.rotation);
            ShieldInstance.transform.parent = transform;
        }
    
    if (Input.GetMouseButtonUp(0))
        {
            ShieldInstance.transform.parent = null;
            ShieldInstance.GetComponent<ShieldController>().LaunchForward(5f);
            Destroy(ShieldInstance, 3f);
        }
    

    But the primary problem was the physics on the shield itself, the code was colliding with 2 functions which caused the weird behaviour I think

    Edit: Setting the velocity is required only once, so a dedicated method is appropriate here (credit derHugo). Although you could have this method in the player class, having it in its own class is better if you want to have more complex behaviour in your game

    Was this intended?

    Into this