How to detect touch in Unity Game Engine (2D) - unity3d

I have a bomb and want it to explode when touched. I just tried implementing this with ray-casting but something isn't working. I'm using unity 2d settings.
Also I'm programming this on a computer(of course) so is there some setting I have to set to make it recognize mouse clicks as touches?
#pragma strict
var explosion:GameObject;
function Update () {
for (var i = 0; i < Input.touchCount; i++) {
if (Input.GetTouch(i).phase == TouchPhase.Began) {
// Construct a ray from the current touch coordinates
var pos:Vector3 = Camera.main.ScreenToWorldPoint (Input.mousePosition);
var hitInfo:RaycastHit2D = Physics2D.Raycast(pos, Vector2.zero);
if (hitInfo != null && hitInfo.collider != null) {
Debug.Log ("I'm hitting "+hitInfo.collider.name);
var whatsHit:GameObject = hitInfo.collider.gameObject;
if(whatsHit.CompareTag("bomb")){
whatsHit.GetComponent(BombScript).Explode(whatsHit.transform.position);
}
} else {
Debug.Log("hitting nothing");
}
}
}
}
function Explode(pos:Vector3){
GameObject.FindGameObjectWithTag("GameController").GetComponent(BombSpawner).spawnBomb = true;
Instantiate(explosion, pos, Quaternion.identity);
Destroy (this.gameObject);
}

The OnMouseDown actually gets raised on touch as well. It, of course, limits your ability to track the finger Id, but if you don't need it then this is perfect since it does allow you to use it on both PC and touch devices with no extra code.

Related

I'm trying to make a touch based drag and drop UI element

I'm in the process of trying to convert an old game jam game to mobile, but I'm running into a number of issues with redesigning the UI. No surprise as I've never worked on a mobile game before.
One of the new things I'm trying to do is make it so that a certain UI element (a block) can be dragged around the screen. To be clear, this is a an image with a script attached. Not a sprite. There is no collider or rigidbody. However, I can't seem to get the touch event to recognize or interact with the block.
I know the touch event is working (the other buttons work fine, though they're just standard TMP_Buttons using OnClick), but not only is the block not moving when I drag it, I tried checking the tag of what my touch event is targeting and it's not the block.
Every tutorial I can find on touch events seems to be focused on 3d and non UI objects.
Here's the code for the update on my Block (where I'm looking for touch events).
private void Update()
{
if (Input.touchCount > 0)
{
Debug.Log("Touch detected");
Touch touch = Input.touches[0];
Vector3 v3 = new Vector3();
Vector3 pos = touch.position;
Ray ray = Camera.main.ScreenPointToRay(pos);
RaycastHit hit;
Vector3 dragStartPos = Camera.main.ScreenToWorldPoint(touch.position);
Debug.Log("Start Position: " + dragStartPos);
if (Physics.Raycast(ray, out hit))
{
Debug.Log(hit.collider.tag);
if (hit.collider.tag == "Block")
{
_toDrag = hit.transform;
v3 = new Vector3(pos.x, pos.y, 0);
v3 = Camera.main.ScreenToWorldPoint(v3);
_offset = _toDrag.position - v3;
_dragging = true;
}
}
if (_dragging && touch.phase == TouchPhase.Moved)
{
v3 = new Vector3(Input.mousePosition.x, Input.mousePosition.y, 0);
v3 = Camera.main.ScreenToWorldPoint(v3);
_toDrag.position = v3 + _offset;
}
if (_dragging && (touch.phase == TouchPhase.Ended || touch.phase == TouchPhase.Canceled))
{
_dragging = false;
}
}
}
There must be something I'm missing. Any ideas?

How do I make the 2D collider not do any function to already colliding objects before level start

In my level, I have a water collider where if you fall in, it triggers a splash effect and water sounds. However, because there is already an object inside the water, whenever I start the level, the water collider triggers and splash and water sounds despite the object already being in the collider.
So, even with the object deep inside the water collider, it creates the splash sound and water effect as if it just fell in.
How do I prevent this?
My code involves OnTrigger2D functions. But how do I make Unity check if an object is already colliding before level load?
Code:
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
gravityoriginal = playerrigidbody.gravityScale;
massoriginal = playerrigidbody.mass;
playerrigidbody.gravityScale = 0.1f;
playerrigidbody.mass = other.GetComponent<Rigidbody2D>().mass + 2f;
splash.Play(); //Plays the initial splash if velocity is high
underwaterbool.IsUnderwater = true; //stop dust particle
mainmusic.enabled = true;
powerupmusic.enabled = true;
deathmusic.enabled = true;
}
else if (other.tag == "Snatcher")
{
masssnatcheroriginal = snatcherrigidbody.mass;
gravityoriginalsnatcher = snatcherrigidbody.gravityScale;
snatcherrigidbody.gravityScale = 0.1f;
snatcherrigidbody.mass = other.GetComponent<Rigidbody2D>().mass + 2f;
splashsnatcher.Play();
snatchersounds.enabled = true;
}
else if (other.tag != "Player" && other.tag != "Snatcher" && other.GetComponent<Rigidbody2D>() != null)
{
gravityoriginalbox = other.GetComponent<Rigidbody2D>().gravityScale;
massoriginalbox = other.GetComponent<Rigidbody2D>().mass;
other.GetComponent<Rigidbody2D>().mass = other.GetComponent<Rigidbody2D>().mass + 2f;
other.GetComponent<Rigidbody2D>().gravityScale = 0.1f;
other.GetComponent<ParticleSystem>().Play(false);
splashaudio.Play();
Splashparticlesforbox.IsUnderwaterBox = true;
}
if(other.GetComponent<Rigidbody2D>() != null)
{
other.GetComponent<Rigidbody2D>().velocity = new Vector2(0f, -0.5f);
}
if (!cooldown)
{
splashaudio.Play();
}
cooldown = true;
StartCoroutine(waittime());
}
Can you post your OnTrigger2D functions code please? Normally Unity does not trigger the OnTriggerEnter method if an object is already inside the trigger when the scene beggins but the OnTriggerStay is executed every frame.
Anyway... one option (not the best one I think) would be to put a boolean propoerty in the trigger that is initialized true and use it to prevent the OnTriggerFunctions to do anything til the fame ends. Then in the LateUpdate method you can set the property as false.
bool m_FirstFrame = true;
void onEnable()
{
m_FirstFrame = true;
}
void OnTriggerEnter2D(Collider2D collision)
{
if(m_FirstFrame){
return;
}
.... //Rest of code
}
//Same for the other OnTrigger2D methods you use
void LateUpdate()
{
m_FirstFrame = false;
}
I hope it helps! Tell me if you need something more, and please, post your code, that way is easier for us to fint where is the issue and get how to fix it.
Good luck ^^

How to show a tracking line from where the model is placed in Augmented Reality?

I am looking to show a line in my app from where the model is placed so that the user knows position where the model is kept in real world. When user changes device camera away from model the line gets turned on to show where the model is. Similarly it turns off when model is detected. I have attached images to show from a similar app white dotted lines show the path. Notice how the lines disappear when the model is detected.
LineRenderer lins;
public GameObject Lineprefab;
private GameObject newline;
public Transform startpoint;
public Renderer m_rend1;
bool HitTestWithResultType (ARPoint point, ARHitTestResultType resultTypes)
{
List<ARHitTestResult> hitResults = UnityARSessionNativeInterface.GetARSessionNativeInterface ().HitTest (point, resultTypes);
if (hitResults.Count > 0 && check==true)
{
foreach (var hitResult in hitResults)
{
Debug.Log ("Got hit!");
//obj.Hideplane();
Genplanes.SetActive(false);
if (Select == 0) {
Debug.Log("hit-zero!");
Instantiate(Instaobj[0], ForSelect);
check = false;
}
if (Select == 1) {
Debug.Log("hit-one!");
Instantiate(Instaobj[1], ForSelect);
check = false;
}
if (Select == 2) {
Debug.Log("hit-two!");
Instantiate(Instaobj[2], ForSelect);
check = false;
}
m_HitTransform.position = UnityARMatrixOps.GetPosition (hitResult.worldTransform);
m_HitTransform.rotation = UnityARMatrixOps.GetRotation (hitResult.worldTransform);
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
obj.StopPlaneTracking();
}
}
return false;
}
private void Start()
{
spawngenerator();
newline.SetActive(false);
m_rend1 = GetComponent<MeshRenderer>();
}
void spawngenerator()
{
GameObject newline = Instantiate(Lineprefab);
lins = newline.GetComponent<LineRenderer>();
}
private void LateUpdate()
{
lins.SetPosition(0, startpoint.position);
lins.SetPosition(1, m_HitTransform.position);
if( m_rend1.isVisible==true)
{
Debug.Log("Render is Visible");
newline.SetActive(false);
}
else if( m_rend1.isVisible==false)
{
newline.SetActive(true);
Debug.Log("It is InVisible");
Debug.Log("Render is InVisible");
}
}
void Update () {
#if UNITY_EDITOR //we will only use this script on the editor side, though there is nothing that would prevent it from working on device
if (Input.GetMouseButtonDown (0)) {
Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
//we'll try to hit one of the plane collider gameobjects that were generated by the plugin
//effectively similar to calling HitTest with ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent
if (Physics.Raycast (ray, out hit, maxRayDistance, collisionLayer)) {
//we're going to get the position from the contact point
m_HitTransform.position = hit.point;
Debug.Log (string.Format ("x:{0:0.######} y:{1:0.######} z:{2:0.######}", m_HitTransform.position.x, m_HitTransform.position.y, m_HitTransform.position.z));
//and the rotation from the transform of the plane collider
m_HitTransform.rotation = hit.transform.rotation;
}
}
#else
if (Input.touchCount > 0 && m_HitTransform != null )
{
var touch = Input.GetTouch(0);
if ((touch.phase == TouchPhase.Began || touch.phase == TouchPhase.Moved) && !EventSystem.current.IsPointerOverGameObject(touch.fingerId))
{
var screenPosition = Camera.main.ScreenToViewportPoint(touch.position);
ARPoint point = new ARPoint {
x = screenPosition.x,
y = screenPosition.y
};
// prioritize reults types
ARHitTestResultType[] resultTypes = {
//ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingGeometry,
ARHitTestResultType.ARHitTestResultTypeExistingPlaneUsingExtent,
// if you want to use infinite planes use this:
//ARHitTestResultType.ARHitTestResultTypeExistingPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedHorizontalPlane,
//ARHitTestResultType.ARHitTestResultTypeEstimatedVerticalPlane,
//ARHitTestResultType.ARHitTestResultTypeFeaturePoint
};
foreach (ARHitTestResultType resultType in resultTypes)
{
if (HitTestWithResultType (point, resultType))
{
return;
}
}
}
}
#endif
}
.
First, I 'd start with checking if the model is within the bounding box of the camera https://docs.unity3d.com/ScriptReference/Renderer-isVisible.html
if the object is not visible (isVisible == false), create a line renderer from object position to wherever it should end.
The end point could be a camera child place just in front of it, so it looks like it starts from the user to the object.

Change object on button down precisely at an object

I have a target object (cube), and a fake mouse that I created from an object (sphere) to be controlled by gamepad joystick. I want to bring out another object (let say; sphere), when I push the gamepad button and precisely hit the target object (cube).
Before, I have tried with a mouse click, and it succeeds, but when I controlled the fake mouse with a joystick, when I press the button even outside the target (cube) it still brings out another object. Here is the code, if anybody can help me to revise it. Thanks
function Start () {}
function Update () {
if (Input.GetButtonDown ("Fire1"))
{
var Cube = GameObject.FindGameObjectsWithTag ("Cube");
if (Cube[0].GetComponent(MeshRenderer).enabled){
var Circle1 = GameObject.FindGameObjectsWithTag ("Circle1");
Circle1[0].GetComponent(MeshRenderer).enabled = true;
Circle1[0].GetComponent(MeshRenderer).material.color = color.red;
}
}
}
[solved]
Thanks to EmreE and Draco18s for replying my question. I have solved it, I made a collision trigger indeed.
Here is my code after several trials.
if (Input.GetButtonDown ("Fire1") && isCollide)
{
var Cube = GameObject.FindGameObjectsWithTag ("Cube");
if (Cube[0].GetComponent(MeshRenderer).enabled){
var Circle1 = GameObject.FindGameObjectsWithTag ("Circle1");
Circle1[0].GetComponent(MeshRenderer).enabled = true;
Circle1[0].GetComponent(MeshRenderer).material.color = Color.red;
Debug.Log("Muncul");
}
}
function OnTriggerEnter (col : Collider)
{
Debug.Log(isCollide);
if(col.gameObject.name == "Mouse3DSphere")
{
isCollide = true;
}
}
function OnTriggerExit (col : Collider)
{
Debug.Log(isCollide);
if(col.gameObject.name == "Mouse3DSphere")
{
isCollide = false;
}
}

Moving object with raycast issues

I have written a script where a gameobject is intended to move to a raycast.point thrown from the player camera. For the most part this works fine, however there are times (approximately when camera is 45 degrees up from the object) when the object rapidly moves towards the camera (i.e. raycast source).
I have tried a number of approaches attempting to resolve this, however I can’t seem to dig out the root of this issue. Managed to prevent this from occurring by deactivating the collider attached to the object being moved. However I need the collider for various reasons so this approach is not appropriate.
If anyone can provide any pointers as to where I am going wrong I would be incredibly grateful.
NB: coding in uJS
Many thanks in advance, Ryan
function FixedUpdate() {
if (modObj != null && !guiMode) {
//Panel Control
if (!selectObjPanel.activeSelf && !modifySelectObjPanel.activeSelf) //if the selectpanel not open and modSelect not already activated
{
activateModSelectObjPanel(true); //activate it
} else if (selectObjPanel.activeSelf) {
activateModSelectObjPanel(false);
}
//Move
if (Input.GetKey(KeyCode.E)) {
if (Input.GetKeyDown(KeyCode.E)) {
// modObj.GetComponent(BoxCollider).enabled = false;
modObj.GetComponent(Rigidbody).isKinematic = true;
modObj.GetComponent(Rigidbody).useGravity = false;
//
initPos = modObj.transform.position;
var initRotation = modObj.transform.rotation;
}
moveObject(modObj, initPos, initRotation);
} else {
// modObj.GetComponent(BoxCollider).enabled = true;
modObj.GetComponent(Rigidbody).isKinematic = false;
modObj.GetComponent(Rigidbody).useGravity = true;
}
}
}
function moveObject(modObj: GameObject, initPos: Vector3, initRotation: Quaternion) {
//Debug.Log("Moving Object");
var hit: RaycastHit;
var foundHit: boolean = false;
foundHit = Physics.Raycast(transform.position, transform.forward, hit);
//Debug.DrawRay(transform.position, transform.forward, Color.blue);
if (foundHit && hit.transform.tag != "Player") {
//Debug.Log("Move to Hit Point: " + hit.point);
modifyObjGUIscript.activateMoveDisplay(initPos, hit.point);
var meshHalfHeight = modObj.GetComponent. < MeshRenderer > ().bounds.size.y / 2; //helps account for large and small objects
// Debug.Log("CurObj Mesh Min: " + meshHalfHeight);
// modObj.transform.position = hit.point; //***method 01***
// modObj.transform.position = Vector3.Lerp(initPos, hit.point, speed); //***method 02***
// modObj.transform.position = Vector3.SmoothDamp(initPos, hit.point, velocity, smoothTime); //***method 02***
var rb = modObj.GetComponent. < Rigidbody > ();
rb.MovePosition(hit.point); //***method 03***
modObj.transform.position.y = modObj.transform.position.y + meshHalfHeight + hoverHeight;
modObj.transform.rotation = initRotation;
}
}
Turns out the issue was being caused by the raycast hitting the object being moved. Resolved this by only allowing hits from the terrain to be used as points to move to.
if(foundHit && hit.transform.tag == "Terrain")