mirror of
https://github.com/solcloud/Counter-Strike.git
synced 2025-02-19 15:45:10 +01:00
update client to threejs v167 modules and add basic visuals for volumetric smokes
This commit is contained in:
parent
2250a3d4b4
commit
f9aa6625f9
@ -33,6 +33,7 @@ const EventList = {
|
||||
ThrowEvent: 11,
|
||||
DropEvent: 12,
|
||||
GrillEvent: 13,
|
||||
SmokeEvent: 14,
|
||||
}
|
||||
|
||||
// server/src/Enum/GameOverReason.php
|
||||
@ -106,6 +107,8 @@ const SoundType = {
|
||||
ITEM_DROP_LAND: 21,
|
||||
FLAME_EXTINGUISH: 22,
|
||||
FLAME_PLAYER_HIT: 23,
|
||||
SMOKE_SPAWN: 24,
|
||||
SMOKE_FADE: 25,
|
||||
}
|
||||
|
||||
// server/src/Enum/ArmorType.php
|
||||
|
@ -109,7 +109,11 @@ export class EventProcessor {
|
||||
}
|
||||
|
||||
eventsCallback[EventList.GrillEvent] = function (data) {
|
||||
game.grillStart(data.position, data.maxTime, data.maxFlames)
|
||||
game.grillStart(data.id, data.position, data.size, data.time, data.count)
|
||||
}
|
||||
|
||||
eventsCallback[EventList.SmokeEvent] = function (data) {
|
||||
game.smokeStart(data.id, data.position, data.size, data.time, data.count)
|
||||
}
|
||||
|
||||
this.#callbacks = eventsCallback
|
||||
|
@ -1,7 +1,9 @@
|
||||
import {EventProcessor} from "./EventProcessor.js";
|
||||
import {Player} from "./Player.js";
|
||||
import {InventorySlot, SoundType} from "./Enums.js";
|
||||
import {SoundRepository} from "./SoundRepository.js";
|
||||
import * as THREE from 'three' // fixme try remove from game, maybe only allow import Vec3...
|
||||
import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js' // todo remove
|
||||
import {EventProcessor} from "./EventProcessor.js"
|
||||
import {Player} from "./Player.js"
|
||||
import {InventorySlot, SoundType} from "./Enums.js"
|
||||
import {SoundRepository} from "./SoundRepository.js"
|
||||
|
||||
export class Game {
|
||||
#world
|
||||
@ -21,13 +23,13 @@ export class Game {
|
||||
#endCallback
|
||||
#soundRepository
|
||||
#hudDebounceTicks = 1
|
||||
#bombTimerId = null;
|
||||
#bombTimerId = null
|
||||
#eventProcessor
|
||||
#dropItems = {};
|
||||
#throwables = {};
|
||||
#flammable = {};
|
||||
#roundIntervalIds = [];
|
||||
#roundDamage = {did: {},got: {}}
|
||||
#dropItems = {}
|
||||
#throwables = {}
|
||||
#volumetrics = {}
|
||||
#roundIntervalIds = []
|
||||
#roundDamage = {did: {}, got: {}}
|
||||
#playerSlotsVisibleModels = [
|
||||
InventorySlot.SLOT_KNIFE, InventorySlot.SLOT_PRIMARY, InventorySlot.SLOT_SECONDARY,
|
||||
InventorySlot.SLOT_BOMB, InventorySlot.SLOT_GRENADE_DECOY, InventorySlot.SLOT_GRENADE_MOLOTOV,
|
||||
@ -56,7 +58,8 @@ export class Game {
|
||||
this.#roundIntervalIds = []
|
||||
Object.keys(this.#dropItems).forEach((id) => this.itemPickUp(id))
|
||||
Object.keys(this.#throwables).forEach((id) => this.removeGrenade(id))
|
||||
Object.keys(this.#flammable).forEach((fireId) => Object.keys(this.#flammable[fireId]).forEach((flameId) => this.destroyFlame(fireId, flameId)))
|
||||
Object.keys(this.#volumetrics).forEach((groupId) => Object.keys(this.#volumetrics[groupId]).forEach((itemId) => this.#world.destroyObject(this.#volumetrics[groupId][itemId])))
|
||||
this.#volumetrics = {}
|
||||
this.#world.reset()
|
||||
}
|
||||
|
||||
@ -97,7 +100,7 @@ export class Game {
|
||||
this.#paused = false
|
||||
this.#hud.clearTopMessage()
|
||||
this.#hud.updateRoundDamage(null)
|
||||
this.#roundDamage = {did: {},got: {}}
|
||||
this.#roundDamage = {did: {}, got: {}}
|
||||
console.log("Game unpause")
|
||||
}
|
||||
|
||||
@ -120,7 +123,7 @@ export class Game {
|
||||
roundEnd(attackersWins, newRoundNumber, score) {
|
||||
let winner = attackersWins ? 'Attackers' : 'Defenders'
|
||||
console.log("Round " + this.#round + " ended. Round wins: " + winner)
|
||||
this.score = score;
|
||||
this.score = score
|
||||
this.#round = newRoundNumber
|
||||
this.#hud.displayTopMessage(winner + ' wins')
|
||||
this.#hud.requestFullScoreBoardUpdate(this.score)
|
||||
@ -200,13 +203,19 @@ export class Game {
|
||||
this.itemPickUp(data.extra.id)
|
||||
}
|
||||
if (data.type === SoundType.FLAME_SPAWN) {
|
||||
this.spawnFlame(data.position, data.extra.size, data.extra.height, data.extra.fire, `${data.position.x}-${data.position.y}-${data.position.z}`)
|
||||
this.spawnFlame(data.position, data.extra.height, data.extra.id, `${data.position.x}-${data.position.y}-${data.position.z}`)
|
||||
}
|
||||
if (data.type === SoundType.SMOKE_SPAWN) {
|
||||
this.spawnSmoke(data.position, data.extra.height, data.extra.id, `${data.position.x}-${data.position.y}-${data.position.z}`)
|
||||
}
|
||||
if (data.type === SoundType.FLAME_EXTINGUISH) {
|
||||
this.destroyFlame(data.extra.fire, `${data.position.x}-${data.position.y}-${data.position.z}`)
|
||||
this.destroyFlame(data.extra.id, `${data.position.x}-${data.position.y}-${data.position.z}`)
|
||||
}
|
||||
if (data.type === SoundType.SMOKE_FADE) {
|
||||
this.smokeFade(data.extra.id)
|
||||
}
|
||||
if (data.type === SoundType.ITEM_DROP_AIR) {
|
||||
const item = this.#dropItems[data.extra.id];
|
||||
const item = this.#dropItems[data.extra.id]
|
||||
item.rotation.x -= 0.1
|
||||
item.rotation.y -= 0.1
|
||||
item.rotation.z -= 0.1
|
||||
@ -216,7 +225,7 @@ export class Game {
|
||||
if (data.item.slot === InventorySlot.SLOT_BOMB) {
|
||||
this.bombDropPosition = data.position
|
||||
}
|
||||
const item = this.#dropItems[data.extra.id];
|
||||
const item = this.#dropItems[data.extra.id]
|
||||
item.rotation.set(0, 0, 0)
|
||||
item.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), Math.random() * 6.28)
|
||||
item.position.set(data.position.x, data.position.y, -data.position.z)
|
||||
@ -225,7 +234,7 @@ export class Game {
|
||||
clearInterval(this.#bombTimerId)
|
||||
}
|
||||
if (data.type === SoundType.GRENADE_AIR || data.type === SoundType.GRENADE_BOUNCE || data.type === SoundType.GRENADE_LAND) {
|
||||
const grenade = this.#throwables[data.extra.id];
|
||||
const grenade = this.#throwables[data.extra.id]
|
||||
grenade.rotation.x += 0.1
|
||||
grenade.rotation.y += 0.1
|
||||
grenade.rotation.z += 0.1
|
||||
@ -266,33 +275,23 @@ export class Game {
|
||||
const direction = grenade.getWorldPosition(new THREE.Vector3()).sub(sightPosition).normalize()
|
||||
if (this.#world.getCamera().getWorldDirection(new THREE.Vector3()).dot(direction) <= 0) { // flash behind spectator
|
||||
this.removeGrenade(throwableId)
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const ray = new THREE.Raycaster(sightPosition, direction)
|
||||
const intersects = ray.intersectObjects([grenade, ...this.getMapObjects()], false);
|
||||
const intersects = ray.intersectObjects([grenade, ...this.getMapObjects()], false)
|
||||
if (intersects.length >= 1 && intersects[0].object === grenade) {
|
||||
this.#hud.showFlashBangScreen()
|
||||
}
|
||||
this.removeGrenade(throwableId)
|
||||
return;
|
||||
return
|
||||
}
|
||||
if (item.slot === InventorySlot.SLOT_GRENADE_SMOKE) {
|
||||
const grenade = this.#throwables[throwableId]
|
||||
const smoke = new THREE.Mesh(new THREE.DodecahedronGeometry(300, 1), new THREE.MeshStandardMaterial({color: 0xdadada}))
|
||||
smoke.material.side = THREE.DoubleSide
|
||||
smoke.position.y = 150
|
||||
grenade.add(smoke)
|
||||
game.#roundIntervalIds.push(setTimeout(() => this.removeGrenade(throwableId), 18000))
|
||||
return;
|
||||
}
|
||||
if (item.slot === InventorySlot.SLOT_GRENADE_MOLOTOV || item.slot === InventorySlot.SLOT_GRENADE_HE) {
|
||||
this.removeGrenade(throwableId)
|
||||
return;
|
||||
if (item.slot === InventorySlot.SLOT_GRENADE_HE) {
|
||||
this.removeGrenade(throwableId) // fixme add some cool effect
|
||||
return
|
||||
}
|
||||
|
||||
console.warn("No handler for grenade: ", item)
|
||||
game.#roundIntervalIds.push(setTimeout(() => this.removeGrenade(throwableId), 1000)) // todo responsive volumetric smokes, etc.
|
||||
game.#roundIntervalIds.push(setTimeout(() => this.removeGrenade(throwableId), 500))
|
||||
}
|
||||
|
||||
itemDrop(item, id) {
|
||||
@ -316,26 +315,67 @@ export class Game {
|
||||
delete this.#throwables[id]
|
||||
}
|
||||
|
||||
grillStart(position, maxTimeMs, maxFlamesCount) {
|
||||
grillStart(fireId, position, size, maxTimeMs, maxPartCount) {
|
||||
this.#volumetrics[fireId] = {}
|
||||
this.#volumetrics[fireId]['size'] = size
|
||||
this.#world.playSound('338301_4811732-lq.mp3', position, false)
|
||||
}
|
||||
|
||||
spawnFlame(point, size, height, fireId, flameId) {
|
||||
if (this.#flammable[fireId] === undefined) {
|
||||
this.#flammable[fireId] = {}
|
||||
}
|
||||
height = lerp(height, randomInt(16, 26), Math.min(Math.sqrt(Object.keys(this.#flammable[fireId]).length) / randomInt(7, 9), 1))
|
||||
spawnFlame(point, height, fireId, partId) {
|
||||
const size = this.#volumetrics[fireId]['size']
|
||||
height = lerp(height, randomInt(16, 26), Math.min(Math.sqrt(Object.keys(this.#volumetrics[fireId]).length) / randomInt(7, 9), 1))
|
||||
const flame = this.#world.spawnFlame(size, height)
|
||||
this.#flammable[fireId][flameId] = flame
|
||||
this.#volumetrics[fireId][partId] = flame
|
||||
flame.position.set(point.x, point.y + (height / 2), -1 * point.z)
|
||||
flame.rotation.x = randomInt(-10, 10) / 100;
|
||||
flame.rotation.x = randomInt(-10, 10) / 100
|
||||
flame.rotateOnWorldAxis(new THREE.Vector3(0, 1, 0), Math.random() * 6.28)
|
||||
}
|
||||
|
||||
destroyFlame(fireId, flameId) {
|
||||
const flame = this.#flammable[fireId][flameId]
|
||||
const flame = this.#volumetrics[fireId][flameId]
|
||||
this.#world.destroyObject(flame)
|
||||
delete this.#flammable[fireId][flameId]
|
||||
delete this.#volumetrics[fireId][flameId]
|
||||
}
|
||||
|
||||
smokeStart(smokeId, position, size, maxTimeMs, maxPartCount) {
|
||||
this.#volumetrics[smokeId] = {}
|
||||
this.#volumetrics[smokeId]['size'] = size
|
||||
this.#volumetrics[smokeId]['count'] = maxPartCount
|
||||
this.#volumetrics[smokeId]['geometries'] = []
|
||||
}
|
||||
|
||||
spawnSmoke(point, height, smokeId, partId) {
|
||||
const size = this.#volumetrics[smokeId]['size']
|
||||
const geo = new THREE.BoxGeometry(size, height, size)
|
||||
geo.translate(point.x, point.y + (geo.parameters.height / 2), -point.z)
|
||||
this.#volumetrics[smokeId]['geometries'].push(geo)
|
||||
|
||||
const len = this.#volumetrics[smokeId]['geometries'].length
|
||||
if (len % 10 !== 0 && len < this.#volumetrics[smokeId]['count']) {
|
||||
return
|
||||
}
|
||||
|
||||
let geometry = BufferGeometryUtils.mergeGeometries(this.#volumetrics[smokeId]['geometries'])
|
||||
geometry = BufferGeometryUtils.mergeVertices(geometry, 2)
|
||||
geometry.computeBoundingBox()
|
||||
let mesh = this.#volumetrics[smokeId]['mesh']
|
||||
if (mesh) {
|
||||
this.#world.destroyObject(mesh)
|
||||
}
|
||||
|
||||
mesh = this.#world.spawnSmoke(geometry)
|
||||
this.#volumetrics[smokeId]['mesh'] = mesh
|
||||
if (len === this.#volumetrics[smokeId]['count']) {
|
||||
this.#volumetrics[smokeId]['range'] = Math.ceil(mesh.geometry.getIndex().count / 50)
|
||||
mesh.geometry.setDrawRange(0, mesh.geometry.getIndex().count)
|
||||
}
|
||||
}
|
||||
|
||||
smokeFade(smokeId) {
|
||||
const range = this.#volumetrics[smokeId]['range']
|
||||
const mesh = this.#volumetrics[smokeId]['mesh']
|
||||
|
||||
this.#roundIntervalIds.push(setInterval(() => mesh.geometry.setDrawRange(0, mesh.geometry.drawRange.count - range), 50))
|
||||
}
|
||||
|
||||
bombPlanted(timeMs, position) {
|
||||
@ -347,7 +387,7 @@ export class Game {
|
||||
this.#hud.bombPlanted(bombSecCount)
|
||||
|
||||
const tenSecWarningSecCount = Math.round(timeMs / 1000 - 10)
|
||||
let tickSecondsCount = 0;
|
||||
let tickSecondsCount = 0
|
||||
let bombTimerId = setInterval(function () {
|
||||
if (tickSecondsCount === bombSecCount) {
|
||||
clearInterval(bombTimerId)
|
||||
@ -356,7 +396,7 @@ export class Game {
|
||||
world.playSound('88532__northern87__woosh-northern87.wav', null, true)
|
||||
}
|
||||
world.playSound('536422__rudmer-rotteveel__setting-electronic-timer-1-beep.wav', position, false)
|
||||
tickSecondsCount++;
|
||||
tickSecondsCount++
|
||||
}, 1000)
|
||||
this.#bombTimerId = bombTimerId
|
||||
}
|
||||
@ -393,7 +433,7 @@ export class Game {
|
||||
}
|
||||
|
||||
this.playerMe = new Player(options.player, this.#world.createPlayerMe())
|
||||
this.players[playerId] = this.playerMe;
|
||||
this.players[playerId] = this.playerMe
|
||||
this.playerSpectate = this.playerMe
|
||||
|
||||
if (this.#readyCallback) {
|
||||
@ -430,7 +470,7 @@ export class Game {
|
||||
const myId = this.playerSpectate.getId()
|
||||
let aliveAvailableSpectateMates = this.getMyTeamPlayers().filter((player) => player.isAlive() && myId !== player.getId())
|
||||
if (aliveAvailableSpectateMates.length === 0) {
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
let ids = aliveAvailableSpectateMates.map((player) => player.getId()).sort()
|
||||
@ -565,7 +605,7 @@ export class Game {
|
||||
#otherPlayersInventoryChanged(player, data) {
|
||||
const world = this.#world
|
||||
const hand = player.get3DObject().getObjectByName('hand')
|
||||
const belt = player.get3DObject().getObjectByName('belt');
|
||||
const belt = player.get3DObject().getObjectByName('belt')
|
||||
|
||||
if (hand.children.length === 1) {
|
||||
const lastHandItemModel = hand.children[0]
|
||||
|
@ -1,3 +1,6 @@
|
||||
import * as THREE from 'three'
|
||||
import {GLTFLoader} from 'three/addons/loaders/GLTFLoader.js';
|
||||
import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js';
|
||||
import {ItemId} from "./Enums.js";
|
||||
|
||||
export class ModelRepository {
|
||||
@ -7,6 +10,7 @@ export class ModelRepository {
|
||||
#meshes = {}
|
||||
#materials = {
|
||||
caps: {},
|
||||
smoke: null,
|
||||
outfitTeam: null,
|
||||
outfitOpponent: null,
|
||||
}
|
||||
@ -16,7 +20,7 @@ export class ModelRepository {
|
||||
#mapObjects = [];
|
||||
|
||||
constructor() {
|
||||
this.#gltfLoader = new THREE.GLTFLoader()
|
||||
this.#gltfLoader = new GLTFLoader()
|
||||
this.#textureLoader = new THREE.TextureLoader()
|
||||
}
|
||||
|
||||
@ -53,7 +57,7 @@ export class ModelRepository {
|
||||
}
|
||||
})
|
||||
|
||||
const sun = new THREE.DirectionalLight(0xffeac2, .9)
|
||||
const sun = new THREE.DirectionalLight(0xffeac2, 4)
|
||||
sun.position.set(4000, 4999, -4000)
|
||||
sun.castShadow = true
|
||||
sun.shadow.mapSize.width = 4096
|
||||
@ -63,7 +67,7 @@ export class ModelRepository {
|
||||
sun.shadow.camera.right = 2000
|
||||
sun.shadow.camera.top = 0
|
||||
sun.shadow.camera.bottom = -3000
|
||||
model.scene.add(sun, new THREE.AmbientLight(0xcfe4bb, .4))
|
||||
model.scene.add(sun, new THREE.AmbientLight(0xcfe4bb, 1))
|
||||
return model.scene
|
||||
})
|
||||
}
|
||||
@ -77,7 +81,7 @@ export class ModelRepository {
|
||||
}
|
||||
|
||||
getPlayer(colorIndex, isOpponent) {
|
||||
const clone = THREE.SkeletonUtils.clone(this.#models.player)
|
||||
const clone = SkeletonUtils.clone(this.#models.player)
|
||||
const player = clone.getObjectByName('player')
|
||||
|
||||
const headWear = player.getObjectByName('Wolf3D_Headwear')
|
||||
@ -101,6 +105,10 @@ export class ModelRepository {
|
||||
return this.#meshes.playerHitMesh.clone()
|
||||
}
|
||||
|
||||
getSmokeMaterial() {
|
||||
return this.#materials.smoke
|
||||
}
|
||||
|
||||
getModelForItem(item) {
|
||||
if (item.id === ItemId.Bomb) {
|
||||
return this.getBomb()
|
||||
@ -235,6 +243,14 @@ export class ModelRepository {
|
||||
const sprite = new THREE.Sprite(material);
|
||||
sprite.scale.set(35, 45, 30);
|
||||
|
||||
|
||||
this.#materials.smoke = new THREE.MeshStandardMaterial({ // todo better material with cool displacement map etc.
|
||||
color: 0x798aa0,
|
||||
map: texture,
|
||||
blending: THREE.AdditiveBlending,
|
||||
side: THREE.FrontSide,
|
||||
})
|
||||
|
||||
this.#meshes.playerHitMesh = sprite
|
||||
}))
|
||||
|
||||
|
@ -1,3 +1,5 @@
|
||||
import {AnimationMixer, Vector3} from 'three'
|
||||
|
||||
export class Player {
|
||||
data = {
|
||||
id: null,
|
||||
@ -45,7 +47,7 @@ export class Player {
|
||||
|
||||
setAnimations(animations) {
|
||||
animations.forEach((clip) => {
|
||||
const mixer = new THREE.AnimationMixer(this.#threeObject)
|
||||
const mixer = new AnimationMixer(this.#threeObject)
|
||||
const action = mixer.clipAction(clip);
|
||||
if (clip.name === 'crouch') {
|
||||
action.play()
|
||||
@ -114,7 +116,7 @@ export class Player {
|
||||
}
|
||||
|
||||
getSightPositionThreeVector() {
|
||||
return new THREE.Vector3(
|
||||
return new Vector3(
|
||||
this.data.position.x,
|
||||
this.data.position.y + this.data.sight,
|
||||
-this.data.position.z,
|
||||
|
@ -136,7 +136,7 @@ export class SoundRepository {
|
||||
if (type === SoundType.FLAME_PLAYER_HIT) {
|
||||
return '512138__beezlefm__item-sound.wav'
|
||||
}
|
||||
if (type === SoundType.FLAME_SPAWN || type === SoundType.FLAME_EXTINGUISH) {
|
||||
if (type === SoundType.FLAME_SPAWN || type === SoundType.FLAME_EXTINGUISH || type === SoundType.SMOKE_SPAWN || type === SoundType.SMOKE_FADE) { // fixme make some noise
|
||||
return null
|
||||
}
|
||||
if (type === SoundType.GRENADE_AIR) {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import * as Enum from "./Enums.js";
|
||||
import {ModelRepository} from "./ModelRepository.js";
|
||||
import * as THREE from 'three'
|
||||
import * as Enum from "./Enums.js"
|
||||
import {RGBELoader} from "three/addons/loaders/RGBELoader.js"
|
||||
import {ModelRepository} from "./ModelRepository.js"
|
||||
|
||||
export class World {
|
||||
#scene
|
||||
@ -9,13 +11,11 @@ export class World {
|
||||
#audioLoader
|
||||
#modelRepository
|
||||
#decals = []
|
||||
#flames = []
|
||||
#cache = {}
|
||||
volume = 30
|
||||
|
||||
constructor() {
|
||||
THREE.Cache.enabled = true
|
||||
THREE.ColorManagement.legacyMode = false
|
||||
|
||||
this.#audioLoader = new THREE.AudioLoader()
|
||||
this.#modelRepository = new ModelRepository()
|
||||
@ -51,15 +51,15 @@ export class World {
|
||||
}
|
||||
const renderer = new THREE.WebGLRenderer(glParameters)
|
||||
renderer.outputEncoding = THREE.sRGBEncoding
|
||||
renderer.toneMapping = THREE.ACESFilmicToneMapping
|
||||
renderer.toneMapping = THREE.CineonToneMapping
|
||||
renderer.toneMappingExposure = setting.getExposure()
|
||||
renderer.physicallyCorrectLights = false
|
||||
renderer.setSize(window.innerWidth, window.innerHeight)
|
||||
if (!setting.shouldPreferPerformance()) {
|
||||
new THREE.RGBELoader().load('./resources/img/orlando_stadium_1k.hdr', function (texture) {
|
||||
new RGBELoader().load('./resources/img/orlando_stadium_1k.hdr', function (texture) {
|
||||
texture.mapping = THREE.EquirectangularReflectionMapping
|
||||
texture.toneMapped = true
|
||||
scene.environment = texture
|
||||
scene.environmentIntensity = 0.4
|
||||
})
|
||||
renderer.shadowMap.enabled = true
|
||||
renderer.shadowMap.type = THREE.PCFSoftShadowMap
|
||||
@ -196,7 +196,12 @@ export class World {
|
||||
mesh.receiveShadow = true
|
||||
|
||||
this.#scene.add(mesh)
|
||||
this.#flames.push(mesh)
|
||||
return mesh
|
||||
}
|
||||
|
||||
spawnSmoke(geometry) {
|
||||
const mesh = new THREE.Mesh(geometry, this.#modelRepository.getSmokeMaterial())
|
||||
this.#scene.add(mesh)
|
||||
return mesh
|
||||
}
|
||||
|
||||
@ -234,8 +239,6 @@ export class World {
|
||||
|
||||
reset() {
|
||||
this.clearDecals()
|
||||
this.#flames.forEach((item) => this.destroyObject(item))
|
||||
this.#flames = []
|
||||
const bomb = this.#modelRepository.getBomb()
|
||||
if (bomb.parent && bomb.parent.name === 'MainScene') {
|
||||
bomb.visible = false
|
||||
@ -243,6 +246,10 @@ export class World {
|
||||
}
|
||||
|
||||
destroyObject(object) {
|
||||
if (object.name === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
if (object.name === `item-${Enum.ItemId.Bomb}`) {
|
||||
if (object.parent && object.parent.name === 'MainScene') {
|
||||
object.visible = false
|
||||
|
@ -1,3 +1,4 @@
|
||||
import * as THREE from 'three'
|
||||
import {Color, InventorySlot} from "../Enums.js";
|
||||
|
||||
export class Radar {
|
||||
|
@ -5,6 +5,7 @@ import {World} from "./World.js";
|
||||
import Stats from "../threejs/Stats.js";
|
||||
import {Setting} from "./Setting.js";
|
||||
import {PlayerAction} from "./PlayerAction.js";
|
||||
import {PointerLockControls} from "three/addons/controls/PointerLockControls.js";
|
||||
|
||||
let launchGame
|
||||
(function () {
|
||||
@ -51,7 +52,7 @@ let launchGame
|
||||
|
||||
const setting = new Setting(settingString)
|
||||
const canvas = await world.init(map, setting)
|
||||
const pointerLock = new THREE.PointerLockControls(world.getCamera(), canvasParent)
|
||||
const pointerLock = new PointerLockControls(world.getCamera(), canvasParent)
|
||||
pointerLock.pointerSpeed = setting.getSensitivity()
|
||||
|
||||
hud.createHud(elementHud, map, setting)
|
||||
|
@ -1,14 +1,14 @@
|
||||
function degreeToRadian(degree) {
|
||||
return THREE.MathUtils.degToRad(degree)
|
||||
return degree * Math.PI / 180
|
||||
}
|
||||
|
||||
function radianToDegree(radian) {
|
||||
return Math.round(THREE.MathUtils.radToDeg(radian))
|
||||
return Math.round(radian * 180 / Math.PI)
|
||||
}
|
||||
|
||||
function threeRotationToServer(eulerYXZ) {
|
||||
const horizontal = THREE.MathUtils.radToDeg(eulerYXZ.y)
|
||||
const vertical = THREE.MathUtils.radToDeg(eulerYXZ.x)
|
||||
const horizontal = eulerYXZ.y * 180 / Math.PI
|
||||
const vertical = eulerYXZ.x * 180 / Math.PI
|
||||
|
||||
if (horizontal === 0) {
|
||||
return [0, vertical]
|
||||
@ -38,11 +38,11 @@ function scopeLevelToZoom(scopeLevel) {
|
||||
}
|
||||
|
||||
function randomInt(start, end) {
|
||||
return THREE.MathUtils.randInt(start, end)
|
||||
return start + Math.floor(Math.random() * (end - start + 1));
|
||||
}
|
||||
|
||||
function lerp(start, end, percentage) {
|
||||
return THREE.MathUtils.lerp(start, end, percentage)
|
||||
return (1 - percentage) * start + percentage * end;
|
||||
}
|
||||
|
||||
function msToTick(timeMs) {
|
||||
|
@ -4,7 +4,9 @@ require __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use cs\Enum\SoundType;
|
||||
use cs\Event\EventList;
|
||||
use cs\Event\GrillEvent;
|
||||
use cs\Event\KillEvent;
|
||||
use cs\Event\SmokeEvent;
|
||||
use cs\Event\SoundEvent;
|
||||
use cs\Event\ThrowEvent;
|
||||
|
||||
@ -55,7 +57,14 @@ $frameIdEnd = null;
|
||||
width: 100%;
|
||||
}
|
||||
</style>
|
||||
<script src="./assets/threejs/three.js"></script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "./assets/threejs/three.min.js",
|
||||
"three/addons/": "./assets/threejs/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="./assets/js/utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
@ -90,7 +99,9 @@ $frameIdEnd = null;
|
||||
<input type="range" id="progress" min="0" value="0" max="<?= $frameIdEnd ?>">
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
<script type="module">
|
||||
import * as THREE from 'three'
|
||||
import {OrbitControls} from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
const renderer = {
|
||||
gl: null,
|
||||
@ -113,7 +124,7 @@ $frameIdEnd = null;
|
||||
})))
|
||||
const lastObject = this.fillWorld(floors, walls)
|
||||
this.camera.lookAt(lastObject)
|
||||
new THREE.OrbitControls(this.camera, this.gl.domElement);
|
||||
new OrbitControls(this.camera, this.gl.domElement);
|
||||
},
|
||||
fillWorld: function (floors, walls) {
|
||||
let lastMesh
|
||||
@ -216,12 +227,12 @@ $frameIdEnd = null;
|
||||
return player
|
||||
},
|
||||
showTrajectory: false,
|
||||
throwables: [],
|
||||
flammable: [],
|
||||
createBox: function (width, height, depth, color) {
|
||||
throwables: {},
|
||||
volumetrics: {},
|
||||
createVolume: function (width, height, depth, color) {
|
||||
let box = new THREE.Mesh(
|
||||
new THREE.BoxGeometry(width, height, depth),
|
||||
new THREE.MeshBasicMaterial({color: color}),
|
||||
new THREE.MeshBasicMaterial({color: color, transparent: true, opacity: 0.4}),
|
||||
)
|
||||
this.scene.add(box)
|
||||
return box
|
||||
@ -254,6 +265,9 @@ $frameIdEnd = null;
|
||||
self.throwables[event.data.id] = ball
|
||||
}
|
||||
}
|
||||
if (event.code === <?= EventList::map[GrillEvent::class] ?> || event.code === <?= EventList::map[SmokeEvent::class] ?>) {
|
||||
self.volumetrics[event.data.id] = {}
|
||||
}
|
||||
if (event.code === <?= EventList::map[SoundEvent::class] ?>) {
|
||||
if ([<?= SoundType::GRENADE_LAND->value ?>, <?= SoundType::GRENADE_BOUNCE->value ?>, <?= SoundType::GRENADE_AIR->value ?>].includes(event.data.type)) {
|
||||
const ball = self.showTrajectory ? self.createBall(self.throwables[event.data.extra.id]) : self.throwables[event.data.extra.id]
|
||||
@ -263,18 +277,17 @@ $frameIdEnd = null;
|
||||
setTimeout(() => ball.visible = false, 2000)
|
||||
}
|
||||
}
|
||||
if (event.data.type === <?= SoundType::FLAME_SPAWN->value ?>) {
|
||||
const color = new THREE.Color(`hsl(53, 100%, ${Math.random() * 70 + 20}%, 1)`)
|
||||
let flame = self.createBox(event.data.extra.size, event.data.extra.height, event.data.extra.size, color)
|
||||
if (self.flammable[event.data.extra.fire] === undefined) {
|
||||
self.flammable[event.data.extra.fire] = {}
|
||||
}
|
||||
self.flammable[event.data.extra.fire][`${event.data.position.x}-${event.data.position.y}-${event.data.position.z}`] = flame
|
||||
flame.position.set(event.data.position.x, event.data.position.y + (event.data.extra.height / 2), -event.data.position.z)
|
||||
if (event.data.type === <?= SoundType::FLAME_SPAWN->value ?> || event.data.type === <?= SoundType::SMOKE_SPAWN->value ?>) {
|
||||
const color = event.data.type === <?= SoundType::FLAME_SPAWN->value ?>
|
||||
? new THREE.Color(`hsl(53, 100%, ${Math.random() * 70 + 20}%, 1)`)
|
||||
: new THREE.Color(0x798aa0)
|
||||
let mesh = self.createVolume(31, event.data.extra.height, 31, color)
|
||||
self.volumetrics[event.data.extra.id][`${event.data.position.x}-${event.data.position.y}-${event.data.position.z}`] = mesh
|
||||
mesh.position.set(event.data.position.x, event.data.position.y + (event.data.extra.height / 2), -event.data.position.z)
|
||||
}
|
||||
if (event.data.type === <?= SoundType::FLAME_EXTINGUISH->value ?>) {
|
||||
const flame = self.flammable[event.data.extra.fire][`${event.data.position.x}-${event.data.position.y}-${event.data.position.z}`]
|
||||
flame.visible = false
|
||||
if (event.data.type === <?= SoundType::FLAME_EXTINGUISH->value ?> || event.data.type === <?= SoundType::SMOKE_FADE->value ?>) {
|
||||
const mesh = self.volumetrics[event.data.extra.id][`${event.data.position.x}-${event.data.position.y}-${event.data.position.z}`]
|
||||
mesh.visible = false
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -298,7 +311,7 @@ $frameIdEnd = null;
|
||||
|
||||
const driver = {
|
||||
frameId: <?= $frameIdStart ?>,
|
||||
defaultAnimationSpeedMs: 100,
|
||||
defaultAnimationSpeedMs: 30,
|
||||
getFrameId: function () {
|
||||
return this.frameId;
|
||||
}
|
||||
|
@ -48,7 +48,14 @@
|
||||
tickMs: 0,
|
||||
}
|
||||
</script>
|
||||
<script src="./assets/threejs/three.js?v=144"></script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "./assets/threejs/three.min.js?v167",
|
||||
"three/addons/": "./assets/threejs/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="./assets/js/utils.js"></script>
|
||||
<script type="module">
|
||||
import {Setting} from "./assets/js/Setting.js";
|
||||
|
@ -38,13 +38,23 @@ foreach ($map->getBoxes() as $box) {
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Map Generator</title>
|
||||
<script src="./assets/threejs/three.js"></script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "./assets/threejs/three.min.js",
|
||||
"three/addons/": "./assets/threejs/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body style="margin:0">
|
||||
<div style="position:absolute;<?= $radarMapGenerator ? 'display:none;' : '' ?>">
|
||||
<textarea class="map">Generating...</textarea>
|
||||
</div>
|
||||
<script>
|
||||
<script type="module">
|
||||
import * as THREE from 'three'
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
|
||||
const forRadar = <?= ($radarMapGenerator ? 'true' : 'false') ?>;
|
||||
let camera, scene, renderer, controls, map, extra;
|
||||
const worldMaterial = new THREE.MeshLambertMaterial({color: 0x9f998e})
|
||||
@ -73,7 +83,7 @@ foreach ($map->getBoxes() as $box) {
|
||||
}
|
||||
camera.position.y = 4000
|
||||
|
||||
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
}
|
||||
|
||||
function createRamp(startX = 1507.1, startY = 0, endX = 1676, endY = 140.1, depth = 80) {
|
||||
@ -130,7 +140,7 @@ foreach ($map->getBoxes() as $box) {
|
||||
map.add(mesh)
|
||||
})
|
||||
|
||||
const s1 = new THREE.SpotLight(0xFFFFFF, .6)
|
||||
const s1 = new THREE.SpotLight(0xFFFFFF, 5_000_000)
|
||||
s1.castShadow = true
|
||||
s1.shadow.mapSize.width = 2048
|
||||
s1.shadow.mapSize.height = 2048
|
||||
@ -138,8 +148,8 @@ foreach ($map->getBoxes() as $box) {
|
||||
s1.shadow.camera.far = maxHeight * 10
|
||||
s1.position.set(center.position.x, maxHeight * 2.5, center.position.z)
|
||||
s1.target = center
|
||||
const d1 = new THREE.DirectionalLight(0xffeac2, 0.6);
|
||||
const a1 = new THREE.AmbientLight(0xDADADA, .8)
|
||||
const d1 = new THREE.DirectionalLight(0xf0eadf, 5);
|
||||
const a1 = new THREE.AmbientLight(0xDADADA, 1)
|
||||
extra.add(s1, d1, a1);
|
||||
|
||||
scene.add(map, extra)
|
||||
|
@ -62,20 +62,30 @@ $slots = [
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Player model Generator</title>
|
||||
<script src="./assets/threejs/three.js"></script>
|
||||
<script type="importmap">
|
||||
{
|
||||
"imports": {
|
||||
"three": "./assets/threejs/three.min.js",
|
||||
"three/addons/": "./assets/threejs/"
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="./assets/js/utils.js"></script>
|
||||
</head>
|
||||
<body style="margin:0">
|
||||
<script>
|
||||
<script type="module">
|
||||
import * as THREE from 'three'
|
||||
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
|
||||
import {ModelRepository} from "./assets/js/ModelRepository.js";
|
||||
|
||||
let camera, scene, renderer, controls;
|
||||
|
||||
////
|
||||
// fixme: add gui controls
|
||||
const opacityPlayer = 1.0
|
||||
const opacityHitBoxes = 0.0
|
||||
const opacityBoundingBox = 0.0
|
||||
////
|
||||
</script>
|
||||
<script>
|
||||
let camera, scene, renderer, controls;
|
||||
|
||||
const materialDefault = new THREE.MeshBasicMaterial({color: 0x664b17, transparent: true, opacity: opacityHitBoxes, depthTest: false})
|
||||
const materialArm = new THREE.MeshBasicMaterial({color: 0x114b3d, transparent: true, opacity: opacityHitBoxes, depthTest: false})
|
||||
@ -103,7 +113,7 @@ $slots = [
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
controls = new THREE.OrbitControls(camera, renderer.domElement);
|
||||
controls = new OrbitControls(camera, renderer.domElement);
|
||||
controls.target.set(0, 110, 0)
|
||||
controls.update()
|
||||
}
|
||||
@ -130,9 +140,6 @@ $slots = [
|
||||
init()
|
||||
extra()
|
||||
animate()
|
||||
</script>
|
||||
<script type="module">
|
||||
import {ModelRepository} from "./assets/js/ModelRepository.js";
|
||||
|
||||
const modelRepository = new ModelRepository()
|
||||
await modelRepository.loadAll()
|
||||
|
Loading…
x
Reference in New Issue
Block a user