Object.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /** @format */
  2. // import { Color, Component, Node, PhysicsSystem, Quat, Vec3, _decorator, ccenum } from 'cc';
  3. import {cBody} from './Body'
  4. import {cCollider} from './Collider'
  5. import {ShapeType, cBox, cCapsule, cShape, cSphere} from './Shape'
  6. import {Data} from '../GameControl'
  7. import Box = cc.Collider.Box
  8. const {ccclass, property} = cc._decorator
  9. cc.Enum(ShapeType)
  10. export enum Trigger {
  11. default = 0,
  12. enter = 1,
  13. stay = 2,
  14. exit = 3,
  15. }
  16. export enum Dirty {
  17. R = 1,
  18. T = 2,
  19. S = 4,
  20. RTS = 7,
  21. RS = R | S,
  22. NON = 0,
  23. }
  24. //从名字获取碰撞分组id, name->group
  25. export const GroupIdxByName = function (name: string) {
  26. const id = cc.game['groupList'].indexOf(name)
  27. return id >= 0 ? 1 << id : 0
  28. }
  29. //从分组id获取碰撞掩码, group->mask
  30. export const MaskBitByGroupIndex = function (groupIndex: number) {
  31. let maskBits = 0
  32. let bits = cc.game['collisionMatrix'][groupIndex]
  33. for (let i = 0; i < bits.length; i++) {
  34. if (!bits[i]) continue
  35. maskBits |= 1 << i
  36. }
  37. return maskBits
  38. }
  39. @ccclass
  40. export class cObject extends cc.Component {
  41. @property()
  42. trigger: boolean = true //碰撞开关
  43. @property({type: ShapeType})
  44. type: ShapeType = ShapeType.Box //相交形状类型
  45. @property({})
  46. center: cc.Vec3 = new cc.Vec3() //偏移位置,是shape相对node节点的中心偏移
  47. @property({
  48. visible() {
  49. return this.type == ShapeType.Box
  50. },
  51. })
  52. size: cc.Vec3 = new cc.Vec3() //方块的长宽高
  53. @property({
  54. visible() {
  55. return this.type != ShapeType.Box
  56. },
  57. })
  58. radius: number = 0 //半径,sphere 或者 capsule
  59. @property({
  60. visible() {
  61. return this.type == ShapeType.Capsule
  62. },
  63. })
  64. height: number = 0 //半高 ,capsule 专用
  65. @property()
  66. agent: boolean = false //碰撞开关
  67. @property({
  68. type: cc.Integer,
  69. visible() {
  70. return this.agent
  71. },
  72. })
  73. priority: number = 0 //Agent避让优先级,越大优先级越高
  74. @property({
  75. visible() {
  76. return this.agent
  77. },
  78. })
  79. maxRadius: number = 0 //Agent碰撞半径,小于等于物体体积
  80. @property({
  81. visible() {
  82. return this.agent
  83. },
  84. })
  85. maxVelocity: number = 0 //Agent最大速度,小于等于物体速度
  86. //常用变量
  87. @property()
  88. velocity: cc.Vec3 = new cc.Vec3(0, 0, 0) //当前速度
  89. speed: number = 0 //最大速度
  90. angle: number = 0 //旋转角度
  91. isDirty: Dirty = Dirty.RTS
  92. shape: cShape = null
  93. body: cBody = null
  94. containsBody: Map<number, cBody> = null
  95. curInBody: number[] = []
  96. curOutBody: number[] = []
  97. onLoad() {}
  98. private _worldScale: cc.Vec3 = new cc.Vec3()
  99. private _worldRTMat3: cc.Mat3 = new cc.Mat3()
  100. private _worldMatrix: cc.Mat4 = new cc.Mat4()
  101. private _worldPosition: cc.Vec3 = new cc.Vec3()
  102. private _worldRotation: cc.Quat = new cc.Quat()
  103. get worldScale() {
  104. this.updateWorldRTS()
  105. //this.node["getWorldScale"](this._worldScale);
  106. return this._worldScale
  107. }
  108. get worldPosition() {
  109. this.updateWorldRTS()
  110. //this.node["getWorldPosition"](this._worldPosition);
  111. return this._worldPosition
  112. }
  113. get worldRotation() {
  114. this.updateWorldRTS()
  115. //this.node["getWorldRotation"](this._worldRotation);
  116. return this._worldRotation
  117. }
  118. get worldRotatioMat3() {
  119. this.updateWorldRTS()
  120. return this._worldRTMat3
  121. }
  122. //同步瞄点,2D专用
  123. setAnchor(anchor: cc.Vec2) {
  124. let c0 = this.center
  125. let c1 = this.shape.center
  126. this.node.setAnchorPoint(anchor)
  127. let s = this.node.getContentSize()
  128. c1.x = (0.5 - anchor.x) * s.width + c0.x
  129. c1.y = (0.5 - anchor.y) * s.height + c0.y
  130. this.isDirty |= Dirty.T
  131. }
  132. //同步角度2D专用
  133. setAngle(angle: number) {
  134. this.node.angle = angle
  135. this.isDirty |= Dirty.R
  136. }
  137. getAngle() {
  138. return this.node.angle
  139. } //旋转角度2d 专用
  140. //同步位置到body
  141. setPosition(position: cc.Vec3) {
  142. this.node.setPosition(position)
  143. this.isDirty |= Dirty.T
  144. }
  145. //同步旋转3D专用
  146. setRotation(rotation: cc.Quat) {
  147. this.node.setRotation(rotation)
  148. this.isDirty |= Dirty.R
  149. }
  150. //同步缩放到body
  151. setScale(scale: cc.Vec3) {
  152. this.node.setScale(scale)
  153. this.isDirty |= Dirty.S
  154. }
  155. private _scale: cc.Vec3 = new cc.Vec3()
  156. private _rotation: cc.Quat = new cc.Quat()
  157. private _position: cc.Vec3 = new cc.Vec3()
  158. getRotation() {
  159. this.node.getRotation(this._rotation)
  160. return this._rotation
  161. }
  162. getPosition() {
  163. this.node.getPosition(this._position)
  164. return this._position
  165. }
  166. getScale() {
  167. this.node.getScale(this._scale)
  168. return this._scale
  169. }
  170. //移除node, 是否回收body ?
  171. remove(retrieve: boolean = true) {
  172. //移除body,是否回收body
  173. cCollider.inst.remove(this.body, retrieve)
  174. //从父节点移除
  175. this.node.removeFromParent(false)
  176. //最后node用户自己控制
  177. //this.remove().destroy() // 马上释放
  178. //pool.push(this.remove()); //回收复用
  179. return this.node
  180. }
  181. //重新添加到父节点
  182. insert(parent: cc.Node) {
  183. cCollider.inst.insert(this.body, true)
  184. //添加到父节点
  185. if (this.node.parent != parent) parent.addChild(this.node)
  186. }
  187. setAnimation(name: string) {}
  188. setColor(color: cc.Color) {}
  189. init(groupIndex: number, entity) {
  190. //创建碰撞形状 暂时只有圆形
  191. switch (this.type) {
  192. case ShapeType.Box:
  193. this.shape = new cBox(this.center, this.size)
  194. break
  195. case ShapeType.Sphere:
  196. this.shape = new cSphere(this.center, this.radius)
  197. break
  198. case ShapeType.Capsule:
  199. this.shape = new cCapsule(this.center, this.radius, this.height)
  200. break
  201. }
  202. // this.node.is3DNode = true; //全局使用3d坐标系
  203. //创建碰撞body容器
  204. this.body = cCollider.inst.create(this)
  205. this.body.entity = entity
  206. // 暂时去掉agent
  207. //this.body.isAgent = this.agent // agent 检测开关
  208. //this.body.priority = this.priority //agent 避让优先级
  209. //this.body.neighborDist = this.maxRadius // agent 体积半径
  210. //this.body.maxVelocity = this.maxVelocity // agent 最大速度
  211. this.body.isAgent = false
  212. this.body.shape = this.shape //绑定碰撞形状
  213. // 动态修改碰撞组
  214. //this.body.group = 1 << this.node.groupIndex //碰撞分组
  215. this.body.group = 1 << groupIndex //碰撞分组
  216. this.body.mask = Data.game.maskBitByGroupIndex(groupIndex) //碰撞掩码
  217. //把body加入碰撞管理 在ecs系统中加入和移除
  218. //cCollider.inst.insert(this.body)
  219. this.isDirty = Dirty.RTS //首次更新标记
  220. //还在碰撞的元素放入碰撞体内
  221. this.containsBody = new Map()
  222. this.curInBody.length = 0
  223. this.curOutBody.length = 0
  224. }
  225. removeNotInBody() {
  226. this.containsBody.forEach((value, key) => {
  227. if (value.isRemove) {
  228. this.containsBody.delete(key)
  229. }
  230. })
  231. }
  232. updateSphereShape(radius) {
  233. this.radius = radius
  234. this.shape = new cSphere(this.center, this.radius)
  235. this.body.shape = this.shape //绑定碰撞形状
  236. this.isDirty = Dirty.RTS
  237. }
  238. updateBoxShape(x, y) {
  239. this.size.x = x
  240. this.size.y = y
  241. this.shape = new cBox(this.center, this.size)
  242. this.body.shape = this.shape //绑定碰撞形状
  243. this.isDirty = Dirty.RTS
  244. }
  245. //trigger 回调 enter,stay exit
  246. onTrigger(b: cBody, trigger: Trigger) {
  247. switch (trigger) {
  248. case Trigger.enter:
  249. //onTriggerEnter();
  250. if (b.entity != 0 && !this.containsBody.has(b.entity)) {
  251. // console.log(
  252. // Data.game.groupList[this.body.group.toString(2).length - 1],
  253. // Data.game.groupList[b.group.toString(2).length - 1],
  254. // '发生碰撞',
  255. // b.entity,
  256. // '进入',
  257. // )
  258. this.containsBody.set(b.entity, b)
  259. this.curInBody.push(b.entity)
  260. }
  261. break
  262. case Trigger.stay:
  263. //onTriggerStay();
  264. break
  265. case Trigger.exit:
  266. //onTriggerExit();
  267. // console.log(
  268. // Data.game.groupList[this.body.group.toString(2).length - 1],
  269. // Data.game.groupList[b.group.toString(2).length - 1],
  270. // '碰撞离开',
  271. // b.entity,
  272. // '离开',
  273. // )
  274. this.containsBody.delete(b.entity)
  275. this.curOutBody.push(b.entity)
  276. break
  277. }
  278. }
  279. onDestroy() {
  280. this.unscheduleAllCallbacks()
  281. this.shape = null
  282. this.body = null
  283. }
  284. updateWorldRTS(dirty: Dirty = Dirty.NON) {
  285. dirty |= this.isDirty
  286. if (dirty == Dirty.NON) return
  287. //更新当前节点世界矩阵
  288. // this.node.getWorldMatrix(this._worldMatrix)
  289. // const m = this._worldMatrix.m
  290. //这是个特别优化,确保上层父节点上已更新的前提下可用
  291. //如果没有正常运行,请使用上面两行代替,或者提前手动刷新parent.getWorldMatrix()
  292. this.node['_calculWorldMatrix']()
  293. const m = this.node['_worldMatrix'].m
  294. if (dirty & Dirty.T) {
  295. const t = this._worldPosition
  296. t.x = m[12]
  297. t.y = m[13]
  298. t.z = m[14]
  299. //console.log('更新世界矩阵', t.x, t.y)
  300. }
  301. const s = this._worldScale
  302. if (dirty & Dirty.S) {
  303. s.x = Math.sqrt(m[0] * m[0] + m[1] * m[1] + m[2] * m[2])
  304. s.y = Math.sqrt(m[4] * m[4] + m[5] * m[5] + m[6] * m[6])
  305. s.z = Math.sqrt(m[8] * m[8] + m[9] * m[9] + m[10] * m[10])
  306. }
  307. const m3 = this._worldRTMat3.m
  308. if (dirty & Dirty.R) {
  309. const sx = 1.0 / s.x,
  310. sy = 1.0 / s.y,
  311. sz = 1.0 / s.z
  312. m3[0] = m[0] * sx
  313. m3[1] = m[1] * sx
  314. m3[2] = m[2] * sx
  315. m3[3] = m[4] * sy
  316. m3[4] = m[5] * sy
  317. m3[5] = m[6] * sy
  318. m3[6] = m[8] * sz
  319. m3[7] = m[9] * sz
  320. m3[8] = m[10] * sz
  321. cc.Quat.fromMat3(this._worldRotation, this._worldRTMat3)
  322. }
  323. }
  324. }