I have a written a multi-touch system that works correctly with objects that have collider2d (use them as buttons) and i can move the player in my android phone.
But when i use an image from the UI canvas system and add this code to the image, it doesn't detect any thing ?!
here is my code :
using UnityEngine;
using System.Collections;
public class Jump : MonoBehaviour {
public float jumpForce;
private GameObject hero;
void Start () {
hero = GameObject.Find("hero");
}
void Update () {
if (Input.touchCount > 0)
{
Touch[] myTouches = Input.touches;
for(int i = 0; i < Input.touchCount; i++)
{
if(Input.GetTouch(i).phase == TouchPhase.Began)
{
CheckTouch(Input.GetTouch(i).position, "began");
}
else if (Input.GetTouch(i).phase == TouchPhase.Ended)
{
CheckTouch(Input.GetTouch(i).position, "ended");
}
}
}
}
void CheckTouch (Vector3 pos, string phase)
{
Vector3 wp = Camera.main.ScreenToWorldPoint (pos);
Vector2 touchPos = new Vector2 (wp.x, wp.y);
Collider2D hit = Physics2D.OverlapPoint(touchPos);
if(hit.gameObject.name == "JumpButton" && hit && phase == "began")
{
hero.rigidbody2D.AddForce(new Vector2(0f, jumpForce)); //Add jump force to hero
audio.Play ();
}
}
}
any help?
For Graphics items in canvas you need to use GraphicRaycaster instead of Physics2D using UnityEngine.UI
You don't have to work with touches yourself anymore. Just implement IPointerClickHandler interface and make sure you have EventSystem and an appropriate raycaster present in the scene.
Related
I have a project that use Android to display Unity Player. So I export Untiy project as Android module which implemented by Android Application.
I create buttons in Android Activity which contains UnityPlayer, And when I click button, it send a message to Unity Player to invoke C# function, just like this:
findViewById(R.id.btnChange).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mUnityPlayer.UnitySendMessage("ScriptHolder", "ChangeSkin", "");
}
});
And the function named "ChangeSkin" is just to change some GameObjects' active. Just like this:
void ChangeSkin()
{
int prefab;
if (_currentPrefab == PREFAB_DEFAULT)
{
prefab = PREFAB_PRINCESS;
}
else
{
prefab = PREFAB_DEFAULT;
}
ShowSkin(prefab);
}
private void ShowSkin(int prefab)
{
_currentPrefab = prefab;
foreach (var item in _defaultDressList)
{
item.SetActive(prefab == PREFAB_DEFAULT);
}
foreach (var item in _princessDressList)
{
item.SetActive(prefab == PREFAB_PRINCESS);
}
}
And something weird happening: when I click button to change the person's cloth in Unity, the GameObjects which called SetActive(true) show at the position above the right position for a frame and become normal, it looks like they flash. Here is the gif of the project demo:
It looks like the position offset is equal to the height of status bar. If I create a button on Unity Scene and call "ChangeSkin" function, everything will be OK.
I tried all I can to fix this but not succeed. So I hope you will help me, thx.
You should check your Unity layout. If you have a layout group that has content size fitter component, and the child objects also have it (content size fitter), this could cause these glitches.
I fixed this problem by using a flag (or trigger). Just like this:
// set value true to trigger ChangeSkin() in Update(),
// instead of invoke ChangeSkin() directly
private bool _changingSkinTrigger = false;
void ChangeSkin()
{
if (_currentPrefab == PREFAB_DEFAULT)
{
_currentPrefab = PREFAB_PRINCESS;
}
else
{
_currentPrefab = PREFAB_DEFAULT;
}
_changingSkinTrigger = true;
}
void Update()
{
if (_changingSkinTrigger)
{
_changingSkinTrigger = false;
ShowSkin();
}
}
private void ShowSkin()
{
foreach (var item in _defaultDressList)
{
item.SetActive(_currentPrefab == PREFAB_DEFAULT);
}
foreach (var item in _princessDressList)
{
item.SetActive(_currentPrefab == PREFAB_PRINCESS);
}
}
Thank #AndriyMarshalek for enlightening me.
I am trying to convert my PC game code in unity to android and I am stuck on the controls change. Please help!
This is the code:
Getting the state of rocket.
enum State { Dying, Alive, Transcending }
State state = State.Alive;
// Update is called once per frame
void Update()
{
if (state == State.Alive)
{
RespondToThrustInput();
RespondToRotateInput();
}
}
When the rocket collides with anything it checks whether it's friendly or not before changing its state from alive to dead.
private void OnCollisionEnter(Collision collision)
{
if (state != State.Alive) { return; }
switch (collision.gameObject.tag)
{
case "Friendly":
break;
case "Finish":
state = State.Transcending;
audioSource.Stop();
audioSource.PlayOneShot(finishgame);
finishgameParticles.Play();
Invoke("LoadNextScene", levelloaddelay);
break;
default:
state = State.Dying;
audioSource.Stop();
audioSource.PlayOneShot(death);
deathParticles.Play();
Invoke("LoadFirstScene", levelloaddelay);
break;
}
}
private void LoadFirstScene()
{
SceneManager.LoadScene(9);
}
Loading next scene using build index.
private void LoadNextScene()
{
if (nextscenetoload > 7)
{
nextscenetoload = 0;
}
SceneManager.LoadScene(nextscenetoload);
}
Space for ignition or force and audio sources for playing sound effects.
private void RespondToThrustInput()
{
if (Input.GetKey(KeyCode.Space))
{
ApplyThrust();
}
else
{
audioSource.Stop();
mainengineParticles.Stop();
}
}
Apply thrust is the method I wrote with the logic of the rocket thrust.
private void ApplyThrust()
{
rigidbody.AddRelativeForce(Vector3.up * mainThrust * Time.deltaTime);
if (!audioSource.isPlaying)
audioSource.PlayOneShot(mainengine);
mainengineParticles.Play();
}
Rotation of the rocket or Left and right. Here I am trying to rotate the rocket using the A and D keys
void RespondToRotateInput()
{
float rotationThisFrame = rcsThrust * Time.deltaTime;
if (Input.GetKey(KeyCode.A))
{
rigidbody.freezeRotation = true;
transform.Rotate(Vector3.forward * rotationThisFrame);
rigidbody.freezeRotation = false;
}
else if (Input.GetKey(KeyCode.D))
{
rigidbody.freezeRotation = true;
transform.Rotate(-Vector3.forward * rotationThisFrame);
rigidbody.freezeRotation = false;
}
}
For PC games there is a keyboard to use to control, but for the android there are touches, you have to verify if there is a touch on the screen, like this:
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
//do something
}
also you need more work to determine where the touch is located and do you customizations... or in case you're not interested about this input handling, you can use some assets from Unity Assets Store to cover this part for you.
check this link for more information about touch control in Unity documentation:
https://docs.unity3d.com/ScriptReference/Input.GetTouch.html
I have an AR Screen where I placed some 3d objects. I am using google AR Core with android SDK.
I need to remove those objects from the scene on clicking of a clear button.
I was able to remove the last placed object. But the other objects were not removing.
This is the code i am using.
if (newAnchor != null) {
arFragment.getArSceneView().getScene().removeChild(newAnchor);
newAnchor.getAnchor().detach();
you can detach android model from scene form using below code
List<Node> children = new ArrayList<>(arFragment.getArSceneView().getScene().getChildren());
for (Node node : children) {
if (node instanceof AnchorNode) {
if (((AnchorNode) node).getAnchor() != null) {
((AnchorNode) node).getAnchor().detach();
}
}
if (!(node instanceof Camera) && !(node instanceof Sun)) {
node.setParent(null);
}
}
You can detect if a user has tapped on a particular node like this - in this example the check is to see if the hit node is an 'Andy' renderable, i.e. the default example renderable with Sceneform:
private void handleOnTouch(HitTestResult hitTestResult, MotionEvent motionEvent) {
Log.d(TAG,"handleOnTouch");
// First call ArFragment's listener to handle TransformableNodes.
arFragment.onPeekTouch(hitTestResult, motionEvent);
// Check for touching a Sceneform node
if (hitTestResult.getNode() != null) {
Log.d(TAG,"handleOnTouch hitTestResult.getNode() != null");
Node hitNode = hitTestResult.getNode();
if (hitNode.getRenderable() == andyRenderable) {
//DO whatever you need to here...
}
return;
And you can delete a node like this:
private void removeAnchorNode(AnchorNode nodeToremove) {
//Remove an anchor node
if (nodeToremove != null) {
arFragment.getArSceneView().getScene().removeChild(nodeToremove);
anchorNodeList.remove(nodeToremove);
nodeToremove.getAnchor().detach();
nodeToremove.setParent(null);
nodeToremove = null;
} else {
//Handle error case here
}
}
Full code available here: https://github.com/mickod/LineView - the above are edited excerpts.
If you need to cleanup the scene, you can do the following:
arSceneView.getScene().callOnHierarchy(node -> {
node.setParent(null);
if (node instanceof AnchorNode) {
((AnchorNode) node).getAnchor().detach();
}
}
I am using AR Core as a 3D Viewer in my application. I am not using Sceneform for AR rendering but for rendering the model in 3D. The problem I am facing is how I can 360 rotate the model with swipe gestures or touch events. Is that possible with sceneform or I need to use the more difficult ways like open GL.
Here is my code.
public class FullDegreeActivity extends AppCompatActivity {
SceneView sceneView;
Scene scene;
Node node;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_full_degree);
inIt();
renderObject();
}
private void inIt() {
sceneView = findViewById(R.id.scene_view);
scene = sceneView.getScene();
}
private void renderObject() {
ModelRenderable.builder().setSource(this, Uri.parse("edited.sfb"))
.build().thenAccept(modelRenderable -> {
addNodeToScene(modelRenderable);
}
).exceptionally(throwable -> {
return null;
});
}
private void addNodeToScene(ModelRenderable renderable) {
node = new Node();
node.setParent(scene);
node.setLocalPosition(new Vector3(0f, 0f, -1f));
node.setLocalScale(new Vector3(1f, 1f, 1f));
node.setName("Dog");
node.setRenderable(renderable);
TransformableNode transformableNode = new TransformableNode(sceneView.getTransformationSystem());
transformableNode.setParent(node);
transformableNode.setLocalRotation(Quaternion.axisAngle(new Vector3(1f, 0, 0), 0f));
transformableNode.setRenderable(renderable);
transformableNode.select();
scene.addChild(transformableNode);
}
#Override
protected void onPause() {
super.onPause();
sceneView.pause();
}
#Override
protected void onResume() {
super.onResume();
try {
sceneView.resume();
} catch (CameraNotAvailableException e) {
e.printStackTrace();
}
}
}
I share my fresh experience, maybe someone still need a solution.
You have two options to achieve that:
As noticed above you can implement your own gestures, scales and rotations
using androids standard gestures or addOnPeekTouchListener listener of scene.
Use Transformable node for it's facilities, then you only have to remove the translation controller and implement a new rotation controller.
Lets consider option 2 in bit detail with Kotlin code
Crate new rotation controller for Drag gestures:
class DragRotationController(transformableNode: BaseTransformableNode, gestureRecognizer: DragGestureRecognizer) :
BaseTransformationController<DragGesture>(transformableNode, gestureRecognizer) {
// Rate that the node rotates in degrees per degree of twisting.
var rotationRateDegrees = 0.5f
public override fun canStartTransformation(gesture: DragGesture): Boolean {
return transformableNode.isSelected
}
public override fun onContinueTransformation(gesture: DragGesture) {
var localRotation = transformableNode.localRotation
val rotationAmountX = gesture.delta.x * rotationRateDegrees
val rotationDeltaX = Quaternion(Vector3.up(), rotationAmountX)
localRotation = Quaternion.multiply(localRotation, rotationDeltaX)
transformableNode.localRotation = localRotation
}
public override fun onEndTransformation(gesture: DragGesture) {}
}
To remove translation controller:
node.translationController.isEnabled = false
node.removeTransformationController(translationController)
Add our custom rotation controller to node
val dragRotationController = DragRotationController(node, transformationSystem.dragRecognizer)
node.addTransformationController(dragRotationController)
And this is the DragTransformableNode
import com.google.ar.sceneform.ux.TransformableNode
import com.google.ar.sceneform.ux.TransformationSystem
class DragTransformableNode(transformationSystem: TransformationSystem) :
TransformableNode(transformationSystem) {
private val dragRotationController = DragRotationController(
this,
transformationSystem.dragRecognizer
)
init {
translationController.isEnabled = false
removeTransformationController(translationController)
removeTransformationController(rotationController)
addTransformationController(dragRotationController)
}
}
You can do it easily with Sceneform. In fact you don't any Sceneform code for it. You just use Android's standard gesture recognition to detect the gesture and use it to update the rotation of your node. https://developer.android.com/training/gestures/detector
I think that your implementation is pretty close to how it should work. Just take a look at the hellosceneform example from Google (https://github.com/google-ar/sceneform-android-sdk/blob/master/samples/hellosceneform/app/src/main/java/com/google/ar/sceneform/samples/hellosceneform/HelloSceneformActivity.java).
I am developing a block game. i have two moving blocks in vertical direction. one of the block is also moving horizontally (like auto moving car in ROAD FIGHTER). i am checking the block interaction by Intersector.overlaps but when my block goes out of window (i.e. position becomes less than 0) ,my code of overlaps not working .
if(Intersector.overlaps(block1.getBoundingRectangle(), block2.getBoundingRectangle())){
// do not update values
}else{
// update the values of block1 and block 2
}
public static int[] value={138,195,248,303};
public static boolean[] valueHolder={true,false,false,true};
public void update(float delta) {
velocity.set(0, backgroun.velocity.y-scrollSpeed);
position.add(velocity.cpy().scl(delta));
if(position.y>850){
isScrollableTop=true;
}
selfMove(delta);
if(position.y<-150){
position.y=-150;
}
carBoundingRectangle.setX(position.x);
carBoundingRectangle.setY(position.y);
}
private void changeArray() {
if(position.x>=138 && position.x<167){
if(!GameConstants.valueHolder[0]){
GameConstants.valueHolder[blockNumber]=false;
GameConstants.valueHolder[0]=true;
blockNumber=0;
}
}else if(position.x>=167 && position.x<222 ){
if(!GameConstants.valueHolder[1]){
GameConstants.valueHolder[blockNumber]=false;
GameConstants.valueHolder[1]=true;
blockNumber=1;
}
}else if(position.x>=222 && position.x<275){
if(!GameConstants.valueHolder[2]){
GameConstants.valueHolder[blockNumber]=false;
GameConstants.valueHolder[2]=true;
blockNumber=2;
}
}else if(position.x>=275 ){
if(!GameConstants.valueHolder[3]){
GameConstants.valueHolder[blockNumber]=false;
GameConstants.valueHolder[3]=true;
blockNumber=3;
}
}
}
Thanks in advance