Compare commits

..

111 Commits

Author SHA1 Message Date
yhh dccd4e21b6 base64辅助类 2020-07-17 15:40:28 +08:00
yhh c96e8b3a04 新增Time/String/Array/Keyboard/Random/Object/Texture辅助类 2020-07-17 14:34:42 +08:00
YHH e686ba64d7 Update README.md 2020-07-17 11:55:29 +08:00
yhh 14cb9cd257 贝塞尔曲线 2020-07-17 11:07:57 +08:00
yhh 13e7737cb9 防止删除一个空的函数发生未定义报错 2020-07-15 10:56:06 +08:00
yhh dd65c60921 Merge branch 'master' of https://github.com/esengine/egret-framework 2020-07-15 10:53:38 +08:00
yhh 7dffb4d94a #12 fix Emitter类移除监听时是否有错 2020-07-15 10:53:30 +08:00
YHH 476204a296 Update README.md 2020-07-13 17:13:53 +08:00
yhh 983c8fbc99 iupdatable无法判断接口 去除改为component支持 2020-07-13 12:48:42 +08:00
YHH c30e591f6e Update README.md 2020-07-13 10:56:25 +08:00
YHH d9a1b5578c Update README.md 2020-07-13 10:56:06 +08:00
YHH f0e04b6981 emitter 支持 context 2020-07-12 23:41:10 +08:00
YHH 14598f08c7 sceneChanged事件 2020-07-12 23:30:48 +08:00
YHH 032b293085 新增analysis用于分析游戏缺陷 2020-07-12 14:51:20 +08:00
YHH d9bb76c105 Merge branch 'master' of https://github.com/esengine/egret-framework
# Conflicts:
#	demo/libs/framework/framework.d.ts
#	demo/libs/framework/framework.min.js
#	demo/src/game/MainScene.ts
#	source/bin/framework.d.ts
#	source/bin/framework.min.js
2020-07-12 09:46:07 +08:00
YHH 20392c8ab6 Set theme jekyll-theme-slate 2020-07-10 12:19:47 +08:00
yhh 583e03d025 Merge branch 'develop' 2020-07-10 11:25:11 +08:00
yhh f6c2d81a83 新增IUpdatable接口 用于减少update所带来的的性能损耗 2020-07-10 11:24:42 +08:00
YHH e703ff4e6c Merge pull request #11 from esengine/develop
Develop
2020-07-09 16:37:13 +08:00
yhh 877fc4c9bf astar 注释 2020-07-09 16:36:42 +08:00
yhh a80bb4b6f3 绘制帮助类 2020-07-09 16:16:04 +08:00
YHH 9b9d210109 Merge pull request #10 from esengine/develop
新增 circleCollider与 polygonCollider
2020-07-09 15:13:58 +08:00
yhh 817b703d4f 新增 circleCollider与 polygonCollider 2020-07-09 15:11:30 +08:00
YHH 88a25453e6 Merge pull request #9 from esengine/develop
对boxcollider碰撞支持
2020-07-09 14:16:52 +08:00
yhh 6e3eb1189a 修复boxcollider碰撞问题 2020-07-09 14:16:10 +08:00
yhh aea50926a9 优化spriteRenderer渲染方法 2020-07-08 18:12:17 +08:00
yhh 299c1b8e7d 修复切换场景未移除问题 2020-07-08 15:15:15 +08:00
YHH 3f6ab79894 滚动精灵 2020-07-07 21:40:57 +08:00
yhh b14fee1685 box重载overlaps 2020-07-07 18:54:19 +08:00
yhh ace8fb685d box 重载 collidesWith 2020-07-07 12:18:51 +08:00
YHH 1870ee5e45 Merge pull request #8 from esengine/develop
Develop
2020-07-03 17:53:08 +08:00
yhh 8be65fa685 update reademe 2020-07-03 17:52:26 +08:00
yhh cf4e76b12d 新增tiledspriterenderer 2020-07-03 17:51:18 +08:00
YHH c156463f10 Merge pull request #7 from esengine/develop
新增动画 移除不相关的库
2020-07-03 16:48:34 +08:00
yhh e7796550c6 移除资源 2020-07-03 16:47:24 +08:00
yhh c3c9181400 新增动画 移除不相关的库 2020-07-03 16:45:52 +08:00
YHH 4f4d508685 Merge pull request #6 from esengine/develop
移除 transform
2020-07-01 16:56:45 +08:00
yhh f36a1cdb27 移除 transform 2020-07-01 16:55:10 +08:00
YHH 28941f2395 Merge pull request #4 from esengine/develop
新增被动系统与协调系统 完善matcher
2020-07-01 15:16:23 +08:00
YHH 7f02272304 Merge pull request #5 from esengine/restyled/develop
Restyle 新增被动系统与协调系统 完善matcher
2020-07-01 15:11:39 +08:00
Restyled.io 02d86e7b0a Restyled by prettier 2020-07-01 06:57:39 +00:00
Restyled.io 4c8b6add98 Restyled by clang-format 2020-07-01 06:57:33 +00:00
yhh 60d646c392 移除restylers 2020-07-01 14:57:09 +08:00
yhh 5e871bc501 新增被动系统与协调系统 完善matcher 2020-07-01 14:54:35 +08:00
yhh 549db2fcfe 新增restylers 2020-07-01 14:35:49 +08:00
yhh d9840d60ef 合并camera 2020-07-01 14:19:40 +08:00
yhh 124cf3f66c code quality 2020-06-30 23:44:52 +08:00
yhh cd78b8de59 Merge branch 'master' of https://github.com/esengine/egret-framework 2020-06-30 23:24:10 +08:00
yhh a3209de000 移除stale 2020-06-30 23:23:25 +08:00
YHH 2908be1705 Create SECURITY.md 2020-06-30 23:22:25 +08:00
YHH 009a01ebf4 Merge pull request #3 from esengine/imgbot
[ImgBot] Optimize images
2020-06-30 23:13:18 +08:00
yhh 3fdbf3bfef 新增stale 2020-06-30 23:10:48 +08:00
ImgBotApp c8ecf3cc69 [ImgBot] Optimize images
*Total -- 168.02kb -> 149.53kb (11.01%)

/demo/resource/assets/Panel/border.png -- 1.02kb -> 0.33kb (67.59%)
/demo/resource/assets/Slider/track.png -- 0.91kb -> 0.30kb (67.52%)
/demo/resource/assets/Panel/header.png -- 0.92kb -> 0.31kb (66.52%)
/demo/resource/assets/ItemRenderer/selected.png -- 0.92kb -> 0.31kb (66.52%)
/demo/resource/assets/ScrollBar/roundthumb.png -- 0.91kb -> 0.31kb (66.45%)
/demo/resource/assets/Slider/tracklight.png -- 0.91kb -> 0.31kb (66.45%)
/demo/resource/assets/CheckBox/checkbox_unselect.png -- 0.98kb -> 0.33kb (66.37%)
/demo/resource/assets/RadioButton/radiobutton_unselect.png -- 1.29kb -> 0.45kb (65.43%)
/demo/resource/assets/CheckBox/checkbox_select_disabled.png -- 1.22kb -> 0.43kb (64.91%)
/demo/resource/assets/ProgressBar/track_pb.png -- 0.95kb -> 0.34kb (64.02%)
/demo/resource/assets/ProgressBar/thumb_pb.png -- 0.95kb -> 0.35kb (63.01%)
/demo/resource/assets/ToggleSwitch/handle.png -- 1.13kb -> 0.43kb (61.49%)
/demo/resource/assets/RadioButton/radiobutton_select_up.png -- 1.42kb -> 0.56kb (60.95%)
/demo/resource/assets/Slider/thumb.png -- 1.23kb -> 0.49kb (60.1%)
/demo/resource/assets/ToggleSwitch/off.png -- 1.24kb -> 0.52kb (58.01%)
/demo/resource/assets/ToggleSwitch/on.png -- 1.25kb -> 0.52kb (57.96%)
/demo/resource/assets/CheckBox/checkbox_select_up.png -- 1.23kb -> 0.53kb (57.23%)
/demo/resource/assets/Button/button_up.png -- 1.00kb -> 0.43kb (57.02%)
/demo/resource/assets/CheckBox/checkbox_select_down.png -- 1.21kb -> 0.52kb (56.96%)
/demo/resource/assets/Button/button_down.png -- 1.02kb -> 0.45kb (56.45%)
/demo/resource/assets/RadioButton/radiobutton_select_down.png -- 1.65kb -> 0.79kb (51.81%)
/demo/resource/assets/RadioButton/radiobutton_select_disabled.png -- 1.65kb -> 0.79kb (51.81%)
/demo/resource/assets/egret_icon.png -- 6.62kb -> 4.20kb (36.61%)
/demo/resource/assets/bg.jpg -- 136.40kb -> 135.55kb (0.62%)

Signed-off-by: ImgBotApp <ImgBotHelp@gmail.com>
2020-06-30 15:08:49 +00:00
yhh 088891c5ca 新增poolcomponent 对象池组件 2020-06-30 22:22:52 +08:00
yhh 099aa749e1 async scenetransition 2020-06-30 21:42:51 +08:00
yhh db7aac2b90 修复场景切换未在临界点切换问题 2020-06-30 14:32:29 +08:00
yhh 366bcf8efc mvc 2020-06-30 11:36:29 +08:00
yhh a4f1ae351f ecs适配egret 2020-06-29 15:41:02 +08:00
YHH a63d8598d8 shader 2020-06-28 08:38:22 +08:00
yhh d7385654ef gaussianblur 特效 2020-06-23 17:36:39 +08:00
yhh 7399b9f5ca 修复transition层级问题 2020-06-23 16:18:14 +08:00
YHH 795bfab1aa 新增postProcessor用于处理屏幕特效 2020-06-23 09:10:40 +08:00
yhh fb5906afe0 新增windtransition 2020-06-22 19:37:10 +08:00
YHH e38cd0f3ca Merge pull request #2 from esengine/develop_scenetransition
新增sceneTransition 用于场景过渡
2020-06-22 15:28:45 +08:00
yhh 481112cfc2 完善渐隐场景转换 2020-06-22 15:27:58 +08:00
YHH 3d9730d956 新增sceneTransition 用于场景过渡 2020-06-21 10:27:15 +08:00
YHH 60646edd6b 新增input类 用于管理触摸点信息 2020-06-19 22:43:56 +08:00
yhh 9bd5a99c81 修复isvisibleFromCamera剔除错误 新增setcolor方法 2020-06-19 19:28:14 +08:00
yhh d22c5775c2 新增Sprite用于控制纹理 2020-06-19 18:16:42 +08:00
YHH 981e149ca5 新增跟随相机 2020-06-19 09:16:49 +08:00
YHH b83b1a5b21 修复stage的宽高错误 2020-06-19 08:32:35 +08:00
YHH 09e6ace142 更新相机强制刷新矩阵 2020-06-19 00:38:37 +08:00
YHH e83bb087ea 相机渲染 2020-06-18 23:22:54 +08:00
yhh feaac83ee7 新增renderer渲染器 用于控制场景如何渲染 2020-06-18 16:35:51 +08:00
yhh 915056203d 新增全局管理器 2020-06-18 12:14:06 +08:00
yhh 231276e39b 新增renderable组件render方法 去除mathhelper.minof/maxof 2020-06-18 10:49:32 +08:00
yhh 9c293979a4 v1.0.1 2020-06-18 10:07:08 +08:00
YHH bc995e36c2 修复 triggerlistener 发生碰撞后不断触发问题(仅第一次碰撞触发) 2020-06-18 09:06:59 +08:00
YHH 18279d16cd 修复 collsionTriggerHelper 遍历问题 2020-06-18 00:03:01 +08:00
YHH 59b2f150f3 新增Long库 移除原有Long.ts 2020-06-17 23:19:25 +08:00
YHH e6d6c4199f fix long 2020-06-17 22:40:49 +08:00
yhh ccf8c4e107 新增 Long 类型 2020-06-17 20:40:56 +08:00
yhh 9e6e5eccc8 新增numberdictionary的散列键 2020-06-16 20:22:22 +08:00
yhh 447ea4efe4 修复box因缺少初始化报错问题 2020-06-16 16:35:17 +08:00
yhh 7f5b78f340 新增gulp build 2020-06-16 13:27:06 +08:00
YHH 4ac8bafa87 Merge pull request #1 from esengine/develop-test-ci
Create node.js.yml
2020-06-16 13:19:06 +08:00
yhh 25ce4c9cf9 remove test 2020-06-16 13:16:58 +08:00
yhh 2b81a0b06b Merge branch 'master' into develop-test-ci 2020-06-16 13:14:37 +08:00
yhh e68f6bd1be packages 2020-06-16 13:13:55 +08:00
YHH 06c1aeb97a Create node.js.yml 2020-06-16 12:46:40 +08:00
yhh ced176706b 修复physics register失效问题 2020-06-16 11:59:40 +08:00
yhh 8b21edc65f 新增mover移动器组件 用于处理itriggerListener接口碰撞信息 2020-06-16 11:22:37 +08:00
YHH 75301f7776 完善 colliderTriggerHelper 用于更新碰撞信息 2020-06-16 09:10:09 +08:00
YHH dba43b9773 完善shapeCollision 支持多边形 2020-06-16 00:04:28 +08:00
yhh 5186bc0187 修复polygon数组错误 修复emit空注册报错 2020-06-15 20:08:21 +08:00
yhh c3120d791f 新增事件发送接收器 2020-06-15 12:16:23 +08:00
yhh 16892eb7af 移除物理引擎 移动到新库 2020-06-15 10:42:06 +08:00
YHH 7f8f1cf0d0 优化collision 2020-06-15 08:46:38 +08:00
yhh 246e9a9511 新增shapecollision 用于计算多边形碰撞 2020-06-12 20:24:51 +08:00
YHH da5a1a0c79 优化Flags 2020-06-12 08:56:10 +08:00
YHH 6fa56dd572 新增flag 帮助处理位掩码 2020-06-12 08:47:13 +08:00
yhh ad68f0e1a0 新增shape形状 2020-06-11 20:36:36 +08:00
yhh 53ded30e0b 优化圆和矩形碰撞检测 2020-06-11 10:06:29 +08:00
YHH 2eec9a82f9 新增box复合体 修复vector2运算问题 2020-06-11 00:03:26 +08:00
yhh 74cbb4c9fd 新增verletworld 2020-06-10 20:29:16 +08:00
yhh fa4c3c5d0b 新增相机bounds与可渲染组件bounds 并添加可渲染组件的剔除方法 2020-06-10 17:41:53 +08:00
yhh f62f449d99 新增renderableComponent 用于控制可渲染组件的基类 不要在transform当中直接更改目标属性 2020-06-10 16:25:39 +08:00
yhh 94818d5784 新增webgl帮助类 用于自定义绘图 2020-06-10 13:38:04 +08:00
yhh 5f7c13c8cd 新增breadthfirst与dijkstra寻路算法 2020-06-10 12:23:19 +08:00
YHH 538677575d 新增polygonmesh 2020-06-10 08:57:17 +08:00
YHH 1816b16924 readme 更新 2020-06-09 23:14:47 +08:00
161 changed files with 30134 additions and 3449 deletions
+34
View File
@@ -0,0 +1,34 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: windows-latest
strategy:
matrix:
node-version: [8.x]
defaults:
run:
shell: cmd
working-directory: ./source
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- name: Install Dependencies
run: npm install
- run: npm run build --if-present
- run: gulp build
+1
View File
@@ -1,2 +1,3 @@
/source/node_modules
/demo/bin-debug
/demo/bin-release
+15
View File
@@ -0,0 +1,15 @@
{
// 使用 IntelliSense 了解相关属性。
// 悬停以查看现有属性的描述。
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "pwa-chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}
+56 -6
View File
@@ -1,11 +1,61 @@
# egret-framework
用于egret 包含众多高性能方法以供使用
(正在施工中)
## 计划列表
- [ ] 包含一套适配egret的ecs框架
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/esengine/egret-framework.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/esengine/egret-framework/context:javascript)
- [ ] 高性能物理引擎
这是一套用于egret的游戏框架,里面包含ECS框架用于管理场景实体,一些常用2D碰撞检测及A*寻路。如果您还需要包含其他的AI系统可以查看作者其他库(行为树、简易FSM、实用AI)。
## 版本计划功能
- [x] 简易ECS框架
- [x] 组件列表
- [x] 碰撞组件
- [x] 移动组件
- [ ] 刚体组件
- [ ] 点光源/灯光组件
- [ ] 阴影组件
- [ ] 轨迹组件
- [ ] 滚动组件
- [ ] 网格弹簧组件
- [ ] 相机震动组件
- [ ] 霓虹灯组件
- [x] 跟随相机组件
- [x] 系统列表
- [x] 被动系统
- [x] 协调系统
- [x] A*寻路(AStar)
- [x] 常用碰撞检测
- [x] 数学库
- [x] 简易矩阵类
- [x] 简易2d 向量类
- [x] 掩码实用类
- [x] 贝塞尔曲线
- [x] 快速随机数类
- [x] BreadthFirst 寻路算法
- [x] Dijkstra 寻路算法
- [x] 事件处理器
## 关于egret用ecs框架(typescript/javascript
ecs 是功能强大的实体组件系统。typescript与其他语言不同,因此我对ecs的设计尽可能的支持typescript特性。虽然ecs拥有标准实体组件系统,但在细节上有很大不同。创建标准ecs通常处于原始速度、缓存位置和其他性能原因。使用typescript,我们没有struct,因为没有必要匹配标准实体组件系统的设计方式,因为我们对内存布局没有那种控制。
ecs更灵活,可以更好的集中、组织、排序和过滤游戏中的对象。ecs让您拥有轻量级实体和组件,这些组件可以由系统批量处理。
例如,您在制作一个射手,您可能会有几十到几百个子弹,这些作为轻量级实体由系统批量处理。
所以ecs在设计当中拥有四种重要类型:世界(Scene),过滤器(Matcher),系统(System)和实体(Entity)
## 世界(Scene
Scene是ecs包含系统和实体最外面的容器。
## 实体(Entity
实体只由系统处理。
## 组件(Component)
组件应该只包含数据而没有逻辑代码。对数据进行逻辑是系统的工作。
## 系统(System
ecs中的系统会不断的更新实体。系统使用过滤器选择某些实体,然后仅更新那些选择的实体。
## 作者其他库(egret
- [行为树/实用AI 系统](https://github.com/esengine/egret-BehaviourTree-ai)
> 尽可能的简单易用
+21
View File
@@ -0,0 +1,21 @@
# Security Policy
## Supported Versions
Use this section to tell people about which versions of your project are
currently being supported with security updates.
| Version | Supported |
| ------- | ------------------ |
| 5.1.x | :white_check_mark: |
| 5.0.x | :x: |
| 4.0.x | :white_check_mark: |
| < 4.0 | :x: |
## Reporting a Vulnerability
Use this section to tell people how to report a vulnerability.
Tell them where to go, how often they can expect to get an update on a
reported vulnerability, what to expect if the vulnerability is accepted or
declined, etc.
+1
View File
@@ -0,0 +1 @@
theme: jekyll-theme-slate
+10
View File
@@ -0,0 +1,10 @@
{
"version": "0.1.0",
"command": "egret",
"isShellCommand": true,
"showOutput": "silent",
"args": [
"build"
],
"problemMatcher": "$tsc"
}
+4
View File
@@ -27,6 +27,10 @@
{
"name": "framework",
"path": "./libs/framework"
},
{
"name": "long",
"path": "./libs/long"
}
]
}
+2 -2
View File
@@ -27,7 +27,7 @@
data-entry-class="Main"
data-orientation="auto"
data-scale-mode="fixedWidth"
data-frame-rate="30"
data-frame-rate="60"
data-content-width="640"
data-content-height="1136"
data-multi-fingered="2"
@@ -77,7 +77,7 @@
* "calculateCanvasScaleFactor": //a function return canvas scale factor
* }
**/
egret.runEgret({ renderMode: "webgl", audioType: 0, calculateCanvasScaleFactor:function(context) {
egret.runEgret({ renderMode: "canvas", audioType: 0, calculateCanvasScaleFactor:function(context) {
var backingStore = context.backingStorePixelRatio ||
context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
+1158 -137
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+1092
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1
View File
File diff suppressed because one or more lines are too long
+6 -2
View File
@@ -7,15 +7,19 @@
"libs/modules/game/game.js",
"libs/modules/tween/tween.js",
"libs/modules/promise/promise.js",
"libs/framework/framework.js"
"libs/framework/framework.js",
"libs/long/long.js"
],
"game": [
"bin-debug/game/CoreEmitterType.js",
"bin-debug/AssetAdapter.js",
"bin-debug/LoadingUI.js",
"bin-debug/Main.js",
"bin-debug/Platform.js",
"bin-debug/ThemeAdapter.js",
"bin-debug/LoadingUI.js",
"bin-debug/game/MainScene.js",
"bin-debug/game/PlayerController.js",
"bin-debug/game/SimplePooled.js",
"bin-debug/game/SpawnerComponent.js",
"bin-debug/game/SpawnerSystem.js"
]
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 456 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1019 B

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1002 B

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 938 B

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 938 B

After

Width:  |  Height:  |  Size: 314 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 970 B

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 813 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 502 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 303 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 933 B

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 444 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 136 KiB

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

+12 -2
View File
@@ -132,9 +132,19 @@
"name": "egret_icon_png"
},
{
"name": "description_json",
"url": "config/description.json",
"type": "json",
"url": "config/description.json"
"name": "description_json"
},
{
"url": "assets/isometric_grass_and_water.json",
"type": "json",
"name": "isometric_grass_and_water_json"
},
{
"url": "assets/isometric_grass_and_water.png",
"type": "image",
"name": "isometric_grass_and_water_png"
}
]
}
+14 -5
View File
@@ -29,6 +29,8 @@
class Main extends eui.UILayer {
public static emitter: Emitter<CoreEmitterType>;
public static manager: SceneManager;
protected createChildren(): void {
super.createChildren();
@@ -51,10 +53,16 @@ class Main extends eui.UILayer {
egret.registerImplementation("eui.IAssetAdapter", assetAdapter);
egret.registerImplementation("eui.IThemeAdapter", new ThemeAdapter());
Main.manager = new SceneManager(this.stage);
Main.emitter = new Emitter<CoreEmitterType>();
this.addEventListener(egret.Event.ENTER_FRAME, this.updateFrame, this);
this.runGame();
}
private updateFrame(evt: egret.Event){
Main.emitter.emit(CoreEmitterType.Update, evt);
}
private async runGame() {
await this.loadResource();
this.createGameScene();
@@ -91,9 +99,10 @@ class Main extends eui.UILayer {
* Create scene interface
*/
protected createGameScene(): void {
let scene = SceneManager.createScene("main", new MainScene(this)).setActive();
let player = scene.createEntity("player");
player.addComponent(new SpawnComponent(EnemyType.worm));
// console.log(player.transform.position);
SceneManager.scene = new MainScene();
// Main.emitter.addObserver(CoreEmitterType.Update, ()=>{
// console.log("update emitter");
// });
}
}
+3
View File
@@ -0,0 +1,3 @@
enum CoreEmitterType {
Update,
}
+85 -10
View File
@@ -1,20 +1,95 @@
class MainScene extends Scene {
constructor(displayContent: egret.DisplayObject){
super(displayContent);
constructor() {
super();
this.addEntityProcessor(new SpawnerSystem(new Matcher()));
// this.addEntityProcessor(new SpawnerSystem(new Matcher()));
this.astarTest();
this.dijkstraTest();
this.breadthfirstTest();
}
public astarTest(){
let graph = new AstarGridGraph(20, 20);
public async onStart() {
let sprite = new Sprite(RES.getRes("checkbox_select_disabled_png"));
let bg = this.createEntity("bg");
bg.addComponent(new SpriteRenderer()).setSprite(sprite).setColor(0xff0000);
bg.addComponent(new PlayerController());
bg.addComponent(new Mover());
bg.addComponent(new ScrollingSpriteRenderer(sprite));
bg.addComponent(new BoxCollider());
bg.position = new Vector2(Math.random() * 200, Math.random() * 200);
graph.weightedNodes.push(new Point(3, 3));
graph.weightedNodes.push(new Point(3, 4));
graph.weightedNodes.push(new Point(4, 3));
graph.weightedNodes.push(new Point(4, 4));
for (let i = 0; i < 20; i++) {
let sprite = new Sprite(RES.getRes("checkbox_select_disabled_png"));
let player2 = this.createEntity("player2");
player2.addComponent(new SpriteRenderer()).setSprite(sprite);
player2.position = new Vector2(Math.random() * 1000, Math.random() * 1000);
player2.addComponent(new BoxCollider());
}
let path = graph.search(new Point(3, 4), new Point(15, 17));
this.camera.follow(bg, CameraStyle.lockOn);
let pool = new ComponentPool<SimplePooled>(SimplePooled);
let c1 = pool.obtain();
let c2 = pool.obtain();
pool.free(c1);
let c1b = pool.obtain();
console.log(c1 != c2);
console.log(c1 == c1b);
let button = new eui.Button();
button.label = "切换场景";
this.addChild(button);
button.addEventListener(egret.TouchEvent.TOUCH_TAP, () => {
SceneManager.startSceneTransition(new FadeTransition(() => {
return new MainScene();
}));
}, this);
Main.emitter.addObserver(CoreEmitterType.Update, this.handleFuncTest, this);
}
/** 测试Emitter */
private handleFuncTest(){
Main.emitter.removeObserver(CoreEmitterType.Update, this.handleFuncTest);
}
public breadthfirstTest() {
let graph = new UnweightedGraph<string>();
graph.addEdgesForNode("a", ["b"]); // a->b
graph.addEdgesForNode("b", ["a", "c", "d"]); // b->a b->c b->d
graph.addEdgesForNode("c", ["a"]); // c->a
graph.addEdgesForNode("d", ["e", "a"]); // d->e d->a
graph.addEdgesForNode("e", ["b"]); // e->b
// 计算从c到e的路径
let path = BreadthFirstPathfinder.search(graph, "c", "e");
console.log(path);
}
public dijkstraTest() {
let graph = new WeightedGridGraph(20, 20);
graph.weightedNodes.push(new Vector2(3, 3));
graph.weightedNodes.push(new Vector2(3, 4));
graph.weightedNodes.push(new Vector2(4, 3));
graph.weightedNodes.push(new Vector2(4, 4));
let path = graph.search(new Vector2(3, 4), new Vector2(15, 17));
console.log(path);
}
public astarTest() {
let graph = new AstarGridGraph(30, 30);
// graph.weightedNodes.push(new Vector2(3, 3));
// graph.weightedNodes.push(new Vector2(3, 4));
// graph.weightedNodes.push(new Vector2(4, 3));
// graph.weightedNodes.push(new Vector2(4, 4));
let startTime = egret.getTimer();
let path = graph.search(new Vector2(1, 1), new Vector2(29, 29));
console.log(egret.getTimer() - startTime);
}
}
+56
View File
@@ -0,0 +1,56 @@
class PlayerController extends Component {
private down: boolean = false;
private touchPoint: Vector2 = Vector2.zero;
private mover: Mover;
private spriteRenderer: SpriteRenderer;
public onAddedToEntity(){
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, this.touchBegin, this);
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE, this.touchBegin, this);
this.entity.scene.stage.addEventListener(egret.TouchEvent.TOUCH_END, this.touchEnd, this);
}
private touchBegin(evt: egret.TouchEvent){
this.down = true;
this.touchPoint = new Vector2(evt.stageX, evt.stageY);
}
private touchEnd(evt: egret.TouchEvent){
this.down = false;
this.touchPoint = new Vector2(evt.stageX, evt.stageY);
}
public update(){
if (!this.mover)
this.mover = this.entity.getComponent<Mover>(Mover);
if (!this.spriteRenderer)
this.spriteRenderer = this.entity.getComponent<SpriteRenderer>(SpriteRenderer);
if (!this.mover)
return;
if (!SpriteRenderer)
return;
if (this.down){
let camera = SceneManager.scene.camera;
let moveLeft: number = 0;
let moveRight: number = 0;
let speed = 100;
let worldPos = Input.touchPosition;
if (worldPos.x < this.spriteRenderer.localPosition.x){
moveLeft = -1;
} else if(worldPos.x > this.spriteRenderer.localPosition.x){
moveLeft = 1;
}
if (worldPos.y < this.spriteRenderer.localPosition.y){
moveRight = -1;
} else if(worldPos.y > this.spriteRenderer.localPosition.y){
moveRight = 1;
}
this.mover.move(new Vector2(moveLeft * speed * Time.deltaTime, moveRight * speed * Time.deltaTime));
}
}
}
+5
View File
@@ -0,0 +1,5 @@
class SimplePooled extends PooledComponent {
public reset(){
}
}
+11 -1
View File
@@ -1,4 +1,4 @@
class SpawnComponent extends Component {
class SpawnComponent extends Component implements ITriggerListener {
public cooldown = -1;
public minInterval = 2;
public maxInterval = 60;
@@ -18,6 +18,16 @@ class SpawnComponent extends Component {
public update() {
// console.log("update");
}
public onTriggerEnter(other: Collider, local: Collider){
if (other == local)
console.log("repeat collider")
console.log("enter collider");
}
public onTriggerExit(other: Collider, local: Collider){
console.log("exit collider");
}
}
enum EnemyType {
+1 -1
View File
@@ -32,7 +32,7 @@ egret_native.egretStart = function () {
//The following is automatically modified, please do not modify
//----auto option start----
entryClassName: "Main",
frameRate: 30,
frameRate: 60,
scaleMode: "fixedWidth",
contentWidth: 640,
contentHeight: 1136,
+3
View File
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "./node_modules/typescript/lib"
}
+1127 -150
View File
File diff suppressed because it is too large Load Diff
+5174 -639
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -10967,13 +10967,13 @@ declare namespace egret {
const RUNTIME2 = "runtime2";
/**
* Running on Alipay
* @version Egret 5.2.23
* @version Egret 5.2.33
* @platform All
* @language en_US
*/
/**
*
* @version Egret 5.2.26
* @version Egret 5.2.33
* @platform All
* @language zh_CN
*/
+1092
View File
File diff suppressed because it is too large Load Diff
+1350
View File
File diff suppressed because it is too large Load Diff
+3823
View File
File diff suppressed because it is too large Load Diff
+1178 -1178
View File
File diff suppressed because it is too large Load Diff
+7 -5
View File
@@ -1,13 +1,14 @@
{
"name": "@esengine/egret-framework",
"version": "1.0.0",
"version": "1.0.1",
"description": "用于egret 包含众多高性能方法以供使用",
"main": "index.js",
"directories": {
"lib": "lib"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
"test": "mocha --recursive --reporter tap --growl",
"eslint": "eslint src --ext .ts"
},
"author": "yhh",
"license": "MIT",
@@ -18,6 +19,7 @@
"gulp": "^3.9.1",
"gulp-babel": "^8.0.0",
"gulp-concat": "^2.6.1",
"gulp-inject-string": "^1.1.2",
"gulp-minify": "^3.1.0",
"gulp-string-replace": "^1.1.2",
"gulp-typescript": "^3.1.6",
@@ -25,10 +27,10 @@
"tsify": "^3.0.1",
"typescript": "^2.2.2",
"vinyl-source-stream": "^1.1.0",
"watchify": "^3.9.0",
"gulp-inject-string": "^1.1.2"
"watchify": "^3.9.0"
},
"publishConfig": {
"registry": "https://npm.pkg.github.com/359807859@qq.com"
}
},
"dependencies": {}
}
@@ -3,6 +3,12 @@
* IAstarGraph和开始/
*/
class AStarPathfinder {
/**
* null
* @param graph
* @param start
* @param goal
*/
public static search<T>(graph: IAstarGraph<T>, start: T, goal: T){
let foundPath = false;
let cameFrom = new Map<T, T>();
@@ -60,6 +66,12 @@ class AStarPathfinder {
return null;
}
/**
* cameFrom字典重新构造路径
* @param cameFrom
* @param start
* @param goal
*/
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[]{
let path = [];
let current = goal;
@@ -2,22 +2,22 @@
* A*使
* walls添加到walls HashSetweightedNodes
*/
class AstarGridGraph implements IAstarGraph<Point> {
public dirs: Point[] = [
new Point(1, 0),
new Point(0, -1),
new Point(-1, 0),
new Point(0, 1)
class AstarGridGraph implements IAstarGraph<Vector2> {
public dirs: Vector2[] = [
new Vector2(1, 0),
new Vector2(0, -1),
new Vector2(-1, 0),
new Vector2(0, 1)
];
public walls: Point[] = [];
public weightedNodes: Point[] = [];
public walls: Vector2[] = [];
public weightedNodes: Vector2[] = [];
public defaultWeight: number = 1;
public weightedNodeWeight = 5;
private _width;
private _height;
private _neighbors: Point[] = new Array(4);
private _neighbors: Vector2[] = new Array(4);
constructor(width: number, height: number){
this._width = width;
@@ -28,27 +28,32 @@ class AstarGridGraph implements IAstarGraph<Point> {
*
* @param node
*/
public isNodeInBounds(node: Point): boolean {
public isNodeInBounds(node: Vector2): boolean {
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
}
/**
*
* walls是不可逾越的
* @param node
*/
public isNodePassable(node: Point): boolean {
return !this.walls.contains(node);
public isNodePassable(node: Vector2): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
public search(start: Point, goal: Point){
/**
* AStarPathfinder.search的快捷方式
* @param start
* @param goal
*/
public search(start: Vector2, goal: Vector2){
return AStarPathfinder.search(this, start, goal);
}
public getNeighbors(node: Point): Point[] {
public getNeighbors(node: Vector2): Vector2[] {
this._neighbors.length = 0;
this.dirs.forEach(dir => {
let next = new Point(node.x + dir.x, node.y + dir.y);
let next = new Vector2(node.x + dir.x, node.y + dir.y);
if (this.isNodeInBounds(next) && this.isNodePassable(next))
this._neighbors.push(next);
});
@@ -56,11 +61,11 @@ class AstarGridGraph implements IAstarGraph<Point> {
return this._neighbors;
}
public cost(from: Point, to: Point): number {
public cost(from: Vector2, to: Vector2): number {
return this.weightedNodes.find((p)=> JSON.stringify(p) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
}
public heuristic(node: Point, goal: Point) {
public heuristic(node: Vector2, goal: Vector2) {
return Math.abs(node.x - goal.x) + Math.abs(node.y - goal.y);
}
@@ -1,5 +1,22 @@
/**
* graph的接口AstarPathfinder.search方法
*/
interface IAstarGraph<T> {
/**
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
* @param node
*/
getNeighbors(node: T): Array<T>;
/**
* from到to的成本
* @param from
* @param to
*/
cost(from: T, to: T): number;
/**
* node到to的启发式WeightedGridGraph了解常用的Manhatten方法
* @param node
* @param goal
*/
heuristic(node: T, goal: T);
}
@@ -1,27 +1,74 @@
/**
* 使 O(1)
* 使5-10
* IPriorityQueue.contains()
*/
class PriorityQueue<T extends PriorityQueueNode> {
private _numNodes: number;
private _nodes: T[];
private _numNodesEverEnqueued;
/**
*
* @param maxNodes (undefined的行为)
*/
constructor(maxNodes: number) {
this._numNodes = 0;
this._nodes = new Array(maxNodes + 1);
this._numNodesEverEnqueued = 0;
}
/**
*
* O(n)
*/
public clear() {
this._nodes.splice(1, this._numNodes);
this._numNodes = 0;
}
/**
*
* O(1)
*/
public get count() {
return this._numNodes;
}
/**
* (Count == MaxSize)undefined的行为
* O(1)
*/
public get maxSize() {
return this._nodes.length - 1;
}
/**
* (O(1))
* O (1)
* @param node
*/
public contains(node: T): boolean {
if (!node){
console.error("node cannot be null");
return false;
}
if (node.queueIndex < 0 || node.queueIndex >= this._nodes.length){
console.error("node.QueueIndex has been corrupted. Did you change it manually? Or add this node to another queue?");
return false;
}
return (this._nodes[node.queueIndex] == node);
}
/**
*
* undefinedundefined
* O(log n)
* @param node
* @param priority
*/
public enqueue(node: T, priority: number) {
node.priority = priority;
this._numNodes++;
@@ -31,12 +78,21 @@ class PriorityQueue<T extends PriorityQueueNode> {
this.cascadeUp(this._nodes[this._numNodes]);
}
/**
* (;)undefined
* O(log n)
*/
public dequeue(): T {
let returnMe = this._nodes[1];
this.remove(returnMe);
return returnMe;
}
/**
* Contains()
* O(log n)
* @param node
*/
public remove(node: T) {
if (node.queueIndex == this._numNodes) {
this._nodes[this._numNodes] = null;
@@ -52,6 +108,9 @@ class PriorityQueue<T extends PriorityQueueNode> {
this.onNodeUpdated(formerLastNode);
}
/**
* /
*/
public isValidQueue(): boolean {
for (let i = 1; i < this._nodes.length; i++) {
if (this._nodes[i]) {
@@ -71,24 +130,29 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
private onNodeUpdated(node: T) {
// 将更新后的节点按适当的方式向上或向下冒泡
let parentIndex = Math.floor(node.queueIndex / 2);
let parentNode = this._nodes[parentIndex];
if (parentIndex > 0 && this.hasHigherPriority(node, parentNode)) {
this.cascadeUp(node);
} else {
// 注意,如果parentNode == node(即节点是根),则将调用CascadeDown。
this.cascadeDown(node);
}
}
private cascadeDown(node: T) {
// 又名Heapify-down
let newParent: T;
let finalQueueIndex = node.queueIndex;
while (true) {
newParent = node;
let childLeftIndex = 2 * finalQueueIndex;
// 检查左子节点的优先级是否高于当前节点
if (childLeftIndex > this._numNodes) {
// 这可以放在循环之外,但是我们必须检查newParent != node两次
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
@@ -99,6 +163,7 @@ class PriorityQueue<T extends PriorityQueueNode> {
newParent = childLeft;
}
// 检查右子节点的优先级是否高于当前节点或左子节点
let childRightIndex = childLeftIndex + 1;
if (childRightIndex <= this._numNodes) {
let childRight = this._nodes[childRightIndex];
@@ -107,13 +172,17 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
}
// 如果其中一个子节点具有更高(更小)的优先级,则交换并继续级联
if (newParent != node) {
// 将新的父节点移动到它的新索引
// 节点将被移动一次,这样做比调用Swap()少一个赋值操作。
this._nodes[finalQueueIndex] = newParent;
let temp = newParent.queueIndex;
newParent.queueIndex = finalQueueIndex;
finalQueueIndex = temp;
} else {
// 参见上面的笔记
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
@@ -121,13 +190,20 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
}
/**
*
* @param node
*/
private cascadeUp(node: T) {
// 又名Heapify-up
let parent = Math.floor(node.queueIndex / 2);
while (parent >= 1) {
let parentNode = this._nodes[parent];
if (this.hasHigherPriority(parentNode, node))
break;
// 节点具有较低的优先级值,因此将其向上移动到堆中
// 出于某种原因,使用Swap()比使用单独的操作更快,如CascadeDown()
this.swap(node, parentNode);
parent = Math.floor(node.queueIndex / 2);
@@ -135,14 +211,22 @@ class PriorityQueue<T extends PriorityQueueNode> {
}
private swap(node1: T, node2: T) {
// 交换节点
this._nodes[node1.queueIndex] = node2;
this._nodes[node2.queueIndex] = node1;
// 交换他们的indicies
let temp = node1.queueIndex;
node1.queueIndex = node2.queueIndex;
node2.queueIndex = temp;
}
/**
* higher的优先级高于lowertruefalse
* HasHigherPriority()()false
* @param higher
* @param lower
*/
private hasHigherPriority(higher: T, lower: T) {
return (higher.priority < lower.priority ||
(higher.priority == lower.priority && higher.insertionIndex < lower.insertionIndex));
@@ -0,0 +1,41 @@
/**
* IUnweightedGraph和开始/
*/
class BreadthFirstPathfinder {
public static search<T>(graph: IUnweightedGraph<T>, start: T, goal: T): T[]{
let foundPath = false;
let frontier = [];
frontier.unshift(start);
let cameFrom = new Map<T, T>();
cameFrom.set(start, start);
while (frontier.length > 0){
let current = frontier.shift();
if (JSON.stringify(current) == JSON.stringify(goal)){
foundPath = true;
break;
}
graph.getNeighbors(current).forEach(next => {
if (!this.hasKey(cameFrom, next)){
frontier.unshift(next);
cameFrom.set(next, current);
}
});
}
return foundPath ? AStarPathfinder.recontructPath(cameFrom, start, goal) : null;
}
private static hasKey<T>(map: Map<T, T>, compareKey: T){
let iterator = map.keys();
let r: IteratorResult<T>;
while (r = iterator.next() , !r.done) {
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
return true;
}
return false;
}
}
@@ -0,0 +1,7 @@
interface IUnweightedGraph<T>{
/**
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
* @param node
*/
getNeighbors(node: T): T[];
}
@@ -0,0 +1,16 @@
/**
*
*
*/
class UnweightedGraph<T> implements IUnweightedGraph<T> {
public edges: Map<T, T[]> = new Map<T, T[]>();
public addEdgesForNode(node: T, edges: T[]){
this.edges.set(node, edges);
return this;
}
public getNeighbors(node: T){
return this.edges.get(node);
}
}
@@ -0,0 +1,61 @@
///<reference path="../../../Math/Vector2.ts" />
/**
* BreadthFirstPathfinder
*/
class UnweightedGridGraph implements IUnweightedGraph<Vector2> {
private static readonly CARDINAL_DIRS: Vector2[] = [
new Vector2(1, 0),
new Vector2(0, -1),
new Vector2(-1, 0),
new Vector2(0, -1)
];
private static readonly COMPASS_DIRS = [
new Vector2(1, 0),
new Vector2(1, -1),
new Vector2(0, -1),
new Vector2(-1, -1),
new Vector2(-1, 0),
new Vector2(-1, 1),
new Vector2(0, 1),
new Vector2(1, 1),
];
public walls: Vector2[] = [];
private _width: number;
private _hegiht: number;
private _dirs: Vector2[];
private _neighbors: Vector2[] = new Array(4);
constructor(width: number, height: number, allowDiagonalSearch: boolean = false) {
this._width = width;
this._hegiht = height;
this._dirs = allowDiagonalSearch ? UnweightedGridGraph.COMPASS_DIRS : UnweightedGridGraph.CARDINAL_DIRS;
}
public isNodeInBounds(node: Vector2): boolean {
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._hegiht;
}
public isNodePassable(node: Vector2): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
public getNeighbors(node: Vector2) {
this._neighbors.length = 0;
this._dirs.forEach(dir => {
let next = new Vector2(node.x + dir.x, node.y + dir.y);
if (this.isNodeInBounds(next) && this.isNodePassable(next))
this._neighbors.push(next);
});
return this._neighbors;
}
public search(start: Vector2, goal: Vector2): Vector2[] {
return BreadthFirstPathfinder.search(this, start, goal);
}
}
@@ -0,0 +1,14 @@
interface IWeightedGraph<T>{
/**
*
* @param node
*/
getNeighbors(node: T): T[];
/**
*
* @param from
* @param to
*/
cost(from: T, to: T): number;
}
@@ -0,0 +1,67 @@
///<reference path="../../../Math/Vector2.ts" />
/**
*
*/
class WeightedGridGraph implements IWeightedGraph<Vector2> {
public static readonly CARDINAL_DIRS = [
new Vector2(1, 0),
new Vector2(0, -1),
new Vector2(-1, 0),
new Vector2(0, 1)
];
private static readonly COMPASS_DIRS = [
new Vector2(1, 0),
new Vector2(1, -1),
new Vector2(0, -1),
new Vector2(-1, -1),
new Vector2(-1, 0),
new Vector2(-1, 1),
new Vector2(0, 1),
new Vector2(1, 1),
];
public walls: Vector2[] = [];
public weightedNodes: Vector2[] = [];
public defaultWeight = 1;
public weightedNodeWeight = 5;
private _width: number;
private _height: number;
private _dirs: Vector2[];
private _neighbors: Vector2[] = new Array(4);
constructor(width: number, height: number, allowDiagonalSearch: boolean = false){
this._width = width;
this._height = height;
this._dirs = allowDiagonalSearch ? WeightedGridGraph.COMPASS_DIRS : WeightedGridGraph.CARDINAL_DIRS;
}
public isNodeInBounds(node: Vector2){
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
}
public isNodePassable(node: Vector2): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
public search(start: Vector2, goal: Vector2){
return WeightedPathfinder.search(this, start, goal);
}
public getNeighbors(node: Vector2): Vector2[]{
this._neighbors.length = 0;
this._dirs.forEach(dir => {
let next = new Vector2(node.x + dir.x, node.y + dir.y);
if (this.isNodeInBounds(next) && this.isNodePassable(next))
this._neighbors.push(next);
});
return this._neighbors;
}
public cost(from: Vector2, to: Vector2): number{
return this.weightedNodes.find(t => JSON.stringify(t) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
}
}
@@ -0,0 +1,83 @@
class WeightedNode<T> extends PriorityQueueNode {
public data: T;
constructor(data: T){
super();
this.data = data;
}
}
class WeightedPathfinder {
public static search<T>(graph: IWeightedGraph<T>, start: T, goal: T){
let foundPath = false;
let cameFrom = new Map<T, T>();
cameFrom.set(start, start);
let costSoFar = new Map<T, number>();
let frontier = new PriorityQueue<WeightedNode<T>>(1000);
frontier.enqueue(new WeightedNode<T>(start), 0);
costSoFar.set(start, 0);
while (frontier.count > 0){
let current = frontier.dequeue();
if (JSON.stringify(current.data) == JSON.stringify(goal)){
foundPath = true;
break;
}
graph.getNeighbors(current.data).forEach(next => {
let newCost = costSoFar.get(current.data) + graph.cost(current.data, next);
if (!this.hasKey(costSoFar, next) || newCost < costSoFar.get(next)){
costSoFar.set(next, newCost);
let priprity = newCost;
frontier.enqueue(new WeightedNode<T>(next), priprity);
cameFrom.set(next, current.data);
}
});
}
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
}
private static hasKey<T>(map: Map<T, number>, compareKey: T){
let iterator = map.keys();
let r: IteratorResult<T>;
while (r = iterator.next() , !r.done) {
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
return true;
}
return false;
}
private static getKey<T>(map: Map<T, T>, compareKey: T){
let iterator = map.keys();
let valueIterator = map.values();
let r: IteratorResult<T>;
let v: IteratorResult<T>;
while (r = iterator.next(), v = valueIterator.next(), !r.done) {
if (JSON.stringify(r.value) == JSON.stringify(compareKey))
return v.value;
}
return null;
}
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[]{
let path = [];
let current = goal;
path.push(goal);
while (current != start){
current = this.getKey(cameFrom, current);
path.push(current);
}
path.reverse();
return path;
}
}
+22
View File
@@ -0,0 +1,22 @@
class Debug {
private static _debugDrawItems: DebugDrawItem[] = [];
public static drawHollowRect(rectanle: Rectangle, color: number, duration = 0){
this._debugDrawItems.push(new DebugDrawItem(rectanle, color, duration));
}
public static render(){
if (this._debugDrawItems.length > 0){
let debugShape = new egret.Shape();
if (SceneManager.scene){
SceneManager.scene.addChild(debugShape);
}
for (let i = this._debugDrawItems.length - 1; i >= 0; i --){
let item = this._debugDrawItems[i];
if (item.draw(debugShape))
this._debugDrawItems.removeAt(i);
}
}
}
}
+4
View File
@@ -0,0 +1,4 @@
class DebugDefaults {
public static verletParticle = 0xDC345E;
public static verletConstraintEdge = 0x433E36;
}
+46
View File
@@ -0,0 +1,46 @@
enum DebugDrawType {
line,
hollowRectangle,
pixel,
text
}
class DebugDrawItem {
public rectangle: Rectangle;
public color: number;
public duration: number;
public drawType: DebugDrawType;
public text: string;
public start: Vector2;
public end: Vector2;
public x: number;
public y: number;
public size: number;
constructor(rectangle: Rectangle, color: number, duration: number){
this.rectangle = rectangle;
this.color = color;
this.duration = duration;
this.drawType = DebugDrawType.hollowRectangle;
}
public draw(shape: egret.Shape): boolean{
switch (this.drawType){
case DebugDrawType.line:
DrawUtils.drawLine(shape, this.start, this.end, this.color);
break;
case DebugDrawType.hollowRectangle:
DrawUtils.drawHollowRect(shape, this.rectangle, this.color);
break;
case DebugDrawType.pixel:
DrawUtils.drawPixel(shape, new Vector2(this.x, this.y), this.color, this.size);
break;
case DebugDrawType.text:
break;
}
this.duration -= Time.deltaTime;
return this.duration < 0;
}
}
+33 -13
View File
@@ -1,12 +1,10 @@
abstract class Component {
abstract class Component extends egret.DisplayObjectContainer {
public entity: Entity;
public displayRender: egret.DisplayObject;
private _enabled: boolean = true;
public updateInterval: number = 1;
public get transform(){
return this.entity.transform;
}
/** 允许用户为实体存入信息 */
public userData: any;
private _updateOrder = 0;
public get enabled(){
return this.entity ? this.entity.enabled && this._enabled : this._enabled;
@@ -16,6 +14,10 @@ abstract class Component {
this.setEnabled(value);
}
public get localPosition(){
return new Vector2(this.entity.x + this.x, this.entity.y + this.y);
}
public setEnabled(isEnabled: boolean){
if (this._enabled != isEnabled){
this._enabled = isEnabled;
@@ -30,7 +32,24 @@ abstract class Component {
return this;
}
public abstract initialize();
/** 更新此实体上组件的顺序 */
public get updateOrder(){
return this._updateOrder;
}
/** 更新此实体上组件的顺序 */
public set updateOrder(value: number){
this.setUpdateOrder(value);
}
public setUpdateOrder(updateOrder: number){
if (this._updateOrder != updateOrder){
this._updateOrder = updateOrder;
}
return this;
}
public initialize(){
}
public onAddedToEntity(){
@@ -48,19 +67,20 @@ abstract class Component {
}
public onEntityTransformChanged(comp: ComponentTransform){
public debugRender(){
}
public update(){
}
/** 绑定显示对象 */
public bind(displayRender: egret.DisplayObject){
this.displayRender = displayRender;
/**
*
* @param comp
*/
public onEntityTransformChanged(comp: TransformComponent){
return this;
}
/** 内部使用 运行时不应该调用 */
+137 -42
View File
@@ -1,13 +1,30 @@
///<reference path="../Component.ts"/>
class Camera extends Component {
private _zoom;
private _origin: Vector2;
private _transformMatrix: Matrix2D = Matrix2D.identity;
private _inverseTransformMatrix = Matrix2D.identity;
private _origin: Vector2 = Vector2.zero;
private _minimumZoom = 0.3;
private _maximumZoom = 3;
private _areMatrixesDirty = true;
private _position: Vector2 = Vector2.zero;
/**
* cameraWindow
*
*/
public followLerp = 0.1;
public deadzone: Rectangle = new Rectangle();
/** 锁定偏移量 默认中心 */
public focusOffset: Vector2 = new Vector2();
/** 是否地图锁定 如果锁定则需要设置mapSize属性 */
public mapLockEnabled: boolean = false;
/** 设置地图大小 默认从0 0左上角开始 只需要输入地图宽高 */
public mapSize: Vector2 = new Vector2();
/** 跟随的实体 设置后镜头将锁定目标为中心 */
public targetEntity: Entity;
private _worldSpaceDeadZone: Rectangle = new Rectangle();
private _desiredPositionDelta: Vector2 = new Vector2();
private _targetCollider: Collider;
/** 相机模式 */
public cameraStyle: CameraStyle = CameraStyle.lockOn;
public get zoom(){
if (this._zoom == 0)
@@ -46,22 +63,45 @@ class Camera extends Component {
public set origin(value: Vector2){
if (this._origin != value){
this._origin = value;
this._areMatrixesDirty = true;
}
}
public get transformMatrix(){
this.updateMatrixes();
public get position(){
return this._position;
}
return this._transformMatrix;
public set position(value: Vector2){
this._position = value;
}
public get x(){
return this._position.x;
}
public set x(value: number){
this._position.x = value;
}
public get y(){
return this._position.y;
}
public set y(value: number){
this._position.y = value;
}
constructor() {
super();
this.width = SceneManager.stage.stageWidth;
this.height = SceneManager.stage.stageHeight;
this.setZoom(0);
}
public onSceneSizeChanged(newWidth: number, newHeight: number){
let oldOrigin = this._origin;
this.origin = new Vector2(newWidth / 2, newHeight / 2);
this.entity.position = Vector2.add(this.entity.position, Vector2.subtract(this._origin, oldOrigin));
}
public setMinimumZoom(minZoom: number): Camera{
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
@@ -78,7 +118,7 @@ class Camera extends Component {
return this;
}
public setZoom(zoom: number){
public setZoom(zoom: number): Camera{
let newZoom = MathHelper.clamp(zoom, -1, 1);
if (newZoom == 0){
this._zoom = 1;
@@ -88,52 +128,107 @@ class Camera extends Component {
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
}
this._areMatrixesDirty = true;
SceneManager.scene.scaleX = this._zoom;
SceneManager.scene.scaleY = this._zoom;
return this;
}
public initialize() {
}
public update(){
SceneManager.getActiveScene().entities.buffer.forEach(entity => entity.components.buffer.forEach(component => {
if (component.displayRender){
let has = this.entity.scene.$children.indexOf(component.displayRender)
if (has == -1){
this.entity.scene.stage.addChild(component.displayRender);
}
}
}));
public setRotation(rotation: number): Camera {
SceneManager.scene.rotation = rotation;
return this;
}
public setPosition(position: Vector2){
this.entity.transform.setPosition(position);
this.entity.position = position;
return this;
}
public updateMatrixes(){
if (!this._areMatrixesDirty)
return;
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow){
this.targetEntity = targetEntity;
this.cameraStyle = cameraStyle;
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
let tempMat: Matrix2D;
this._transformMatrix = Matrix2D.createTranslation(-this.entity.transform.position.x, -this.entity.transform.position.y);
if (this._zoom != 1){
tempMat = Matrix2D.createScale(this._zoom, this._zoom);
this._transformMatrix = Matrix2D.multiply(this._transformMatrix, tempMat);
switch (this.cameraStyle){
case CameraStyle.cameraWindow:
let w = cameraBounds.width / 6;
let h = cameraBounds.height / 3;
this.deadzone = new Rectangle((cameraBounds.width - w) / 2, (cameraBounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(cameraBounds.width / 2, cameraBounds.height / 2, 10, 10);
break;
}
tempMat = Matrix2D.createTranslation(this._origin.x, this._origin.y, tempMat);
this._transformMatrix = Matrix2D.multiply(this._transformMatrix, tempMat);
this._inverseTransformMatrix = Matrix2D.invert(this._transformMatrix);
this._areMatrixesDirty = false;
}
public destory() {
public update(){
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
let halfScreen = Vector2.multiply(new Vector2(cameraBounds.width, cameraBounds.height), new Vector2(0.5));
this._worldSpaceDeadZone.x = this.position.x - halfScreen.x + this.deadzone.x + this.focusOffset.x;
this._worldSpaceDeadZone.y = this.position.y - halfScreen.y + this.deadzone.y + this.focusOffset.y;
this._worldSpaceDeadZone.width = this.deadzone.width;
this._worldSpaceDeadZone.height = this.deadzone.height;
if (this.targetEntity)
this.updateFollow();
this.position = Vector2.lerp(this.position, Vector2.add(this.position, this._desiredPositionDelta), this.followLerp);
this.entity.roundPosition();
if (this.mapLockEnabled){
this.position = this.clampToMapSize(this.position);
this.entity.roundPosition();
}
}
private clampToMapSize(position: Vector2){
let cameraBounds = new Rectangle(0, 0, SceneManager.stage.stageWidth, SceneManager.stage.stageHeight);
let halfScreen = Vector2.multiply(new Vector2(cameraBounds.width, cameraBounds.height), new Vector2(0.5));
let cameraMax = new Vector2(this.mapSize.x - halfScreen.x, this.mapSize.y - halfScreen.y);
return Vector2.clamp(position, halfScreen, cameraMax);
}
private updateFollow(){
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
if (this.cameraStyle == CameraStyle.lockOn){
let targetX = this.targetEntity.position.x;
let targetY = this.targetEntity.position.y;
if (this._worldSpaceDeadZone.x > targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
else if(this._worldSpaceDeadZone.x < targetX)
this._desiredPositionDelta.x = targetX - this._worldSpaceDeadZone.x;
if (this._worldSpaceDeadZone.y < targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
else if(this._worldSpaceDeadZone.y > targetY)
this._desiredPositionDelta.y = targetY - this._worldSpaceDeadZone.y;
} else {
if (!this._targetCollider){
this._targetCollider = this.targetEntity.getComponent<Collider>(Collider);
if (!this._targetCollider)
return;
}
let targetBounds = this.targetEntity.getComponent<Collider>(Collider).bounds;
if (!this._worldSpaceDeadZone.containsRect(targetBounds)){
if (this._worldSpaceDeadZone.left > targetBounds.left)
this._desiredPositionDelta.x = targetBounds.left - this._worldSpaceDeadZone.left;
else if(this._worldSpaceDeadZone.right < targetBounds.right)
this._desiredPositionDelta.x = targetBounds.right - this._worldSpaceDeadZone.right;
if (this._worldSpaceDeadZone.bottom < targetBounds.bottom)
this._desiredPositionDelta.y = targetBounds.bottom - this._worldSpaceDeadZone.bottom;
else if(this._worldSpaceDeadZone.top > targetBounds.top)
this._desiredPositionDelta.y = targetBounds.top - this._worldSpaceDeadZone.top;
}
}
}
}
enum CameraStyle {
lockOn,
cameraWindow,
}
@@ -0,0 +1,22 @@
class ComponentPool<T extends PooledComponent>{
private _cache: T[];
private _type: any;
constructor(typeClass: any){
this._type = typeClass;
this._cache = [];
}
public obtain(): T{
try {
return this._cache.length > 0 ? this._cache.shift() : new this._type();
} catch(err){
throw new Error(this._type + err);
}
}
public free(component: T){
component.reset();
this._cache.push(component);
}
}
+32
View File
@@ -0,0 +1,32 @@
///<reference path="./RenderableComponent.ts" />
class Mesh extends RenderableComponent {
private _mesh: egret.Mesh;
constructor(){
super();
this._mesh = new egret.Mesh();
}
public setTexture(texture: egret.Texture): Mesh{
this._mesh.texture = texture;
return this;
}
public onAddedToEntity(){
this.addChild(this._mesh);
}
public onRemovedFromEntity(){
this.removeChild(this._mesh);
}
public render(camera: Camera){
this.x = this.entity.position.x - camera.position.x + camera.origin.x;
this.y = this.entity.position.y - camera.position.y + camera.origin.y;
}
public reset() {
}
}
@@ -0,0 +1,74 @@
///<reference path="./Collider.ts" />
class BoxCollider extends Collider {
public get width(){
return (this.shape as Box).width;
}
public set width(value: number){
this.setWidth(value);
}
/**
* BoxCollider的宽度
* @param width
*/
public setWidth(width: number): BoxCollider{
this._colliderRequiresAutoSizing = false;
let box = this.shape as Box;
if (width != box.width){
// 更新框,改变边界,如果我们需要更新物理系统中的边界
box.updateBox(width, box.height);
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
}
return this;
}
public get height(){
return (this.shape as Box).height;
}
public set height(value: number){
this.setHeight(value);
}
/**
* BoxCollider的高度
* @param height
*/
public setHeight(height: number){
this._colliderRequiresAutoSizing = false;
let box = this.shape as Box;
if (height != box.height){
// 更新框,改变边界,如果我们需要更新物理系统中的边界
box.updateBox(box.width, height);
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
}
}
/**
* RenderableComponent在实体上
*/
constructor(){
super();
// 我们在这里插入一个1x1框作为占位符,直到碰撞器在下一阵被添加到实体并可以获得更精确的自动调整大小数据
this.shape = new Box(1, 1);
this._colliderRequiresAutoSizing = true;
}
public setSize(width: number, height: number){
this._colliderRequiresAutoSizing = false;
let box = this.shape as Box;
if (width != box.width || height != box.height){
// 更新框,改变边界,如果我们需要更新物理系统中的边界
box.updateBox(width, height);
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
}
return this;
}
}
@@ -0,0 +1,41 @@
class CircleCollider extends Collider {
public get radius(): number{
return (this.shape as Circle).radius;
}
public set radius(value: number){
this.setRadius(value);
}
/**
*
*
* @param radius
*/
constructor(radius?: number){
super();
if (radius)
this._colliderRequiresAutoSizing = true;
// 我们在这里插入一个1px的圆圈作为占位符
// 直到碰撞器被添加到实体并可以获得更精确的自动调整大小数据的下一帧
this.shape = new Circle(radius ? radius : 1);
}
/**
*
* @param radius
*/
public setRadius(radius: number): CircleCollider{
this._colliderRequiresAutoSizing = false;
let circle = this.shape as Circle;
if (radius != circle.radius){
circle.radius = radius;
circle._originalRadius = radius;
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
}
return this;
}
}
@@ -0,0 +1,161 @@
abstract class Collider extends Component {
/** 对撞机的基本形状 */
public shape: Shape;
/** 在处理冲突时,physicsLayer可以用作过滤器。Flags类有帮助位掩码的方法。 */
public physicsLayer = 1 << 0;
/** 如果这个碰撞器是一个触发器,它将不会引起碰撞,但它仍然会触发事件 */
public isTrigger: boolean;
/**
*
* 使
*/
public registeredPhysicsBounds: Rectangle = new Rectangle();
/** 如果为true,碰撞器将根据附加的变换缩放和旋转 */
public shouldColliderScaleAndRotateWithTransform = true;
/** 默认为所有层。 */
public collidesWithLayers = Physics.allLayers;
public _localOffsetLength: number;
/** 标记来跟踪我们的实体是否被添加到场景中 */
protected _isParentEntityAddedToScene;
protected _colliderRequiresAutoSizing;
protected _localOffset: Vector2 = new Vector2(0, 0);
/** 标记来记录我们是否注册了物理系统 */
protected _isColliderRegistered;
public get bounds(): Rectangle {
this.shape.recalculateBounds(this);
return this.shape.bounds;
}
public get localOffset() {
return this._localOffset;
}
/**
* localOffset添加到实体
*/
public set localOffset(value: Vector2) {
this.setLocalOffset(value);
}
public setLocalOffset(offset: Vector2) {
if (this._localOffset != offset) {
this.unregisterColliderWithPhysicsSystem();
this._localOffset = offset;
this._localOffsetLength = this._localOffset.length();
this.registerColliderWithPhysicsSystem();
}
}
/**
* ()
*/
public registerColliderWithPhysicsSystem() {
// 如果在将我们添加到实体之前更改了origin等属性,则实体可以为null
if (this._isParentEntityAddedToScene && !this._isColliderRegistered) {
Physics.addCollider(this);
this._isColliderRegistered = true;
}
}
/**
* ()
*/
public unregisterColliderWithPhysicsSystem() {
if (this._isParentEntityAddedToScene && this._isColliderRegistered) {
Physics.removeCollider(this);
}
this._isColliderRegistered = false;
}
/**
*
* @param other
*/
public overlaps(other: Collider) {
return this.shape.overlaps(other.shape);
}
/**
* ()true
* @param collider
* @param motion
*/
public collidesWith(collider: Collider, motion: Vector2) {
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
let oldPosition = this.shape.position;
this.shape.position = Vector2.add(this.shape.position, motion);
let result = this.shape.collidesWithShape(collider.shape);
if (result)
result.collider = collider;
// 将图形位置返回到检查前的位置
this.shape.position = oldPosition;
return result;
}
public onAddedToEntity() {
if (this._colliderRequiresAutoSizing) {
if (!(this instanceof BoxCollider || this instanceof CircleCollider)) {
console.error("Only box and circle colliders can be created automatically");
}
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable) {
let bounds = renderable.bounds;
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
let width = bounds.width / this.entity.scale.x;
let height = bounds.height / this.entity.scale.y;
// 圆碰撞器需要特别注意原点
if (this instanceof CircleCollider){
let circleCollider = this as CircleCollider;
circleCollider.radius = Math.max(width, height) * 0.5;
this.localOffset = bounds.location;
} else {
let boxCollider = this;
boxCollider.width = width;
boxCollider.height = height;
this.localOffset = bounds.location;
}
} else {
console.warn("Collider has no shape and no RenderableComponent. Can't figure out how to size it.");
}
}
this._isParentEntityAddedToScene = true;
this.registerColliderWithPhysicsSystem();
}
public onRemovedFromEntity() {
this.unregisterColliderWithPhysicsSystem();
this._isParentEntityAddedToScene = false;
}
public onEnabled() {
this.registerColliderWithPhysicsSystem();
}
public onDisabled() {
this.unregisterColliderWithPhysicsSystem();
}
public onEntityTransformChanged(comp: TransformComponent) {
if (this._isColliderRegistered)
Physics.updateCollider(this);
}
public update(){
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable){
this.$setX(renderable.x + this.localOffset.x);
this.$setY(renderable.y + this.localOffset.y);
}
}
}
@@ -0,0 +1,24 @@
/**
*
*/
class PolygonCollider extends Collider {
/**
* localOffset的差异为居中
* @param points
*/
constructor(points: Vector2[]){
super();
// 第一点和最后一点决不能相同。我们想要一个开放的多边形
let isPolygonClosed = points[0] == points[points.length - 1];
// 最后一个移除
if (isPolygonClosed)
points.splice(points.length - 1, 1);
let center = Polygon.findPolygonCenter(points);
this.setLocalOffset(center);
Polygon.recenterPolygonVerts(points);
this.shape = new Polygon(points);
}
}
@@ -0,0 +1,4 @@
interface ITriggerListener {
onTriggerEnter(other: Collider, local: Collider);
onTriggerExit(other: Collider, local: Collider);
}
@@ -0,0 +1,93 @@
/**
*
* ITriggerListener接口用于管理对移动过程中违反的任何触发器的回调
* move方法
*
* ITriggerListener
*/
class Mover extends Component {
private _triggerHelper: ColliderTriggerHelper;
public onAddedToEntity(){
this._triggerHelper = new ColliderTriggerHelper(this.entity);
}
/**
*
* @param motion
*/
public calculateMovement(motion: Vector2){
let collisionResult = new CollisionResult();
if (!this.entity.getComponent(Collider) || !this._triggerHelper){
return null;
}
// 移动所有的非触发碰撞器并获得最近的碰撞
let colliders: Collider[] = this.entity.getComponents(Collider);
for (let i = 0; i < colliders.length; i ++){
let collider = colliders[i];
// 不检测触发器 在我们移动后会重新访问它
if (collider.isTrigger)
continue;
// 获取我们在新位置可能发生碰撞的任何东西
let bounds = collider.bounds;
bounds.x += motion.x;
bounds.y += motion.y;
let boxcastResult = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers);
bounds = boxcastResult.bounds;
let neighbors = boxcastResult.tempHashSet;
for (let j = 0; j < neighbors.length; j ++){
let neighbor = neighbors[j];
// 不检测触发器
if (neighbor.isTrigger)
continue;
let _internalcollisionResult = collider.collidesWith(neighbor, motion);
if (_internalcollisionResult){
// 如果碰撞 则退回之前的移动量
motion = Vector2.subtract(motion, _internalcollisionResult.minimumTranslationVector);
// 如果我们碰到多个对象,为了简单起见,只取第一个。
if (_internalcollisionResult.collider){
collisionResult = _internalcollisionResult;
}
}
}
}
ListPool.free(colliders);
return {collisionResult: collisionResult, motion: motion};
}
/**
* calculatemomovement应用到实体并更新triggerHelper
* @param motion
*/
public applyMovement(motion: Vector2){
// 移动实体到它的新位置,如果我们有一个碰撞,否则移动全部数量。当碰撞发生时,运动被更新
this.entity.position = Vector2.add(this.entity.position, motion);
// 对所有是触发器的碰撞器与所有宽相位碰撞器进行重叠检查。任何重叠都会导致触发事件。
if (this._triggerHelper)
this._triggerHelper.update();
}
/**
* calculateMovement和applyMovement来移动考虑碰撞的实体;
* @param motion
*/
public move(motion: Vector2){
let movementResult = this.calculateMovement(motion);
let collisionResult = movementResult.collisionResult;
motion = movementResult.motion;
this.applyMovement(motion);
return collisionResult;
}
}
@@ -0,0 +1,56 @@
/**
* itriggerlistener报告冲突的移动器
*
*/
class ProjectileMover extends Component {
private _tempTriggerList: ITriggerListener[] = [];
private _collider: Collider;
public onAddedToEntity(){
this._collider = this.entity.getComponent<Collider>(Collider);
if (!this._collider)
console.warn("ProjectileMover has no Collider. ProjectilMover requires a Collider!");
}
/**
*
* @param motion
*/
public move(motion: Vector2): boolean{
if (!this._collider)
return false;
let didCollide = false;
// 获取我们在新位置可能发生碰撞的任何东西
this.entity.position = Vector2.add(this.entity.position, motion);
// 获取任何可能在新位置发生碰撞的东西
let neighbors = Physics.boxcastBroadphase(this._collider.bounds, this._collider.collidesWithLayers);
for (let i = 0; i < neighbors.colliders.length; i ++){
let neighbor = neighbors.colliders[i];
if (this._collider.overlaps(neighbor)){
didCollide = true;
this.notifyTriggerListeners(this._collider, neighbor);
}
}
return didCollide;
}
private notifyTriggerListeners(self: Collider, other: Collider){
// 通知我们重叠的碰撞器实体上的任何侦听器
other.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){
this._tempTriggerList[i].onTriggerEnter(self, other);
}
this._tempTriggerList.length = 0;
// 通知此实体上的任何侦听器
this.entity.getComponents("ITriggerListener", this._tempTriggerList);
for (let i = 0; i < this._tempTriggerList.length; i ++){
this._tempTriggerList[i].onTriggerEnter(other, self);
}
this._tempTriggerList.length = 0;
}
}
@@ -0,0 +1,4 @@
/** 回收实例的组件类型。 */
abstract class PooledComponent extends Component {
public abstract reset();
}
@@ -0,0 +1,56 @@
///<reference path="./PooledComponent.ts" />
/**
*
*/
abstract class RenderableComponent extends PooledComponent implements IRenderable {
private _isVisible: boolean;
protected _areBoundsDirty = true;
protected _bounds: Rectangle = new Rectangle();
protected _localOffset: Vector2 = Vector2.zero;
public color: number = 0x000000;
public get width(){
return this.getWidth();
}
public get height(){
return this.getHeight();
}
public get isVisible(){
return this._isVisible;
}
public set isVisible(value: boolean){
this._isVisible = value;
if (this._isVisible)
this.onBecameVisible();
else
this.onBecameInvisible();
}
public get bounds(): Rectangle{
return new Rectangle(this.getBounds().x, this.getBounds().y, this.getBounds().width, this.getBounds().height);
}
protected getWidth(){
return this.bounds.width;
}
protected getHeight(){
return this.bounds.height;
}
protected onBecameVisible(){}
protected onBecameInvisible(){}
public abstract render(camera: Camera);
public isVisibleFromCamera(camera: Camera): boolean{
this.isVisible = camera.getBounds().intersects(this.getBounds());
return this.isVisible;
}
}
@@ -0,0 +1,37 @@
///<reference path="./TiledSpriteRenderer.ts"/>
class ScrollingSpriteRenderer extends TiledSpriteRenderer {
public scrollSpeedX = 15;
public scroolSpeedY = 0;
private _scrollX = 0;
private _scrollY = 0;
public update(){
this._scrollX += this.scrollSpeedX * Time.deltaTime;
this._scrollY += this.scroolSpeedY * Time.deltaTime;
this.sourceRect.x = this._scrollX;
this.sourceRect.y = this._scrollY;
}
public render(camera: Camera) {
if (!this.sprite)
return;
super.render(camera);
let renderTexture = new egret.RenderTexture();
let cacheBitmap = new egret.DisplayObjectContainer();
cacheBitmap.removeChildren();
cacheBitmap.addChild(this.leftTexture);
cacheBitmap.addChild(this.rightTexture);
this.leftTexture.x = this.sourceRect.x;
this.rightTexture.x = this.sourceRect.x - this.sourceRect.width;
this.leftTexture.y = this.sourceRect.y;
this.rightTexture.y = this.sourceRect.y;
cacheBitmap.cacheAsBitmap = true;
renderTexture.drawToTexture(cacheBitmap, new egret.Rectangle(0, 0, this.sourceRect.width, this.sourceRect.height));
this.bitmap.texture = renderTexture;
}
}
+24
View File
@@ -0,0 +1,24 @@
class Sprite {
public texture2D: egret.Texture;
public readonly sourceRect: Rectangle;
public readonly center: Vector2;
public origin: Vector2;
public readonly uvs: Rectangle = new Rectangle();
constructor(texture: egret.Texture,
sourceRect: Rectangle = new Rectangle(0, 0, texture.textureWidth, texture.textureHeight),
origin: Vector2 = sourceRect.getHalfSize()) {
this.texture2D = texture;
this.sourceRect = sourceRect;
this.center = new Vector2(sourceRect.width * 0.5, sourceRect.height * 0.5);
this.origin = origin;
let inverseTexW = 1 / texture.textureWidth;
let inverseTexH = 1 / texture.textureHeight
this.uvs.x = sourceRect.x * inverseTexW;
this.uvs.y = sourceRect.y * inverseTexH;
this.uvs.width = sourceRect.width * inverseTexW;
this.uvs.height = sourceRect.height * inverseTexH;
}
}
@@ -0,0 +1,9 @@
class SpriteAnimation {
public readonly sprites: Sprite[];
public readonly frameRate: number;
constructor(sprites: Sprite[], frameRate: number){
this.sprites = sprites;
this.frameRate = frameRate;
}
}
+142
View File
@@ -0,0 +1,142 @@
///<reference path="./SpriteRenderer.ts" />
class SpriteAnimator extends SpriteRenderer {
/** 在动画完成时触发,包括动画名称; */
public onAnimationCompletedEvent: Function;
/** 动画播放速度 */
public speed = 1;
/** 动画的当前状态 */
public animationState = State.none;
/** 当前动画 */
public currentAnimation: SpriteAnimation;
/** 当前动画的名称 */
public currentAnimationName: string;
/** 当前动画的精灵数组中当前帧的索引 */
public currentFrame: number;
/** 检查当前动画是否正在运行 */
public get isRunning(): boolean{
return this.animationState == State.running;
}
private _animations: Map<string, SpriteAnimation> = new Map<string, SpriteAnimation>();
private _elapsedTime: number = 0;
private _loopMode: LoopMode;
constructor(sprite?: Sprite){
super();
if (sprite) this.setSprite(sprite);
}
/**
* SpriteAnimation
* @param name
* @param animation
*/
public addAnimation(name: string, animation: SpriteAnimation): SpriteAnimator{
if (!this.sprite && animation.sprites.length > 0)
this.setSprite(animation.sprites[0]);
this._animations[name] = animation;
return this;
}
/**
*
* @param name
* @param loopMode
*/
public play(name: string, loopMode: LoopMode = null){
this.currentAnimation = this._animations[name];
this.currentAnimationName = name;
this.currentFrame = 0;
this.animationState = State.running;
this.sprite = this.currentAnimation.sprites[0];
this._elapsedTime = 0;
this._loopMode = loopMode ? loopMode : LoopMode.loop;
}
/**
* ())
* @param name
*/
public isAnimationActive(name: string): boolean{
return this.currentAnimation && this.currentAnimationName == name;
}
/**
*
*/
public pause(){
this.animationState = State.paused;
}
/**
*
*/
public unPause(){
this.animationState = State.running;
}
/**
* null
*/
public stop(){
this.currentAnimation = null;
this.currentAnimationName = null;
this.currentFrame = 0;
this.animationState = State.none;
}
public update(){
if (this.animationState != State.running || !this.currentAnimation) return;
let animation = this.currentAnimation;
let secondsPerFrame = 1 / (animation.frameRate * this.speed);
let iterationDuration = secondsPerFrame * animation.sprites.length;
this._elapsedTime += Time.deltaTime;
let time = Math.abs(this._elapsedTime);
if (this._loopMode == LoopMode.once && time > iterationDuration ||
this._loopMode == LoopMode.pingPongOnce && time > iterationDuration * 2){
this.animationState = State.completed;
this._elapsedTime = 0;
this.currentFrame = 0;
this.sprite = animation.sprites[this.currentFrame];
return;
}
// 弄清楚我们在哪个坐标系上
let i = Math.floor(time / secondsPerFrame);
let n = animation.sprites.length;
if (n > 2 && (this._loopMode == LoopMode.pingPong || this._loopMode == LoopMode.pingPongOnce)){
// pingpong
let maxIndex = n - 1;
this.currentFrame = maxIndex - Math.abs(maxIndex - i % (maxIndex * 2));
}else{
this.currentFrame = i % n;
}
this.sprite = animation.sprites[this.currentFrame];
}
}
enum LoopMode {
/** 在一个循环序列[A][B][C][A][B][C][A][B][C]... */
loop,
/** [A][B][C]然后暂停,设置时间为0 [A] */
once,
/** [A][B][C]。当它到达终点时,它会继续播放最后一帧,并且不会停止播放 */
clampForever,
/** 以一个乒乓循环的方式永远播放这个序列 [A][B][C][B][A][B][C][B]... */
pingPong,
/** 将顺序向前播放一次,然后返回到开始[A][B][C][B][A],然后暂停并设置时间为0 */
pingPongOnce,
}
enum State {
none,
running,
paused,
completed,
}
@@ -0,0 +1,62 @@
class SpriteRenderer extends RenderableComponent{
private _sprite: Sprite;
protected bitmap: egret.Bitmap;
/** 应该由这个精灵显示的精灵 */
public get sprite(): Sprite{
return this._sprite;
}
/** 应该由这个精灵显示的精灵 */
public set sprite(value: Sprite){
this.setSprite(value);
}
public setSprite(sprite: Sprite): SpriteRenderer{
this.removeChildren();
this._sprite = sprite;
if (this._sprite) {
this.anchorOffsetX = this._sprite.origin.x / this._sprite.sourceRect.width;
this.anchorOffsetY = this._sprite.origin.y / this._sprite.sourceRect.height;
}
this.bitmap = new egret.Bitmap(sprite.texture2D);
this.addChild(this.bitmap);
return this;
}
public setColor(color: number): SpriteRenderer{
let colorMatrix = [
1, 0, 0, 0, 0,
0, 1, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0
];
colorMatrix[0] = Math.floor(color / 256 / 256) / 255;
colorMatrix[6] = Math.floor(color / 256 % 256) / 255;
colorMatrix[12] = color % 256 / 255;
let colorFilter = new egret.ColorMatrixFilter(colorMatrix);
this.filters = [colorFilter];
return this;
}
public isVisibleFromCamera(camera: Camera): boolean{
this.isVisible = new Rectangle(0, 0, this.stage.stageWidth, this.stage.stageHeight).intersects(this.bounds);
this.visible = this.isVisible;
return this.isVisible;
}
/** 渲染处理 在每个模块中处理各自的渲染逻辑 */
public render(camera: Camera){
this.x = -camera.position.x + camera.origin.x;
this.y = -camera.position.y + camera.origin.y;
}
public onRemovedFromEntity(){
if (this.parent)
this.parent.removeChild(this);
}
public reset(){
}
}
@@ -0,0 +1,57 @@
///<reference path="./SpriteRenderer.ts" />
/**
*
*/
class TiledSpriteRenderer extends SpriteRenderer {
protected sourceRect: Rectangle;
protected leftTexture: egret.Bitmap;
protected rightTexture: egret.Bitmap;
public get scrollX() {
return this.sourceRect.x;
}
public set scrollX(value: number) {
this.sourceRect.x = value;
}
public get scrollY() {
return this.sourceRect.y;
}
public set scrollY(value: number) {
this.sourceRect.y = value;
}
constructor(sprite: Sprite) {
super();
this.leftTexture = new egret.Bitmap();
this.rightTexture = new egret.Bitmap();
this.leftTexture.texture = sprite.texture2D;
this.rightTexture.texture = sprite.texture2D;
this.setSprite(sprite);
this.sourceRect = sprite.sourceRect;
}
public render(camera: Camera) {
if (!this.sprite)
return;
super.render(camera);
let renderTexture = new egret.RenderTexture();
let cacheBitmap = new egret.DisplayObjectContainer();
cacheBitmap.removeChildren();
cacheBitmap.addChild(this.leftTexture);
cacheBitmap.addChild(this.rightTexture);
this.leftTexture.x = this.sourceRect.x;
this.rightTexture.x = this.sourceRect.x - this.sourceRect.width;
this.leftTexture.y = this.sourceRect.y;
this.rightTexture.y = this.sourceRect.y;
cacheBitmap.cacheAsBitmap = true;
renderTexture.drawToTexture(cacheBitmap, new egret.Rectangle(0, 0, this.sourceRect.width, this.sourceRect.height));
this.bitmap.texture = renderTexture;
}
}
+4
View File
@@ -0,0 +1,4 @@
enum CoreEvents{
/** 当场景发生变化时触发 */
SceneChanged,
}
+65 -91
View File
@@ -1,107 +1,50 @@
class Entity {
class Entity extends egret.DisplayObjectContainer {
private static _idGenerator: number;
public name: string;
public readonly id: number;
/** 当前实体所属的场景 */
public scene: Scene;
/** 封装实体的位置/旋转/缩放,并允许设置一个高层结构 */
public readonly transform: Transform;
/** 当前附加到此实体的所有组件的列表 */
public readonly components: ComponentList;
private _updateOrder: number = 0;
private _enabled: boolean = true;
private _isDestoryed: boolean;
public _isDestoryed: boolean;
private _tag: number = 0;
public componentBits: BitSet;
public get parent(){
return this.transform.parent;
}
public set parent(value: Transform){
this.transform.setParent(value);
public get isDestoryed(){
return this._isDestoryed;
}
public get position(){
return this.transform.position;
return new Vector2(this.x, this.y);
}
public set position(value: Vector2){
this.transform.setPosition(value);
}
public get localPosition(){
return this.transform.localPosition;
}
public set localPosition(value: Vector2){
this.transform.setLocalPosition(value);
}
public get rotation(){
return this.transform.rotation;
}
public set rotation(value: number){
this.transform.setRotation(value);
}
public get rotationDegrees(){
return this.transform.rotationDegrees;
}
public set rotationDegrees(value: number){
this.transform.setRotationDegrees(value);
}
public get localRotation(){
return this.transform.localRotation;
}
public set localRotation(value: number){
this.transform.setLocalRotation(value);
}
public get localRotationDegrees(){
return this.transform.localRotationDegrees;
}
public set localRotationDegrees(value: number){
this.transform.setLocalRotationDegrees(value);
this.$setX(value.x);
this.$setY(value.y);
this.onEntityTransformChanged(TransformComponent.position);
}
public get scale(){
return this.transform.scale;
return new Vector2(this.scaleX, this.scaleY);
}
public set scale(value: Vector2){
this.transform.setScale(value);
this.$setScaleX(value.x);
this.$setScaleY(value.y);
this.onEntityTransformChanged(TransformComponent.scale);
}
public get localScale(){
return this.transform.scale;
public set rotation(value: number){
this.$setRotation(value);
this.onEntityTransformChanged(TransformComponent.rotation);
}
public set localScale(value: Vector2){
this.transform.setScale(value);
}
public get worldInverseTransform(){
return this.transform.worldInverseTransform;
}
public get localToWorldTransform(){
return this.transform.localToWorldTransform;
}
public get worldToLocalTransform(){
return this.transform.worldToLocalTransform;
}
public get isDestoryed(){
return this._isDestoryed;
public get rotation(){
return this.$getRotation();
}
public get enabled(){
@@ -128,13 +71,25 @@ class Entity {
this.setTag(value);
}
public get stage(){
if (!this.scene)
return null;
return this.scene.stage;
}
constructor(name: string){
super();
this.name = name;
this.transform = new Transform(this);
this.components = new ComponentList(this);
this.id = Entity._idGenerator ++;
this.componentBits = new BitSet();
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
}
private onAddToStage(){
this.onEntityTransformChanged(TransformComponent.position);
}
public get updateOrder(){
@@ -145,6 +100,10 @@ class Entity {
this.setUpdateOrder(value);
}
public roundPosition(){
this.position = Vector2Ext.round(this.position);
}
public setUpdateOrder(updateOrder: number){
if (this._updateOrder != updateOrder){
this._updateOrder = updateOrder;
@@ -175,8 +134,8 @@ class Entity {
newScene.entities.add(this);
this.components.registerAllComponents();
for (let i = 0; i < this.transform.childCount; i ++){
this.transform.getChild(i).entity.attachToScene(newScene);
for (let i = 0; i < this.numChildren; i ++){
(this.getChildAt(i) as Component).entity.attachToScene(newScene);
}
}
@@ -184,13 +143,14 @@ class Entity {
this.scene.entities.remove(this);
this.components.deregisterAllComponents();
for (let i = 0; i < this.transform.childCount; i ++)
this.transform.getChild(i).entity.detachFromScene();
for (let i = 0; i < this.numChildren; i ++)
(this.getChildAt(i) as Component).entity.detachFromScene();
}
public addComponent<T extends Component>(component: T): T{
component.entity = this;
this.components.add(component);
this.addChild(component);
component.initialize();
return component;
}
@@ -212,6 +172,14 @@ class Entity {
return this.components.getComponent(type, false) as T;
}
public getComponents(typeName: string | any, componentList?){
return this.components.getComponents(typeName, componentList);
}
private onEntityTransformChanged(comp: TransformComponent){
this.components.onEntityTransformChanged(comp);
}
public removeComponentForType<T extends Component>(type){
let comp = this.getComponent<T>(type);
if (comp){
@@ -234,7 +202,6 @@ class Entity {
public update(){
this.components.update();
this.transform.updateTransform();
}
public onAddedToScene(){
@@ -243,21 +210,28 @@ class Entity {
public onRemovedFromScene(){
if (this._isDestoryed)
this.components.remove
this.components.removeAllComponents();
}
public onTransformChanged(comp: ComponentTransform){
this.components.onEntityTransformChanged(comp);
}
public destory(){
public destroy(){
this._isDestoryed = true;
this.scene.entities.remove(this);
this.transform.parent = null;
this.removeEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
for (let i = this.transform.childCount - 1; i >= 0; i --){
let child = this.transform.getChild(i);
child.entity.destory();
this.scene.entities.remove(this);
this.removeChildren();
if (this.parent)
this.parent.removeChild(this);
for (let i = this.numChildren - 1; i >= 0; i --){
let child = this.getChildAt(i);
(child as Component).entity.destroy();
}
}
}
enum TransformComponent {
rotation,
scale,
position
}
+131 -42
View File
@@ -1,49 +1,54 @@
/** 场景 */
class Scene extends egret.DisplayObjectContainer {
public camera: Camera;
public camera: Camera;
public readonly entities: EntityList;
public readonly renderableComponents: RenderableComponentList;
public readonly content: ContentManager;
public enablePostProcessing = true;
private _projectionMatrix: Matrix2D;
private _transformMatrix: Matrix2D;
private _matrixTransformMatrix: Matrix2D;
private _renderers: Renderer[] = [];
private _postProcessors: PostProcessor[] = [];
private _didSceneBegin;
public readonly entityProcessors: EntityProcessorList;
constructor(displayObject: egret.DisplayObject){
constructor() {
super();
displayObject.stage.addChild(this);
this._projectionMatrix = new Matrix2D(0, 0, 0, 0, 0, 0);
this.entityProcessors = new EntityProcessorList();
this.renderableComponents = new RenderableComponentList();
this.entities = new EntityList(this);
this.content = new ContentManager();
this.width = SceneManager.stage.stageWidth;
this.height = SceneManager.stage.stageHeight;
this.addEventListener(egret.Event.ACTIVATE, this.onActive, this);
this.addEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
this.addEventListener(egret.Event.ENTER_FRAME, this.update, this);
}
public createEntity(name: string){
public createEntity(name: string) {
let entity = new Entity(name);
entity.transform.position = new Vector2(0, 0);
entity.position = new Vector2(0, 0);
return this.addEntity(entity);
}
public addEntity(entity: Entity){
public addEntity(entity: Entity) {
this.entities.add(entity);
entity.scene = this;
this.addChild(entity);
for (let i = 0; i < entity.transform.childCount; i ++)
this.addEntity(entity.transform.getChild(i).entity);
for (let i = 0; i < entity.numChildren; i++)
this.addEntity((entity.getChildAt(i) as Component).entity);
return entity;
}
public destroyAllEntities(){
for (let i = 0; i < this.entities.count; i ++){
this.entities.buffer[i].destory();
public destroyAllEntities() {
for (let i = 0; i < this.entities.count; i++) {
this.entities.buffer[i].destroy();
}
}
public findEntity(name: string): Entity{
public findEntity(name: string): Entity {
return this.entities.findEntity(name);
}
@@ -51,13 +56,13 @@ class Scene extends egret.DisplayObjectContainer {
* EntitySystem处理器
* @param processor
*/
public addEntityProcessor(processor: EntitySystem){
public addEntityProcessor(processor: EntitySystem) {
processor.scene = this;
this.entityProcessors.add(processor);
return processor;
}
public removeEntityProcessor(processor: EntitySystem){
public removeEntityProcessor(processor: EntitySystem) {
this.entityProcessors.remove(processor);
}
@@ -65,34 +70,102 @@ class Scene extends egret.DisplayObjectContainer {
return this.entityProcessors.getProcessor<T>();
}
public setActive(): Scene{
SceneManager.setActiveScene(this);
public addRenderer<T extends Renderer>(renderer: T) {
this._renderers.push(renderer);
this._renderers.sort();
return this;
renderer.onAddedToScene(this);
return renderer;
}
/** 初始化场景 */
public initialize(){
public getRenderer<T extends Renderer>(type): T {
for (let i = 0; i < this._renderers.length; i++) {
if (this._renderers[i] instanceof type)
return this._renderers[i] as T;
}
return null;
}
public removeRenderer(renderer: Renderer) {
this._renderers.remove(renderer);
renderer.unload();
}
public begin() {
if (SceneManager.sceneTransition){
SceneManager.stage.addChildAt(this, SceneManager.stage.numChildren - 1);
}else{
SceneManager.stage.addChild(this);
}
if (this._renderers.length == 0) {
this.addRenderer(new DefaultRenderer());
console.warn("场景开始时没有渲染器 自动添加DefaultRenderer以保证能够正常渲染");
}
/** 初始化默认相机 */
this.camera = this.createEntity("camera").addComponent(new Camera());
this.camera = this.createEntity("camera").getOrCreateComponent(new Camera());
Physics.reset();
if (this.entityProcessors)
this.entityProcessors.begin();
this.camera.onSceneSizeChanged(this.stage.stageWidth, this.stage.stageHeight);
this._didSceneBegin = true;
this.onStart();
}
public end() {
this._didSceneBegin = false;
this.removeEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this);
for (let i = 0; i < this._renderers.length; i++) {
this._renderers[i].unload();
}
for (let i = 0; i < this._postProcessors.length; i++) {
this._postProcessors[i].unload();
}
this.entities.removeAllEntities();
this.removeChildren();
Physics.clear();
this.camera = null;
this.content.dispose();
if (this.entityProcessors)
this.entityProcessors.end();
this.unload();
if (this.parent)
this.parent.removeChild(this);
}
protected async onStart() {
}
/** 场景激活 */
public onActive(){
protected onActive() {
}
/** 场景失去焦点 */
public onDeactive(){
protected onDeactive() {
}
public update(){
Time.update(egret.getTimer());
protected unload() { }
public update() {
this.entities.updateLists();
if (this.entityProcessors)
@@ -102,23 +175,39 @@ class Scene extends egret.DisplayObjectContainer {
if (this.entityProcessors)
this.entityProcessors.lateUpdate();
this.renderableComponents.updateList();
}
public prepRenderState(){
this._projectionMatrix.m11 = 2 / this.stage.width;
this._projectionMatrix.m22 = -2 / this.stage.height;
public postRender() {
let enabledCounter = 0;
if (this.enablePostProcessing) {
for (let i = 0; i < this._postProcessors.length; i++) {
if (this._postProcessors[i].enable) {
let isEven = MathHelper.isEven(enabledCounter);
enabledCounter ++;
this._transformMatrix = this.camera.transformMatrix;
this._matrixTransformMatrix = Matrix2D.multiply(this._transformMatrix, this._projectionMatrix);
this._postProcessors[i].process();
}
}
}
}
public destory(){
this.removeEventListener(egret.Event.DEACTIVATE, this.onDeactive, this);
this.removeEventListener(egret.Event.ACTIVATE, this.onActive, this);
public render() {
for (let i = 0; i < this._renderers.length; i++) {
this._renderers[i].render(this);
}
}
this.camera.destory();
this.camera = null;
public addPostProcessor<T extends PostProcessor>(postProcessor: T): T{
this._postProcessors.push(postProcessor);
this._postProcessors.sort();
postProcessor.onAddedToScene(this);
this.entities.removeAllEntities();
if (this._didSceneBegin){
postProcessor.onSceneBackBufferSizeChanged(this.stage.stageWidth, this.stage.stageHeight);
}
return postProcessor;
}
}
+120 -29
View File
@@ -1,40 +1,131 @@
/** 运行时的场景管理。 */
class SceneManager {
private static _loadedScenes: Map<string, Scene> = new Map();
/** 上一个场景 */
private static _lastScene: Scene;
/** 当前激活的场景 */
private static _activeScene: Scene;
/**
* 使
*
*
* @param name
* @param scene
*/
public static createScene(name: string, scene: Scene){
scene.name = name;
this._loadedScenes.set(name, scene);
return scene;
private static _scene: Scene;
private static _nextScene: Scene;
public static sceneTransition: SceneTransition;
public static stage: egret.Stage;
/** 订阅此事件以在活动场景发生更改时得到通知。 */
public static activeSceneChanged: Function;
/** 核心发射器。只发出核心级别的事件 */
public static emitter: Emitter<CoreEvents>;
/** 全局内容管理器加载任何应该停留在场景之间的资产 */
public static content: ContentManager;
/** 简化对内部类的全局内容实例的访问 */
private static _instnace: SceneManager;
public static get Instance(){
return this._instnace;
}
public static setActiveScene(scene: Scene){
if (this._activeScene){
// 如果场景相同则不进行切换
if (this._activeScene == scene)
return;
constructor(stage: egret.Stage) {
stage.addEventListener(egret.Event.ENTER_FRAME, SceneManager.update, this);
this._lastScene = this._activeScene;
this._activeScene.destory();
SceneManager._instnace = this;
SceneManager.emitter = new Emitter<CoreEvents>();
SceneManager.content = new ContentManager();
SceneManager.stage = stage;
SceneManager.initialize(stage);
}
public static get scene() {
return this._scene;
}
public static set scene(value: Scene) {
if (!value)
throw new Error("场景不能为空");
if (this._scene == null) {
this._scene = value;
this._scene.begin();
SceneManager.Instance.onSceneChanged();
} else {
this._nextScene = value;
}
this._activeScene = scene;
this._activeScene.initialize();
return scene;
this.registerActiveSceneChanged(this._scene, this._nextScene);
}
public static getActiveScene(){
return this._activeScene;
public static initialize(stage: egret.Stage) {
Input.initialize(stage);
}
public static update() {
Time.update(egret.getTimer());
if (SceneManager._scene) {
for (let i = GlobalManager.globalManagers.length - 1; i >= 0; i--) {
if (GlobalManager.globalManagers[i].enabled)
GlobalManager.globalManagers[i].update();
}
if (!SceneManager.sceneTransition ||
(SceneManager.sceneTransition && (!SceneManager.sceneTransition.loadsNewScene || SceneManager.sceneTransition.isNewSceneLoaded))) {
SceneManager._scene.update();
}
if (SceneManager._nextScene) {
SceneManager._scene.end();
SceneManager._scene = SceneManager._nextScene;
SceneManager._nextScene = null;
SceneManager._instnace.onSceneChanged();
SceneManager._scene.begin();
}
}
SceneManager.render();
}
public static render() {
if (this.sceneTransition){
this.sceneTransition.preRender();
if (this._scene && !this.sceneTransition.hasPreviousSceneRender){
this._scene.render();
this._scene.postRender();
this.sceneTransition.onBeginTransition();
} else if (this.sceneTransition) {
if (this._scene && this.sceneTransition.isNewSceneLoaded) {
this._scene.render();
this._scene.postRender();
}
this.sceneTransition.render();
}
} else if (this._scene) {
this._scene.render();
Debug.render();
this._scene.postRender();
}
}
/**
* SceneTransition
* @param sceneTransition
*/
public static startSceneTransition<T extends SceneTransition>(sceneTransition: T): T {
if (this.sceneTransition) {
console.warn("在前一个场景完成之前,不能开始一个新的场景转换。");
return;
}
this.sceneTransition = sceneTransition;
return sceneTransition;
}
public static registerActiveSceneChanged(current: Scene, next: Scene){
if (this.activeSceneChanged)
this.activeSceneChanged(current, next);
}
/**
*
*/
public onSceneChanged(){
SceneManager.emitter.emit(CoreEvents.SceneChanged);
Time.sceneChanged();
}
}
@@ -7,12 +7,21 @@ abstract class EntityProcessingSystem extends EntitySystem {
super(matcher);
}
/**
*
* @param entity
*/
public abstract processEntity(entity: Entity);
public lateProcessEntity(entity: Entity) {
}
/**
*
* @param entities
*/
protected process(entities: Entity[]) {
entities.forEach(entity => this.processEntity(entity));
}
+11
View File
@@ -0,0 +1,11 @@
abstract class PassiveSystem extends EntitySystem {
public onChanged(entity: Entity){
}
protected process(entities: Entity[]){
// 我们用我们自己的不考虑实体的基本实体系统来代替
this.begin();
this.end();
}
}
@@ -0,0 +1,15 @@
/** 用于协调其他系统的通用系统基类 */
abstract class ProcessingSystem extends EntitySystem {
public onChanged(entity: Entity){
}
protected process(entities: Entity[]){
this.begin();
this.processSystem();
this.end();
}
/** 处理我们的系统 每帧调用 */
public abstract processSystem();
}
-359
View File
@@ -1,359 +0,0 @@
enum DirtyType{
clean,
positionDirty,
scaleDirty,
rotationDirty,
}
enum ComponentTransform{
position,
scale,
rotation
}
class Transform {
/** 相关联的实体 */
public readonly entity: Entity;
private _children: Transform[];
private _parent: Transform;
private _localPosition: Vector2;
private _localRotation: number = 0;
private _localScale: Vector2;
private _translationMatrix: Matrix2D;
private _rotationMatrix: Matrix2D;
private _scaleMatrix: Matrix2D;
private _worldTransform = Matrix2D.identity;
private _worldToLocalTransform = Matrix2D.identity;
private _worldInverseTransform = Matrix2D.identity;
private _rotation: number = 0;
private _position: Vector2;
private _scale: Vector2;
private _localTransform;
private _hierachyDirty: DirtyType;
private _localDirty: boolean;
private _localPositionDirty: boolean;
private _localScaleDirty: boolean;
private _localRotationDirty: boolean;
private _positionDirty: boolean;
private _worldToLocalDirty: boolean;
private _worldInverseDirty: boolean;
public get childCount(){
return this._children.length;
}
constructor(entity: Entity){
this.entity = entity;
this._scale = this._localScale = Vector2.One;
this._children = [];
}
public getChild(index: number){
return this._children[index];
}
public get worldInverseTransform(){
this.updateTransform();
if (this._worldInverseDirty){
this._worldInverseTransform = Matrix2D.invert(this._worldTransform, this._worldInverseTransform);
this._worldInverseDirty = false;
}
return this._worldInverseTransform;
}
public get localToWorldTransform(){
this.updateTransform();
return this._worldTransform;
}
public get worldToLocalTransform(){
if (this._worldToLocalDirty){
if (!this.parent){
this._worldInverseTransform = Matrix2D.identity;
} else{
this.parent.updateTransform();
this._worldToLocalTransform = Matrix2D.invert(this.parent._worldTransform, this._worldToLocalTransform);
}
this._worldToLocalDirty = false;
}
return this._worldToLocalTransform;
}
public get parent(){
return this._parent;
}
public set parent(value: Transform){
this.setParent(value);
}
public setParent(parent: Transform){
if (this._parent == parent)
return this;
if (this._parent)
this._parent._children.remove(this);
if (parent)
parent._children.push(this);
this._parent = parent;
return this;
}
public get rotation() {
this.updateTransform();
return this._rotation;
}
public set rotation(value: number){
this.setRotation(value);
}
public get localRotation(){
this.updateTransform();
return this._localRotation;
}
public set localRotation(value: number){
this.setLocalRotation(value);
}
public get position(){
this.updateTransform();
if (!this.parent){
this._position = this._localPosition;
}else{
this.parent.updateTransform();
this._position = Vector2.transform(this._localPosition, this.parent._worldTransform);
}
return this._position;
}
public set position(value: Vector2){
this.setPosition(value);
}
public get localPosition(){
this.updateTransform();
return this._localPosition;
}
public set localPosition(value: Vector2){
this.setLocalPosition(value);
}
public get scale(){
this.updateTransform();
return this._scale;
}
public set scale(value: Vector2){
this.setScale(value);
}
public get localScale(){
this.updateTransform();
return this._localScale;
}
public set localScale(value: Vector2){
this.setLocalScale(value);
}
public get rotationDegrees(){
return MathHelper.toDegrees(this._rotation);
}
public set rotationDegrees(value: number){
this.setRotation(MathHelper.toRadians(value));
}
public get localRotationDegrees(){
return MathHelper.toDegrees(this._localRotation);
}
public set localRotationDegrees(value: number){
this.localRotation = MathHelper.toRadians(value);
}
public setLocalScale(scale: Vector2){
this._localScale = scale;
this._localDirty = this._positionDirty = this._localScaleDirty = true;
this.setDirty(DirtyType.scaleDirty);
return this;
}
public setScale(scale: Vector2){
this._scale = scale;
if (this.parent){
this.localScale = Vector2.divide(scale, this.parent._scale);
}else{
this.localScale = scale;
}
for (let i = 0; i < this.entity.components.buffer.length; i ++){
let component = this.entity.components.buffer[i];
if (component.displayRender){
component.displayRender.scaleX = this.scale.x;
component.displayRender.scaleY = this.scale.y;
}
}
return this;
}
public setLocalRotationDegrees(degrees: number){
return this.setLocalRotation(MathHelper.toRadians(degrees));
}
public setLocalRotation(radians: number){
this._localRotation = radians;
this._localDirty = this._positionDirty = this._localPositionDirty = this._localRotationDirty = this._localScaleDirty = true;
this.setDirty(DirtyType.rotationDirty);
return this;
}
public setRotation(radians: number){
this._rotation = radians;
if (this.parent){
this.localRotation = this.parent.rotation + radians;
} else {
this.localRotation = radians;
}
for (let i = 0; i < this.entity.components.buffer.length; i ++){
let component = this.entity.components.buffer[i];
if (component.displayRender){
component.displayRender.rotation = this.rotation;
}
}
return this;
}
public setRotationDegrees(degrees: number){
return this.setRotation(MathHelper.toRadians(degrees));
}
public setLocalPosition(localPosition: Vector2){
if (localPosition == this._localPosition)
return this;
this._localPosition = localPosition;
this._localDirty = this._positionDirty = this._localPositionDirty = this._localRotationDirty = this._localScaleDirty = true;
this.setDirty(DirtyType.positionDirty);
return this;
}
public setPosition(position: Vector2){
if (position == this._position)
return this;
this._position = position;
if (this.parent){
this.localPosition = Vector2.transform(this._position, this._worldToLocalTransform);
}else{
this.localPosition = position;
}
for (let i = 0; i < this.entity.components.buffer.length; i ++){
let component = this.entity.components.buffer[i];
if (component.displayRender){
component.displayRender.x = this.entity.scene.camera.transformMatrix.m31 + this.position.x;
component.displayRender.y = this.entity.scene.camera.transformMatrix.m32 + this.position.y;
}
}
return this;
}
public setDirty(dirtyFlagType: DirtyType){
if ((this._hierachyDirty & dirtyFlagType) == 0){
this._hierachyDirty |= dirtyFlagType;
switch (dirtyFlagType){
case DirtyType.positionDirty:
this.entity.onTransformChanged(ComponentTransform.position);
break;
case DirtyType.rotationDirty:
this.entity.onTransformChanged(ComponentTransform.rotation);
break;
case DirtyType.scaleDirty:
this.entity.onTransformChanged(ComponentTransform.scale);
break;
}
if (this._children == null)
this._children = [];
for (let i = 0; i < this._children.length; i ++){
this._children[i].setDirty(dirtyFlagType);
}
}
}
public updateTransform(){
if (this._hierachyDirty != DirtyType.clean){
if (this.parent)
this.parent.updateTransform();
if (this._localDirty){
if (this._localPositionDirty){
this._translationMatrix = Matrix2D.createTranslation(this._localPosition.x, this._localPosition.y);
this._localPositionDirty = false;
}
if (this._localRotationDirty){
this._rotationMatrix = Matrix2D.createRotation(this._localRotation);
this._localRotationDirty = false;
}
if (this._localScaleDirty){
this._scaleMatrix = Matrix2D.createScale(this._localScale.x, this._localScale.y);
this._localScaleDirty = false;
}
this._localTransform = Matrix2D.multiply(this._scaleMatrix, this._rotationMatrix);
this._localTransform = Matrix2D.multiply(this._localTransform, this._translationMatrix);
if (!this.parent){
this._worldTransform = this._localTransform;
this._rotation = this._localRotation;
this._scale = this._localScale;
this._worldInverseDirty = true;
}
this._localDirty = false;
}
if (this.parent){
this._worldTransform = Matrix2D.multiply(this._localTransform, this.parent._worldTransform);
this._rotation = this._localRotation + this.parent._rotation;
this._scale = Vector2.multiply( this.parent._scale, this._localScale);
this._worldInverseDirty = true;
}
this._worldToLocalDirty = true;
this._positionDirty = true;
this._hierachyDirty = DirtyType.clean;
}
}
}
+120 -34
View File
@@ -1,28 +1,35 @@
class ComponentList {
private _entity: Entity;
/** 添加到实体的组件列表 */
private _components: Component[] = [];
/** 添加到此框架的组件列表。用来对组件进行分组,这样我们就可以同时进行加工 */
private _componentsToAdd: Component[] = [];
/** 标记要删除此框架的组件列表。用来对组件进行分组,这样我们就可以同时进行加工 */
private _componentsToRemove: Component[] = [];
private _tempBufferList: Component[] = [];
constructor(entity: Entity){
constructor(entity: Entity) {
this._entity = entity;
}
public get count(){
public get count() {
return this._components.length;
}
public get buffer(){
public get buffer() {
return this._components;
}
public add(component: Component){
public add(component: Component) {
this._componentsToAdd.push(component);
}
public remove(component: Component){
if (this._componentsToAdd.contains(component)){
public remove(component: Component) {
if (this._componentsToRemove.contains(component))
console.warn(`You are trying to remove a Component (${component}) that you already removed`)
// 这可能不是一个活动的组件,所以我们必须注意它是否还没有被处理,它可能正在同一帧中被删除
if (this._componentsToAdd.contains(component)) {
this._componentsToAdd.remove(component);
return;
}
@@ -30,8 +37,11 @@ class ComponentList {
this._componentsToRemove.push(component);
}
public removeAllComponents(){
for (let i = 0; i < this._components.length; i ++){
/**
*
*/
public removeAllComponents() {
for (let i = 0; i < this._components.length; i++) {
this.handleRemove(this._components[i]);
}
@@ -40,27 +50,37 @@ class ComponentList {
this._componentsToRemove.length = 0;
}
public deregisterAllComponents(){
for (let i = 0; i < this._components.length; i ++){
public deregisterAllComponents() {
for (let i = 0; i < this._components.length; i++) {
let component = this._components[i];
// 处理渲染层列表
if (component instanceof RenderableComponent)
this._entity.scene.renderableComponents.remove(component);
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component), false);
this._entity.scene.entityProcessors.onComponentRemoved(this._entity);
}
}
public registerAllComponents(){
for (let i = 0; i < this._components.length; i ++){
public registerAllComponents() {
for (let i = 0; i < this._components.length; i++) {
let component = this._components[i];
if (component instanceof RenderableComponent)
this._entity.scene.renderableComponents.add(component);
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component));
this._entity.scene.entityProcessors.onComponentAdded(this._entity);
}
}
public updateLists(){
if (this._componentsToRemove.length > 0){
for (let i = 0; i < this._componentsToRemove.length; i ++){
/**
*
*/
public updateLists() {
if (this._componentsToRemove.length > 0) {
for (let i = 0; i < this._componentsToRemove.length; i++) {
this.handleRemove(this._componentsToRemove[i]);
this._components.remove(this._componentsToRemove[i]);
}
@@ -68,9 +88,11 @@ class ComponentList {
this._componentsToRemove.length = 0;
}
if (this._componentsToAdd.length > 0){
for (let i = 0, count = this._componentsToAdd.length; i < count; i ++){
if (this._componentsToAdd.length > 0) {
for (let i = 0, count = this._componentsToAdd.length; i < count; i++) {
let component = this._componentsToAdd[i];
if (component instanceof RenderableComponent)
this._entity.scene.renderableComponents.add(component);
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component));
this._entity.scene.entityProcessors.onComponentAdded(this._entity);
@@ -79,13 +101,16 @@ class ComponentList {
this._tempBufferList.push(component);
}
// 在调用onAddedToEntity之前清除,以防添加更多组件
this._componentsToAdd.length = 0;
for (let i = 0; i < this._tempBufferList.length; i++){
// 现在所有的组件都添加到了场景中,我们再次循环并调用onAddedToEntity/onEnabled
for (let i = 0; i < this._tempBufferList.length; i++) {
let component = this._tempBufferList[i];
component.onAddedToEntity();
if (component.enabled){
// enabled检查实体和组件
if (component.enabled) {
component.onEnabled();
}
}
@@ -94,7 +119,22 @@ class ComponentList {
}
}
private handleRemove(component: Component){
public onEntityTransformChanged(comp: TransformComponent) {
for (let i = 0; i < this._components.length; i++) {
if (this._components[i].enabled)
this._components[i].onEntityTransformChanged(comp);
}
for (let i = 0; i < this._componentsToAdd.length; i++) {
if (this._componentsToAdd[i].enabled)
this._componentsToAdd[i].onEntityTransformChanged(comp);
}
}
private handleRemove(component: Component) {
if (component instanceof RenderableComponent)
this._entity.scene.renderableComponents.remove(component);
this._entity.componentBits.set(ComponentTypeManager.getIndexFor(component), false);
this._entity.scene.entityProcessors.onComponentRemoved(this._entity);
@@ -102,15 +142,23 @@ class ComponentList {
component.entity = null;
}
public getComponent<T extends Component>(type, onlyReturnInitializedComponents: boolean): T{
for (let i = 0; i < this._components.length; i ++){
/**
* T的第一个组件并返回它
* (onAddedToEntity方法的组件)
* null
* @param type
* @param onlyReturnInitializedComponents
*/
public getComponent<T extends Component>(type, onlyReturnInitializedComponents: boolean): T {
for (let i = 0; i < this._components.length; i++) {
let component = this._components[i];
if (component instanceof type)
return component as T;
}
if (!onlyReturnInitializedComponents){
for (let i = 0; i < this._componentsToAdd.length; i ++){
// 我们可以选择检查挂起的组件,以防addComponent和getComponent在同一个框架中被调用
if (!onlyReturnInitializedComponents) {
for (let i = 0; i < this._componentsToAdd.length; i++) {
let component = this._componentsToAdd[i];
if (component instanceof type)
return component as T;
@@ -120,19 +168,57 @@ class ComponentList {
return null;
}
public update(){
this.updateLists();
}
/**
* T类型的所有组件使
* @param typeName
* @param components
*/
public getComponents(typeName: string | any, components?) {
if (!components)
components = [];
public onEntityTransformChanged(comp){
for (let i = 0; i < this._components.length; i++){
if (this._components[i].enabled)
this._components[i].onEntityTransformChanged(comp);
for (let i = 0; i < this._components.length; i++) {
let component = this._components[i];
if (typeof (typeName) == "string") {
if (egret.is(component, typeName)) {
components.push(component);
}
} else {
if (component instanceof typeName) {
components.push(component);
}
}
}
for (let i = 0; i < this._componentsToAdd.length; i ++){
if (this._componentsToAdd[i].enabled)
this._componentsToAdd[i].onEntityTransformChanged(comp);
for (let i = 0; i < this._componentsToAdd.length; i++) {
let component = this._componentsToAdd[i];
if (typeof (typeName) == "string") {
if (egret.is(component, typeName)) {
components.push(component);
}
} else {
if (component instanceof typeName) {
components.push(component);
}
}
}
return components;
}
public update() {
this.updateLists();
for (let i = 0; i < this._components.length; i++) {
let updatable = this._components[i];
let updateableComponent;
if (updatable instanceof Component)
updateableComponent = updatable as Component;
if (updatable.enabled &&
updateableComponent.enabled &&
(updateableComponent.updateInterval == 1 ||
Time.frameCount % updateableComponent.updateInterval == 0))
updatable.update();
}
}
}

Some files were not shown because too many files have changed in this diff Show More