fix castingVision giving vision to neutrals

This commit is contained in:
2025-01-24 14:41:30 +09:00
parent de3c175914
commit 2b2336bf70
11 changed files with 72 additions and 55 deletions
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 B

After

Width:  |  Height:  |  Size: 95 B

File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 B

+51 -42
View File
@@ -36,6 +36,8 @@ const teamMaterials = {
redTransparent: new THREE.MeshToonMaterial({ color: 0xff4444, transparent: true, opacity }), redTransparent: new THREE.MeshToonMaterial({ color: 0xff4444, transparent: true, opacity }),
projectile: new THREE.MeshToonMaterial({ color: 0xff00ff, transparent: true, opacity }), projectile: new THREE.MeshToonMaterial({ color: 0xff00ff, transparent: true, opacity }),
range: new THREE.MeshToonMaterial({ color: 0x00ffff, transparent: true, opacity: opacity / 2 }), 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 // TODO: draw lines of path for minimap camera
@@ -70,9 +72,9 @@ const preloadGLTF = function loadTemplate(path) {
gltfLoader.load(path, (loadedGLTF) => gltf[path] = loadedGLTF) 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) { if (gltf[path] == null) {
setTimeout(() => addGLTF(scene, path, id), 200) setTimeout(() => addGLTF(scene, path, id, additionalSteps), 200)
return return
} }
@@ -89,6 +91,7 @@ const addGLTF = function addGLTF(scene, path, id) {
}) })
model.scale.set(scale, scale, scale) model.scale.set(scale, scale, scale)
additionalSteps(model)
scene.add(model) scene.add(model)
} }
@@ -208,6 +211,7 @@ var websocket = null
global.websocket = null global.websocket = null
var timerId = null var timerId = null
var playerId = null var playerId = null
var playerTeam = null
function connectWebSocket() { function connectWebSocket() {
websocket = new WebSocket(`ws://${window.location.hostname}:1280/ws`) websocket = new WebSocket(`ws://${window.location.hostname}:1280/ws`)
@@ -236,6 +240,11 @@ function connectWebSocket() {
tweenDuration = 1000 / stateUpdates.tickRate 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) { if (stateUpdates.width != null && stateUpdates.height != null) {
state.width = stateUpdates.width state.width = stateUpdates.width
state.height = stateUpdates.height 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)) { for (const e of Object.values(entities)) {
e.userData.flaggedForRemoval = true e.userData.flaggedForRemoval = true
} }
for (const e of state.entities ?? []) { for (const e of state.entities ?? []) {
let entity let entity
let created = false
if (e.id == playerId && playerTeam != e.team) {
playerTeam = e.team
}
if (e.id in entities) { if (e.id in entities) {
entity = entities[e.id] entity = entities[e.id]
} }
@@ -335,17 +345,19 @@ function connectWebSocket() {
// const entityMaterial = teamMaterials[e.team] // const entityMaterial = teamMaterials[e.team]
// entity = new THREE.Mesh(new THREE.CylinderGeometry(e.visualRadius / 100, e.visualRadius / 100, e.height / 50), entityMaterial) // entity = new THREE.Mesh(new THREE.CylinderGeometry(e.visualRadius / 100, e.visualRadius / 100, e.height / 50), entityMaterial)
// TODO: change entity material // TODO: change entity material
created = true
entity = new THREE.Group() entity = new THREE.Group()
entity.rotation.x = Math.PI / 2 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.type = 'entity'
entity.userData.id = e.id entity.userData.id = e.id
entity.position.set(e.position.x / 100, e.position.y / 100, 0) entity.position.set(e.position.x / 100, e.position.y / 100, 0)
scene.add(entity) scene.add(entity)
const hpMargin = 4.8 const hpMargin = 0.5
const maxHp = new THREE.Sprite(new THREE.SpriteMaterial({ color: 0xd03333 })) 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.scale.set(1.5, 0.2, 1)
maxHp.layers.set(1) maxHp.layers.set(1)
entity.add(maxHp) entity.add(maxHp)
@@ -358,36 +370,20 @@ function connectWebSocket() {
const teamMaterial = teamMaterials[`${e.team}Transparent`] const teamMaterial = teamMaterials[`${e.team}Transparent`]
const teamMarker = new THREE.Mesh(new THREE.CylinderGeometry(1, 0.00001, 1), teamMaterial) 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) entity.add(teamMarker)
const buffMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, transparent: true, opacity: 0.4 }) const buffMaterial = new THREE.MeshToonMaterial({ color: 0xffff00, transparent: true, opacity: 0.4 })
const buffMarkerRadius = 0.6 const buffMarker = new THREE.Mesh(new THREE.TorusGeometry(0.95, 0.15), buffMaterial)
const buffMarker = new THREE.Mesh(new THREE.CylinderGeometry(buffMarkerRadius, buffMarkerRadius, 0.3), buffMaterial) buffMarker.rotation.x = Math.PI / 2
buffMarker.position.y = 2
buffMarker.layers.set(1) buffMarker.layers.set(1)
buffMarker.visible = false buffMarker.visible = false
entity.add(buffMarker) 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 rangeMaterial = teamMaterials['range']
// const rangeSize = e.visionRange ?? 0
const rangeSize = (state.abilities.find((it) => it.id == e.abilities?.a)?.range ?? 0) + e.radius 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) 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.layers.set(1)
rangeMarker.visible = false rangeMarker.visible = false
entity.add(rangeMarker) entity.add(rangeMarker)
@@ -397,10 +393,22 @@ function connectWebSocket() {
modelRotationBase.layers.set(1) modelRotationBase.layers.set(1)
entity.add(modelRotationBase) entity.add(modelRotationBase)
addGLTF(modelRotationBase, 'models/generic-player-placeholder.gltf', e.id) const visionRangeMaterial = teamMaterials['visionRange']
const animations = animationActions[e.id] ?? {} const visionRangeSize = e.visionRange ?? 0
if (e.dead) { const visionRangeMarker = new THREE.Mesh(new THREE.CylinderGeometry(visionRangeSize / e.visualRadius, visionRangeSize / e.visualRadius, 0.001), visionRangeMaterial)
animations.dead?.reset().play() 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 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 entity.children.at(2).visible = e.buffs.some((it) => it.id == 'exposed') // TODO: only works for Exposed now
const animations = animationActions[e.id] ?? {} const animations = animationActions[e.id] ?? {}
const fadeIn = 0.15 const fadeIn = created ? 0 : 0.15
if (e.dead) { if (e.dead) {
if (!animations.dead?.isRunning()) { if (!animations.dead?.isRunning()) {
@@ -433,26 +441,25 @@ function connectWebSocket() {
} }
entity.userData.flaggedForRemoval = false entity.userData.flaggedForRemoval = false
entity.children.at(3).rotation.y = e.rotation const oldRotationY = entity.children.at(4).rotation.y
const oldRotationY = entity.children.at(5).rotation.y
const newRotationY = e.rotation - (Math.PI / 2) const newRotationY = e.rotation - (Math.PI / 2)
if (Math.abs((oldRotationY - (2 * Math.PI)) - newRotationY) < Math.abs(oldRotationY - newRotationY)) { 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)) { 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() 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 hp = entity.children.at(0).children.at(0)
const percentageHp = e.health / e.maxHealth const percentageHp = e.health / e.maxHealth
hp.scale.x = percentageHp hp.scale.x = percentageHp
hp.position.x = -(1 - percentageHp) / 2 hp.position.x = -(1 - percentageHp) / 2
entity.children.at(4).visible = e.id == playerId entity.children.at(3).visible = e.id == playerId
// entity.children.at(3).children.at(0).visible = e.casting != null // entity.children.at(5).visible = !e.dead && e.team == playerTeam
} }
for (const e of Object.values(entities)) { for (const e of Object.values(entities)) {
@@ -613,7 +620,9 @@ function connectWebSocket() {
} }
window.addEventListener('load', () => { window.addEventListener('load', () => {
preloadGLTF('models/generic-bam-placeholder.gltf')
preloadGLTF('models/generic-player-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()) const params = Object.fromEntries(new URLSearchParams(window.location.search).entries())
playerId = params.id playerId = params.id
+2
View File
@@ -20,6 +20,7 @@ export default class Entity {
health = null health = null
height = null height = null
maxHealth = 1 maxHealth = 1
model = null
position = null position = null
radius = 0 radius = 0
rotation = 0 rotation = 0
@@ -681,6 +682,7 @@ export default class Entity {
owner: this.id, owner: this.id,
position: this.position.clone(), position: this.position.clone(),
visionRange: radius, visionRange: radius,
team: enemyTeam,
}) })
this.game?.spawnProjectile(projectile) this.game?.spawnProjectile(projectile)
+15 -12
View File
@@ -7,9 +7,10 @@ export default class Template {
return { return {
abilities: {}, abilities: {},
logic: this.#basiliskLogic(), logic: this.#basiliskLogic(),
maxHealth: 3000,
model: 'models/generic-bam-placeholder.gltf',
radius: 180, radius: 180,
speed: 230, speed: 230,
maxHealth: 3000,
...overrides, ...overrides,
} }
} }
@@ -19,6 +20,7 @@ export default class Template {
abilities: { a: options.ranged ? Ability.rangedAttack.id : Ability.meleeAttack.id }, abilities: { a: options.ranged ? Ability.rangedAttack.id : Ability.meleeAttack.id },
logic: this.#minionLogic(options.route, (team != Team.blue)), logic: this.#minionLogic(options.route, (team != Team.blue)),
maxHealth: options.ranged ? 300 : 450, 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, pathfindingCooldown: 0.2,
pathfindingObstacleLimit: 0, pathfindingObstacleLimit: 0,
position: options.route?.at(0) ?? options.position ?? new Vector2(0, 0), position: options.route?.at(0) ?? options.position ?? new Vector2(0, 0),
@@ -42,6 +44,7 @@ export default class Template {
}, },
logic: this.#playerLogic, logic: this.#playerLogic,
maxHealth: 600, maxHealth: 600,
model: Team.blue == (overrides.team ?? Team.blue) ? 'models/generic-player-placeholder.gltf' : 'models/generic-player-placeholder-red.gltf',
pathfindingObstacleLimit: 3, pathfindingObstacleLimit: 3,
radius: 65, radius: 65,
spawnPosition: new Vector2(500, 150), spawnPosition: new Vector2(500, 150),
@@ -60,17 +63,17 @@ export default class Template {
const despawnDelay = entity.game?.secToTick(despawnDelaySec) ?? 1 const despawnDelay = entity.game?.secToTick(despawnDelaySec) ?? 1
const timestamp = entity.game?.currentTick ?? 0 const timestamp = entity.game?.currentTick ?? 0
if (entity.dead) { if (entity.dead && diedOnTick == null) { diedOnTick = timestamp }
if (diedOnTick == null) { if (entity.dead && diedOnTick != null && diedOnTick + despawnDelay < timestamp) { entity.despawn() }
diedOnTick = timestamp if (!entity.dead) { diedOnTick = null }
} if (entity.dead) { return }
else if (diedOnTick + despawnDelay < timestamp) {
entity.despawn() const target = entity.closestTargetTo(entity.position, 500)
} if (target == null) { return }
}
else if (diedOnTick != null) { const directionToTarget = target.position.clone().sub(entity.position).normalize()
diedOnTick = null const entityRotationVector = new Vector2(1, 0).rotateAround(new Vector2(), entity.rotation)
} entity.rotation = directionToTarget.clone().add(entityRotationVector).add(entityRotationVector).add(entityRotationVector).angle()
} }
} }