I can't quite understand how Physics.OverlapSphere works at this point. As shown below in the code, if the player enters the overlapsphere then it should return true, but I keep getting false when the player enters the sphere.
This is the script that call the method
void Update()
{
float distance = Vector3.Distance(target.position, transform.position);
if (distance <= lookRadius)
{
agent.SetDestination(target.position);
if (distance <= agent.stoppingDistance)
{
CharacterStats targetStats = target.GetComponent<CharacterStats>();
Debug.Log(enemy.onPlayerEnter());
if (targetStats != null && enemy.onPlayerEnter())
{//if player exist and the player enters the attack area
Combat.Attack(targetStats);
}
FaceTarget();
}
}
animator.SetFloat("speed", agent.velocity.magnitude);
this is the script of the method:
public bool onPlayerEnter()
{
Collider[] hitColliders = Physics.OverlapSphere(interactionTransform.transform.localPosition, radius);
//Debug.Log(interactionTransform.transform.localPosition);
for(int i = 0; i < hitColliders.Length; i++)
{
if(LayerMask.LayerToName(hitColliders[i].gameObject.layer) == "Player")
{
Debug.Log("Player enter");
return true;
}
}
return false;
}
//visualize the overlapsphere
private void OnDrawGizmosSelected()
{
if (interactionTransform == null) interactionTransform = transform;
Gizmos.color = Color.cyan;
Gizmos.DrawWireSphere(interactionTransform.position, radius);
}
collider with monster
[Collide with player[][1]][2]
https://i.stack.imgur.com/8Fgh0.png
https://i.stack.imgur.com/jnubp.png
For unknown reason, I found that the overlapsphere works at certain position in the map, but the rest of the position does not work at all. I think this probably is a bug in Unity.
weird position
Your sphere gizmo and actual sphere are different: for drawing gizmo you use transform.position, but for overlap sphere - transform.transform.localPosition (no need to double like transform.transform, and position and localPosition can be very different). I think, this is the answer.
Its easy to get mess with LayerMask, its a good approach, but for testing you better use tag, or gameObject.InstanceID, or even gameObject.name. But its minor, in general it looks like you deal with layers right.
Be sure that your agent.StoppingDistance not set too small
It`s a bad practice to use GetComponent every frame, as you do for get targetStats.
Related
Firstly, the code:
private bool? _hasJumped = false;
private void Update()
{
Debug.Log("Checking the _hasJumped value in Update(): " + _hasJumped);
Debug.Log("Is the player Grounded?: " + IsGrounded());
if (IsGrounded())
{
_extraJumps = _extraJumpCount;
_coyoteTimer = _coyoteTimerVal;
_hasJumped = false; //The Variable that I am having issues with.
Debug.Log("This statement only runs when the player is on ground!");
}
else
{
_coyoteTimer -= Time.deltaTime;
}
}
public bool IsGrounded()
{
return Physics2D.OverlapCircle(_feetpos.position,_feetCheckRadius,_groundLayerMask);
}
public void GetJumpInput(InputAction.CallbackContext context)
{
if (context.started)
{
_jumpBuffer = Time.time;
}
if (_coyoteTimer > 0f && (Time.time - _jumpBuffer >= 0) && context.performed)
{
if(context.interaction is TapInteraction)
{
_myRigidBody.velocity += new Vector2 (0f, _jumpForce);
_whichInteraction = 0;
}
else if (context.interaction is HoldInteraction)
{
_myRigidBody.velocity += new Vector2 (0f, _jumpForce);
_whichInteraction = 1;
}
_jumpBuffer = null;
_hasJumped = true; //_hasJumped set to true when I first jump
Debug.Log("The Player Has Pressed Jump!: " + _hasJumped);
}
else if (_extraJumps > 0 && context.performed && hasJumped) //Double Jump should ONLY work when I have jumped, and not when I fall off a ledge.
{
Debug.Log(_hasJumped);
_extraJumps--;
if(context.interaction is TapInteraction)
{
_myRigidBody.velocity += new Vector2 (0f, _jumpForce*_secondJumpForceMult);
_whichInteraction = 0;
}
}
else
{
_coyoteTimer = 0f;
}
}
Sorry if the the code is confusing, I've tried to add comments to the variable in focus. But the issue that I'm facing is this:
Right now, when a player falls off the edge, the player is able to jump once because of the additional "extra jump" but this should not be happening. The "extra jump" should only come into effect when the player HAS already jumped.
To stop this, I decided to use a bool "_hasJumped" which (in my head works as follows):
As long as the player is touching the ground, it is false.
When the player first jumps, it is set to true.
Only when it is true can player perform the "extra jump".
If it isn't true, the player cannot perform the "extra jump".
However, the issue that I'm facing is that although _hasJumped is set to true when I jump, it is immediately set to false in the next update (even though I'm still in the air!). Video Evidence #1
I've checked that my IsGrounded() function is working completely fine [Video Evidence #2].
The only reason I can deduce is that it may have something to do with Unity's runtime order? I'm a newbie though so I could be wrong.
I am also using the new Input System.
Thank you for taking the time to read it/give advice/help! I really appreciate it!
The problem is how fast the update actually runs in relation to the way you structured your code.
To visualize, this is what happens when the player pressed the jump button:
First frame: Player presses jump button
Second frame: Character is slightly up on the air, but the overlap collision detector is still touching the ground
Solution
Only check for IsGrounded() when the player presses the jump button, not per-update.
This also saves some computing resource as doing Physics calculation per-frame can be demanding.
Use OnCollisionEnter2D or OnTriggerEnter2D to check if the character has just landed to set canExtraJump to false.
Looks something like this:
bool canExtraJump = false;
void Update(){
// Set extrajump when player inputs jump button, and char is grounded
if (Player_Input_Jump) {
if (IsGrounded()){
Jump();
canExtraJump = true;
}
}
}
void TriggerLandedOnGround(){
canExtraJump = false;
}
// ...
/// Ideally this function should be in the character's feet (as another gameObject)
/// As you do not want this to trigger when the side of a character touches the platform.
void OnTriggerEnter2D(Collider2D other){
if (other.CompareTag("platform")){
TriggerLandedOnGround();
}
}
I'm a beginner. I'm making a ball game in Unity, in which ball have to avoid the collision with the obstacle. In the game, I'm increasing the ball speed in every 3 seconds. Everything's working fine, but in the middle of game, I noticed the ball starts shaking, the speed decreases, and the camera can't catch the ball. I attached physics material to all gameobjects, and made all frictions zero, but the ball is still shaking.
Here is the link of the my game and the problem. Have a look: https://youtu.be/TR4M5whweTk
Here is the script attached to the ball:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class PlayerController : MonoBehaviour
{
public Text gameOverText;
public Text scoreText;
public bool isGameOver;
public float speeder;
public float Score;
Touch touch;
public float speedmodifier ;
public float speed = 5;
// Start is called before the first frame update
private void Awake()
{
isGameOver = false;
Score = 0;
if(PlayerPrefs.GetFloat("HighScore") == 0)
{
PlayerPrefs.SetFloat("HighScore", 0);
}
PlayerPrefs.SetFloat("Score", Score);
}
void Start()
{
speeder = 4f;
gameOverText.enabled = false;
speedmodifier = 0.01f;
// GetComponent<Rigidbody>().velocity = new Vector3(0,0,speed);
}
// Update is called once per frame
void Update()
{ if(speeder >= 0)
{
speeder -= Time.deltaTime;
}
if (speeder<= 0 && speed < 50)
{
speed++;
speeder = 4f;
}
Debug.Log(speed);
if (isGameOver == false)
{
Score++;
}
scoreText.text = "Score : " + Score ;
if (Input.touchCount >0 && transform.position.x >= -3.5f && transform.position.x <= 3.5f)
{
touch = Input.GetTouch(0);
transform.Translate(touch.deltaPosition.x * speedmodifier,0,0);
}
else if(transform.position.x > 3.5f)
{
transform.position = new Vector3(3.49f,transform.position.y,transform.position.z);
}
else if(transform.position.x < -3.5f)
{
transform.position = new Vector3(-3.49f,transform.position.y,transform.position.z) ;
}
if (Input.GetKey(KeyCode.RightArrow) && transform.position.x < 3.5f)
{
transform.Translate(Vector3.right*speed* Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftArrow) && transform.position.x >-3.5f)
{
transform.Translate(Vector3.left*speed* Time.deltaTime);
}
transform.Translate(Vector3.forward * speed * Time.deltaTime);
}
private void OnTriggerEnter(Collider other)
{
if(other.gameObject.tag == "enemy")
{
isGameOver = true;
StartCoroutine("Wait");
GetComponent<MeshRenderer>().enabled = false;
gameObject.GetComponentInChildren<TrailRenderer>().enabled = false;
gameOverText.enabled = true;
if(PlayerPrefs.GetFloat("HighScore") < Score)
{
PlayerPrefs.SetFloat("HighScore", Score);
PlayerPrefs.SetFloat("Score", Score);
}
else
{
PlayerPrefs.SetFloat("Score", Score);
}
}
}
IEnumerator Wait()
{
Debug.Log(" My HighScore is : " + PlayerPrefs.GetFloat("HighScore"));
Debug.Log(" Score is : " + PlayerPrefs.GetFloat("Score"));
yield return new WaitForSeconds(3f);
SceneManager.LoadScene(1);
}
}
As BugFinder pointed out you are actually not moving the ball with physics, but just teleporting the ball with Transform.Translate which might be affecting the shacking issue, the other possible problem is that your ball speed might be varying due to a collision with the road, have you tried making the road RigidBody to Kinematic? so it won't affect the speed of the ball
OK you SHOULD NOT be using unity phsyics for this.
It's a "raster" game (and that's fun).
remove all physics everything. completely remove rigidbody, collider, etc
simply move the ball and/or scenery using a calculation each time.
(It's basically just frame time * speed, obviously.)
(Note, you can use strictly triggers - if you want - simply to know if the "ball" is near a "stick". But you can do that with 1 line of code, really no need for colliders/etc.)
Your Question
I just want to make sure that I am understanding your question correctly first, I believe you are asking for a way to prevent the ball from shaking during the game. (Let me know if this is incorrect, if so I apologize). From what I have gathered, this does not seem like a code based issue
Collision Detection
In unity, the rigidbody component has a field named 'Collision Detection' and this is set to discrete by default. This means that unity will look in direction of travel for a possible collider every now and again. That is an okay method to use when trying to save computer resources, however when in constant contact or at high velocities it is best to use the 'continuous' mode. This will check for a collision every physics update which occurs every physics time-step.
Colliders
Colliders in unity are a little finicky. Most notorious are mesh colliders as they have to be more heavenly processed/calculated. Using a box collider for your ground might give more accurate physics results.
Other Solutions
Whilst looking at your game video you published on YouTube, it looks like using physics may not be able to work. Since you are only traveling left, right, and forward globally, I would suggest implementing a movement script that uses an object's transform component instead of physics. This will be less resource intensive and will save further debugging headaches in the long run.
I've been adding some extra movement techniques to a Character Controller in Unity3D. Currently, I'm working on a dash function, but currently, it's behaving very weirdly.
Dashing Backwards, Works as I want it to
Dashing Forwards, Doesn't work as I want it to...
As you can see in the first Image, the silhouttes being essentially where I've dashed, I'm moving in a straight line backwards, as represented by the Green Arrows. However in the second Image, the silhouttes go diagonally to the top left, instead of straight ahead. As represented by the yellow arrows, this time green showing where I want and expect it to go.
private void DashFuncW()
{
if (Time.realtimeSinceStartup - timeOfFirstButton < DoublePressSpan && Input.GetKeyDown(KeyCode.W) && firstButtonPressed)
{
Dash(transform.forward);
firstButtonPressed = false;
timeOfFirstButton = 0f;
}
if (Input.GetKeyDown(KeyCode.W))
{
timeOfFirstButton = Time.realtimeSinceStartup;
firstButtonPressed = true;
}
}
private void DashFuncS()
{
if (Time.realtimeSinceStartup - timeOfFirstButton < DoublePressSpan && Input.GetKeyDown(KeyCode.S) && firstButtonPressed)
{
Dash(-transform.forward);
firstButtonPressed = false;
timeOfFirstButton = 0f;
}
if (Input.GetKeyDown(KeyCode.S))
{
timeOfFirstButton = Time.realtimeSinceStartup;
firstButtonPressed = true;
}
}
These 2 Functions get the double-tap style input and call the actual Dash function while passing it the Direction it needs to go to. As you can see, both use 'transform.forward', just the S key function uses '-transform.forward'. This is what confuses me the most. If it can go one way fine, why can't it go the other way, especially when they're the exact mirror values of one another.
private void Dash(Vector3 Direction)
{
GameObject WarpClone = Instantiate(gameObject);
WarpClone.transform.position = transform.position;
Destroy(WarpClone.GetComponent<CharacterMovement>());
Destroy(WarpClone.GetComponent<CharacterController>());
Destroy(WarpClone.GetComponent<Animator>());
foreach (Transform child in WarpClone.GetComponentsInChildren<Transform>())
{
Destroy(child.GetComponent<Collider>());
SkinnedMeshRenderer[] SMRs = WarpClone.GetComponentsInChildren<SkinnedMeshRenderer>();
MeshRenderer[] MRs = WarpClone.GetComponentsInChildren<MeshRenderer>();
foreach (SkinnedMeshRenderer SMR in SMRs)
{
SMR.material = warpMaterial;
}
foreach (MeshRenderer MR in MRs)
{
MR.material = warpMaterial;
}
}
Destroy(WarpClone, 100f); //100 Seconds for testing
CC.Move(Direction * dashStrength);
}
And this function is the one that creates the silhouettes and actually moves the player. If it matters any, 'dashStrength' is equal to 3, and all 3 of these functions are in a bigger 'Movement' function which moves the character based on Axis input, which runs in the Update() call, as FixedUpdate makes for jittery movement. I cannot for the life of me find out why it won't work properly. I'd appreciate any help :/
Well, if anyone ends up with the same problem somehow, I ended up fixing it by disabling the character controller and changing transform.position like so:
CC.enabled = false;
transform.position = transform.position + (Direction * dashStrength);
CC.enabled = true;
I'm making a small sandbox game for kids where they get to spawn some 2d objects, drag them all over the screen and throw them against each other.
I tried to avoid using AddForce() because the algorithms don't seem to fit my problem (if the kid drags one object in multiple directions, the object trajectory will be quite messy and unrealistic when he releases it).
What I went with instead is to spawn an empty object when you click on an object and attach the two with a HingeJoint2D. It works well when it comes to dragging the object across the screen, but the object just fall flat onto the ground when you release it (the empty object with HingeJoint gets deleted when you release it).
// Update is called once per frame
void Update()
{
// MousePosition
Vector3 mousePos = Input.mousePosition;
mousePos.z = 10;
Vector3 screenPos = Camera.main.ScreenToWorldPoint(mousePos);
if (Input.GetMouseButtonDown(0) && !objectInHand)
{
RaycastHit2D hit = Physics2D.Raycast(screenPos, Vector2.zero);
if (hit && hit.collider.tag == "DraggableObject")
{
emptyObject = new GameObject("HingeHolder");
emptyObject.transform.position = screenPos;
emptyObject.AddComponent<HingeJoint2D>();
objectInHand = hit.collider.gameObject;
emptyObject.GetComponent<Rigidbody2D>().isKinematic = true;
emptyObject.GetComponent<HingeJoint2D>().connectedBody = objectInHand.GetComponent<Rigidbody2D>();
emptyObject.GetComponent<HingeJoint2D>().autoConfigureConnectedAnchor = false;
}
}
else if(Input.GetMouseButton(0) && objetInHand)
{
emptyObject.transform.position = screenPos;
}
else if (Input.GetMouseButtonUp(0) && objetInHand)
{
emptyObject.GetComponent<Rigidbody2D>().isKinematic = false;
emptyObject.GetComponent<HingeJoint2D>().connectedBody = null;
Destroy(emptyObject);
objectInHand = null;
}
}
I would like my object to keep its force on release and to work like AddForce(), but I just can't get it to work properly this way. Am I doing this wrong ? Is this possible without using AddForce() ?
Thanks in advance
Another way to do what you want is by adding a script to each box:
using System.Collections.Generic;
public class Draggable: MonoBehaviour, IDragHandler {
public float z = 1f;
public void OnDrag(PointerEventData data)
{
Vector3 mousePosition = Input.mousePosition;
mousePosition.z = z;
transform.position = Camera.main.ScreenToWorldPoint(mousePosition);
}
}
this solution prevents us from needing to use the update (improving performance) and you could adjust the mass, gravity, z and other factors, so that your game.
it would also be good if he had physical limits when his stage is over
Looking for a bit of help to see how I can make this algorithm a little better. So I have some code for a pan tool that moves the camera based on the user dragging the mouse to move the camera around. However it is really jumpy unless it is done in really short drags. I.e. the objects in the scene appear to vibrate, which is more likely to be the camera and canvas 'vibrating' rather than the objects themselves.
The code works by toggling a dragging boolean using the SystemEvent methods OnPointerDown and OnPointerUp and assigns a MouseStart Vector3 in world coordinates and also a CameraStart Vector3.
public void OnPointerDown(PointerEventData EventData)
{
if (!dragging)
{
dragging = true;
MouseStart = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f);
CameraStart = TheCamera.transform.position;
}
}
public void OnPointerUp(PointerEventData EventData)
{
if (dragging)
{
dragging = false;
}
}
Then in the update loop while the dragging variable is true, xChange and yChange float values are determined based on the current mouse position compared to the original mouse position, the camera position is then adjusted according to these. My thought process was that because it is relative to a fixed MouseStart (because it is only changed in the single frame where the pointer is clicked and dragging = 0) that if I were to drag and then say keep the mouse still, there would be no change in coordinates as it'd be repeatedly putting the Camera in the same position. The full code looks like this:
private bool dragging;
private string CurrentTool;
private ButtonController[] DrawingTools;
public Camera TheCamera;
public Vector3 MouseStart;
public Vector3 CameraStart;
public float sensitivity;
// Use this for initialization
void Start () {
TheCamera = FindObjectOfType<Camera>();
DrawingTools = FindObjectsOfType<ButtonController>();
}
// Update is called once per frame
void Update () {
for (int i = 0; i < DrawingTools.Length; i++)
{
if (DrawingTools[i].Pressed)
{
CurrentTool = DrawingTools[i].gameObject.name;
}
}
if (dragging && CurrentTool == "PanTool Button")
{
float xChange;
float yChange;
Vector3 MousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if (MousePosition.x > MouseStart.x)
{
xChange = -Mathf.Abs(MousePosition.x - MouseStart.x);
}
else
{
xChange = Mathf.Abs(MousePosition.x - MouseStart.x);
}
if (MousePosition.y > MouseStart.y)
{
yChange = -Mathf.Abs(MousePosition.y - MouseStart.y);
}
else
{
yChange = Mathf.Abs(MousePosition.y - MouseStart.y);
}
TheCamera.transform.position = new Vector3(CameraStart.x + xChange*sensitivity, CameraStart.y + yChange*sensitivity, CameraStart.z);
}
}
public void OnPointerDown(PointerEventData EventData)
{
if (!dragging)
{
dragging = true;
MouseStart = new Vector3(Camera.main.ScreenToWorldPoint(Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y, 0f);
CameraStart = TheCamera.transform.position;
}
}
public void OnPointerUp(PointerEventData EventData)
{
if (dragging)
{
dragging = false;
}
}
Any help is appreciated, thanks.
EDIT: Just to clarify this is a 2d environment
This is happening because the Camera from which you are determining the world position of the mouse is being updated every frame according to the world position of the mouse, which causes a feedback loop (and therefore noise + jitter).
You can reduce noise from the feedback loop by smoothing the Camera's movement over time (effectively a low pass), or try to remove the feedback loop entirely by altering your calculations so the camera position and target position (mouse) don't rely on each other - although I'm not sure how to go about that if it's actually possible for your intent.
Check out Vector3.SmoothDamp.
Gradually changes a vector towards a desired goal over time.
The vector is smoothed by some spring-damper like function, which will
never overshoot. The most common use is for smoothing a follow camera.