private static GameObject CreateShip(VoxelTypes types, MaterialInstance materialInstance) { var gridLength = 4; var voxelSize = 1; var voxelSpaceData = new VoxelGridData(gridLength, gridLength, gridLength, voxelSize); voxelSpaceData[0, 0, 0] = new Voxel() { Exists = true }; var voxelSpace = new VoxelSpace(new Vector3i(gridLength, gridLength, gridLength), voxelSize); var spaceShip = new GameObject("Single Block"); spaceShip.AddComponent(voxelSpace); spaceShip.AddComponent(new DynamicVoxelSpaceBody()); spaceShip.AddComponent(new Construct()); spaceShip.AddComponent(new ConstructFlightControl()); spaceShip.AddComponent(new ConstructVoxelSpaceExpander(types, materialInstance)); var voxelGridObj = new GameObject($"{spaceShip.Name} Voxel Grid"); voxelGridObj.AddComponent(new VoxelGrid(voxelSpaceData, new Dictionary <Vector3i, GameObject>())); voxelGridObj.AddComponent(new VoxelMeshRenderable(types, materialInstance)); //voxelGridObj.AddComponent(new VoxelGridRenderable(types, materialInstance)); voxelSpace.Add(new Vector3i(0, 0, 0), voxelGridObj); return(spaceShip); }
public Job_PlantSeed(Vector2i plantPos, VoxelTypes seedType, IGrowPattern growPattern) : base(Labors.Farm, "Plant Seed", "Planting seed") { PlantPos = plantPos; SeedType = seedType; GrowPattern = growPattern; }
public override void OnBlockChanged(Vector2i block, VoxelTypes newValue) { //If we can't plant a seed here anymore, the job should be cancelled. if (!WorldVoxels.CanPlantOn(WorldVoxels.GetVoxelAt(PlantPos.LessY)) || !WorldVoxels.CanPlantIn(WorldVoxels.GetVoxelAt(PlantPos))) { if (elveMovement != null) { StopJob(false, "Can't plant seed anymore"); } else { Cancel("Can't plant seed anymore"); } return; } //If there is an Elve doing this job, and his path was affected, recalculate pathing. System.Func<VoxelNode, bool> isAffected = (n) => { return Mathf.Abs(block.x - n.WorldPos.x) <= 1 && Mathf.Abs(block.y - n.WorldPos.y) <= 1; }; if (elveMovement != null && elveMovement.Path.Any(isAffected)) { if (!elveMovement.StartPath(PlantPos)) { StopJob(true, "Path became blocked"); return; } } }
public GrowData(Vector2i sproutPos, VoxelTypes treeType, Vector2i minBoundBox, Vector2i maxBoundBox) { SproutPos = sproutPos; TreeType = treeType; MinBoundBox = minBoundBox; MaxBoundBox = maxBoundBox; }
public ChunkGenerator(VoxelTypes types, MaterialInstance materialInstance, int chunkSize, int voxelSize) { _types = types; _materialInstance = materialInstance; _chunkSize = chunkSize; _voxelSize = voxelSize; _noise = new FastNoise(DateTime.Now.Second); _noise.SetFrequency(0.08f); }
public VoxelGridMesher(EntityCommandRecorder commandRecorder, World world, VoxelTypes types, GraphicsDevice device, IParallelRunner runner) : base(world, runner) { _commandRecorder = commandRecorder; _types = types; _device = device; _vertices = new ThreadLocal <PooledList <VertexPositionTextureNormal> >(() => new PooledList <VertexPositionTextureNormal>()); _indices = new ThreadLocal <PooledList <ushort> >(() => new PooledList <ushort>()); _transIndices = new ThreadLocal <PooledList <ushort> >(() => new PooledList <ushort>()); _lights = new ThreadLocal <PooledList <float> >(() => new PooledList <float>()); }
public static void FindExposedSides(ref VoxelGrid grid, VoxelTypes types, T sideProcessor) { var space = grid.VoxelSpace; for (int x = 0; x < grid.GridSize; x++) { for (int y = 0; y < grid.GridSize; y++) { for (int z = 0; z < grid.GridSize; z++) { Voxel voxel = grid[x, y, z]; if (voxel.Exists) { if (ShouldRenderSide(ref grid, ref space, types, voxel.BlockType, x, y - 1, z)) { sideProcessor.Process(x, y, z, VoxelSide.BOTTOM); } if (ShouldRenderSide(ref grid, ref space, types, voxel.BlockType, x + 1, y, z)) { sideProcessor.Process(x, y, z, VoxelSide.EAST); } if (ShouldRenderSide(ref grid, ref space, types, voxel.BlockType, x - 1, y, z)) { sideProcessor.Process(x, y, z, VoxelSide.WEST); } if (ShouldRenderSide(ref grid, ref space, types, voxel.BlockType, x, y + 1, z)) { sideProcessor.Process(x, y, z, VoxelSide.TOP); } if (ShouldRenderSide(ref grid, ref space, types, voxel.BlockType, x, y, z - 1)) { sideProcessor.Process(x, y, z, VoxelSide.NORTH); } if (ShouldRenderSide(ref grid, ref space, types, voxel.BlockType, x, y, z + 1)) { sideProcessor.Process(x, y, z, VoxelSide.SOUTH); } } } } } }
private static bool ShouldRenderSide(VoxelGrid grid, VoxelTypes types, ushort otherType, int x, int y, int z) { var voxelIndex = new Vector3i(x, y, z); if (grid.ContainsIndex(voxelIndex)) { var voxel = grid[x, y, z]; return(!voxel.Exists || (types[voxel.BlockType].Transparent && voxel.BlockType != otherType)); } else { var spaceIndex = grid.VoxelSpace.GetSpaceIndexFromVoxelIndex(grid.MemberIndex, voxelIndex); var voxel = grid.VoxelSpace.GetVoxel(spaceIndex); return(!voxel.HasValue || !voxel.Value.Exists || (types[voxel.Value.BlockType].Transparent && voxel.Value.BlockType != otherType)); } }
private void InitializedVoxelData() { chunkData = new VoxelTypes[CHUNK_SIZE][][]; for (int i = 0; i < CHUNK_SIZE; i++) { chunkData[i] = new VoxelTypes[CHUNK_SIZE][]; for (int j = 0; j < CHUNK_SIZE; j++) { chunkData[i][j] = new VoxelTypes[CHUNK_SIZE]; for (int k = 0; k < CHUNK_SIZE; k++) { // if(j <= 10){ chunkData[i][j][k] = VoxelTypes.Default; // } // else{ // chunkData[i][j][k] = VoxelTypes.Air; // } } } } }
public List<Vector2i> Grow(VoxelTypes[,] worldGrid, GrowData dataBase) { GrowData_Oak dat = (GrowData_Oak)dataBase; List<Vector2i> changed = new List<Vector2i>(); //Clear out the current leaves. changed.Capacity += dat.Leaves.Count; for (int i = 0; i < dat.Leaves.Count; ++i) { worldGrid[dat.Leaves[i].x, dat.Leaves[i].y] = VoxelTypes.Empty; changed.Add(dat.Leaves[i]); } dat.Leaves.Clear(); //Extend the tree-top upwards. Vector2i counter = new Vector2i(dat.SproutPos.x, dat.TopY); for (int i = 0; i < GrowthRate && counter.y < worldGrid.GetLength(1) - 1; ++i) { counter.y += 1; if (!WorldVoxels.IsTreeFodder(worldGrid[counter.x, counter.y])) { break; } worldGrid[counter.x, counter.y] = dat.TreeType; changed.Add(counter); dat.TopY = counter.y; dat.MaxBoundBox.y = UnityEngine.Mathf.Max(dat.MaxBoundBox.y, counter.y); } //Add leaves spreading out from the top. dat.LeavesRadius += 1; AddLeaves(dat, worldGrid); changed.Capacity += dat.Leaves.Count; changed.AddRange(dat.Leaves); return changed; }
//this method acts as a filter of primitive types, dont want quads and planes GameObject getVoxelType(VoxelTypes option) { switch (option) { case VoxelTypes.Cube: return(GameObject.CreatePrimitive(PrimitiveType.Cube)); case VoxelTypes.Sphere: return(GameObject.CreatePrimitive(PrimitiveType.Sphere)); case VoxelTypes.Cylinder: return(GameObject.CreatePrimitive(PrimitiveType.Cylinder)); case VoxelTypes.Capsule: return(GameObject.CreatePrimitive(PrimitiveType.Capsule)); case VoxelTypes.Custom: return(customVoxel); default: return(GameObject.CreatePrimitive(PrimitiveType.Cube)); } }
public BasicVoxelAddingTool(string name, ushort voxelType, VoxelTypes types, MaterialInstance materialInstance) : base(voxelType, types, materialInstance) { Name = name; }
public ThrusterVoxelEditingTool(Rectangle flameRect, MaterialInstance flameMaterial, ushort voxelType, VoxelTypes types, MaterialInstance materialInstance) : base(voxelType, types, materialInstance) { _flameRect = flameRect; _flameMaterial = flameMaterial; }
/// <summary> /// Whether the given voxel can have seeds planted on its outside surface. /// </summary> public static bool CanPlantOn(VoxelTypes type) { return canPlantOn[(int)type]; }
/// <summary> /// Sets the given world position to contain the given block. /// Assumes the given position is inside the world's voxel grid. /// Automatically updates secondary data like meshes, jobs, and pathing. /// </summary> public void SetVoxelAt(Vector2i worldPos, VoxelTypes newValue) { Vector2i chunkPos = new Vector2i(worldPos.x / Chunk.Size, worldPos.y / Chunk.Size); Voxels[worldPos.x, worldPos.y] = newValue; Chunks[chunkPos.x, chunkPos.y].RegenMesh(); VoxelTex.SetPixel(worldPos.x, worldPos.y, GetVoxelTexValue(newValue)); VoxelTex.Apply(); //Re-calculate connections for adjacent voxels as well as this one. for (int y = -1; y <= 1; ++y) { for (int x = -1; x <= 1; ++x) { GetConnections(new Vector2i(worldPos.x + x, worldPos.y + y)); } } JobManager.Instance.OnBlockChanged(worldPos, newValue); }
public VoxelAddingTool(ushort voxelType, VoxelTypes types, MaterialInstance materialInstance) { VoxelType = voxelType; _types = types; _materialInstance = materialInstance; }
/// <summary> /// Called when the given voxel is changed. Lets this job react to that information. /// </summary> public abstract void OnBlockChanged(Vector2i block, VoxelTypes newValue);
public GrowData_Oak(Vector2i sproutPos, VoxelTypes treeType) : base(sproutPos, treeType, sproutPos, sproutPos) { Leaves = new List<Vector2i>(); TopY = SproutPos.y; }
/// <summary> /// The recursive loop for adding leaves to the top of a tree. /// </summary> private static void AddLeaves_Iterate(Vector2i pos, int stepsLeft, VoxelTypes[,] worldGrid, GrowData_Oak dat) { if (WorldVoxels.IsTreeFodder(worldGrid[pos.x, pos.y])) { worldGrid[pos.x, pos.y] = VoxelTypes.Leaf; dat.Leaves.Add(pos); dat.MinBoundBox.x = UnityEngine.Mathf.Min(dat.MinBoundBox.x, pos.x); dat.MinBoundBox.y = UnityEngine.Mathf.Min(dat.MinBoundBox.y, pos.y); dat.MaxBoundBox.x = UnityEngine.Mathf.Max(dat.MaxBoundBox.x, pos.x); dat.MaxBoundBox.y = UnityEngine.Mathf.Max(dat.MaxBoundBox.y, pos.y); if (stepsLeft > 0) { stepsLeft -= 1; if (pos.x > 0) { AddLeaves_Iterate(pos.LessX, stepsLeft, worldGrid, dat); } if (pos.x < worldGrid.GetLength(0) - 1) { AddLeaves_Iterate(pos.MoreX, stepsLeft, worldGrid, dat); } if (pos.y > 0) { AddLeaves_Iterate(pos.LessY, stepsLeft, worldGrid, dat); } if (pos.y < worldGrid.GetLength(1) - 1) { AddLeaves_Iterate(pos.MoreY, stepsLeft, worldGrid, dat); } } } }
/// <summary> /// Adds leaves to the top of the given oak tree. /// </summary> private static void AddLeaves(GrowData_Oak dat, VoxelTypes[,] worldGrid) { Vector2i topPos = new Vector2i(dat.SproutPos.x, dat.TopY); if (topPos.x > 0) { AddLeaves_Iterate(topPos.LessX, dat.LeavesRadius, worldGrid, dat); } if (topPos.x < worldGrid.GetLength(0) - 1) { AddLeaves_Iterate(topPos.MoreX, dat.LeavesRadius, worldGrid, dat); } if (topPos.y < worldGrid.GetLength(1) - 1) { AddLeaves_Iterate(topPos.MoreY, dat.LeavesRadius, worldGrid, dat); } }
public GrowData Sprout(VoxelTypes[,] worldGrid, VoxelTypes treeType, Vector2i seedPos, List<Vector2i> changedPoses) { GrowData_Oak dat = new GrowData_Oak(seedPos, treeType); worldGrid[seedPos.x, seedPos.y] = treeType; changedPoses.Add(seedPos); dat.TopY = seedPos.y; //If we have room, add another tree block above it. if (seedPos.y < worldGrid.GetLength(1) - 1) { Vector2i above = seedPos.MoreY; if (WorldVoxels.IsTreeFodder(worldGrid[above.x, above.y])) { worldGrid[above.x, above.y] = treeType; changedPoses.Add(above); dat.TopY = above.y; dat.MaxBoundBox.y += 1; } } //Add a few leaves. AddLeaves(dat, worldGrid); changedPoses.Capacity += dat.Leaves.Count; changedPoses.AddRange(dat.Leaves); return dat; }
public TypeAndFriction(VoxelTypes t, float f) { Type = t; Friction = f; }
/// <summary> /// Gets the color for the given block in the voxel texture. /// </summary> public static Color GetVoxelTexValue(VoxelTypes block) { bool solid = IsSolid(block); return new Color(solid ? 1.0f : 0.0f, solid ? WaterConstants.Instance.Friction[(int)block].Friction : 0.0f, 0.0f, 0.0f); }
void showVoxelSelector() { EditorGUILayout.BeginHorizontal(); voxelType = (VoxelTypes)EditorGUILayout.EnumPopup("Voxel Type", voxelType); EditorGUILayout.EndHorizontal(); }
/// <summary> /// Converts between seed types and their corresponding tree types. /// Returns "Empty" if the given type isn't a seed or a tree. /// </summary> public static VoxelTypes ConvertSeedTypeTreeType(VoxelTypes type) { return seedTreeConverter[(int)type]; }
static void Main(string[] args) { WindowCreateInfo wci = new WindowCreateInfo { X = 100, Y = 100, WindowWidth = 1280, WindowHeight = 720, WindowTitle = "Tortuga Demo" }; GraphicsDeviceOptions options = new GraphicsDeviceOptions( debug: false, swapchainDepthFormat: PixelFormat.R16_UNorm, syncToVerticalBlank: true, resourceBindingModel: ResourceBindingModel.Improved, preferDepthRangeZeroToOne: true, preferStandardClipSpaceYDirection: true); #if DEBUG options.Debug = true; #endif var scene = new Scene(); var types = new VoxelTypes(new[] { new VoxelType( "DarkStone", new Vector2(390, 1690), new Vector2(390, 1690), new Vector2(390, 1690)), new VoxelType( "Metal", new Vector2(650, 1300), new Vector2(650, 1300), new Vector2(650, 1300)), new VoxelType( "Thruster", new Vector2(650, 1170), new Vector2(650, 1300), new Vector2(650, 1300)) }); var resourceLoader = new ResourceLoader(); var voxelTexturesResource = resourceLoader.LoadImage("Assets\\spritesheet_tiles.png"); var mesh3dMaterial = new Material(Mesh3d.VertexCode, Mesh3d.FragmentCode); var voxelMaterialInstance = new MaterialInstance(mesh3dMaterial, voxelTexturesResource, new ObjectProperties() { Colour = RgbaFloat.White }); var noCullingMaterial = new Material(Mesh3d.VertexCode, Mesh3d.UnlitFragmentCode, true); var noCullingVoxelMaterial = new MaterialInstance(noCullingMaterial, voxelTexturesResource, new ObjectProperties() { Colour = RgbaFloat.White }); //var cross = QuadCrossFactory.Build(new Rectangle(390, 130, 128, 128), true, noCullingVoxelMaterial); //cross.Name = "Cross"; //scene.AddGameObject(cross); var tools = new Tool[] { new RemoveVoxelEditingTool() { Name = "Remove" }, new BasicVoxelAddingTool("DarkStone", 0, types, voxelMaterialInstance), new BasicVoxelAddingTool("Metal", 1, types, voxelMaterialInstance), new ThrusterVoxelEditingTool(new Rectangle(390, 130, 128, 128), noCullingVoxelMaterial, 2, types, voxelMaterialInstance) { Name = "Thruster" } }; var px = Image.Load("Assets\\skybox_px.png"); var nx = Image.Load("Assets\\skybox_nx.png"); var py = Image.Load("Assets\\skybox_py.png"); var ny = Image.Load("Assets\\skybox_ny.png"); var pz = Image.Load("Assets\\skybox_pz.png"); var nz = Image.Load("Assets\\skybox_nz.png"); var camera = new GameObject("Player"); camera.Transform.Position = new Vector3(0, 0, 3); camera.AddComponent(new Camera()); camera.AddComponent(new Character()); camera.AddComponent(new CharacterInput()); camera.AddComponent(new ComponentSwitcher(tools)); //camera.AddComponent(new EditorMenu()); //camera.AddComponent(new Inspector()); //camera.AddComponent(new Clunker.Editor.Console.Console()); camera.AddComponent(new Skybox(px, nx, py, ny, pz, nz)); scene.AddGameObject(camera); var ship = CreateShip(types, voxelMaterialInstance); scene.AddGameObject(ship); //camera.AddComponent(new ObjectFollower() { ToFollow = ship, Distance = new Vector3(0.5f, 1, 6) }); var chunkSize = 32; var worldSpaceObj = new GameObject("World Space"); var worldSpace = new VoxelSpace(new Vector3i(chunkSize, chunkSize, chunkSize), 1); worldSpaceObj.AddComponent(worldSpace); scene.AddGameObject(worldSpaceObj); var worldSystem = new WorldSystem( camera, worldSpace, new ChunkStorage(), new ChunkGenerator(types, voxelMaterialInstance, chunkSize, 1), 10, chunkSize); scene.AddSystem(worldSystem); scene.AddSystem(new PhysicsSystem()); var app = new ClunkerApp(resourceLoader, scene); app.Start(wci, options).Wait(); }
public ThrusterVoxelEditingTool(ushort voxelType, VoxelTypes types, MaterialInstance materialInstance) : base(voxelType, types, materialInstance) { }
/// <summary> /// Whether the given voxel is a tree block (not including leaves). /// </summary> public static bool IsTree(VoxelTypes type) { return isTree[(int)type]; }
/// <summary> /// Whether the given voxel is a solid surface. /// </summary> public static bool IsSolid(VoxelTypes type) { return isSolid[(int)type]; }
public VoxelGridMesher(Scene scene, VoxelTypes types, GraphicsDevice device, IParallelRunner runner) : base(scene.World, runner) { _scene = scene; _types = types; _device = device; }
/// <summary> /// Whether a tree can destroy/grow over the given type of block. /// </summary> public static bool IsTreeFodder(VoxelTypes type) { return isTreeFodder[(int)type]; }
public VoxelData(VoxelTypes type, Vector2 subTexturePixelMin) { Type = type; SubTexturePixelMin = subTexturePixelMin; }
/// <summary> /// Whether the given voxel is an item, like a planted seed. /// </summary> public static bool IsItem(VoxelTypes type) { return isItem[(int)type]; }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Classification functions /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public void ActivateType(VoxelTypes newType) { typeIntensityValue[(int)newType] = 1; }
private VoxelTypes CycleVoxel(VoxelTypes inV) { return (WorldVoxels.IsSolid(inV) ? VoxelTypes.Empty : VoxelTypes.Dirt); }