I'm not very good with Unity especially in AR, but I finally built my first AR game. However, there is one issue: when I place my game objects on the plane, I want them to be still and want them to move when I touch the display. Is there a way to disable the touch hit or whatever it is called?
......................................................................................................................................................................................................................................................................................................................................................................................................
enter code here
[RequireComponent(typeof(ARRaycastManager))]
public class PlaceOnPlane : MonoBehaviour
{
[SerializeField]
[Tooltip("Instantiates this prefab on a plane at the touch location.")]
GameObject m_PlacedPrefab;
/// <summary>
/// The prefab to instantiate on touch.
/// </summary>
public GameObject placedPrefab
{
get { return m_PlacedPrefab; }
set { m_PlacedPrefab = value; }
}
/// <summary>
/// The object instantiated as a result of a successful raycast
intersection with a plane.
/// </summary>
public GameObject spawnedObject { get; private set; }
void Awake()
{
m_RaycastManager = GetComponent<ARRaycastManager>();
}
bool TryGetTouchPosition(out Vector2 touchPosition)
{
#if UNITY_EDITOR
if (Input.GetMouseButton(0))
{
var mousePosition = Input.mousePosition;
touchPosition = new Vector2(mousePosition.x, mousePosition.y);
return true;
}
else
if (Input.touchCount > 0)
{
touchPosition = Input.GetTouch(0).position;
return true;
}
#endif
touchPosition = default;
return false;
}
void Update()
{
if (!TryGetTouchPosition(out Vector2 touchPosition))
return;
if (m_RaycastManager.Raycast(touchPosition, s_Hits, TrackableType.PlaneWithinPolygon))
{
// Raycast hits are sorted by distance, so the first one
// will be the closest hit.
var hitPose = s_Hits[0].pose;
if (spawnedObject == null)
{
spawnedObject = Instantiate(m_PlacedPrefab,
hitPose.position, hitPose.rotation);
}
else
{
spawnedObject.transform.position = hitPose.position;
}
}
}
static List<ARRaycastHit> s_Hits = new List<ARRaycastHit>();
ARRaycastManager m_RaycastManager;
}
Depending on your comments, if you are placing the object with the button, all you need to do right now is to disable this script that you have attached here. The object should not be moving since what causes its movement is this code bit in Update:
spawnedObject.transform.position = hitPose.position;
You can either comment out this part or deactivate the script, both should work fine.
Related
I have some childs on my main gameobject, what am I down wrong on the below code? I bassically want to access to the sprite renderer of the childs of my game object,
If I put that code on the direct child that have the sprite render I can access to the sprite with GetComponent, please if anyone know what can I do let me know
SpriteRenderer sprite;
private bool changeColorState = false;
public float time;
void Start(){
sprite = GetComponentsInChildren<SpriteRenderer>();
}
void Update(){
StartCoroutine(timeOfColorChange());
}
IEnumerator timeOfColorChange(){
yield return new WaitForSeconds(time);
if (changeColorState) {
chooseColor(.5f);
} else {
chooseColor(1f);
}
}
private void OnTriggerEnter2D(Collider2D otherObject){
if (otherObject.GetComponent<Player>()) {
changeColorState = true;
}
}
private void OnTriggerExit2D(Collider2D otherObject){
if (otherObject.GetComponent<Player>()) {
changeColorState = false;
}
}
public void chooseColor(float float1){
this.GetComponent<SpriteRenderer>().color = new Color(1f, 1f, 1f, float1);
}
I've tried GetComponentsOnChild but it's not working
You're not using the "sprite" variable inside chooseColor, where you're using GetComponent instead of GetComponentInChildren. Swap it for sprite.color and it should work.
Can someone explain why this code is not working as intended? Currently if there is a collision the sprite (flag) changes to green. The debug statements are working as I would expect but the sprite (flag) is not changed back to red in the event of no collision.
public Sprite gflag;
public Sprite rflag;
public SpriteRenderer render;
public GameObject Player;
private Checkpoint checkpoint;
private bool hit = false;
void Update()
{
if(hit != true)
{
Debug.Log("False!");
render.sprite = rflag;
}
}
// Modify color of flag depending on collision
void OnTriggerEnter2D(Collider2D collider)
{
if (collider.gameObject.tag == "Player")
{
Debug.Log("True!");
render.sprite = gflag;
hit = true;
}
}
Here is a screen shot of the checkpoint prefab:
Have you considered moving the logic in the Update() function to a OnTriggerExit2D function?
public Sprite gflag;
public Sprite rflag;
public SpriteRenderer render;
public GameObject Player;
private Checkpoint checkpoint;
private bool hit = false;
// Modify color of flag depending on collision
void OnTriggerEnter2D(Collider2D collider)
{
if (collider.gameObject.tag == "Player")
{
Debug.Log("True!");
render.sprite = gflag;
hit = true;
}
}
// Modify color of flag depending on collision
void OnTriggerExit2D(Collider2D collider)
{
if (collider.gameObject.tag == "Player")
{
Debug.Log("False!");
render.sprite = rflag;
hit = false;
}
}
This way, instead of checking in Update every frame, it will be handled within the collision functions entirely.
EDIT: To answer your initial question, the reason the code was not updating the flag back to red in the case of no collision is because you were not setting the hit boolean to false once the collision was exited.
I had my unity movement working on my computer, however when i try to play on my android it is not moving for me at all. I am sure it is probably a small error i am overlooking but i would be very appreciative of any help! I do not get any errors when i try yo run my code if that is of any assistance! I will supply the code below:
using UnityEngine;
using System.Collections;
//Adding this allows us to access members of the UI namespace including Text.
using UnityEngine.UI;
public class PlayerControler : MonoBehaviour {
public Text countText; //Store a reference to the UI Text component which will display the number of pickups collected.
//public Text winText; //Store a reference to the UI Text component which will display the 'You win' message.
private double count; //Integer to store the number of pickups collected so far.
//Player movement controls
private Vector3 touchPosition; //where your finger touches screen
private Vector3 direction; //direction you drag sprite
private Rigidbody2D rb2d; //Store a reference to the Rigidbody2D component required to use 2D Physics.
public float speed = 10f; //Floating point variable to store the player's movement speed.
// Use this for initialization
void Start()
{
//Get and store a reference to the Rigidbody2D component so that we can access it.
rb2d = GetComponent<Rigidbody2D> ();
//Initialize count to zero.
count = 0;
//Initialze winText to a blank string since we haven't won yet at beginning.
//winText.text = " "; //error here??
//Call our SetCountText function which will update the text with the current value for count.
//SetCountText ();
}
void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
touchPosition = Camera.main.ScreenToWorldPoint(touch.position);
touchPosition.z = 0;
direction = (touchPosition - transform.position);
rb2d.velocity = new Vector2(direction.x , direction.y) * speed;
if(touch.phase == TouchPhase.Ended)
{
rb2d.velocity = Vector2.zero;
}
}
}
//OnTriggerEnter2D is called whenever this object overlaps with a trigger collider.
void OnTriggerEnter2D(Collider2D other)
{
//Check the provided Collider2D parameter other to see if it is tagged "PickUp", if it is...
if (other.gameObject.CompareTag ("PickUp"))
{
//... then set the other object we just collided with to inactive.
other.gameObject.SetActive(false);
//Add one to the current value of our count variable.
count = count + 1;
//Update the currently displayed count by calling the SetCountText function.
//SetCountText ();
}
}
Here is my 2D Player Movement Controller.
Code(Character Controller) -
using UnityEngine;
using UnityEngine.Events;
public class CharacterController2D : MonoBehaviour
{
[SerializeField] private float m_JumpForce = 400f; // Amount of force added when the player jumps.
[Range(0, 1)] [SerializeField] private float m_CrouchSpeed = .36f; // Amount of maxSpeed applied to crouching movement. 1 = 100%
[Range(0, .3f)] [SerializeField] private float m_MovementSmoothing = .05f; // How much to smooth out the movement
[SerializeField] private bool m_AirControl = false; // Whether or not a player can steer while jumping;
[SerializeField] private LayerMask m_WhatIsGround; // A mask determining what is ground to the character
[SerializeField] private Transform m_GroundCheck; // A position marking where to check if the player is grounded.
[SerializeField] private Transform m_CeilingCheck; // A position marking where to check for ceilings
[SerializeField] private Collider2D m_CrouchDisableCollider; // A collider that will be disabled when crouching
const float k_GroundedRadius = .2f; // Radius of the overlap circle to determine if grounded
private bool m_Grounded; // Whether or not the player is grounded.
const float k_CeilingRadius = .2f; // Radius of the overlap circle to determine if the player can stand up
private Rigidbody2D m_Rigidbody2D;
private bool m_FacingRight = true; // For determining which way the player is currently facing.
private Vector3 m_Velocity = Vector3.zero;
[Header("Events")]
[Space]
public UnityEvent OnLandEvent;
[System.Serializable]
public class BoolEvent : UnityEvent<bool> { }
public BoolEvent OnCrouchEvent;
private bool m_wasCrouching = false;
private void Awake()
{
m_Rigidbody2D = GetComponent<Rigidbody2D>();
if (OnLandEvent == null)
OnLandEvent = new UnityEvent();
if (OnCrouchEvent == null)
OnCrouchEvent = new BoolEvent();
}
private void FixedUpdate()
{
bool wasGrounded = m_Grounded;
m_Grounded = false;
// The player is grounded if a circlecast to the groundcheck position hits anything designated as ground
// This can be done using layers instead but Sample Assets will not overwrite your project settings.
Collider2D[] colliders = Physics2D.OverlapCircleAll(m_GroundCheck.position, k_GroundedRadius, m_WhatIsGround);
for (int i = 0; i < colliders.Length; i++)
{
if (colliders[i].gameObject != gameObject)
{
m_Grounded = true;
if (!wasGrounded)
OnLandEvent.Invoke();
}
}
}
public void Move(float move, bool crouch, bool jump)
{
// If crouching, check to see if the character can stand up
if (!crouch)
{
// If the character has a ceiling preventing them from standing up, keep them crouching
if (Physics2D.OverlapCircle(m_CeilingCheck.position, k_CeilingRadius, m_WhatIsGround))
{
crouch = true;
}
}
//only control the player if grounded or airControl is turned on
if (m_Grounded || m_AirControl)
{
// If crouching
if (crouch)
{
if (!m_wasCrouching)
{
m_wasCrouching = true;
OnCrouchEvent.Invoke(true);
}
// Reduce the speed by the crouchSpeed multiplier
move *= m_CrouchSpeed;
// Disable one of the colliders when crouching
if (m_CrouchDisableCollider != null)
m_CrouchDisableCollider.enabled = false;
}
else
{
// Enable the collider when not crouching
if (m_CrouchDisableCollider != null)
m_CrouchDisableCollider.enabled = true;
if (m_wasCrouching)
{
m_wasCrouching = false;
OnCrouchEvent.Invoke(false);
}
}
// Move the character by finding the target velocity
Vector3 targetVelocity = new Vector2(move * 10f, m_Rigidbody2D.velocity.y);
// And then smoothing it out and applying it to the character
m_Rigidbody2D.velocity = Vector3.SmoothDamp(m_Rigidbody2D.velocity, targetVelocity, ref m_Velocity, m_MovementSmoothing);
// If the input is moving the player right and the player is facing left...
if (move > 0 && !m_FacingRight)
{
// ... flip the player.
Flip();
}
// Otherwise if the input is moving the player left and the player is facing right...
else if (move < 0 && m_FacingRight)
{
// ... flip the player.
Flip();
}
}
// If the player should jump...
if (m_Grounded && jump)
{
// Add a vertical force to the player.
m_Grounded = false;
m_Rigidbody2D.AddForce(new Vector2(0f, m_JumpForce));
}
}
private void Flip()
{
// Switch the way the player is labelled as facing.
m_FacingRight = !m_FacingRight;
// Multiply the player's x local scale by -1.
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
And here is the actual Character Movement Code -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public CharacterController2D controller;
public float runSpeed = 40f;
float horizontalMove = 0f;
bool jump = false;
private void Update()
{
horizontalMove = Input.GetAxisRaw("Horizontal") * runSpeed;
if(Input.GetButtonDown("Jump"))
{
jump = true;
}
}
private void FixedUpdate()
{
controller.Move(horizontalMove * Time.fixedDeltaTime, false, jump);
jump = false;
}
}
Maybe the movement on android device is too small to be noticed. Try multiplying speed to delta time and then tweak the speed value to reach your desired movement speed.
rb2d.velocity = new Vector2(direction.x , direction.y) * speed * Time.deltaTime;
Make sure the script is attached to the game object with Rigidbody2D component. Also if your computer doesn't support touch, you can use mouse input to have the same result on computer and mobile device.
if (Input.GetMouseButtonUp(0))
{
rb2d.velocity = Vector2.zero;
}
else if (Input.GetMouseButton(0))
{
touchPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
touchPosition.z = 0;
direction = (touchPosition - transform.position);
rb2d.velocity = new Vector2(direction.x, direction.y) * speed * Time.deltaTime;
}
This code is also works on mobile devices.
Try adding Time.deltaTime or increasing the force with Time.deltaTime.
From a top down perspective I am trying to make it so that a player can fall into a pit. I want to use 2DCircleCollider.IsTouching(ContactFilter2D) to check whether the players hitbox overlaps with the ground but this always returns false despite OverlapCollider fuctioning correctly with the same contactfilter. My character has a rigidbody attatched and the ground does not. Are these two functions fundamentally different or am I using IsTouching wrong?
EDIT
public class CollisionChecker : MonoBehaviour
{
private CircleCollider2D p1Box;
private Rigidbody2D rb2d;
//public LayerMask Iceberg;
public ContactFilter2D cf2d;
// Use this for initialization
void Start()
{
p1Box = GetComponent<CircleCollider2D>();
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
int debugcount = 0;
Collider2D\[\] results = new Collider2D\[100\];
p1Box.OverlapCollider(cf2d, results);
for (int i = 0; i < results.Length; i++)
{
if (results\[i\] != null)
{
debugcount++;
}
else
{
break;
}
}
Debug.Log(debugcount);
Debug.Log(p1Box.IsTouching(cf2d));
debugcount = 0;
//if (!rb2d.IsTouchingLayers(Iceberg))
//{
// Debug.Log("AAAAAAAAAAAAAAA");
//}
}
}
player object with inspector
ground tile with inspector
I have script called PlayerCharacter to control a player on the Unity 2D Platform. It's perfect, working as usual.
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
[RequireComponent(typeof (Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]
public class PlayerCharacter : MonoBehaviour
{
public float speed = 1.0f;
public string axisName = "Horizontal";
private Animator anim;
public string jumpButton = "Fire1";
public float jumpPower = 10.0f;
public float minJumpDelay = 0.5f;
public Transform[] groundChecks;
private float jumpTime = 0.0f;
private Transform currentPlatform = null;
private Vector3 lastPlatformPosition = Vector3.zero;
private Vector3 currentPlatformDelta = Vector3.zero;
// Use this for initialization
void Start ()
{
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update ()
{
//Left and right movement
anim.SetFloat("Speed", Mathf.Abs(Input.GetAxis(axisName)));
if(Input.GetAxis(axisName) < 0)
{
Vector3 newScale = transform.localScale;
newScale.x = -1.0f;
transform.localScale = newScale;
Debug.Log("Move to left");
}
else if(Input.GetAxis(axisName) > 0)
{
Vector3 newScale = transform.localScale;
newScale.x = 1.0f;
transform.localScale = newScale;
Debug.Log ("Move to Right");
}
transform.position += transform.right*Input.GetAxis(axisName)*speed*Time.deltaTime;
//Jump logic
bool grounded = false;
foreach(Transform groundCheck in groundChecks)
{
grounded |= Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
}
anim.SetBool("Grounded", grounded);
if(jumpTime > 0)
{
jumpTime -= Time.deltaTime;
}
if(Input.GetButton("jumpButton") && anim.GetBool("Grounded") )
{
anim.SetBool("Jump",true);
rigidbody2D.AddForce(transform.up*jumpPower);
jumpTime = minJumpDelay;
}
if(anim.GetBool("Grounded") && jumpTime <= 0)
{
anim.SetBool("Jump",false);
}
//Moving platform logic
//Check what platform we are on
List<Transform> platforms = new List<Transform>();
bool onSamePlatform = false;
foreach(Transform groundCheck in groundChecks)
{
RaycastHit2D hit = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
if(hit.transform != null)
{
platforms.Add(hit.transform);
if(currentPlatform == hit.transform)
{
onSamePlatform = true;
}
}
}
if(!onSamePlatform)
{
foreach(Transform platform in platforms)
{
currentPlatform = platform;
lastPlatformPosition = currentPlatform.position;
}
}
}
void LateUpdate()
{
if(currentPlatform != null)
{
//Determine how far platform has moved
currentPlatformDelta = currentPlatform.position - lastPlatformPosition;
lastPlatformPosition = currentPlatform.position;
}
if(currentPlatform != null)
{
//Move with the platform
transform.position += currentPlatformDelta;
}
}
}
A problem arises when I try to modify the script with a touchable controller. I have googled many times and modified the script as I could, and still it gives me no result (btw, I'm new to Unity). Then I found a tutorial from a website about making a touch controller with a GUI Texture (TouchControls). I think that tutorial is easy to learn. Here is the script
using UnityEngine;
using System.Collections;
[RequireComponent(typeof (Rigidbody2D))]
[RequireComponent(typeof(BoxCollider2D))]
public class TouchControls : MonoBehaviour {
// GUI textures
public GUITexture guiLeft;
public GUITexture guiRight;
public GUITexture guiJump;
private Animator anim;
// Movement variables
public float moveSpeed = 5f;
public float jumpForce = 50f;
public float maxJumpVelocity = 2f;
// Movement flags
private bool moveLeft, moveRight, doJump = false;
void Start ()
{
anim = gameObject.GetComponent<Animator>();
}
// Update is called once per frame
void Update () {
// Check to see if the screen is being touched
if (Input.touchCount > 0)
{
// Get the touch info
Touch t = Input.GetTouch(0);
// Did the touch action just begin?
if (t.phase == TouchPhase.Began)
{
// Are we touching the left arrow?
if (guiLeft.HitTest(t.position, Camera.main))
{
Debug.Log("Touching Left Control");
moveLeft = true;
}
// Are we touching the right arrow?
if (guiRight.HitTest(t.position, Camera.main))
{
Debug.Log("Touching Right Control");
moveRight = true;
}
// Are we touching the jump button?
if (guiJump.HitTest(t.position, Camera.main))
{
Debug.Log("Touching Jump Control");
doJump = true;
}
}
// Did the touch end?
if (t.phase == TouchPhase.Ended)
{
// Stop all movement
doJump = moveLeft = moveRight = false;
}
}
// Is the left mouse button down?
if (Input.GetMouseButtonDown(0))
{
// Are we clicking the left arrow?
if (guiLeft.HitTest(Input.mousePosition, Camera.main))
{
Debug.Log("Touching Left Control");
moveLeft = true;
}
// Are we clicking the right arrow?
if (guiRight.HitTest(Input.mousePosition, Camera.main))
{
Debug.Log("Touching Right Control");
moveRight = true;
}
// Are we clicking the jump button?
if (guiJump.HitTest(Input.mousePosition, Camera.main))
{
Debug.Log("Touching Jump Control");
doJump = true;
}
}
if (Input.GetMouseButtonUp(0))
{
// Stop all movement on left mouse button up
doJump = moveLeft = moveRight = false;
}
}
void FixedUpdate()
{
//anim.SetFloat("Speed", Mathf.Abs);
// Set velocity based on our movement flags.
if (moveLeft)
{
rigidbody2D.velocity = -Vector2.right * moveSpeed;
}
if (moveRight)
{
rigidbody2D.velocity = Vector2.right * moveSpeed;
}
if (doJump)
{
// If we have not reached the maximum jump velocity, keep applying force.
if (rigidbody2D.velocity.y < maxJumpVelocity)
{
rigidbody2D.AddForce(Vector2.up * jumpForce);
} else {
// Otherwise stop jumping
doJump = false;
}
}
}
}
But I have no idea how to implement the script from the tutorial (TouchControls) and assign that to my player control script (PlayerCharacter). How can I combine both scripts so that a player can control it with a touchable control?
The best thing you can do is not to drag the touch controls from the touchcontrols tutorial to the playercontroller but the other way around, use the touchcontrols tutorial script as your template.
Since your playercontroller uses floats in its input such as moveleft = 50.0f; and the touchcontrols uses moveleft = true;
the scripts are very different from each other to just merge and work.
so from that in the touchcontrols leave the update function as it is,
and only update the fixedupate function with your controls logic since
the update void, is the condition controller for right, left, up & down so to speak.
and it will also handle the actual input of the touch.
the fixed update could then control some things that the playercontroller has such as
apply force when touching a tagged object or stuff like that.
and the update only does the input condition, good advice would be to wrap the update touch code in its own function so the update is not only touch but also other game logic related code.
You should search use copy the touch control script inside the player controller while changing the right parts. For example, instead of using Input.GetKeyDown you should use the Input.GetTouch but it depends on the game you are creating. You should pay attention to that code and change some parts