博客 / 詳情

返回

【前端框架】ZryaJS – 2D 遊戲引擎

ZryaJS 是一個極簡、可擴展、類 Flame 風格的 2D 遊戲引擎,基於 Canvas2D 渲染,包含:

  • 世界/相機/組件體系
  • 精靈渲染 & 文本渲染
  • 輸入系統(Pointer / Keyboard)
  • 粒子系統
  • 特效系統(抖屏、閃爍)
  • 物理引擎(基礎)
  • 碰撞系統(AABB)
  • Overlay 層
  • Layout/UI
  • LayerManager
  • 資源緩存(ResourceCache)
  • 事件系統(EventBus)
  • Timer/Vec2/Rect 等工具類
  • Devtools hook
  • ImageComposition 工具
  • 擴展/實驗特性系統

目錄

  1. 初始化遊戲
  2. 世界 & 相機
  3. 組件體系 Component
  4. SpriteComponent 精靈
  5. TextComponent 文本
  6. 輸入系統
  7. 碰撞系統
  8. 物理系統
  9. Overlay 系統
  10. 粒子系統
  11. Parallax 視差背景
  12. 特效系統
  13. LayerManager 圖層
  14. UI / Layout
  15. ResourceCache 緩存
  16. EventBus 事件系統
  17. Timer 定時器
  18. Math / Rect
  19. Devtools Hook
  20. Image Composer
  21. Extensions / Experimental
  22. 完整 Demo

初始化遊戲

import { ZryaGame, CanvasRenderer } from "zryajs";

const canvas = document.querySelector("canvas")!;
const renderer = new CanvasRenderer(canvas);

const game = new ZryaGame(renderer);
game.start();

世界 & 相機

World2D

世界是組件樹的根。

game.world.root.add(new Player());

CameraComponent

用來平移/縮放/旋轉世界。

import { CameraComponent } from "zryajs";

const camera = new CameraComponent();
camera.x = 200;
camera.y = 150;
camera.zoom = 1.2;

game.world.camera = camera;

組件體系 Component

所有東西都是 Component。

import { Component } from "zryajs";

class MyObject extends Component {
  update(dt: number) {
    console.log("每幀更新", dt);
  }
}

生命週期:

  • onLoad()
  • onMount()
  • onRemove()

樹結構:

const parent = new Component();
const child = new Component();
parent.add(child);

SpriteComponent 精靈

支持圖片、canvas、ImageBitmap、video。

import { SpriteComponent } from "zryajs";

const sprite = new SpriteComponent();
sprite.texture = { image: myImage };
sprite.x = 100;
sprite.y = 200;

game.world.root.add(sprite);

裁剪:

sprite.texture = {
  image: sheet,
  sx: 32, sy: 0, sw: 32, sh: 32
};

TextComponent 文本

import { TextComponent } from "zryajs";

const txt = new TextComponent("Hello World", {
  fontSize: 20,
  color: "#ff0",
  align: "center"
});
txt.x = 300;
txt.y = 80;

game.world.root.add(txt);

輸入系統

Pointer(鼠標/觸摸)

import { Pointer } from "zryajs";

game.pointer.onDown = (p) => console.log("點擊", p.x, p.y);

Keyboard

game.keyboard.onKeyDown = (key) => {
  if (key === "Space") console.log("Jump!");
};

碰撞系統

Hitbox(AABB)

import { Hitbox } from "zryajs";

class Block extends Hitbox {
  constructor() {
    super({
      type: "aabb",
      offsetX: 0,
      offsetY: 0,
      width: 40,
      height: 40
    });
  }

  onCollisionStart(other) {
    console.log("撞到了:", other);
  }
}

掛載後自動參與碰撞檢測。

CollisionSystem

ZryaGame 自動包含:

game.collisionSystem.step(world);

無需手動調用。


物理系統

基礎物理支持:

  • 重力
  • 速度/加速度
  • 阻尼
  • 簡易地面檢測
import { PhysicsBody } from "zryajs";

class Player extends PhysicsBody {
  constructor() {
    super();
    this.gravity = 1000;
  }

  update(dt) {
    if (game.keyboard.isDown("Space") && this.onGround)
      this.velocityY = -400;
  }
}

Overlay 系統

顯示 UI 層、暫停菜單等。

import { OverlayManager } from "zryajs";

game.overlays.show("pauseMenu");
game.overlays.hide("pauseMenu");

粒子系統

兩部分:

  • ParticleSystem
  • ParticleEmitterComponent

使用粒子發射器

import { ParticleEmitterComponent } from "zryajs";

const emitter = new ParticleEmitterComponent({
  rate: 20,
  life: [0.3, 0.6],
  speed: [50, 120],
  angle: [0, Math.PI * 2],
  color: "orange"
});

emitter.x = 200;
emitter.y = 300;

game.world.root.add(emitter);

Parallax 視差背景

import { ParallaxComponent } from "zryajs";

const layer = new ParallaxComponent({
  image: bgImage,
  factorX: 0.5,
  factorY: 0
});

game.world.root.add(layer);

特效系統

所有特效由 EffectManager 調用。

CameraShake

import { CameraShakeEffect } from "zryajs";

game.effects.add(new CameraShakeEffect({
  duration: 0.3,
  strength: 8
}));

BlinkEffect(閃爍)

import { BlinkEffect } from "zryajs";

game.effects.add(new BlinkEffect(player, {
  duration: 0.2
}));

LayerManager 圖層

允許按渲染順序分層。

import { LayerManager } from "zryajs";

game.layers.add("bg");
game.layers.add("game");
game.layers.add("ui");

UI / Layout

LayoutComponent

自動對子組件定位。

import { LayoutComponent } from "zryajs";

const layout = new LayoutComponent("horizontal", 10);

layout.add(new TextComponent("A"));
layout.add(new TextComponent("B"));

game.world.root.add(layout);

UiElement

基礎 UI 元素(大小、佈局、anchor)。


ResourceCache 緩存

import { ResourceCache } from "zryajs";

const images = new ResourceCache<string, HTMLImageElement>(async (url) => {
  const img = new Image();
  img.src = url;
  await img.decode();
  return img;
});

const playerImg = await images.getOrLoad("/player.png");

EventBus 事件系統

import { EventBus } from "zryajs";

const bus = new EventBus();

bus.on("damage", (v) => console.log("Damage:", v));
bus.emit("damage", 10);

Timer 定時器

import { Timer } from "zryajs";

const timer = new Timer(1.0, () => console.log("1 秒到了"));
timer.repeat = true;

game.timers.add(timer);

Math / Rect / Vec2

import { Vec2, Rect } from "zryajs";

const v = new Vec2(10, 5).normalized();
const r = new Rect(0, 0, 100, 50);

Devtools Hook

允許外部調試器掛載遊戲狀態。

import { DevtoolsHook } from "zryajs";

DevtoolsHook.expose(game);

Image Composer

將多個 sprite 合成一張圖。

import { ImageComposer } from "zryajs";

const out = await ImageComposer.compose([
  { image: img1, x: 0,   y: 0 },
  { image: img2, x: 100, y: 50 }
]);

Extensions / Experimental

import { ExperimentalFeatureFlag } from "zryajs";

ExperimentalFeatureFlag.enable("fast-collision");

完整 Demo

import {
  ZryaGame, CanvasRenderer,
  SpriteComponent, TextComponent,
  CameraComponent, PhysicsBody,
  ParticleEmitterComponent, CameraShakeEffect
} from "zryajs";

const canvas = document.querySelector("canvas")!;
const game = new ZryaGame(new CanvasRenderer(canvas));

// 玩家
class Player extends PhysicsBody {
  constructor() {
    super();
    this.gravity = 1400;
    this.width = 40;
    this.height = 40;
  }
  update(dt) {
    if (game.keyboard.isDown("ArrowLeft")) this.velocityX -= 600 * dt;
    if (game.keyboard.isDown("ArrowRight")) this.velocityX += 600 * dt;

    if (game.keyboard.isDown("Space") && this.onGround)
      this.velocityY = -600;

    if (Math.abs(this.velocityX) > 300) {
      game.effects.add(new CameraShakeEffect({ duration: 0.1, strength: 4 }));
    }
  }
}

// 地板
class Ground extends PhysicsBody {
  constructor() {
    super();
    this.static = true;
    this.width = 600;
    this.height = 30;
  }
}

const camera = new CameraComponent();
game.world.camera = camera;

// 添加對象
const player = new Player();
player.x = 200;
player.y = 100;

const ground = new Ground();
ground.x = 300;
ground.y = 350;

game.world.root.add(ground);
game.world.root.add(player);

// 跟隨
camera.follow(player);

game.start();

ZyraJs版本號

import { zryaJsVersion } from "zryajs";

console.log(zryaJsVersion());
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.