Modify a cloned entity in aframe - clone

I am coding my second aframe project in order to better understand how the framework works. For a forest, I defined a prototype tree
<a-entity id="tree">
<a-cylinder id="cylinder" radius="0.3" height="5" color="#754" position="0 2.5 0"></a-cylinder>
<a-cone radius="2" height="4" color="#6d4" position="0 7 0"></a-cone>
</a-entity>
Then I clone this tree with the help of this script:
<a-entity clone="#tree" position="2 0 0"></a-entity>
Cloning works fine. But how can I modify the radius of the cylinder? Or is there a better way to clone entities in aframe?

In order to move forward, I defined a dedicated component for a tree:
<script>
AFRAME.registerComponent('tree', {
schema: {
height: {type: 'number', default: 9.0},
crown: {type: 'number', default: 2.0},
trunk: {type: 'number', default: 0.3}
},
init: function () {
let trunk = document.createElement('a-cylinder');
trunk.setAttribute('radius', this.data.trunk);
trunk.setAttribute('height', this.data.height * 5.0/9.0);
trunk.setAttribute('color', "#754");
trunk.object3D.position.y += this.data.height * 5.0/18.0;
this.el.appendChild(trunk);
let crown = document.createElement('a-cone');
crown.setAttribute('radius-bottom', this.data.crown);
crown.setAttribute('height', this.data.height * 4.0/9.0);
crown.setAttribute('color', "#6d4");
crown.object3D.position.y += this.data.height * 14.0/18.0;
this.el.appendChild(crown);
}
});
</script>
The component then can be instantiated and its parameters modified:
<a-entity tree></a-entity>
<a-entity tree="crown: 4; trunk: 0.7; height: 12" position="3 0 0"></a-entity>
However, this solution follows the Class/Instance paradigm and not the Prototype-Pattern. And in an educational context, a solution that hides the javascript from students would be preferable.

Notice that A-Frame follows an entity component paradigm: different than class/instance or prototype inheritance. Your tree component configures an entity as a tree and other additional components can modify or add that initial configuration. You can expose students to the pattern. The A-Frame documentation is a good starting point

Related

Three.js GIS Map (connect layers/attributive information)

Q: How to connect Three.js with any GIS map and place/process .JS (important .js) object there?
Description:
I have an app with .js model and 3D mesh model (tiles), now I need to retrieve the attributive information of the map (3D mesh) objects where ray intersects, e. I.: this is water, this is forest.
I got an idea to connect any open map and retrieve the information from there by layers (water layer, forest layer).
So far I found threebox + mapbox-gl to connect OpenStreetMap (seems like the one solution). But I cannot place the .js object. Moreover, there are two instances of three.js in the project (one is mine and one from threebox). Can anyone explain how to:
Use just one Three.js instance?
Place JS object in map?
Move object in map (in my own app I have manipulators, but seems like they won't work)?
Would be nice to hear #jscastro
No result:
tb.loadObj({
obj: 'projects/testProject/model/js/test.js',
type: 'custom',
scale: 1, /* same for 1000000000 */
units: 'meters',
rotation: { x: 90, y: 177, z: 0 },
anchor: 'auto'
}, function (model) {
console.log(model)
model.setCoords([25.2826859, 54.6718792, 1280]);
model.addTooltip("Blabla", true);
model.color = 0xffffff;
//model.selected = true;
tb.add(model);
})
up: no problem with loading .js in own app.

A-Frame Frustum Culling

How do I turn off frustum culling on a gltf model in A-Frame? I know in Three.js you can just traverse the object and add node.frustumCulled = false. I've tried
AFRAME.registerComponent('disable-culling', {
init: function(){
var object3D = this.el.sceneEl.object3D;
object3D.traverse((node) => {
node.frustumCulled = false
})
}
})
but that doesn't work. Does anyone have any idea? The entity is
<a-entity
id="ball"
scale="0.3 0.3 0.3"
position="0 0 -7"
gltf-model="#ballModel"
disable-culling
animation-mixer="clip: *; loop: once; clampWhenFinished: true;"
shadow>
</a-entity>
I had a similar problem which was solved with frustum culling -
el.addEventListener('model-loaded', () => {
const model = el.getObject3D('mesh');
model.traverse((node) => {
if (node.isMesh) {
node.frustumCulled = false;
}
});
});
I wonder if your solution didn't work simply because the model hadn't finished loading.
Go back with your 3D model to Blender, select your model on object mode and then press "ctrl A" - apply all transformations.
I just had this problem where animated models were getting culled before fully exiting the scene. In my case, the cause seemed to be that the object scale was too small. Once I scaled up the object up in Blender and re-exported the gltf file, the models were culled correctly.

Collision between camera and objects in A-Frame

I've been trying to develop a VR experience using aframe on google cardboard. The player in this game will get point deduction and knock-back when collide with vehicle (car1). Initially I tried to apply static-body and dynamic-body and define the script when collide occurs. However, it's not working as intended.
I'm out of ideas and really don't understand why I cant get the knock-back.
Need some help from A-Frame experts and developers
Thanks in advance!
<a-scene stats physics="debug:true;
<a-entity id='player' camera="active: true" look-controls wasd-controls
data-aframe-default-camera static-body>
<a-text id="score" value="Score" position="-0.2 -0.5 -1" color="black" width="5" anchor="left"></a-text>
</a-entity>
<a-entity id='car1' obj-model="obj:#car_obj;mtl:#car_mtl" dynamic-body></a-entity>
</a-scene>
<script>
let score = 0;
let hit = false
const knockback= () => {
clearTimeout(resetId)
$("#player").body.position.set(0, 0.6,-4)
$("#player").body.velocity.set(0, 5,0)
$("#player").body.angularVelocity.set(0, 0,0)
hit = false
}
on($("#player"), 'collide', (e) => {
const car1 =$("#car1")
if (e.detail.body.id == car1.body.id){
hit = true
score = score + 1
$("#score").setAttribute('text','value','Score '+score)
}
})
</script>

Angular2 move animation

Angular 1 handles enter, leave and move animations. The Angular 2 documentation describes how to do enter and leave animations (void => * and * => void), but how can one implement move animations in Angular 2?
Read Angular's official guide for animations if you haven't already.
You define animation states and the transitions between them. For instance:
animations: [
trigger('heroState', [
state('inactive', style({
backgroundColor: '#eee',
transform: 'scale(1)'
})),
state('active', style({
backgroundColor: '#cfd8dc',
transform: 'scale(1.1)'
})),
transition('inactive => active', animate('100ms ease-in')),
transition('active => inactive', animate('100ms ease-out'))
])
]
inactive and active can be replaced with any arbitrary strings and you can have as many unique states as you wish, but there must be a valid transition to each one or else the animation won't happen. void is a special case for when elements aren't yet attached to the view and * is a wildcard, applying to any of the defined states.
EDIT:
Hmm... well, for one thing, you might be able to use this Sortable library. It claims to support Angular 2 and is pure Javascript (no jQuery) so theoretically, it should work well but I have not used it myself.
Otherwise, I am certain it would be possible purely inside Angular 2, but it would probably require some fairly clever code. Relative motion (irrespective of a component or element's particular position) is easy with transform: translateY() property. The problem is that Angular 2 animation states only apply if the component is in that state so if you give it a translateY(-20px) to move an element up a position, it's not going to keep that position if you want to want to move it up again.
See this plunker for the solution I have come up with.
template: `
<div #thisElement>
<div class="div-box" #moveState="state">Click buttons to move <div>
</div>
<button (click)="moveUp()">Up</button>
<button (click)="moveDown()">Down</button>
`,
I defined animation states for 'moveUp' and 'moveDown' that ONLY apply during the actual animation and a 'static' state that is applied when the component isn't moving.
animations: [
trigger('moveState', [
state('moveUp', style({
transform: 'translateY(-30px)';
})),
state('moveDown', style({
transform: 'translateY(30px)';
})),
state('static', style({
transform: 'translateY(0)';
})),
transition('* => moveUp', animate('100ms ease-in')),
transition('* => moveDown', animate('100ms ease-out')),
transition('* => static', animate('0ms linear'))
])
]
For the function that actually initiates the animation, it applies the 'moveUp' or 'moveDown' state and then starts a timeout that triggers a callback after an amount of time equal to the length of the transition. In the callback, it sets the animation state to 'static' (the transition to the 'static' state is set to 0 ms so we don't actually animate it moving back to a static position). Then we use Renderer to apply a translation for where we want it to ultimately end up (calculated using a position property that would define it's position relative to where it was initially, not it's position in the array). The Renderer applies its styles separately from the animation so we can apply both without them conflicting with each other.
export class MyComponent {
state = 'static';
#ViewChild('thisElement') thisBox: ElementRef;
position: number = 0;
//...
moveUp() {
this.state = 'moveUp';
this.position--;
setTimeout(() => {
this.state = 'static';
this.renderer.setElementStyle(this.thisBox.nativeElement, 'transform', 'translateY(' + String(this.position * 30) + 'px)');
}, 100)
}
moveDown() {
this.state = 'moveDown';
this.position++;
setTimeout(() => {
this.state = 'static';
this.renderer.setElementStyle(this.thisBox.nativeElement, 'transform', 'translateY(' + String(this.position * 30) + 'px)');
}, 100)
}
//...
}
This is only an example of how you can animate moves without having to define states for each possible position it could be in. As far as triggering the animations on array manipulation, you'll have to figure that out for yourself. I would use some kind of implementation with EventEmitters or Subjects to send events to the components that would then decide on whether or not they need to animate or not.

Angular2 Animations :: Easings not working as expected

I'm working on a collapsable component, one that you can click to roll-up/down to show/hide details. The component is as follows:
// component.ts
import {Component, Directive, Input} from '#angular/core';
import {trigger, state, style, transition, animate} from '#angular/core'
#Component({
selector: 'expandable',
template: '<div *ngIf="isExpanded" #animate="'slide'"><ng-content></ng-content></div>',
animations: [
trigger('animate', [
state('slide', style({ overflow: 'hidden', height: '*' })),
transition('slide => void', [animate('200ms ease-out', style({ height: 0 }))]),
transition('void => slide', [style({ height: 0 }), animate('200ms ease-out', style({ height: '*' }))])
])
]
})
export class SimExpandable {
private _expanded: boolean = false;
#Input('expanded') set expanded(value: string | boolean) {
this._expanded = (value === 'true' || value === true);
}
get isExpanded(): boolean { return this._expanded }
}
The component works fine, partially. The animations, however, are not perfect. I've configured the component to use ease-out animation but in reality, the component animates linearly.
I've tried using ease-out, easeOut, ease-out-cubic, easeOutCubic, ease-in-out, easeInOut, bounce, and a lot of other permutations but the component still animates linearly. I REALLY need to use ease-out for my component. Any help would be really appreciated.
CSS properties transition and animation allow you to pick the easing
function. Unfortunately, they don’t support all easings and you must
specify the desired easing function yourself (as a Bezier curve).
Easings.net
It would seem that there are 4 default types of easing that should work.
linear
ease
ease-in
ease-out
ease-in-out
These work directly, however the differences are subtle
For more effective types of easing, you have to use a bezier-curve which allows you to create your own easing. For example the below is "easeInOutBack"
cubic-bezier(0.680, -0.550, 0.265, 1.550)
When using with Angular animate function
animate("1500ms 2000ms cubic-bezier(0.680, -0.550, 0.265, 1.550)", style({transform: "translateX(-100%)"}))
You can navigate to this bezier curver generator which should provide you with the ability to create your own easings.
Animate is no longer a part in angular/core.. so you have to import it, its part of the module ngAnimate .. so to use the $animate service you need to import js/lib/angular-animate.js libs.
bower install --save angular-animate

Resources