My main.js load module like this :
import * as THREE from "https://threejs.org/build/three.module.js";
import
OrbitControls
} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import
} from "https://threejs.org/examples/jsm/csm/CSM.js";
import
TWEEN
} from 'https://unpkg.com/[email protected]/examples//jsm/libs/tween.module.min'
i have also class inside my main.js file :
class Player{
constructor()
this.geom = new THREE.BoxGeometry(2,2,2);
this.mat = new THREE.MeshPhongMaterial({
color: 0xfffff,
this.mesh = new THREE.Mesh(this.geom, this.mat);
Until now everything works good. But i would to put my class Player in another external js file like this :
├── classes
│ └── player.js
├── index.html
└── main.js
Change in my main.js like this :
let player = new Player()
And in my index.html i do this :
<script src="js/classes/player.js"></script>
<script type='module' src="js/main.js"></script>
and my error is :
Uncaught ReferenceError: THREE is not defined
How do you do to work with external js classes files and put this on a main.js file with modules ?
Just for clarification: This runtime error happens since your import three.js
as an ES6 module. That means the resulting THREE
namespace is not available in the global space (and hence not in your Player
class). Try the following:
Implement your Player
class as an ES6 module like so:
import * as THREE from "https://threejs.org/build/three.module.js";
class Player{
constructor()
this.geom = new THREE.BoxGeometry(2,2,2);
this.mat = new THREE.MeshPhongMaterial({
color: 0xfffff,
this.mesh = new THREE.Mesh(this.geom, this.mat);
export default Player;
Import the Player
class in main.js
like so:
import Player from `./classes/player.js`;
Remove the obsolete import in your index.html
:
<script src="js/classes/player.js"></script>
that is the easy way. you either use global IIFE’s in very specific order. i would suggest you do not because it’s only a matter of time until three casts it out. or modules, which have namespaces. if your module uses something it needs to import it.
of course if you actually want to build something real using esm like that will never work, because you can’t have dependencies. the only thing that makes sense in that case is skypack or bundlers, everything else will hurt you in the process.
With Phaser and it works also with THREE.js i write my classes like this :
//in player.js
class Player{
constructor(T)
this.geom = new T.BoxGeometry(2,2,2);
this.mat = new T.MeshPhongMaterial({
color: 0xfffff,
this.mesh = new T.Mesh(this.geom, this.mat);
//in main.js
import * as THREE from "https://threejs.org/build/three.module.js";
let player = new Player(THREE)
The advantage is :
One file to load all the modules (main.js) and all the classes load the modules with abbreviations/parameters.
Is not a good way ? and Why ?
Here my files :
// classes/player.js
import * as THREE from "https://threejs.org/build/three.module.js";
class PLAYER
constructor()
this.geom = new THREE.BoxGeometry(2, 2, 2);
this.mat = new THREE.MeshPhongMaterial({
color: 0xfffff,
this.mesh = new THREE.Mesh(this.geom, this.mat);
scene.add(this.mesh)
export default PLAYER;
and my main.js
import * as THREE from "https://threejs.org/build/three.module.js";
import
OrbitControls
} from "https://threejs.org/examples/jsm/controls/OrbitControls.js";
import
} from "https://threejs.org/examples/jsm/csm/CSM.js";
import
TWEEN
} from 'https://unpkg.com/[email protected]/examples//jsm/libs/tween.module.min'
import
PLAYER
} from "./classes/player.js"
console.clear();
const params = {
color_cube: 0xacaaad,
let m = {} // materials
let g = {} // geometry
let o = {} // objects
let s = {} // sounds
let startX, startY, my_latest_tap;
let scene, camera, renderer, container, controls; // what to see
let csm, csmHelper; // plugin to have shadows on huge scene
// // // TOUCH ACTIONS
function init_app()
init()
//CHANGE KEY TOGGLES
animate()
///////////////////////////////////////////////////////////////////////////////////////////
function init()
// init_minimal(this)
const random = (min, max) => Math.floor(Math.random() * (max - min + 1) + min);
scene = new THREE.Scene();
// pour avoir une couleur de fond dans le ciel
scene.background = new THREE.Color(0xf6ffb9);
scene.fog = new THREE.Fog(params.color_fog, 0, params.distance_fog);
// camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 0.01, 2000);
camera = new THREE.PerspectiveCamera(55, window.innerWidth / window.innerHeight, 2, 2000);
// for camera with mouse
// camera.position.set(10, 1, 10);
// for camera with controls
camera.position.set(40, 13, 40);
camera.rotation.order = "YXZ";
camera.rotation.y = -Math.PI / 2;
o.direction = new THREE.Vector3(0, 0, 0);
console.log(o.direction)
camera.getWorldDirection(o.direction);
renderer = new THREE.WebGLRenderer({
antialias: true,
alpha: true,
renderer.setPixelRatio(window.devicePixelRatio);
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
// document.getElementById("canvas").appendChild(renderer.domElement);
//Shadows
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// ORBIT
controls = new OrbitControls(camera, renderer.domElement);
// controls.target.y = 5
// LIGHTS
var ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
g.cube = new THREE.BoxGeometry(2, 2, 2);
m.cube = new THREE.MeshPhongMaterial({
color: params.color_cube,
shininess: 100,
///////////////////////////////////////////////////////////////////////////////////////////
o.cube = new THREE.Mesh(g.cube, m.cube);
o.cube.castShadow = true
o.cube.receiveShadow = true
o.cube.outside = true
scene.add(o.cube);
let pl = new Player()
function animate()
requestAnimationFrame(animate);
///////////////////////////////////////////////////////////////////////////////////////////
camera.updateMatrixWorld();
renderer.render(scene, camera);
init_app()
my error is :
Uncaught SyntaxError: The requested module ‘./classes/player.js’ does not provide an export named ‘PLAYER’
Why ?
Just a last question :
how do you put scene.add(this.mesh) directly in the class ?
import * as THREE from “https://threejs.org/build/three.module.js”;
class PLAYER
constructor()
this.geom = new THREE.BoxGeometry(2, 2, 2);
this.mat = new THREE.MeshPhongMaterial({
color: 0xfffff,
this.mesh = new THREE.Mesh(this.geom, this.mat);
// DON'T WORKS
//scene.add(this.mesh)
export default PLAYER;
let pl = new Player(scene);
You could also consider to derive the Player
class from Mesh
and then add the player object directly to the scene.
scene.add(pl);
this fixed the issue I was having trying to just do the tutorial!
The WebGL Compatibility check in the tutorial was messing up!
So I fixed the import statement to be correctly styled put the check code below the animate function.
Voila! About two hours of bug fixing done!