Run an event when my GameObject has a chosen position in Unity3D - c#

my GameObject (Rocket) does fly up when I start the level (Its a 2D Game).
Now I want code it so, that my Rocket will do something when it will arrive at the position for example (0,0,0) but it does not start at 0 it starts something like (0,-15,0).
I tried to code that but it does not work, I checked already that it arrives for 100% at (0,0,0) but I dont understand why it does not run my code when this happen.
My Code:
public class Flying : MonoBehaviour
{
public float speed = 5f;
private void FixedUpdate()
{
transform.position += new Vector3(0, 1, 0) * (Time.deltaTime * speed);
//Check if my Rocket arrives at (0,0,0)
if (transform.position == new Vector3(0,0,0))
{
Debug.Log("I'm here!");
speed = 3f;
}
}
}
Any idea how to solve that?

I solve the problem with another GameObject that is invisible and have Collider2D on it with Rigidbody2D. Now when my Rocket touches the invisible GameObject the speed will change.
I hoped that I could code that easier.
My final code:
public class Flying : MonoBehaviour
{
public float Speed = 5f;
private void FixedUpdate()
{
transform.position += new Vector3(0, 1, 0) * (Time.deltaTime * Speed)
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.name == "Slow")
{
Speed = 3f;
}
}
}

Related

Enemy is moving in a jittery way and I do not know how to solve this

I am new to Unity and I was working on the enemy's movement of my first video game with C#.
The thing is that whenever the enemy follows the main character, it moves in a very jittery way and I do not know why. I tried a lot of solutions including a different code approach but notthing worked. I tried changing some configurations in its rigid body like collision detection but nothing happend.
This is the code of my enemy:
public class Black : Enemy
{
public float checkRadius;
public float attackRadius;
public bool shouldRotate;
public LayerMask lm;
private Rigidbody2D bd;
private Vector2 movement;
public Vector3 dir;
private bool isInchaseRange;
private bool isInattackRange;
// Start is called before the first frame update
void Start()
{
Debug.Log("Jugador " + player.name);
bd = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
isInchaseRange = Physics2D.OverlapCircle(transform.position, checkRadius, lm);
isInattackRange = Physics2D.OverlapCircle(transform.position, attackRadius, lm);
dir = player.position - transform.position;
dir.Normalize();
movement = dir;
}
void FixedUpdate() {
if (isInchaseRange && !isInattackRange) {
MoveCharacter(movement);
}
if (isInattackRange)
{
bd.velocity = Vector2.zero;
}
}
private void MoveCharacter(Vector2 dir) {
transform.position = Vector2.MoveTowards(transform.position, player.position, speed * Time.deltaTime);
}
}
This is how I move my main character if it helps you
public class PlayerMovement : MonoBehaviour
{
public float speed;
private Rigidbody2D rb;
private Vector2 moveAmount;
public float health;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
Vector2 moveInput = new Vector2(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));
moveAmount = moveInput.normalized * speed;
}
void FixedUpdate()
{
move();
}
void move()
{
rb.MovePosition(rb.position + moveAmount * Time.fixedDeltaTime);
}
public void takeDamage(int damageAmount)
{
health -= damageAmount;
if (health <= 0)
{
Destroy(gameObject);
}
}
}
The character has the same stuff as the enemy: Script, box collider 2d, rigid body
Any ideas on how to solve this?
As you can see by the gif it is not working as it should
https://im2.ezgif.com/tmp/ezgif-2-fbffacda5a27.gif
Thanks
Try making the chase range huge and attack range very small and see if it still moves in a jittery way to make sure it's not jittering because it's going in and out of range very quickly.
Set Rigidbody2D to interpolate from the inspector.
Also for the player, use Time.deltaTime instead of Time.fixedDeltaTime. Although this probably isn't related to your problem, this will give more smooth movement for the player. Time.fixedDeltaTime is just for setting the target you want the unity to stay at, but it will never precisely achieve that frametime. And Time.deltaTime will return the correct value based on whether it's called from Update() or FixedUpdate()
When this is called from inside MonoBehaviour.FixedUpdate, it returns Time.fixedDeltaTime. - Unity Docs

FPS Projectile firing from the wrong place

I'm trying to make a basic FPS game in Unity and I'm having an issue where the projectiles I shoot won't instantiate in the right place. From what I can tell, the projectile instantiates in roughly the same position relative to the player regardless of where I look (that position being a little to the left of the starting angle of the player).
Here's a 20 second video demonstration of what I'm talking about.
https://youtu.be/WLVuqUtMqd0
Even when I'm facing the exact opposite direction of where the projectile usually instantiates it still spawns in the same place, which means the projectile ends up spawning behind the player and hitting the player.
I tried using Debug.DrawRay() to see if maybe the firepoint itself is wrong (which would be shown by the ray starting somewhere other than the gun barrel). However it seems like the starting point of the ray is correct every time.
I'm not sure if this is related to the issue above, but I have noticed that the ray direction is wrong if I'm looking a little below the horizon. It seems like the projectile's direction is correct regardless though.
Ray directions when looking slightly above the horizon vs. lower
Here's my code for intantiating/shooting the projectile. I think the most relevant parts are probably shootProjectile() and instantiateProjectile(). This script is attached to the player character.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting : MonoBehaviour
{
public Camera cam;
public GameObject projectile;
public Transform firePoint;//firePoint is set to the end of the barrel.
public float projectileSpeed = 40;
//private var ray;
private Vector3 destination;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
//var ray = cam.ViewportPointToRay(new Vector3(0.5f,0.5f,0));
//Debug.DrawRay(ray.origin, ray.direction);
if(Input.GetButtonDown("Fire1")) {
//player is shooting
ShootProjectile();
}
}
void ShootProjectile() {
Ray ray1 = cam.ScreenPointToRay(Input.mousePosition);
//Debug.Log(ray.direction);
RaycastHit hit;
if(Physics.Raycast(ray1, out hit))//checking whether the player is going to hit something
{
destination = hit.point;
}
else {
destination = ray1.GetPoint(1000);
}
Debug.DrawRay(firePoint.position, destination, Color.white, 10f);
InstantiateProjectile(firePoint);
}
void InstantiateProjectile(Transform firePoint) {
var projectileObj = Instantiate (projectile, firePoint.position, Quaternion.identity) as GameObject;//projectile is instantiated
projectileObj.GetComponent<Rigidbody>().velocity = (destination - firePoint.position).normalized * projectileSpeed;//projectile is set in motion
}
}
Here's the location of firePoint.
firePoint (i.e. where the projectile should instantiate)
I would appreciate any help on this, as I've been trying to fix it (on and off) for several days, and really have no idea what the problem is.
Edit: Here's my player movement script(s) as well. The first one is PlayerController.cs, and it converts the player's inputs into the appropriate movement vectors and camera rotation. It then calls methods from PlayerMotor.cs, which actually performs the movements.
PlayerController
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(PlayerMotor))]
public class PlayerController : MonoBehaviour
{
[SerializeField]
public float speed = 10f;
[SerializeField]
private float lookSens = 3f;
private PlayerMotor motor;
void Start() {
motor = GetComponent<PlayerMotor>();
//Debug.Log("PlayerControllerStart");
Cursor.lockState = CursorLockMode.Locked;
}
void Update() {
//Debug.Log("PlayerControllerUpdate");
//calculate movement velocity as 3D vector.
float xMov = Input.GetAxisRaw("Horizontal");
float zMov = Input.GetAxisRaw("Vertical");
Vector3 movHorizontal = transform.right * xMov;
Vector3 movVertical = transform.forward * zMov;
Vector3 velocity = (movHorizontal + movVertical).normalized * speed;
motor.move(velocity);
//speed*=(float)1.15;
//rotation
float yRot = Input.GetAxisRaw("Mouse X");
Vector3 rotation = new Vector3 (0f, yRot, 0f) * lookSens;
motor.rotate(rotation);
float xRot = Input.GetAxisRaw("Mouse Y");
Vector3 cameraRotation = new Vector3 (xRot, 0f, 0f) * lookSens;
motor.rotateCamera(cameraRotation);
if (Input.GetKeyDown(KeyCode.Space) == true && motor.isGrounded()) {
motor.canJump=true;
}
if (Input.GetKey(KeyCode.W) == true) {
motor.accel=true;
}
else{
motor.accel=false;
}
}
}
PlayerMotor:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class PlayerMotor : MonoBehaviour
{
[SerializeField]
private Camera cam;
private Vector3 velocity = Vector3.zero;
private Vector3 rotation = Vector3.zero;
private Vector3 cameraRotation = Vector3.zero;
private Vector3 jumpVector = new Vector3 (0f, 5f, 0f);
private PlayerController pc;
private Rigidbody rb;
public bool canJump;
public bool accel;
public float acceleration;
int jumpCount;
void Start() {
rb = GetComponent<Rigidbody>();
pc = GetComponent<PlayerController>();
canJump=false;
jumpCount=0;
accel=false;
//acceleration = 1.0;
//distToGround = collider.bounds.extents.y;
//Debug.Log("PlayerMotorStart");
}
//sets velocity to a given movement vector.
public void move(Vector3 _velocity) {
velocity = _velocity;
}
public void rotate(Vector3 _rotation) {
rotation = _rotation;
}
public void rotateCamera(Vector3 _cameraRotation) {
cameraRotation = _cameraRotation;
}
public bool isGrounded() {
return Physics.Raycast(transform.position, -Vector3.up, (float)2.5);
}
public void jump() {
rb.AddForce(transform.up * 250f);
//Debug.Log("Jump"+jumpCount);
jumpCount++;
canJump=false;
}
void FixedUpdate() {
performMovement();
performRotation();
if (canJump) {
jump();
}
//Debug.Log("PlayerMotorUpdate");
if(accel&&pc.speed<20f&&isGrounded())
{
//Debug.Log("W Pressed");
pc.speed*=(float)1.005;
}
else if(!accel) {
pc.speed=7f;
}
}
void performMovement() {
if(velocity != Vector3.zero) {
rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
//Debug.Log("Movement");
}
}
void performRotation() {
rb.MoveRotation(rb.rotation * Quaternion.Euler(rotation));
if(cam != null) {
cam.transform.Rotate(-cameraRotation);
}
}
}
Here are some pictures of my projectile prefab as well.
To solve one first confusion: The method Debug.DrawRay takes as paramters
a start position
a ray direction(!)
You are passing in another position which is not what you want.
This might only work "accidentally" as long as you stand on 0,0,0 so maybe it wasn't that notable but the debt ray definitely points into a wrong direction.
Rather do e.g.
Debug.DrawRay(firePoint.position, destination - firePoint.position, Color.white, 10f);
Or instead rather use Debug.DrawLine which rather actually takes
start position
end position
Then you don't need to calculate the direction first
Debug.DrawLine(firePoint.position, destination, Color.white, 10f);
Then I suspect the following is happening: The spawned projectileObj actually is placed correctly but it is the visuals inside that projectile prefab that have a local offset against the parent prefab root.
Since you always spawn the projectile in world rotation Quaternion.identity that offset stays the same no matter where you look.
I guess a simple fix would already be to also apply the same rotation like
var projectileObj = Instantiate (projectile, firePoint.position, firePoint.rotation);

My player prefab moves forward fine until it hits an object, what is going on?

I'm making a unity game based off of TierZoo, and while testing a movement script, i crashed into one of the rigidbody trees for fun... and that made the player prefab stop moving forward, and it started moving in odd directions Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewPlayerController : MonoBehaviour
{
private Rigidbody rb;
public GameObject player;
public float thrust = 1.0f;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.W))
{
rb.AddRelativeForce(player.transform.right * thrust * 2.5f);
}
if (Input.GetKey(KeyCode.A)) { player.transform.Rotate(0, -1, 0); }
if (Input.GetKey(KeyCode.D)) { player.transform.Rotate(0, 1, 0); }
if (Input.GetKey(KeyCode.S))
{
rb.AddRelativeForce(player.transform.right * thrust * -2.5f);
}
}
}
If you can find a way to fix this, let me know.
You could fix the rotation also in Y direction by keeping track of it and setting it hard in FixedUpdate.
In general as said in the comments:
Whenever a Rigidbody is involved you should not
do movements through the transform component
do movements in Update
both breaks the physics engine and you might get strange and unexpected movements or simply no collisions working etc.
Rather do
- go through the Rigidbody component e.g. using MovePosition and MoveRotation
- do these in FixedUpdate
these keeps the physics intact and moves your Rigidbody only e.g. until it collides meanwhile.
Then for the rotation you have framerate-dependent values Rotate(0, -1, 0)! You rather want to use Time.deltaTime in order to get smooth framerate-independent rotation speed - not in 1 degree per frame but rather e.g. 45 degrees per second.
You script could look like
public class NewPlayerController : MonoBehaviour
{
// already reference this via the Inspector
[SerializeField] private Rigidbody rb;
public GameObject player;
public float thrust = 1.0f;
private void Awake()
{
// as fallback get it on runtime
if(!rb) rb = GetComponent<Rigidbody>();
}
bool moveLeft;
bool moveRight;
bool rotateLeft;
bool rotateRight;
private float angle;
void Update()
{
// Get User input here
// (in your case it would be also fine to do it in FixedUpdate.
// What doesn't work in FixedUpdate are mainly the one-time events like GetKeyDown)
moveRight = Input.GetKey(KeyCode.W);
rotateLeft = Input.GetKey(KeyCode.A);
rotateRight = Input.GetKey(KeyCode.D);
moveLeft = Input.GetKey(KeyCode.S);
}
private void FixedUpdate()
{
if(moveRight) rb.AddRelativeForce(rb.rotation * Vector3.right * thrust * 2.5f);
if(moveLeft) rb.AddRelativeForce(rb.rotation * Vector3.right * thrust * -2.5f);
// Now for the rotations keep track of what you rotated already
// and overwrite the rotation with the fix value:
if(rotateLeft)
{
// e.g. for rotating 45°/second
angle -= -45 * Time.deltaTime;
rb.MoveRotation(Quaternion.Euler(0, angle, 0));
}
if(rotateRight)
{
angle += 45 * Time.deltaTime;
rb.MoveRotation(Quaternion.Euler(0, angle, 0));
}
}
}

How to make a sprite slower when it moves over a sprite?

I have a game object called "Player" and my map is made up of short grasses and long grasses. If my player is on the long grass, I want it to slow down. One additional problem is that there are multiple Long grasses game objects in my game. Here is a screenshot of them :
https://imgur.com/hUq4baV
This is what my current movement code looks like :
public class PlayerMovement : MonoBehaviour
{
public Sprite Up;
public Sprite Down;
public Sprite Right;
public Sprite Left;
public float speed;
private SpriteRenderer sr;
// Update is called once per frame
void Update()
{
Vector3 move;
if (Input.GetKey(KeyCode.W))
{
GetComponent<SpriteRenderer>().sprite = Up;
move = new Vector2(0, speed * Time.deltaTime);
transform.position += move;
}
if (Input.GetKey(KeyCode.A))
{
GetComponent<SpriteRenderer>().sprite = Left;
move = new Vector2(speed * Time.deltaTime, 0);
transform.position -= move;
}
if (Input.GetKey(KeyCode.D))
{
GetComponent<SpriteRenderer>().sprite = Right;
move = new Vector2(speed * Time.deltaTime, 0);
transform.position += move;
}
if (Input.GetKey(KeyCode.S))
{
GetComponent<SpriteRenderer>().sprite = Down;
move = new Vector2(0,speed * Time.deltaTime);
transform.position -= move;
}
}
}
// All my code does is that on each WASD, it changes to a different sprite and moves it.
An explanation would be appreciated because I'm a beginner to this.
use colliders, eg. boxcolliders to detect if player is touching the grass.
Use a tag on you player
use the oncollisionenter2d() method on the grass
void OnCollisionEnter2D(Collision2D col) {
if(col.tag == "PlayerTag") {
playerScriptWhereSpeedIsLocated.speed = 1 //the speed you want
} }
One solution to this would be to use 2D Trigger Colliders.
Assuming your player has some sort of 2D collider attached to it, you may attach trigger colliders to your grass objects which can then send a message to the PlayerMovement script when the player enters/leaves the trigger by adding the OnTriggerEnter2D and OnTriggerExit2D methods to your PlayerMovement class. Here's an example of how this might work:
void OnTriggerEnter2D(Collider2D col)
{
// You can use gameObject.tag to determine what type of object we're colliding with
if(col.gameObject.tag == "LongGrass"){
speed = .8f;
}
}
void OnTriggerExit2D(Collider2D col)
{
if(col.gameObject.tag == "LongGrass"){
speed = 1f;
}
}
I would encourage you to look into the Collision action matrix if you are having
trouble detecting collisions in this way. You'll also make sure you tag your grass correctly for this method to work.

Make ball Jumping

I am trying to make a script where i can move a ball, horizontal and vertical. I managed to get that working.
But now I want to make my ball "jump". I ended with script below, but now my ball just get launched like a rocket xD
Can anyone help me out
using UnityEngine;
using System.Collections;
public class PlayerController : MonoBehaviour
{
public float speed;
public float jumpSpeed;
public GUIText countText;
public GUIText winText;
private int count;
void Start()
{
count = 0;
SetCountText();
winText.text = " ";
}
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis ("Horizontal");
float moveVertical = Input.GetAxis ("Vertical");
Vector3 movement = new Vector3 (moveHorizontal, 0, moveVertical);
Vector3 jump = new Vector3 (0, jumpSpeed, 0);
GetComponent<Rigidbody>().AddForce (movement * speed * Time.deltaTime);
if (Input.GetButtonDown ("Jump"));
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
}
void OnTriggerEnter(Collider other)
{
if (other.gameObject.tag == "PickUp") {
other.gameObject.SetActive(false);
count = count +1;
SetCountText();
}
}
void SetCountText()
{
countText.text = "Count: " + count.ToString();
if (count >= 10)
{
winText.text = "YOU WIN!";
}
}
}
Jumping does not work with adding a continuous force on an object. You will have to apply a single impulse to the object once when the jump button is first pressed. This impulse will also not include a time factor, because it is applied only once. So you would get something like this:
bool jumping;
if (Input.GetButtonDown ("Jump") && !this.jumping);
{
GetComponent<Rigidbody>().AddForce (jumpForce * new Vector3(0,1,0));
this.jumping = true;
}
Also note that in your example you are multiplying the upward unit vector by the jumpspeed twice. Once in the jump vector initialization and then once in the AddForce method.
Of course, you will also have to make sure that gravity applies to pull the object back down (and if the object hits the ground, reset the jump bool.
In general, depending on what kind of game you are making, it is easier to just set the velocity of the object yourself and don't work with the Unity physics engine to do some simple moving around.
There is an error in your code in the function FixedUpdate:
if (Input.GetButtonDown ("Jump"));
in that way you are applying a force on your object at every frame because the semicolon is excluding the row below from the condition. By removing the semicolon you will have a correct if implementation in case of a jump, as long as on your RigidBody component UseGravity is enabled.
if (Input.GetButtonDown ("Jump"))
GetComponent<Rigidbody>().AddForce (jump * jumpSpeed * Time.deltaTime);
Hope it helps.
Thanks everyone, it was a great help. I now have a jumping character. One who can only jump when grounded.
public bool IsGrounded;
void OnCollisionStay (Collision collisionInfo)
{
IsGrounded = true;
}
void OnCollisionExit (Collision collisionInfo)
{
IsGrounded = false;
}
if (Input.GetButtonDown ("Jump") && IsGrounded)
{
GetComponent<Rigidbody>().velocity = new Vector3(0, 10, 0);
}

Categories

Resources