[Tutorial] Mini Game 01 -- Infinite Instantiation, Timer, and Randomization
FeaturedTutorial -- Catch Objects with Your Mouth
Hello everyone! This is the first post of a tutorial series about a mini game in Lens Studio where cookies fall from top of the screen and players would ‘catching’ them with their mouth.
To find the next part of this tutorial, check here:
[Tutorial] Mini Game 02 -- Duplicate & Recycle Textures and Materials
In this session we’ll tackle infinite spawning falling objects, let’s get started!
Concept
A general practice for any game / interactive experiences involving spawning infinite objects is to have two components in the scene. One is the object itself with an ObjectScript attached to it, another is a controller object with an ObjectSpawnerScript attached to it. The logic looks like something like this:
Setting up the Project
First we’ll have our assets ready (linked in the zip below). For this example I made a simple cookie image, and an animation of the cookie breaking for when the cookie is ‘caught’. Let’s import them to our project to get started.
We’ll create an ObjectSpawner object and an ObjectPrefab object both as Screen Images and put the ObjectSpawner above screen.
Then we’ll attach a script to each, we’ll create an ObjectSpawner script and ObjectPrefab script and attach them to the SceneObject with the same name.
Getting the cookie to drop
First we’ll need to create a prefab from the ObjectPrefab, we can do so by dragging ObjectPrefab to our Resources folder.
Pro-tip: For more info about prefabs, check out the Prefab page here!
We can safely delete the ObjectPrefab object in our scene.Then in the ObjectSpawner script, we’ll add a reference to the prefab and link the prefab to it. We’ll simply add this line:
//@input Asset.ObjectPrefab objectPrefab
Instantiating Objects
To instantiate an object we’ll do so in a function, let’s call it spawnObject(). In this function we’ll create a copy of the prefab and assign a position to it. We’ll be using anchor positions here. It will be a value between -1 and 1, -1 indicating left/bottom part of the screen and 1 indicating top/right.
We’ll just spawn it at the position of ObjectSpawner for now, and give it the same parent as our ObjectSpawner object. Here’s what the function would look like:
function spawnObject(){
//creating a copy of the prefab
var newObj = script.objectPrefab.instantiate(script.getSceneObject().getParent());
//get screen position of this aka ObjectSpawner object
var screenTransform = script.getSceneObject().getComponent("Component.ScreenTransform");
var myScreenPos = screenTransform.anchors.getCenter();
//set screen position of newObj aka ObjectPrefab object
var objScreenTransform = newObj.getComponent("Component.ScreenTransform");
objScreenTransform.anchors.setCenter(myScreenPos);
}
Pro-tip: Take a look at the downloadable project to see the script!
Try calling this function by calling spawnObject(); anywhere outside of this function. If you drag ObjectSpawner into the scene and refresh, you’ll see a cookie being spawned. That means our script is working!
Creating a Timer
We don’t want the object to just be instantiated once, we want to instantiate it at different time intervals and different locations. To do so we’ll need to create a few new variables, spawnFrequency, spawnRange and spawnTimer.
//spawnFrequency -- how frequent each object is spawned per second
var spawnFrequency = 0.5;
//spawnRange -- how wide they’ll be apart on the screen
var spawnRange = 1;
//spawnTimer -- track time of spawning
var spawnTimer = 0;
We’ll also create an Update function where our code will be run every frame. In it we’ll create a counting function that looks something like this:
script.createEvent("UpdateEvent").bind(function(){
if(spawnTimer < spawnFrequency){
spawnTimer += getDeltaTime();
}else{
spawnObject();
spawnTimer = 0;
}
});
So spawnTimer would increase when lens turns on, and once its value is higher than spawnFrequency (0.5 aka half a second by default), spawnObject() will get called once and spawnTimer would be reset to 0, then it’ll increase in value again and the loop continues.
If you put a print() function in spawnObject() you’ll see it popping up in Logger when lens is running at time interval of the value of spawnFrequency.
Randomize Position
This is all working great but we still have to give a random position to the object prefab when it’s being spawned. We’ll really only need to randomize the X position of objects on screen, here’s what we’ll add in our spawnObject() function, right after we assign position to objScreenTransform.
//randomize position with range
var randomXpos = myScreenPos.x + Math.random()*spawnRange*2 - spawnRange;
var newObjPosition = new vec2(randomXpos, myScreenPos.y);
And replace the variable when we assign positions to objScreenTransform:
objScreenTransform.anchors.setCenter(newObjPosition);
Now when we refresh our lens with ObjectSpawner visible on screen, we can see the cookies are spawning at random positions on screen, yay!
Make it Rain!
Our last step is to make the object fall. This would be most easily achieved within our ObjectPrefab script. We’ll simply create a fallingSpeed and an Update function where we apply this speed to the y position of the anchor center of our object, this is what our script would look like:
var screenTransform = script.getSceneObject().getComponent("Component.ScreenTransform");
var fallingSpeed = 0.3;
script.createEvent("UpdateEvent").bind(function(){
var currentpos = screenTransform.anchors.getCenter();
currentpos.y -= fallingSpeed * getDeltaTime();
screenTransform.anchors.setCenter(currentpos);
});
And once we move our ObjectSpawner object back to above the screen, we’ll have our objects falling infinitely! Woohoo!~
Feel free to adjust values of spawnFrequency and spawnRange for different outcomes :)
Another thing we need to do is to destroy the object once it falls beyond the screen since we don’t need our cpu to do all that calculation once an object is not visible anymore, we can do so by simply adding an if statement with a y position check in ObjectPrefab script:
//-1 would be the bottom of screen, so -1.5 would be a safe y position to destroy object
if(currentpos.y < -1.5){
script.getSceneObject().destroy();
}
Adding Randomization
A good way to make your game more ‘unpredictable’ is to randomize your parameters a little bit, in this case we can randomize things such as fallingSpeed and spawnFrequency.
A good practice in any game development is to have a centralized place for all your variables so it’s easier to tweak values later on. Right now we have spawnRange and spawnFrequency in our ObjectSpawner script, we can create a fallingSpeed range in there as well. We’ll also give them min and max values for easier tweaking in Inspector.
We’ll add these at the top of our ObjectSpawner script:
//@input float spawnFrequency{"widget":"slider","min":0, "max":3, "step":0.1}
//@input float spawnRange {"widget":"slider","min":0, "max":1, "step":0.1}
//@input float fallingSpeedMin
//@input float fallingSpeedMax
And replace our spawnFrequency and spawnRange variables.
While we replace our spawnFrequency variable, we can reverse the numbers here so it makes more sense (higher spawnFrequency = more cookies)
var nextSpawnTime = (1/script.spawnFrequency);
var spawnRange = script.spawnRange;
Now we can adjust parameters in Inspector and observe different outcomes of our mini game:
Pro-tip: for more info about scripting custom UI, check out the Custom Script UI page!
We still need to link fallingSpeed in ObjectPrefab script with the values here. To do so we’ll first link the ObjectSpawner script in our ObjectPrefab script by adding:
//@input Component.ScriptComponent objectSpawner
Then we’ll drag the prefab into our scene, drag in ObjectSpawner, then click ‘Apply’.
In the ObjectSpawner script we’ll create a function that returns a random value between fallingSpeedMin and fallingSpeedMax:
function getFallingSpeed(){
return Math.random() * (script.fallingSpeedMax - script.fallingSpeedMin) + script.fallingSpeedMin;
}
And we’ll need to refer this function with script.api so we’ll add this line as well:
script.api.getFallingSpeed = getFallingSpeed;
Now in the ObjectPrefab script, all we need to do is replacing our arbitrary value for fallingSpeed with getFallingSpeed from ObjectSpawner:
var fallingSpeed = script.objectSpawner.api.getFallingSpeed();
Remember to set different values of fallingSpeedMin and fallingSpeedMax in the ObjectSpawner script, and now our objects will fall at different speeds!
We can also randomize spawnFrequency. We can use a slightly different method this time, by adding a randomized value to our spawnFrequency each time we spawn our object. We can create a randomizer value first, and have it around 0.2:
//@input float spawnRandomizer {"widget":"slider","min":0, "max":0.5, "step":0.05}
And we’ll give a new value to nextSpawnTime in our if statement right under after we reset spawnTimer to 0:
nextSpawnTime = 1.0/script.spawnFrequency + (Math.random() - 0.5) * script.spawnRandomizer;
And now we shall have a very nice UI board for adjusting all parameters!
That’s it for today’s tutorial~ We've covered:
- Instantiating infinite prefab objects
- Having custom behavior for each prefab
- Connecting central manager script (ObjectSpawner) with individual scripts (ObjectPrefab)
- Randomize in-game parameters
----------------------------------------------------------------------
Click here for project asset (cookie image)
Click here for entire example project
-------
For the next tutorial we’ll create a mouth catching interaction and play cookie ‘crack’ animation on caught by mouth, stay tuned!
Nice! I'm definitely gonna try something!
Keep up the good work with lens studio 3.0!
HI.
I would like to thank you for your help and Tutorial.
I'm not able to access to the file? I have an error 404 :( Access not allowed.
Thanks
Hi Laurent !
I have updated the links, should be good now! Sorry about the inconvenience.
Hello, thanks a lot for this tutorial. Is it possible to do the same for creating objects for the World Lens?
Please tell me how to do this?
Hi @...,
The logic for creating objects for world lens would be the same as this. You'll just need to create an object in 3D space and use getWorldPosition() instead.
Happy creating!
Thank you so much
HI.
this great lesson
i will try to apply
Thanks
Hi @...
you r such a good teacher...i will sure make this game in future
try my new snap filter https://www.snapchat.com/unlock/?type=SNAPCODE&uuid=56a06aee6d14484dbf164167054892cb&metadata=01
and please help me to be verified as i made almost 30+ 3d ar lenses and 2 games
...my total views is 300 million and total snapchat play time is greater than 200+ days
Thank You !!
Hi Nico!
Thanks for the tutorial. Can you pls explain where you apply the textures of the cookies?
Thank you,
Sara
Hi Sara Orfali
To apply texture to a Screen Image object, just click on the screen image and go to its inspector, under the Texture field just drag in any custom texture you have!
Hai Nico
Thanks for tutorial;. can u help me please?
Script ObjectPrefab
var currentpos = screenTransform.anchors.getCenter();
[Scenarium] TypeError: cannot read property 'anchors' of null
at [anon] (Script/ObjectPrefab.js:9) preventsyield
Script ObjectSpawner
var myScreenPos = screenTransform.anchors.getCenter();
[Scenarium] TypeError: cannot read property 'anchors' of null
at [anon] (Script/ObjectPrefab.js:9) preventsyield
Thank u
Hi 6_Kurnivan Noer Yusvianto
For this error, the property screenTransform was not declared and defined so Lens Studio returns an error when you try to use screenTransform without defining it. If you add this line above that it should work:
var screenTransform = script.getSceneObject().getComponent("Component.ScreenTransform");
Hi Nico,
Thanks for the tutorial! I seem to get this error (all I've done so far is add image objects, make a prefab and started adding to ObjectSpawner script) when calling spawnObject(). Are we supposed to do something with the ObjectPrefab script? There doesnt seem to be any mention of it at the stage im at apart from adding it to resources and adding to the object prefab image object (it is blank as far as instructions go at this stage):
Did anybody find a work around on creating a prefab and adjusting the script? I'm having trouble putting in my objects for the prefab spawn.