Building an Advanced Scene
Note: This documentation is for the old 0.2.0 version of A-Frame. Check out the documentation for the current 1.6.0 version
Play with the [finished example on CodePen][http://codepen.io/team/mozvr/pen/PNoWEz/?editors=1000].
We built a basic scene, but how can we do more? A-Frame is just an abstraction on top of three.js, and with A-Frame components (not to be confused with Web Components), we can do just about anything three.js can, which is a lot. Let’s go through an example building a scene where the workflow revolves around writing components. We’ll build an interactive scene in which we fire lasers at enemies surrounding us. We can use the standard components that ship with A-Frame, or use components that A-Frame developers have published to the ecosystem. Better yet, we can write our own components to do whatever we want!
Let’s start by adding an enemy target:
See the Pen Laser Shooter - Step 1 by MozVR (@mozvr) on CodePen.
This creates a basic static scene where the enemy stares at you even as you move around. We can use A-Frame components from the ecosystem to do some neat things.
Using Components
The awesome-aframe repository is a great place to find components that the community has created to enable new features. Many of these components are started from the [Component Boilerplate][boilerplate and should provide builds in the dist/
folders in their repositories. Take the layout component for example. We can grab the build, drop it into our scene, and immediately be able to use a 3D layout system to automatically position entities. Instead of having one enemy, let’s have ten enemies positioned in a circle around the player:
See the Pen Laser Shooter - Step 2 by MozVR (@mozvr) on CodePen.
It is messy in markup to have the enemy entity duplicated ten times. We can drop in the template component to clean that up. We can also use the animation system to have enemies march in a circle around us:
See the Pen Laser Shooter - Step 3 by MozVR (@mozvr) on CodePen.
By mixing and matching the layout and template components, we now have ten enemies surrounding us in a circle. Let’s enable gameplay by writing our own components.
Writing Components
Developers that are comfortable with JavaScript and three.js can write components to add appearance, behavior, and functionality to the experience. As we’ve seen these components can then be reused and shared with the community. Though not all components have to be shared; they can be ad-hoc or one-off. Since A-Frame is based on an entity-component-system pattern, most logic should be implemented within components. The development workflow within A-Frame should try to revolve around components. The component documentation goes into much more detail on what a component looks like and how to write one.
We want to be able to fire lasers at the enemies and have them disappear. We will need a component to create lasers on click, a component to generate clicks, a component to propel those lasers, a component to check when a laser comes in contact with an enemy.
spawner Component
Let’s start by being able to create lasers. We want to be able to spawn a laser entity that starts at the player’s current position. We’ll create a spawner component that listens to an event on the entity, and when that event is emitted, we’ll spawn an entity with a predefined mixin of components:
AFRAME.registerComponent('spawner', { |
click-listener Component
Now we need to a way to generate a click event on the player entity in order to spawn the laser. We could just write a vanilla JavaScript event handler in a content script, but it is more reusable to write a component that can allow any entity to listen for clicks:
AFRAME.registerComponent('click-listener', { |
From HTML, we define the laser mixin and attach the spawner and click-listener components to the player. When we click, the spawner component will generate a laser starting in front of the camera:
See the Pen Laser Shooter - Step 4 by MozVR (@mozvr) on CodePen.
projectile Component
Now lasers will spawn in front of us when we click, but we need them to fire and travel. In the spawner component, we had the laser point in the rotation of the camera, and we rotated it 90-degrees around the X-axis to align it correctly. We can add a projectile component to have the laser travel straight in the direction it’s already facing (its local Y-axis in this case):
AFRAME.registerComponent('projectile', { |
Then attach the projectile component to the laser mixin:
<a-assets> |
The laser will now fire like a projectile on click:
See the Pen Laser Shooter - Step 5 by MozVR (@mozvr) on CodePen.
collider Component
The last step is to add a collider component so we can detect when the laser hits an entity. We can do this using the three.js Raycaster, drawing a ray (line) from one end of the laser to the other, then continuously checking if one of the enemies are intersecting the ray. If an enemy is intersecting our ray, then it is touching the laser, and we use an event to tell the enemy that it got hit:
AFRAME.registerComponent('collider', { |
Then attach a class to the enemies to designate them as targets, attach animations to listen for collisions to make them disappear, and attach the collider component to the laser that targets enemies. For good measure, let’s make it a challenge and have the enemies march around you as well:
Then we attach a class to the enemies to designate them as targets, attach animations that trigger on collision to make them disappear, and finally attach the collider component to the laser that targets enemies:
<a-assets> |
And there we have a complete basic interactive scene in A-Frame that can be viewed in VR. We package power into components that allow us to declaratively build scenes without losing control or flexibility. The result is a rudimentary FPS game that supports VR in ultimately just 30 lines of HTML:
See the Pen Laser Shooter - Final by MozVR (@mozvr) on CodePen.