From 2b2336bf7099105da1e573abfd77a737b75a4af0 Mon Sep 17 00:00:00 2001 From: Thayol Date: Fri, 24 Jan 2025 14:41:30 +0900 Subject: [PATCH] fix castingVision giving vision to neutrals --- models/blue.png | Bin 95 -> 95 bytes models/generic-bam-placeholder.bbmodel | 1 + models/generic-bam-placeholder.gltf | 1 + models/generic-player-placeholder-red.gltf | 1 + models/generic-player-placeholder.bbmodel | 2 +- models/neutral.png | Bin 0 -> 543 bytes models/red.png | Bin 0 -> 95 bytes models/white.png | Bin 0 -> 95 bytes public/client.js | 93 +++++++++++---------- src/entity.js | 2 + src/template.js | 27 +++--- 11 files changed, 72 insertions(+), 55 deletions(-) create mode 100644 models/generic-bam-placeholder.bbmodel create mode 100644 models/generic-bam-placeholder.gltf create mode 100644 models/generic-player-placeholder-red.gltf create mode 100644 models/neutral.png create mode 100644 models/red.png create mode 100644 models/white.png diff --git a/models/blue.png b/models/blue.png index 94d13047063e1e4b1b1c8a9ec95fe190b4afe0ff..fc04b755d3a13db331d15a3c0e4c208405d20a19 100644 GIT binary patch delta 43 zcma!#pJ1u>E{QXLvVx_T5$n1_lOCS3j3^P65Lp6ul7@op!`cDHOpN7je<#O(qO>LXvUD*v^PEm2uFz>r39t^tH_g$r}=9 zCAv^SaO1*-Kfr~wxOO4bz5WhYF5C*0S3=bb7cS>s&N-a>>i%e>UR$XFKz-2n#sF|x z^o8>PaP`+Q1^_7^Z}i~c+m#;xaCX`qb^$)US@@050l>wy|2PM@bR=3@x^ed@fb@b* zw)ocYo)sjKj!EKEy^K;2Wp~OH2YZyuKAp1IQGb5^qRNao>Z8`MF-&jM9oC;`^uc^I z3Fdo2o2VVPUb9Q9jM9j5ESJ%KoLi-%oDf@aZV4DEuAPz48hh*2MMgqL+2K635Gsm7 zFHAkjrpRcw+o;h*&8C)-P|Kgh9G6<0U#|!}ngaYvcW7_mYewtPZb znvYGQ83w@`CZ?eg(f3h<0B~*Kbth|^!N7}FU6MzcShbpZ~NIFj(exv literal 0 HcmV?d00001 diff --git a/models/red.png b/models/red.png new file mode 100644 index 0000000000000000000000000000000000000000..dfccf7c0bd5bd5d80b9bbb4fac82486f7f9598f4 GIT binary patch literal 95 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4kiW$h6xih%orFL7>k44ofy`glX=O&z#!@A x;uvDln{1k44ofy`glX=O&z#!@A x;uvDloBZehe|u)lhEA2Mi>2I5c{F($LUWmAD-0JbU|?Wi@O1TaS?83{1OUPB7nlG5 literal 0 HcmV?d00001 diff --git a/public/client.js b/public/client.js index b641d83..87022dc 100644 --- a/public/client.js +++ b/public/client.js @@ -36,6 +36,8 @@ const teamMaterials = { redTransparent: new THREE.MeshToonMaterial({ color: 0xff4444, transparent: true, opacity }), projectile: new THREE.MeshToonMaterial({ color: 0xff00ff, transparent: true, opacity }), range: new THREE.MeshToonMaterial({ color: 0x00ffff, transparent: true, opacity: opacity / 2 }), + visionRange: new THREE.MeshToonMaterial({ color: 0x226022 }), + // visionRange: new THREE.MeshToonMaterial({ color: 0x00ffff, transparent: true, opacity: opacity / 6 }), } // TODO: draw lines of path for minimap camera @@ -70,9 +72,9 @@ const preloadGLTF = function loadTemplate(path) { gltfLoader.load(path, (loadedGLTF) => gltf[path] = loadedGLTF) } -const addGLTF = function addGLTF(scene, path, id) { +const addGLTF = function addGLTF(scene, path, id, additionalSteps = function noAdditionalSteps() {}) { if (gltf[path] == null) { - setTimeout(() => addGLTF(scene, path, id), 200) + setTimeout(() => addGLTF(scene, path, id, additionalSteps), 200) return } @@ -89,6 +91,7 @@ const addGLTF = function addGLTF(scene, path, id) { }) model.scale.set(scale, scale, scale) + additionalSteps(model) scene.add(model) } @@ -208,6 +211,7 @@ var websocket = null global.websocket = null var timerId = null var playerId = null +var playerTeam = null function connectWebSocket() { websocket = new WebSocket(`ws://${window.location.hostname}:1280/ws`) @@ -236,6 +240,11 @@ function connectWebSocket() { tweenDuration = 1000 / stateUpdates.tickRate } + if (stateUpdates.width != null && stateUpdates.height != null && stateUpdates.width != (state.width ?? -1) && stateUpdates.height != (state.height ?? -1) ) { + ground.geometry = new THREE.PlaneGeometry(stateUpdates.width / 100, stateUpdates.height / 100) + ground.position.set(stateUpdates.width / 200, stateUpdates.height / 200, 0) + } + if (stateUpdates.width != null && stateUpdates.height != null) { state.width = stateUpdates.width state.height = stateUpdates.height @@ -317,17 +326,18 @@ function connectWebSocket() { } } - if (state.width != null && state.height != null && (ground.geometry.attributes.width != state.width || ground.geometry.attributes.height != state.height)) { - ground.geometry = new THREE.PlaneGeometry(state.width / 100, state.height / 100) - ground.position.set(state.width / 200, state.height / 200, 0) - } - for (const e of Object.values(entities)) { e.userData.flaggedForRemoval = true } for (const e of state.entities ?? []) { let entity + let created = false + + if (e.id == playerId && playerTeam != e.team) { + playerTeam = e.team + } + if (e.id in entities) { entity = entities[e.id] } @@ -335,17 +345,19 @@ function connectWebSocket() { // const entityMaterial = teamMaterials[e.team] // entity = new THREE.Mesh(new THREE.CylinderGeometry(e.visualRadius / 100, e.visualRadius / 100, e.height / 50), entityMaterial) // TODO: change entity material + created = true + entity = new THREE.Group() entity.rotation.x = Math.PI / 2 - entity.scale.set(e.visualRadius / 100, e.height / 100, e.visualRadius / 100) + entity.scale.set(e.visualRadius / 100, e.visualRadius / 100, e.visualRadius / 100) entity.userData.type = 'entity' entity.userData.id = e.id entity.position.set(e.position.x / 100, e.position.y / 100, 0) scene.add(entity) - const hpMargin = 4.8 + const hpMargin = 0.5 const maxHp = new THREE.Sprite(new THREE.SpriteMaterial({ color: 0xd03333 })) - maxHp.position.set(0, hpMargin, 0) + maxHp.position.set(0, 0, 0) maxHp.scale.set(1.5, 0.2, 1) maxHp.layers.set(1) entity.add(maxHp) @@ -358,36 +370,20 @@ function connectWebSocket() { const teamMaterial = teamMaterials[`${e.team}Transparent`] const teamMarker = new THREE.Mesh(new THREE.CylinderGeometry(1, 0.00001, 1), teamMaterial) - teamMarker.position.y = -0.496 + teamMarker.position.y = -0.493 entity.add(teamMarker) const buffMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, transparent: true, opacity: 0.4 }) - const buffMarkerRadius = 0.6 - const buffMarker = new THREE.Mesh(new THREE.CylinderGeometry(buffMarkerRadius, buffMarkerRadius, 0.3), buffMaterial) - buffMarker.position.y = 2 + const buffMarker = new THREE.Mesh(new THREE.TorusGeometry(0.95, 0.15), buffMaterial) + buffMarker.rotation.x = Math.PI / 2 buffMarker.layers.set(1) buffMarker.visible = false entity.add(buffMarker) - const castingMarkerrotationBase = new THREE.Group() - entity.add(castingMarkerrotationBase) - - const castingMaterial = new THREE.MeshToonMaterial({ color: 0x10dde0, transparent: true, opacity: 0.4 }) - const castingMarker = new THREE.Mesh(new THREE.CylinderGeometry((e.height * 0.9) / 100, (e.height * 0.9) / 100, 1), castingMaterial) - const castingMarkerSize = 800 - castingMarker.rotation.z = Math.PI / 2 - castingMarker.position.x = 1 - castingMarker.position.y = 1 - castingMarker.scale.y = e.height / castingMarkerSize - castingMarker.layers.set(1) - castingMarker.visible = false - castingMarkerrotationBase.add(castingMarker) - const rangeMaterial = teamMaterials['range'] - // const rangeSize = e.visionRange ?? 0 const rangeSize = (state.abilities.find((it) => it.id == e.abilities?.a)?.range ?? 0) + e.radius const rangeMarker = new THREE.Mesh(new THREE.CylinderGeometry(rangeSize / e.visualRadius, rangeSize / e.visualRadius, 0.001), rangeMaterial) - rangeMarker.position.y = 0.002 + rangeMarker.position.y = 0.004 rangeMarker.layers.set(1) rangeMarker.visible = false entity.add(rangeMarker) @@ -397,10 +393,22 @@ function connectWebSocket() { modelRotationBase.layers.set(1) entity.add(modelRotationBase) - addGLTF(modelRotationBase, 'models/generic-player-placeholder.gltf', e.id) - const animations = animationActions[e.id] ?? {} - if (e.dead) { - animations.dead?.reset().play() + const visionRangeMaterial = teamMaterials['visionRange'] + const visionRangeSize = e.visionRange ?? 0 + const visionRangeMarker = new THREE.Mesh(new THREE.CylinderGeometry(visionRangeSize / e.visualRadius, visionRangeSize / e.visualRadius, 0.001), visionRangeMaterial) + visionRangeMarker.position.y = 0.002 + visionRangeMarker.layers.set(1) + visionRangeMarker.visible = false + entity.add(visionRangeMarker) + + if (e.model != null) { + addGLTF(modelRotationBase, e.model, e.id, function(model) { + const box = new THREE.Box3().setFromObject(model) + const size = box.getSize(new THREE.Vector3()) + maxHp.position.set(0, size.y + hpMargin, 0) + buffMarker.position.y = size.y / 2 + buffMarker.scale.z = size.y / 10 + }) } entities[e.id] = entity @@ -411,7 +419,7 @@ function connectWebSocket() { entity.children.at(2).visible = e.buffs.some((it) => it.id == 'exposed') // TODO: only works for Exposed now const animations = animationActions[e.id] ?? {} - const fadeIn = 0.15 + const fadeIn = created ? 0 : 0.15 if (e.dead) { if (!animations.dead?.isRunning()) { @@ -433,26 +441,25 @@ function connectWebSocket() { } entity.userData.flaggedForRemoval = false - entity.children.at(3).rotation.y = e.rotation - const oldRotationY = entity.children.at(5).rotation.y + const oldRotationY = entity.children.at(4).rotation.y const newRotationY = e.rotation - (Math.PI / 2) if (Math.abs((oldRotationY - (2 * Math.PI)) - newRotationY) < Math.abs(oldRotationY - newRotationY)) { - entity.children.at(5).rotation.y = oldRotationY - (2 * Math.PI) + entity.children.at(4).rotation.y = oldRotationY - (2 * Math.PI) } if (Math.abs((oldRotationY + (2 * Math.PI)) - newRotationY) < Math.abs(oldRotationY - newRotationY)) { - entity.children.at(5).rotation.y = oldRotationY + (2 * Math.PI) + entity.children.at(4).rotation.y = oldRotationY + (2 * Math.PI) } positionTweens[entity.id] = new Tween(entity.position).to({ x: e.position.x / 100, y: e.position.y / 100, z: 0 }, tweenDuration).start() - rotationTweens[entity.id] = new Tween(entity.children.at(5).rotation).to({ x: 0, y: newRotationY, z: 0 }, tweenDuration).start() + rotationTweens[entity.id] = new Tween(entity.children.at(4).rotation).to({ x: 0, y: newRotationY, z: 0 }, tweenDuration).start() const hp = entity.children.at(0).children.at(0) const percentageHp = e.health / e.maxHealth hp.scale.x = percentageHp hp.position.x = -(1 - percentageHp) / 2 - entity.children.at(4).visible = e.id == playerId - // entity.children.at(3).children.at(0).visible = e.casting != null + entity.children.at(3).visible = e.id == playerId + // entity.children.at(5).visible = !e.dead && e.team == playerTeam } for (const e of Object.values(entities)) { @@ -613,7 +620,9 @@ function connectWebSocket() { } window.addEventListener('load', () => { + preloadGLTF('models/generic-bam-placeholder.gltf') preloadGLTF('models/generic-player-placeholder.gltf') + preloadGLTF('models/generic-player-placeholder-red.gltf') const params = Object.fromEntries(new URLSearchParams(window.location.search).entries()) playerId = params.id diff --git a/src/entity.js b/src/entity.js index 2171799..3540d4e 100644 --- a/src/entity.js +++ b/src/entity.js @@ -20,6 +20,7 @@ export default class Entity { health = null height = null maxHealth = 1 + model = null position = null radius = 0 rotation = 0 @@ -681,6 +682,7 @@ export default class Entity { owner: this.id, position: this.position.clone(), visionRange: radius, + team: enemyTeam, }) this.game?.spawnProjectile(projectile) diff --git a/src/template.js b/src/template.js index af22e42..393b13f 100644 --- a/src/template.js +++ b/src/template.js @@ -7,9 +7,10 @@ export default class Template { return { abilities: {}, logic: this.#basiliskLogic(), + maxHealth: 3000, + model: 'models/generic-bam-placeholder.gltf', radius: 180, speed: 230, - maxHealth: 3000, ...overrides, } } @@ -19,6 +20,7 @@ export default class Template { abilities: { a: options.ranged ? Ability.rangedAttack.id : Ability.meleeAttack.id }, logic: this.#minionLogic(options.route, (team != Team.blue)), maxHealth: options.ranged ? 300 : 450, + model: Team.blue == (team ?? Team.blue) ? 'models/generic-player-placeholder.gltf' : 'models/generic-player-placeholder-red.gltf', pathfindingCooldown: 0.2, pathfindingObstacleLimit: 0, position: options.route?.at(0) ?? options.position ?? new Vector2(0, 0), @@ -42,6 +44,7 @@ export default class Template { }, logic: this.#playerLogic, maxHealth: 600, + model: Team.blue == (overrides.team ?? Team.blue) ? 'models/generic-player-placeholder.gltf' : 'models/generic-player-placeholder-red.gltf', pathfindingObstacleLimit: 3, radius: 65, spawnPosition: new Vector2(500, 150), @@ -60,17 +63,17 @@ export default class Template { const despawnDelay = entity.game?.secToTick(despawnDelaySec) ?? 1 const timestamp = entity.game?.currentTick ?? 0 - if (entity.dead) { - if (diedOnTick == null) { - diedOnTick = timestamp - } - else if (diedOnTick + despawnDelay < timestamp) { - entity.despawn() - } - } - else if (diedOnTick != null) { - diedOnTick = null - } + if (entity.dead && diedOnTick == null) { diedOnTick = timestamp } + if (entity.dead && diedOnTick != null && diedOnTick + despawnDelay < timestamp) { entity.despawn() } + if (!entity.dead) { diedOnTick = null } + if (entity.dead) { return } + + const target = entity.closestTargetTo(entity.position, 500) + if (target == null) { return } + + const directionToTarget = target.position.clone().sub(entity.position).normalize() + const entityRotationVector = new Vector2(1, 0).rotateAround(new Vector2(), entity.rotation) + entity.rotation = directionToTarget.clone().add(entityRotationVector).add(entityRotationVector).add(entityRotationVector).angle() } }