I am trying to get deformation object to change it properties by JS, but I cannot even get it by any Spark module.
Spark AR have sample project with face distortion deformation.
https://developers.facebook.com/docs/ar-studio/tutorials-and-samples/samples/face-distortion/
You can even see in tutorial, that there is some morph object attached, which called faceDistortionPack. This object is located in assets, and I tried to get it by different ways in script, but couldn't make it. I want to write some js logic to manipulate deformations.
const Scene = require('Scene');
const Diagnostics = require('Diagnostics');
const faceMesh = Scene.root.find('facemesh_distortion');
Diagnostics.log(faceMesh); // FaceMesh: https://sparkar.facebook.com/ar-studio/learn/documentation/reference/classes/scenemodule.facemesh
Diagnostics.log(faceMesh.deformation); // null
Diagnostics.log(faceMesh.find('faceDistortionPack')); // Exception...
// ....
I want to get 'faceDistortionPack' object to access it properties, like 'nose_z', so I can change them by JS.
Although this is a pretty old question I thought I'd answer anyway if anyone struggles with this and comes across this thread.
First of all: There's an amazing collection of helpful tips, tutorials, snippets etc. called Spark AR Community. There you can find a GitBook with an alternative, better indexed and better working version of the official script object reference. I recommend using it if you're lost in the official reference or it's not working which happens quite often. There you can see, that the BlendShapesMesh, mentioned in the previous answer is deprecated as of Spark AR v85+, so that won't help anyone. ()
So, what you are trying to achieve, if I understand it correctly, is to access the faceMesh's Blendshapes and change their value through script. What you need to do is this:
Follow the instructions in this Tutorial: https://sparkar.facebook.com/ar-studio/learn/tutorials/face-distortion-retouching/
After you applied the Blendshapes, mess around a bit with adjusting the Blendshapes, so you understand what's happening.
Add a script to your assets. You're gonna want to access the faceMesh-Object's Blendshapes' weight Property through script. That can be done by using the getBlendshapes()-Method of the Mesh-Class.
Here's a code example:
//Require Modules
const Scene = require('Scene');
const Diagnostics = require('Diagnostics');
const Reactive = require('Reactive');
//Enable async/await [part 1]
(async function () {
//Load Assets as Promise
const loadAssets = await Promise.all(
[
Scene.root.findFirst("faceMesh0"), //Put name of your facemesh here, default is faceMesh0
]
).then(function(assets){
const faceMesh = assets[0]; //Assign the facemesh from the assets-Array of the promise to a variable you can work with better
const faceMeshShapes = faceMesh.getBlendShapes(); //Access all Blendshapes of the faceMesh-Object and store them in an Array
What you have now is a variable called faceMeshShapes, that's an object with an array of Blenshapes in it. You can console log it with Diagnostics.log(faceMeshShapes) and see that there's an array called "_value" in it, that's filled with all Blendshapes as objects, that have a weight-Property, which specifies the weight of the Blendshape with a scalarValue. You can consolelog this Value by converting it with the pinLastValue()-Method of the scalarValue-Class and you can assign different values by binding it to a custom value, that you convert to a scalarValue by using the val()-Method from the Reactive-Module.
Here's an example:
Diagnostics.log(faceMeshShapes._value[0].weight.pinLastValue()); //console log the Value of the weight property's scalarValue of the Blendshape that's stored at the index 0 of the _value-Array
faceMeshShapes._value[0].weight = Reactive.val(0.5) //set the weight to 0.5
Diagnostics.log(faceMeshShapes._value[0].weight.pinLastValue()); //console log the changed value of the weight property
So basically, that's how you can access every Blendshape's weight. The index should be according to the order in which they are listed in spar AR studio, beginning with 0 for the first BlendShape. Now you can do lots of things with this value, like binding it to an animation that animates it from 0-1 or to the mouth-openess using the face-tracking module and so on.
Last but not least, don't forget any semicolons and close all brackets.
});
})(); // Enable async/await [part 2]
P.S.: It can really help sometimes to understand what's happening and how to access stuff, by console logging a list of all properties of an object. Especially since the spark AR documentation is pretty weak on that part (and pretty weak in general). You can use the following function from MDN to do that. It's nothing fancy, but it does the job and has saved me a couple of times already :)
function listAllProperties(o) {
var objectToInspect;
var result = [];
for(objectToInspect = o; objectToInspect !== null;
objectToInspect = Object.getPrototypeOf(objectToInspect)) {
result = result.concat(
Object.getOwnPropertyNames(objectToInspect)
);
}
return result;
}
The link you posted isn't live any more.
I'm guessing the below links are more relevant now for others looking into this. I animated a series of blendShapes, and these links were useful. Basically cycling through the weights of each blendShape.
https://sparkar.facebook.com/ar-studio/learn/documentation/reference/classes/scenemodule.blendshapesmesh
https://sparkar.facebook.com/ar-studio/learn/documentation/reference/classes/scenemodule.blendshape
Related
I am a beginner to Javascript and I am trying to make a text-based game for practice. I have made objects for enemies like so:
export const spider = {
strength: 1,
health: 4,
gold: 1
};
I am now trying to make a function which can search for their stats when their name is entered in the field. It looks like this:
export const findStats = (target) => {
return target.health;
}
However, when I do this and test it I get 'undefined.' However, if I replace 'target.health' with 'spider.health' it works properly.
The error occurs when I try doing findStats("spider") which gives me the 'undefined results.'
Any help would be appreciated. Note: I did look around this site but found the threads too complex or not quite what I was looking for. I am a beginner so simple terms would be greatly appreciated!
Thanks for all your comments!
My issue is unlike to the one on the right as when I try it with my code is still returns 'undefined.' Here is the code that I have just tried using the other thread. Keep in mind I am a beginner so I am probably doing it very wrong but if you could help further I would be very happy.
export const findLocalStats = (target) => {
var bar = 'strength';
console.log(target[bar]);
}
Here are is my test command:
expect(findLocalStats("spider")).toEqual(1);
Furthermore, when I tried the code written in JSFiddle in my editor, it still gave the same error in the terminal which is 'undefined.'
export function findStats(target) {
return target.strength;
}
And the test command:
expect(findStats("spider")).toEqual(1);
And the exact error message:
findStats() gives the stats of the target wanted.
expect(received).toEqual(expected)
Expected value to equal:
1
Received:
undefined
Difference:
Comparing two different types of values. Expected number but received undefined.
Sorry if this is very tedious.
Note 2: I posted this question before but I have changed it to attempt to explain my issue better as I still do not understand the answers I was given and the links to duplicate questions - which I have tried to replicate. Furthermore, the duplicate that I was given was different. It used the object as the keyword, however I want to use it as a feed-in to a parameter so that it is versatile for more than one enemies if that makes sense. Thank you!
When you are calling findStats like this : findStats("spider") you are sending a string to the function as an argument. That's why when it tries to get the property health it says undefined.
You need to give the function an instance of your spider object. To create an instance you can use the Object.create() method like var killMe = Object.create(spider). This will create a new object based on the one you declared before. Then you can call your function like this : findStats(killMe)
You can find an exemple here : https://jsfiddle.net/10ex1xqt/
So, I recently discovered EaselJS (and more generally CreateJS) and I'm trying to figure out a way to make turbomedia (ie this kind of thing) with it.
At the current time, I'm working on reversibility. A turbomedia tells its story through a series of states/frames, and a key feature is the ability to move back and forth between these frames at will (usually through keystrokes). In order to achieve this property of reversibility, I need states to be independent from previous events (ie state #2 must be the same whether it's reached from state #1 or state #3).
Until recently, I'd simply work with single bitmaps (such that each state would correspond to one existing file) so the problem would never present itself. However, now I'd like the ability to have states be compositions made out of multiple images (since this allows a lot more flexibility). Thus, a state might be described by the array ["sky3", "ground2", "character5"], meaning "this state contains the images stored in sky3, ground2 and character5".
The problem I'm hitting is twofold.
First, I need the ability to compare array contents so that whenever the current state changes, the new state is compared with the previous one and images are swapped around as needed (ie going from ["sky1", "kid1"] to ["sky2", "kid1"] will remove sky1 from the stage, add sky2, and keep kid1 since it's present in both states). This is to preserve animation timings across states, and to try and make transitions lighter (although I'm not sure that's needed?).
But I have no idea how to compare arrays contents like this.
The second problem is probably much simpler, but I lack experience with Javascript and honestly I have no idea what I'm doing wrong. I am unable to target the content of my states. Here is my init():
stage = new createjs.Stage("testing");
currentstate = 1;
terra1 = new createjs.Bitmap("terra1.png");
terra2 = new createjs.Bitmap("terra2.png");
bullet1 = new createjs.Bitmap("bullet1.png");
bullet2 = new createjs.Bitmap("bullet2.png");
state1 = ["terra1"];
state2 = ["terra2", "bullet1"];
state3 = ["terra2", "bullet2"];
calcstate = "state" + currentstate;
// Call the first state (at least that's what I'm going for).
console.log(calcstate);
// This returns "state1". I want it to return ["terra1"] since that's the
//content of state1.
for (i = 0; i < calcstate.length; i++) {
stage.addChild(calcstate[i]);
// Currently useless since previous code doesn't work, but would be the
// function to "create the first stage".
};
stage.update();
So yeah, for now I'm pretty much stuck. Any suggestion?
You are not referring to the instances properly.
Your calcState will be a string (such as "state1"), and not a reference to the variable state1. You could use bracket access to reference it:
Example:
this[calcState]
// OR, depending on your scope
window[calcState]
Even if your reference the state arrays correctly, they just contain strings themselves, so you would be adding "terra1" to the stage, and not the instance terra1. You can use bracket access here too, but a better way is to actually add the instances to your state arrays instead:
Example:
state1 = [terra1];
state2 = [terra2, bullet1];
state3 = [terra2, bullet2];
I recommend using console.log() to output the values calcState, as well as the calcstate[i] in your for loop, which should shed some light at what your are looking at.
An easier way to handle this would to make a states array, which has sub-elements:
states = [
[terra1],
[terra2, bullet1],
[terra2, bullet2]
];
// Refer to your states. Note that calcState should be 0-2 and not 1-3
states[calcState][i];
Hope that helps.
I've recently been working on a nice little JavaScript game engine that works a lot like Game Maker, but lets people create basic JavaScript games within a browser. Every instance of every object will have it's own preset methods, which the runner will iterate through and execute. I'm trying to find a way to let the user / creator dynamically edit any of the methods source code. When I say 'preset methods', I mean blank methods stored under specific preset names within the objects / object instances. Here's a basic example:
var newObject = object_add("object_name"); // Adds a new object 'blueprint' and returns the reference.
The function object_add(); creates a JavaScript object, and adds a number of preset methods to it, such as:
create
destroy
step
draw
.. and many more
Each of these methods will have no code in them to start with. I need to let the creator dynamically change any of the methods source code. I could simply overwrite the variable that points towards the method, with a new method, but how can you set method's source code using a string?
I know that something like:
newObject.create = function(){textbox.innerHTML};
definitely wouldn't work. Any ideas?
Many thanks,
Dan.
Looks like you want to use eval function, but it's generally a bad idea.
The answer was found at: Creating functions dynamically in JS
Here's the answer (copied from the other page).
Well, you could use Function, like in this example:
var f = new Function('name', 'return alert("hello, " + name + "!");');
f('erick');
//This way you're defining a new function with arguments and body and assigning it to a variable f. You could use a hashset and store many functions:
var fs = [];
var fs['f1'] = new Function('name', 'return alert("hello, " + name + "!");');
fs['f1']('erick');
//Loading xml depends if it is running on browser or server.
Thanks, #CBroe https://stackoverflow.com/users/1427878/cbroe
This question is related to What are the best practices to follow when declaring an array in Javascript?
Let's say a client, let's call them "D. B. Cooper", has a first requirement that the following code must run before any other JavaScript code:
Array = function(){
alert('Mwahahahaha');
};
Furthermore, Cooper requires that custom functions must be added to the built in Array object (not the hijacked one). For example, if Array was unhijacked, this would be done with:
Array.prototype.coolCustomFunction = function(){
alert('I have ' + this.length + ' elements! Cool!');
};
Which would afford:
var myArray = [];
myArray.coolCustomFunction();
However, this is not compatible with the first requirement. Thus, how can you best fulfill both of D. B. Cooper's requirements?
Note: D.B. even wrote a test fiddle to help make sure solutions meet his requirements...what a guy!
Update:
For those of you who like a challenge: please try to find an unhijackable cross-browser solution to this problem. For example, here's an even more hijacked test case (thanks for reformatting this Bergi) that hijacks Array, Object, Array.prototype.constructor, and Object.prototype.constructor. Thus far, it looks like there may be a browser-specific solution to this (see Bergi's comment on his answer, and let us know if you find a way to hijack it in FF), but it is unclear at this point if there is a cross-browser solution to this.
Whatever your Array function/constructor is, the literal syntax for arrays will always generate "real" arrays with their [[prototype]] set to the native array prototype object (once, this was a security vulnerability). So, you can always access that by using
Object.getPrototypeOf([])
even if Array or [].constructor are hijacked. (Will of course not work when Object is hijacked, then it get's really complicated)
(Brought D.B. down!)
If you want to use a workaround, in FF the following line will always work (and is not hijackable):
[].__proto__.coolCustomFunction = coolCustomFunction;
Since Array is not necessarily equal to [].constructor, you could use [].constructor to refer to the original Array function since this is hardwired and Array = function(){} won't alter it.
Array = function () { alert("foo")};
// this will always point to the original Array
[].constructor.prototype.foo = "bar";
var myArray = [0, 1];
alert(myArray.foo) // alerts "bar"
http://jsfiddle.net/yXPJ8/5/
Yes ... you just did ... but you created the array using [] .. if you use new Array() it works fine ...
See example here
I need to catch the event of getting back suggestions for google maps autocomplete. I know it is undocumented, but doing some research I found that it could be down via some prototype hacking.
<input type='text' id='myInput'>
<script src="http://maps.google.com/maps/api/js?libraries=places&sensor=false&language=en-EN"></script>
<script>
function catcher(key) { console.log(key); }
function MyProto() {}
MyProto.prototype = new google.maps.MVCObject();
MyProto.prototype.changed = catcher;
var gAuto = new google.maps.places.Autocomplete(
document.getElementById('myInput'), ['geocode']);
// one of two should be commented
//gAuto.__proto__.__proto__.changed = catcher; // every key, including 'predictions'
gAuto.__proto__.__proto__ = MyProto.prototype; // only 'types', '0', and 'place' when selected
</script>
JSFiddle link: http://jsfiddle.net/agentcooper/hRyTF/ (check the console)
Check the last two lines. When setting 'changed' function directly on MVCObject prototype (first one, commented), everything works great and I can catch key 'predictions' in the 'catcher' function. The problem is that catcher needs to be different if, for example, I need to have two instances of autocomplete on my page. So when I'm trying to inject custom object in autocomplete's prototype chain (last line) everything fails. Is there any way to solve this?
EDIT: working version, thanks to Sajid :-)
UPDATE: Completed the code, maybe it will be helpful to anyone
In the second line, you are replacing the entire prototype of the MVC object with an instance of the MVC object, and depending on how the thing is initialized, this will likely not work at all. The first like replaces one function, though in the process it completely breaks that function since you don't call its superclass version, so you are not extending, you are really clobbering. To not clobber, you need to do:
(function() {
var oldChanged = gAuto.__proto__.__proto__.changed;
function catcher(key) {
// call old version, and make sure to maintain this reference correctly
oldChanged.call(this, key);
// do your stuff here
}
gAuto.__proto__.__proto__.changed = catcher;
})();
One simple solution is that each object has an idea of this mentioned above. So changed has a reference to this, which will refer to the object being used as the caller's target (except in specific situations that are a bit out of scope here). But basically:
var x = new MVCObject();
x.changed('hi') // this === x
So if your two versions need to do different things, you can check which this the changed method was called from and react appropriately.