a prefab I instantiate (the boss of my game) is following my camera whenever this script is active, which is not what I'm telling it to do. Well, to be more accurate, when the camera goes to the right, the cloned prefab goes to the left, and vice versa. If I have the boss already in the scene and start the game, it does everything I tell it to, and doesn't follow the camera. The prefab only does half the things and yes, I did apply the changes to the prefab several times. I know it's not attaching itself to the camera automatically because I moved the camera in the scene view with this script off and it didn't follow my camera in-game.
The boss isn't even being referenced in this script. I am absolutely positive that the problem isn't even script wise. But it occurs when this script that has nothing to do with the boss is active. So my question is, can I tell the boss script in some way to blind itself to this script? Or better yet, is there something in Unity that can cause this, to which at that end I can fix? The only thing this script does is follow the player's characters based on whenever you switch between them. And the boss does follow the camera regardless of whatever character you have active at the time so it has nothing to do with that either. Lastly, the camera is not being referenced in the boss script at all, or in the script attached to another 2D trigger collider that instantiates the boss.
using UnityEngine;
using System.Collections;
public class cameraFollow : MonoBehaviour {
public Transform player;
public Transform player2;
private bool idleFollow = true;
private bool mountFollow = false;
public theWatcher wMana;
public tulMove tulia;
private bool alphaGirl;
[HideInInspector]
public bool blinking = false;
[HideInInspector]
public bool vTul = true;
void Update ()
{
CameraSwitching ();
}
void CameraSwitching()
{
if (!wMana.alphaGirl && !wMana.switched && vTul && wMana.cur_mana > 0f && Input.GetKeyDown (KeyCode.Space)) {
vTul = false;
return;
}
if (!vTul && wMana.cur_mana > 0f && Input.GetKeyDown (KeyCode.Space)) {
vTul = true;
return;
}
if (!vTul && wMana.cur_mana <= 0) {
vTul = true;
}
if (vTul && wMana.cur_mana <= 0 && Input.GetKeyDown (KeyCode.Space)) {
vTul = true;
}
if (!wMana.paused && vTul){
transform.position = new Vector3 (player.position.x + .5f, player.position.y + .55f, -7.75f);
}
if (!wMana.paused && !vTul) {
transform.position = new Vector3 (player2.position.x + .5f, player2.position.y + .55f, -7.75f);
}
if (wMana.switched) {
transform.position = new Vector3 (player2.position.x + .5f, player2.position.y + .55f, -7.75f);
}
if (!wMana.switched) {
transform.position = new Vector3 (player.position.x + .5f, player.position.y + .55f, -7.75f);
}
}
}
this is the code to spawn my boss. I know it's not this because I used other prefabs besides my boss and those were working fine.
so, since there are no known solutions to a problem with a random, unrelated cause, I just decided to work around the issue. What I did was have the boss already placed in the scene and made a trigger collider activate the existing GameObject. If the player dies, I'll just move the boss back to his original position and deactivate him. It sucks I can't have a prefab of this character for whatever reason, but at least it's a character you only have to beat once anyway.
Related
I've been trying to set an enemy on a patrol path while not chasing my player character. I want to use RayCast so that the enemy can spot the player and begin to chase the player. It functions as I intended. However, even when there's an obstacle or wall between us, or when I approach from behind, the enemy 'sees' my player and starts to chase me. It seems to ignore the Raycast, and instead focuses on the proximity to the enemy.
Enemy spotting player through wall
public class EnemyController : MonoBehaviour
{
private NavMeshAgent enemy;// assaign navmesh agent
private Transform playerTarget;// reference to player's position
private float attackRadius = 10.0f; // radius where enemy will spot player
public Transform[] destinationPoints;// array of points for enemy to patrol
private int currentDestination;// reference to current position
public bool canSeePlayer = false;
private Ray enemyEyes;
public RaycastHit hitData;
private void Awake()
{
enemy = GetComponent<NavMeshAgent>();
playerTarget = GameObject.Find("Player").GetComponent<Transform>();
enemyEyes = new Ray(transform.position, transform.forward);
}
private void Start()
{
Physics.Raycast(enemyEyes, attackRadius);
}
private void Update()
{
Lurk();
Debug.DrawRay(transform.position, transform.forward * attackRadius);
}
void Lurk()
{
Debug.Log("Lurking");
float distanceToPlayer = Vector3.Distance(transform.position, playerTarget.position);
//check if raycast hits playerLayer and enemy is close enough to attack
if (Physics.Raycast(enemyEyes, out hitData, attackRadius * 2, layerMask: ~6) && distanceToPlayer < attackRadius)
{
Debug.Log("You hit " + hitData.collider.gameObject.name);
ChasePlayer();
}
else
{
canSeePlayer = false;
Patrol();
}
}
void Patrol()
{
if (!canSeePlayer && enemy.remainingDistance < 0.5f)
{
enemy.destination = destinationPoints[currentDestination].position;
UpdateCurrentPoint();
}
}
void UpdateCurrentPoint()
{
if (currentDestination == destinationPoints.Length - 1)
{
currentDestination = 0;
}
else
{
currentDestination++;
}
}
void ChasePlayer()
{
StartCoroutine(ChaseTime());
canSeePlayer = true;
transform.LookAt(playerTarget.position);
Vector3 moveTo = Vector3.MoveTowards(transform.position, playerTarget.position, attackRadius);
enemy.SetDestination(moveTo);
}
IEnumerator ChaseTime()
{
Debug.Log("Chasing");
yield return new WaitForSeconds(10.0f);
if (!Physics.Raycast(enemyEyes, out hitData, attackRadius * 2, layerMask: ~6))
{
canSeePlayer = false;
Debug.Log("Lurking");
Lurk();
}
}
}
I've removed the tilde "~" for the layermask, but then the enemy doesn't ever see the player.
I've initialised and set a layer mask reference to the 'playerLayer' and used it in place of "layermask: ~6", to no avail.
I've used the int reference to the Player layer, to no avail.
I've used bitwise operator to reference the player layer, to no avail.
I've removed the distanceToPlayer conditional, but the enemy doesn't see the player.
I've adjusted the length of the Ray but if it's ever shorter than the attack radius, it doesn't work.
I don't understand why you need a layer mask. If you want the Raycast to hit something in front of the player then you must include all layers in the Raycast.
What you need to do is remove the layermask from Raycast and in the if statement check if the out hit collider is on Player and if the player is in attack radius. Here is a simple outline
If(raycast)
{
if(hit.collider.gameobject==player && player in proximity)
{
Then can see is true
}
}
You can give this article on Unity Raycast a read to understand more on layermask.
regarding player detection through a wall,I would try adding an extra if statement in the Lurk method.This condition would check if the raycast is touching the wall, if so, do not proceed with the method, if not, continue. Sorry for giving the code in this form but I don't have access to a computer and the phone doesn't want to cooperate
enter image description here
I am developing a 2d game in unity, and I am trying to add friction to slow the player down when he is on the ground. I launch the player into the air with the rigidbody's add force. I have heard of physics materials, and am currently trying to use them. I am using the 2d version of them, I made one material which had high friction. I add the material to the floor, and then I play the game, and my character is still sliding on the floor. I thought the problem might be with the player not having a physics material, so I added one. It still didn't work.
I tried doing different combinations with the different materials.
I tried attaching a rigidbody, but kinematic to the floor.
I tried looking it up, and couldn't find an answer.
Here is the code that moves the player:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public bool isGrounded = true;
public float fireForce;
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
camera = camObj.GetComponent<Camera>();
}
void Update()
{
RotateToPoint();
Fire();
}
void OnCollisionEnter2D(Collision2D obj)
{
if (obj.gameObject.tag == "surface")
{
isGrounded = true;
}
}
void OnCollisionExit2D(Collision2D obj)
{
if (obj.gameObject.tag == "surface")
{
isGrounded = false;
}
}
void Fire()
{
if (Input.GetKeyDown(KeyCode.Mouse0) && isGrounded)
{
rb.AddForce(transform.up * fireForce, ForceMode2D.Impulse);
}
}
}
I do not know if I am approaching the problem correctly. If I am not, does anyone know how to avoid slippery game objects. Any help would be appreciated.
Adding a higher angular drag was the solution to my problem. Angular drag is what slows the object down along its rotation. Friction may not always be the problem.
Notice the two highlighted variables. You might want to raise these values (I changed angular drag from its default) to something higher. Adding the physics material might help, you should try this if this first solution doesn't work.
The problem here is that you are not limiting the velocity of the player, so what you can do is set an if statement if the player is touching the floor and the velocity is higher than what you want it to be.
Example:
void FixedUpdate()
{
if (isGrounded == true && rb.velocity.x > 1 || isGrounded == true && rb.velocity.z >1)
{
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
}
}
Overview
Using Unity2D 2019.3.5, I am making a platformer game using C#. I implemented raycast to detect when my player is touching the ground and attempted to make it only so the player can jump only once.
Problem
Although I thought I programmed my character to jump once, after the first jump, the Unity engine still shows a checkmark to my "isGrounded" variable and only turns to false (unchecked) after a second jump before hitting the ground.
My Code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player_Controller : MonoBehaviour
{
public int playerSpeed = 10;
public int playerJumpPower = 1250;
private float moveX;
public bool isGrounded;
public float distanceToBottomOfPlayer = .7f;
// Update is called once per frame
void Update()
{
PlayerMove();
PlayerRaycast();
}
void PlayerMove()
{
// CONTROLS
moveX = Input.GetAxis("Horizontal");
if (Input.GetButtonDown("Jump") && isGrounded == true)
{
Jump();
}
// ANIMATIONS
// PLAYER DIRECTION
if (moveX < 0.0f)
{
GetComponent<SpriteRenderer>().flipX = true;
}
else if (moveX > 0.0f)
{
GetComponent<SpriteRenderer>().flipX = false;
}
// PHYSICS
gameObject.GetComponent<Rigidbody2D>().velocity = new Vector2(moveX * playerSpeed,
gameObject.GetComponent<Rigidbody2D>().velocity.y);
}
void Jump()
{
GetComponent<Rigidbody2D>().AddForce(Vector2.up * playerJumpPower);
isGrounded = false;
}
void PlayerRaycast()
{
// Ray Down
RaycastHit2D rayDown = Physics2D.Raycast(transform.position, Vector2.down);
if (rayDown.collider != null && rayDown.distance < distanceToBottomOfPlayer &&
rayDown.collider.tag == "ground")
{
isGrounded = true;
}
}
}
Extra Info
I did have to change a Unity setting in Edit > Project Settings > Physics 2D > Queries Start In Colliders. I had to turn this setting off (uncheck) in order to get my player to jump using the code I wrote above. I know there are other ways of making my player jump, however, this seemed to be the most efficient while maintaining the readability of the code.
Solutions Tried
What I believe the problem is that I have a raycast issue that I don't know how to fix. I looked at other Stack Overflow posts including the ones recommended after writing this post, but none of them applied to my problem.
Final Notes
As I said before, I know there are other ways to make my player jump only once using different code, however, I would like to stick with this code for my own learning purposes and for future reference.
Because you can't be sure that isGrounded is false when you call Jump().
I think issue lies there.
Try not setting isGrounded flag when calling Jump(). Setting isGrounded is purely PlayerRaycast()'s job.
void Update()
{
// Raycast before moving
PlayerRaycast();
PlayerMove();
}
void PlayerRaycast()
{
// Ray Down
RaycastHit2D rayDown = Physics2D.Raycast(transform.position, Vector2.down);
if (rayDown.collider != null && rayDown.collider.tag == "ground")
{
if( rayDown.distance < distanceToBottomOfPlayer )
{
isGrounded = true;
}
else
{
isGrounded = false;
}
}
}
void Jump()
{
GetComponent<Rigidbody2D>().AddForce(Vector2.up * playerJumpPower);
//isGrounded = false;
}
The first problem is that you add the force and check for the ground at the same frame.
Applied Force is calculated in FixedUpdate or by explicitly calling
the Physics.Simulate method.
So after you press the "Jump" button, the object is still on the ground until the next frame comes.
To fix this, you can simply exchange the order of "move" and "raycast"
void Update()
{
PlayerRaycast();
PlayerMove();
}
The second problem is if the jump power is not large enough, the object can still be close to the ground in the next frame, you should avoid checking the landing when the jump is in ascending state.
void PlayerRaycast()
{
if(GetComponent<Rigidbody2D>().velocity.y > 0)
return;
...
}
So, I'm still not the best at this but I'm trying to use this script for 2D movement but the jumping isn't working for some reason. It keeps saying that the OnCollisionEnter function "is declared but never used". Can someone tell me what im doing wrong? Thanks
If I remove the (Collision col) part it says that "void cannot be used in this context".
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RonyWalking : MonoBehaviour
{
Rigidbody2D rigid;
SpriteRenderer sprite;
public bool isJumping;
public float spd = 2.0f;
// Start is called before the first frame update
void Start()
{
rigid = GetComponent<Rigidbody2D>();
sprite = GetComponent<SpriteRenderer>();
}
// Update is called once per frame
void Update()
{
if(Input.GetKey("d")){rigid.velocity = new Vector2(spd, 0);}
else if(Input.GetKey("a")){rigid.velocity = new Vector2(-spd, 0);}
if(Input.GetKeyDown("w") && isJumping == false)
{
rigid.velocity = new Vector2(0, 5);
isJumping = true;
}
void OnCollisionStay(Collision col)
{
isJumping = false;
}
}
}
When using 2D physics, you need to use the 2D lifecycle methods;
void OnCollisionStay2D(Collision2D col)
{
isJumping = false;
}
And you shouldn't put this method inside your Update method... It should be on class level:
public class RonyWalking
{
void Update()
{
// ...
}
void OnCollisionStay2D(Collision2D col)
{
// ...
}
}
Don't worry about "Is declared but never used", this may be because you don't have specific code referencing the method, but Unity will raise events that calls it, "automagically"
Another thing that I can see while reading your code, that may be unintentional behaviour for you, is that when clicking left/right, you set velocity UP to 0, and when clicking up you set LEFT/RIGHT velocity to 0; this will result in freezing the movement mid-air if you jump, then move while in air:
Click D; velocity = 2, 0
Click W; velocity = 0, 5
Character will now move upwards until another input is given
Click D; velocity = 2, 0 and the character will continue moving while in air because when moving sideways the up/down velocity is set to 0
To solve this, either set the other to existing velocity or make the inputs manipulate a Vector that you then apply at the end of the movement code:
Vector2 existingMovement = rigid.velocity;
if (Input.GetKey(KeyCode.D))
existningMovement.x = spd;
else if (Input.GetKey(KeyCode.A))
existningMovement.x = -spd;
if (Input.GeyKeyDown(KeyCode.W) && !isJumping)
{
existningMovement.y = 5f;
isJumping = true;
}
Furthermore, I think you may have some unexpected behaviour with OnCollisionStay; it will fire every frame that you're colliding with the ground, I assume. But I think it may also fire a frame or two AFTER you've jumped since the physics of your character will not INSTANTLY leave the collision, so isJumping will be set to false even after your jump, letting you jump while in the air one more time.
I would recommend that you use OnCollisionExit2D(Collision2D col) to set isJumping = true instead, or OnCollisionEnter2D(Collision2D col) and set it to isJumping = false, depending on the functionality you desire (if you want the ability to jump after walking out of a cliff)
In my game for pong, the ball is supposed to bounce and never become slower. However, the ball is steadily slowing down over time. I will put an image of the ball object and the scripts.
Here is the ball properties on the left
Here is the ball script
using UnityEngine;
using System.Collections;
public class Ball : MonoBehaviour
{
public float ballVelocity = 3000;
Rigidbody rb;
bool isPlay;
int randInt;
void Awake()
{
rb = GetComponent<Rigidbody>();
randInt = Random.Range(1,3);
}
void Update()
{
if (Input.GetMouseButton(0) && isPlay == false)
{
transform.parent = null;
isPlay = true;
rb.isKinematic = false;
if (randInt == 1)
{
rb.AddForce(new Vector3(ballVelocity, ballVelocity, 0));
}
if (randInt == 2)
{
rb.AddForce(new Vector3(-ballVelocity, -ballVelocity, 0));
}
}
}
}
and here is the bounce physics image
and since I have no idea why it won't work, here is my physics project settings
The reason why this is happening is because of the randomness being added. All it takes is it to hit harder in one direction one than the opposite direction. Eventually, idk after how long of a time, but it will finally settle at a velocity of 0. To fix this, you need to remove the drag coefficient if you haven't already. Next, you need to clear whatever the current velocity is from the ball. "rigidbody.velocity = Vector3.zero;" should do it for you. After that, you can either generate a new velocity directly using some maths that I do not know off of my head, or add a new force that is no longer dependent on the previous condition of the ball. I hope this helps, and if not, leave a comment and let's see if we can't find a better solution :)