/agdg/ - Amateur Game Development General

Just Like Make Game

SAVE THIS FILE: Anon.cafe Fallback File v1.1 (updated 2021-12-13)

Board Owners: Hourly thread limits and Early 404 help protect your boards against erasure under slide attacks. Enable them today.

Want your event posted here? Requests accepted in this /meta/ thread.

Max message length: 20000

Drag files to upload or
click here to select them

Maximum 5 files / Maximum size: 20.00 MB

Board Rules

(used to delete files and postings)

Open file (530.02 KB 1284x804 laserpointer.png)
Open file (11.86 MB 1282x802 stairs_again.webm)
Open file (6.70 MB 1282x798 clamp.webm)
Open file (14.18 MB 1282x798 swim.webm)
Open file (1.73 MB 1920x1013 metrics.png)
Anon makes an MMORPG (LOL) yesdev 07/07/2023 (Fri) 06:21:01 No.914
Alright, I said I'd stop shitting up the progress thread so here it is. I'm beginning to plan to prepare to lay the preliminary groundwork for an old-school 3D MMORPG in the vein of Everquest, Meridian 59, Ultima Online, and others. I'm pretty much rolling it from scratch, using Raylib for a lot of the input/rendering/sound/etc. functionality plus a few more libraries for XML handling, UDP networking, serialization, and that's about it. You can see some project background and the progress up to this point in the progress thread starting from here: >>755 Spent some time yesterday working on the character controller. Getting capsule -> mesh collisions working wasn't too bad, but getting proper FPS style movement out of it was a fucking nightmare. I ended up raising up and shortening the capsule so it wasn't colliding with everything and anything, using a raycast from the center down to handle different surfaces and steps and the like, while using the capsule to collide with walls/ceilings/very steep slopes. Played with the swimming a bit too, still some funkiness with getting in and out of water. Some shots showing part of the setup for developing the movement metrics - slopes to test walking up and down steps without skipping and bumping, as well as test walking into slopes too steep to traverse. Also got some steps to test what heights the player should be able to automatically step up onto without jumping. TODO: handle sliding down steep slopes, determine jump height/distance, and support crouching and movement on ladders. I would like to use crouch to enter low/tight spaces, hide from enemies (LOS is currently handled with a ray from eye to eye), as well as disabling walking off edges when crouched, so you could carefully approach a cliff edge and look over if you wanted to, or move carefully on a narrow/icy ledge or something. Will be dumping progress here from now so keep an eye out.
>>914 >old-school 3D MMORPG in the vein of Everquest, Meridian 59, Ultima Online, and others Very cool project Anon. What's your vision for how it ends up being used? People running their own realm servers?
Open file (14.93 MB 1282x802 daynight.webm)
Tried my hand at implementing a simple day-night cycle. It wasn't hard to rotate a directional light around the world with the target at the origin (0, 0, 0). The light color and intensity, as well as the ambient color, is a function of the sun's normalized height over the horizon (z-axis 0 in this case) as a proportion of the rotation radius (just larger than the world). The non-linear change on the z-axis makes it get up to nearly full intensity quickly (but not quickly enough? IDK). The sun object is actually drawn as rotating around the player position, with the depth buffer disabled and drawn after the skybox but before any meshes, so as to always appear the same size, in the same direction, and behind everything. The formulas to calculate the light color, intensity, etc. are complicated and I'm not entirely satisfied with the result; I may end up just lerping between a few hand-picked values based on time of day (sun angle). Things will also need to be tweaked for gameplay purposes. I want night to be dark, like real dark, not videogame dark, so having a sun moving at a fixed rotational speed will give me a night length equal to the day length, worse, if surrounded by mountains or tall forests. Which I don't think will be a good idea. Especially if I do things like making some shops close their doors or the dead come to life at night or something. Speaking of which, I'm going to need to think about the length of a day in real world time too. >>929 Not sure yet. A large part of the gameplay will be exploration and discovery, hence my focus on keeping secrets secret, by not giving the client any more information than it needs at any given time, streaming world assets as they are discovered, and such. Turning the whole thing over to the community right off the bat would instantly spoil everything. Releasing only the "engine", as in the client and server code, without any of the assets and database contents, would also be rather useless, as anyone trying to make original games with it will be years behind the official server in terms of knowledge of the internals and asset development, and would get very little players. That said, I don't believe that MMOs should try to milk their content forever, by trying to release expansion content faster than their players can consume it (impossible), or by re-releasing the game by starting new servers with the original game content and re-releasing the expansions every few months or whatever. But Everquest and WoW are guilty of this. Project 1999, the free-to-play EQ emulator, takes a different approach: provide the content for the original game and first 2 expansions, then leave it at that. People have been playing that shit forever. To get to the point, I would aim for a base game + 1 or 2 expansions to address some deficits of the base game or to expand the game in the direction of the player meta, with some kind of resolution, not in terms of "story", but completeness as a game. Then, keep the game on maintenance mode while developing a sequel, using as much of the original code as possible, with a new world and different and improved gameplay. If you're married to your character and don't want to have to "start all over again", you can keep playing "MMO 1", and be max level and beat 100% of the content, see all the secrets, get best in slot gear, whatever. If you're done with "MMO 1" and you want more of the same experience - discover a new world, figure out the gameplay and the way your class plays, do it all over again, you can move to "MMO 2" when it launches. I have to do some more research to see if any other games managed to do this. Everquest did something similar with Everquest 2, but things were complicated then. They were bleeding subscriptions to WoW, plus most of the original dev team had left or split off to work on Vanguard, another MMORPG. In my opinion, EQ2 deviated too far from the EQ formula for EQ players to be comfortable with, and the pursuit of "realistic" graphics, which was all the rage in those dark times (and these for that matter), didn't help them. As for letting people run their own servers, I don't know. A source release will definitely happen, as well as enough resources to get an original game up and going - documentation, tutorials, example zones/scripts/database/etc. Perhaps like I mentioned above, releasing just the source might "buy enough time" to run the official servers for a few years before the community "catches up" and releases competing titles. We'll see.
Open file (3.76 MB 1282x804 flame.webm)
Animated billboards. Just a texture-mapped plane rotated and scaled according to the "right" part of the camera lookat matrix (perpendicular to the camera look vector and up vector), except for the z axis part, which keeps it upright. // draw a billboard that rotates around the Z-axis, centered at position void draw_billboard(Camera & camera, Texture & texture, Vector3 position, float width, float height, int num_frames, int frame, Color color) { Matrix matView = MatrixLookAt(camera.position, camera.target, camera.up); Vector3 right = {matView.m0, matView.m4, matView.m8}; Vector3 right_normal = vec3_normalize(right); Vector3 top_left; top_left.x = position.x - right_normal.x * width / 2.0f; top_left.y = position.y - right_normal.y * width / 2.0f; top_left.z = position.z + height / 2.0f; Vector3 top_right; top_right.x = position.x + right_normal.x * width / 2.0f; top_right.y = position.y + right_normal.y * width / 2.0f; top_right.z = position.z + height / 2.0f; Vector3 bottom_left = top_left; bottom_left.z -= height; Vector3 bottom_right = top_right; bottom_right.z -= height; rlSetTexture(texture.id); float u_step = 1.0f / num_frames; float u_start = frame * u_step; rlBegin(RL_QUADS); rlColor4ub(color.r, color.g, color.b, color.a); // top-left corner for texture and quad rlTexCoord2f(u_start, 0.0f); rlVertex3f(top_left.x, top_left.y, top_left.z); // bottom-left corner for texture and quad rlTexCoord2f(u_start, 1.0f); rlVertex3f(bottom_left.x, bottom_left.y, bottom_left.z); // bottom-right corner for texture and quad rlTexCoord2f(u_start + u_step, 1.0f); rlVertex3f(bottom_right.x, bottom_right.y, bottom_right.z); // top-right corner for texture and quad rlTexCoord2f(u_start + u_step, 0.0f); rlVertex3f(top_right.x, top_right.y, top_right.z); rlEnd(); rlSetTexture(0); }
Open file (1.21 MB 1288x808 zone1.png)
Open file (1.86 MB 1287x806 zone2.png)
Open file (1.17 MB 1285x805 zone3.png)
Open file (1.08 MB 1920x1080 metrics2.png)
Open file (710.30 KB 1643x918 dungeon.png)
Finally got around to cleaning up the code some and implementing a basic level format for testing, so I can quickly load and switch between different areas depending on what I'm trying to test - scale and metrics, swimming, lighting, etc. Up until now I've had to mess with the source code to drop in a new mesh or something and it's turned into thousands of lines of spaghetti. Still need to implement a proper lighting model where dynamic lights can affect any mesh based on light radius. Still working on blockout scale stuff in between lighting and texture work. I'd like to get an indoor zone up and running some point soon so I'm thinking of taking a page from these guys' book and make a floor/ceiling and a wall prefab and just go nuts with those two meshes, rotating and pulling faces until I got something like a dungeon - like you see in the last pic. You can see a quick try at that in my shots - the stone wall rooms thing is just one 60x60x250cm square pillar copied and pasted and stretched and mashed together at the corners with no regards for topo or z-fighting.
Open file (1.21 MB 1284x803 tpblend1.png)
Open file (1.15 MB 1284x805 tpblend3.png)
Open file (833.58 KB 1287x806 tpblend4.png)
Open file (2.20 MB 1285x803 fixthis.png)
Open file (630.82 KB 1284x803 point_in_frustum.png)
>>937 Minor update - just a few screen shots with no real explanation. Made a modified version of the triplanar blockout shader I did before to blend between the three axis projections, like you see used on heightmapped terrain and the like. Plan on using this for testing lighting in the test dungeon - want to get a better feel of the final look so I need some actual stone textures, not just the 1 meter block-out shits. Discovered a minor bug when using a ray to collide with the ground - player can fall down into even the tinyest of cracks, which is both unrealistic and visually distracting. As a fix I can either implement something to tell whether the player could fit down in the space or not (while hopefully not fucking up the stair/slope handling I spent the better part of three days on) or, use simplified ground geometry, hand-crafter after the zone is built, which may be needed for NPC path-finding anyway, gotta wait and see. And a big step forward for me, implementing a camera frustum and frustum AABB culling. Spent hours on this one, was a nightmare. I tried all the elegant solutions out there where you use the view matrix multiplied by the projection matrix, then do some operations on the matrix rows there to get the 6 planes, represented by 4 floats (somehow, I know the equation for a plane but eh it's weird to me). Then taking the dot product of the vector from the point to the plane and the plane normal then looking at the sign or some shit. Never could get it to work because I can't figure out which of the raylib matrices are the ones I need, nor is it easy to debug print 4x4 matrices and operations on them in real-time. Anyway, I remembered my billboard code and how I obtained the camera up and right vectors from the camera look-at matrix, then used them to plot a plane in world-space. So that's what I ended up doing - getting points at the intersection of the camera look vector and the near and far clip planes, using some trig and the screen ratio to get the corners of those planes, then using those as the 8 corners of my frustum, in world space of course. I then do a simple "half space check" against each corner of the AABB. If a single point of the AABB is "behind" all of the outward-facing frustum planes (inside the frustum), the AABB is within the frustum and thus rendered or updated or whatever. Ran into my first floating point precision bug from the size of the frustum, so had to make a new Vec3Double struct and all the vector operators for it but whatever, it works now. Feels good to finally make some progress on the rendering front. My two biggest obstacles to being able to lay out full-size/fidelity zones right now are "chunking" the visible world geometry and frustum culling the non-visible chunks. Got a preliminary version of the second working now though and at least a plan for the first.
>>943 >using those as the 8 corners of my frustum, in world space of course. I then do a simple "half space check" against each corner of the AABB. If a single point of the AABB is "behind" all of the outward-facing frustum planes (inside the frustum), the AABB is within the frustum and thus rendered or updated or whatever. Correction - I'm retarded. You really want to check if something can be culled or not, not whether it's within the frustum or not. The above approach doesn't take into account collisions between AABB line segments and the frustum, and handling that is quite expensive and unneccesary. The correct approach is actually to find the first frustum plane for which all 8 AABB corners lie on the "outside" of it. If you can find one out of the six planes that satisfies this condition, the object within the AABB is 100% not visible and can be culled. If you can't find such a plane, the thing in the AABB may be visible, and should be updated/rendered.
>>946 Tested with a 22 x 22 x 22 grid of evenly spaced AABBs (total of 10648). I was a little worried at first when I saw 4.5-5 ms time to cull, but then I remembered I was building with debug flags and no optimization. Rebuilt with -O2 and got ~1000us. Culls 10648 down to about 1400-1500 visible by the way. Seems to work well enough for now. Time to actually get some complex terrain and entities in here.
>>943 From the looks of it, you gotta generate collision mesh either way. Or you can have "minimal" height, which probably look better. If player character Z position stays within minimal range, it doesnt visibly change. Ideally you will have torso stay within range, and legs will bend when needed. Not sure how it would look with small ramps tho, but you can figure it out. Also, benefit of collision mesh is loading what player will be able to see from it. Also, easier solution, is to not give small objects collision.
Open file (308.91 KB 1285x805 oct1.png)
Open file (89.43 KB 1284x805 oct2.png)
Open file (1.95 MB 1284x804 octree.webm)
Octree implemented. Got to thinking and came to the conclusion that you can't really get around using one. Got the idea of how to implement properly from thinking about how I would bin each mesh triangle into its respective "chunk" without duplicates or gaps, when I split the zone terrain mesh(es) for rendering/loading. I start by loading all of the models/meshes/whatever. Then, I get an AABB that encompasses them all exactly, which is easy enough, you just find the smallest and largest mesh x point, smallest and largest mesh y point, etc. Then, if I'm encompassing more than 8 meshes in that AABB, I split that AABB into 8 dividing by the length, width, and height. That gives me 8 new AABBs, which I bin the meshes into according to their AABB center point (again, simple to calculate). Then, I recurse, which of course, means for each child AABB, I resize to properly enclose the mesh AABBs, then see how many their are, if more than 8... and so on. I use some flags to indicate empty/leaf node/etc. too. Memory management handled with shared_ptr, as in each Octree has "std::shared_ptr<Octree> nodes[8];" which are instantiated as needed. No malloc/realloc bullshit. The idea for mesh chunking is basically the same except splitting in on a regular 3-dimensional grid, then sorting and re-meshing the tris in each according to originating mesh/mesh material. Those smaller meshes, of which there may be thousands, can then be view culled with an octree. Next thing I have to think about is how to calculate chunk <-> chunk visibility without it taking hours to weeks to "bake". I said before that I'd like to stream the world geometry to each player as they need it. I just have to determine exactly when they need it, based on their position/heading. Have to re-do the collision mesh chunking to work with this octree too. Screenshots - first one is what the whole "zone" looks like. Red boxes are the octree's encompassing AABBs, green are actual mesh AABBs. Second shot and video are what the world looks like through the eyes of placeholder guy.
Open file (104.66 KB 1200x900 capsule_explained.png)
>>948 There is a collision mesh. Or do you mean a simplified, collision-only mesh? I have no plans for any kind of inverse kinematics and I don't really want the feet clipping into the ground any more than they do now (which I spent a long time getting right). I made this pic to show exactly what I'm dealing with. The top half shows some of the problems encountered with a "naive" capsule collider implementation. On flat ground it behaves ok. However, on stairs it's all sorts of fucked. You can get stuck in a floaty halfway-between-stairs state, plus you can't ever really approach the side of the step. On slopes too, you will always be floating a bit off of the ground and it gets worse as the angle increases. Not to mention the way you fly and bounce going down a slope. My approach is the bottom half. I use a capsule for normal wall/ceiling collision, and a ray for ground collision/detection. Raising the capsule lets you get right up to the edge of steps, then "pops" you up to the next one immediately with no "in-between" state - you're either on one step or the other. On slopes, too, it places your origin position exactly on the z-axis value of the slope at that point. I also use a longer ray when moving horizontally or downwards, to detect and "clamp" the player to the slope so you don't bounce down it. The only "bug" I've encountered so far has been falling down into small gaps that the player shouldn't normally be able to. I'm confident I can figure something out though, without radically changing the approach. If I'm missing something obvious though, let me know.
Open file (4.77 MB 1282x800 octree2.webm)
>>949 Thought it would be cool to show the frustum so I gave it a try.

Report/Delete/Moderation Forms

no cookies?