Project Structure Overview
The core implementation utilizes Three.js for 3D rendering in WeChat mini games. The project organization includes:
game.json,project.config.json: WeChat mini-game configuration filesgame.js: Main application entry pointworkers/: Web Workers for enemy AI calculationsunits/: Utility functions and math operationsmodels/: Character, enemy, and environment assetsjs/: Core game implementation logicimages/,audio/: Resource directories
Initialization and Core Arcihtecture
The game entry point initializes the main engine class:
// game.js
import './js/libs/weapp-adapter';
import './js/libs/symbol';
import GameEngine from './js/Main';
const gameInstance = new GameEngine();
The main engine class handles scene setup and resource management:
class GameEngine {
constructor() {
this.level = 1;
this.movementSpeed = 16;
this.player = null;
this.controlInterface = null;
this.worker = wx.createWorker('workers/enemyWorker.js');
this.worker.onProcessKilled(() => {
this.worker = wx.createWorker('workers/enemyWorker.js');
});
this.audioController = new AudioManager();
this.initializeScene();
this.loadLevel(this.level);
}
}
Character Control Implementation
A virtual joystick controls character movement. The HUD element implementation:
const hudConfig = {
visible: true,
name: "controlPad",
type: "plane",
width: controlRadius * 0.9,
height: controlRadius * 0.9,
texture: "images/control_pad.png",
position: { x: -window.innerWidth/2 + controlRadius,
y: window.innerHeight/2 - controlRadius*3,
z: -150 }
};
sceneManager.addHudElement(hudConfig);
Touch event handling for controls:
handleTouchEvent(element, event) {
if (element.name === "controlPad") {
const player = sceneManager.findObject("player");
sceneManager.camera.originalPosition = { ...sceneManager.camera.position };
sceneManager.camera.targetPosition = { ...sceneManager.controls.target };
sceneManager.camera.position.set(
player.position.x,
player.position.y + 400,
player.position.z
);
sceneManager.controls.target.set(
player.position.x + 3000 * Math.sin(player.rotation.y),
player.position.y + 200,
player.position.z + 3000 * Math.cos(player.rotation.y)
);
return false;
}
}
Combat System Mechanics
Character combat animations and state management:
function executeCombatMove() {
clearInterval(player.movementTimer);
player.movementTimer = setInterval(() => {
if (currentLevel) {
currentLevel.updatePlayerPosition();
currentLevel.adjustCamera();
}
if (Math.abs(controlInterface.velocity.x) <= 0.1 &&
Math.abs(controlInterface.velocity.y) <= 0.1) {
if (player.currentAnimation !== "idle") {
player.playAnimation("idle");
}
}
}, 100);
}
Enemy Navigation Algorithms
Pathfinding with collision avoidance:
class NavigationUtils {
static translateLineNormal(x1, y1, x2, y2, offset) {
const angle = this.calculateAngle(x1, y1, x2, y2) * Math.PI / 180;
return [
x1 - offset * Math.sin(angle),
y1 + offset * Math.cos(angle),
x2 - offset * Math.sin(angle),
y2 + offset * Math.cos(angle)
];
}
static findLineIntersection(a, b, c, d) {
const denominator = (b.y - a.y) * (d.x - c.x) - (a.x - b.x) * (c.y - d.y);
if (denominator === 0) return null;
const x = ((b.x - a.x) * (d.x - c.x) * (c.y - a.y) +
(b.y - a.y) * (d.x - c.x) * a.x -
(d.y - c.y) * (b.x - a.x) * c.x) / denominator;
const y = -((b.y - a.y) * (d.y - c.y) * (c.x - a.x) +
(b.x - a.x) * (d.y - c.y) * a.y -
(d.x - c.x) * (b.y - a.y) * c.y) / denominator;
const onSegment1 = (x - a.x) * (x - b.x) <= 0 && (y - a.y) * (y - b.y) <= 0;
const onSegment2 = (x - c.x) * (x - d.x) <= 0 && (y - c.y) * (y - d.y) <= 0;
return { x, y, intersects: onSegment1 && onSegment2 };
}
}
Special Atack Implementation
Special move execution with particle effects:
player.playAnimation("special_move", 1, (time, frame) => {
if (frame === "effect_trigger") {
const effect = sceneManager.findObject("special_effect");
effect.visible = true;
const leftHand = player.children[4].children[0].children[0].getWorldPosition();
const rightHand = player.children[3].children[0].children[0].getWorldPosition();
effect.position.set(
(leftHand.x + rightHand.x) / 2,
(leftHand.y + rightHand.y) / 2 + 30,
(leftHand.z + rightHand.z) / 2
);
effect.scale.set(1, 1, 1);
currentLevel.detectEffectCollisions(effect);
}
});
Level Progression System
Level transition implementation:
loadLevel(levelId) {
wx.triggerGC();
this.level = levelId;
if (levelId === 1) {
this.currentLevel = new LevelOne(this, THREE, TWEEN);
this.currentLevel.initialize();
} else if (levelId === 2) {
if (this.currentLevel) {
this.currentLevel.cleanup(() => {
this.currentLevel = new LevelTwo(this, THREE, TWEEN);
this.currentLevel.initialize();
});
} else {
this.currentLevel = new LevelTwo(this, THREE, TWEEN);
this.currentLevel.initialize();
}
}
}
Development Considerations
Key focus areas during implementation:
- Gameplay mecahnics and engagement factors
- Performance optimization for mobile platforms
- Balancing visual quality with resource constraints