StageJS
用于游戏开发的2D HTML5渲染和布局引擎
README
Stage.js是一个2D的HTML5 Javascript库,用于跨平台游戏开发,它量轻,快速,且开源。
介绍
Canvas是HTML游戏开发中的图形元素,但它只支持绘图接口,但它没有任何可以像DOM那样支持你应用程序操作的数据模型,你必须手动绘制你的应用程序,并且管理渲染循环才可以“玩”它。再有,鼠标事件也仅仅在整个的画布层级上可用,它们也需要被手动处理。
Stage.js提供了类似于DOM的树型数据模型,来操作你的应用程序,且在内部管理渲染循环及应用程序的绘制,它也处理且向目标树节点,发布鼠标及触摸事件。一个Stage.js应用包含了许多的树节点,每个节点都相对于它的父级节点定位(变型),且拥有0/1/或更多个图像纹理。
每次渲染循环都包含了激活及绘制树节点,在激活节点时,会将它们调节为最近一次更新(的样子),然后在绘制每个节点时,会按照它们的“钉”对它们进行转换,再绘制它们的纹理。
渲染在它没有变化时仍然被保留了下来,且为暂停状态。
举例
- ```js
- // Create new app
- Stage(function(stage) {
- // Set view box
- stage.viewbox(300, 200);
- // Create an image and append it to stage
- var box = Stage.image('box').appendTo(stage);
- // Align box to center
- box.pin('align', 0.5);
- // On mouse click...
- box.on('click', function(point) {
- // ...tween scale values of this node
- this.tween().ease('bounce').pin({
- scaleX : Math.random() + 0.5,
- scaleY : Math.random() + 0.5
- });
- });
- });
- // Adding a texture
- Stage({
- image : 'sample.png',
- textures : {
- box : { x : 0, y : 0, width : 30, height : 30 }
- }
- });
- ```
安装
下载
项目发布页面中提供了最新版本。
使用NPM安装
- ```
- npm install stage-js --save
- ```
使用Bower安装
- ```
- bower install stage-js --save
- ```
用法
在浏览器端使用
在你的应用程序之前,将适合的构建文件,从dist目录中包含到你的HTML页面上,例如:
- ```html
- <script src="path/to/stage.web.min.js"></script>
- <script src="path/to/your-app.js"></script>
- ```
Browserify, CommonJS, Node.js
通常,最好在HTML页面中直接包含浏览器构建文件,但也可以使用CommonJS require,例如:
- ```js
- var Stage = require('stage-js/platform/web');
- ```
有关其他可用模块,请参阅平台目录。
资源
Stage.js 介绍 by Baljeet Rathi, SitePoint
中文手册 by Villor 紫刃
接口文档
应用程序
应用程序就是通过Stage()的回调函数来创建的,库会先调用,创建并初始化所有包含的组件,并会在应用程序根节点上调用所提供的(回调)函数,然后将容器显示出来(通常为一个Canvas元素)。
- ```javascript
- // Create and start an application
- Stage(function(stage, display) {
- // Set viewbox for stage, see pinning for valid modes
- stage.viewbox(width, height, mode = 'in-pad');
- // Listen to view port resize events
- stage.on('viewport', function(viewport) {
- // `viewport` attributes are `width`, `height` and `ratio`
- });
- // Pause playing
- stage.pause();
- // Resume playing
- stage.resume();
- });
- ```
Tree Model 树模型
每个应用都包含了一个树,树的根节点(由程序)作为阶段提供。
- ```javascript
- // Create a new node instance (with no textures)
- var node = Stage.create();
- // Append/prepend child to parent's children (accepts array)
- parent.append(child);
- parent.prepend(child);
- // Append/prepend child to parent's children
- child.appendTo(parent);
- child.prependTo(parent);
- // Insert sibling after/before child (accepts array)
- child.insertNext(sibling);
- child.insertPrev(sibling);
- // Insert sibling after/before child
- sibling.insertAfter(child);
- sibling.insertBefore(child);
- // Remove child from its parent
- child.remove();
- // Remove child from parent (accepts array)
- parent.remove(child);
- // Remove all of parent's children
- parent.empty();
- // Get parent's first/last (visible) child
- parent.first(onlyVisible = false);
- parent.last(onlyVisible = false);
- // Get immediate parent
- child.parent();
- // Get child's next/prev (visible) sibling
- child.next(onlyVisible = false);
- child.prev(onlyVisible = false);
- // Get node's visiblity
- node.visible();
- // Set node's visiblity
- node.visible(visible);
- node.hide();
- node.show();
- // Iterate over parent's children, child can not be removed
- for (var child = parent.first(); child; child = child.next()) {
- // use child
- }
- // Iterate over parent's children, child can be removed
- var child, next = parent.first();
- while (child = next) {
- next = child.next();
- // use child
- }
- // Visit node's sub-tree including node itself
- node.visit({
- start : function(node) {
- return skipChildren;
- },
- end : function(node) {
- return stopVisit;
- },
- reverse : reverseChildrenOrder = false,
- visible : onlyVisibleNodes = false
- });
- ```
Game Loop 游戏循环
每次渲染循环都包含了激活及重绘应用程序树。应用程序及它的节点都可以在激活时被更新,根据应用程序的活动性,下边有三种在激活后不同方式的后续行为:
如果至少有一个节点被触及,那个整个应用程序树都被重绘,且游戏循环会继续。
如果没有节点被触及,但至少有一个激活函数返回了true那么游戏循环会继续,但会保持之前的绘制状态。
如果没有节点被触及,也没有任何一个激活函数返回true那么应用程序会暂停,直到它被直接或间接地触及。
节点可以被直接触及,使用node.touch()方法,但通常它们都是被其它动作间接触及的,比如说定位或树的操作。
Nodes can be touched directly by calling node.touch() but usually they are touched indirectly by other actions such as pinning or tree manipulation.
- ```javascript
- // Register a function to be called on ticking
- node.tick(function(millisecElapsed) {
- return continueGameLoop;
- }, beforeChildren = false);
- // Touch node
- node.touch();
- ```
Pinning 定位
定位指定了一个节点如何附加在它的父节点上,定位包含了尺寸、转换、定位及透明度。
- ```javascript
- // Get a pinning value
- node.pin(name);
- // Set a pinning value
- node.pin(name, value);
- // Set one or more pinning values
- node.pin({
- name : value,
- ...
- });
- ```
当nameX等于nameY时,就可以简短地使用name来代替它们。
尺寸
对于一些节点来说,比如说图像、字符串、行和列,尺寸的设置是自动进行的
- ```javascript
- node.pin({
- height : height,
- width : width
- });
- // Shortcut for setting size:
- node.size(width, height);
- node.width(width);
- node.height(height);
- // Shortcut for getting size:
- node.width();
- node.height();
- ```
转换
转换包含了缩放、错切及旋转。转换要应用在缩放和错切之后。
- ```javascript
- node.pin({
- scaleX : 1,
- scaleY : 1,
- skewX : 0,
- skewY : 0,
- rotation : 0
- });
- // Shortcut for setting transformation:
- node.scale(x, y = x);
- node.scale({ x : x, y : y });
- node.skew(x, y = x);
- node.skew({ x : x, y : y });
- node.rotate(angle);
- ```
定位
当定位时,自身上的控制点,以父节点上对齐点的位置(作为参照)进行偏移。控制点及对齐点定义为width宽或height高的比例,0代表左上,1代表右下(同CSS中的background-position的关键字left/top/bottom/right的意义)。如果没指定的话,控制点默认就是对齐点的值。
- ```javascript
- node.pin({
- alignX : 0,
- alignY : 0,
- handleX : 0,
- handleY : 0,
- offsetX : 0,
- offsetY : 0
- });
- // Shortcut methods for setting positioning:
- node.offset(x, y);
- node.offset({ x : x, y : y });
- ```
默认轴对齐包围盒(AABB盒)是要在转换后才使用定位的,但也可能会使用未转换的盒来设置枢纽定位。枢纽定位用未转换的宽高来定义,它被用作自身的缩放、错切及旋转的中心点。
- ```javascript
- node.pin({
- pivotX : 0,
- pivotY : 0
- });
- ```
透明度
透明度既可以应用在节点纹理及子树节点上,又可以只应用在节点纹理自己上。
- ```javascript
- node.pin({
- alpha : 1,
- textureAlpha : 1
- });
- // Shortcut methods for setting transparency:
- node.alpha(alpha);
- node.alpha(alpha, textureAlpha);
- ```
缩放至
缩放到新的宽高,如果设置了按比例缩放,可以使用的模式有:
- in: 最大化缩放,保持各边缘在scaleWidth和scaleHeight(下边都使用“指定的尺寸”)的里边
- in-pad: 比较像in模式,但均匀地将整个节点填充到指定的尺寸里边
- out: 最小化缩放,各边缘保持在指定的尺寸之外
- out-crop: 像out一样,但是会均匀地剪裁画面到指定的尺寸
- ```javascript
- node.pin({
- scaleMode : mode,
- scaleWidth : width,
- scaleHeight : height
- });
- // Shortcut method:
- node.scaleTo(width, height, mode);
- ```
事件
事件监听器可以用来在节点上注册及解注册(事件),监听器是在有事件发布在节点上时被调用的。有些事件可以被发布在多个节点上,但事件却不会传播(冒泡)。
- ```javascript
- // Register a listener to node
- // Event `name` can be one or an array of strings or spaced separated strings
- node.on(name, listener);
- // Unregister a listener from node.
- node.off(name, listener);
- // Get listeners registered to node
- // Returns an array or undefined
- node.listeners(name);
- // Call listeners with args
- // Returns number of listeners called
- node.publish(name, args);
- ```
鼠标和触摸
本地的鼠标及触摸事件可以被捕获、处理及发布到应用程序的节点上,节点接收局部坐标的鼠标事件,也就是鼠标相对于节点的左上角的指定的位置
- ```javascript
- // Add click listener to node
- node.on('click', function(point) {
- // point.x and point.y are relative to this node left and top
- // point.raw is original event
- });
- ```
创建语法单击事件并将其发布到节点,而不是本机单击事件。
除了标准事件类型之外,还支持语法mousecancel事件类型,该类型类似于touchcancel,但在mousedown后面没有mouseup时发布。
- ```javascript
- // Mouse events:
- Stage.Mouse.CLICK = 'click';
- Stage.Mouse.START = 'touchstart mousedown';
- Stage.Mouse.MOVE = 'touchmove mousemove';
- Stage.Mouse.END = 'touchend mouseup';
- Stage.Mouse.CANCEL = 'touchcancel mousecancel';
- ```
纹理
纹理是可绘制的对象,树节点会使用它,来在画布表面绘制图像。
纹理图集
纹理图集(精灵图)包含了命名为纹理的一个集合,在应用程序中,它通过名称来被引用。
图集通常使用静态图像文件来建立,图集中的图像引用是自动预调用的。
- ```javascript
- // Adding texture atlas
- Stage({
- name : 'mario', // optional
- image : {
- src : 'mario.png',
- ratio : 1, // optional, for high-res images
- }
- textures : {
- stand : { x : 0, y : 0, width : 40, height : 60 },
- walk : [
- { x : 40, y : 0, width : 40, height : 60 },
- { x : 80, y : 0, width : 40, height : 60 },
- { x : 120, y : 0, width : 40, height : 60 }
- ],
- number : {
- '0' : { x : 0, y : 60, width : 10, height : 14 },
- '1' : { x : 10, y : 60, width : 10, height : 14 },
- '2' : { x : 20, y : 60, width : 10, height : 14 },
- '3' : { x : 30, y : 60, width : 10, height : 14 },
- '4' : { x : 40, y : 60, width : 10, height : 14 },
- '5' : { x : 50, y : 60, width : 10, height : 14 },
- '6' : { x : 60, y : 60, width : 10, height : 14 },
- '7' : { x : 70, y : 60, width : 10, height : 14 },
- '8' : { x : 80, y : 60, width : 10, height : 14 },
- '9' : { x : 90, y : 60, width : 10, height : 14 }
- }
- }
- });
- Stage.image('mario:stand');
- Stage.anim('mario:walk').play();
- Stage.string('mario:number').value(100);
- ```
如果图像的src以./开头的话,它会被解释成相对于当前脚本URL的位置
图片
图片就是带有一种纹理的节点
- ```javascript
- // Create a new image instance
- var image = Stage.image(texture);
- // Change image texture
- image.image(texture);
- // Tile/Stretch image when pinning width and/or height
- // To define borders add top, bottom, left and right to texture
- image.tile();
- image.stretch();
- ```
动画
动画或anim对象是带有纹理数组的节点,纹理被用作帧。
- ```javascript
- // Create a new anim instance
- var anim = Stage.anim(textures, fps = 15);
- // Get or set animation frame-per-second
- anim.fps();
- anim.fps(fps);
- // Set animation frames, `textures` can be an array or a texture selector
- anim.frames(textures);
- // Go to n-th frame
- anim.gotoFrame(n);
- // Move n frames forward (or backward if n is negative)
- anim.moveFrame(n);
- // Get number of frames
- anim.length();
- // Start playing (from `frameName` if specified)
- anim.play(frameName = undefined);
- // Stop playing (and jump to `frameName` if specified)
- anim.stop(frameName = undefined);
- // Play `repeat * length` frames and then stop and call `callback`
- anim.repeat(repeat, callback = null);
- ```
字符串动画
字符串是一行图片,它使用字符串值中的每个字符(或数组值中的元素)来动态地选择帧。
- ```javascript
- // Create a new string instance with frames
- var string = Stage.string(frames);
- // Set frames, a string referencing a map in an atlas
- string.frames("digits");
- // Set frames, a map with textures as values and frame names as keys
- string.frames({
- '0' : zeroTexture,
- '1' : oneTexture,
- ...
- });
- // Set frames, a function which takes a char (or item) and returns a texture
- string.frames(function(char) {
- // create a texture for char
- return texture;
- });
- // Set value, it can be a string (or an array)
- // Characters (or items) are used to select frames and create a row of images
- string.value(value);
- // Get assigned value
- string.value();
- ```
行和列
行/列也是一种节点,用来组织它的子元素,呈现横向/纵向的序列。
- ```javascript
- // Create a new row/column
- var row = Stage.row(childrenAlignY = 0);
- var column = Stage.column(childrenAlignX = 0);
- // Make node a row/column
- node.row(childrenAlignY = 0);
- node.column(childrenAlignX = 0);
- // Add spacing between row/column cells
- node.spacing(space);
- ```
盒(试验中)
盒会重新调整尺寸以包裹它的子元素。它可以被用来平铺/拉伸图像,来创建一个变化尺寸的元素,比如说窗口或按钮。
- ```javascript
- // Create a new box
- var box = Stage.box();
- // Make node a box
- node = node.box();
- ```
补间动画
补间动画是应用在平滑转换的定位值上的。
- ```javascript
- // Create a tweening entry
- // When `append` is true new entry is appended to current entries otherwise replaces them
- var tween = node.tween(duration = 400, delay = 0, append = false);
- // Set pinning values and start tweening
- // Pinning shortcut methods, such as `.scale()`, can also be used
- tween.pin(pinning);
- // Set easing for tweening, it can be either a function or an identifier
- // defined as 'name[-mode][(params)]', for example 'quad' or 'poly-in-out(3)'
- // Names: linear, quad, cubic, quart, quint, poly(p), sin/sine,
- // exp, circle/circ, bounce, elastic(a, p), back(s)
- // Modes: in, out, in-out, out-in
- tween.ease(easing);
- // Set duration in milliseconds
- tween.duration(ms);
- // Set delay in milliseconds
- tween.delay(ms);
- // Callback when tweening is done
- tween.done(function() {
- // this === node
- });
- // Remove this node when tweening ends
- tween.remove();
- // Hide this node when tweening ends
- tween.hide();
- // Create and chain a new tweening to this entry
- var nextTween = tween.tween(duration = 400, delay = 0);
- ```
全局方法
- ```javascript
- // Create a new app
- Stage(function(stage, display) { });
- // Create and preload a texture atlas
- Stage({ });
- // A function to be called before starting any app
- // Can be used for preloading application assets
- Stage.preload(function(done) {
- // Call `done` when loaded or failed
- done(error);
- });
- // Preload and execute a JS file
- // URLs starting with `./` are resolved relative to current script URL
- Stage.preload(src);
- // Pause playing all applications
- Stage.pause();
- // Resume playing all applications
- Stage.resume();
- ```
发展
要尝试使用实时生成的示例,请运行以下命令并检查要在浏览器中打开的URL的输出:
- ```
- npm run dev
- ```
许可证
Copyright 2020 Ali Shakiba http://shakiba.me/stage.js
根据MIT许可证提供