StageJS

用于游戏开发的2D HTML5渲染和布局引擎

README

Stage

Stage.js是一个2D的HTML5 Javascript库,用于跨平台游戏开发,它量轻,快速,且开源。


介绍


Canvas是HTML游戏开发中的图形元素,但它只支持绘图接口,但它没有任何可以像DOM那样支持你应用程序操作的数据模型,你必须手动绘制你的应用程序,并且管理渲染循环才可以“玩”它。再有,鼠标事件也仅仅在整个的画布层级上可用,它们也需要被手动处理。

Stage.js提供了类似于DOM的树型数据模型,来操作你的应用程序,且在内部管理渲染循环及应用程序的绘制,它也处理且向目标树节点,发布鼠标及触摸事件。一个Stage.js应用包含了许多的树节点,每个节点都相对于它的父级节点定位(变型),且拥有0/1/或更多个图像纹理。

每次渲染循环都包含了激活及绘制树节点,在激活节点时,会将它们调节为最近一次更新(的样子),然后在绘制每个节点时,会按照它们的“钉”对它们进行转换,再绘制它们的纹理。

渲染在它没有变化时仍然被保留了下来,且为暂停状态。

举例


  1. ```js
  2. // Create new app
  3. Stage(function(stage) {

  4.   // Set view box
  5.   stage.viewbox(300, 200);

  6.   // Create an image and append it to stage
  7.   var box = Stage.image('box').appendTo(stage);

  8.   // Align box to center
  9.   box.pin('align', 0.5);

  10.   // On mouse click...
  11.   box.on('click', function(point) {
  12.     // ...tween scale values of this node
  13.     this.tween().ease('bounce').pin({
  14.       scaleX : Math.random() + 0.5,
  15.       scaleY : Math.random() + 0.5
  16.     });
  17.   });
  18. });

  19. // Adding a texture
  20. Stage({
  21.   image : 'sample.png',
  22.   textures : {
  23.     box : { x : 0, y : 0, width : 30, height : 30 }
  24.   }
  25. });
  26. ```


安装


下载

项目发布页面中提供了最新版本

使用NPM安装


  1. ```
  2. npm install stage-js --save
  3. ```

使用Bower安装


  1. ```
  2. bower install stage-js --save
  3. ```


用法


在浏览器端使用


在你的应用程序之前,将适合的构建文件,从dist目录中包含到你的HTML页面上,例如:


  1. ```html
  2. <script src="path/to/stage.web.min.js"></script>
  3. <script src="path/to/your-app.js"></script>
  4. ```

Browserify, CommonJS, Node.js


通常,最好在HTML页面中直接包含浏览器构建文件,但也可以使用CommonJS require,例如:
  1. ```js
  2. var Stage = require('stage-js/platform/web');
  3. ```

有关其他可用模块,请参阅平台目录。


资源


Stage.js 介绍  by Baljeet Rathi, SitePoint

中文手册  by Villor 紫刃


接口文档


应用程序

应用程序就是通过Stage()的回调函数来创建的,库会先调用,创建并初始化所有包含的组件,并会在应用程序根节点上调用所提供的(回调)函数,然后将容器显示出来(通常为一个Canvas元素)。

  1. ```javascript
  2. // Create and start an application
  3. Stage(function(stage, display) {

  4.   // Set viewbox for stage, see pinning for valid modes
  5.   stage.viewbox(width, height, mode = 'in-pad');

  6.   // Listen to view port resize events
  7.   stage.on('viewport', function(viewport) {
  8.     // `viewport` attributes are `width`, `height` and `ratio`
  9.   });

  10.   // Pause playing
  11.   stage.pause();

  12.   // Resume playing
  13.   stage.resume();
  14. });
  15. ```


Tree Model 树模型


每个应用都包含了一个树,树的根节点(由程序)作为阶段提供。


  1. ```javascript
  2. // Create a new node instance (with no textures)
  3. var node = Stage.create();

  4. // Append/prepend child to parent's children (accepts array)
  5. parent.append(child);
  6. parent.prepend(child);

  7. // Append/prepend child to parent's children
  8. child.appendTo(parent);
  9. child.prependTo(parent);

  10. // Insert sibling after/before child (accepts array)
  11. child.insertNext(sibling);
  12. child.insertPrev(sibling);

  13. // Insert sibling after/before child
  14. sibling.insertAfter(child);
  15. sibling.insertBefore(child);

  16. // Remove child from its parent
  17. child.remove();

  18. // Remove child from parent (accepts array)
  19. parent.remove(child);

  20. // Remove all of parent's children
  21. parent.empty();

  22. // Get parent's first/last (visible) child
  23. parent.first(onlyVisible = false);
  24. parent.last(onlyVisible = false);

  25. // Get immediate parent
  26. child.parent();

  27. // Get child's next/prev (visible) sibling
  28. child.next(onlyVisible = false);
  29. child.prev(onlyVisible = false);

  30. // Get node's visiblity
  31. node.visible();
  32. // Set node's visiblity
  33. node.visible(visible);
  34. node.hide();
  35. node.show();

  36. // Iterate over parent's children, child can not be removed
  37. for (var child = parent.first(); child; child = child.next()) {
  38.   // use child
  39. }

  40. // Iterate over parent's children, child can be removed
  41. var child, next = parent.first();
  42. while (child = next) {
  43.   next = child.next();
  44.   // use child
  45. }

  46. // Visit node's sub-tree including node itself
  47. node.visit({
  48.   start : function(node) {
  49.     return skipChildren;
  50.   },
  51.   end : function(node) {
  52.     return stopVisit;
  53.   },
  54.   reverse : reverseChildrenOrder = false,
  55.   visible : onlyVisibleNodes = false
  56. });
  57. ```


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.

  1. ```javascript
  2. // Register a function to be called on ticking
  3. node.tick(function(millisecElapsed) {
  4.   return continueGameLoop;
  5. }, beforeChildren = false);

  6. // Touch node
  7. node.touch();
  8. ```


Pinning 定位

定位指定了一个节点如何附加在它的父节点上,定位包含了尺寸、转换、定位及透明度。


  1. ```javascript
  2. // Get a pinning value
  3. node.pin(name);

  4. // Set a pinning value
  5. node.pin(name, value);

  6. // Set one or more pinning values
  7. node.pin({
  8.   name : value,
  9.   ...
  10. });
  11. ```

当nameX等于nameY时,就可以简短地使用name来代替它们。

尺寸

对于一些节点来说,比如说图像、字符串、行和列,尺寸的设置是自动进行的

  1. ```javascript
  2. node.pin({
  3.   height : height,
  4.   width : width
  5. });

  6. // Shortcut for setting size:
  7. node.size(width, height);
  8. node.width(width);
  9. node.height(height);

  10. // Shortcut for getting size:
  11. node.width();
  12. node.height();
  13. ```

转换

转换包含了缩放、错切及旋转。转换要应用在缩放和错切之后。

  1. ```javascript
  2. node.pin({
  3.   scaleX : 1,
  4.   scaleY : 1,
  5.   skewX : 0,
  6.   skewY : 0,
  7.   rotation : 0
  8. });

  9. // Shortcut for setting transformation:
  10. node.scale(x, y = x);
  11. node.scale({ x : x, y : y });
  12. node.skew(x, y = x);
  13. node.skew({ x : x, y : y });
  14. node.rotate(angle);
  15. ```

定位

当定位时,自身上的控制点,以父节点上对齐点的位置(作为参照)进行偏移。控制点及对齐点定义为width宽或height高的比例,0代表左上,1代表右下(同CSS中的background-position的关键字left/top/bottom/right的意义)。如果没指定的话,控制点默认就是对齐点的值。

  1. ```javascript
  2. node.pin({
  3.   alignX : 0,
  4.   alignY : 0,
  5.   handleX : 0,
  6.   handleY : 0,
  7.   offsetX : 0,
  8.   offsetY : 0
  9. });

  10. // Shortcut methods for setting positioning:
  11. node.offset(x, y);
  12. node.offset({ x : x, y : y });
  13. ```

默认轴对齐包围盒(AABB盒)是要在转换后才使用定位的,但也可能会使用未转换的盒来设置枢纽定位。枢纽定位用未转换的宽高来定义,它被用作自身的缩放、错切及旋转的中心点。


  1. ```javascript
  2. node.pin({
  3.   pivotX : 0,
  4.   pivotY : 0
  5. });
  6. ```

透明度

透明度既可以应用在节点纹理及子树节点上,又可以只应用在节点纹理自己上。

  1. ```javascript
  2. node.pin({
  3.   alpha : 1,
  4.   textureAlpha : 1
  5. });

  6. // Shortcut methods for setting transparency:
  7. node.alpha(alpha);
  8. node.alpha(alpha, textureAlpha);
  9. ```

缩放至

缩放到新的宽高,如果设置了按比例缩放,可以使用的模式有:
- in: 最大化缩放,保持各边缘在scaleWidthscaleHeight(下边都使用“指定的尺寸”)的里边
- in-pad: 比较像in模式,但均匀地将整个节点填充到指定的尺寸里边
- out: 最小化缩放,各边缘保持在指定的尺寸之外
- out-crop: 像out一样,但是会均匀地剪裁画面到指定的尺寸

  1. ```javascript
  2. node.pin({
  3.   scaleMode : mode,
  4.   scaleWidth : width,
  5.   scaleHeight : height
  6. });

  7. // Shortcut method:
  8. node.scaleTo(width, height, mode);
  9. ```


事件

事件监听器可以用来在节点上注册及解注册(事件),监听器是在有事件发布在节点上时被调用的。有些事件可以被发布在多个节点上,但事件却不会传播(冒泡)。

  1. ```javascript
  2. // Register a listener to node
  3. // Event `name` can be one or an array of strings or spaced separated strings
  4. node.on(name, listener);

  5. // Unregister a listener from node.
  6. node.off(name, listener);

  7. // Get listeners registered to node
  8. // Returns an array or undefined
  9. node.listeners(name);

  10. // Call listeners with args
  11. // Returns number of listeners called
  12. node.publish(name, args);
  13. ```


鼠标和触摸

本地的鼠标及触摸事件可以被捕获、处理及发布到应用程序的节点上,节点接收局部坐标的鼠标事件,也就是鼠标相对于节点的左上角的指定的位置

  1. ```javascript
  2. // Add click listener to node
  3. node.on('click', function(point) {
  4.   // point.x and point.y are relative to this node left and top
  5.   // point.raw is original event
  6. });
  7. ```

创建语法单击事件并将其发布到节点,而不是本机单击事件。

除了标准事件类型之外,还支持语法mousecancel事件类型,该类型类似于touchcancel,但在mousedown后面没有mouseup时发布。

  1. ```javascript
  2. // Mouse events:
  3. Stage.Mouse.CLICK = 'click';
  4. Stage.Mouse.START = 'touchstart mousedown';
  5. Stage.Mouse.MOVE = 'touchmove mousemove';
  6. Stage.Mouse.END = 'touchend mouseup';
  7. Stage.Mouse.CANCEL = 'touchcancel mousecancel';
  8. ```


纹理

纹理是可绘制的对象,树节点会使用它,来在画布表面绘制图像。


纹理图集


纹理图集(精灵图)包含了命名为纹理的一个集合,在应用程序中,它通过名称来被引用。

图集通常使用静态图像文件来建立,图集中的图像引用是自动预调用的。


  1. ```javascript
  2. // Adding texture atlas
  3. Stage({
  4.   name : 'mario', // optional
  5.   image : {
  6.     src : 'mario.png',
  7.     ratio : 1, // optional, for high-res images
  8.   }
  9.   textures : {
  10.     stand : { x : 0,   y : 0, width : 40, height : 60 },
  11.     walk : [
  12.       { x : 40,  y : 0, width : 40, height : 60 },
  13.       { x : 80,  y : 0, width : 40, height : 60 },
  14.       { x : 120, y : 0, width : 40, height : 60 }
  15.     ],
  16.     number : {
  17.       '0' : { x : 0,  y : 60, width : 10, height : 14 },
  18.       '1' : { x : 10, y : 60, width : 10, height : 14 },
  19.       '2' : { x : 20, y : 60, width : 10, height : 14 },
  20.       '3' : { x : 30, y : 60, width : 10, height : 14 },
  21.       '4' : { x : 40, y : 60, width : 10, height : 14 },
  22.       '5' : { x : 50, y : 60, width : 10, height : 14 },
  23.       '6' : { x : 60, y : 60, width : 10, height : 14 },
  24.       '7' : { x : 70, y : 60, width : 10, height : 14 },
  25.       '8' : { x : 80, y : 60, width : 10, height : 14 },
  26.       '9' : { x : 90, y : 60, width : 10, height : 14 }
  27.     }
  28.   }
  29. });

  30. Stage.image('mario:stand');

  31. Stage.anim('mario:walk').play();

  32. Stage.string('mario:number').value(100);
  33. ```

如果图像的src以./开头的话,它会被解释成相对于当前脚本URL的位置


图片

图片就是带有一种纹理的节点

  1. ```javascript
  2. // Create a new image instance
  3. var image = Stage.image(texture);

  4. // Change image texture
  5. image.image(texture);

  6. // Tile/Stretch image when pinning width and/or height
  7. // To define borders add top, bottom, left and right to texture
  8. image.tile();
  9. image.stretch();
  10. ```


动画

动画或anim对象是带有纹理数组的节点,纹理被用作帧。

  1. ```javascript
  2. // Create a new anim instance
  3. var anim = Stage.anim(textures, fps = 15);

  4. // Get or set animation frame-per-second
  5. anim.fps();
  6. anim.fps(fps);

  7. // Set animation frames, `textures` can be an array or a texture selector
  8. anim.frames(textures);

  9. // Go to n-th frame
  10. anim.gotoFrame(n);

  11. // Move n frames forward (or backward if n is negative)
  12. anim.moveFrame(n);

  13. // Get number of frames
  14. anim.length();

  15. // Start playing (from `frameName` if specified)
  16. anim.play(frameName = undefined);

  17. // Stop playing (and jump to `frameName` if specified)
  18. anim.stop(frameName = undefined);

  19. // Play `repeat * length` frames and then stop and call `callback`
  20. anim.repeat(repeat, callback = null);
  21. ```


字符串动画

字符串是一行图片,它使用字符串值中的每个字符(或数组值中的元素)来动态地选择帧。

  1. ```javascript
  2. // Create a new string instance with frames
  3. var string = Stage.string(frames);

  4. // Set frames, a string referencing a map in an atlas
  5. string.frames("digits");

  6. // Set frames, a map with textures as values and frame names as keys
  7. string.frames({
  8.   '0' : zeroTexture,
  9.   '1' : oneTexture,
  10.   ...
  11. });

  12. // Set frames, a function which takes a char (or item) and returns a texture
  13. string.frames(function(char) {
  14.   // create a texture for char
  15.   return texture;
  16. });

  17. // Set value, it can be a string (or an array)
  18. // Characters (or items) are used to select frames and create a row of images
  19. string.value(value);

  20. // Get assigned value
  21. string.value();
  22. ```


行和列

行/列也是一种节点,用来组织它的子元素,呈现横向/纵向的序列。

  1. ```javascript
  2. // Create a new row/column
  3. var row = Stage.row(childrenAlignY = 0);
  4. var column = Stage.column(childrenAlignX = 0);

  5. // Make node a row/column
  6. node.row(childrenAlignY = 0);
  7. node.column(childrenAlignX = 0);

  8. // Add spacing between row/column cells
  9. node.spacing(space);
  10. ```


盒(试验中)

盒会重新调整尺寸以包裹它的子元素。它可以被用来平铺/拉伸图像,来创建一个变化尺寸的元素,比如说窗口或按钮。


  1. ```javascript
  2. // Create a new box
  3. var box = Stage.box();

  4. // Make node a box
  5. node = node.box();
  6. ```


补间动画

补间动画是应用在平滑转换的定位值上的。

  1. ```javascript
  2. // Create a tweening entry
  3. // When `append` is true new entry is appended to current entries otherwise replaces them
  4. var tween = node.tween(duration = 400, delay = 0, append = false);

  5. // Set pinning values and start tweening
  6. // Pinning shortcut methods, such as `.scale()`, can also be used
  7. tween.pin(pinning);

  8. // Set easing for tweening, it can be either a function or an identifier
  9. // defined as 'name[-mode][(params)]', for example 'quad' or 'poly-in-out(3)'
  10. // Names: linear, quad, cubic, quart, quint, poly(p), sin/sine,
  11. //        exp, circle/circ, bounce, elastic(a, p), back(s)
  12. // Modes: in, out, in-out, out-in
  13. tween.ease(easing);

  14. // Set duration in milliseconds
  15. tween.duration(ms);

  16. // Set delay in milliseconds
  17. tween.delay(ms);

  18. // Callback when tweening is done
  19. tween.done(function() {
  20.   // this === node
  21. });

  22. // Remove this node when tweening ends
  23. tween.remove();

  24. // Hide this node when tweening ends
  25. tween.hide();

  26. // Create and chain a new tweening to this entry
  27. var nextTween = tween.tween(duration = 400, delay = 0);
  28. ```


全局方法

  1. ```javascript

  2. // Create a new app
  3. Stage(function(stage, display) { });

  4. // Create and preload a texture atlas
  5. Stage({ });

  6. // A function to be called before starting any app
  7. // Can be used for preloading application assets
  8. Stage.preload(function(done) {
  9.   // Call `done` when loaded or failed
  10.   done(error);
  11. });

  12. // Preload and execute a JS file
  13. // URLs starting with `./` are resolved relative to current script URL
  14. Stage.preload(src);

  15. // Pause playing all applications
  16. Stage.pause();

  17. // Resume playing all applications
  18. Stage.resume();
  19. ```


发展

要尝试使用实时生成的示例,请运行以下命令并检查要在浏览器中打开的URL的输出:
  1. ```
  2. npm run dev
  3. ```


许可证

Copyright 2020 Ali Shakiba http://shakiba.me/stage.js  
根据MIT许可证提供