diff --git a/assets/resources/game/heros/war.prefab b/assets/resources/game/heros/war.prefab index 9ddfa180..ff95cd56 100644 --- a/assets/resources/game/heros/war.prefab +++ b/assets/resources/game/heros/war.prefab @@ -41,10 +41,16 @@ }, { "__id__": 36 + }, + { + "__id__": 38 + }, + { + "__id__": 40 } ], "_prefab": { - "__id__": 38 + "__id__": 42 }, "_lpos": { "__type__": "cc.Vec3", @@ -790,6 +796,74 @@ "__type__": "cc.CompPrefabInfo", "fileId": "37VIdk5BVNxqSq7DlGbRu2" }, + { + "__type__": "cc.BoxCollider2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 39 + }, + "tag": 0, + "_group": 4, + "_density": 1, + "_sensor": false, + "_friction": 0.2, + "_restitution": 0, + "_offset": { + "__type__": "cc.Vec2", + "x": -2.7, + "y": -2.5 + }, + "_size": { + "__type__": "cc.Size", + "width": 87.4, + "height": 77.5 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "ab5bK/AhFOkYq0VRXDd8u9" + }, + { + "__type__": "cc.RigidBody2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 41 + }, + "enabledContactListener": true, + "bullet": true, + "awakeOnLoad": true, + "_group": 4, + "_type": 0, + "_allowSleep": true, + "_gravityScale": 1, + "_linearDamping": 0, + "_angularDamping": 0, + "_linearVelocity": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_angularVelocity": 0, + "_fixedRotation": false, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "8cB93RhXpG8IPDs33L6HGa" + }, { "__type__": "cc.PrefabInfo", "root": { diff --git a/assets/resources/game/map/map_rpg.prefab b/assets/resources/game/map/map_rpg.prefab index 8cc75b27..5c6c7dfd 100644 --- a/assets/resources/game/map/map_rpg.prefab +++ b/assets/resources/game/map/map_rpg.prefab @@ -787,7 +787,7 @@ }, "_type": 0, "_fillType": 0, - "_sizeMode": 1, + "_sizeMode": 0, "_fillCenter": { "__type__": "cc.Vec2", "x": 0, diff --git a/assets/resources/game/monster/monster.prefab b/assets/resources/game/monster/monster.prefab index 20d8e427..0156d59d 100644 --- a/assets/resources/game/monster/monster.prefab +++ b/assets/resources/game/monster/monster.prefab @@ -41,10 +41,16 @@ }, { "__id__": 36 + }, + { + "__id__": 38 + }, + { + "__id__": 40 } ], "_prefab": { - "__id__": 38 + "__id__": 42 }, "_lpos": { "__type__": "cc.Vec3", @@ -790,6 +796,74 @@ "__type__": "cc.CompPrefabInfo", "fileId": "88a6VdbQBB7YwXovYCN2Sy" }, + { + "__type__": "cc.BoxCollider2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 39 + }, + "tag": 1, + "_group": 2, + "_density": 1, + "_sensor": false, + "_friction": 0.2, + "_restitution": 0, + "_offset": { + "__type__": "cc.Vec2", + "x": 3.6, + "y": -2.5 + }, + "_size": { + "__type__": "cc.Size", + "width": 75.1, + "height": 70 + }, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "b2Dt9lJI9FyJCDezkDBPBl" + }, + { + "__type__": "cc.RigidBody2D", + "_name": "", + "_objFlags": 0, + "__editorExtras__": {}, + "node": { + "__id__": 1 + }, + "_enabled": true, + "__prefab": { + "__id__": 41 + }, + "enabledContactListener": true, + "bullet": true, + "awakeOnLoad": true, + "_group": 2, + "_type": 0, + "_allowSleep": true, + "_gravityScale": 1, + "_linearDamping": 0, + "_angularDamping": 0, + "_linearVelocity": { + "__type__": "cc.Vec2", + "x": 0, + "y": 0 + }, + "_angularVelocity": 0, + "_fixedRotation": false, + "_id": "" + }, + { + "__type__": "cc.CompPrefabInfo", + "fileId": "d8rVs6intBQ7lRU8Dw4zXV" + }, { "__type__": "cc.PrefabInfo", "root": { diff --git a/assets/script/Main.ts b/assets/script/Main.ts index 31139bf2..8f813700 100644 --- a/assets/script/Main.ts +++ b/assets/script/Main.ts @@ -23,7 +23,12 @@ export class Main extends Root { protected async run() { smc.initialize = ecs.getEntity(Initialize); - smc.monsters = ['war','magic','heath'] + smc.monsters = [ + {profession:'m1',speed:60}, + {profession:'m2',speed:600}, + {profession:'m3',speed:200}, + {profession:'m4',speed:100}, + ] smc.heros = [ {profession:'war',speed:60}, {profession:'magic',speed:60}, diff --git a/assets/script/game/common/MoveTo.ts b/assets/script/game/common/MoveTo.ts new file mode 100644 index 00000000..d93c65ee --- /dev/null +++ b/assets/script/game/common/MoveTo.ts @@ -0,0 +1,136 @@ +/* + * @Author: dgflash + * @Date: 2021-08-11 16:41:12 + * @LastEditors: dgflash + * @LastEditTime: 2023-01-19 15:27:24 + */ +import { Node, Vec3 } from "cc"; +import { Timer } from "../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer"; +import { Vec3Util } from "../../../../extensions/oops-plugin-framework/assets/core/utils/Vec3Util"; +import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; + +/** 向目标移动,移动过程中目标位置变化会自动修正移动目标点,直到未修正前移动到目标点停止 */ +@ecs.register('MoveTo') +export class MoveToComp extends ecs.Comp { + /** 移动节点 */ + node: Node = null!; + /** 移动方向 */ + velocity: Vec3 = Vec3Util.zero; + /** 移动速度(每秒移动的像素距离) */ + speed: number = 0; + /** 目标实体ECS编号、目标位置 */ + target: Vec3 | Node | null = null; + + /** 坐标标(默认本地坐标) */ + ns: number = Node.NodeSpace.LOCAL; + /** 偏移距离 */ + offset: number = 0; + /** 偏移向量 */ + offsetVector: Vec3 | null = null; + /** 移动完成回调 */ + onComplete: Function | null = null; + /** 距离变化时 */ + onChange: Function | null = null; + + reset() { + this.ns = Node.NodeSpace.LOCAL; + this.offset = 0; + this.target = null; + this.offsetVector = null; + this.onComplete = null; + this.onChange = null; + } +} + +@ecs.register('VariableMoveTo') +class VariableMoveToComponent extends ecs.Comp { + /** 延时触发器 */ + timer: Timer = new Timer(); + /** 终点备份 */ + end: Vec3 | null = null; + /** 目标位置 */ + target!: Vec3; + + reset() { + this.end = null; + this.timer.reset(); + } +} + +/** 跟踪移动到目标位置 */ +export class MoveToSystem extends ecs.ComblockSystem implements ecs.IEntityEnterSystem, ecs.IEntityRemoveSystem, ecs.ISystemUpdate { + filter(): ecs.IMatcher { + return ecs.allOf(MoveToComp); + } + + entityEnter(e: ecs.Entity): void { + e.add(VariableMoveToComponent); + } + + entityRemove(e: ecs.Entity): void { + e.remove(VariableMoveToComponent); + } + + update(e: ecs.Entity) { + let move = e.get(MoveToComp); + let mtv = e.get(VariableMoveToComponent); + let end: Vec3; + + console.assert(move.speed > 0, "移动速度必须要大于零"); + + if (move.target instanceof Node) { + end = move.ns == Node.NodeSpace.WORLD ? move.target.worldPosition : move.target.position; + } + else { + end = move.target as Vec3; + } + + // 目标移动后,重计算移动方向与移动到目标点的速度 + if (mtv.end == null || !mtv.end.strictEquals(end)) { + let target = end.clone(); + if (move.offsetVector) { + target = target.add(move.offsetVector); // 这里的问题 + } + + // 移动方向与移动数度 + let start = move.ns == Node.NodeSpace.WORLD ? move.node.worldPosition : move.node.position; + move.velocity = Vec3Util.sub(target, start).normalize(); + + // 移动时间与目标偏位置计算 + let distance = Vec3.distance(start, target) - move.offset; + + move.onChange?.call(this); + + if (distance - move.offset <= 0) { + this.exit(e); + } + else { + mtv.timer.step = distance / move.speed; + mtv.end = end.clone(); + mtv.target = move.velocity.clone().multiplyScalar(distance).add(start); + } + } + + if (move.speed > 0) { + let trans = Vec3Util.mul(move.velocity, move.speed * this.dt); + move.node.translate(trans, Node.NodeSpace.LOCAL); + } + + // 移动完成事件 + if (mtv.timer.update(this.dt)) { + if (move.ns == Node.NodeSpace.WORLD) + move.node.worldPosition = mtv.target; + else + move.node.position = mtv.target; + + this.exit(e); + } + } + + private exit(e: ecs.Entity) { + let move = e.get(MoveToComp); + move.onComplete?.call(this); + e.remove(VariableMoveToComponent); + e.remove(MoveToComp); + } +} \ No newline at end of file diff --git a/assets/script/game/common/MoveTo.ts.meta b/assets/script/game/common/MoveTo.ts.meta new file mode 100644 index 00000000..a6cfacb5 --- /dev/null +++ b/assets/script/game/common/MoveTo.ts.meta @@ -0,0 +1,9 @@ +{ + "ver": "4.0.23", + "importer": "typescript", + "imported": true, + "uuid": "d233722c-c438-4eb3-ad17-6b407ef7bad0", + "files": [], + "subMetas": {}, + "userData": {} +} diff --git a/assets/script/game/heros/HeroSpineAnimator.ts b/assets/script/game/heros/HeroSpineAnimator.ts index 183bded0..f3776b29 100644 --- a/assets/script/game/heros/HeroSpineAnimator.ts +++ b/assets/script/game/heros/HeroSpineAnimator.ts @@ -20,7 +20,7 @@ export default class HeroSpineAnimator extends Component { private spine!: sp.Skeleton; start() { this.spine = this.getComponent(sp.Skeleton)!; - console.log("HeroSpineAnimator start"); + // console.log("HeroSpineAnimator start"); this.playAnimation(this.animName, this.loop); } @@ -44,9 +44,9 @@ export default class HeroSpineAnimator extends Component { * @param loop 是否循环播放 */ protected playAnimation(animName: string, loop: boolean) { - console.log("HeroSpineAnimator playAnimation"); + // console.log("HeroSpineAnimator playAnimation"); if (animName) { - console.log("HeroSpineAnimator playAnimation animName", animName); + // console.log("HeroSpineAnimator playAnimation animName", animName); this.animName = animName; this.loop = loop; this.spine.setAnimation(0, this.animName, this.loop); diff --git a/assets/script/game/map/view/MapViewComp.ts b/assets/script/game/map/view/MapViewComp.ts index 4098d0bc..7b81e34d 100644 --- a/assets/script/game/map/view/MapViewComp.ts +++ b/assets/script/game/map/view/MapViewComp.ts @@ -8,6 +8,7 @@ import { Hero } from "../../heros/Hero"; // import MapRoadUtils from "./map/road/MapRoadUtils"; import { MapViewScene } from "./MapViewScene"; import { Timer } from "../../../../../extensions/oops-plugin-framework/assets/core/common/timer/Timer"; +import { oops } from "../../../../../extensions/oops-plugin-framework/assets/core/Oops"; const { ccclass, property } = _decorator; @ccclass('MapViewComp') @@ -23,7 +24,13 @@ export class MapViewComp extends CCComp { /** 转场碰撞点对象集合 */ private timer: Timer = new Timer(2); - + onLoad(){ + // 监听全局事件 + oops.message.on("monster_load", this.onMonsterLoaded, this); + } + private onMonsterLoaded(event: string, args: any) { + console.log('on_monster_load', args); + } reset(): void { } @@ -59,7 +66,8 @@ export class MapViewComp extends CCComp { if (smc.monsters.length>0){ let monster = ecs.getEntity(Monster); - monster.load(v3(360,-60)); + monster.load(v3(360,-60),smc.monsters[0].speed); + monster.move(v3(0,-60)); smc.monsters.splice(0,1) } diff --git a/assets/script/game/monster/Monster.ts b/assets/script/game/monster/Monster.ts index c230b004..81bba770 100644 --- a/assets/script/game/monster/Monster.ts +++ b/assets/script/game/monster/Monster.ts @@ -5,7 +5,7 @@ * @LastEditors: dgflash * @LastEditTime: 2022-08-04 15:43:04 */ -import { instantiate, Node, Prefab, Vec3 ,tween} from "cc"; +import { instantiate, Node, Prefab, Vec3 ,tween, v3,Collider2D,Contact2DType,PhysicsSystem2D,IPhysics2DContact} from "cc"; import { UICallbacks } from "../../../../extensions/oops-plugin-framework/assets/core/gui/layer/Defines"; import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; @@ -14,18 +14,22 @@ import { smc } from "../common/SingletonModuleComp"; import { MonsterModelComp } from "./MonsterModelComp"; import { MonsterSpine } from "./MonsterSpine"; import { MonsterViewComp } from "./MonsterViewComp"; -import { MoveTo } from "../../../../extensions/oops-plugin-framework/assets/libs/animator-move/MoveTo"; +import { MoveToComp } from "../common/MoveTo"; +import { GameCollision } from "../../../../extensions/oops-plugin-framework/assets/module/common/GameCollision"; /** 角色实体 */ @ecs.register(`Monster`) export class Monster extends ecs.Entity { // 数据层 MonsterModel!: MonsterModelComp; + GameCollision: GameCollision =new GameCollision(); // 视图层 MonsterView!: MonsterViewComp; + RoleMoveTo!: MoveToComp; // 移动 protected init() { this.addComponents( MonsterModelComp); + } destroy(): void { @@ -34,10 +38,8 @@ export class Monster extends ecs.Entity { } /** 加载角色 */ - load(pos: Vec3 = Vec3.ZERO) { - + load(pos: Vec3 = Vec3.ZERO,speed:number = 100) { var path = "game/monster/monster"; - var prefab: Prefab = oops.res.get(path, Prefab)!; var node = instantiate(prefab); var scene = smc.map.MapView.scene; @@ -46,14 +48,22 @@ export class Monster extends ecs.Entity { node.setPosition(pos) var mv = node.getComponent(MonsterViewComp)!; + mv.speed = speed; + console.log("speed:"+mv.speed) + mv.Tpos = v3(0,0,0); this.add(mv); // node.setScale(-1, 1, 1); - tween(node).to(1, { position: new Vec3(0, -60, 0) }, { - onComplete: () => { - // this.as.walk(); - } - }).start(); + + oops.message.dispatchEvent("monster_load",this) } + /** 移动(ECS System处理逻辑,分享功能独立的业务代码) */ + move(target: Vec3,speed:number = 100) { + var move = this.get(MoveToComp) || this.add(MoveToComp); + move.target = target; + move.node = this.MonsterView.node; + move.speed = speed; + } + } \ No newline at end of file diff --git a/assets/script/game/monster/MonsterModelComp.ts b/assets/script/game/monster/MonsterModelComp.ts index 7141af01..b7aceac4 100644 --- a/assets/script/game/monster/MonsterModelComp.ts +++ b/assets/script/game/monster/MonsterModelComp.ts @@ -16,12 +16,14 @@ export class MonsterModelComp extends ecs.Comp { /** 角色名 */ name: string = "monster"; - + /** speed */ + speed: number = 0; /** 动画名资源 */ anim: string = "monster"; reset() { this.id = -1; + this.speed = 0; this.name = ""; } } diff --git a/assets/script/game/monster/MonsterSpineAnimator.ts b/assets/script/game/monster/MonsterSpineAnimator.ts index e7b96a6c..ea449be8 100644 --- a/assets/script/game/monster/MonsterSpineAnimator.ts +++ b/assets/script/game/monster/MonsterSpineAnimator.ts @@ -20,7 +20,7 @@ export default class MonsterSpineAnimator extends Component { private spine!: sp.Skeleton; start() { this.spine = this.getComponent(sp.Skeleton)!; - console.log("MonsterSpineAnimator start"); + // console.log("MonsterSpineAnimator start"); this.playAnimation(this.animName, this.loop); } @@ -44,9 +44,9 @@ export default class MonsterSpineAnimator extends Component { * @param loop 是否循环播放 */ protected playAnimation(animName: string, loop: boolean) { - console.log("MonsterSpineAnimator playAnimation"); + // console.log("MonsterSpineAnimator playAnimation"); if (animName) { - console.log("MonsterSpineAnimator playAnimation animName", animName); + // console.log("MonsterSpineAnimator playAnimation animName", animName); this.animName = animName; this.loop = loop; this.spine.setAnimation(0, this.animName, this.loop); diff --git a/assets/script/game/monster/MonsterViewComp.ts b/assets/script/game/monster/MonsterViewComp.ts index 76983631..e2d222d3 100644 --- a/assets/script/game/monster/MonsterViewComp.ts +++ b/assets/script/game/monster/MonsterViewComp.ts @@ -5,10 +5,12 @@ * @LastEditTime: 2022-08-17 12:36:18 */ -import { Vec3, _decorator ,tween} from "cc"; +import { Vec3, _decorator ,tween, v3,Collider2D,Contact2DType,PhysicsSystem2D,IPhysics2DContact} from "cc"; import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS"; import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp"; import { MonsterSpine } from "./MonsterSpine"; +import { Monster } from "./Monster"; +import { MonsterModelComp } from "./MonsterModelComp"; const { ccclass, property } = _decorator; @@ -18,16 +20,53 @@ const { ccclass, property } = _decorator; export class MonsterViewComp extends CCComp { /** 角色动画 */ as: MonsterSpine = null!; - /** 角色控制器 */ - + speed: number = 100; + Tpos: Vec3 = v3(0,-60,0); /** 视图层逻辑代码分离演示 */ - onLoad() { - this.as = this.getComponent(MonsterSpine); - //移动到0,-60 - + start () { + // 注册单个碰撞体的回调函数 + console.log('MonsterViewComp start'); + let collider = this.getComponent(Collider2D); + if (collider) { + collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); + collider.on(Contact2DType.END_CONTACT, this.onEndContact, this); + collider.on(Contact2DType.PRE_SOLVE, this.onPreSolve, this); + collider.on(Contact2DType.POST_SOLVE, this.onPostSolve, this); + } + + // 注册全局碰撞回调函数 + if (PhysicsSystem2D.instance) { + console.log('PhysicsSystem2D.instance'); + PhysicsSystem2D.instance.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this); + PhysicsSystem2D.instance.on(Contact2DType.END_CONTACT, this.onEndContact, this); + PhysicsSystem2D.instance.on(Contact2DType.PRE_SOLVE, this.onPreSolve, this); + PhysicsSystem2D.instance.on(Contact2DType.POST_SOLVE, this.onPostSolve, this); + } + } + onBeginContact (selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { + // 只在两个碰撞体开始接触时被调用一次 + console.log('onBeginContact'); + } + onEndContact (selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { + // 只在两个碰撞体结束接触时被调用一次 + console.log('onEndContact'); + } + onPreSolve (selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { + // 每次将要处理碰撞体接触逻辑时被调用 + console.log('onPreSolve'); + } + onPostSolve (selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) { + // 每次处理完碰撞体接触逻辑时被调用 + console.log('onPostSolve'); } - + onLoad() { + this.as = this.getComponent(MonsterSpine); + } + + update(dt: number){ + this.node.setPosition(this.node.position.x-dt*this.speed, this.node.position.y, this.node.position.z); + } reset() { this.node.destroy(); diff --git a/settings/v2/packages/project.json b/settings/v2/packages/project.json index 690d662c..ae2c8358 100644 --- a/settings/v2/packages/project.json +++ b/settings/v2/packages/project.json @@ -22,5 +22,32 @@ "visible": true } }, - "custom_joint_texture_layouts": [] + "custom_joint_texture_layouts": [], + "physics": { + "collisionGroups": [ + { + "index": 1, + "name": "monster" + }, + { + "index": 2, + "name": "hero" + }, + { + "index": 3, + "name": "monster_skill" + }, + { + "index": 4, + "name": "hero_skill" + } + ], + "collisionMatrix": { + "0": 1, + "1": 20, + "2": 10, + "3": 4, + "4": 2 + } + } }