• Content Count

  • Joined

  • Last visited


About timetocode

  • Rank
    Advanced Member

Contact Methods

  • Website URL
  • Twitter

Profile Information

  • Gender
    Not Telling
  • Location
    Seattle, WA
  • Interests
    game development, pixel art, procedural content generation, game music

Recent Profile Visitors

1294 profile views
  1. Link: JigsawPuzzles.io - multiplayer cooperative jigsaw puzzles There are always a few ongoing public games on the homepage. Anyone can join these. If you want a more controlled experienced, signing in allows the creation of private games. You can invite friends into your private games. Tech stuff: The game is made in a hybrid of canvas and Pixi v4. The multiplayer is node.js + websockets via nengi.js. The game is only online multiplayer, even when playing alone. I'm primarily a network programmer and the whole project began as strange experiment of programming a casual puzzle game as if it were a shooter (movement prediction, lag compensation, reconciliation). I usually work on shooters. The hope was that the controls would come out feeling like the game was single player up to 500 ms of latency and 5% packet loss. The project has changed a little since then (the servers are no longer 30 tick) but the essence remains. It uses 2K and 4K images depending on the puzzle size, which is kinda fun because of how much it is possible to zoom in/out. The big puzzles are primarily aimed at desktop users, but are decent on touch tablets. Mobile isn't supported yet... but it does kinda work on some phones just by chance. We've got a few crazy modes that we're considering in the future. For now the only mode is a cooperative recreation of the table top experience. Thank you for checking out the game Here's a 1148 piece puzzle: Here's a smaller puzzle: What the catalog/setup page looks like (gotta sign in first, so that progress we can save): Social accounts for the game: https://www.facebook.com/JigsawPuzzles.io/ https://www.instagram.com/jigsawpuzzles.io/ https://twitter.com/JigsawPuzzlesIO https://www.reddit.com/r/jigsawpuzzlesio/ https://discordapp.com/invite/axT9bRw
  2. I do something just like this for a rewind + collision check feature. The trick is to use mesh.computeWorldMatrix(true) on the meshes that are being checked for collisions after being moved. This is the internal operation being performed by scene render that makes the collisions work (among other things, such as rendering). I think this is needed whenever moving and positioning objects in-between frames, esp if the object is being moved multiple times and checked for collisions before the next render. In the case of my rewind collision check, I never actually wanted to render the object in the rewound position -- I just needed the object to be in the correct state so that babylon could do the math for me. For me that meant copying its original position, moving it to a new position, invoking computeWorldMatrix, doing the intersection test, and then restoring it to the original position. While not identical, this does come out somewhat similar to the notion of moving an object (or a copy of that object) until it collides, uncolliding it, and then having it in the uncollided position all before actually rendering anything. Here's the PG w/o scene render in the collision checks: https://playground.babylonjs.com/#1UK40Z#8 If I understand what you have made, then this in theory will never turn the torus white.
  3. It looks awesome!! I took your advice and tried to make sure that babylon was the same version everywhere that I was using it. I'm not sure what I really did, but somewhere along the process of trying to change out 3.3 for 4, and then undoing it, little things started working. In the end I made a new custom deploy of babylon 4.0, and then I copied and pasted *just* the water material from that directly above my own code. This gave the water reflections, but no animation. I couldn't really figure out a way to get 4.0 running NullEngine (I'll just wait until it is released on npm, and then untangle things). As for the water animation, that part does make sense to me now, I was missing this: engine.runRenderLoop(() => {}) ^ my previous code only called scene.render(), which might explain why some pg code doesn't work the same for me... i'm not sure what invoking runRenderLoop with an empty function does, but i'm guessing it triggers some important core-level update logic..? in this case passing variables to the water shader maybe. I also learned that I *can* setGlobalVolume if I do it inside of setTimeout -- I'm not sure what mess I've made, but I'm either accidentally overwriting the audioEngine or things aren't initialized quite when I think they are.
  4. Everything seems to work in the PG. Multiple times I've taken some seemingly encapsulated function out of a PG and pasted into my game and not had it do quite the same thing. I'm not sure how to reproduce it. I'm starting to think I may have a more fundamental issue, like perhaps I accidentally have multiple instances of BABYLON's global scope, engine, or scene. Maybe this is a hint: BABYLON.Engine.audioEngine.setGlobalVolume(0.1) does not change the volume of sounds in my game. I have to invoke setVolume on every sound individually to change volume. Does that point at any general type of issue? I'm using const BABYLON = require('babylonjs') in most files instead of an html script tag, as most of the code runs in node... i wonder if that is related.
  5. I must be doing something incorrect with the water, as it is rendering black: I pasted the code from this playground, and included the files for the waterbump.png and skybox: https://www.babylonjs-playground.com/#1SLLOJ#17 Here's my code, although its very similar to the PG. My guess is the error isn't in this code, though I'm not sure what else would affect the water. It is as if it has nothing in its render list -- but I can definitely see the sky, and the sky is added to the list. this.canvasEle = document.getElementById('main-canvas') this.engine = new BABYLON.Engine(this.canvasEle, true) this.engine.enableOfflineSupport = false this.engine.setHardwareScalingLevel(1) this.scene = new BABYLON.Scene(this.engine) //this.scene.freezeActiveMeshes() //this.scene.collisionsEnabled = true //this.scene.clearColor = new BABYLON.Color4(0.3, 0.5, 0.75, 1.0) this.scene.fogMode = BABYLON.Scene.FOGMODE_EXP this.scene.fogDensity = 0.0005 this.camera = new BABYLON.TargetCamera('camera', new BABYLON.Vector3(0, 0.5, 0), this.scene) this.camera.fov = 0.8 this.camera.minZ = 0.1 //this.scene.autoClear = false //this.scene.autoClearDepthAndStencil = false var light = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(0.66, -0.75, 1.25), this.scene) light.position = new BABYLON.Vector3(1, 40, 10) light.intensity = 0.5 var light3 = new BABYLON.DirectionalLight("dir01", new BABYLON.Vector3(-0.5, 0.75, -1.25), this.scene) light3.position = new BABYLON.Vector3(1, 40, 1) light3.intensity = 0.5 var light2 = new BABYLON.HemisphericLight('h', new BABYLON.Vector3(0, 1, 0), this.scene) light2.intensity = 0.6 var skybox = BABYLON.Mesh.CreateBox("skyBox", 5000.0, this.scene) var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", this.scene) skyboxMaterial.backFaceCulling = false skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("images/TropicalSunnyDay", this.scene) skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0) skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0) skyboxMaterial.disableLighting = true skybox.material = skyboxMaterial var waterMesh = BABYLON.Mesh.CreateGround("waterMesh", 2048, 2048, 16, this.scene, false) var water = new BABYLON.WaterMaterial("water", this.scene, new BABYLON.Vector2(512, 512)) water.backFaceCulling = true water.bumpTexture = new BABYLON.Texture("images/waterbump.png", this.scene) water.windForce = -10 water.waveHeight = 1.7 water.bumpHeight = 0.1 water.windDirection = new BABYLON.Vector2(1, 1) water.waterColor = new BABYLON.Color3(0, 0, 221 / 255) water.colorBlendFactor = 0.0 water.addToRenderList(skybox) waterMesh.material = water Any ideas?
  6. Now that I have this reproduced, I think I'm realizing that this idea was never going to work due to the number of sounds. I did a little bit more testing with a 500 KB wav file vs a 15 KB mp3, and the degradation seems more related to the number of sounds than their size. In my game each weapon has like 5-20 sounds, and a player can hold a few weapons. The walk/run cycle has like 16 sounds per material (concrete, wood, grass, etc). It can add up to about ~100 possible sounds per player, though 99% of them aren't playing at any given point. BJS seems totally fine with that many sounds, but it looks like attachToMesh is not designed for this. I read the source code, and it looks like it *might* be viable if it would check if the sound is playing before rebuilding the matrices. Currently it does some fairly expensive work, even for non-playing sounds (setPosition and computeWorldMatrix fill the profiler when stress tested with cloned sounds on moving meshes). I'm going to test positioning the sounds manually at the time that they are played, and not having them move along with the mesh. If that doesn't work I guess I'll pool them in addition. Edit: definitely need a pool Edit#2 at 21 players firing the same automatic rifle, the pool brought the active number of sound instances from 210 down to 59 Here's an ultra simple auto-expanding pool if anyone wants. Usage is just to use 'get' for short-lived sounds and it will handle allocation and releasing on its own. It never deallocs. class SoundPool { constructor() { this.scene = null this.sounds = {} } init(scene) { this.scene = scene } allocate(name) { const sound = BABYLON.Sound.FromAtlas(name, name, this.scene) sound.onEndedObservable.add(() => { this.release(sound) }) this.sounds[name].push(sound) } get(name) { if (!this.sounds[name]) { this.sounds[name] = [] } if (this.sounds[name].length === 0) { this.allocate(name) } return this.sounds[name].pop() } release(obj) { this.sounds[obj.name].push(obj) } } const singleton = new SoundPool() module.exports = singleton BABYLON.Sound.FromAtlas is a little wrapper that clones sounds without making additional xhrs (e.g. 'sounds/foo.mp3', clones it and applies new options)
  7. I was finally able to reproduce it in a PG. https://www.babylonjs-playground.com/#8B9YRN#1 This is based off of the playground where violin music is playing inside of spheres. As the camera enters the sphere, the music becomes audible. In this playground I have one purple dome with music playing on loop, and then 100 purple domes that have a clone of the music linked to their mesh, but the music is intentionally not being played. The purple dome that is playing music is separate from all of the others. It is the only one playing music. If we keep increasing the number of silent domes (see the for loop around line ~45) eventually the sound will degrade, even though we're only playing a single wav on loop. I left the PG on 100 silent domes b/c I don't want to crash people's computers. Personally I have to increase this number to 1200(!!) before I get the sound problems that are occurring in my game. So to reproduce, change the count on line 45 and then walk into the isolated sphere. That 1200 is a big number but this problem happens in my game at around 300 sounds (even though 298 of the sounds aren't playing). These are just sounds that are attached to meshes and aren't playing, but they can get triggered later.
  8. This is probably a browser thing and not a babylon thing... but I'm getting this thing where the game sound effects degrade the more players I add to a game. I have a player character and I attach ~20 sounds to its mesh. It is a first person shooter and each gun has about that many sounds between gunshots, reloading, and a handful of variants of each. In the development version these are all wav files which are far larger than whatever I'll convert them to later. As I load more players, the gun of the first player starts to sound worse and worse. The weird part is none of the other players are making any sound.. they're all holding still and not firing their gun. At first it just gets a little tinny or crunchy, but as the player count goes up the sound crunches so much that it eventually goes almost almost silent. It sounds like a game lagging very badly, but the FPS is remaining 120+ Any idea why this is happening? All that is occurring on the sound level is that I'm cloning more and more of the gun sounds, I'm not actually playing anything more than one player worth of a sounds. I tried to reproduce this on the babylon playground but even cloning the violin music 3000 times didn't change a thing -- it sounds the same no matter how many clones are around. Maybe I'm causing some memory problem in my audio hardware with the wavs...? The biggest is about 475 KB.
  9. Thanks Raggar that looks good! I wonder if anyone would be interested in having this behavior added to the api. Or maybe just tacked on by including a file. The following is all pseudo code, but I will probably implement it for real on Monday. Usage: BABYLON.SoundAtlas.add('filename.ext') // etc for all sounds BABYLON.SoundAtlas.load(scene, callback) // starts loading // using a sound from the atlas, while mimicking the original BJS api const gunshot = BABYLON.Sound.FromAtlas('gunshot', 'filename.ext', scene, { volume: 1 }) Possible extension to babylon Sound: BABYLON.Sound.prototype.FromAtlas = (name, filepath, scene, options) => { const cachedSound = BABYLON.SoundAtlas.get(filepath) if (!cachedSound) { throw new Error('Sound not found in SoundAtlas') } const sound = cachedSound.clone() sound.name = name sound.updateOptions(options) // autoplay won't work without some minor modification } Presumably would not work with multiple scenes. Everything I've made is all single scene with programmatically spawned meshes, so I'm not sure what would have to change. Sound atlas: /* Sound Atlas */ const BABYLON = require('babylonjs') const basePath = './sounds/' // should be modifiable instead const sounds = new Map() const soundFilenames = [] const queueSounds = (assetsManager, scene) => { soundFilenames.forEach(soundFilename => { const path = `${basePath}` const name = `${basePath}${soundFileName}` const binaryTask = assetsManager.addBinaryFileTask(name '', path, soundFilename) binaryTask.onSuccess = (task) => { const sound = new BABYLON.Sound(task.name, task.data, scene, null, {}) sounds.set(task.name, sound) } }) } const add = (soundFilename) => { soundFilenames.push(soundFilename) } const load = (scene, cb) => { const assetsManager = new BABYLON.AssetsManager(scene) queueSounds(assetsManager, scene) assetsManager.onFinish = () => { cb() } assetsManager.onTaskError = (task) => { console.log('error loading task', task) } assetsManager.load() } module.exports.add = add module.exports.load = load Haven't tried it yet, but that's the gist of it.
  10. Hello there. What is intended method of playing the same sound multiple times *concurrently* without re-downloading the sound file from the server? const gunshot = new BABYLON.Sound('foo', "sounds/gun_semi_etc.wav", scene, null, { volume: 1 }) If I have multiple players or bots in my game, any of them can produce gunfire. As each of them shoots, I end up with a separate web request per entity: I'm accustomed to howler, where the first time a sound is created, like 'foo.wav' it will load it from the server. Any subsequent sound objects created that play 'foo.wav' will build themselves from the same sound data without an xhr. How do I accomplish the equivalent? TY TY
  11. Social logins work for identifying a player. The APIs typically provide a special id to store in your own database, and this id will be provided via api each time the player comes back. A single player type of a game played in a browser means that the entire game's state is not in control of the developer. This is running on the player's computer, and they can alter the code and do whatever they want. Scores submitted by a game like this cannot ever be trusted. That doesn't stop developers from making plenty of games like this, but inherently there is no way to know that any submitted score is valid without doing something vastly more sophisticated. Usually people just periodically clean out their leaderboards of all the fake scores. An example of something more sophisticated would be a game that submitted all of its player input. This is uncommon (maybe non-existent) in single player games, but for example a game like Tetris could be made where the game records every move the player makes. At the end of the round the game client could submit this long list of moves to the server, and the server could re-simulate the same game and generate the player's score. The player could still be a hacker submitting fraudulent moves, so the server would still have to validate some things... but this provides a basis for knowing whether submitted information is potentially valid whereas receiving a json message like { playerId: 219, score: 9999999 } leaves very little to validate. All we can really do with that data is perhaps guess that they are a cheater. Meanwhile to hack a game that submits a move list that then gets simulated on the server is very difficult -- it requires essentially writing a bot that can play the game like a human (but better). I'm not saying anyone should make a system like this, but this "deterministic simulation built from player input" is the element that prevents cheating in real time strategy games. A similar concept reduces the cheating in server-authoritative first person shooters (and is why aim bots exist).
  12. Found mesh.flipFaces(false) which seems to fix all of the meshes I've had problems with so far. I also tried the full scene-wide flip (scene.useRightHandSystem = true) which worked as well and allowed me to not have any negative scales. I'm going back to left hand though, not sure if it is more intuitive or if I just have too much code that relies on it, but flipping a voxel collision system and maps was not so easy.
  13. On some objs that I import, I'm having to do foo.scaling = new BABYLON.Vector3(-1, 1, 1). For example this zombie needed the torso scaling set (-1, 1, 1) before the left and right hands appeared on the correct sides of the body among other details. The arms are parented to the torso, so I think that is how the scale is factoring into which side they appear on. The head is actually flipped incorrectly at the moment as well, but that doesn't really matter. I'm fine with scaling(-1,1,1) as a solution, but for some reason the gun now has its mesh inside out or something. So my question is two parts: 1) why is the gun inside out? The parent order (child to parent) is weapon -> leftHand -> lowerLeftArm -> upperLeftArm -> torso. In theory everything is inheriting its scale from torso. Each body part is a separate mesh made the same way, yet only the weapon is inside out, not the torso or any of the arm parts (maybe I just have an error in my code, unless there is some reason that this would naturally by the case). 2) is there a babylon function to fix only an individual mesh? I searched the forum and found many pgs dating back up to 3 years, and some mention of including righthand vs lefthand modes in bjs... but I wasn't sure what the current day method would be to fix just the weapon mesh below. It may be a little hard to see that it is in fact inside-out, so here's another picture of what the weapon is supposed to look like: I cannot use blender+babylon-exporter to make the full model at this point (some complex issues with networking bone animations exported from blender to babylon, a topic for another time). I am still using blender to pose my character as a visual reference before converting the rotations of each body part over to a custom animation system -- so this is perhaps where the conflicting notion of left/right arms is coming from originally. Thanks
  14. Something that can be neat for clientside events is adding custom events to google analytics. Those are easy to make, and then they end up in the same data set with the rest of the stuff. Obv. not a viable candidate for player data, just analytics For serverside persistence of player data, this isn't going to be particularly helpful, but I just do it myself on a vps (vultr and linode lately). I usually need authentication as part of my games, and I do that with a node + express + passport + postgres. At that point I already have a server with psql installed so I just add a table or some columns for the game-specific data. Despite doing this, I have mixed reservations about whether the work is worth it. It can be a lot cheaper than something like aws or a standalone sql provider (that probably uses aws behind the scenes..) but it is a lot of work. Edit: I'd also like to mention that if the data stored about players is just like a finite number of columns with some counts like "totalKills" it ends up being a very small amount of data. On bruh.io, our data was like that, and during its most popular days (when breaking 1000+ ccu at peak every day) our needs were easily met by the smallest dedicated instance from elephantsql. In total that game has ~320k registered users and 25 million rounds played. By comparison I've tried to estimate the storage needs for a first person shooter style game where every single kill and item pick up is saved as a time stamped event. If a game like that was played the same amount as bruh, it is hard to say exactly, but we'd be going from 100 GB being total overkill to wanting a several TB.