Jump to content
  • Advertisement

Greedy Goblin

  • Content Count

  • Joined

  • Last visited

  • Days Won


Greedy Goblin last won the day on October 6

Greedy Goblin had the most liked content!

Community Reputation

15 Neutral

About Greedy Goblin

  • Rank

Personal Information

Recent Profile Visitors

618 profile views
  1. Greedy Goblin

    State Changes

    Games usually (if not always) require some way to manage state changes... and I'm sure most of you (if not all of you) know far more about State Machines than I do. And I'm certain that I could learn a heck of lot from reading up about the subject to build a state machine that works beautifully and makes my code look amazing etc etc. Pfft.. never mind all that... I'm building this game 'off the cuff' as it were, making it up as I go along and following the principle of 'I build what I need when I need it and only insofar that it adequately fulfils the requirements at that time'. I don't try to plan ahead (not in any granular sense anyway), I'm not building a reusable one-size-fits-all game engine, I'm not trying to make the code beautfiul, or win any awards or even make any money from the darn thing. It just needs to perform well enough for what I want it to do. So my immediate requirement is that I have a way to manage the player switching from walking to running to whatever. If I can use it elsewhere for other things then great... and I'll be honest, I do like reusable code so I tend to naturally sway toward that. What I'm trying to avoid is getting myself stuck in a rut, spending weeks/months deliberating over the smallest details because it's got to be 'perfect' and then realising I've still got 99.5% of the game to build! Quick and dirty is OK in my world. I often approach things from a top-down perspective. This boils down to: 'How do I want to instruct the computer to do x, y or z?' So for this particular requirement, how do I want to instruct the game that the player can change from walking to running and running to walking, or walking/running to falling (assuming I make that a player state - which I do), but not from sleeping to running for example? Hell, I don't even know all the states that I want yet, but these are the ones I have a feel for so far: Walking Running Skiiing Driving Falling Drowning Sleeping Eating Introducing 'When' I thought it might be nice to be able to write something like this in my player setup: // Configure valid player state transitions When( this.playerState ).changes().from( PLAYER_STATES.WALKING ).to( PLAYER_STATES.RUNNING ).then( function () { } ); When( this.playerState ).changes().from( PLAYER_STATES.RUNNING ).to( PLAYER_STATES.WALKING ).then( function () { } ); When( this.playerState ).changes().from( PLAYER_STATES.WALKING ).to( PLAYER_STATES.SKIING ).then( function () { } ); When( this.playerState ).changes().from( PLAYER_STATES.SKIING ).to( PLAYER_STATES.WALKING ).then( function () { } ); When( this.playerState ).changes().from( PLAYER_STATES.WALKING, PLAYER_STATES.RUNNING, PLAYER_STATES.SKIING ).to( PLAYER_STATES.FALLING ).then( function () { } ); There's probably a library for something like this out there, but heck, where's the fun in that?! So I create a new 'Stateful' object that represents a state (in this case the playerState) and it's allowed transitions and a 'When' function so I can write the code exactly as above: const Stateful = function () { } Stateful.isStateful = function ( obj ) { return obj.constructor && obj.constructor.name === Stateful.name; } Stateful.areEqual = function ( v1, v2 ) { return v1.equals ? v1.equals( v2 ) : v1 == v2; } Stateful.prototype = { constructor: Stateful, set: function ( v ) { let newState = typeof ( v ) === "function" ? new v() : v; for ( let i = 0; i < this.transitions.length; i++ ) { let transition = this.transitions[i]; if ( transition && typeof ( transition.callback ) === "function" ) { let fromMatch = Stateful.areEqual( transition.vFrom, this ); let toMatch = Stateful.areEqual( transition.vTo, newState ); if ( fromMatch && toMatch ) { // We can only change to the new state if a valid transition exists. this.previousState = Object.assign( Object.create( {} ), this ); Object.assign( this, newState ); transition.callback( this.previousState, this ); } } } }, transitions: Object.create( Object.assign( Array.prototype, { from: function ( vFrom ) { this.vFrom = typeof ( vFrom ) === "function" ? new vFrom() : vFrom; return this; }, to: function ( vTo ) { this.vTo = typeof ( vTo ) === "function" ? new vTo() : vTo; return this; }, remove: function ( fn ) { this.vFrom = this.vFrom === undefined ? { equals: function () { return true; } } : this.vFrom; this.vTo = this.vTo === undefined ? { equals: function () { return true; } } : this.vTo; for ( let i = 0; i < this.length; i++ ) { let transition = this[i]; let fromMatch = Stateful.areEqual( this.vFrom, transition.vFrom ); let toMatch = Stateful.areEqual( this.vTo, transition.vTo ); let fnMatch = fn === undefined ? true : transition.callback == fn; if ( fromMatch && toMatch & fnMatch ) { delete this[i]; } } } } ) ) } function When( statefulObj ) { if ( !Stateful.isStateful( statefulObj ) ) { throw "Argument must be a Stateful object"; } return { changes: function () { return { from: function ( ...vFrom ) { this.vFrom = vFrom; return this; }, to: function ( ...vTo ) { this.vTo = vTo; return this; }, then: function ( fn ) { if ( typeof ( fn ) === "function" ) { this.vFrom = this.vFrom === undefined ? [true] : this.vFrom; this.vTo = this.vTo === undefined ? [true] : this.vTo; for ( let i = 0; i < this.vFrom.length; i++ ) { for ( let j = 0; j < this.vTo.length; j++ ) { statefulObj.transitions.push( { vFrom: typeof ( this.vFrom[i] ) === "function" ? new this.vFrom[i]() : this.vFrom[i], vTo: typeof ( this.vTo[j] ) === "function" ? new this.vTo[j]() : this.vTo[j], callback: fn } ); } } } else { throw "Supplied argument must be a function"; } } }; } } } I drop the aforementioned 'When' statements into my Player setup and remove the old 'If' statements that were previously controlling changes between walking and running and insert the new playerState.set() calls where appropriate. e.g. "run": ( pc, keyup ) => { if ( keyup ) { _this.player.playerState.set( PLAYER_STATES.WALKING ); } else { _this.player.playerState.set( PLAYER_STATES.RUNNING ); } } And it seems to work! (Yes I was actually surprised by that) 😂 TheBerg-StateChanges.mp4 p.s. I've switched to using Bandicam for screen capture as it seems far superior to what I was using previously.
  2. Greedy Goblin

    The Berg

    Album for The Berg
  3. Greedy Goblin

    Nighty Knight 3D [HTML5/Android/iOS] [FREE]

    To be honest, I was on my desktop PC at the time I checked it out so I couldn't play it properly as it doesn't appear to fully support keyboard controls... well, I couldn't use WASD to move anyway, the cursor keys seemed to allow me hack and slash a bit. I'll have to try it out on my mobile phone later.
  4. A code smell is not necessarily a bad piece of code, just something that needs further investigation in its own context if, like you say, the code is not performant or becoming bloated or overly complicated. That does not mean "if... is..." is necessarily wrong. My point was not to beat yourself up so much over your code quality. It's not healthy and very rarely helpful in my experience. If you have lots of If statements but your code is performing to your requirements and easy to read/maintain (which is of course subjective) then I fail to see what the problem is. Guides to writing good clean code are exactly that, guides, not some religious mandate (which is how some people seem to treat them). Thanks goodness I don't work in an environment like that any more. 😂
  5. Greedy Goblin

    Nighty Knight 3D [HTML5/Android/iOS] [FREE]

    Nice work! Keep it up!
  6. Greedy Goblin

    My brief tour through 3d engines

    You might want to consider checking this out...
  7. Doesn't C# have the "is" operator? So if Sword extends from Weapon then: if (weapon is Sword) should suffice for determining weapon type shouldn't it? Or maybe I'm just another person who has misunderstood? Seriously?! Are you doing this professionally or as a hobby? If the latter, then why do you care so much about what others think of your code quality? Does your solution work? If yes, then who cares if it's 'bad code'. Honestly, every developer under the sun has their own opinions of what is good code and what is bad code. I've worked professional in an environment like that (too many egos and pedants) and it was probably one of the least productive places I've ever worked; fearful of touching the keyboard cos you know you'll be criticised and have your code ripped to shreds. It's not healthy! No shit Sherlock. I can't speak for others but I do it mainly because I find it fun.
  8. Greedy Goblin

    Slopey McSlopeface (part 2)

    Having played around with the character movement a bit more I realised I was doing many things wrong. Not that I had ever intended to do things perfectly, but the slope handling just wasn't up to scratch. I had acceleration working, but deceleration didn't due to the way I had built things. So I decided to do a little bit of an overhaul of the player movement system. Nothing too major it turns out but I now have both acceleration and deceleration working very nicely and it gives a much smoother feel to the controls. It's subtle but necessary in my opinion. There is one aspect of slopes that I haven't tackled yet though and that is falling, tumbling or sliding on steep slopes. As I'm not using any fancy physics engine my player character is essentially glued to the terrain like it's on rails. It's not really an issue in so far as jumping is concerned because I don't intend to have any jumping ability in the game. However, I decided that I didn't want to artificially prevent the player from walking off the edge of a cliff so I need some form of falling action (and tumbling if you run down a steep slope too fast - potentially injuring yourself). So what I've done is add forces into my CollisionBody class to represent an accelerant force due to gravity. But to keep my brain from imploding over the quirks of simulating physics (and so as not to have to implement a full-blown physics engine) I decided to half keep the on-rails aspect by doing this: if ( obj.collisionBody.position.y <= targetPos.y ) { obj.collisionBody.position.y = targetPos.y; obj.collisionBody.resetForces(); } else { // Apply gravity obj.collisionBody.applyForce( new Force( DEFAULT_VECTORS.down, _this.gAcceleration ) ); } Where 'targetPos' is the ground position. So if the player is in contact with the ground or moves below it, then they player will just snap back to the precise point on the terrain. It's only when the player goes above the terrain (into the air) that gravity comes into play. This helps keep things nice and simple and gives a nice feel to the movement. Oh and I've also added in some 'head-bobbing' to add a bit of realism to the movement. Overall it gives a really nice result.... and I can now fall off cliffs... You may also notice that the camera rotation is now much smoother too as I now 'slerp' between rotations rather than doing absolute movements, although my screen recording software doesn't do it justice in the video above.
  9. Greedy Goblin

    The Berg

  10. Greedy Goblin

    Look what I found....

    Haha! Take a look what I uncovered the other day while digging through my books.... It even came with a good old floppy disk! (I couldn't even use it if I wanted to now)... This book was my very first on 3D graphics programming, before 3D graphics card were even a thing (for the mainstream masses anyway). Published in 1994, it's a book that served as a really good primer to understanding 3D geometry and programming even if I never bothered with the later chapters on curved geometry. All the code samples were in C (not even C++) and there was no such mention of things such as texture mapping (although it did cover shadows, reflections and refraction!). It took you right from the beginning; from the equation of a straight line, translations, matrices etc to projections (viewing pyramid) and clipping algorithms. Great stuff! I still find it useful now as I re-read the introductory chapters and refresh myself on a few basics. My other go-to book is "Real Time Collision Detection" by Christer Ericson - an absolute diamond of a book! Do you guys and girls have any books that you rely on or hold in high regard for your game development? It would be interesting to know if anyone has ever seen or read the Georg Glaeser book above. Anyway, I'll soon have another update on The Berg, but it's bed time for me now. Night all.
  11. Greedy Goblin

    Efficient Instancing in a Streaming Scenario

    Excellent article and some really awesome use of GPU shaders. I have yet to get stuck into compute shaders but it seems the possibilities are great!
  12. Greedy Goblin

    Slopey McSlopeface (part 1)

    Hmmm, I love sausage rolls. Oh sorry, just having a tasty sausage roll for my lunch while thinking about the problem of... slopes. So I have this nice terrain an' all, that I can now walk around on. But those hills aren't exactly challenging my player character. I breeze up those as easily as I descend a vertical drop. Why is that? Because I'm just making the player follow the terrain like it's on rails, that's why! No fancy pants physics engines here guv. I need to make the player ascend steep inclines more slowly than flat terrain and also come to a halt against any vertical, or near-vertical inclines. I also need to make the player fall or tumble if they attempt to go down any incline too steep... but that's for another blog. I first messed around with attempting to stop the player if they tried to walk up anything with a gradient over a certain threshold... that didn't work out too well. Lots of jittery movement ensued. Then I realised my approach was all wrong! When I climb a steep hill, I don't just come to a dead stop in reality, I just move more slowly as I ascend. So this just became a case of factoring in the terrain gradient to my player speed... simples! // Test slope in direction of travel let direction = new THREE.Vector3().copy( this.collisionBody.resolveMoves().normalize() ); let p1 = new THREE.Vector3().copy( this.position ); let intersection1 = _this.terrain.heightAt( p1.x, p1.z ); let p2 = new THREE.Vector3().addVectors( this.position, direction ); let intersection2 = _this.terrain.heightAt( p2.x, p2.z ); let grad = intersection2.h - intersection1.h; _this.playerController.currentSpeed = Math.clamp( -_this.playerController.DEFAULT_SPEEDS.WALKING * grad + _this.playerController.DEFAULT_SPEEDS.WALKING, 0, 2 ); Works a treat.... except (sigh) when I'm up against a near vertical incline. I can still climb those, just a bit more slowly (sigh). In fact, no, this doesn't look right at all. The graident should be so large when approaching a near vertical incline that it should reduce my speed to 0. But for some reason I get this.... TheBerg-SlopeyMcSlopeface-01.mp4 Much head scratching ensued! Then I realised it must be something to do with the order of processing. The way I handle movement is through a "CollisionBody" object which is attached to the player. I call a "move" function on the CollisionBody which basically stores it in an array until the "PhysicsManager" decides to resolve it (reminder: there is no fancy physics going on at all yet... I just decided to call it a PhysicsManager). The thing is, my PlayerController was calling "move" before I had changed my speed to zero, so the movement vectors were already baked in (I know, I know, this is getting complicated already!) and changing the speed did nothing. Each alternate frame I was then resetting my speed back to normal walking speed.... You know, it's only when I write all that down I see just how crazy dumb it was! 😂 So I decided on an alternative approach. Instead of setting an absolute velocity vector when calling CollisionBody.move I now pass a direction vector and speed as a new Velocity object... however... the speed doesn't have to be a number... it can be a function! Thereby I can delay the resolution of the velocity until absolutely necessary (i.e. when the PhysicsManager needs to apply the moves). It may sound complicated but I quite like it. I can then make any other adjustments to the speed (not velocity) during the frame update and it will take effect when the PhysicsManager resolves everything! e.g. PlayerController handles movement -> player.collisionBody.move( new Velocity( direction, () => player.speed ) Player object "update" tests for slopes and adjusts speed accordingly PhysicsManager "update" resolves all player.collisionBody movements, in turn resolving all Velocity values using the new updated speed rather than the speed as it was in step 1 So how does this work out now? TheBerg-SlopeyMcSlopeface-02.mp4 Better... if you watch very closely you might notice I've added in a subtle acceleration too which gives a smoother feel to the player movement (later I'll add in head bobbing). However, I'm still not entirely happy with it. When you stop the player doesn't decelerate, but comes to an abrupt stop... which is fine but feels a little unnatural. Near vertical inclines are also handled better, although I still find with the "right" movements I can still climb them so I definitely need to work on this more. Acceleration is done by adding in a targetSpeed property on the Player, so the actual speed will accelerate towards that speed until it is reached. It does decelerate too as the incline increases, but when you lift your key from the keyboard the direction vector is reset to {0, 0, 0} so the speed has no effect. I'll have a think a bit more about this later. Ideas and suggestions are welcome!
  13. Greedy Goblin

    Into The Berg

    Hey Awoken and thanks for the interest in 'The Berg'! I've never tried this technique with a spherical world but I guess it's pretty much the same principle except you would need a curved plane or sphere rather than a flat plane. Mapping UVs to that becomes a little more complicated I would guess. I'm not sure how you could use a texture to represent the x,y,z coordinates for vertices to be honest as I would imagine you would need to sample every pixel of the texture on every pass. Shaders don't like big for-loops! (In fact if memory serves me correctly there used to be an explicit limit to the number of loops you could do on a single pass. I wouldn't know if that's still the case). For my water I simply use another plane mesh with a different shader. Nothing complicated. And lastly... can you have my code? Sure! Once I'm a bit further in and got something half-playable it will be on the internet for all to see... code and all! (I can't guarantee it will be nice clean code but hey, you get what you pay for)
  14. Hi Gerhart and welcome to the wonderful, wacky (and sometimes a right pain in the derrière) world of game dev. Javascript/HTML5 is certainly an option for creating games. I created a simple mobile game a few years back using JS/HTML5 and Cordova and am now starting another project using NodeJS and ThreeJS to atempt to create a browser based first person survival game... The best bit of Javascript is it's flexibility, giving you the ability to prototype things really quickly. The worst bit..... is it's flexibility, meaning that those ugly, dirty prototypes you hacked together late one night while maxed out on Redbull end up as production code. But as a beginner to programming I really wouldn't worry about that (and stay clear of the Redbull!). However, having said all this... if you really want to focus more on the game design and less on the programming I'd advise going for something more like Phaser, Gamemaker (albeit there is a cost with this one) or Unity. And as a final word of advice, don't underestimate how much is involved in creating a game. Often, what may sound simple in your mind turns out to be really complex. Fortunately we have the internet and sites like this to help us on our way these days. Most of all though... have fun!
  15. Oh boy... my fave part... simulating water! You'll see on my YouTube channel I'm not new to this... But let's not get carried away... I don't need water looking anywhere near as realistic for 'The Berg'. A simple sub-divided plane and another vertex displacement shader will do the trick... The problem I have is that I get 'hung up' on water. I can fiddle for hours tweaking this and that. MUST NOT DO THAT THIS TIME!! ... Several days later... float step = viewSize / subdivisions; vec2 pp = vec2(playerPos.x, -playerPos.z); vec2 adjPlayerPos = floor(pp / step) * step; vec2 remainderPP = pp - adjPlayerPos; float uvScale = viewSize / mapSize; vec2 uvOffset = vec2(adjPlayerPos + (mapSize / 2.) - (viewSize / 2.)) / mapSize; vec2 newUV = uvOffset + uv * uvScale; float dOffset = 0.001; vec2 depths = vec2(0); depths.x = clamp(nSeaLevel - texture2D(heightMap, newUV + vec2(-dOffset, -dOffset)).r, 0., nSeaLevel) / nSeaLevel; depths.y = clamp(nSeaLevel - texture2D(heightMap, newUV + vec2(dOffset, dOffset)).r, 0., nSeaLevel) / nSeaLevel; float avDepth = (depths.x + depths.y) / 2.; float displace = 0.; vec2 waveOrigin[3]; waveOrigin[0] = vec2(0.5, 0.5); waveOrigin[1] = vec2(0.3, 0.25); waveOrigin[2] = vec2(0.9, 0.75); float waveOriginDist[3]; waveOriginDist[0] = distance( waveOrigin[0], newUV ); waveOriginDist[1] = distance( waveOrigin[1], newUV ); waveOriginDist[2] = distance( waveOrigin[2], newUV ); vec2 t; for (int i = 0; i < 3; i++) { displace += cos( waveFreq * ( 1. / float(i + 1) ) * waveOriginDist[i] + (time * 2.)) * avDepth; displace += cos( waveFreq * avDepth * 2.5 * waveOriginDist[i] - (time * 1.5) ) * 0.5; t += normalize(newUV - waveOrigin[i]) * cos(time * 0.1); } displace *= avDepth; t *= 10.; vec2 adjVertPos = vec2( position.x - remainderPP.x, position.y - remainderPP.y ); vec3 newPos = vec3( adjVertPos.x + t.x, adjVertPos.y + t.y, displace * heightScale ); vec3 transformed = newPos; What... have... I... done...? What kind of monster have I created? ... 🤣 Just kidding....
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!