Compare commits

..

124 Commits

Author SHA1 Message Date
YHH 14b70b307c camera.mapSize 支持左上顶点更改 2020-08-08 15:09:10 +08:00
YHH a39b98b5d9 #23 修复绘制层级问题 2020-08-08 14:43:43 +08:00
YHH 3492bbdf5e 修复scrollingSprite无法向左移动问题 2020-08-08 14:11:25 +08:00
YHH 7d0bcbcb32 demo fix 2020-08-08 10:18:56 +08:00
YHH c02a3aa071 Merge branch 'master' of https://github.com/esengine/egret-framework 2020-08-08 10:12:43 +08:00
YHH a105bb11ca 修复origin导致显示位置错误问题 2020-08-08 10:12:08 +08:00
YHH 3fbbba7ac2 Merge pull request #25 from esengine/develop
#16 新增createEntityAsync方法
2020-08-08 09:51:24 +08:00
YHH 7cd38ea54e #16 新增createEntityAsync方法
修复entity.id为null
2020-08-08 09:50:40 +08:00
YHH 42852c5dba Merge pull request #24 from esengine/develop
#23 组件绘制层支持
2020-08-08 09:44:05 +08:00
YHH 6a3622a5ef #23 组件绘制层支持 2020-08-08 09:43:03 +08:00
YHH 03b568e28d Merge pull request #22 from esengine/develop
#21 新增gapXY用于平铺/滚动间距
2020-08-08 09:07:35 +08:00
YHH e7fb9e0d6b #21 完善 gapxy 2020-08-08 09:06:32 +08:00
yhh 463c64c628 #21 新增gapXY用于平铺/滚动间距 2020-08-07 15:34:42 +08:00
YHH 4025bc8554 Merge pull request #20 from esengine/develop
实现精灵平铺效果
2020-08-07 11:03:05 +08:00
yhh 1bf822725a #19 滚动精灵支持 2020-08-07 11:02:04 +08:00
YHH 359d7ae223 实现 scrollingSprite 2020-08-07 09:21:55 +08:00
YHH c611e31f7e Merge branch 'master' into develop
# Conflicts:
#	demo/libs/framework/framework.min.js
#	demo/src/game/MainScene.ts
#	source/bin/framework.min.js
2020-08-07 08:51:19 +08:00
YHH 834ad565e1 #19 实现精灵平铺效果 2020-08-07 08:50:26 +08:00
yhh ab3f38c6a8 修复lockUtils在wx上报错问题 2020-08-06 12:01:20 +08:00
yhh d0199e357b 修复vector2 y=0赋值错误问题 2020-08-06 10:55:02 +08:00
yhh 8e3bcc1257 射线检测完善 2020-08-03 14:45:57 +08:00
YHH a4fe9f5798 Merge pull request #15 from esengine/develop_ray
射线检测
2020-08-03 14:08:30 +08:00
yhh c692f0157e 新增射线检测 2020-08-03 14:06:47 +08:00
yhh bc6626865e ray2d 2020-07-31 19:33:04 +08:00
yhh 40fe7a57db 新增raycast射线 2020-07-31 17:17:44 +08:00
yhh 514572f291 reformat code 2020-07-28 16:25:20 +08:00
yhh 5994f0bee3 Merge branch 'master' of https://github.com/esengine/egret-framework 2020-07-28 16:12:31 +08:00
yhh b3e1f2c446 边框支持旋转 2020-07-28 16:11:58 +08:00
YHH ed13186779 Merge pull request #13 from esengine/develop_collider
整理ecs框架
2020-07-28 11:08:46 +08:00
yhh d730851d97 修复circleToBox检测偏差问题 2020-07-27 18:16:19 +08:00
yhh 60921f703b #12 fix addObserver函数异常错误 2020-07-27 17:27:32 +08:00
yhh 506f8ddc0f 新增renderablecomponent显示
优化返回值
2020-07-27 16:10:36 +08:00
YHH 149a3e5833 修复tostring导致的循环maxinum call 2020-07-26 23:27:42 +08:00
yhh 2b13e5ee7d 初始化默认数值 2020-07-24 16:57:26 +08:00
yhh 6be43fc9ac 优化transform结构
新增实体列表排序
2020-07-24 15:29:07 +08:00
yhh d4c244daf5 修复运行时未初始化 2020-07-23 19:28:01 +08:00
yhh 79c5d6990c SceneManager更改为Core继承egret.DisplayContainer 2020-07-23 15:39:18 +08:00
yhh 347626a8ea 忽略ide缓存 2020-07-23 13:26:52 +08:00
yhh e61dd0c16b 优化matrix 2020-07-23 13:25:10 +08:00
yhh 1b52bc5fd1 全部移动至es模块 2020-07-23 11:00:46 +08:00
YHH 814234ca61 移动类至es模块 2020-07-23 09:10:27 +08:00
YHH 15c0844e29 移动部分类模块至es
优化框架
2020-07-22 23:30:31 +08:00
yhh 5b8f414a45 整理ecs框架 2020-07-22 20:07:14 +08:00
yhh 6b8569b0b5 collider更改 2020-07-20 16:38:49 +08:00
yhh 2a38858838 提供对SpriteAnimator中的一些字段的访问 2020-07-20 13:46:58 +08:00
yhh e76d5815f2 1. 修正了相机在变焦时不能保持在目标中心的问题
2. 增加检查,以确保碰撞器被触发时enabled也开启
2020-07-20 13:44:26 +08:00
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 1e3b2763e8 Merge branch 'develop' of https://github.com/esengine/egret-framework into develop 2020-07-08 22:00:39 +08:00
YHH a3dacd04f0 Merge branch 'master' into develop
# Conflicts:
#	demo/libs/framework/framework.min.js
#	demo/src/game/MainScene.ts
#	source/bin/framework.min.js
2020-07-08 21:56:07 +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
176 changed files with 37601 additions and 13826 deletions
+4
View File
@@ -1,2 +1,6 @@
/source/node_modules
/demo/bin-debug
/demo/bin-release
/.idea
/.vscode
/demo_wxgame
-15
View File
@@ -1,15 +0,0 @@
{
// 使用 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}"
}
]
}
+44 -26
View File
@@ -1,23 +1,14 @@
# egret-framework
用于egret的一套框架 包含众多游戏中可能用到的系统
## 当前版本功能
[![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] A*寻路(AStar)
- [x] 常用碰撞检测
- [x] 数学库
- [x] 简易矩阵类
- [x] 简易2d 向量类
- [x] 掩码实用类
- [x] BreadthFirst 寻路算法
- [x] Dijkstra 寻路算法
- [x] 事件处理器
## 计划列表
- [ ] ECS
- [ ] 组件列表
- [x] 组件列表
- [x] 碰撞组件
- [x] 移动组件
- [ ] 刚体组件
@@ -28,16 +19,43 @@
- [ ] 网格弹簧组件
- [ ] 相机震动组件
- [ ] 霓虹灯组件
- [ ] 跟随相机组件
- [ ] 系统列表
- [ ] 被动系统
- [ ] 协调系统
- [ ] 数学库
- [ ] 贝塞尔曲线
- [ ] 快速随机数类
- [ ] 浮点助手
- [ ] 高性能数组
- [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
- [x] [行为树/实用AI 系统](https://github.com/esengine/egret-BehaviourTree-ai)
- [行为树/实用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
+2
View File
@@ -0,0 +1,2 @@
# Default ignored files
/workspace.xml
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="JavaScriptSettings">
<option name="languageLevel" value="ES6" />
</component>
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/demo.iml" filepath="$PROJECT_DIR$/.idea/demo.iml" />
</modules>
</component>
</project>
+6
View File
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>
+10
View File
@@ -0,0 +1,10 @@
{
"version": "0.1.0",
"command": "egret",
"isShellCommand": true,
"showOutput": "silent",
"args": [
"build"
],
"problemMatcher": "$tsc"
}
+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 ||
+1851 -826
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
+2 -1
View File
@@ -16,8 +16,9 @@
"bin-debug/Main.js",
"bin-debug/Platform.js",
"bin-debug/ThemeAdapter.js",
"bin-debug/game/CoreEmitterType.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"
}
]
}
+3
View File
@@ -44,6 +44,9 @@ export class WxgamePlugin implements plugins.Command {
if (filename == 'main.js') {
content += "\n;window.Main = Main;"
}
if (filename == 'libs/long/long.js' || filename == 'libs/long/long.min.js'){
content += "window.Long = long;"
}
this.md5Obj[path.basename(filename)] = this.md5(content)
file.contents = new Buffer(content);
}
+18 -82
View File
@@ -27,77 +27,29 @@
//
//////////////////////////////////////////////////////////////////////////////////////
class Main extends eui.UILayer {
public static emitter: Emitter<CoreEmitterType>;
protected createChildren(): void {
super.createChildren();
egret.lifecycle.addLifecycleListener((context) => {
// custom lifecycle plugin
})
egret.lifecycle.onPause = () => {
egret.ticker.pause();
}
egret.lifecycle.onResume = () => {
egret.ticker.resume();
}
//inject the custom material parser
//注入自定义的素材解析器
let assetAdapter = new AssetAdapter();
egret.registerImplementation("eui.IAssetAdapter", assetAdapter);
egret.registerImplementation("eui.IThemeAdapter", new ThemeAdapter());
Main.emitter = new Emitter<CoreEmitterType>();
this.addEventListener(egret.Event.ENTER_FRAME, this.updateFrame, this);
class Main extends es.Core {
protected initialize() {
this.runGame();
}
private updateFrame(evt: egret.Event){
Main.emitter.emit(CoreEmitterType.Update, evt);
let activeScene = SceneManager.getActiveScene();
if (activeScene){
let player = activeScene.findEntity("player");
if (player){
let mover = player.getComponent<Mover>(Mover);
mover.move(new Vector2(0, 0));
}
}
private runGame() {
this.loadResource();
}
private async runGame() {
await this.loadResource();
this.createGameScene();
}
private async loadResource() {
try {
const loadingView = new LoadingUI();
this.stage.addChild(loadingView);
await RES.loadConfig("resource/default.res.json", "resource/");
await this.loadTheme();
await RES.loadGroup("preload", 0, loadingView);
this.stage.removeChild(loadingView);
}
catch (e) {
console.error(e);
}
}
private loadTheme() {
return new Promise((resolve, reject) => {
// load skin theme configuration file, you can manually modify the file. And replace the default skin.
//加载皮肤主题配置文件,可以手动修改这个文件。替换默认皮肤。
let theme = new eui.Theme("resource/default.thm.json", this.stage);
theme.addEventListener(eui.UIEvent.COMPLETE, () => {
resolve();
}, this);
})
private loadResource() {
const loadingView = new LoadingUI();
this.stage.addChild(loadingView);
RES.loadConfig("resource/default.res.json", "resource/").then(()=>{
RES.loadGroup("preload", 0, loadingView).then(()=>{
this.stage.removeChild(loadingView);
this.createGameScene();
}).catch(err => {
console.error(err);
});
}).catch(err =>{
console.error(err);
});
}
/**
@@ -105,22 +57,6 @@ 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 PolygonMesh([new Vector2(0, 0),
new Vector2(10, 0),
new Vector2(10, 10),
new Vector2(0, 10),
new Vector2(0, 0)]));
player.addComponent(new SpawnComponent(EnemyType.worm));
player.addComponent(new BoxCollider()).setSize(100, 100).isTrigger = true;
player.addComponent(new Mover());
let player2 = scene.createEntity("player2");
player2.addComponent(new BoxCollider()).setSize(99, 99);
// Main.emitter.addObserver(CoreEmitterType.Update, ()=>{
// console.log("update emitter");
// });
es.Core.scene = new scene.MainScene();
}
}
-3
View File
@@ -1,3 +0,0 @@
enum CoreEmitterType {
Update,
}
+92 -46
View File
@@ -1,48 +1,94 @@
class MainScene extends Scene {
constructor(displayContent: egret.DisplayObject){
super(displayContent);
module scene {
export class MainScene extends es.Scene {
constructor() {
super();
// this.addEntityProcessor(new SpawnerSystem(new Matcher()));
this.astarTest();
this.dijkstraTest();
this.breadthfirstTest();
// this.addEntityProcessor(new SpawnerSystem(new Matcher()));
this.astarTest();
this.dijkstraTest();
this.breadthfirstTest();
}
public async onStart() {
let sprite = new es.Sprite(RES.getRes("checkbox_select_disabled_png"));
this.createEntityAsync("bg").then(bg => {
bg.addComponent(new component.PlayerController());
bg.addComponent(new es.Mover());
let spriteRenderer = bg.addComponent(new es.ScrollingSpriteRenderer(sprite));
spriteRenderer.setRenderLayer(4);
spriteRenderer.scrollX = -30;
// bg.addComponent(new es.BoxCollider());
this.camera.follow(bg, es.CameraStyle.lockOn);
});
// // bg.addComponent(new es.SpriteRenderer()).setSprite(sprite).setColor(0xff0000);
for (let i = 0; i < 20; i++) {
let sprite = new es.Sprite(RES.getRes("checkbox_select_disabled_png"));
let player2 = this.createEntity("bg");
player2.addComponent(new es.SpriteRenderer()).setSprite(sprite).setRenderLayer(i);
player2.position = new es.Vector2(30 * i, 30 * i);
// player2.addComponent(new es.BoxCollider());
}
let pool = new es.ComponentPool<component.SimplePooled>(component.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, () => {
es.Core.startSceneTransition(new es.FadeTransition(() => {
return new MainScene();
}));
}, this);
}
public breadthfirstTest() {
let graph = new es.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 = es.BreadthFirstPathfinder.search(graph, "c", "e");
console.log(path);
}
public dijkstraTest() {
let graph = new es.WeightedGridGraph(20, 20);
graph.weightedNodes.push(new es.Vector2(3, 3));
graph.weightedNodes.push(new es.Vector2(3, 4));
graph.weightedNodes.push(new es.Vector2(4, 3));
graph.weightedNodes.push(new es.Vector2(4, 4));
let path = graph.search(new es.Vector2(3, 4), new es.Vector2(15, 17));
console.log(path);
}
public astarTest() {
let graph = new es.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 es.Vector2(1, 1), new es.Vector2(29, 29));
console.log(egret.getTimer() - startTime);
}
}
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 Point(3, 3));
graph.weightedNodes.push(new Point(3, 4));
graph.weightedNodes.push(new Point(4, 3));
graph.weightedNodes.push(new Point(4, 4));
let path = graph.search(new Point(3, 4), new Point(15, 17));
console.log(path);
}
public astarTest(){
let graph = new AstarGridGraph(20, 20);
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));
let path = graph.search(new Point(3, 4), new Point(15, 17));
console.log(path);
}
}
}
+66
View File
@@ -0,0 +1,66 @@
module component {
import Component = es.Component;
import Vector2 = es.Vector2;
import Mover = es.Mover;
import SpriteRenderer = es.SpriteRenderer;
import Time = es.Time;
import Input = es.Input;
import CollisionResult = es.CollisionResult;
export 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 moveLeft: number = 0;
let moveRight: number = 0;
let speed = 100;
let worldPos = this.entity.scene.camera.mouseToWorldPoint();
if (worldPos.x < this.spriteRenderer.transform.position.x){
moveLeft = -1;
} else if(worldPos.x > this.spriteRenderer.transform.position.x){
moveLeft = 1;
}
if (worldPos.y < this.spriteRenderer.transform.position.y){
moveRight = -1;
} else if(worldPos.y > this.spriteRenderer.transform.position.y){
moveRight = 1;
}
let collisionResult = new CollisionResult();
this.mover.move(new Vector2(moveLeft * speed * Time.deltaTime, moveRight * speed * Time.deltaTime), collisionResult);
}
}
}
}
+9
View File
@@ -0,0 +1,9 @@
module component {
import PooledComponent = es.PooledComponent;
export class SimplePooled extends PooledComponent {
public reset(){
}
}
}
+32 -30
View File
@@ -1,35 +1,37 @@
class SpawnComponent extends Component implements ITriggerListener {
public cooldown = -1;
public minInterval = 2;
public maxInterval = 60;
public enemyType = EnemyType.worm;
public numSpawned = 0;
public numAlive = 0;
module component {
export class SpawnComponent extends es.Component implements es.ITriggerListener {
public cooldown = -1;
public minInterval = 2;
public maxInterval = 60;
public enemyType = EnemyType.worm;
public numSpawned = 0;
public numAlive = 0;
constructor(enemyType: EnemyType) {
super();
this.enemyType = enemyType;
constructor(enemyType: EnemyType) {
super();
this.enemyType = enemyType;
}
public initialize() {
// console.log("initialize");
}
public update() {
// console.log("update");
}
public onTriggerEnter(other: es.Collider, local: es.Collider){
if (other == local)
console.log("repeat collider");
console.log("enter collider");
}
public onTriggerExit(other: es.Collider, local: es.Collider){
console.log("exit collider");
}
}
public initialize() {
// console.log("initialize");
}
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");
export enum EnemyType {
worm
}
}
enum EnemyType {
worm
}
+31 -29
View File
@@ -1,34 +1,36 @@
class SpawnerSystem extends EntityProcessingSystem {
constructor(matcher: Matcher){
super(matcher);
}
public processEntity(entity: Entity){
let spawner = entity.getComponent<SpawnComponent>(SpawnComponent);
if (!spawner)
return;
if (spawner.numAlive <= 0)
spawner.enabled = true;
if (!spawner.enabled)
return;
console.log("cooldown", spawner.cooldown);
if (spawner.cooldown == -1){
spawner.cooldown = Math.random() * 60;
spawner.cooldown /= 4;
module system {
export class SpawnerSystem extends es.EntityProcessingSystem {
constructor(matcher: es.Matcher){
super(matcher);
}
spawner.cooldown -= Time.deltaTime;
if (spawner.cooldown <= 0){
spawner.cooldown = Math.random() * 60;
// CreateEnemy
spawner.numSpawned ++;
spawner.numAlive ++;
public processEntity(entity: es.Entity){
let spawner = entity.getComponent<component.SpawnComponent>(component.SpawnComponent);
if (!spawner)
return;
if (spawner.numAlive > 0)
spawner.enabled = false;
if (spawner.numAlive <= 0)
spawner.enabled = true;
if (!spawner.enabled)
return;
console.log("cooldown", spawner.cooldown);
if (spawner.cooldown == -1){
spawner.cooldown = Math.random() * 60;
spawner.cooldown /= 4;
}
spawner.cooldown -= es.Time.deltaTime;
if (spawner.cooldown <= 0){
spawner.cooldown = Math.random() * 60;
// CreateEnemy
spawner.numSpawned ++;
spawner.numAlive ++;
if (spawner.numAlive > 0)
spawner.enabled = false;
}
}
}
}
}
+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,
+1
View File
@@ -2,6 +2,7 @@
"compilerOptions": {
"target": "es5",
"outDir": "bin-debug",
"sourceMap": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"lib": [
+11 -11
View File
@@ -1,13 +1,13 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "gulp",
"task": "build",
"group": "build",
"problemMatcher": []
}
]
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"type": "gulp",
"task": "build",
"group": "build",
"problemMatcher": []
}
]
}
+3
View File
@@ -0,0 +1,3 @@
{
"typescript.tsdk": "./node_modules/typescript/lib"
}
+1851 -826
View File
File diff suppressed because it is too large Load Diff
+8445 -3825
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
+3 -3
View File
@@ -8,10 +8,10 @@ const tsProject = ts.createProject('tsconfig.json');
gulp.task('buildJs', () => {
return tsProject.src()
.pipe(tsProject())
.js.pipe(inject.replace('var framework;', ''))
.pipe(inject.prepend('window.framework = {};\n'))
.js.pipe(inject.replace('var es;', ''))
.pipe(inject.prepend('window.es = {};\n'))
.pipe(inject.replace('var __extends =', 'window.__extends ='))
.pipe(minify({ ext: { min: ".min.js" } }))
.pipe(minify({ext: {min: ".min.js"}}))
.pipe(gulp.dest('./bin'));
});
+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
*/
+1350
View File
File diff suppressed because it is too large Load Diff
+3945
View File
File diff suppressed because it is too large Load Diff
@@ -1,89 +1,103 @@
///<reference path="./PriorityQueueNode.ts" />
/**
* IAstarGraph和开始/
*/
class AStarPathfinder {
public static search<T>(graph: IAstarGraph<T>, start: T, goal: T){
let foundPath = false;
let cameFrom = new Map<T, T>();
cameFrom.set(start, start);
module es {
/**
* IAstarGraph和开始/
*/
export 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>();
cameFrom.set(start, start);
let costSoFar = new Map<T, number>();
let frontier = new PriorityQueue<AStarNode<T>>(1000);
frontier.enqueue(new AStarNode<T>(start), 0);
let costSoFar = new Map<T, number>();
let frontier = new PriorityQueue<AStarNode<T>>(1000);
frontier.enqueue(new AStarNode<T>(start), 0);
costSoFar.set(start, 0);
costSoFar.set(start, 0);
while (frontier.count > 0){
let current = frontier.dequeue();
while (frontier.count > 0) {
let current = frontier.dequeue();
if (JSON.stringify(current.data) == JSON.stringify(goal)){
foundPath = true;
break;
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 priority = newCost + graph.heuristic(next, goal);
frontier.enqueue(new AStarNode<T>(next), priority);
cameFrom.set(next, current.data);
}
});
}
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 priority = newCost + graph.heuristic(next, goal);
frontier.enqueue(new AStarNode<T>(next), priority);
cameFrom.set(next, current.data);
}
});
return foundPath ? this.recontructPath(cameFrom, start, goal) : null;
}
return foundPath ? this.recontructPath(cameFrom, start, goal) : 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;
path.push(goal);
while (current != start) {
current = this.getKey(cameFrom, current);
path.push(current);
}
path.reverse();
return path;
}
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;
}
}
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;
/**
* 使PriorityQueue需要的额外字段将原始数据封装在一个小类中
*/
export class AStarNode<T> extends PriorityQueueNode {
public data: T;
constructor(data: T) {
super();
this.data = data;
}
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;
}
}
/**
* 使PriorityQueue需要的额外字段将原始数据封装在一个小类中
*/
class AStarNode<T> extends PriorityQueueNode {
public data: T;
constructor(data: T){
super();
this.data = data;
}
}
@@ -1,67 +1,74 @@
/**
* 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)
];
public walls: Point[] = [];
public weightedNodes: Point[] = [];
public defaultWeight: number = 1;
public weightedNodeWeight = 5;
private _width;
private _height;
private _neighbors: Point[] = new Array(4);
constructor(width: number, height: number){
this._width = width;
this._height = height;
}
module es {
/**
*
* @param node
* A*使
* walls添加到walls HashSetweightedNodes
*/
public isNodeInBounds(node: Point): boolean {
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
export 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: Vector2[] = [];
public weightedNodes: Vector2[] = [];
public defaultWeight: number = 1;
public weightedNodeWeight = 5;
private _width;
private _height;
private _neighbors: Vector2[] = new Array(4);
constructor(width: number, height: number) {
this._width = width;
this._height = height;
}
/**
*
* @param node
*/
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: Vector2): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
/**
* AStarPathfinder.search的快捷方式
* @param start
* @param goal
*/
public search(start: Vector2, goal: Vector2) {
return AStarPathfinder.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((p) => JSON.stringify(p) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
}
public heuristic(node: Vector2, goal: Vector2) {
return Math.abs(node.x - goal.x) + Math.abs(node.y - goal.y);
}
}
/**
*
* @param node
*/
public isNodePassable(node: Point): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
public search(start: Point, goal: Point){
return AStarPathfinder.search(this, start, goal);
}
public getNeighbors(node: Point): Point[] {
this._neighbors.length = 0;
this.dirs.forEach(dir => {
let next = new Point(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: Point, to: Point): number {
return this.weightedNodes.find((p)=> JSON.stringify(p) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
}
public heuristic(node: Point, goal: Point) {
return Math.abs(node.x - goal.x) + Math.abs(node.y - goal.y);
}
}
}
+26 -5
View File
@@ -1,5 +1,26 @@
interface IAstarGraph<T> {
getNeighbors(node: T): Array<T>;
cost(from: T, to: T): number;
heuristic(node: T, goal: T);
}
module es {
/**
* graph的接口AstarPathfinder.search方法
*/
export 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);
}
}
+213 -127
View File
@@ -1,150 +1,236 @@
class PriorityQueue<T extends PriorityQueueNode> {
private _numNodes: number;
private _nodes: T[];
private _numNodesEverEnqueued;
module es {
/**
* 使 O(1)
* 使5-10
* IPriorityQueue.contains()
*/
export class PriorityQueue<T extends PriorityQueueNode> {
private _numNodes: number;
private _nodes: T[];
private _numNodesEverEnqueued;
constructor(maxNodes: number) {
this._numNodes = 0;
this._nodes = new Array(maxNodes + 1);
this._numNodesEverEnqueued = 0;
}
/**
*
* @param maxNodes (undefined的行为)
*/
constructor(maxNodes: number) {
this._numNodes = 0;
this._nodes = new Array(maxNodes + 1);
this._numNodesEverEnqueued = 0;
}
public clear() {
this._nodes.splice(1, this._numNodes);
this._numNodes = 0;
}
/**
*
* O(1)
*/
public get count() {
return this._numNodes;
}
public get count() {
return this._numNodes;
}
/**
* (Count == MaxSize)undefined的行为
* O(1)
*/
public get maxSize() {
return this._nodes.length - 1;
}
public contains(node: T): boolean {
return (this._nodes[node.queueIndex] == node);
}
/**
*
* O(n)
*/
public clear() {
this._nodes.splice(1, this._numNodes);
this._numNodes = 0;
}
public enqueue(node: T, priority: number) {
node.priority = priority;
this._numNodes++;
this._nodes[this._numNodes] = node;
node.queueIndex = this._numNodes;
node.insertionIndex = this._numNodesEverEnqueued++;
this.cascadeUp(this._nodes[this._numNodes]);
}
/**
* (O(1))
* O (1)
* @param node
*/
public contains(node: T): boolean {
if (!node) {
console.error("node cannot be null");
return false;
}
public dequeue(): T {
let returnMe = this._nodes[1];
this.remove(returnMe);
return returnMe;
}
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;
}
public remove(node: T) {
if (node.queueIndex == this._numNodes) {
this._nodes[this._numNodes] = null;
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++;
this._nodes[this._numNodes] = node;
node.queueIndex = this._numNodes;
node.insertionIndex = this._numNodesEverEnqueued++;
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;
this._numNodes--;
return;
}
let formerLastNode = this._nodes[this._numNodes];
this.swap(node, formerLastNode);
delete this._nodes[this._numNodes];
this._numNodes--;
return;
this.onNodeUpdated(formerLastNode);
}
let formerLastNode = this._nodes[this._numNodes];
this.swap(node, formerLastNode);
delete this._nodes[this._numNodes];
this._numNodes--;
/**
* /
*/
public isValidQueue(): boolean {
for (let i = 1; i < this._nodes.length; i++) {
if (this._nodes[i]) {
let childLeftIndex = 2 * i;
if (childLeftIndex < this._nodes.length && this._nodes[childLeftIndex] &&
this.hasHigherPriority(this._nodes[childLeftIndex], this._nodes[i]))
return false;
this.onNodeUpdated(formerLastNode);
}
public isValidQueue(): boolean {
for (let i = 1; i < this._nodes.length; i++) {
if (this._nodes[i]) {
let childLeftIndex = 2 * i;
if (childLeftIndex < this._nodes.length && this._nodes[childLeftIndex] &&
this.hasHigherPriority(this._nodes[childLeftIndex], this._nodes[i]))
return false;
let childRightIndex = childLeftIndex + 1;
if (childRightIndex < this._nodes.length && this._nodes[childRightIndex] &&
this.hasHigherPriority(this._nodes[childRightIndex], this._nodes[i]))
return false;
}
}
return true;
}
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 {
this.cascadeDown(node);
}
}
private cascadeDown(node: T) {
let newParent: T;
let finalQueueIndex = node.queueIndex;
while (true) {
newParent = node;
let childLeftIndex = 2 * finalQueueIndex;
if (childLeftIndex > this._numNodes) {
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
}
let childLeft = this._nodes[childLeftIndex];
if (this.hasHigherPriority(childLeft, newParent)) {
newParent = childLeft;
}
let childRightIndex = childLeftIndex + 1;
if (childRightIndex <= this._numNodes) {
let childRight = this._nodes[childRightIndex];
if (this.hasHigherPriority(childRight, newParent)) {
newParent = childRight;
let childRightIndex = childLeftIndex + 1;
if (childRightIndex < this._nodes.length && this._nodes[childRightIndex] &&
this.hasHigherPriority(this._nodes[childRightIndex], this._nodes[i]))
return false;
}
}
if (newParent != node) {
this._nodes[finalQueueIndex] = newParent;
return true;
}
let temp = newParent.queueIndex;
newParent.queueIndex = finalQueueIndex;
finalQueueIndex = temp;
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 {
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
// 注意,如果parentNode == node(即节点是根),则将调用CascadeDown。
this.cascadeDown(node);
}
}
}
private cascadeUp(node: T) {
let parent = Math.floor(node.queueIndex / 2);
while (parent >= 1) {
let parentNode = this._nodes[parent];
if (this.hasHigherPriority(parentNode, node))
break;
private cascadeDown(node: T) {
// 又名Heapify-down
let newParent: T;
let finalQueueIndex = node.queueIndex;
while (true) {
newParent = node;
let childLeftIndex = 2 * finalQueueIndex;
this.swap(node, parentNode);
// 检查左子节点的优先级是否高于当前节点
if (childLeftIndex > this._numNodes) {
// 这可以放在循环之外,但是我们必须检查newParent != node两次
node.queueIndex = finalQueueIndex;
this._nodes[finalQueueIndex] = node;
break;
}
parent = Math.floor(node.queueIndex / 2);
let childLeft = this._nodes[childLeftIndex];
if (this.hasHigherPriority(childLeft, newParent)) {
newParent = childLeft;
}
// 检查右子节点的优先级是否高于当前节点或左子节点
let childRightIndex = childLeftIndex + 1;
if (childRightIndex <= this._numNodes) {
let childRight = this._nodes[childRightIndex];
if (this.hasHigherPriority(childRight, newParent)) {
newParent = childRight;
}
}
// 如果其中一个子节点具有更高(更小)的优先级,则交换并继续级联
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;
}
}
}
/**
*
* @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);
}
}
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));
}
}
private swap(node1: T, node2: T) {
this._nodes[node1.queueIndex] = node2;
this._nodes[node2.queueIndex] = node1;
let temp = node1.queueIndex;
node1.queueIndex = node2.queueIndex;
node2.queueIndex = temp;
}
private hasHigherPriority(higher: T, lower: T) {
return (higher.priority < lower.priority ||
(higher.priority == lower.priority && higher.insertionIndex < lower.insertionIndex));
}
}
}
@@ -1,14 +1,16 @@
class PriorityQueueNode {
/**
*
*/
public priority: number = 0;
/**
* 使-
*/
public insertionIndex: number = 0;
/**
* 使-
*/
public queueIndex: number = 0;
}
module es {
export class PriorityQueueNode {
/**
*
*/
public priority: number = 0;
/**
* 使-
*/
public insertionIndex: number = 0;
/**
* 使-
*/
public queueIndex: number = 0;
}
}
@@ -1,41 +1,43 @@
/**
* IUnweightedGraph和开始/
*/
class BreadthFirstPathfinder {
public static search<T>(graph: IUnweightedGraph<T>, start: T, goal: T): T[]{
let foundPath = false;
let frontier = [];
frontier.unshift(start);
module es {
/**
* IUnweightedGraph和开始/
*/
export 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);
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;
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);
}
});
}
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;
}
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;
}
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;
}
return false;
}
}
}
@@ -1,7 +1,9 @@
interface IUnweightedGraph<T>{
/**
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
* @param node
*/
getNeighbors(node: T): T[];
}
module es {
export interface IUnweightedGraph<T> {
/**
* getNeighbors方法应该返回从传入的节点可以到达的任何相邻节点
* @param node
*/
getNeighbors(node: T): T[];
}
}
@@ -1,16 +1,18 @@
/**
*
*
*/
class UnweightedGraph<T> implements IUnweightedGraph<T> {
public edges: Map<T, T[]> = new Map<T, T[]>();
module es {
/**
*
*
*/
export 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 addEdgesForNode(node: T, edges: T[]) {
this.edges.set(node, edges);
return this;
}
public getNeighbors(node: T){
return this.edges.get(node);
public getNeighbors(node: T) {
return this.edges.get(node);
}
}
}
}
@@ -1,61 +1,63 @@
///<reference path="../../../Math/Point.ts" />
/**
* BreadthFirstPathfinder
*/
class UnweightedGridGraph implements IUnweightedGraph<Point> {
private static readonly CARDINAL_DIRS: Point[] = [
new Point(1, 0),
new Point(0, -1),
new Point(-1, 0),
new Point(0, -1)
];
///<reference path="../../../Math/Vector2.ts" />
module es {
/**
* BreadthFirstPathfinder
*/
export 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 Point(1, 0),
new Point(1, -1),
new Point(0, -1),
new Point(-1, -1),
new Point(-1, 0),
new Point(-1, 1),
new Point(0, 1),
new Point(1, 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: Point[] = [];
public walls: Vector2[] = [];
private _width: number;
private _hegiht: number;
private _width: number;
private _hegiht: number;
private _dirs: Point[];
private _neighbors: Point[] = new Array(4);
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;
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);
}
}
public isNodeInBounds(node: Point): boolean {
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._hegiht;
}
public isNodePassable(node: Point): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
public getNeighbors(node: Point) {
this._neighbors.length = 0;
this._dirs.forEach(dir => {
let next = new Point(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: Point, goal: Point): Point[] {
return BreadthFirstPathfinder.search(this, start, goal);
}
}
}
@@ -1,14 +1,16 @@
interface IWeightedGraph<T>{
/**
*
* @param node
*/
getNeighbors(node: T): T[];
module es {
export interface IWeightedGraph<T> {
/**
*
* @param node
*/
getNeighbors(node: T): T[];
/**
*
* @param from
* @param to
*/
cost(from: T, to: T): number;
}
/**
*
* @param from
* @param to
*/
cost(from: T, to: T): number;
}
}
@@ -1,67 +1,69 @@
///<reference path="../../../Math/Point.ts" />
/**
*
*/
class WeightedGridGraph implements IWeightedGraph<Point> {
public static readonly CARDINAL_DIRS = [
new Point(1, 0),
new Point(0, -1),
new Point(-1, 0),
new Point(0, 1)
];
///<reference path="../../../Math/Vector2.ts" />
module es {
/**
*
*/
export 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 Point(1, 0),
new Point(1, -1),
new Point(0, -1),
new Point(-1, -1),
new Point(-1, 0),
new Point(-1, 1),
new Point(0, 1),
new Point(1, 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: Point[] = [];
public weightedNodes: Point[] = [];
public defaultWeight = 1;
public weightedNodeWeight = 5;
public walls: Vector2[] = [];
public weightedNodes: Vector2[] = [];
public defaultWeight = 1;
public weightedNodeWeight = 5;
private _width: number;
private _height: number;
private _dirs: Point[];
private _neighbors: Point[] = new Array(4);
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;
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;
}
}
public isNodeInBounds(node: Point){
return 0 <= node.x && node.x < this._width && 0 <= node.y && node.y < this._height;
}
public isNodePassable(node: Point): boolean {
return !this.walls.firstOrDefault(wall => JSON.stringify(wall) == JSON.stringify(node));
}
public search(start: Point, goal: Point){
return WeightedPathfinder.search(this, start, goal);
}
public getNeighbors(node: Point): Point[]{
this._neighbors.length = 0;
this._dirs.forEach(dir => {
let next = new Point(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: Point, to: Point): number{
return this.weightedNodes.find(t => JSON.stringify(t) == JSON.stringify(to)) ? this.weightedNodeWeight : this.defaultWeight;
}
}
}
@@ -1,83 +1,85 @@
class WeightedNode<T> extends PriorityQueueNode {
public data: T;
module es {
export class WeightedNode<T> extends PriorityQueueNode {
public data: T;
constructor(data: T){
super();
this.data = data;
constructor(data: T) {
super();
this.data = data;
}
}
}
class WeightedPathfinder {
public static search<T>(graph: IWeightedGraph<T>, start: T, goal: T){
let foundPath = false;
export 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 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);
let costSoFar = new Map<T, number>();
let frontier = new PriorityQueue<WeightedNode<T>>(1000);
frontier.enqueue(new WeightedNode<T>(start), 0);
costSoFar.set(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;
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);
}
});
}
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 foundPath ? this.recontructPath(cameFrom, start, goal) : null;
}
return false;
}
public static recontructPath<T>(cameFrom: Map<T, T>, start: T, goal: T): T[] {
let path = [];
let current = goal;
path.push(goal);
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;
while (current != start) {
current = this.getKey(cameFrom, current);
path.push(current);
}
path.reverse();
return path;
}
return 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;
}
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);
return false;
}
path.reverse();
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 path;
return null;
}
}
}
}
+24
View File
@@ -0,0 +1,24 @@
module es {
export 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 (Core.scene) {
Core.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);
}
}
}
}
}
+6 -4
View File
@@ -1,4 +1,6 @@
class DebugDefaults {
public static verletParticle = 0xDC345E;
public static verletConstraintEdge = 0x433E36;
}
module es {
export class DebugDefaults {
public static verletParticle = 0xDC345E;
public static verletConstraintEdge = 0x433E36;
}
}
+49
View File
@@ -0,0 +1,49 @@
module es {
export enum DebugDrawType {
line,
hollowRectangle,
pixel,
text
}
export 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;
}
}
}
+133 -70
View File
@@ -1,74 +1,137 @@
abstract class Component {
public entity: Entity;
private _enabled: boolean = true;
public updateInterval: number = 1;
module es {
/**
*
* - onAddedToEntity
* - OnEnabled
*
*
* - onRemovedFromEntity
*/
export abstract class Component extends egret.HashObject {
/**
*
*/
public entity: Entity;
/**
*
*/
public updateInterval: number = 1;
public get transform(){
return this.entity.transform;
}
public get enabled(){
return this.entity ? this.entity.enabled && this._enabled : this._enabled;
}
public set enabled(value: boolean){
this.setEnabled(value);
}
public setEnabled(isEnabled: boolean){
if (this._enabled != isEnabled){
this._enabled = isEnabled;
if (this._enabled){
this.onEnabled();
}else{
this.onDisabled();
}
/**
* 访 this.entity.transform
*/
public get transform(): Transform {
return this.entity.transform;
}
return this;
private _enabled: boolean = true;
/**
* onEnabled/onDisable
*/
public get enabled() {
return this.entity ? this.entity.enabled && this._enabled : this._enabled;
}
/**
* onEnabled/onDisable
* @param value
*/
public set enabled(value: boolean) {
this.setEnabled(value);
}
private _updateOrder = 0;
/** 更新此实体上组件的顺序 */
public get updateOrder() {
return this._updateOrder;
}
/** 更新此实体上组件的顺序 */
public set updateOrder(value: number) {
this.setUpdateOrder(value);
}
/**
* 西访
*/
public initialize() {
}
/**
*
*/
public onAddedToEntity() {
}
/**
*
*/
public onRemovedFromEntity() {
}
/**
*
* @param comp
*/
public onEntityTransformChanged(comp: transform.Component) {
}
/**
*
*/
public debugRender() {
}
/**
*
*/
public onEnabled() {
}
/**
*
*/
public onDisabled() {
}
/**
*
*/
public update() {
}
public setEnabled(isEnabled: boolean) {
if (this._enabled != isEnabled) {
this._enabled = isEnabled;
if (this._enabled) {
this.onEnabled();
} else {
this.onDisabled();
}
}
return this;
}
public setUpdateOrder(updateOrder: number) {
if (this._updateOrder != updateOrder) {
this._updateOrder = updateOrder;
}
return this;
}
/**
*
*/
public clone(): Component {
let component = ObjectUtils.clone<Component>(this);
component.entity = null;
return component;
}
}
public initialize(){
}
public onAddedToEntity(){
}
public onRemovedFromEntity(){
}
public onEnabled(){
}
public onDisabled(){
}
public onEntityTransformChanged(comp: ComponentTransform){
}
public update(){
}
public debugRender(){
}
/** 内部使用 运行时不应该调用 */
public registerComponent(){
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this), false);
this.entity.scene.entityProcessors.onComponentAdded(this.entity);
}
public deregisterComponent(){
this.entity.componentBits.set(ComponentTypeManager.getIndexFor(this));
this.entity.scene.entityProcessors.onComponentRemoved(this.entity);
}
}
}
+456 -164
View File
@@ -1,192 +1,484 @@
///<reference path="../Component.ts"/>
class Camera extends Component {
private _zoom;
private _origin: Vector2;
private _transformMatrix: Matrix2D = Matrix2D.identity;
private _inverseTransformMatrix = Matrix2D.identity;
module es {
export enum CameraStyle {
lockOn,
cameraWindow,
}
private _minimumZoom = 0.3;
private _maximumZoom = 3;
private _areMatrixesDirty = true;
private _inset: CameraInset;
private _bounds: Rectangle;
private _areBoundsDirty = true;
export class CameraInset {
public left: number = 0;
public right: number = 0;
public top: number = 0;
public bottom: number = 0;
}
public get bounds(){
if (this._areMatrixesDirty)
this.updateMatrixes();
export class Camera extends Component {
public _inset: CameraInset = new CameraInset();
public _areMatrixedDirty: boolean = true;
public _areBoundsDirty: boolean = true;
public _isProjectionMatrixDirty = true;
/**
* cameraWindow
*
*/
public followLerp = 0.1;
/**
* cameraWindow模式下/
* lockOn模式下使deadZone的x/y值 setCenteredDeadzone重写它来自定义deadZone
*/
public deadzone: Rectangle = new Rectangle();
/**
*
*/
public focusOffset: Vector2 = Vector2.zero;
/**
* true 0, 0, mapwidth, mapheight
*/
public mapLockEnabled: boolean = false;
/**
*
*/
public mapSize: Rectangle = new Rectangle();
public _targetEntity: Entity;
public _targetCollider: Collider;
public _desiredPositionDelta: Vector2 = new Vector2();
public _cameraStyle: CameraStyle;
public _worldSpaceDeadZone: Rectangle = new Rectangle();
if (this._areBoundsDirty){
let stage = this.entity.scene.stage;
let topLeft = this.screenToWorldPoint(new Vector2(this._inset.left, this._inset.top));
let bottomRight = this.screenToWorldPoint(new Vector2(stage.stageWidth - this._inset.right, stage.stageHeight - this._inset.bottom));
constructor(targetEntity: Entity = null, cameraStyle: CameraStyle = CameraStyle.lockOn) {
super();
if (this.entity.transform.rotation != 0){
let topRight = this.screenToWorldPoint(new Vector2(stage.stageWidth - this._inset.right, this._inset.top));
let bottomLeft = this.screenToWorldPoint(new Vector2(this._inset.left, stage.stageHeight - this._inset.bottom));
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
this.setZoom(0);
}
let minX = MathHelper.minOf(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
let maxX = MathHelper.maxOf(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
let minY = MathHelper.minOf(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
let maxY = MathHelper.maxOf(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
/**
* entity.transform.position的快速访问
*/
public get position() {
return this.entity.transform.position;
}
this._bounds.location = new Vector2(minX, minY);
this._bounds.width = maxX - minX;
this._bounds.height = maxY - minY;
}else{
this._bounds.location = topLeft;
this._bounds.width = bottomRight.x - topLeft.x;
this._bounds.height = bottomRight.y - topLeft.y;
/**
* entity.transform.position的快速访问
* @param value
*/
public set position(value: Vector2) {
this.entity.transform.position = value;
}
/**
* entity.transform.rotation的快速访问
*/
public get rotation(): number {
return this.entity.transform.rotation;
}
/**
* entity.transform.rotation的快速访问
* @param value
*/
public set rotation(value: number) {
this.entity.transform.rotation = value;
}
public _zoom;
/**
* -11minimumZoom转换为maximumZoom
* /使-11
*/
public get zoom() {
if (this._zoom == 0)
return 1;
if (this._zoom < 1)
return MathHelper.map(this._zoom, this._minimumZoom, 1, -1, 0);
return MathHelper.map(this._zoom, 1, this._maximumZoom, 0, 1);
}
/**
* -11minimumZoom转换为maximumZoom
* /使-11
* @param value
*/
public set zoom(value: number) {
this.setZoom(value);
}
public _minimumZoom = 0.3;
/**
* 0-number.max0.3
*/
public get minimumZoom() {
return this._minimumZoom;
}
/**
* 0-number.max0.3
* @param value
*/
public set minimumZoom(value: number) {
this.setMinimumZoom(value);
}
public _maximumZoom = 3;
/**
* 0-number.max3
*/
public get maximumZoom() {
return this._maximumZoom;
}
/**
* 0-number.max3
* @param value
*/
public set maximumZoom(value: number) {
this.setMaximumZoom(value);
}
public _bounds: Rectangle = new Rectangle();
/**
* -
*/
public get bounds() {
if (this._areMatrixedDirty)
this.updateMatrixes();
if (this._areBoundsDirty) {
// 旋转或非旋转的边界都需要左上角和右下角
let topLeft = this.screenToWorldPoint(new Vector2(this._inset.left, this._inset.top));
let bottomRight = this.screenToWorldPoint(new Vector2(Core.graphicsDevice.viewport.width - this._inset.right,
Core.graphicsDevice.viewport.height - this._inset.bottom));
if (this.entity.transform.rotation != 0) {
// 特别注意旋转的边界。我们需要找到绝对的最小/最大值并从中创建边界
let topRight = this.screenToWorldPoint(new Vector2(Core.graphicsDevice.viewport.width - this._inset.right,
this._inset.top));
let bottomLeft = this.screenToWorldPoint(new Vector2(this._inset.left,
Core.graphicsDevice.viewport.height - this._inset.bottom));
let minX = Math.min(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
let maxX = Math.max(topLeft.x, bottomRight.x, topRight.x, bottomLeft.x);
let minY = Math.min(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
let maxY = Math.max(topLeft.y, bottomRight.y, topRight.y, bottomLeft.y);
this._bounds.location = new Vector2(minX, minY);
this._bounds.width = maxX - minX;
this._bounds.height = maxY - minY;
} else {
this._bounds.location = topLeft;
this._bounds.width = bottomRight.x - topLeft.x;
this._bounds.height = bottomRight.y - topLeft.y;
}
this._areBoundsDirty = false;
}
this._areBoundsDirty = false;
return this._bounds;
}
return this._bounds;
}
public _transformMatrix: Matrix2D = new Matrix2D().identity();
public get zoom(){
if (this._zoom == 0)
return 1;
if (this._zoom < 1)
return MathHelper.map(this._zoom, this._minimumZoom, 1, -1, 0);
return MathHelper.map(this._zoom, 1, this._maximumZoom, 0, 1);
}
public set zoom(value: number){
this.setZoom(value);
}
public get minimumZoom(){
return this._minimumZoom;
}
public set minimumZoom(value: number){
this.setMinimumZoom(value);
}
public get maximumZoom(){
return this._maximumZoom;
}
public set maximumZoom(value: number){
this.setMaximumZoom(value);
}
public get origin(){
return this._origin;
}
public set origin(value: Vector2){
if (this._origin != value){
this._origin = value;
this._areMatrixesDirty = true;
/**
*
*/
public get transformMatrix(): Matrix2D {
if (this._areMatrixedDirty)
this.updateMatrixes();
return this._transformMatrix;
}
}
public get transformMatrix(){
if (this._areBoundsDirty)
public _inverseTransformMatrix: Matrix2D = new Matrix2D().identity();
/**
*
*/
public get inverseTransformMatrix(): Matrix2D {
if (this._areMatrixedDirty)
this.updateMatrixes();
return this._inverseTransformMatrix;
}
public _origin: Vector2 = Vector2.zero;
public get origin() {
return this._origin;
}
public set origin(value: Vector2) {
if (this._origin != value) {
this._origin = value;
this._areMatrixedDirty = true;
}
}
/**
*
* @param newWidth
* @param newHeight
*/
public onSceneSizeChanged(newWidth: number, newHeight: number) {
let oldOrigin = this._origin;
this.origin = new Vector2(newWidth / 2, newHeight / 2);
this.entity.transform.position = Vector2.add(this.entity.transform.position, Vector2.subtract(this._origin, oldOrigin));
}
/**
*
* @param left
* @param right
* @param top
* @param bottom
*/
public setInset(left: number, right: number, top: number, bottom: number): Camera {
this._inset = new CameraInset();
this._inset.left = left;
this._inset.right = right;
this._inset.top = top;
this._inset.bottom = bottom;
this._areBoundsDirty = true;
return this;
}
/**
* entity.transform.setPosition快速访问
* @param position
*/
public setPosition(position: Vector2) {
this.entity.transform.setPosition(position.x, position.y);
return this;
}
/**
* entity.transform.setRotation的快速访问
* @param rotation
*/
public setRotation(rotation: number): Camera {
this.entity.transform.setRotation(rotation);
return this;
}
/**
* -11minimumZoom转换为maximumZoom
* /使-11
* @param zoom
*/
public setZoom(zoom: number): Camera {
let newZoom = MathHelper.clamp(zoom, -1, 1);
if (newZoom == 0) {
this._zoom = 1;
} else if (newZoom < 0) {
this._zoom = MathHelper.map(newZoom, -1, 0, this._minimumZoom, 1);
} else {
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
}
this._areMatrixedDirty = true;
return this;
}
/**
* 0-number.max 0.3
* @param minZoom
*/
public setMinimumZoom(minZoom: number): Camera {
if (minZoom <= 0) {
console.error("minimumZoom must be greater than zero");
return;
}
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
this._minimumZoom = minZoom;
return this;
}
/**
* 0-number.max 3
* @param maxZoom
*/
public setMaximumZoom(maxZoom: number): Camera {
if (maxZoom <= 0) {
console.error("maximumZoom must be greater than zero");
return;
}
if (this._zoom > maxZoom)
this._zoom = maxZoom;
this._maximumZoom = maxZoom;
return this;
}
public onEntityTransformChanged(comp: transform.Component) {
this._areMatrixedDirty = true;
}
public zoomIn(deltaZoom: number) {
this.zoom += deltaZoom;
}
public zoomOut(deltaZoom: number) {
this.zoom -= deltaZoom;
}
/**
*
* @param worldPosition
*/
public worldToScreenPoint(worldPosition: Vector2): Vector2 {
this.updateMatrixes();
return this._transformMatrix;
}
worldPosition = Vector2.transform(worldPosition, this._transformMatrix);
return worldPosition;
}
public get inverseTransformMatrix(){
if (this._areBoundsDirty)
/**
*
* @param screenPosition
*/
public screenToWorldPoint(screenPosition: Vector2): Vector2 {
this.updateMatrixes();
return this._inverseTransformMatrix;
}
constructor() {
super();
this.setZoom(0);
}
public setMinimumZoom(minZoom: number): Camera{
if (this._zoom < minZoom)
this._zoom = this.minimumZoom;
this._minimumZoom = minZoom;
return this;
}
public setMaximumZoom(maxZoom: number): Camera {
if (this._zoom > maxZoom)
this._zoom = maxZoom;
this._maximumZoom = maxZoom;
return this;
}
public setZoom(zoom: number){
let newZoom = MathHelper.clamp(zoom, -1, 1);
if (newZoom == 0){
this._zoom = 1;
} else if(newZoom < 0){
this._zoom = MathHelper.map(newZoom, -1, 0, this._minimumZoom, 1);
} else {
this._zoom = MathHelper.map(newZoom, 0, 1, 1, this._maximumZoom);
screenPosition = Vector2.transform(screenPosition, this._inverseTransformMatrix);
return screenPosition;
}
this._areMatrixesDirty = true;
return this;
}
public initialize() {
}
public update(){
}
public setPosition(position: Vector2){
this.entity.transform.setPosition(position);
return this;
}
public updateMatrixes(){
if (!this._areMatrixesDirty)
return;
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);
/**
*
*/
public mouseToWorldPoint(): Vector2 {
return this.screenToWorldPoint(Input.touchPosition);
}
tempMat = Matrix2D.createTranslation(this._origin.x, this._origin.y, tempMat);
this._transformMatrix = Matrix2D.multiply(this._transformMatrix, tempMat);
public onAddedToEntity() {
this.follow(this._targetEntity, this._cameraStyle);
}
this._inverseTransformMatrix = Matrix2D.invert(this._transformMatrix);
public update() {
let halfScreen = Vector2.multiply(new Vector2(this.bounds.width, this.bounds.height), new Vector2(0.5));
this._worldSpaceDeadZone.x = this.position.x - halfScreen.x * Core.scene.scaleX + this.deadzone.x + this.focusOffset.x;
this._worldSpaceDeadZone.y = this.position.y - halfScreen.y * Core.scene.scaleY + this.deadzone.y + this.focusOffset.y;
this._worldSpaceDeadZone.width = this.deadzone.width;
this._worldSpaceDeadZone.height = this.deadzone.height;
this._areBoundsDirty = true;
this._areMatrixesDirty = false;
}
if (this._targetEntity)
this.updateFollow();
public screenToWorldPoint(screenPosition: Vector2){
this.updateMatrixes();
return Vector2.transform(screenPosition, this._inverseTransformMatrix);
}
this.position = Vector2.lerp(this.position, Vector2.add(this.position, this._desiredPositionDelta), this.followLerp);
this.entity.transform.roundPosition();
public worldToScreenPoint(worldPosition: Vector2){
this.updateMatrixes();
return Vector2.transform(worldPosition, this._transformMatrix);
}
if (this.mapLockEnabled) {
this.position = this.clampToMapSize(this.position);
this.entity.transform.roundPosition();
}
}
public destory() {
/**
*
* @param position
*/
public clampToMapSize(position: Vector2) {
let halfScreen = Vector2.multiply(new Vector2(this.bounds.width, this.bounds.height), new Vector2(0.5)).add(new Vector2(this.mapSize.x, this.mapSize.y));
let cameraMax = new Vector2(this.mapSize.width - halfScreen.x, this.mapSize.height - halfScreen.y);
return Vector2.clamp(position, halfScreen, cameraMax);
}
public updateFollow() {
this._desiredPositionDelta.x = this._desiredPositionDelta.y = 0;
if (this._cameraStyle == CameraStyle.lockOn) {
let targetX = this._targetEntity.transform.position.x;
let targetY = this._targetEntity.transform.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;
}
}
}
public follow(targetEntity: Entity, cameraStyle: CameraStyle = CameraStyle.cameraWindow) {
this._targetEntity = targetEntity;
this._cameraStyle = cameraStyle;
switch (this._cameraStyle) {
case CameraStyle.cameraWindow:
let w = this.bounds.width / 6;
let h = this.bounds.height / 3;
this.deadzone = new Rectangle((this.bounds.width - w) / 2, (this.bounds.height - h) / 2, w, h);
break;
case CameraStyle.lockOn:
this.deadzone = new Rectangle(this.bounds.width / 2, this.bounds.height / 2, 10, 10);
break;
}
}
/**
*
* @param width
* @param height
*/
public setCenteredDeadzone(width: number, height: number) {
this.deadzone = new Rectangle((this.bounds.width - width) / 2, (this.bounds.height - height) / 2, width, height);
}
protected updateMatrixes() {
if (!this._areMatrixedDirty)
return;
let tempMat: Matrix2D;
this._transformMatrix = Matrix2D.create().translate(-this.entity.transform.position.x, -this.entity.transform.position.y);
if (this._zoom != 1) {
tempMat = Matrix2D.create().scale(this._zoom, this._zoom);
this._transformMatrix = this._transformMatrix.multiply(tempMat);
}
if (this.entity.transform.rotation != 0) {
tempMat = Matrix2D.create().rotate(this.entity.transform.rotation);
this._transformMatrix = this._transformMatrix.multiply(tempMat);
}
tempMat = Matrix2D.create().translate(this._origin.x, this._origin.y);
this._transformMatrix = this._transformMatrix.multiply(tempMat);
this._inverseTransformMatrix = this._transformMatrix.invert();
// 无论何时矩阵改变边界都是无效的
this._areBoundsDirty = true;
this._areMatrixedDirty = false;
}
}
}
class CameraInset {
public left;
public right;
public top;
public bottom;
}
@@ -0,0 +1,24 @@
module es {
export 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);
}
}
}
@@ -0,0 +1,10 @@
module es {
/**
*
*/
export class IUpdatableComparer {
public compare(a: Component, b: Component) {
return a.updateOrder - b.updateOrder;
}
}
}
+15 -47
View File
@@ -1,57 +1,25 @@
class Mesh extends Component {
private _verts: VertexPosition[];
private _primitiveCount: number;
private _triangles: number[];
private _topLeftVertPosition: Vector2;
private _width;
private _height;
///<reference path="./RenderableComponent.ts" />
module es {
export class Mesh extends RenderableComponent {
private _mesh: egret.Mesh;
public initialize() {
}
public setVertPosition(positions: Vector2[]){
let createVerts = !this._verts || this._verts.length != positions.length;
if (createVerts)
this._verts = new Array(positions.length);
constructor() {
super();
for (let i = 0; i < this._verts.length; i ++){
this._verts[i] = new VertexPosition(positions[i]);
this._mesh = new egret.Mesh();
}
return this;
}
public setTexture(texture: egret.Texture): Mesh {
this._mesh.texture = texture;
this._mesh.$renderNode = new egret.sys.RenderNode();
public setTriangles(triangles: number[]){
this._primitiveCount = triangles.length / 3;
this._triangles = triangles;
return this;
}
public recalculateBounds(){
this._topLeftVertPosition = new Vector2(Number.MAX_VALUE, Number.MAX_VALUE);
let max = new Vector2(Number.MIN_VALUE, Number.MIN_VALUE);
for (let i = 0; i < this._verts.length; i ++){
this._topLeftVertPosition.x = Math.min(this._topLeftVertPosition.x, this._verts[i].position.x);
this._topLeftVertPosition.y = Math.min(this._topLeftVertPosition.y, this._verts[i].position.y);
max.x = Math.max(max.x, this._verts[i].position.x);
max.y = Math.max(max.y, this._verts[i].position.y);
return this;
}
this._width = max.x - this._topLeftVertPosition.x;
this._height = max.y - this._topLeftVertPosition.y;
public reset() {
}
return this;
}
public render(){
render(camera: es.Camera) {
}
}
}
class VertexPosition{
public position: Vector2;
constructor(position: Vector2){
this.position = position;
}
}
@@ -1,62 +1,85 @@
///<reference path="./Collider.ts" />
class BoxCollider extends Collider {
public get width(){
return (this.shape as Box).width;
}
module es {
export class BoxCollider extends Collider {
/**
* RenderableComponent在实体上
*/
constructor() {
super();
public set width(value: number){
this.setWidth(value);
}
public setWidth(width: number): BoxCollider{
this._colliderRequiresAutoSizing = false;
let box = this.shape as Box;
if (width != box.width){
box.updateBox(width, box.height);
this._isPositionDirty = true;
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
// 我们在这里插入一个1x1框作为占位符,直到碰撞器在下一阵被添加到实体并可以获得更精确的自动调整大小数据
this.shape = new Box(1, 1);
this._colliderRequiresAutoSizing = true;
}
return this;
}
public get height(){
return (this.shape as Box).height;
}
public set height(value: number){
this.setHeight(value);
}
public setHeight(height: number){
this._colliderRequiresAutoSizing = false;
let box = this.shape as Box;
if (height != box.height){
box.updateBox(box.width, height);
this._isPositionDirty = true;
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
}
}
constructor(){
super();
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);
this._isPositionDirty = true;
if (this.entity && this._isParentEntityAddedToScene)
Physics.updateCollider(this);
public get width() {
return (this.shape as Box).width;
}
return this;
public set width(value: number) {
this.setWidth(value);
}
public get height() {
return (this.shape as Box).height;
}
public set height(value: number) {
this.setHeight(value);
}
/**
* BoxCollider的大小
* @param width
* @param height
*/
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;
}
/**
* 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;
}
/**
* 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);
}
}
public toString() {
return `[BoxCollider: bounds: ${this.bounds}]`;
}
}
}
}
@@ -0,0 +1,48 @@
module es {
export class CircleCollider extends Collider {
/**
*
*
* @param radius
*/
constructor(radius?: number) {
super();
if (radius)
this._colliderRequiresAutoSizing = true;
// 我们在这里插入一个1px的圆圈作为占位符
// 直到碰撞器被添加到实体并可以获得更精确的自动调整大小数据的下一帧
this.shape = new Circle(radius ? radius : 1);
}
public get radius(): number {
return (this.shape as Circle).radius;
}
public set radius(value: number) {
this.setRadius(value);
}
/**
*
* @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;
}
public toString() {
return `[CircleCollider: bounds: ${this.bounds}, radius: ${(this.shape as Circle).radius}]`
}
}
}
@@ -1,132 +1,238 @@
abstract class Collider extends Component{
public shape: Shape;
public physicsLayer = 1 << 0;
public isTrigger: boolean;
public registeredPhysicsBounds: Rectangle;
public shouldColliderScaleAndRotationWithTransform = true;
public collidesWithLayers = Physics.allLayers;
module es {
export abstract class Collider extends Component {
/**
*
*/
public shape: Shape;
/**
*
*/
public isTrigger: boolean;
/**
* physicsLayer可以用作过滤器Flags类有帮助位掩码的方法
*/
public physicsLayer = 1 << 0;
/**
* 使
*
*/
public collidesWithLayers = Physics.allLayers;
/**
* true
*/
public shouldColliderScaleAndRotateWithTransform = true;
/**
*
* 使
*/
public registeredPhysicsBounds: Rectangle = new Rectangle();
public _localOffsetLength: number;
public _isPositionDirty: boolean = true;
public _isRotationDirty: boolean = true;
protected _colliderRequiresAutoSizing;
/**
*
*/
protected _isParentEntityAddedToScene;
/**
*
*/
protected _isColliderRegistered;
public _localOffsetLength: number;
public _isPositionDirty = true;
public _isRotationDirty = true;
protected _isParentEntityAddedToScene;
protected _colliderRequiresAutoSizing;
protected _localOffset: Vector2 = new Vector2(0, 0);
protected _isColliderRegistered;
public get bounds(): Rectangle {
if (this._isPositionDirty || this._isRotationDirty){
this.shape.recalculateBounds(this);
this._isPositionDirty = this._isRotationDirty = false;
/**
*
*/
public get absolutePosition(): Vector2 {
return Vector2.add(this.entity.transform.position, this._localOffset);
}
return this.shape.bounds;
}
/**
* transform.rotation
*/
public get rotation(): number {
if (this.shouldColliderScaleAndRotateWithTransform && this.entity)
return this.entity.transform.rotation;
public get localOffset(){
return this._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._isPositionDirty = true;
this.registerColliderWithPhysicsSystem();
return 0;
}
}
public registerColliderWithPhysicsSystem(){
if (this._isParentEntityAddedToScene && !this._isColliderRegistered){
Physics.addCollider(this);
this._isColliderRegistered = true;
}
}
public unregisterColliderWithPhysicsSystem(){
if (this._isParentEntityAddedToScene && this._isColliderRegistered){
Physics.removeCollider(this);
}
this._isColliderRegistered = false;
}
public overlaps(other: Collider){
return this.shape.overlaps(other.shape);
}
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)){
console.error("Only box and circle colliders can be created automatically");
public get bounds(): Rectangle {
if (this._isPositionDirty || this._isRotationDirty) {
this.shape.recalculateBounds(this);
this._isPositionDirty = this._isRotationDirty = false;
}
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable){
let renderbaleBounds = renderable.bounds;
return this.shape.bounds;
}
let width = renderbaleBounds.width / this.entity.transform.scale.x;
let height = renderbaleBounds.height / this.entity.transform.scale.y;
protected _localOffset: Vector2 = Vector2.zero;
if (this instanceof BoxCollider){
let boxCollider = this as BoxCollider;
boxCollider.width = width;
boxCollider.height = height;
/**
* localOffset添加到实体
* /
*/
public get localOffset(): Vector2 {
return this._localOffset;
}
this.localOffset = Vector2.subtract(renderbaleBounds.center, this.entity.transform.position);
/**
* localOffset添加到实体
* /
* @param value
*/
public set localOffset(value: Vector2) {
this.setLocalOffset(value);
}
/**
* localOffset添加到实体
*
* @param offset
*/
public setLocalOffset(offset: Vector2): Collider {
if (this._localOffset != offset) {
this.unregisterColliderWithPhysicsSystem();
this._localOffset = offset;
this._localOffsetLength = this._localOffset.length();
this._isPositionDirty = true;
this.registerColliderWithPhysicsSystem();
}
return this;
}
/**
* true
* @param shouldColliderScaleAndRotationWithTransform
*/
public setShouldColliderScaleAndRotateWithTransform(shouldColliderScaleAndRotationWithTransform: boolean): Collider {
this.shouldColliderScaleAndRotateWithTransform = shouldColliderScaleAndRotationWithTransform;
this._isPositionDirty = this._isRotationDirty = true;
return this;
}
public onAddedToEntity() {
if (this._colliderRequiresAutoSizing) {
if (!(this instanceof BoxCollider || this instanceof CircleCollider)) {
console.error("Only box and circle colliders can be created automatically");
return;
}
let renderable = this.entity.getComponent<RenderableComponent>(RenderableComponent);
if (renderable) {
let renderableBounds = renderable.bounds;
// 这里我们需要大小*反尺度,因为当我们自动调整碰撞器的大小时,它需要没有缩放的渲染
let width = renderableBounds.width / this.entity.scale.x;
let height = renderableBounds.height / this.entity.scale.y;
// 圆碰撞器需要特别注意原点
if (this instanceof CircleCollider) {
this.radius = Math.max(width, height) * 0.5;
} else {
this.width = width;
this.height = height;
}
// 获取渲染的中心,将其转移到本地坐标,并使用它作为碰撞器的localOffset
this.localOffset = Vector2.subtract(renderableBounds.center, this.entity.transform.position);
} else {
console.warn("Collider has no shape and no RenderableComponent. Can't figure out how to size it.");
}
}
this._isParentEntityAddedToScene = true;
this.registerColliderWithPhysicsSystem();
}
this._isParentEntityAddedToScene = true;
this.registerColliderWithPhysicsSystem();
}
public onRemovedFromEntity(){
this.unregisterColliderWithPhysicsSystem();
this._isParentEntityAddedToScene = false;
}
public onEntityTransformChanged(comp: ComponentTransform){
switch (comp){
case ComponentTransform.position:
this._isPositionDirty = true;
break;
case ComponentTransform.scale:
this._isPositionDirty = true;
break;
case ComponentTransform.rotation:
this._isRotationDirty = true;
break;
public onRemovedFromEntity() {
this.unregisterColliderWithPhysicsSystem();
this._isParentEntityAddedToScene = false;
}
if (this._isColliderRegistered)
Physics.updateCollider(this);
}
public onEntityTransformChanged(comp: transform.Component) {
switch (comp) {
case transform.Component.position:
this._isPositionDirty = true;
break;
case transform.Component.scale:
this._isPositionDirty = true;
break;
case transform.Component.rotation:
this._isRotationDirty = true;
break;
}
public onEnabled(){
this.registerColliderWithPhysicsSystem();
this._isPositionDirty = this._isRotationDirty = true;
}
if (this._isColliderRegistered)
Physics.updateCollider(this);
}
public onDisabled(){
this.unregisterColliderWithPhysicsSystem();
public onEnabled() {
this.registerColliderWithPhysicsSystem();
this._isPositionDirty = this._isRotationDirty = true;
}
public onDisabled() {
this.unregisterColliderWithPhysicsSystem();
}
/**
* ()
*/
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): boolean {
return this.shape.overlaps(other.shape);
}
/**
* ()true
* @param collider
* @param motion
* @param result
*/
public collidesWith(collider: Collider, motion: Vector2, result: CollisionResult): boolean {
// 改变形状的位置,使它在移动后的位置,这样我们可以检查重叠
let oldPosition = this.entity.position;
this.entity.position = this.entity.position.add(motion);
let didCollide = this.shape.collidesWithShape(collider.shape, result);
if (didCollide)
result.collider = collider;
// 将图形位置返回到检查前的位置
this.entity.position = oldPosition;
return didCollide;
}
public clone(): Component {
let collider = ObjectUtils.clone<Collider>(this);
collider.entity = null;
if (this.shape)
collider.shape = this.shape.clone();
return collider;
}
}
}
}
@@ -0,0 +1,26 @@
module es {
/**
*
*/
export 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);
}
}
}
@@ -1,4 +1,23 @@
interface ITriggerListener {
onTriggerEnter(other: Collider, local: Collider);
onTriggerExit(other: Collider, local: Collider);
}
module es {
/**
* /退
* ITriggerListener方法将在实现接口的触发器实体上的任何组件上调用
* Mover类一起工作
*/
export interface ITriggerListener {
/**
*
* Mover/ProjectileMover方法处理使
* @param other
* @param local
*/
onTriggerEnter(other: Collider, local: Collider);
/**
*
* @param other
* @param local
*/
onTriggerExit(other: Collider, local: Collider);
}
}
+74 -47
View File
@@ -1,62 +1,89 @@
class Mover extends Component {
private _triggerHelper: ColliderTriggerHelper;
module es {
/**
*
* ITriggerListener接口用于管理对移动过程中违反的任何触发器的回调
* move方法
*
* ITriggerListener
*/
export class Mover extends Component {
private _triggerHelper: ColliderTriggerHelper;
public onAddedToEntity(){
this._triggerHelper = new ColliderTriggerHelper(this.entity);
}
public calculateMovement(motion: Vector2){
let collisionResult = new CollisionResult();
if (!this.entity.getComponent(Collider) || !this._triggerHelper){
return null;
public onAddedToEntity() {
this._triggerHelper = new ColliderTriggerHelper(this.entity);
}
let colliders: Collider[] = this.entity.getComponents(Collider);
for (let i = 0; i < colliders.length; i ++){
let collider = colliders[i];
/**
*
* @param motion
* @param collisionResult
*/
public calculateMovement(motion: Vector2, collisionResult: CollisionResult): boolean {
if (!this.entity.getComponent(Collider) || !this._triggerHelper) {
return false;
}
if (collider.isTrigger)
continue;
// 移动所有的非触发碰撞器并获得最近的碰撞
let colliders: Collider[] = this.entity.getComponents(Collider);
for (let i = 0; i < colliders.length; i++) {
let collider = colliders[i];
let bounds = collider.bounds;
bounds.x += motion.x;
bounds.y += motion.y;
let neighbors = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers);
for (let j = 0; j < neighbors.length; j ++){
let neighbor = neighbors[j];
if (neighbor.isTrigger)
// 不检测触发器 在我们移动后会重新访问它
if (collider.isTrigger)
continue;
let _internalcollisionResult = collider.collidesWith(neighbor, motion);
if (_internalcollisionResult){
motion = Vector2.subtract(motion, _internalcollisionResult.minimumTranslationVector);
// 获取我们在新位置可能发生碰撞的任何东西
let bounds = collider.bounds;
bounds.x += motion.x;
bounds.y += motion.y;
let neighbors = Physics.boxcastBroadphaseExcludingSelf(collider, bounds, collider.collidesWithLayers);
if (_internalcollisionResult.collider){
collisionResult = _internalcollisionResult;
for (let j = 0; j < neighbors.length; j++) {
let neighbor = neighbors[j];
// 不检测触发器
if (neighbor.isTrigger)
continue;
let _internalcollisionResult: CollisionResult = new CollisionResult();
if (collider.collidesWith(neighbor, motion, _internalcollisionResult)) {
// 如果碰撞 则退回之前的移动量
motion = motion.subtract(_internalcollisionResult.minimumTranslationVector);
// 如果我们碰到多个对象,为了简单起见,只取第一个。
if (_internalcollisionResult.collider != null) {
collisionResult = _internalcollisionResult;
}
}
}
}
ListPool.free(colliders);
return collisionResult.collider != null;
}
ListPool.free(colliders);
/**
* calculatemomovement应用到实体并更新triggerHelper
* @param motion
*/
public applyMovement(motion: Vector2) {
// 移动实体到它的新位置,如果我们有一个碰撞,否则移动全部数量。当碰撞发生时,运动被更新
this.entity.position = Vector2.add(this.entity.position, motion);
return collisionResult;
// 对所有是触发器的碰撞器与所有宽相位碰撞器进行重叠检查。任何重叠都会导致触发事件。
if (this._triggerHelper)
this._triggerHelper.update();
}
/**
* calculateMovement和applyMovement来移动考虑碰撞的实体;
* @param motion
* @param collisionResult
*/
public move(motion: Vector2, collisionResult: CollisionResult) {
this.calculateMovement(motion, collisionResult);
this.applyMovement(motion);
return collisionResult.collider != null;
}
}
public applyMovement(motion: Vector2){
this.entity.transform.position = Vector2.add(this.entity.transform.position, motion);
if (this._triggerHelper)
this._triggerHelper.update();
}
public move(motion: Vector2){
let collisionResult = this.calculateMovement(motion);
this.applyMovement(motion);
return collisionResult;
}
}
}
@@ -0,0 +1,58 @@
module es {
/**
* itriggerlistener报告冲突的移动器
*
*/
export 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.length; i++) {
let neighbor = neighbors[i];
if (this._collider.overlaps(neighbor) && neighbor.enabled) {
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;
}
}
}
-12
View File
@@ -1,12 +0,0 @@
class PolygonMesh extends Mesh {
constructor(points: Vector2[], arePointsCCW: boolean = true){
super();
let triangulator = new Triangulator();
triangulator.triangulate(points, arePointsCCW);
this.setVertPosition(points);
this.setTriangles(triangulator.triangleIndices);
this.recalculateBounds();
}
}
@@ -0,0 +1,6 @@
module es {
/** 回收实例的组件类型。 */
export abstract class PooledComponent extends Component {
public abstract reset();
}
}
+184 -53
View File
@@ -1,61 +1,192 @@
/**
*
*/
abstract class RenderableComponent extends Component {
private _isVisible: boolean;
private _areBoundsDirty = true;
private _bounds: Rectangle;
private _localOffset: Vector2;
///<reference path="./PooledComponent.ts" />
module es {
/**
*
*/
export abstract class RenderableComponent extends Component implements IRenderable {
/**
* egret显示对象
*/
public displayObject: egret.DisplayObject = new egret.DisplayObject();
/**
*
*/
public color: number = 0x000000;
protected _areBoundsDirty = true;
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 this.getBounds();
}
protected getWidth(){
return this.bounds.width;
}
protected getHeight(){
return this.bounds.height;
}
protected getBounds(){
if (this._areBoundsDirty){
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, new Vector2(0, 0),
this.entity.transform.scale, this.entity.transform.rotation, this.width, this.height);
this._areBoundsDirty = false;
/**
* renderableComponent的宽度
* bounds属性则需要实现这个
*/
public get width() {
return this.bounds.width;
}
return this._bounds;
}
/**
* renderableComponent的高度
* bounds属性则需要实现这个
*/
public get height() {
return this.bounds.height;
}
protected onBecameVisible(){}
protected _localOffset: Vector2 = Vector2.zero;
protected onBecameInvisible(){}
/**
*
*/
public get localOffset(): Vector2 {
return this._localOffset;
}
public isVisibleFromCamera(camera: Camera): boolean{
this.isVisible = camera.bounds.intersects(this.bounds);
return this.isVisible;
/**
*
* @param value
*/
public set localOffset(value: Vector2) {
this.setLocalOffset(value);
}
protected _renderLayer: number = 0;
/**
*
*/
public get renderLayer(): number {
return this._renderLayer;
}
public set renderLayer(value: number) {
this.setRenderLayer(value);
}
protected _bounds: Rectangle = new Rectangle();
/**
* AABB,
*/
public get bounds(): Rectangle {
if (this._areBoundsDirty) {
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, Vector2.zero,
this.entity.transform.scale, this.entity.transform.rotation, this.width, this.height);
this._areBoundsDirty = false;
}
return this._bounds;
}
private _isVisible: boolean;
/**
* onBecameVisible/onBecameInvisible方法
*/
public get isVisible() {
return this._isVisible;
}
/**
* onBecameVisible/onBecameInvisible方法
* @param value
*/
public set isVisible(value: boolean) {
if (this._isVisible != value) {
this._isVisible = value;
if (this._isVisible)
this.onBecameVisible();
else
this.onBecameInvisible();
}
}
public onEntityTransformChanged(comp: transform.Component) {
this._areBoundsDirty = true;
}
/**
* 使
* @param camera
*/
public abstract render(camera: Camera);
/**
* renderableComponent的边界与camera.bounds相交 true
* isVisible标志的状态开关
* 使
* @param camera
*/
public isVisibleFromCamera(camera: Camera): boolean {
this.isVisible = camera.bounds.intersects(this.bounds);
return this.isVisible;
}
/**
*
* @param renderLayer
*/
public setRenderLayer(renderLayer: number): RenderableComponent {
if (renderLayer != this._renderLayer) {
let oldRenderLayer = this._renderLayer;
this._renderLayer = renderLayer;
// 如果该组件拥有一个实体,那么是由ComponentList管理,需要通知它改变了渲染层
if (this.entity && this.entity.scene)
this.entity.scene.renderableComponents.updateRenderableRenderLayer(this, oldRenderLayer, this._renderLayer);
}
return this;
}
/**
*
* @param color
*/
public setColor(color: number): RenderableComponent {
this.color = color;
return this;
}
/**
*
* @param offset
*/
public setLocalOffset(offset: Vector2): RenderableComponent {
if (this._localOffset != offset) {
this._localOffset = offset;
}
return this;
}
/**
*
*/
public sync(camera: Camera) {
this.displayObject.x = this.entity.position.x + this.localOffset.x - camera.position.x + camera.origin.x;
this.displayObject.y = this.entity.position.y + this.localOffset.y - camera.position.y + camera.origin.y;
this.displayObject.scaleX = this.entity.scale.x;
this.displayObject.scaleY = this.entity.scale.y;
this.displayObject.rotation = this.entity.rotation;
}
public toString() {
return `[RenderableComponent] renderLayer: ${this.renderLayer}`;
}
/**
* renderableComponent进入相机框架时调用
* isVisibleFromCamera进行剔除检查
*/
protected onBecameVisible() {
this.displayObject.visible = this.isVisible;
}
/**
* renderableComponent离开相机框架时调用
* isVisibleFromCamera进行剔除检查
*/
protected onBecameInvisible() {
this.displayObject.visible = this.isVisible;
}
}
}
@@ -0,0 +1,67 @@
///<reference path="./TiledSpriteRenderer.ts"/>
module es {
import Bitmap = egret.Bitmap;
export class ScrollingSpriteRenderer extends TiledSpriteRenderer {
/**
* x自动滚动速度(/s为单位)
*/
public scrollSpeedX = 15;
/**
* y速度(/s为单位)
*/
public scroolSpeedY = 0;
public get textureScale(): Vector2 {
return this._textureScale;
}
public set textureScale(value: Vector2){
this._textureScale = value;
// 重新计算我们的inverseTextureScale和源矩形大小
this._inverseTexScale = new Vector2(1 / this._textureScale.x, 1 / this._textureScale.y);
}
public set scrollWidth(value: number){
this._scrollWidth = value;
}
public get scrollWidth(){
return this._scrollWidth;
}
public set scrollHeight(value: number){
this._scrollHeight = value;
}
public get scrollHeight(){
return this._scrollHeight;
}
private _scrollX = 0;
private _scrollY = 0;
private _scrollWidth = 0;
private _scrollHeight = 0;
constructor(sprite: Sprite) {
super(sprite);
this._scrollWidth = this.width;
this._scrollHeight = this.height;
}
public update() {
if (!this.sprite)
return;
this._scrollX += this.scrollSpeedX * Time.deltaTime;
this._scrollY += this.scroolSpeedY * Time.deltaTime;
this._sourceRect.x = this._scrollX;
this._sourceRect.y = this._scrollY;
this._sourceRect.width = this._scrollWidth + Math.abs(this._scrollX);
this._sourceRect.height = this._scrollHeight + Math.abs(this._scrollY);
}
}
}
+26
View File
@@ -0,0 +1,26 @@
module es {
export 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,11 @@
module es {
export class SpriteAnimation {
public readonly sprites: Sprite[];
public readonly frameRate: number;
constructor(sprites: Sprite[], frameRate: number) {
this.sprites = sprites;
this.frameRate = frameRate;
}
}
}
+164
View File
@@ -0,0 +1,164 @@
///<reference path="./SpriteRenderer.ts" />
module es {
export 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,
}
export enum State {
none,
running,
paused,
completed,
}
export class SpriteAnimator extends SpriteRenderer {
/**
*
*/
public onAnimationCompletedEvent: (string) => {};
/**
*
*/
public speed = 1;
/**
*
*/
public animationState = State.none;
/**
*
*/
public currentAnimation: SpriteAnimation;
/**
*
*/
public currentAnimationName: string;
/**
*
*/
public currentFrame: number;
public _elapsedTime: number = 0;
public _loopMode: LoopMode;
constructor(sprite?: Sprite) {
super(sprite);
}
/**
*
*/
public get isRunning(): boolean {
return this.animationState == State.running;
}
private _animations: Map<string, SpriteAnimation> = new Map<string, SpriteAnimation>();
/** 提供对可用动画列表的访问 */
public get animations() {
return this._animations;
}
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);
// Once和PingPongOnce完成后重置为Time = 0
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];
}
/**
* 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;
}
}
}
+128 -21
View File
@@ -1,24 +1,131 @@
class SpriteRenderer extends RenderableComponent {
private _sprite: egret.DisplayObject;
private _origin: Vector2;
module es {
import Bitmap = egret.Bitmap;
public get sprite(){
return this._sprite;
export class SpriteRenderer extends RenderableComponent {
constructor(sprite: Sprite | egret.Texture = null) {
super();
if (sprite instanceof Sprite)
this.setSprite(sprite);
else if (sprite instanceof egret.Texture)
this.setSprite(new Sprite(sprite));
}
public get bounds() {
if (this._areBoundsDirty) {
if (this._sprite) {
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, this._origin,
this.entity.transform.scale, this.entity.transform.rotation, this._sprite.sourceRect.width,
this._sprite.sourceRect.height);
this._areBoundsDirty = false;
}
}
return this._bounds;
}
/**
*
* x/y 0-1
*/
public get originNormalized(): Vector2 {
return new Vector2(this._origin.x / this.width * this.entity.transform.scale.x,
this._origin.y / this.height * this.entity.transform.scale.y);
}
/**
*
* x/y 0-1
* @param value
*/
public set originNormalized(value: Vector2) {
this.setOrigin(new Vector2(value.x * this.width / this.entity.transform.scale.x,
value.y * this.height / this.entity.transform.scale.y));
}
protected _origin: Vector2;
/**
*
*/
public get origin(): Vector2 {
return this._origin;
}
/**
*
* @param value
*/
public set origin(value: Vector2) {
this.setOrigin(value);
}
protected _sprite: Sprite;
/**
*
* origin
*/
public get sprite(): Sprite {
return this._sprite;
}
/**
*
* origin
* @param value
*/
public set sprite(value: Sprite) {
this.setSprite(value);
}
/**
* sprite.origin
* @param sprite
*/
public setSprite(sprite: Sprite): SpriteRenderer {
this._sprite = sprite;
if (this._sprite) {
this._origin = this._sprite.origin;
this.displayObject.anchorOffsetX = this._origin.x;
this.displayObject.anchorOffsetY = this._origin.y;
}
this.displayObject = new Bitmap(sprite.texture2D);
return this;
}
/**
*
* @param origin
*/
public setOrigin(origin: Vector2): SpriteRenderer {
if (this._origin != origin) {
this._origin = origin;
this.displayObject.anchorOffsetX = this._origin.x;
this.displayObject.anchorOffsetY = this._origin.y;
this._areBoundsDirty = true;
}
return this;
}
/**
*
* x/y 0-1
* @param value
*/
public setOriginNormalized(value: Vector2): SpriteRenderer {
this.setOrigin(new Vector2(value.x * this.width / this.entity.transform.scale.x,
value.y * this.height / this.entity.transform.scale.y));
return this;
}
public render(camera: Camera) {
this.sync(camera);
this.displayObject.x = this.entity.position.x + this.localOffset.x - camera.position.x + camera.origin.x;
this.displayObject.y = this.entity.position.y + this.localOffset.y - camera.position.y + camera.origin.y;
}
}
}
public set sprite(value: egret.DisplayObject){
this.setSprite(value);
}
public setSprite(sprite: egret.DisplayObject): SpriteRenderer{
this._sprite = sprite;
if (this._sprite)
this._origin = new Vector2(this._sprite.anchorOffsetX, this._sprite.anchorOffsetY);
return this;
}
public initialize() {
}
}
@@ -0,0 +1,148 @@
///<reference path="./SpriteRenderer.ts" />
module es {
import Bitmap = egret.Bitmap;
import RenderTexture = egret.RenderTexture;
/**
*
*/
export class TiledSpriteRenderer extends SpriteRenderer {
public get bounds(): Rectangle {
if (this._areBoundsDirty){
if (this._sprite){
this._bounds.calculateBounds(this.entity.transform.position, this._localOffset, this._origin,
this.entity.transform.scale, this.entity.transform.rotation, this.width, this.height);
this._areBoundsDirty = false;
}
}
return this._bounds;
}
/**
* x值
*/
public get scrollX() {
return this._sourceRect.x;
}
/**
* x值
* @param value
*/
public set scrollX(value: number) {
this._sourceRect.x = value;
}
/**
* y值
*/
public get scrollY() {
return this._sourceRect.y;
}
/**
* y值
* @param value
*/
public set scrollY(value: number) {
this._sourceRect.y = value;
}
/**
*
*/
public get textureScale(): Vector2 {
return this._textureScale;
}
/**
*
* @param value
*/
public set textureScale(value: Vector2) {
this._textureScale = value;
// 重新计算我们的inverseTextureScale和源矩形大小
this._inverseTexScale = new Vector2(1 / this._textureScale.x, 1 / this._textureScale.y);
this._sourceRect.width = this._sprite.sourceRect.width * this._inverseTexScale.x;
this._sourceRect.height = this._sprite.sourceRect.height * this._inverseTexScale.y;
}
/**
* TiledSprite可以有一个独立于其纹理的宽度
*/
public get width(): number{
return this._sourceRect.width;
}
public set width(value: number) {
this._areBoundsDirty = true;
this._sourceRect.width = value;
}
public get height(): number {
return this._sourceRect.height;
}
public set height(value: number) {
this._areBoundsDirty = true;
this._sourceRect.height = value;
}
public get gapXY(): Vector2{
return new Vector2(this._gapX, this._gapY);
}
public set gapXY(value: Vector2){
this._gapX = value.x;
this._gapY = value.y;
let renderTexture = new RenderTexture();
let newRectangle = this.sprite.sourceRect;
newRectangle.x = 0;
newRectangle.y = 0;
newRectangle.width += this._gapX;
newRectangle.height += this._gapY;
renderTexture.drawToTexture(this.displayObject, newRectangle);
if (!this.displayObject){
this.displayObject = new Bitmap(renderTexture);
}else{
(this.displayObject as Bitmap).texture = renderTexture;
}
}
protected _sourceRect: Rectangle;
protected _textureScale = Vector2.one;
protected _inverseTexScale = Vector2.one;
private _gapX = 0;
private _gapY = 0;
constructor(sprite: Sprite) {
super(sprite);
this._sourceRect = sprite.sourceRect;
let bitmap = this.displayObject as Bitmap;
bitmap.$fillMode = egret.BitmapFillMode.REPEAT;
}
/**
*
* @param value
*/
public setGapXY(value: Vector2): TiledSpriteRenderer {
this.gapXY = value;
return this;
}
public render(camera: es.Camera) {
super.render(camera);
let bitmap = this.displayObject as Bitmap;
bitmap.width = this.width;
bitmap.height = this.height;
bitmap.scrollRect = this._sourceRect;
}
}
}
+230
View File
@@ -0,0 +1,230 @@
module es {
/**
*
*/
export class Core extends egret.DisplayObjectContainer {
/**
*
*/
public static emitter: Emitter<CoreEvents>;
/**
* 访
*/
public static graphicsDevice: GraphicsDevice;
/**
*
*/
public static content: ContentManager;
/**
* 访
*/
public static _instance: Core;
public _nextScene: Scene;
public _sceneTransition: SceneTransition;
/**
* 访
*/
public _globalManagers: GlobalManager[] = [];
constructor() {
super();
Core._instance = this;
Core.emitter = new Emitter<CoreEvents>();
Core.content = new ContentManager();
this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);
}
/**
* /访
* @constructor
*/
public static get Instance() {
return this._instance;
}
public _scene: Scene;
/**
*
*/
public static get scene() {
if (!this._instance)
return null;
return this._instance._scene;
}
/**
*
* @param value
*/
public static set scene(value: Scene) {
if (!value) {
console.error("场景不能为空");
return;
}
if (this._instance._scene == null) {
this._instance._scene = value;
this._instance.addChild(value);
this._instance._scene.begin();
Core.Instance.onSceneChanged();
} else {
this._instance._nextScene = value;
}
}
/**
* SceneTransition
* @param sceneTransition
*/
public static startSceneTransition<T extends SceneTransition>(sceneTransition: T): T {
if (this._instance._sceneTransition) {
console.warn("在前一个场景完成之前,不能开始一个新的场景转换。");
return;
}
this._instance._sceneTransition = sceneTransition;
return sceneTransition;
}
/**
*
* @param manager
*/
public static registerGlobalManager(manager: es.GlobalManager) {
this._instance._globalManagers.push(manager);
manager.enabled = true;
}
/**
*
* @param manager
*/
public static unregisterGlobalManager(manager: es.GlobalManager) {
this._instance._globalManagers.remove(manager);
manager.enabled = false;
}
/**
* T的全局管理器
* @param type
*/
public static getGlobalManager<T extends es.GlobalManager>(type): T {
for (let i = 0; i < this._instance._globalManagers.length; i++) {
if (this._instance._globalManagers[i] instanceof type)
return this._instance._globalManagers[i] as T;
}
return null;
}
public onOrientationChanged() {
Core.emitter.emit(CoreEvents.OrientationChanged);
}
public async draw() {
if (this._sceneTransition) {
this._sceneTransition.preRender();
// 如果我们有场景转换的特殊处理。我们要么渲染场景过渡,要么渲染场景
if (this._scene && !this._sceneTransition.hasPreviousSceneRender) {
this._scene.render();
this._scene.postRender();
await 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();
}
}
public startDebugUpdate() {
TimeRuler.Instance.startFrame();
TimeRuler.Instance.beginMark("update", 0x00FF00);
}
public endDebugUpdate() {
TimeRuler.Instance.endMark("update");
}
/**
*
*/
public onSceneChanged() {
Core.emitter.emit(CoreEvents.SceneChanged);
Time.sceneChanged();
}
/**
*
*/
protected onGraphicsDeviceReset() {
Core.emitter.emit(CoreEvents.GraphicsDeviceReset);
}
protected initialize() {
}
protected async update() {
// this.startDebugUpdate();
// 更新我们所有的系统管理器
Time.update(egret.getTimer());
if (this._scene) {
for (let i = this._globalManagers.length - 1; i >= 0; i--) {
if (this._globalManagers[i].enabled)
this._globalManagers[i].update();
}
// 仔细阅读:
// 当场景转换发生时,我们不会更新场景
// -除非是不改变场景的场景转换(没有理由不更新)
// -或者它是一个已经切换到新场景的场景转换(新场景需要做它自己的事情)
if (!this._sceneTransition ||
(this._sceneTransition && (!this._sceneTransition.loadsNewScene || this._sceneTransition.isNewSceneLoaded))) {
this._scene.update();
}
if (this._nextScene) {
this.removeChild(this._scene);
this._scene.end();
this._scene = this._nextScene;
this._nextScene = null;
this.onSceneChanged();
this.addChild(this._scene);
await this._scene.begin();
}
}
// this.endDebugUpdate();
await this.draw();
}
private onAddToStage() {
Core.graphicsDevice = new GraphicsDevice();
this.addEventListener(egret.Event.RESIZE, this.onGraphicsDeviceReset, this);
this.addEventListener(egret.StageOrientationEvent.ORIENTATION_CHANGE, this.onOrientationChanged, this);
this.addEventListener(egret.Event.ENTER_FRAME, this.update, this);
Input.initialize();
this.initialize();
}
}
}
+16
View File
@@ -0,0 +1,16 @@
module es {
export enum CoreEvents {
/**
* VRAM将被擦除
*/
GraphicsDeviceReset,
/**
*
*/
SceneChanged,
/**
*
*/
OrientationChanged,
}
}
+405 -236
View File
@@ -1,267 +1,436 @@
class Entity {
private static _idGenerator: number;
module es {
export class Entity {
public static _idGenerator: number = 0;
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;
private _tag: number = 0;
/**
*
*/
public scene: Scene;
/**
*
*/
public name: string;
/**
*
*/
public readonly id: number;
/**
* //
*/
public readonly transform: Transform;
/**
*
*/
public readonly components: ComponentList;
/**
* entity update方法的频率12
*/
public updateInterval: number = 1;
public componentBits: BitSet;
public componentBits: BitSet;
constructor(name: string) {
this.components = new ComponentList(this);
this.transform = new Transform(this);
this.name = name;
this.id = Entity._idGenerator++;
public get parent(){
return this.transform.parent;
}
public set parent(value: Transform){
this.transform.setParent(value);
}
public get position(){
return this.transform.position;
}
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);
}
public get scale(){
return this.transform.scale;
}
public set scale(value: Vector2){
this.transform.setScale(value);
}
public get localScale(){
return this.transform.scale;
}
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 enabled(){
return this._enabled;
}
public set enabled(value: boolean){
this.setEnabled(value);
}
public setEnabled(isEnabled: boolean){
if (this._enabled != isEnabled){
this._enabled = isEnabled;
this.componentBits = new BitSet();
}
return this;
}
public _isDestroyed: boolean;
public get tag(){
return this._tag;
}
/**
* destroytrue
*/
public get isDestroyed() {
return this._isDestroyed;
}
public set tag(value: number){
this.setTag(value);
}
private _tag: number = 0;
constructor(name: string){
this.name = name;
this.transform = new Transform(this);
this.components = new ComponentList(this);
this.id = Entity._idGenerator ++;
/**
* 使使
*/
public get tag(): number {
return this._tag;
}
this.componentBits = new BitSet();
}
/**
* 使使
* @param value
*/
public set tag(value: number) {
this.setTag(value);
}
public get updateOrder(){
return this._updateOrder;
}
private _enabled: boolean = true;
public set updateOrder(value: number){
this.setUpdateOrder(value);
}
/**
* /
*/
public get enabled() {
return this._enabled;
}
public setUpdateOrder(updateOrder: number){
if (this._updateOrder != updateOrder){
this._updateOrder = updateOrder;
if (this.scene){
/**
* /
* @param value
*/
public set enabled(value: boolean) {
this.setEnabled(value);
}
private _updateOrder: number = 0;
/**
* updateOrder还用于对scene.entities上的标签列表进行排序
*/
public get updateOrder() {
return this._updateOrder;
}
/**
* updateOrder还用于对scene.entities上的标签列表进行排序
* @param value
*/
public set updateOrder(value: number) {
this.setUpdateOrder(value);
}
public get parent(): Transform {
return this.transform.parent;
}
public set parent(value: Transform) {
this.transform.setParent(value);
}
public get childCount() {
return this.transform.childCount;
}
public get position(): Vector2 {
return this.transform.position;
}
public set position(value: Vector2) {
this.transform.setPosition(value.x, value.y);
}
public get localPosition(): Vector2 {
return this.transform.localPosition;
}
public set localPosition(value: Vector2) {
this.transform.setLocalPosition(value);
}
public get rotation(): number {
return this.transform.rotation;
}
public set rotation(value: number) {
this.transform.setRotation(value);
}
public get rotationDegrees(): number {
return this.transform.rotationDegrees;
}
public set rotationDegrees(value: number) {
this.transform.setRotationDegrees(value);
}
public get localRotation(): number {
return this.transform.localRotation;
}
public set localRotation(value: number) {
this.transform.setLocalRotation(value);
}
public get localRotationDegrees(): number {
return this.transform.localRotationDegrees;
}
public set localRotationDegrees(value: number) {
this.transform.setLocalRotationDegrees(value);
}
public get scale(): Vector2 {
return this.transform.scale;
}
public set scale(value: Vector2) {
this.transform.setScale(value);
}
public get localScale(): Vector2 {
return this.transform.localScale;
}
public set localScale(value: Vector2) {
this.transform.setLocalScale(value);
}
public get worldInverseTransform(): Matrix2D {
return this.transform.worldInverseTransform;
}
public get localToWorldTransform(): Matrix2D {
return this.transform.localToWorldTransform;
}
public get worldToLocalTransform(): Matrix2D {
return this.transform.worldToLocalTransform;
}
public onTransformChanged(comp: transform.Component) {
// 通知我们的子项改变了位置
this.components.onEntityTransformChanged(comp);
}
/**
*
* @param tag
*/
public setTag(tag: number): Entity {
if (this._tag != tag) {
// 我们只有在已经有场景的情况下才会调用entityTagList。如果我们还没有场景,我们会被添加到entityTagList
if (this.scene)
this.scene.entities.removeFromTagList(this);
this._tag = tag;
if (this.scene)
this.scene.entities.addToTagList(this);
}
return this;
}
}
public setTag(tag: number): Entity{
if (this._tag != tag){
if (this.scene){
this.scene.entities.removeFromTagList(this);
/**
*
* @param isEnabled
*/
public setEnabled(isEnabled: boolean) {
if (this._enabled != isEnabled) {
this._enabled = isEnabled;
if (this._enabled)
this.components.onEntityEnabled();
else
this.components.onEntityDisabled();
}
this._tag = tag;
if (this.scene){
this.scene.entities.addToTagList(this);
return this;
}
/**
* updateOrder还用于对scene.entities上的标签列表进行排序
* @param updateOrder
*/
public setUpdateOrder(updateOrder: number) {
if (this._updateOrder != updateOrder) {
this._updateOrder = updateOrder;
if (this.scene) {
this.scene.entities.markEntityListUnsorted();
this.scene.entities.markTagUnsorted(this.tag);
}
return this;
}
}
return this;
}
/**
*
*/
public destroy() {
this._isDestroyed = true;
this.scene.entities.remove(this);
this.transform.parent = null;
public attachToScene(newScene: Scene){
this.scene = newScene;
newScene.entities.add(this);
this.components.registerAllComponents();
for (let i = 0; i < this.transform.childCount; i ++){
this.transform.getChild(i).entity.attachToScene(newScene);
}
}
public detachFromScene(){
this.scene.entities.remove(this);
this.components.deregisterAllComponents();
for (let i = 0; i < this.transform.childCount; i ++)
this.transform.getChild(i).entity.detachFromScene();
}
public addComponent<T extends Component>(component: T): T{
component.entity = this;
this.components.add(component);
component.initialize();
return component;
}
public hasComponent<T extends Component>(type){
return this.components.getComponent<T>(type, false) != null;
}
public getOrCreateComponent<T extends Component>(type: T){
let comp = this.components.getComponent<T>(type, true);
if (!comp){
comp = this.addComponent<T>(type);
// 销毁所有子项
for (let i = this.transform.childCount - 1; i >= 0; i--) {
let child = this.transform.getChild(i);
child.entity.destroy();
}
}
return comp;
}
/**
* 下面的生命周期方法将被调用在组件上:OnRemovedFromEntity
*/
public detachFromScene() {
this.scene.entities.remove(this);
this.components.deregisterAllComponents();
public getComponent<T extends Component>(type): T{
return this.components.getComponent(type, false) as T;
}
public getComponents(typeName: string | any, componentList?){
return this.components.getComponents(typeName, componentList);
}
public removeComponentForType<T extends Component>(type){
let comp = this.getComponent<T>(type);
if (comp){
this.removeComponent(comp);
return true;
for (let i = 0; i < this.transform.childCount; i++)
this.transform.getChild(i).entity.detachFromScene();
}
return false;
}
/**
*
* @param newScene
*/
public attachToScene(newScene: Scene) {
this.scene = newScene;
newScene.entities.add(this);
this.components.registerAllComponents();
public removeComponent(component: Component){
this.components.remove(component);
}
for (let i = 0; i < this.transform.childCount; i++) {
this.transform.getChild(i).entity.attachToScene(newScene);
}
}
public removeAllComponents(){
for (let i = 0; i < this.components.count; i ++){
this.removeComponent(this.components.buffer[i]);
/**
*
* CopyFrom方法
* !!
* @param position
*/
public clone(position: Vector2 = new Vector2()): Entity {
let entity = new Entity(this.name + "(clone)");
entity.copyFrom(this);
entity.transform.position = position;
return entity;
}
/**
*
*/
public onAddedToScene() {
}
/**
*
*/
public onRemovedFromScene() {
// 如果已经被销毁了,移走我们的组件。如果我们只是分离,我们需要保持我们的组件在实体上。
if (this._isDestroyed)
this.components.removeAllComponents();
}
/**
*
*/
public update() {
this.components.update();
}
/**
*
* @param component
*/
public addComponent<T extends Component>(component: T): T {
component.entity = this;
this.components.add(component);
component.initialize();
return component;
}
/**
* T的第一个组件并返回它null
* @param type
*/
public getComponent<T extends Component>(type): T {
return this.components.getComponent(type, false) as T;
}
/**
*
* @param type
*/
public hasComponent<T extends Component>(type) {
return this.components.getComponent<T>(type, false) != null;
}
/**
* T的第一个组件并返回它
* @param type
*/
public getOrCreateComponent<T extends Component>(type: T) {
let comp = this.components.getComponent<T>(type, true);
if (!comp) {
comp = this.addComponent<T>(type);
}
return comp;
}
/**
* typeName类型的所有组件使
* @param typeName
* @param componentList
*/
public getComponents(typeName: string | any, componentList?) {
return this.components.getComponents(typeName, componentList);
}
/**
*
* @param component
*/
public removeComponent(component: Component) {
this.components.remove(component);
}
/**
* T的第一个组件
* @param type
*/
public removeComponentForType<T extends Component>(type) {
let comp = this.getComponent<T>(type);
if (comp) {
this.removeComponent(comp);
return true;
}
return false;
}
/**
*
*/
public removeAllComponents() {
for (let i = 0; i < this.components.count; i++) {
this.removeComponent(this.components.buffer[i]);
}
}
public compareTo(other: Entity): number {
let compare = this._updateOrder - other._updateOrder;
if (compare == 0)
compare = this.id - other.id;
return compare;
}
public toString(): string {
return `[Entity: name: ${this.name}, tag: ${this.tag}, enabled: ${this.enabled}, depth: ${this.updateOrder}]`;
}
/**
*
* @param entity
*/
protected copyFrom(entity: Entity) {
this.tag = entity.tag;
this.updateInterval = entity.updateInterval;
this.updateOrder = entity.updateOrder;
this.enabled = entity.enabled;
this.transform.scale = entity.transform.scale;
this.transform.rotation = entity.transform.rotation;
for (let i = 0; i < entity.components.count; i++)
this.addComponent(entity.components.buffer[i].clone());
for (let i = 0; i < entity.components._componentsToAdd.length; i++)
this.addComponent(entity.components._componentsToAdd[i].clone());
for (let i = 0; i < entity.transform.childCount; i++) {
let child = entity.transform.getChild(i).entity;
let childClone = child.clone();
childClone.transform.copyFrom(child.transform);
childClone.transform.parent = this.transform;
}
}
}
public update(){
this.components.update();
this.transform.updateTransform();
}
public onAddedToScene(){
}
public onRemovedFromScene(){
if (this._isDestoryed)
this.components.remove
}
public onTransformChanged(comp: ComponentTransform){
this.components.onEntityTransformChanged(comp);
}
public destory(){
this._isDestoryed = true;
this.scene.entities.remove(this);
this.transform.parent = null;
for (let i = this.transform.childCount - 1; i >= 0; i --){
let child = this.transform.getChild(i);
child.entity.destory();
}
}
}
}

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