I'm working on a little 2d game where you control a planet to dodge incoming asteroids. I'm implementing gravity in the following manner:
public class Gravity : MonoBehaviour
{
Rigidbody2D rb;
Vector2 lookDirection;
float lookAngle;
[Header ("Gravity")]
// Distance where gravity works
[Range(0.0f, 1000.0f)]
public float maxGravDist = 150.0f;
// Gravity force
[Range(0.0f, 1000.0f)]
public float maxGravity = 150.0f;
// Your planet
public GameObject planet;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
// Distance to the planet
float dist = Vector3.Distance(planet.transform.position, transform.position);
// Gravity
Vector3 v = planet.transform.position - transform.position;
rb.AddForce(v.normalized * (1.0f - dist / maxGravDist) * maxGravity);
// Rotating to the planet
lookDirection = planet.transform.position - transform.position;
lookAngle = Mathf.Atan2(lookDirection.y, lookDirection.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, lookAngle);
}
}
The problem is that the asteroids are attracted to the initial spawn point of the planet (0,0), it doesn't update in real time with the movement of the planet. So if I move the planet to the corner of the screen, the asteroids are still attracted to the centre of it.
When I use Debug.Log for each value all change except for planet.transform.position that stays at 0,0,0 even after moving it.
Is it a problem with the rigidbody of the planet? Any settings? I'm a bit lost.
Is there a way to solve this?
Thank you very much and excuse any flagrant errors!
Because the asteroids were dynamically spanwed from a prefab, they weren't a gameobject, the planet selected on the gameobject variable on the script was the prefab, not the real gameobject on the scene. I had to add this line to my spawner script
if (interval > random) {
GameObject newAsteroid = Instantiate(asteroidPrefab,
GetRandomPosition(), Quaternion.identity);
newAsteroid.GetComponent<Gravity>().planet = planet;
}
and at the top in your variables add
public GameObject planet;
add in your spawner script in the editor, drag and drop your planet
gameobject.
This fixed the issue.
Related
I Have a gun that spawn a projectile that bounces of colliders (a Ricochet). It is supposed to be shooting to the direction of where the gun is facing but what I am getting is the projectile always shoots 45 degrees upwards to the right I know this is because of my constant declared vector 2.
I tried using Vector2.up but it prevents the projectile to do the ricochet effect because it always wants to go upwards.
How should I implement those things? I just want the projectile to shoot to the direction where my gun is facing and bounces of on colliders. This is a 2D game btw. I have my codes attached below so you can see. Thanks!
Projectile Script:
private Rigidbody2D rb;
public static bool canMove = true;
void Start()
{
rb = GetComponent<Rigidbody2D>();
rb.velocity = new Vector2(10f, 10f);
}
void Update()
{
//transform.Translate(Vector2.up * speed * Time.deltaTime);
if (canMove)
{
rb.isKinematic = false;
}
else if (!canMove)
{
rb.isKinematic = true;
}
}
Gun Script:
float offset = -90f;
public GameObject projectile;
public Transform shotPoint;
public GameObject child;
void Start()
{
}
void Update()
{
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
float rotZ = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(0f, 0f, rotZ + offset);
if (Input.GetMouseButtonDown(0))
{
Instantiate(projectile, shotPoint.position, transform.rotation);
Projectile.canMove = true;
}
}
The Rigodbody.velocity is in World-Space coordinates.
When you pass in
rb.velocity = new Vector2(10f, 10f);
it will go in world space 10 in X and 10 in Y direction.
In order to pass it in as local coordinates in general you can not always rely on Tramsform.InverseTransformDirection as suggested here since the Transform component. In this specific case it might work but in general you set velocities in FixedUpdate and in that moment the Transform component might not be updated yet!
But the Rigidbody2D component is so in general you can use Rigidbody2D.GetRelativeVector in order to convert a local vector relative to the Rigidbody into world coordinates:
// Might also be Vector.up depending on your setup
rb.velocity = rb.GetRelativeVector(Vector2.right * speed);
Note: it would be better you make
[SerializeField] private Rigidbody2D rb;
and already reference it via the Inspector. Then you can get rid of the expensive GetComponent call.
Because you are telling it to do so.
rb.velocity = new Vector2(10f, 10f);
10 to the right, and 10 upwards.
Unless your projectile has a constant force applied to it, like a missile, get rid of everything related to forces or velocity in the projectile script. It will do you no good.
Then, on the gun script:
//...
if (Input.GetMouseButtonDown(0)) {
var projectileInstance = Instantiate(projectile, shotPoint.position, transform.rotation);
var rigidbody = projectileInstance.GetComponent<Rigidbody2D>();
rigidbody.velocity = transform.TransformDirection(yourDirectionVector);
Projectile.canMove = true;
}
Where Transform.TransformDirection is what makes yourDirectionVector, which is a direction relative to the gun, be transformed into one relative to world-space.
I am currently working on an multiplayer shooter game. Basicly atm you play as a cube and you have your hand(red square) following the cursor ingame.
I want to restrict the cursor movement to a perfect circle around my player sprite.
See attached picture for clarification.
https://imgur.com/TLliade
Following script is attached to the "Hand" (red square).
public class Handscript : MonoBehaviour
{
void Update()
{
Cursor.visible = false;
Vector3 a = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
a.Set(a.x, a.y, transform.position.z);
transform.position = Vector3.Lerp(transform.position, a, 1f);
}
}
Now I want to restrict cursor movement inside my radius that is a public transform attached to my Player prefab like this:
//Hand radius
public float radius;
public Transform centerRadius;
I am hard stuck and new to coding overall and I could use a push in the right direction.
Basicly the same question is asked here if I am being to unclear:
https://answers.unity.com/questions/1439356/limit-mouse-movement-around-player.html
EDIT: My goal in the end is to have similar hand movement as in the legendary "Madness Interactive" game, found here:
https://www.newgrounds.com/portal/view/118826
EDIT2: It might be impossible to lock the cursor inside the radius circle. Is it possible to just have the GameObject "Hand" locked inside this radius?
EDIT3: This is the code I use and it works like a charm:
using System;
using UnityEngine;
public class Handscript : Photon.MonoBehaviour
{
[SerializeField] private GameObject Player2; //Drag your player game object here for its position
[SerializeField] private float radius; //Set radius here
public new PhotonView photonView; //Never mind this if its not a photon project
private void Start()
{
Cursor.visible = false;
}
void Update()
{
if (photonView.isMine) //Never mind this if statement if it isnt a photon project
{
Vector3 cursorPos = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0));
Vector3 playerPos = Player2.transform.position;
Vector3 playerToCursor = cursorPos - playerPos;
Vector3 dir = playerToCursor.normalized;
Vector3 cursorVector = dir * radius;
if (playerToCursor.magnitude < cursorVector.magnitude) // detect if mouse is in inner radius
cursorVector = playerToCursor;
transform.position = playerPos + cursorVector;
}
}
#if UNITY_EDITOR
private void OnDrawGizmosSelected()
{
UnityEditor.Handles.DrawWireDisc(transform.parent.position, Vector3.back, radius); // draw radius
}
#endif
}
Get vector from the player to the cursor:
Vector3 playerToCursor = cursorPos - playerPos;
Normalize it to get the direction:
Vector3 dir = playerToCursor.normalized;
Multiply direction by your desired radius:
Vector3 cursorVector = dir * radius;
Add the cursor vector to the player position to get the final position:
Vector3 finalPos = playerPos + cursorVector;
I am trying to make a game where a ball will be ricocheting off several different colliders on screen. Based on what I researched I got some code that seemed to make sense at first but does not seem to work at all. I am testing it out just by having the ball fall down onto a 2D floor with a box collider attached to it. However once it collides with the floor it just stops there and doesn't bounce back up. I tried disabling "Queries Start in Colliders" in the project settings and offsetting the origin position of the RaycastHit2D so that it would not detect the collider its attached to but that still didn't work. I don't think the RaycastHit2D is working at all because it doesn't even display anything in the console. Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBehavior : MonoBehaviour {
Rigidbody2D rigidbody;
public Vector2 startPos;
public float speed;
public float hitOffset;
Vector3 vector = new Vector3(0, 5,0); //used to offset origin point of RaycastHit2D hit
private void OnEnable()
{
rigidbody = GetComponent<Rigidbody2D>();
this.transform.position = startPos;
}
private void Update()
{
transform.Translate(Vector2.down * speed * Time.deltaTime);
RaycastHit2D hit = Physics2D.Raycast(transform.position + vector, - transform.up, speed * Time.deltaTime + hitOffset);
Debug.DrawRay(transform.position, -transform.up, Color.red);
Ray2D ray = new Ray2D(transform.position, -transform.up);
if (hit)
{
Debug.Log(speed * Time.deltaTime + hitOffset);
Debug.Log(hit.collider.name);
Vector2 reflectDir = Vector2.Reflect(ray.direction,hit.normal);
float rotation = Mathf.Atan2(reflectDir.y, reflectDir.x) * Mathf.Rad2Deg;
transform.eulerAngles = new Vector3(0, 0, rotation);
}
}
}
Is my math bad? Any help is very appreciated, thanks.
When player shoot, the bullet fly to the center of the screen. But if player stay too close to some object, then bullet hits it not in the center, because it flies from the gun on the right side of the screen. How can I fix this?
public Rigidbody projectile;
public int speed = 50;
public Transform startBulletPosition;
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
Rigidbody clone;
clone = Instantiate(projectile, startBulletPosition.position, transform.rotation) as Rigidbody;
var centre = new Vector3(0.5f, 0.5f, 0f);
var ray = Camera.main.ViewportPointToRay(centre);
clone.velocity = ray.direction * speed;
}
}
public Rigidbody projectile;
public Transform startBulletPosition;
public float speed;
public float rotationSpeed;
public Camera camera;
Vector3 startingDirection;
void Start() {
startingDirection = startBulletPosition.transform.forward;
}
void Update() {
if (Input.GetButtonDown("Fire1")) {
RaycastHit hit;
Vector3 targetDirection;
if (Physics.Raycast(Camera.main.transform.position, camera.transform.forward, out hit)){
targetDirection = hit.transform.position - startBulletPosition.position;
} else {
targetDirection = startingDirection;
}
Vector3 newDirection = Vector3.RotateTowards( startBulletPosition.transform.forward, targetDirection, rotationSpeed * Time.deltaTime, 0.0f);
startBulletPosition.transform.forward = newDirection;
Rigidbody clone;
clone = Instantiate(projectile, startBulletPosition.position, startBulletPosition.rotation) as Rigidbody;
clone.velocity = targetDirection * speed;
}
}
I would do a Raycast from the Camera Position to see what you can hit and then rotate the weapon to that direction. As in my Example Code. The weapon will point to exactly Center View on what your camera Raycast hits.
Also you can control the max turnspeed by that public float. This will make for a nice weapon movement and not just instantaneous jumps.
Here are the docu links of what I used in this snippet:
https://docs.unity3d.com/ScriptReference/RaycastHit.html
https://docs.unity3d.com/ScriptReference/Vector3.RotateTowards.html
If the raycast misses, the stored original direction of the weapon will be used. (Assuming startBulletPosition is the transform of the weapon...)
If you want, you can add the maxDistance Parameter to the Physics.Raycast call to limit the distance on which this behaviour is active.
I have been writing a script for enemy movement in my game, but when the target(Player) jumps, the enemy begins to gradually float up to the same y position the target was in. I would like it if the enemy stayed at the same position as the ground, but I have not found out how I would be able to do that. I am new to Unity, so the only thing I could think of was adding a rigidbody to the enemy but that did not seem to work. Would anyone have any Idea on how to do this? Here is my script:
public class EnemyMovement : MonoBehaviour {
//target
public Transform Player;
//the distace the enemy will begin walking towards the player
public float walkingDistance = 10.0f;
//the speed it will take the enemy to move
public float speed = 10.0f;
private Vector3 Velocity = Vector3.zero;
void Start(){
}
void Update(){
transform.LookAt (Player);
//finding the distance between the enemy and the player
float distance = Vector3.Distance(transform.position, Player.position);
if(distance < walkingDistance){
//moving the enemy towards the player
transform.position = Vector3.SmoothDamp(transform.position,
Player.position, ref Velocity, speed);
}
}
Just set the y value before doing the movement
public class EnemyMovement : MonoBehaviour {
//target
public Transform Player;
//the distace the enemy will begin walking towards the player
public float walkingDistance = 10.0f;
//the speed it will take the enemy to move
public float speed = 10.0f;
private Vector3 Velocity = Vector3.zero;
void Start(){
}
void Update(){
transform.LookAt (Player);
Vector3 target = Player.position;
target.y = transform.position.y;
//finding the distance between the enemy and the player
float distance = Vector3.Distance(transform.position, target);
if(distance < walkingDistance){
//moving the enemy towards the player
transform.position = Vector3.SmoothDamp(transform.position,
target, ref Velocity, speed);
}
}