How to place model once in ARCore - arcore

In my code, the model gets rendered every time I tap the screen. I want that once the model is placed in AR, even if the user taps it should not place the second model. How can I do it? I am using ARcore.

Regardless if it is a native android or an UNITY ARCore project.The easiest logic will be to use a boolean like isPlaced (initially false). Once the model is placed in the AR scene, change the boolean to true.
have the Ontap functions logic in an if statement checking is isPlaced is false.
bool isPlaced = false;
// function to handle tap interaction
ontapped(){
if(!isPlaced){
// logic to place model in AR Scene
isPlaced = true;
}
}

Anchor anchor = hitresult.createAnchor();
AnchorNode anchorNode = new AnchorNode(anchor);
anchorNode.setParent(arFragment.getArSceneView().getScene());
TransformableNode lamp = new TransformableNode(arFragment.getTransformationSystem());
lamp.getScaleController().setSensitivity(3);
lamp.setParent(anchorNode);
lamp.setRenderable(tanRenderable);
lamp.select();
***arFragment.setOnTapArPlaneListener(null)***;

Related

Remove touch gestures (rotation/translation) for Ios ar object

Summary: Remove touch gestures on an AR object after adding it?
AR View Code (Just the relevant bit).
Where arObject is a model entity with a mesh, material and a collision shape.
func updateUIView(_ uiView: ARView, context: Context) {
arObject = CreateCustomModelEntity()
uiView.installGestures([.translation, .rotation], for: arObject)
}
The above could would add touch gestures to my arObject and allow it to be rotated and moved across the anchored plane.
However, I want to remove the touch gestures after adding it.
User Flow:
The user would click a model, move it around and place it where they'll like and touch the Confirm button. After the confirm button is touched, the arObject can no longer be moved around.
Looking at the Apple docs, there's an installGestures, but no equivalent removeGestures. Is this even possible?
A few ideas,
completely remove the anchor and recreate it (but then the placement of the object is lost, so this is bad)
Override the existing child ar object with a new one without the touch gestures installed. I believe this would retain the object placement, but double creating ar objects isn't ideal unless there's no other solution.
Create a temp ar object with install gestures and then override it with a new arObject (without touch gestures) after placement has been confirmed. Similar to 2. solution.
The installGestures method returns an array of EntityGestureRecognizers and also assigns these gesturesRecognizers to the arView.gesturesRecognizers array. If you want to remove gestures for a given entity you need to find the gesturesRecognizers you want and remove them from that array.
The code below assigns the translation and rotation gestureRecognizers separately to a property which you use to find the corresponding index in the arView.gesturesRecognizers array.
func updateUIView(_ uiView: ARView, context: Context) {
arObject = CreateCustomModelEntity()
translationGestureRecognizer = uiView.installGestures([.translation], for: arObject).first
rotationGestureRecognizer = uiView.installGestures([.rotation], for: arObject).first
}
func removeGesture() {
let recognizerIndex = arView.gestureRecognizers?.firstIndex(of: translationGestureRecognizer!)
arView.gestureRecognizers?.remove(at: recognizerIndex!)
}
I found removing gestureRecognizers from the arView mandatory also when removing an object from the scene because otherwise it isn't released from memory and thus it increases the app's footprint.

MKMapView with annotations issue

I have MKMapView with many annotations in proper order. And I have button to change map mode:
- (IBAction)userDidPressTrackButton:(id)sender {
if (self.mapView.userTrackingMode == MKUserTrackingModeFollow) {
self.mapView.userTrackingMode = MKUserTrackingModeFollowWithHeading;
return;
}
if (self.mapView.userTrackingMode == MKUserTrackingModeFollowWithHeading) {
self.mapView.userTrackingMode = MKUserTrackingModeNone;
return;
}
if (self.mapView.userTrackingMode == MKUserTrackingModeNone) {
self.mapView.userTrackingMode = MKUserTrackingModeFollow;
}
}
when mode = MKUserTrackingModeFollowWithHeading annotations begin to put themselves in random order. It seems that in this mode mapview begin to redraw itself every second and put all the subview (annotations) in unknown order.
How to cancel changing order of annotations?
The array of annotations that you get back from mapview.annotations is not guaranteed to be in the same order you that added them in. If you are relying on them vein in a special order you are probably doing your viewForAnnotations function wrong. It is given an annotation as a parameter, you use that to determine what view to draw. Usually people make a custom class that implements the MKAnnotation protocol and has some addition variables in which they store the data needed to create the right view. When viewForAnnotations gets called they check if the provided annotation is one of their special class, and if so extract the data, make the view and return it. There is no need to know the order of the annotations array, and it wouldn't do you any good because an MKMapView can and will ask for the annotations in any sequence it likes.
Side note: Why are you writing your own function for toggling the tracking mode? You can just use the official one and it will do it all for you.

iOS: How to prevent multiple taps of button from creating multiple new instances

Just noticed something peculiar with my app. Whenever I tap one of the bar buttons to open a popover viewcontroller, if I tap it again it simply opens another instance of that vc (I can keep doing this).
How do I stop this? Should I use a boolean to disable the button when the boolean is active and then somehow reset it when the user closes the VC by other means (such as tapping part of the screen that isn't the same VC)?
Tried the boolean suggestion:
In my prepareForSegue method I have the following:
if(isActive==false){
InformationViewController *informationViewController = [segue destinationViewController];
informationViewController.delegate = self;
isActive = true;
}
This may no longer be important, but I would recommend the boolean solution you proposed with one modification. If you move the
isActive = true;
statement to viewWillAppear, I'm pretty sure the button will remain disabled until the modal view closes.
Yes, I would suggest using a global bool value. Set the variable to true when the button is pressed.
In the function that creates the instance, check to make sure that the variable is false before creating the instance.
Once the instance is deleted, set the variable back to false.
Psuedo-code (in C++):
bool isActive = false;
void CreateInstance()
{
if (isActive == false)
{
-- code
isActive = true;
}
}
void InstanceDestroyed()
{
-- code
isActive = false;
}
You could set the button to disable once the view appears, and then add code in your popover view to:
a) send a notification using Notification Center once the popover is dismissed to be "caught" by the view that holds the button and re-enable the button, or...
b) use the delegation pattern using a protocol to handle the re-enabling of the button once the popover view is dismissed.
These methods might require a little bit more work, but I try not to use any global variables in a MVC pattern.

Actionscript 3 - fl.controls.UIScrollBar - setting scrollPosition does not work

I have a scroll bar ( fl.controls.UIScrollBar ), which i create dynamically in a class, and add it to the stage.
public class Slider extends Sprite
{
private var scroll:UIScrollBar = new UIScrollBar();
// etc.
// constructor
addChild(scroll);
scroll.setSize(15.75, 205.3);
scroll.direction = ScrollBarDirection.HORIZONTAL;
scroll.setScrollProperties(150, minScrollPos, maxScrollPos,snapInterval);
scroll.addEventListener(ScrollEvent.SCROLL, scrollHandler);
}
Then, I try to call
scroll.scrollPosition = 30;
My method call will not update the scroll thumb.Any ideas why?
Salut Mihai,
I found that odd at first. I expected setting the value would suffice.
If I set scrollPosition in an enter frame loop, it works, but not if I use the setter straight away. This probably means that if you make the calls right after creating/setting up the component, internally, it's not ready yet. UIComponents(like UIScrollBar) have a whole lifecycle to deal with. Jeff Kamerer has a nice set of devnet articles on this, if you're interested.
Long story short, the component is not ready right away, so the best bet is to wait for it to be ready by listening to the RENDER event:
scroll.addEventListener(Event.RENDER,rendered);
function rendered(event:Event):void {
scroll.removeEventListener(Event.RENDER,rendered);
scroll.scrollPosition = 30;
}

Loop activated on mouse movement

I'm just going to explain the context so it is clearer.
I made this menu : my menu
I am looking to make an improved and more advanced version of the same menu.
I made an animation of waves on the cofee's surface and am looking to make it loop when the mouse is moving and to stop looping when it's not.
Sorry for the lack of specifications as I am quite new to actionscript, but I hope somebody will be able to help me. :)
Thanks,
Mathieu
Well, you said it - leverage MouseEvent.MOUSE_MOVE to set a conditional in your looping routine.
private var _isMoving:Boolean = false;
stage.addEventListener(MouseEvent.MOUSE_MOVE, checkMouse);
this.addEventListener(Event.ENTER_FRAME, doLoop);
private function checkMouse(e:MouseEvent):void
{
_isMoving = true;
}
private function doLoop(e:Event):void
{
trace("moving =" + _isMoving);
if(_isMoving)
{
// loop animation
}
_isMoving = false;
}
depending on how you want it to work I would do this as follows:
create an animation of wavy coffee
ensure the animation loops
note that clips loop by default, so all you have to do is match the first and last frames!
place the clip at the edge of your current coffee graphic
double click on the graphic to edit it
drag an instance of the looping animation from the library onto the "edge" of the graphic
OR just replace your entire light brown graphic with an animated one that loops
when the mouse is moving, call play on the animated loop clip
when the mouse stops, call stop on the animated loop clip
Some example code would be along the lines of:
public function init():void {
menuClip.addEventListener(MouseEvent.MOUSE_OVER, onMenuRollOver);
menuClip.addEventListener(MouseEvent.MOUSE_OUT, onMenuRollOut);
}
public function onMenuRollOver(event:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
/* do the stuff you're currently doing to animate the clip here.
something like: coffee graphic height = ease to mouseHeight */
}
public function onMenuRollOut(event:MouseEvent):void {
/* do the stuff you're currently doing to stop the clip here. */
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
coffeeClip.stop();
}
public function onMove(event:MouseEvent):void {
resetTimer();
coffeeClip.play(); //note: play has no effect when movie is playing (that's ideal in this case)
}
public function resetTimer():void {
if(mouseMovementTimer == null) createTimer();
mouseMovementTimer.reset();
mouseMovementTimer.start();
}
public function createTimer():Timer {
mouseMovementTimer = new Timer(DELAY, 1); //fiddle with the delay variable. Try 500, at first
mouseMovementTimer.addEventListener(TimerEvent.TIMER, stopAnimationLoop);
}
public function stopAnimationLoop(event:TimerEvent):void {
mouseMovementTimer.removeEventListener(TimerEvent.TIMER, stopAnimationLoop); //optional but recommended
mouseMovementTimer = null;
coffeClip.stop();
}
Of course, you would need to do things like call init() and import flash.utils.Timer and initialize variables like mouseMovementTimer, menuClip, coffeeClip and DELAY.
Warning: This code is off the top of my head and untested. So there's likely to be small bugs in it but you should get the general idea:
add a mouse listener when the user mouses over the menu
remove that listener if the user mouses out of the menu
have that listener play the looping movie clip
trigger an event that will stop the looping clip if movement hasn't been detected in a while
once the trigger goes of, stop the clip
The key is in detecting when the mouse stops moving. Flash detects interaction well but does not detect NON-INTERACTION for obvious reasons. One easy way to solve that is to trigger a timer that will go off once too much time has elapsed since the last activity. Then, when the timer triggers, you know action has stopped!
I think that's the key piece to solving your problem. I hope that helps someone in some way.
~gmale

Resources