Make Things Change on Tap
FeaturedHey Everyone,
Let’s make something change on tap! In this guide we will go through an example of tapping to change objects, tapping to change sprite textures, and tapping to change material colors.
So in my current project, I have three objects that I want to tap through. In this example each item is an object with a MeshVisual component (3D object), but it can be anything, such as: a sprite, a parent of multiple , a billboard, etc..
First let’s create a box (Add new -> Mesh Visual -> Box) to define where a user’s tap would count and call it TouchCollision. Resize this box to roughly encompass our objects.
Although you can use any MeshVisual, including the actual object you’re displaying, it’s sometimes to have a seperate mesh since it can stay consistent across different objects and allow you to tap on non-MeshVisual object such as a sprite.
Since we don’t actually want to see the TouchCollision, let’s give it an invisible material. In the TouchCollision Inspector panel, under Mesh Visual component, click “Default” to open the material selection window. In this window, we can Add New “Unlit” material. Select the new Unlit material in the Resources panel and uncheck “‘Depth Test”, “Depth Write”, “Color Write”.
To use the TouchCollision, we’ll add a TouchComponent (Inspector Panel -> Add Component -> Touch) and assign the TouchCollision to it.
Next, let’s add a ScriptComponent (Inspector Panel -> Add Component -> Script) on the same object. This script will use theTouchComponent and iterate through our items when we tap. Add a new script to this component on ‘Initialize’.
Then let’s edit the script (double-click on the script in your Resources panel). To get references to our items in this script, we can create an input that takes in an array of SceneObject. Then in the Inspector Panel of TouchCollision, you can add our objects to the array--in this case item1, item2, item3.
// @input SceneObject[] items
Since we only want to see one object at a time, we can loop through our “items” array and disable everything but the first one.
// Arrays are indexed from 0.
// Disable everything but the first (0th) item
for (var i = 1; i < script.items.length; i++) {
script.items[i].enabled = false;
}
Below that, we tell the script that we want to activate the next item in the array when a TouchStartEvent happens.
function activateNextItem () {
// we’ll fill this in a second
}
// Bind the function to the touch event.
var touchEvent = script.createEvent("TapEvent");
touchEvent.bind(activateNextItem)
When activateNextItem gets called by the TapEvent, we want the Lens to disable the current item and enable the next item. To help us do this, we need to keep track of our current item.
// We remember what item is currently visible.
// When we start it’s the 0th item.
var currentItemIndex = 0;
// Define what happens when you tap.
function activateNextItem () {
// Disable the current item.
script.items[currentItemIndex].enabled = false;
// Increment the current item index
currentItemIndex += 1;
// We need the current item index to wrap around
// once it's higher than the number of items we have.
currentItemIndex = currentItemIndex % script.items.length;
// Enable the new item.
script.items[currentItemIndex].enabled = true;
}
And that’s it! In your preview you should be able to do this:
Our final script:
// @input SceneObject[] items
// Arrays are indexed from 0.
// Disable everything but the first (0th) item .
for (var i = 1; i < script.items.length; i++) {
script.items[i].enabled = false;
}
// We remember what item is currently visible.
// When we start it's the 0th item.
var currentItemIndex = 0;
// Define what happens when you tap.
function activateNextItem () {
// Disable the current item.
script.items[currentItemIndex].enabled = false;
// Increment the current item index
currentItemIndex += 1;
// We need the current item index to wrap around
// once it's higher than the number of items we have.
currentItemIndex = currentItemIndex % script.items.length;
// Enable the new item.
script.items[currentItemIndex].enabled = true;
}
// Bind the function to the touch event.
var touchEvent = script.createEvent("TapEvent");
touchEvent.bind(activateNextItem)
Bonus:
You can also use similar scripts to modify existing objects:
Instead of passing an array of objects, you can pass in an array of textures and then iterate through the textures on one sprite.
// @input Component.SpriteVisual sprite
// @input Asset.Texture[] textures
// Our starting texture index
var currentItemIndex = 0;
// Assign the initial texture to our sprite
script.sprite.mainPass.baseTex = script.textures[currentItemIndex]
// Define what happens when you tap.
function changeTexture () {
// Increment the current item index
currentItemIndex += 1;
// We need the current item index to wrap around
// once it's higher than the number of items we have.
currentItemIndex = currentItemIndex % script.textures.length;
// Change the sprite's texture
script.sprite.mainPass.baseTex = script.textures[currentItemIndex];
}
// Bind the function to the touch event.
var touchEvent = script.createEvent("TapEvent");
touchEvent.bind(changeTexture);
Or instead of passing any array, you can use script to get random results on tap!
// -----JS CODE-----
// @input SceneObject object
// Define what happens when you tap.
function changeColor () {
// Get the item's mesh visual
var meshVisual = script.object.getFirstComponent("Component.MeshVisual");
// Change it's baseColor
meshVisual.mainPass.baseColor = new vec4(Math.random(), Math.random(), Math.random(), 1.0);
}
// Bind the function to the touch event.
var touchEvent = script.createEvent("TapEvent");
touchEvent.bind(changeColor);
Happy crafting!
Thank you managed to get it working in the end for a sprite event.
Very helpful. I'm using your script to change the material colour (the one at the bottom of the guide), but it only triggers after pressing once first. Any clue how to solve this?
hi great feature.. are you able to share how you setup the texture?
bit confused putting the two from the item to the texture
Figured it out...
you add all the images in to inspector.
this is great feature :)
I misunderstood thought it went through the var +i switiching the images over you
👍🏾
now how to make it cycle through the images when tapped once? so on tap cycle through textures?
Hi Patrick, Glad to hear! Don't forget to show us what you come up with :)
Hi Tai, Can you clarify what you mean by "tap cycle through textures"? Do you mean when you tap once, it will cycle through multiple images (like every second?)
Hi Patrick, Currently Lens Studio does not provide that. We'll add this to our feature request. Thanks!
Can’t share till my company approves the output (stupid working for the man!!!)
This is related to this but can move out what about using hash table?
Am I starting to push the limit of what can be done/ purpose of Lens studio?
Hi Patrick!
You are able to use a hash table in Javascript. It might make sense when your project becomes more complex to use a central hash table for cleanliness. But it really depends on what you're trying to accomplish.
And finally, I wouldn't say you are pushing the limit. Lens Studio's Javascript is very powerful and I'm really excited to see more and more complex interactive experiences.
Cheers,
Travis
Hey Travis.
Good to know, at this stage I am guess I am trying to future proof and push the box with what Lens Studio's JS can do :) and how to work in certain limitations (dynamic Text, no external API etc)
"I wouldn't say you are pushing the limit" - > Challenge accepted :D
Hello everyone! :)
I do not understand what's going on with my script.
How can I add my items to the board?
Here's what I see in the console:
22:23:19 Failed to parse scripts. Reason: incorrect value name 'text_english,' at line:
And how do I add my objects in the script:
@input SceneObject [text_english, text_english] elements
// Tables are indexed from 0.
// Disables everything except the first (0) element.
for (var i = 1; i <script.items.length; i ++) {
script.items [i] .enabled = false;
I hope you know where the problem comes from :)
Thank you!
Hi Mrtolien!
Your @input should be
Then, in the Inspector panel where your script is being used, you should be able to add your items. In your script you can access these items by doing something like:
Best,
Jonathan
Hello Jonathan!
Thanks for the quick answer! I tried to do exactly the same example as you, but when I add my objects in the Inspector panel under the script, I still have this error in the console:
and this is my line 2:
So nothing happens when I touch in the preview :(
I can't figure out the issue..
Best,
Hi Mrtolien,
Please try this:
Looks like I accidentally dropped the slash ;)
Thanks!
Jon
Hi Jonathan!
Thank you so much for your time! it's working very well !
Thanks! :D
Have great day!
Best,
I keep getting this error... please help!!!
TypeError: cannot write property 'enabled' of undefined
at activateNextItem (Script:22) preventsyield
Hi Nathan,
If you're using the script above, it looks like the list of "items" hasn't been set in the Inspector panel and so when the script tries to set "enabled" it fails because there is no object.
Here I add things to the Item list in the Inspector panel of my script:
If this is not the issue, can you post your script so we can take a look at it?
Thanks!
Jon
hi Jonathan,
is there a way to change these forehead binding on tap? and if i want to do it for more than one face could it be done?
Dear Jonathan,
i started a new project , but when i use the script provided above i get a mainpass error as u can see in the attached photo, i would appreciate your feed back , the aim of the lens is to attach the hair do as a sprite and then change hair dos with a tap
Hi Sweet Ice!
I think you're very close. In the Inspector panel of where you placed your script, make sure that you have your face sprite on the Sprite field:
Then once you add your different hair do as the values in Textures, you should be able to touch the screen to change hair do! (In this example I just add in the default textures that comes with the project).
Let me know if you need any clarification! Excited to see the result :)
Cheers,
Jon
Thank you that worked just the way i want it to, i just need to adjust my textures so they all the the same distentions and location so they would fit perfectly.
follow up questions:
i can use the same script for a second face right?
and if i wanted to add a different sprite as well ( lets say a nose ) in addition to the first one would that work?
Yup! You'll just need to add another script component to put the same script on so you can point it to the new Face Sprite.
thanks for your help!
I'm testing a lens, I changed an object when I tap, I would like add music and change them as the same time as object.
Is it the same process?
Thanks
Hi Takinours!
Yes we can use something similar, instead of enabling or disabling objects, we can tell the script to change the audio track on an audio component, then tell it to play:
Then, you should have something like this:
You can create an Audio component, by clicking "Add New" at the bottom of the Inspector panel, and clicking Audio.
Then select the Audio Component field and choose the newly created audio component. Finally, you can drag your audio from the Resources panel into the different values in the Items field.
Let me know if you need any clarification. Can't wait to see what you come up with!
Cheers,
Jon
Thanks Jon! That's work perfectly!
I thank you again for your help.
When I tap, Is it possible to change element in same time on the front and back camera?
I tap one time, I wear a component , if I switch on the back camera I find a component associated. If I tap another time I wear a new component and if I switch of camera I Have a new component.
I don't if I'm clear ....
Thanks!
Hi Takinours!
Yup! All you need to do is call the function when the front and back camera events get called. At the end of your script you can add the following:
Let me know how it goes!
Cheers,
Jon
Thank you Jonathan,
I would like to put a picture then when you tap on the screen it shows another picture then it keeps the last picture.
Like this : Picture 1 *tap on the screen* -> Shows picture 2 and keeps the picture 2 on the screen.
How can I manage to do that? sorry for my broken english?
Hi Appkit1,
Is that similar to how the first example under the bonus section in the first post?
In that example, tapping changes the picture on the screen, and it won't change unless the user taps again.
If it's not, can you explain a little bit more what you mean?
Thanks in advance!
Jon