Here's my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GoToMouse : MonoBehaviour
{
private Transform tf;
private bool Selected = false;
// Start is called before the first frame update
void Start()
{
tf = GetComponent<Transform>();
}
private void OnMouseDown()
{
if (Selected == false)
{
Selected = true;
}
if (Selected == true)
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
tf.position = mousePos;
}
}
private void OnMouseUp()
{
if (Selected == true)
{
Selected = false;
}
if (Selected == false)
{
}
}
// Update is called once per frame
void Update()
{
}
}
In this script, I want to do two things. I want an object to become selected when clicked and unselected when you let go of the mouse. When an object is selected I want it to move towards the mouse cursor. Basically, you can drag it around with the mouse cursor and throw it with physics.
This script has a couple problems.
Whenever I click the object it completely vanishes. I have no background or anything it could be going behind, so I don't know what is causing this. The object also doesn't move anywhere (I checked its transform) So it appears it's sprite just stops rendering
Whenever I select it and try to move it, it moves less that 1 unit along the X and Y axis and then stops. For some reason, it deselects itself or stops moving before I let go of the mouse. I don't know why this would be since the only way to deselect an object is by letting go of the mouse.
This is a unity2D project BTW, and this script is the backbone of the game I'm making. Please help!
thanks.
I understand tf as a character which is needed to move.
According to the OnMouseDown function,
OnMouseDown is called when the user has pressed the mouse button while over the Collider.
Doc Link here
You will require a background and script may attach to it. Get the mouse position from background. Than set the position to the tf(character). 2D game z position always should be 0.
And of course, you can change the size of the background as large as you need.
Image and script can explain better.
Here is GoToMouse.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GoToMouse : MonoBehaviour
{
public Transform tf;
private bool Selected = false;
// Start is called before the first frame update
void Start()
{
// the tf is drag and drop from unity
//tf = GetComponent<Transform>();
}
private void OnMouseDown()
{
if (Selected == false)
{
Selected = true;
}
if (Selected == true)
{
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
tf.position = new Vector3(mousePos.x,mousePos.y,tf.position.z); // notice the tf.position.z
}
}
private void OnMouseUp()
{
if (Selected == true)
{
Selected = false;
}
}
}
I ended up figuring it out, I'm not sure what I was doing wrong but this new script seems to work great. Here's the script for people who want to plagiarize.
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
public class MoveTowards : MonoBehaviour
{
private Rigidbody2D rb;
public float force = 1f;
private bool selected = false;
public void Awake()
{
//Get rigidbody from the gameobject this script is attatched to
rb = GetComponent<Rigidbody2D>();
}
public void OnMouseDown()
{
//become selected when clicked
selected = true;
}
public void OnMouseUp()
{
//become deselected when you let go of left click
selected = false;
}
void Update()
{
if (selected == true)
{
//move towards mouse if selected
Vector3 mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
Vector3 dir = (mousePos - transform.position);
dir.z = 0.0f;
Vector3 dirNormalized = dir.normalized;
Vector2 relativePos = mousePos - gameObject.transform.position;
rb.AddForce(relativePos * force);
}
}
}
Related
The script is attached to two gameobjects.
One it's colliding area the collider is big enough so when the game start the player is already inside the collider area and then when he exit the area everything is working fine.
The problem is when I attached the object to another gameobject with collider but this time the collider s smaller and he is inside the bigger collider so now the player is entering the smaller collider and not first time exiting. but I want in both case to make the same effect.
If the player exit the collider he slow down wait then turn around and move inside back.
The same I want to make when the player getting closer to the fire flames slow down wait turn around and move back in it's just with the flames the player entering the collider area and then exit while in the bigger collider he first exit then enter.
Screenshot of the two colliders areas. The small one on the left is the one the player entering first and not exiting. The game start when the player is in the bigger collider area.
And the script :
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityStandardAssets.Characters.ThirdPerson;
public class DistanceCheck : MonoBehaviour
{
public Transform targetToRotateTowards;
public Transform colliderArea;
public float lerpDuration;
public float rotationSpeed;
[TextArea(1, 2)]
public string textToShow;
public GameObject descriptionTextImage;
public TextMeshProUGUI text;
public ThirdPersonUserControl thirdPersonUserControl;
private Animator anim;
private float timeElapsed = 0;
private float startValue = 1;
private float endValue = 0;
private float valueToLerp = 0;
private bool startRotating = false;
private bool slowOnBack = true;
private bool exited = false;
private Vector3 exitPosition;
private float distance;
void Start()
{
anim = transform.GetComponent<Animator>();
}
private void FixedUpdate()
{
if (startRotating)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation,
Quaternion.LookRotation(targetToRotateTowards.position - transform.position),
rotationSpeed * Time.deltaTime);
}
if (exitPosition != new Vector3(0, 0, 0) && slowOnBack)
{
distance = Vector3.Distance(transform.position, exitPosition);
}
if (distance > 5 && slowOnBack)
{
slowOnBack = false;
StartCoroutine(SlowDown());
}
}
private void OnTriggerExit(Collider other)
{
if (other.name == colliderArea.name)
{
exited = true;
slowOnBack = true;
exitPosition = transform.position;
thirdPersonUserControl.enabled = false;
descriptionTextImage.SetActive(true);
text.text = textToShow;
StartCoroutine(SlowDown());
}
}
private void OnTriggerEnter(Collider other)
{
if (other.name == colliderArea.name)
{
exited = false;
startRotating = false;
text.text = "";
descriptionTextImage.SetActive(false);
}
}
IEnumerator SlowDown()
{
timeElapsed = 0;
while (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
anim.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
yield return null;
}
if (exited)
{
yield return new WaitForSeconds(3f);
startRotating = true;
StartCoroutine(SpeedUp());
}
if (slowOnBack == false)
{
thirdPersonUserControl.enabled = true;
}
}
IEnumerator SpeedUp()
{
timeElapsed = 0;
while (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(endValue, startValue, timeElapsed / lerpDuration);
anim.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
yield return null;
}
}
}
Two problems I'm facing right now :
The smaller collider the player enter it then exit and the bigger collider the player exit it then enter so I need to change somehow the OnTriggerExit/Enter behavior logic in the script. but how to make the logic ?
Maybe it's better to make the script to be on the player object only and make it some how generic so I can drag to it many colliders and to make the effect in each one of the colliders the problem is how to make a text field for each collider area ? Now because I attach the script to each collider object I have one colliderArea variable but if I want to make the script only attached to the player I need to change the colliderArea variable to a List<Transform> collidersAreas and then how to create a text field/area to each collider area in the List ?
I think I would do this by creating two tags, NoExit and NoEntry. Once the tags are created you can set the tag on the GameObjects that hold your colliders. Then you can check for tags in the OnTriggerEnter and OnTriggerExit and act accordingly.
I can't tell for sure which functionality you've got written is for which case, or if it's both - everything looks muddled. Ultimately what you should be going for is a function like RepositionPlayer, that moves them back to before they're violating the no entry or no exit rules, and then some kind of OnPlayerRepositioned event that restores their control.
I'll leave it up to you to split out your functionality, but in general I'd look to do something like the following:
private void OnTriggerExit(Collider other)
{
if (other.tag == "NoExit")
{
RepositionPlayer();
}
else if(other.tag == "NoEntry")
{
OnPlayerRepositioned();
}
}
private void OnTriggerEnter(Collider other)
{
if (other.tag == "NoExit")
{
OnPlayerRepositioned();
}
else if(other.tag == "NoEntry")
{
RepositionPlayer();
}
}
And again here it's not clear to me what you're trying to do to reposition the player, but it looks like it's something like:
private void RepositionPlayer()
{
// Stuff that needs to happen to reposition the player
exited = true;
slowOnBack = true;
exitPosition = transform.position;
thirdPersonUserControl.enabled = false;
descriptionTextImage.SetActive(true);
text.text = textToShow;
StartCoroutine(SlowDown());
}
private void OnPlayerRepositioned()
{
// stuff you need to do to clear the "repositioning" status
exited = false;
startRotating = false;
text.text = "";
descriptionTextImage.SetActive(false);
}
Splitting up the logic like this makes it easier to both read and maintain.
I'm trying to make simple 2D game following tutorials when I did same thing as tutorial my jump functionality not working and left and right move functionality working please help me below I attached my source code and relevant screen shot
my player class
public class Player : MonoBehaviour
{
private Rigidbody2D _rigid;
//variable for jump
[SerializeField]
private float _jumpForce = 5.0f;
[SerializeField]
private LayerMask _grondLayer;
private bool _resetJump = false;
// Start is called before the first frame update
void Start()
{
_rigid = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
Movement();
}
void Movement()
{
float move = Input.GetAxisRaw("Horizontal");
_rigid.velocity = new Vector2(move,_rigid.velocity.y);
if(Input.GetKeyDown(KeyCode.Space) && IsGrounded()==true)
{
Debug.Log("jump");
_rigid.velocity = new Vector2(_rigid.velocity.x,_jumpForce);
StartCoroutine(ResetJumpNeededRoutine());
}
}
bool IsGrounded()
{
RaycastHit2D hitInfo = Physics2D.Raycast(transform.position, Vector2.down, 0.6f, _grondLayer);
if(hitInfo.collider != null)
{
if(_resetJump==false){return true;}
}
return false;
}
IEnumerator ResetJumpNeededRoutine()
{
_resetJump = true;
yield return new WaitForSeconds(0.1f);
_resetJump = false;
}
}
Correct way to implement the jump mechanism on 2d character.
_rigid.AddForce(new Vector2(0, _jumpForce), ForceMode2D.Impulse);
The problem is probably the LayerMask you selected Ground layer to be ignored therefore IsGrounded function will return false.
What you wanna do is select the layers you'd like your Raycast to ignore (All except Ground I assume) in the unity editor then give it another go.
When i'm moving the mouse around the player is walking facing to the mouse cursor.
Now i want to make that if i'm not moving the mouse to make the player idle.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldInteraction : MonoBehaviour
{
public int speed = 5; // Determines how quickly object moves towards position
public float rotationSpeed = 5f;
private Animator _animator;
private bool toMove = true;
private Vector3 tmpMousePosition;
UnityEngine.AI.NavMeshAgent playerAgent;
private void Start()
{
tmpMousePosition = Input.mousePosition;
_animator = GetComponent<Animator>();
_animator.CrossFade("Idle", 0);
playerAgent = GetComponent<UnityEngine.AI.NavMeshAgent>();
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && toMove == false &&
!UnityEngine.EventSystems.EventSystem.current.IsPointerOverGameObject())
{
toMove = true;
}
if (Input.GetMouseButtonDown(1) && toMove == true)
{
toMove = false;
}
if (toMove == true)
{
GetInteraction();
}
}
void GetInteraction()
{
if (tmpMousePosition != Input.mousePosition)
{
tmpMousePosition = Input.mousePosition;
_animator.CrossFade("Walk", 0);
Ray interactionRay = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit interactionInfo;
if (Physics.Raycast(interactionRay, out interactionInfo, Mathf.Infinity))
{
GameObject interactedObject = interactionInfo.collider.gameObject;
if (interactedObject.tag == "Interactable Object")
{
interactedObject.GetComponent<Interactable>().MoveToInteraction(playerAgent);
}
else
{
playerAgent.destination = interactionInfo.point;
}
}
}
else
{
_animator.CrossFade("Idle", 0);
}
}
}
I'm using the variable tmpMousePosition to check if the mouse is in a move or not. The problem is when it's on a move and the player is in "Walk" mode the player is stuttering each a second or so.
The idea is when the mouse is moving then move the player when the mouse is not moving make the player in Idle.
In the Update function i'm using a bool to stop/continue the interaction like a switch with the mouse left/right buttons. But now i want to use the mouse movement to Walk/Idle the player.
Just get the movement through Input.GetAxis("Mouse X") and if it's not moving , play Idle
I'm not so good with Visual Studio.
I'm making a simple game and my gameobject (player) should move up when Space or Left Mouse Button is pressed.
Here is my code
using UnityEngine;
using System.Collections;
public class PixelMovement : MonoBehaviour {
Vector3 velocity = Vector3.zero;
public Vector3 PressVelocity;
public float maxSpeed = 5f;
public float fowardSpeed = 1f;
bool didPress = false;
// Use this for initialization
void Start () {
}
//Do Graphic & Input updates
void update() {
if(Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) {
didPress = true;
}
}
//Do physics engine updates here
void FixedUpdate () {
velocity.x = fowardSpeed;
if (didPress == true){
didPress = false;
velocity += PressVelocity;
}
velocity = Vector3.ClampMagnitude(velocity, maxSpeed);
transform.position += velocity * Time.deltaTime;
}
}
So, it should move like contrary to gravity. And when it stops holding, it continues to fall. I already have gravity I just need that "Up movement"
//Do Graphic & Input updates
void update() {
if(Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) {
didPress = true;
}
}
I think the problem is because update() should be Update()
Try:
//Do Graphic & Input updates
void Update() {
if(Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButtonDown(0)) {
didPress = true;
}
}
This is a quick fix: You're calling Input.GetKeyDown() and Input.GetMouseButtonDown() which only return true on the first frame that the button is pressed.
If you want a repeating event (I.E., the mouse button or space is held down), use Input.GetKey(KeyCode.Space) and Input.GetMouseButton(0).
I am making a 2D platformer in Unity for iOS, and I need to make buttons so the user can move, but for some reason, the script I made is not working. Also, the script I am putting in is just for the Left button, but the Right and Jump scripts work the same way.
Code:
using UnityEngine;
using System.Collections;
public class Left : MonoBehaviour {
public GameObject player;
public GameObject button;
void Start () {
}
void Update () {
if (Input.GetKey (KeyCode.A)) {
player.GetComponent<PlayerAnimator>().animationState = MovementState.moveLeft;
player.transform.position+=Vector3.left / 30;
}
if (Input.touchCount > 0){
foreach(Touch touch in Input.touches){
Collider2D col = button.GetComponent<Collider2D>();
Vector3 tpos = Camera.main.ScreenToWorldPoint(new Vector3(touch.position.x, touch.position.y, 0));
if(col.bounds.Contains(tpos)){
Debug.Log ("left");
player.GetComponent<PlayerAnimator>().animationState = MovementState.moveLeft;
player.transform.position+=Vector3.left / 30;
}
}
}
}
void OnMouseOver(){
Debug.Log ("left");
player.GetComponent<PlayerAnimator>().animationState = MovementState.moveLeft;
player.transform.position+=Vector3.left / 30;
}
void OnMouseUp(){
player.GetComponent<PlayerAnimator> ().animationState = MovementState.idleLeft;
}
}
Don't use OnMouseOver for android application. It isn't usable on touch devices. But instead of it, OnMouseDrag function will work.
void OnMouseDrag(){
Debug.Log ("left");
player.GetComponent<PlayerAnimator>().animationState = MovementState.moveLeft;
player.transform.position+=Vector3.left / 30;
}
Edit: Because OnMouseOver is called when position of mouse is over object but not clicked. Otherwise OnMouseDrag is called when position of mouse is over object and clicked. In mobile devices OnMouseOver situation isn't possible.