1. LayaAir 引擎入门指南:从零开始掌握核心功能
作为一名使用 LayaAir 引擎多年的开发者,我深知新手在入门阶段最需要哪些知识。这份指南将带你系统性地了解 LayaAir 的核心功能,避免走弯路。不同于官方文档的碎片化说明,我会结合实战经验,告诉你哪些 API 真正常用、哪些配置项容易被忽略、以及那些官方没明说但实际开发中必须注意的细节。
LayaAir 是一款优秀的 HTML5 和 Native 游戏引擎,特别适合中小型游戏团队和个人开发者。它支持 TypeScript 和 JavaScript 开发,拥有完善的 2D/3D 功能,性能表现优异。下面我们就从最基础的引擎初始化开始,逐步深入各个核心模块。
2. 引擎初始化与全局配置
2.1 基础初始化方式
LayaAir 的初始化是整个游戏的起点,正确的初始化配置能为后续开发省去很多麻烦。最基本的初始化方式是通过 Laya.init() 方法:
typescript复制// 最简单的初始化方式 - 指定画布宽高
Laya.init(750, 1334).then(() => {
// 初始化完成后进入游戏主逻辑
gameStart();
});
这里有几个新手常犯的错误需要注意:
Laya.init()返回的是 Promise,记得用.then()处理初始化完成后的逻辑- 宽高参数单位是像素,建议使用设计分辨率尺寸
- 在移动端,这个尺寸会被自动适配到屏幕实际大小
实际项目中,我建议使用配置对象的方式进行初始化,这样可以设置更多参数,后面会详细介绍。
2.2 高级初始化配置
更专业的做法是使用配置对象初始化,这样可以精细控制引擎的各个方面:
typescript复制const config = {
width: 750, // 设计宽度
height: 1334, // 设计高度
renderMode: "webgl", // 渲染模式:"webgl"|"canvas"|"auto"
antialias: true, // 是否开启抗锯齿
transparent: false, // 画布是否透明
fps: 60, // 目标帧率
useRetinalCanvas: true, // 是否使用视网膜屏优化
devicePixelRatio: 2 // 设备像素比
};
Laya.init(config).then(() => {
// 游戏主逻辑
});
这些配置项中,有几个特别值得关注:
renderMode:WebGL 模式性能更好但兼容性稍差,Canvas 模式兼容性更好但性能较低。现代浏览器建议使用 WebGL。useRetinalCanvas:在高清屏(如 iPhone 的 Retina 屏)上开启可以获得更清晰的显示效果。devicePixelRatio:通常设置为 1 或 2,控制画布的实际像素与逻辑像素的比例。
2.3 全局对象解析
引擎初始化后,会创建几个重要的全局对象:
typescript复制Laya.stage; // 舞台实例,所有显示对象的根容器
Laya.timer; // 全局计时器,用于游戏主循环
Laya.loader; // 资源加载管理器
Laya.systemTimer; // 系统计时器(引擎内部使用)
Laya.physicsTimer; // 物理计时器
其中 Laya.stage 是最常用的对象,它代表游戏的根容器,具有以下重要属性:
typescript复制// 设置设计尺寸
Laya.stage.designWidth = 750;
Laya.stage.designHeight = 1334;
// 屏幕适配模式
Laya.stage.scaleMode = "fixedwidth"; // 固定宽度,高度自适应
Laya.stage.screenMode = "horizontal"; // 横屏模式
// 对齐方式
Laya.stage.alignV = "middle"; // 垂直居中
Laya.stage.alignH = "center"; // 水平居中
// 帧率设置
Laya.stage.frameRate = 60; // 目标60帧
关于屏幕适配,这是新手最容易出问题的地方。LayaAir 提供了多种 scaleMode:
noscale:不缩放,按原始尺寸显示exactfit:拉伸填满屏幕,可能变形showall:保持比例显示全部内容,可能有黑边noborder:保持比例填满屏幕,可能裁剪fixedwidth:固定宽度,高度自适应fixedheight:固定高度,宽度自适应fixedauto:根据屏幕方向自动选择 fixedwidth 或 fixedheight
对于手机游戏,我推荐使用 fixedwidth 或 fixedauto,这样能更好地适应不同屏幕比例。
3. 显示列表与节点系统
3.1 显示列表基础架构
LayaAir 的显示列表采用树状结构,所有可见对象都是 Node 的子类。理解这个结构对游戏开发至关重要:
code复制Node (基类)
├── Sprite (2D精灵)
│ ├── Stage (舞台)
│ └── Scene (场景)
└── Sprite3D (3D精灵)
└── Scene3D (3D场景)
3.2 Node 基类详解
Node 是所有显示对象的基类,提供了节点管理的基础功能:
typescript复制// 创建节点
const node = new Laya.Node();
// 设置节点属性
node.name = "hero"; // 节点名称
node.zOrder = 10; // 渲染层级(越大越靠前)
node.visible = true; // 是否可见
node.alpha = 0.8; // 透明度(0-1)
// 添加到舞台
Laya.stage.addChild(node);
节点管理常用方法:
typescript复制// 添加子节点
parent.addChild(child);
parent.addChildAt(child, 0); // 添加到指定位置
// 移除子节点
parent.removeChild(child);
parent.removeChildAt(0); // 移除指定位置的子节点
parent.removeChildren(); // 移除所有子节点
// 查找子节点
parent.getChildAt(0); // 按索引获取
parent.getChildByName("hero");// 按名称获取
parent.findChild("weapon"); // 递归查找
实际开发中,频繁添加/移除节点会影响性能。对于需要反复使用的对象(如子弹、敌人),建议使用对象池技术。
3.3 Sprite 精灵类
Sprite 是最常用的 2D 显示对象,继承自 Node,增加了图形渲染和交互功能:
typescript复制const sprite = new Laya.Sprite();
// 位置和变换
sprite.x = 100;
sprite.y = 200;
sprite.scaleX = 0.5; // 水平缩放
sprite.scaleY = 0.5; // 垂直缩放
sprite.rotation = 45; // 旋转角度(度)
sprite.skewX = 10; // 水平倾斜
sprite.skewY = 10; // 垂直倾斜
// 锚点设置(默认0,0即左上角)
sprite.pivotX = 0.5; // 水平轴心点(0-1)
sprite.pivotY = 0.5; // 垂直轴心点(0-1)
// 交互设置
sprite.mouseEnabled = true; // 启用鼠标交互
Sprite 的绘图功能通过 graphics 属性实现:
typescript复制// 绘制矩形
sprite.graphics.drawRect(0, 0, 100, 50, "#FF0000");
// 绘制圆形
sprite.graphics.drawCircle(50, 50, 30, "#00FF00");
// 绘制图片
sprite.graphics.drawTexture(Laya.loader.getRes("image.png"));
// 清除绘图
sprite.graphics.clear();
3.4 显示列表性能优化
在游戏开发中,显示列表的性能直接影响游戏流畅度。以下是几个关键优化点:
- 减少重绘:对于静态内容,设置
cacheAs = "bitmap"可以缓存为位图 - 控制可见性:对不可见的对象设置
visible = false,避免不必要的渲染 - 合理使用 zOrder:正确设置渲染层级,避免频繁的深度排序
- 及时销毁对象:不再使用的对象调用
destroy()释放资源
typescript复制// 缓存为位图(适合静态内容)
sprite.cacheAs = "bitmap";
// 销毁对象
sprite.destroy();
4. 事件系统与用户交互
4.1 事件监听基础
LayaAir 的事件系统基于 EventDispatcher,几乎所有交互对象都继承自它:
typescript复制// 监听点击事件
sprite.on(Laya.Event.CLICK, this, onClickHandler);
function onClickHandler(e: Laya.Event) {
console.log("Sprite被点击了", e.target);
}
// 移除监听
sprite.off(Laya.Event.CLICK, this, onClickHandler);
常用事件类型:
typescript复制Laya.Event.CLICK; // 点击
Laya.Event.MOUSE_DOWN; // 鼠标按下
Laya.Event.MOUSE_UP; // 鼠标抬起
Laya.Event.MOUSE_MOVE; // 鼠标移动
Laya.Event.KEY_DOWN; // 按键按下
Laya.Event.KEY_UP; // 按键抬起
4.2 事件冒泡机制
LayaAir 的事件系统支持冒泡,事件会从目标节点向上传播到舞台:
typescript复制// 启用事件冒泡
const event = new Laya.Event("click", true); // 第二个参数true表示冒泡
// 在父容器监听
parent.on(Laya.Event.CLICK, this, onParentClick);
function onParentClick(e: Laya.Event) {
console.log("父容器收到点击事件", e.target);
}
可以通过 e.stopPropagation() 阻止事件继续冒泡:
typescript复制sprite.on(Laya.Event.CLICK, this, (e) => {
e.stopPropagation(); // 阻止事件冒泡
});
4.3 键盘与触摸输入
键盘输入处理:
typescript复制// 监听键盘事件
Laya.stage.on(Laya.Event.KEY_DOWN, this, (e) => {
if (e.keyCode === Laya.Keyboard.A) {
console.log("A键被按下");
}
});
// 检查按键状态
if (Laya.Keyboard.hasKeyDown(Laya.Keyboard.SPACE)) {
console.log("空格键正被按住");
}
多点触控处理:
typescript复制// 启用多点触控
Laya.Input.multiTouchEnabled = true;
// 监听触摸事件
Laya.stage.on(Laya.Event.TOUCH_MOVE, this, (e) => {
const touches = e.touches; // 获取所有触摸点
touches.forEach((touch) => {
console.log(`触摸点${touch.identifier}: (${touch.posX}, ${touch.posY})`);
});
});
5. 资源加载与管理
5.1 基本加载方式
LayaAir 提供了强大的资源加载系统,支持多种资源类型:
typescript复制// 加载单个资源
Laya.loader.load("res/image.png", Laya.Handler.create(this, onLoaded));
// 加载多个资源
const resArray = [
{ url: "res/image.png", type: Laya.Loader.IMAGE },
{ url: "res/atlas.json", type: Laya.Loader.ATLAS },
{ url: "res/sound.mp3", type: Laya.Loader.SOUND }
];
Laya.loader.load(resArray, Laya.Handler.create(this, onAllLoaded));
常用资源类型常量:
typescript复制Laya.Loader.IMAGE; // 图片
Laya.Loader.ATLAS; // 图集
Laya.Loader.SOUND; // 音频
Laya.Loader.JSON; // JSON
Laya.Loader.TEXT; // 文本
Laya.Loader.PREFAB; // 预制体
5.2 资源缓存与释放
合理管理资源缓存对内存控制至关重要:
typescript复制// 获取已加载资源
const texture = Laya.loader.getRes("res/image.png");
// 缓存资源
Laya.loader.cacheRes("res/image.png", texture);
// 释放资源
Laya.loader.clearRes("res/image.png");
// 释放纹理资源(包括GPU内存)
Laya.loader.clearTextureRes("res/image.png");
// 销毁所有未使用的资源
Laya.Resource.destroyUnusedResources();
实际项目中,我建议为每个场景维护一个资源清单,在场景切换时释放不再需要的资源。
5.3 图集与纹理使用
使用纹理图集能显著提升渲染性能:
typescript复制// 加载图集
Laya.loader.load("res/atlas.json", Laya.Handler.create(this, onAtlasLoaded));
function onAtlasLoaded() {
// 从图集创建精灵
const sprite = new Laya.Sprite();
sprite.graphics.drawTexture(Laya.loader.getRes("atlas/hero.png"));
Laya.stage.addChild(sprite);
}
纹理的高级用法:
typescript复制// 创建空白纹理
const texture = new Laya.Texture2D();
texture.loadImageSource(imageSource);
// 纹理属性设置
texture.wrapModeU = Laya.Texture.WRAP_REPEAT; // 水平重复
texture.wrapModeV = Laya.Texture.WRAP_CLAMP; // 垂直钳制
texture.filterMode = Laya.Texture.FILTER_LINEAR; // 线性过滤
6. 动画系统与定时器
6.1 缓动动画 Tween
LayaAir 的 Tween 类提供了强大的缓动动画功能:
typescript复制// 基本缓动
Laya.Tween.to(sprite, { x: 100, y: 200 }, 1000);
// 带缓动函数和回调
Laya.Tween.to(sprite, {
x: 100,
y: 200,
alpha: 0.5
}, 1000, Laya.Ease.elasticOut, Laya.Handler.create(this, onTweenComplete));
// 链式动画
Laya.Tween.to(sprite, { x: 100 }, 500)
.to(sprite, { y: 200 }, 500);
常用缓动函数:
typescript复制Laya.Ease.linearIn; // 线性
Laya.Ease.backIn; // 回弹
Laya.Ease.elasticOut; // 弹性
Laya.Ease.bounceOut; // 弹跳
6.2 帧动画 Animation
对于序列帧动画,可以使用 Animation 组件:
typescript复制// 创建动画组件
const animation = sprite.addComponent(Laya.Animation) as Laya.Animation;
// 加载动画剪辑
animation.loadAnimation("res/anim/hero.ani");
// 播放动画
animation.play("run"); // 播放名为"run"的动画剪辑
6.3 定时器 Timer
LayaAir 提供了多种定时器实现方式:
typescript复制// 帧循环(每帧执行)
Laya.timer.frameLoop(1, this, onFrame);
// 时间循环(每1000毫秒执行)
Laya.timer.loop(1000, this, onTimer);
// 延迟执行(500毫秒后执行一次)
Laya.timer.once(500, this, onDelay);
function onFrame() {
console.log("每帧执行");
}
function onTimer() {
console.log("每秒执行");
}
function onDelay() {
console.log("延迟执行");
}
定时器清理:
typescript复制// 清除特定回调
Laya.timer.clear(this, onFrame);
// 清除对象的所有定时器
Laya.timer.clearAll(this);
7. 3D 开发基础
7.1 3D 场景与相机
3D 开发的基本结构:
typescript复制// 创建3D场景
const scene = new Laya.Scene3D();
// 创建相机
const camera = new Laya.Camera(0, 0.1, 100);
camera.transform.translate(new Laya.Vector3(0, 1.5, 3));
camera.transform.rotate(new Laya.Vector3(-15, 0, 0), true);
scene.addChild(camera);
// 设置场景
Laya.stage.setScene(scene);
相机的重要参数:
typescript复制camera.fieldOfView = 60; // 视野角度(度)
camera.nearPlane = 0.1; // 近裁剪面
camera.farPlane = 100; // 远裁剪面
camera.clearColor = "#000000"; // 背景色
camera.orthographic = false; // 是否正交投影
7.2 3D 模型与材质
加载和使用 3D 模型:
typescript复制// 加载模型
Laya.Sprite3D.load("res/model/hero.lh", Laya.Handler.create(this, (sprite) => {
scene.addChild(sprite);
// 获取材质并修改
const meshSprite = sprite.getChildAt(0) as Laya.MeshSprite3D;
const material = meshSprite.meshRenderer.material as Laya.BlinnPhongMaterial;
material.albedoColor = new Laya.Vector4(1, 0, 0, 1); // 设置为红色
}));
创建自定义材质:
typescript复制// 创建标准材质
const material = new Laya.BlinnPhongMaterial();
material.albedoTexture = Laya.Texture2D.load("res/texture/diffuse.png");
material.specularColor = new Laya.Vector3(1, 1, 1);
material.gloss = 32;
// 应用到模型
meshSprite.meshRenderer.material = material;
8. 组件化开发
8.1 自定义组件
通过继承 Laya.Script 创建自定义组件:
typescript复制class PlayerController extends Laya.Script {
public speed: number = 5;
constructor() {
super();
}
onUpdate() {
const transform = this.owner.transform;
if (Laya.Keyboard.hasKeyDown(Laya.Keyboard.W)) {
transform.translate(new Laya.Vector3(0, 0, -this.speed * Laya.timer.delta / 1000));
}
}
}
// 使用组件
const player = new Laya.Sprite3D();
player.addComponent(PlayerController);
8.2 组件生命周期
组件的主要生命周期方法:
typescript复制class MyComponent extends Laya.Script {
onAwake() {
// 组件创建时调用
}
onEnable() {
// 组件启用时调用
}
onStart() {
// 第一次onUpdate前调用
}
onUpdate() {
// 每帧调用
}
onLateUpdate() {
// 每帧在所有onUpdate之后调用
}
onDisable() {
// 组件禁用时调用
}
onDestroy() {
// 组件销毁时调用
}
}
9. 音频系统
9.1 播放音效与音乐
LayaAir 的音频系统使用简单:
typescript复制// 播放音效(可同时播放多个)
const soundChannel = Laya.SoundManager.playSound("res/sound/shoot.mp3", 1);
// 播放背景音乐(同时只能播放一个)
Laya.SoundManager.playMusic("res/sound/bgm.mp3", 0); // 0表示无限循环
// 停止所有声音
Laya.SoundManager.stopAll();
// 设置音量
Laya.SoundManager.soundVolume = 0.5; // 音效音量
Laya.SoundManager.musicVolume = 0.7; // 音乐音量
9.2 音频控制
对音频通道的精细控制:
typescript复制// 获取音频通道
const channel = Laya.SoundManager.playSound("res/sound/long.mp3");
// 暂停/恢复
channel.pause();
channel.resume();
// 停止
channel.stop();
// 设置播放位置(秒)
channel.position = 10.5;
// 设置播放速率
channel.playbackRate = 1.5; // 1.5倍速
10. 实战经验与性能优化
10.1 常见问题解决
-
画面闪烁或卡顿
- 检查帧率是否稳定:
Laya.stage.frameRate - 减少每帧的绘制调用(DrawCall)
- 对静态内容使用
cacheAs = "bitmap"
- 检查帧率是否稳定:
-
内存泄漏
- 确保销毁不再使用的对象:
sprite.destroy() - 定期调用
Laya.Resource.destroyUnusedResources() - 使用对象池管理频繁创建/销毁的对象
- 确保销毁不再使用的对象:
-
触摸事件不响应
- 检查
mouseEnabled是否开启 - 确认对象在显示列表中且
visible = true - 检查是否有其他对象拦截了事件
- 检查
10.2 性能优化技巧
-
渲染优化
- 合并图集,减少纹理切换
- 使用
cacheAs缓存复杂静态内容 - 合理设置
zOrder减少深度排序开销
-
内存优化
- 及时释放不用的资源
- 使用对象池重用对象
- 避免在循环中创建新对象
-
CPU 优化
- 减少不必要的计算
- 使用
Laya.timer.frameLoop替代onUpdate控制执行频率 - 对复杂计算考虑使用 Worker 线程
10.3 调试技巧
-
性能分析
typescript复制// 显示性能统计面板 Laya.Stat.show(); -
调试绘制
typescript复制// 显示碰撞体边框 Laya.physicsDebugDraw.enable = true; -
控制台输出
typescript复制// 打印节点树 console.log(Laya.stage._children); // 打印资源缓存 console.log(Laya.Loader.loadedMap);
掌握这些核心功能和技巧后,你已经具备了使用 LayaAir 开发游戏的基础能力。实际项目中,建议多参考官方示例和社区分享的最佳实践,不断积累经验。