From c0a6e8d05191f3ff2edf0ec24b710b15dc1b10b7 Mon Sep 17 00:00:00 2001 From: Evoleo Date: Fri, 29 Nov 2024 02:06:07 +0300 Subject: [PATCH] server-side entity origin x/y --- Client/rooms/r1v1/r1v1.yy | 4 +- Client/sprites/sPlayer/sPlayer.yy | 6 +- Client/sprites/sWarpPortal/sWarpPortal.yy | 6 +- TypescriptServer/src/concepts/entity.ts | 99 ++++++++++++++------ TypescriptServer/src/entities/player.ts | 10 +- TypescriptServer/src/entities/warp_portal.ts | 5 + TypescriptServer/src/initializers/08_ping.ts | 4 + 7 files changed, 95 insertions(+), 39 deletions(-) diff --git a/Client/rooms/r1v1/r1v1.yy b/Client/rooms/r1v1/r1v1.yy index a8c3d66..e647249 100644 --- a/Client/rooms/r1v1/r1v1.yy +++ b/Client/rooms/r1v1/r1v1.yy @@ -32,13 +32,13 @@ {"$GMOverriddenProperty":"v1","%Name":"","name":"","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"propertyId":{"name":"portal_type","path":"objects/oWarpPortal/oWarpPortal.yy",},"resourceType":"GMOverriddenProperty","resourceVersion":"2.0","value":"\"Both\"",}, {"$GMOverriddenProperty":"v1","%Name":"","name":"","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"propertyId":{"name":"warp_id","path":"objects/oWarpPortal/oWarpPortal.yy",},"resourceType":"GMOverriddenProperty","resourceVersion":"2.0","value":"2",}, {"$GMOverriddenProperty":"v1","%Name":"","name":"","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"propertyId":{"name":"room_to","path":"objects/oWarpPortal/oWarpPortal.yy",},"resource":{"name":"r1v1","path":"rooms/r1v1/r1v1.yy",},"resourceType":"GMOverriddenProperty","resourceVersion":"2.0","value":"r1v1",}, - ],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":2.0,"scaleY":2.0,"x":1216.0,"y":224.0,}, + ],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":2.0,"scaleY":2.0,"x":1248.0,"y":256.0,}, {"$GMRInstance":"v1","%Name":"inst_1FE54369","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_1FE54369","objectId":{"name":"oWall","path":"objects/oWall/oWall.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":3.0,"scaleY":1.0,"x":1152.0,"y":288.0,}, {"$GMRInstance":"v1","%Name":"inst_8CFA511","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_8CFA511","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"properties":[ {"$GMOverriddenProperty":"v1","%Name":"","name":"","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"propertyId":{"name":"portal_type","path":"objects/oWarpPortal/oWarpPortal.yy",},"resourceType":"GMOverriddenProperty","resourceVersion":"2.0","value":"\"Both\"",}, {"$GMOverriddenProperty":"v1","%Name":"","name":"","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"propertyId":{"name":"warp_id","path":"objects/oWarpPortal/oWarpPortal.yy",},"resourceType":"GMOverriddenProperty","resourceVersion":"2.0","value":"2",}, {"$GMOverriddenProperty":"v1","%Name":"","name":"","objectId":{"name":"oWarpPortal","path":"objects/oWarpPortal/oWarpPortal.yy",},"propertyId":{"name":"room_to","path":"objects/oWarpPortal/oWarpPortal.yy",},"resource":{"name":"r1v1","path":"rooms/r1v1/r1v1.yy",},"resourceType":"GMOverriddenProperty","resourceVersion":"2.0","value":"r1v1",}, - ],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":2.0,"scaleY":2.0,"x":128.0,"y":224.0,}, + ],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":2.0,"scaleY":2.0,"x":160.0,"y":256.0,}, {"$GMRInstance":"v1","%Name":"inst_1877875B","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_1877875B","objectId":{"name":"oPingManager","path":"objects/oPingManager/oPingManager.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":5.0,"scaleY":5.0,"x":0.0,"y":0.0,}, {"$GMRInstance":"v1","%Name":"inst_3838DA3A","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_3838DA3A","objectId":{"name":"oWall","path":"objects/oWall/oWall.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":2.0,"scaleY":1.0,"x":1024.0,"y":288.0,}, {"$GMRInstance":"v1","%Name":"inst_6597467D","colour":4294967295,"frozen":false,"hasCreationCode":false,"ignore":false,"imageIndex":0,"imageSpeed":1.0,"inheritCode":false,"inheritedItemId":null,"inheritItemSettings":false,"isDnd":false,"name":"inst_6597467D","objectId":{"name":"oWall","path":"objects/oWall/oWall.yy",},"properties":[],"resourceType":"GMRInstance","resourceVersion":"2.0","rotation":0.0,"scaleX":3.0,"scaleY":1.0,"x":64.0,"y":288.0,}, diff --git a/Client/sprites/sPlayer/sPlayer.yy b/Client/sprites/sPlayer/sPlayer.yy index b30dac0..bc70451 100644 --- a/Client/sprites/sPlayer/sPlayer.yy +++ b/Client/sprites/sPlayer/sPlayer.yy @@ -23,7 +23,7 @@ ], "name":"sPlayer", "nineSlice":null, - "origin":0, + "origin":4, "parent":{ "name":"Gameplay", "path":"folders/Warp Demo/Sprites/Gameplay.yy", @@ -75,8 +75,8 @@ ], "visibleRange":null, "volume":1.0, - "xorigin":0, - "yorigin":0, + "xorigin":16, + "yorigin":16, }, "swatchColours":null, "swfPrecision":2.525, diff --git a/Client/sprites/sWarpPortal/sWarpPortal.yy b/Client/sprites/sWarpPortal/sWarpPortal.yy index c57a0df..d81314b 100644 --- a/Client/sprites/sWarpPortal/sWarpPortal.yy +++ b/Client/sprites/sWarpPortal/sWarpPortal.yy @@ -25,7 +25,7 @@ ], "name":"sWarpPortal", "nineSlice":null, - "origin":0, + "origin":4, "parent":{ "name":"Gameplay", "path":"folders/Warp Demo/Sprites/Gameplay.yy", @@ -83,8 +83,8 @@ ], "visibleRange":null, "volume":1.0, - "xorigin":0, - "yorigin":0, + "xorigin":16, + "yorigin":16, }, "swatchColours":null, "swfPrecision":2.525, diff --git a/TypescriptServer/src/concepts/entity.ts b/TypescriptServer/src/concepts/entity.ts index 0f11111..51a9b3e 100644 --- a/TypescriptServer/src/concepts/entity.ts +++ b/TypescriptServer/src/concepts/entity.ts @@ -53,8 +53,6 @@ class Entity extends EventEmitter { static object_name:string = 'oUnknownEntity'; type: string; object_name: string; - // type = Entity.type; - // object_name = Entity.object_name; is_solid = false; is_static = false; @@ -63,12 +61,14 @@ class Entity extends EventEmitter { pos:Point; // keep in mind that the coordinates are always set to a whole number (to achieve pixel-perfect collisions) spd:Point; // speed in pixels per second, can be fractional angle:number = 0; + origin:Point = {x: 0, y: 0}; // origin from 0 (top/left) to 1 (bottom/right) prev_pos:Point; serialized:SerializedEntity; // save the last serialized version of this entity (to compare changes) base_size:Point = { x: 64, y: 64 }; scale:Point = { x: 1, y: 1 }; + flip:Point = { x: 0, y: 0 }; // the custom variables that need sending with the entitiy @@ -84,6 +84,7 @@ class Entity extends EventEmitter { collider:Collider = null; // a polygon or a circle collider_type:ColliderType|string = 'box'; + collider_origin:Point = {x: 0, y: 0}; collider_radius:number = this.width/2; // only relevant when collider_type is 'circle' collider_vertices:Point[] = []; // if this is not overridden, a default rectangle collider will be used @@ -112,7 +113,7 @@ class Entity extends EventEmitter { if (typeof value === 'string') { this._state = this.states[value]; } - // it's a number + // state is a number // (-1 means keep the old state) else if (value != -1) { this._state = value; @@ -133,14 +134,13 @@ class Entity extends EventEmitter { this.id = crypto.randomUUID(); this.room = room; this.pos = { x, y }; - this.spd = { x: 0, y: 0}; + this.spd = { x: 0, y: 0 }; this.prev_pos = { x, y }; this.type = this.constructor['type']; this.object_name = this.constructor['object_name']; this.createCollider(); - this.collider.entity = this; this.tree.insert(this.collider); } @@ -194,12 +194,15 @@ class Entity extends EventEmitter { } public createCollider(x = this.x, y = this.y) { - let pos = {x: x, y: y}; + let pos = { + x: x + this.width * (this.collider_origin.x - this.origin.x), + y: y + this.height * (this.collider_origin.y - this.origin.y) + }; // create the collider switch(this.collider_type) { case 'box': - this.collider = new BoxCollider(pos, this.width - .01, this.height - .01); + this.collider = new BoxCollider(pos, this.base_size.x - .01, this.base_size.y - .01); break; case 'circle': this.collider = new CircleCollider(pos, this.collider_radius); @@ -212,6 +215,10 @@ class Entity extends EventEmitter { throw 'Unknown collider type: ' + this.collider_type; } + this.collider.setScale(this.xscale, this.yscale); + this.collider.setAngle(this.angle); + // this.tree.updateBody(this.collider); + this.collider.entity = this; } @@ -224,46 +231,72 @@ class Entity extends EventEmitter { this.tree.insert(this.collider); } - protected updateCollider(x = this.x, y = this.y) { - if (this.size.x != this.prev_size.x || this.size.y != this.prev_size.y) { - this.regenerateCollider(x, y); + protected updateCollider(x = this.x, y = this.y, collider = this.collider) { + let pos = { + x: x + this.width * (this.collider_origin.x - this.origin.x), + y: y + this.height * (this.collider_origin.y - this.origin.y) + }; + + if (collider === this.collider) { + collider.setScale(this.xscale, this.yscale); + collider.setAngle(this.angle); + collider.setPosition(pos.x, pos.y); + } + else { + collider.setPosition(x, y); } - this.collider.setAngle(this.angle); - this.collider.setPosition(x, y); - this.tree.updateBody(this.collider); + this.tree.updateBody(collider); } - public checkCollision(x: number = this.x, y: number = this.y, e:Entity):boolean { - this.updateCollider(x, y); - return this.tree.checkCollision(this.collider, e.collider); + public checkCollision(x: number = this.x, y: number = this.y, e:Entity, collider = this.collider):boolean { + this.updateCollider(x, y, collider); + + let result = this.tree.checkCollision(collider, e.collider); + + // move back the collider + if (collider === this.collider) + this.updateCollider(this.x, this.y); + + return result; } - public placeMeeting(x:number = this.x, y:number = this.y, type:EntityType|string = 'solid'):boolean { - this.updateCollider(x, y); + public placeMeeting(x:number = this.x, y:number = this.y, type:EntityType|string = 'solid', collider = this.collider):boolean { + this.updateCollider(x, y, collider); this.prev_size = {x: this.size.x, y: this.size.y} - return this.tree.checkOne(this.collider, (res) => { + let result = this.tree.checkOne(this.collider, (res) => { let e = res.b.entity; - return e.matchesType(type); + return e && e.matchesType(type); }); + + // move back the collider + if (collider === this.collider) + this.updateCollider(this.x, this.y); + + return result; } - public placeMeetingAll(x:number = this.x, y:number = this.y, type:EntityType|string = 'solid'):T[] { - this.updateCollider(x, y); + public placeMeetingAll(x:number = this.x, y:number = this.y, type:EntityType|string = 'solid', collider = this.collider):T[] { + this.updateCollider(x, y, collider); let entities = []; - this.tree.checkOne(this.collider, (res) => { + this.tree.checkOne(collider, (res) => { let e = res.b.entity; - if (e.matchesType(type)) + if (e && e.matchesType(type)) entities.push(e); }); + + // move back the collider + if (collider === this.collider) + this.updateCollider(this.x, this.y); + return entities; } isOutsideRoom(x = this.x, y = this.y):boolean { - let bbox = this.bbox; // this is an optimization btw + let bbox = this.bbox; // don't call the getter every time return bbox.left - this.x + x > this.room.width || bbox.right - this.x + x < 0 @@ -301,8 +334,11 @@ class Entity extends EventEmitter { // removes the entity from the room (and triggers the 'remove' event) public remove() { - this.emit('remove'); let idx = this.room.entities.indexOf(this); + if (idx === -1) { // already removed + return; + } + this.emit('remove'); this.room.entities.splice(idx, 1); this.tree.remove(this.collider); } @@ -343,11 +379,14 @@ class Entity extends EventEmitter { let x:number = this.x, y:number = this.y; let w:number = this.width, h:number = this.height; + let ox = this.origin.x; + let oy = this.origin.y; + return { - left: x, - top: y, - right: x + w, - bottom: y + h + left: x - w*ox, + top: y - h*oy, + right: x + w*(1-ox), + bottom: y + h*(1-oy) } } diff --git a/TypescriptServer/src/entities/player.ts b/TypescriptServer/src/entities/player.ts index 5509055..a696e31 100644 --- a/TypescriptServer/src/entities/player.ts +++ b/TypescriptServer/src/entities/player.ts @@ -1,5 +1,5 @@ import trace from '#util/logging'; -import Entity from '#concepts/entity'; +import Entity, { ColliderType } from '#concepts/entity'; import Client from '#concepts/client'; import Room from '#concepts/room'; import Point from '#types/point'; @@ -37,6 +37,9 @@ export default class PlayerEntity extends PhysicsEntity { static object_name = 'oPlayer'; collider_type = 'box'; + // collider_type:ColliderType = 'circle'; + // collider_radius: number = 16; + collider_origin = { x: 0, y: 0 }; collision_type = 'discrete' as CollisionType; precise_collisions = true; @@ -56,6 +59,11 @@ export default class PlayerEntity extends PhysicsEntity { y: 2 } + origin = { + x: 0.5, + y: 0.5 + } + states = { idle: 0, walk: 1 }; client:Client; diff --git a/TypescriptServer/src/entities/warp_portal.ts b/TypescriptServer/src/entities/warp_portal.ts index f7127be..d311b3d 100644 --- a/TypescriptServer/src/entities/warp_portal.ts +++ b/TypescriptServer/src/entities/warp_portal.ts @@ -17,6 +17,11 @@ export default class WarpPortal extends Entity { x: 32, y: 32 } + + origin = { + x: 0.5, + y: 0.5 + } collider_type = 'box'; diff --git a/TypescriptServer/src/initializers/08_ping.ts b/TypescriptServer/src/initializers/08_ping.ts index 8361da3..602e866 100644 --- a/TypescriptServer/src/initializers/08_ping.ts +++ b/TypescriptServer/src/initializers/08_ping.ts @@ -1,6 +1,10 @@ const ping_interval = setInterval(() => { global.clients.forEach((c) => { c.sendPing(); + + if (c.reconnect_timer < 0) { + + } }) }, global.config.ping_interval);