Lumberjacked - WIP Procedural Survival Game

Lumberjacked
***Lumberjacked is a Survival game which I’ve been proposing and started working on today. At the moment, it looks like this;


The early random terrain


How terrain/loot currently looks


In the forest

The landscape is generated using Perlin Noise, and generates as the player walks. Currently, weapons or “Tools” are held depending on the resources which the player has, as are the constructions… which can be initiated where the player is looking.
Everything constructed can be destroyed, and axes and pickaxes can be used to yield materials from trees and rocks. I’m looking at adding mines at a later date. My biggest fear works and works fast! There are now rocks and trees, they don’t grow on slopes… they are randomly distributed based on a separate perlin noise algorithm.

At the moment, I’m working on a shovel which can modify the elevation of the landscape at a particular point, and my so-called ‘Base Structures’, which will require flat ground to be built. Beyond that, I’ll be looking at making enemies and working on the modular building system


Destroying a well for resources

The UI and models are all temporary, but the code is the main focus at the moment. I’m trying to write a foundation so that I won’t need to do so much stuff later on, a unified system so to speak.
If you want to have a gander, you can access the proposal in it’s full size here. I’m not suggesting it’s going to go anywhere, but it’s a bit of an idea which I think I might be able to finish off.

Attachments


Minecraft remake? Only without the irritating cubeworld?
Cool!

That’s pretty much it. Started quite differently as a solid-world urban survival game, but I just decided to get more and more procedural as I went.

Started messing with Weapons/Tools
These guys probably aren’t final either, I’m not happy with them really. Still, I’ll put them up here.

Wood Axe


Battleaxe (Still not sure why I made this, not sure I even want it in the game)


Bow (Also not sure)

Apart from those three, coding is taking up most of the time working on the project. Especially wrapping my head around a procedurally generated landscape with trees and rocks… what a headache! I didn’t dream it would be this difficult. Ah well, I press on.

The weapon handling system is also giving me grief. I hate these walls, they’re impeding my progress… I just want to plow through the walls so I can get to the fun stuff!

The first axe looks really good, though the wedge that keeps the axe-head on should be bigger, and not a small circle (or at least, from all the axes I’ve seen).
Yeah, I think you should remodel the second axe. To be honest, it looks quite terrible ^^;
The bow looks fine as a sort of unrefined bow made by somebody who ust started learning bowmaking (a lv 1 bow so to speak).

I know what you mean, them “walls” can end up being very demotivating :C

Especially wrapping my head around a procedurally generated landscape with trees and rocks… what a headache! I didn’t dream it would be this difficult. Ah well, I press on.

Tell me about it! I spend 2 weeks just trying to figure out the vector interactions! In my case, a 10KBU plane must match a 1BU plane, scale up 10000 times! For now, I placed objects randomly on some vertices, but later will have to use a face density distibution formula. Ecrivain gave me such a script a few years ago! If you need, I can share it with you. Trees are distributed according to vertex color/intensity.

Seriously… You would do that for me? At the moment I’m doing it exactly like your first suggestion… the objects are being placed at the same location as generated vertices. It’s working, and I am currently experimenting with placing objects on vertices randomly and then moving them away from the vertices, also randomly, then aligning them with the normals and sticking them to the plane using a ray. A bit of a stray for a generation script.

The second method I fiddled with was gathering the dimensions of the generated plane and casting rays downwards at random X and Y Co-Ordinates, then adding the terrain at the hit position to align with the normal of the plane.

The problem with both of these methods is… I have no way to efficiently place terrain based on slope. Well, I guess I could, using the first method and measuring the ray cast distance from the vertices where the terrain was placed in Z after movement, and only allowing it if it is under a certain amount. But… wow, actually coding all this stuff? It’s a nightmare

I’d be really intrigued to see the script, if you are willing, if not just because it would save me weeks of headache! Thanks for replying too!

EDIT: Also, if I have any breakthroughs, I’ll be sure to post them here

Is no trouble at all! I just fixed a few things…
I think I’ll be using this as well!

Good luck!

Attachments

vegitation3.blend (118 KB)

oh dear, i also wasted like 2 or 3 weeks of my life last month trying to start a survival game, and i started making the terrain generator(what a mistake!) and ended up with something really crappy, and then didnt want to continue it, seeing your work i think i may finish it, it was going to be pretty much like yours ;D

i made the object distribution like this:
first i have a cube in a hidden layer, that has two distance constraints set to range = 100, force distance = 0, one for the +Z and another for the -Z
so then i spawn that cube in the first layer from any random object with a code like this:

#range is the maximum world coordinate that a object may have
range = 100
propSpawner = scene.addObject("propSpawner", own)
propSpawner.position = [random.uniform(-range, range), random.uniform(-range, range), 0.0]

then i run another code from that newly spawned cube to spawn the prop, and delete the spawner, like this

prop = scene.addObject(random.choice(["tree", "rock", "wathever"]), own)
own.endObject()

thats quite silly, but it works, it has a little of lag at the start, because of all the constraints, but when the cubes are removed, it comes back to 60fps, and it only works for planar worlds, i have no idea how you would implement this to a non planar object

if you didnt understand, i can upload a blend, its incredibly easy to set up after you get how it works
anyway, your game looks nice and makes me want to make a sandbox haha, good luck ;D

-lucki

thats quite silly, but it works, it has a little of lag at the start, because of all the constraints, but when the cubes are removed, it comes back to 60fps, and it only works for planar worlds, i have no idea how you would implement this to a non planar object

It is silly indeed. You can directly spawn the objects where the spawner cube should be place. Furthermore, if your scene is a place like a forest, you can have a better fps and poly count control by spawning all elements at once! Let me explain:

Lets assume, your forest is a 1 km2 area. for every 10k m2, you spawn 100 trees, 50 rocks and 200 variations of bushes maximum. So have those in the scene, out of camera range like 1 000 000 BU away

  1. You generate a props maps determining what object appears where in the map. Or use a random generation function(better option).
  2. Place the props in the area around the player, radius 100
  3. As the player moves, take the further prop and place it back to the distant place or to the new location it is required.

Spawning objects causes lag, so if you start moving the objects around, your frames will improve and you can have various objects around without having to wait until the bge removes the objects, then adds them.

Wonderful! I’ll be sure to test this with my terrain generation as soon as I can, and put the results here. Thanks once again!

Looks like a great method! The way I am doing the terrain generation at the moment, is creating a base mesh using the diamond square algorithm to start. When the player moves near the edge of the mesh, the seed is used to generate a new mesh. The meshes themselves are not saved in the save game, only the seed. Each piece of terrain gets an ID, called a ‘Region’. Soon, each of these regions will be saved if they have had any objects added or the height has been modified in any way.
It seemed very simple in theory, but in practice it was annoying. Getting collision to work properly is now one of a bunch of issues I am trying to iron out.

As for the prop spawning, I’ll give tora’s script a go first, but the way I was working with it was that a small empty (named terrainController) would sit there and watch for when a new ‘region’ is created. Once that happens, it iterates through every vertice in the mesh with a 60% chance of adding a random object to it. Once these objects were added, they each had a script of their own which would move them randomly, cast a ray up and down, then attach themselves to the hit position and align to the normal.

Trouble is, rocks ended up looking funky and trees grew at odd angles. It’s a never-ending puzzle.

Still, I’ll be sticking to the survival genre for the time being :), Would have been nice to see your game!

…then attach themselves to the hit position and align to the normal.

It seems your terrain is planar, so no need to align to the normals, trees normally grow vertically… you can rotate the rock in a random degree!

small empty (named terrainController) would sit there and watch for when a new ‘region’ is created. Once that happens, it iterates through every vertice in the mesh with a 60% chance of adding a random object to it.

Your iteration might be about 3 - 4 times longer if it goes through all vertices(since there might be up to 4 in one spot). What I do is iterate twice: once, I map the vertices in a dict, where each key is the original position for the vertices. Then a second time, now through the dict.keys(), which are about 4 times less. I use the second iteration for all other things, like the use of the terrain deformation function, the placement of props, etc.

Hello infinite terrain, I’m relatively proud of my achievement with this

How did I eventually do my infinite terrain? It works like this:
Initial tile is generated when player spawns, with a radius of 2 60m tiles around the player
As player moves, collision with each tile causes a re-evaluation of which tiles should be around player
Non-required tiles are deleted, new ones created

The entire process is done using Perlin Noise. 2D perlin noise only requires 2 arguments, x and y, then generates a Z value. I used this method to generate my procedural landscape, as each tile is simply the previous one, with a different position in world space. One problem I had is I needed to re-generate my normals, and I was so confused with my shading errors for a long time.

As for water and trees, they should come easily. Using Torakunsama’s wonderful script (albeit slightly modified), and a simple plane generated for water, and a script per-tile… it shouldn’t take long to get them working properly.

One thing I am tackling is weather and time of day. For Time of Day, I would simply rotate the sun, but I would also need to change the sky colours and add a sun in the sky where the sun is. I think I may leave that for a bit later, I need a bit of a recap on my math skills for that sort of thing.

Doing some early work on the main menu, pretty sure I got the right idea here,

Yeah, looks cozy but adventurous.

That’s the plan! Where do you think the buttons should go? Left, right or middle?

Hmm… depends… How many buttons are there going to be? (Start game, Load game and exit for sure, but any others?)

Quick update! The water now has a physics system, with objects being buoyant.


There’s probably a more efficient way to do this, but for the moment it’s done through a script on an object called physicsController. This script iterates through every dynamic object in the scene in the immediate vicinity of the player and adds force to it, depending on how far under the water level it is, multiplied by the object’s “Buoyancy” property, or a default value.
It affects the player too!
The objects are also rotated by the parts with the most volume. Yay!

My water system is working nicely! At the very base, the python script is as simple as this:


#This defines custom physics properties
from bge import logic as g
import mathutils

def main(cont):
    #Water physics
    scene = cont.owner.scene
    
    for object in scene.objects:
        underwater = False
        if object.worldPosition.z < g.sea_level:
            buoyancy = object["buoyancy"] if "buoyancy" in object else 10/3
            object.applyForce(mathutils.Vector((0.0, 0.0, (g.sea_level - object.worldPosition.z)*buoyancy)))
            underwater = True


As for my next struggle, it will be with populating the terrain, At the moment I’m working with torak’s wonderful script, but multiplying the density by the Perlin algorithm to generate “forests” of different trees. Also, I’m working with how performance is going to be, and I have figured out it is better to merely move the trees rather than re-spawn and delete the old ones, so that is what I will do.

As for the other aspect, they will also need LOD’s. This will be done by 3 LOD’s for the tree, a faraway crossed image sprite for when the tree is far in the distance, a second very basic mesh with a few leaves for the second LOD, and the closest LOD with all the detail.

Beyond that, I’m wondering about a random tree generation script. Many ideas!

Ok, another update. I have made a lot of optimizations to what I have already made of the game, meaning I can do a lot more with BGE than I originally hoped for. Another thing I have done is re-written my buoyancy script based on this paper here by intel. It has given me more insight on how to write my water physics, and now they look wonderful!


#This defines custom physics properties
from bge import logic as g
import mathutils
import lumberjacked

def main(cont):
    #Water physics
    scene = cont.owner.scene
    
    fluid_density = 2
    drag = 0.7
    
    for object in scene.objects:
        if object.mass > 0:
    
            #Actual force
            if object.worldPosition.z < g.sea_level:
                volume = object["buoyancy"] if "buoyancy" in object else 5
                
                #Forces
                density = (g.sea_level - object.worldPosition.z)*fluid_density
                bouyancy = density * volume
                drag = (-0.5)*density*(object.getLinearVelocity()[2]*object.getLinearVelocity()[2])*surface_area(object)*drag
                
                
                object.applyForce(mathutils.Vector((0.0, 0.0, bouyancy+drag)))
                
def surface_area(solid):
    
    if "surfaceArea" not in solid:
        
        surface_area = 0
        polygons = 0
        
        for mesh in solid.meshes:
            for p_index in range(mesh.numPolygons):
                poly = mesh.getPolygon(p_index)
                p1 = mesh.getVertex(0, poly.v1).getXYZ()
                p2 = mesh.getVertex(0, poly.v2).getXYZ()
                p3 = mesh.getVertex(0, poly.v3).getXYZ()
                
                if poly.v4 != 0:
                    area = 0
                    area += mathutils.geometry.area_tri(p1, p2, p3)
                    area += mathutils.geometry.area_tri(p1, p2, mesh.getVertex(0, poly.v4).getXYZ())
                    surface_area += area
                else:
                    surface_area += mathutils.geometry.area_tri(p1, p2, p3)
                    
                polygons += 1
                
        lumberjacked.log("Solid " + solid.name + " has had water physics initialised with a surface area of " + str(surface_area))
        solid["surfaceArea"] = surface_area/1000
        
    return solid["surfaceArea"]

As you can see, the script uses the surface area of the object to affect drag, as mentioned in the article. The method was a lot easier to implement than I originally anticipated.

Also, here’s another WIP screenshot of resource mechanics

Due to the new-found efficiency of the chunk spawning system, and the manual LOD applied to every tree and rock, every single tree and rock in that picture can be destroyed, using a ‘destruction script’. I haven’t written these scripts yet, but the framework for them is already in the game. Basically, when the resources are hit… they will show cosmetic damage (visual vertex dinting, tree falls over) until no resources remain, at which point the original resource will dissapear.

Also, sound is beginning to get a bit of thought. Here’s a quick script for the ocean in the game


def loop(cont):
    #This one is for water
    factor = cont.owner["waterDistance"]
    sound = cont.actuators["water"]
    vol = 1-((cont.owner.worldPosition.z - g.sea_level)/factor)
    if vol > 0 and vol < 1:
        sound.volume = vol*g.volume
    
    #Underwater pitch change
#    if cont.owner.parent.parent["underwater"]:
#        for actuator in cont.actuators:
#            actuator.pitch = -0.5
#    else:
#        for actuator in cont.actuators:
#            actuator.pitch = 0.0

All this stuff is way over my head, It looks amazing. (Makes me want to learn python ect.)