first commit

This commit is contained in:
2022-07-08 09:14:55 +08:00
commit 4d6bd72555
1123 changed files with 456307 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 26fec7636ebd7ae43a99e2c187ed6500
folderAsset: yes
timeCreated: 1524052388
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Black
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 5
m_CustomRenderQueue: -1
stringTagMap: {}
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Cutoff
second: 0.5
data:
first:
name: _Parallax
second: 0.02
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: 0.33
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 0.06666667, g: 0.06666667, b: 0.06666667, a: 1}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1598ff147655ecb4893e78f88baa9475
timeCreated: 1524052433
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: LightGreen
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 5
m_CustomRenderQueue: -1
stringTagMap: {}
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Cutoff
second: 0.5
data:
first:
name: _Parallax
second: 0.02
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: 0.5
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 0.6397059, g: 0.63179064, b: 0.35277897, a: 1}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cd644746d7159df42b0c206b559af881
timeCreated: 1524052433
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Orange
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 5
m_CustomRenderQueue: -1
stringTagMap: {}
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Cutoff
second: 0.5
data:
first:
name: _Parallax
second: 0.02
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: 0.32
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0.2
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 1, g: 0.52796555, b: 0, a: 1}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 09adc4af150569a4cb996354c367b8c8
timeCreated: 1524052433
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Red
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 5
m_CustomRenderQueue: -1
stringTagMap: {}
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Cutoff
second: 0.5
data:
first:
name: _Parallax
second: 0.02
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: 0.45
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 0.7058823, g: 0.15069398, b: 0, a: 1}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ad7ce727a68a61f4897679b81da7b344
timeCreated: 1524052433
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,138 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 6
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 0}
m_Name: Yellow
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
m_ShaderKeywords:
m_LightmapFlags: 5
m_CustomRenderQueue: -1
stringTagMap: {}
m_SavedProperties:
serializedVersion: 2
m_TexEnvs:
data:
first:
name: _MainTex
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _BumpMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailNormalMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _ParallaxMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _OcclusionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _EmissionMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailMask
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _DetailAlbedoMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
data:
first:
name: _MetallicGlossMap
second:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Floats:
data:
first:
name: _SrcBlend
second: 1
data:
first:
name: _DstBlend
second: 0
data:
first:
name: _Cutoff
second: 0.5
data:
first:
name: _Parallax
second: 0.02
data:
first:
name: _ZWrite
second: 1
data:
first:
name: _Glossiness
second: 0.5
data:
first:
name: _BumpScale
second: 1
data:
first:
name: _OcclusionStrength
second: 1
data:
first:
name: _DetailNormalMapScale
second: 1
data:
first:
name: _UVSec
second: 0
data:
first:
name: _Mode
second: 0
data:
first:
name: _Metallic
second: 0
m_Colors:
data:
first:
name: _EmissionColor
second: {r: 0, g: 0, b: 0, a: 1}
data:
first:
name: _Color
second: {r: 0.972, g: 0.72733563, b: 0.025086528, a: 1}

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 90623549d4482f042ade35d8a0758e35
timeCreated: 1524052433
licenseType: Store
NativeFormatImporter:
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e1fad393017993c4893877b645062417
timeCreated: 1521730297
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,9 @@
fileFormatVersion: 2
guid: 66ccfe3c456c20c4f9de20d08685de69
folderAsset: yes
timeCreated: 1521730244
licenseType: Store
DefaultImporter:
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,14 @@
using UnityEngine;
namespace Photon.Pun.Demo.Procedural
{
/// <summary>
/// The Block component is attach to each instantiated Block at runtime.
/// It provides the Block's ID as well as the parent's Cluster ID in order to apply modifications.
/// </summary>
public class Block : MonoBehaviour
{
public int BlockId { get; set; }
public int ClusterId { get; set; }
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 8b205f33043c113489ab36d5b56f7730
timeCreated: 1521735355
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,178 @@
using System.Collections.Generic;
using UnityEngine;
using ExitGames.Client.Photon;
namespace Photon.Pun.Demo.Procedural
{
/// <summary>
/// The Cluster component has references to all Blocks that are part of this Cluster.
/// It provides functions for modifying single Blocks inside this Cluster.
/// It also handles modifications made to the world by other clients.
/// </summary>
public class Cluster : MonoBehaviourPunCallbacks
{
private string propertiesKey;
private Dictionary<int, float> propertiesValue;
public int ClusterId { get; set; }
public Dictionary<int, GameObject> Blocks { get; private set; }
#region UNITY
public void Awake()
{
Blocks = new Dictionary<int, GameObject>();
propertiesValue = new Dictionary<int, float>();
}
/// <summary>
/// Sets the unique key of this Cluster used for storing modifications within the Custom Room Properties.
/// </summary>
private void Start()
{
propertiesKey = "Cluster " + ClusterId;
}
#endregion
#region CLASS FUNCTIONS
/// <summary>
/// Adds a Block to the Cluster.
/// This is called by the WorldGenerator while the generation process is running.
/// In order to modify Blocks directly, we are storing the ID as well as a reference to the certain GameObject.
/// </summary>
public void AddBlock(int blockId, GameObject block)
{
Blocks.Add(blockId, block);
}
/// <summary>
/// Gets called before a new world can be generated.
/// Destroys each Block from this Cluster and removes the data stored in the Custom Room Properties.
/// </summary>
public void DestroyCluster()
{
foreach (GameObject block in Blocks.Values)
{
Destroy(block);
}
Blocks.Clear();
if (PhotonNetwork.IsMasterClient)
{
RemoveClusterFromRoomProperties();
}
}
/// <summary>
/// Decreases a Block's height locally before applying the modification to the Custom Room Properties.
/// </summary>
public void DecreaseBlockHeight(int blockId)
{
float height = Blocks[blockId].transform.localScale.y;
height = Mathf.Max((height - 1.0f), 0.0f);
SetBlockHeightLocal(blockId, height);
}
/// <summary>
/// Increases a Block's height locally before applying the modification to the Custom Room Properties.
/// </summary>
public void IncreaseBlockHeight(int blockId)
{
float height = Blocks[blockId].transform.localScale.y;
height = Mathf.Min((height + 1.0f), 8.0f);
SetBlockHeightLocal(blockId, height);
}
/// <summary>
/// Gets called when a remote client has modified a certain Block within this Cluster.
/// Called by the WorldGenerator or the Cluster itself after the Custom Room Properties have been updated.
/// </summary>
public void SetBlockHeightRemote(int blockId, float height)
{
GameObject block = Blocks[blockId];
Vector3 scale = block.transform.localScale;
Vector3 position = block.transform.localPosition;
block.transform.localScale = new Vector3(scale.x, height, scale.z);
block.transform.localPosition = new Vector3(position.x, height / 2.0f, position.z);
}
/// <summary>
/// Gets called whenever the local client modifies any Block within this Cluster.
/// The modification will be applied to the Block first before it is published to the Custom Room Properties.
/// </summary>
private void SetBlockHeightLocal(int blockId, float height)
{
GameObject block = Blocks[blockId];
Vector3 scale = block.transform.localScale;
Vector3 position = block.transform.localPosition;
block.transform.localScale = new Vector3(scale.x, height, scale.z);
block.transform.localPosition = new Vector3(position.x, height / 2.0f, position.z);
UpdateRoomProperties(blockId, height);
}
/// <summary>
/// Gets called in order to update the Custom Room Properties with the modification made by the local client.
/// </summary>
private void UpdateRoomProperties(int blockId, float height)
{
propertiesValue[blockId] = height;
Hashtable properties = new Hashtable {{propertiesKey, propertiesValue}};
PhotonNetwork.CurrentRoom.SetCustomProperties(properties);
}
/// <summary>
/// Removes the modifications of this Cluster from the Custom Room Properties.
/// </summary>
private void RemoveClusterFromRoomProperties()
{
Hashtable properties = new Hashtable {{propertiesKey, null}};
PhotonNetwork.CurrentRoom.SetCustomProperties(properties);
}
#endregion
#region PUN CALLBACKS
/// <summary>
/// Gets called whenever the Custom Room Properties are updated.
/// When the changed properties contain the previously set PropertiesKey (basically the Cluster ID),
/// the Cluster and its Blocks will be updated accordingly.
/// </summary>
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
if (propertiesThatChanged.ContainsKey(propertiesKey))
{
if (propertiesThatChanged[propertiesKey] == null)
{
propertiesValue = new Dictionary<int, float>();
return;
}
propertiesValue = (Dictionary<int, float>) propertiesThatChanged[propertiesKey];
foreach (KeyValuePair<int, float> pair in propertiesValue)
{
SetBlockHeightRemote(pair.Key, pair.Value);
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 3fde284a91e7bf14dbf72b084e11736d
timeCreated: 1521731876
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,269 @@
using ExitGames.Client.Photon;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.UI;
namespace Photon.Pun.Demo.Procedural
{
/// <summary>
/// The Ingame Control Panel basically controls the WorldGenerator.
/// It is only interactable for the current MasterClient in the room.
/// </summary>
public class IngameControlPanel : MonoBehaviourPunCallbacks
{
private bool isSeedValid;
private InputField seedInputField;
private Dropdown worldSizeDropdown;
private Dropdown clusterSizeDropdown;
private Dropdown worldTypeDropdown;
private Button generateWorldButton;
#region UNITY
/// <summary>
/// When the object gets created, all necessary references are set up.
/// Also the UI elements get set up properly in order to control the WorldGenerator.
/// </summary>
public void Awake()
{
isSeedValid = false;
seedInputField = GetComponentInChildren<InputField>();
seedInputField.characterLimit = 10;
seedInputField.characterValidation = InputField.CharacterValidation.Integer;
seedInputField.interactable = PhotonNetwork.PhotonServerSettings.StartInOfflineMode;
seedInputField.onValueChanged.AddListener((string value) =>
{
int seed;
if (int.TryParse(value, out seed))
{
isSeedValid = true;
WorldGenerator.Instance.Seed = seed;
}
else
{
isSeedValid = false;
Debug.LogError("Invalid Seed entered. Only numeric Seeds are allowed.");
}
});
worldSizeDropdown = GetComponentsInChildren<Dropdown>()[0];
worldSizeDropdown.interactable = PhotonNetwork.PhotonServerSettings.StartInOfflineMode;
worldSizeDropdown.onValueChanged.AddListener((int value) =>
{
switch (value)
{
case 0:
{
WorldGenerator.Instance.WorldSize = WorldSize.Tiny;
break;
}
case 1:
{
WorldGenerator.Instance.WorldSize = WorldSize.Small;
break;
}
case 2:
{
WorldGenerator.Instance.WorldSize = WorldSize.Medium;
break;
}
case 3:
{
WorldGenerator.Instance.WorldSize = WorldSize.Large;
break;
}
}
});
clusterSizeDropdown = GetComponentsInChildren<Dropdown>()[1];
clusterSizeDropdown.interactable = PhotonNetwork.PhotonServerSettings.StartInOfflineMode;
clusterSizeDropdown.onValueChanged.AddListener((int value) =>
{
switch (value)
{
case 0:
{
WorldGenerator.Instance.ClusterSize = ClusterSize.Small;
break;
}
case 1:
{
WorldGenerator.Instance.ClusterSize = ClusterSize.Medium;
break;
}
case 2:
{
WorldGenerator.Instance.ClusterSize = ClusterSize.Large;
break;
}
}
});
worldTypeDropdown = GetComponentsInChildren<Dropdown>()[2];
worldTypeDropdown.interactable = PhotonNetwork.PhotonServerSettings.StartInOfflineMode;
worldTypeDropdown.onValueChanged.AddListener((int value) =>
{
switch (value)
{
case 0:
{
WorldGenerator.Instance.WorldType = WorldType.Flat;
break;
}
case 1:
{
WorldGenerator.Instance.WorldType = WorldType.Standard;
break;
}
case 2:
{
WorldGenerator.Instance.WorldType = WorldType.Mountain;
break;
}
}
});
generateWorldButton = GetComponentInChildren<Button>();
generateWorldButton.interactable = PhotonNetwork.PhotonServerSettings.StartInOfflineMode;
generateWorldButton.onClick.AddListener(() =>
{
if (!PhotonNetwork.InRoom)
{
Debug.LogError("Client is not in a room.");
return;
}
if (!isSeedValid)
{
Debug.LogError("Invalid Seed entered. Only numeric Seeds are allowed.");
return;
}
WorldGenerator.Instance.ConfirmAndUpdateProperties();
});
}
#endregion
#region PUN CALLBACKS
/// <summary>
/// Gets called when the local client has joined the room.
/// Since only the MasterClient can control the WorldGenerator,
/// we are checking if we have to make the UI controls available for the local client.
/// </summary>
public override void OnJoinedRoom()
{
seedInputField.interactable = PhotonNetwork.IsMasterClient;
worldSizeDropdown.interactable = PhotonNetwork.IsMasterClient;
clusterSizeDropdown.interactable = PhotonNetwork.IsMasterClient;
worldTypeDropdown.interactable = PhotonNetwork.IsMasterClient;
generateWorldButton.interactable = PhotonNetwork.IsMasterClient;
}
/// <summary>
/// Gets called whenever the current MasterClient has left the room and a new one is selected.
/// If the local client is the new MasterClient, we make the UI controls available for him.
/// </summary>
public override void OnMasterClientSwitched(Player newMasterClient)
{
seedInputField.interactable = newMasterClient.IsLocal;
worldSizeDropdown.interactable = newMasterClient.IsLocal;
clusterSizeDropdown.interactable = newMasterClient.IsLocal;
worldTypeDropdown.interactable = newMasterClient.IsLocal;
generateWorldButton.interactable = newMasterClient.IsLocal;
}
/// <summary>
/// Gets called whenever the Custom Room Properties are updated.
/// In this callback we are interested in the settings the MasterClient can apply to the WorldGenerator.
/// If all possible settings are updated (and available within the updated properties), these settings are also used
/// to update the Ingame Control Panel as well as the WorldGenerator on all clients.
/// Afterwards the WorldGenerator creates a new world with the new settings.
/// </summary>
public override void OnRoomPropertiesUpdate(Hashtable propertiesThatChanged)
{
if (propertiesThatChanged.ContainsKey(WorldGenerator.Instance.SeedPropertiesKey) && propertiesThatChanged.ContainsKey(WorldGenerator.Instance.WorldSizePropertiesKey) && propertiesThatChanged.ContainsKey(WorldGenerator.Instance.ClusterSizePropertiesKey) && propertiesThatChanged.ContainsKey(WorldGenerator.Instance.WorldTypePropertiesKey))
{
// Updating Seed
int seed = (int) propertiesThatChanged[WorldGenerator.Instance.SeedPropertiesKey];
seedInputField.text = seed.ToString();
// Updating World Size
WorldSize worldSize = (WorldSize) propertiesThatChanged[WorldGenerator.Instance.WorldSizePropertiesKey];
switch (worldSize)
{
case WorldSize.Tiny:
{
worldSizeDropdown.value = 0;
break;
}
case WorldSize.Small:
{
worldSizeDropdown.value = 1;
break;
}
case WorldSize.Medium:
{
worldSizeDropdown.value = 2;
break;
}
case WorldSize.Large:
{
worldSizeDropdown.value = 3;
break;
}
}
// Updating Cluster Size
ClusterSize clusterSize = (ClusterSize) propertiesThatChanged[WorldGenerator.Instance.ClusterSizePropertiesKey];
switch (clusterSize)
{
case ClusterSize.Small:
{
clusterSizeDropdown.value = 0;
break;
}
case ClusterSize.Medium:
{
clusterSizeDropdown.value = 1;
break;
}
case ClusterSize.Large:
{
clusterSizeDropdown.value = 2;
break;
}
}
// Updating World Type
WorldType worldType = (WorldType) propertiesThatChanged[WorldGenerator.Instance.WorldTypePropertiesKey];
switch (worldType)
{
case WorldType.Flat:
{
worldTypeDropdown.value = 0;
break;
}
case WorldType.Standard:
{
worldTypeDropdown.value = 1;
break;
}
case WorldType.Mountain:
{
worldTypeDropdown.value = 2;
break;
}
}
// Generating a new world
WorldGenerator.Instance.CreateWorld();
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: e821c7c24a983d941a2d2c4400ecf9f7
timeCreated: 1522919791
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,393 @@
// Copyright(c) 2018, Benjamin Ward
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
// * Redistributions of source code must retain the above copyright notice, this
// list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the copyright holder nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
// DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// SimplexNoise for C#
// Author: Benjamin Ward
// Github Link: https://github.com/WardBenjamin/SimplexNoise
// Originally authored by Heikki Törmälä
using System;
namespace Simplex
{
/// <summary>
/// Implementation of the Perlin simplex noise, an improved Perlin noise algorithm.
/// Based loosely on SimplexNoise1234 by Stefan Gustavson <http://staffwww.itn.liu.se/~stegu/aqsis/aqsis-newnoise/>
/// </summary>
public class Noise
{
public static float[] Calc1D(int width, float scale)
{
float[] values = new float[width];
for (int i = 0; i < width; i++)
values[i] = Generate(i * scale) * 128 + 128;
return values;
}
public static float[,] Calc2D(int width, int height, float scale)
{
float[,] values = new float[width, height];
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
values[i, j] = Generate(i * scale, j * scale) * 128 + 128;
return values;
}
public static float[,,] Calc3D(int width, int height, int length, float scale)
{
float[,,] values = new float[width, height, length];
for (int i = 0; i < width; i++)
for (int j = 0; j < height; j++)
for (int k = 0; k < length; k++)
values[i, j, k] = Generate(i * scale, j * scale, k * scale) * 128 + 128;
return values;
}
public static float CalcPixel1D(int x, float scale)
{
return Generate(x * scale) * 128 + 128;
}
public static float CalcPixel2D(int x, int y, float scale)
{
return Generate(x * scale, y * scale) * 128 + 128;
}
public static float CalcPixel3D(int x, int y, int z, float scale)
{
return Generate(x * scale, y * scale, z * scale) * 128 + 128;
}
static Noise()
{
perm = new byte[permOriginal.Length];
Simplex.Noise.permOriginal.CopyTo(perm, 0);
}
public static int Seed
{
get { return seed; }
set
{
if (value == 0)
{
perm = new byte[permOriginal.Length];
Simplex.Noise.permOriginal.CopyTo(perm, 0);
}
else
{
perm = new byte[512];
Random random = new Random(value);
random.NextBytes(perm);
}
}
}
private static int seed = 0;
/// <summary>
/// 1D simplex noise
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
internal static float Generate(float x)
{
int i0 = FastFloor(x);
int i1 = i0 + 1;
float x0 = x - i0;
float x1 = x0 - 1.0f;
float n0, n1;
float t0 = 1.0f - x0 * x0;
t0 *= t0;
n0 = t0 * t0 * grad(perm[i0 & 0xff], x0);
float t1 = 1.0f - x1 * x1;
t1 *= t1;
n1 = t1 * t1 * grad(perm[i1 & 0xff], x1);
// The maximum value of this noise is 8*(3/4)^4 = 2.53125
// A factor of 0.395 scales to fit exactly within [-1,1]
return 0.395f * (n0 + n1);
}
/// <summary>
/// 2D simplex noise
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns></returns>
internal static float Generate(float x, float y)
{
const float F2 = 0.366025403f; // F2 = 0.5*(sqrt(3.0)-1.0)
const float G2 = 0.211324865f; // G2 = (3.0-Math.sqrt(3.0))/6.0
float n0, n1, n2; // Noise contributions from the three corners
// Skew the input space to determine which simplex cell we're in
float s = (x + y) * F2; // Hairy factor for 2D
float xs = x + s;
float ys = y + s;
int i = FastFloor(xs);
int j = FastFloor(ys);
float t = (float)(i + j) * G2;
float X0 = i - t; // Unskew the cell origin back to (x,y) space
float Y0 = j - t;
float x0 = x - X0; // The x,y distances from the cell origin
float y0 = y - Y0;
// For the 2D case, the simplex shape is an equilateral triangle.
// Determine which simplex we are in.
int i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords
if (x0 > y0) { i1 = 1; j1 = 0; } // lower triangle, XY order: (0,0)->(1,0)->(1,1)
else { i1 = 0; j1 = 1; } // upper triangle, YX order: (0,0)->(0,1)->(1,1)
// A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and
// a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where
// c = (3-sqrt(3))/6
float x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords
float y1 = y0 - j1 + G2;
float x2 = x0 - 1.0f + 2.0f * G2; // Offsets for last corner in (x,y) unskewed coords
float y2 = y0 - 1.0f + 2.0f * G2;
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
int ii = Mod(i, 256);
int jj = Mod(j, 256);
// Calculate the contribution from the three corners
float t0 = 0.5f - x0 * x0 - y0 * y0;
if (t0 < 0.0f) n0 = 0.0f;
else
{
t0 *= t0;
n0 = t0 * t0 * grad(perm[ii + perm[jj]], x0, y0);
}
float t1 = 0.5f - x1 * x1 - y1 * y1;
if (t1 < 0.0f) n1 = 0.0f;
else
{
t1 *= t1;
n1 = t1 * t1 * grad(perm[ii + i1 + perm[jj + j1]], x1, y1);
}
float t2 = 0.5f - x2 * x2 - y2 * y2;
if (t2 < 0.0f) n2 = 0.0f;
else
{
t2 *= t2;
n2 = t2 * t2 * grad(perm[ii + 1 + perm[jj + 1]], x2, y2);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to return values in the interval [-1,1].
return 40.0f * (n0 + n1 + n2); // TODO: The scale factor is preliminary!
}
internal static float Generate(float x, float y, float z)
{
// Simple skewing factors for the 3D case
const float F3 = 0.333333333f;
const float G3 = 0.166666667f;
float n0, n1, n2, n3; // Noise contributions from the four corners
// Skew the input space to determine which simplex cell we're in
float s = (x + y + z) * F3; // Very nice and simple skew factor for 3D
float xs = x + s;
float ys = y + s;
float zs = z + s;
int i = FastFloor(xs);
int j = FastFloor(ys);
int k = FastFloor(zs);
float t = (float)(i + j + k) * G3;
float X0 = i - t; // Unskew the cell origin back to (x,y,z) space
float Y0 = j - t;
float Z0 = k - t;
float x0 = x - X0; // The x,y,z distances from the cell origin
float y0 = y - Y0;
float z0 = z - Z0;
// For the 3D case, the simplex shape is a slightly irregular tetrahedron.
// Determine which simplex we are in.
int i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords
int i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords
/* This code would benefit from a backport from the GLSL version! */
if (x0 >= y0)
{
if (y0 >= z0)
{ i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // X Y Z order
else if (x0 >= z0) { i1 = 1; j1 = 0; k1 = 0; i2 = 1; j2 = 0; k2 = 1; } // X Z Y order
else { i1 = 0; j1 = 0; k1 = 1; i2 = 1; j2 = 0; k2 = 1; } // Z X Y order
}
else
{ // x0<y0
if (y0 < z0) { i1 = 0; j1 = 0; k1 = 1; i2 = 0; j2 = 1; k2 = 1; } // Z Y X order
else if (x0 < z0) { i1 = 0; j1 = 1; k1 = 0; i2 = 0; j2 = 1; k2 = 1; } // Y Z X order
else { i1 = 0; j1 = 1; k1 = 0; i2 = 1; j2 = 1; k2 = 0; } // Y X Z order
}
// A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z),
// a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and
// a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where
// c = 1/6.
float x1 = x0 - i1 + G3; // Offsets for second corner in (x,y,z) coords
float y1 = y0 - j1 + G3;
float z1 = z0 - k1 + G3;
float x2 = x0 - i2 + 2.0f * G3; // Offsets for third corner in (x,y,z) coords
float y2 = y0 - j2 + 2.0f * G3;
float z2 = z0 - k2 + 2.0f * G3;
float x3 = x0 - 1.0f + 3.0f * G3; // Offsets for last corner in (x,y,z) coords
float y3 = y0 - 1.0f + 3.0f * G3;
float z3 = z0 - 1.0f + 3.0f * G3;
// Wrap the integer indices at 256, to avoid indexing perm[] out of bounds
int ii = Mod(i, 256);
int jj = Mod(j, 256);
int kk = Mod(k, 256);
// Calculate the contribution from the four corners
float t0 = 0.6f - x0 * x0 - y0 * y0 - z0 * z0;
if (t0 < 0.0f) n0 = 0.0f;
else
{
t0 *= t0;
n0 = t0 * t0 * grad(perm[ii + perm[jj + perm[kk]]], x0, y0, z0);
}
float t1 = 0.6f - x1 * x1 - y1 * y1 - z1 * z1;
if (t1 < 0.0f) n1 = 0.0f;
else
{
t1 *= t1;
n1 = t1 * t1 * grad(perm[ii + i1 + perm[jj + j1 + perm[kk + k1]]], x1, y1, z1);
}
float t2 = 0.6f - x2 * x2 - y2 * y2 - z2 * z2;
if (t2 < 0.0f) n2 = 0.0f;
else
{
t2 *= t2;
n2 = t2 * t2 * grad(perm[ii + i2 + perm[jj + j2 + perm[kk + k2]]], x2, y2, z2);
}
float t3 = 0.6f - x3 * x3 - y3 * y3 - z3 * z3;
if (t3 < 0.0f) n3 = 0.0f;
else
{
t3 *= t3;
n3 = t3 * t3 * grad(perm[ii + 1 + perm[jj + 1 + perm[kk + 1]]], x3, y3, z3);
}
// Add contributions from each corner to get the final noise value.
// The result is scaled to stay just inside [-1,1]
return 32.0f * (n0 + n1 + n2 + n3); // TODO: The scale factor is preliminary!
}
private static byte[] perm;
private static readonly byte[] permOriginal = new byte[]
{
151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180,
151,160,137,91,90,15,
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180
};
private static int FastFloor(float x)
{
return (x > 0) ? ((int)x) : (((int)x) - 1);
}
private static int Mod(int x, int m)
{
int a = x % m;
return a < 0 ? a + m : a;
}
private static float grad(int hash, float x)
{
int h = hash & 15;
float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
if ((h & 8) != 0) grad = -grad; // Set a random sign for the gradient
return (grad * x); // Multiply the gradient with the distance
}
private static float grad(int hash, float x, float y)
{
int h = hash & 7; // Convert low 3 bits of hash code
float u = h < 4 ? x : y; // into 8 simple gradient directions,
float v = h < 4 ? y : x; // and compute the dot product with (x,y).
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -2.0f * v : 2.0f * v);
}
private static float grad(int hash, float x, float y, float z)
{
int h = hash & 15; // Convert low 4 bits of hash code into 12 simple
float u = h < 8 ? x : y; // gradient directions, and compute dot product.
float v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h = 12 to 15
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v);
}
private static float grad(int hash, float x, float y, float z, float t)
{
int h = hash & 31; // Convert low 5 bits of hash code into 32 simple
float u = h < 24 ? x : y; // gradient directions, and compute dot product.
float v = h < 16 ? y : z;
float w = h < 8 ? z : t;
return ((h & 1) != 0 ? -u : u) + ((h & 2) != 0 ? -v : v) + ((h & 4) != 0 ? -w : w);
}
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 980b260de9546514d80e3d867a591802
timeCreated: 1521731073
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,83 @@
using UnityEngine;
namespace Photon.Pun.Demo.Procedural
{
/// <summary>
/// Simple Input Handler to control the camera.
/// </summary>
public class ProceduralController : MonoBehaviour
{
private Camera cam;
#region UNITY
public void Awake()
{
cam = Camera.main;
}
/// <summary>
/// Use horizontal and vertical axes (by default WASD or the arrow keys) for moving for-, back- or sidewards.
/// Use E or Q for 'zooming' in or out.
/// Use the left mouse button to decrease a Block's height
/// or the right mouse button to increase a Block's height.
/// </summary>
public void Update()
{
float h = Input.GetAxisRaw("Horizontal");
float v = Input.GetAxisRaw("Vertical");
if (h >= 0.1f)
{
cam.transform.position += Vector3.right * 10.0f * Time.deltaTime;
}
else if (h <= -0.1f)
{
cam.transform.position += Vector3.left * 10.0f * Time.deltaTime;
}
if (v >= 0.1f)
{
cam.transform.position += Vector3.forward * 10.0f * Time.deltaTime;
}
else if (v <= -0.1f)
{
cam.transform.position += Vector3.back * 10.0f * Time.deltaTime;
}
if (Input.GetKey(KeyCode.Q))
{
cam.transform.position += Vector3.up * 10.0f * Time.deltaTime;
}
else if (Input.GetKey(KeyCode.E))
{
cam.transform.position += Vector3.down * 10.0f * Time.deltaTime;
}
if (Input.GetMouseButtonDown(0) || Input.GetMouseButtonDown(1))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, 100.0f))
{
Block b = hit.transform.GetComponent<Block>();
if (b != null)
{
if (Input.GetMouseButtonDown(0))
{
WorldGenerator.Instance.DecreaseBlockHeight(b.ClusterId, b.BlockId);
}
else if (Input.GetMouseButtonDown(1))
{
WorldGenerator.Instance.IncreaseBlockHeight(b.ClusterId, b.BlockId);
}
}
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 11937abc60ef5bc4796d4b3a3d273f83
timeCreated: 1522938410
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,289 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Hashtable = ExitGames.Client.Photon.Hashtable;
namespace Photon.Pun.Demo.Procedural
{
/// <summary>
/// Describes the Size of the World.
/// A 'Tiny' world for example will be created with 16 x 16 Blocks.
/// </summary>
public enum WorldSize
{
Tiny = 16,
Small = 32,
Medium = 64,
Large = 128
}
/// <summary>
/// Describes the type of the generated world.
/// This basically influences the maximum height of a Block.
/// </summary>
public enum WorldType
{
Flat = 4,
Standard = 8,
Mountain = 16
}
/// <summary>
/// Describes how many Blocks are part of one CLuster.
/// Having a 'Small' ClusterSize increases the amount of Clusters being created,
/// whereat generating a world with a 'Large' ClusterSize doesn't create that many Clusters.
/// </summary>
public enum ClusterSize
{
Small = 4,
Medium = 16,
Large = 64
}
/// <summary>
/// The World Generator creates a world based on four options the current MasterClient can set.
/// These options are available on the Ingame Control Panel. If those options are confirmed by the current MasterClient,
/// they will be stored in the Custom Room Properties to make them available on all clients.
/// These options are:
/// 1) a numerical Seed to make sure that each client generates the same world and to avoid Random functions and 'network-instantiate' everything
/// 2) the World Size to describe how large the generated world should be
/// 3) the Cluster Size to describe how many Blocks are inside each Cluster
/// 4) the World Type to make the generated world appear in different 'looks'.
/// </summary>
public class WorldGenerator : MonoBehaviour
{
public readonly string SeedPropertiesKey = "Seed";
public readonly string WorldSizePropertiesKey = "WorldSize";
public readonly string ClusterSizePropertiesKey = "ClusterSize";
public readonly string WorldTypePropertiesKey = "WorldType";
private static WorldGenerator instance;
public static WorldGenerator Instance
{
get
{
if (instance == null)
{
instance = FindObjectOfType<WorldGenerator>();
}
return instance;
}
}
public int Seed { get; set; }
public WorldSize WorldSize { get; set; }
public ClusterSize ClusterSize { get; set; }
public WorldType WorldType { get; set; }
private Dictionary<int, GameObject> clusterList;
public Material[] WorldMaterials;
#region UNITY
public void Awake()
{
clusterList = new Dictionary<int, GameObject>();
WorldSize = WorldSize.Tiny;
ClusterSize = ClusterSize.Small;
WorldType = WorldType.Standard;
}
#endregion
#region CLASS FUNCTIONS
/// <summary>
/// Called whenever a client receives a Custom Room Properties update containing all necessary information for creating a world.
/// If there is currently a world generation process running, it will be stopped automatically.
/// Also if there is a world already existing, it will be destroyed before the new one gets created.
/// </summary>
public void CreateWorld()
{
StopAllCoroutines();
DestroyWorld();
StartCoroutine(GenerateWorld());
}
/// <summary>
/// Destroys each Block from each Cluster before actually destroying the Cluster itself.
/// </summary>
private void DestroyWorld()
{
foreach (GameObject cluster in clusterList.Values)
{
Cluster clusterComponent = cluster.GetComponent<Cluster>();
clusterComponent.DestroyCluster();
Destroy(cluster);
}
clusterList.Clear();
}
/// <summary>
/// Whenever the 'Confirm' button on the Control Panel is clicked by the MasterClient,
/// the Room Properties will be updated with the settings he defined.
/// </summary>
public void ConfirmAndUpdateProperties()
{
if (!PhotonNetwork.IsMasterClient)
{
return;
}
Hashtable properties = new Hashtable
{
{SeedPropertiesKey, Seed},
{WorldSizePropertiesKey, (int) WorldSize},
{ClusterSizePropertiesKey, (int) ClusterSize},
{WorldTypePropertiesKey, (int) WorldType}
};
PhotonNetwork.CurrentRoom.SetCustomProperties(properties);
}
/// <summary>
/// Decreases the height of a certain Block from a certain Cluster.
/// </summary>
public void DecreaseBlockHeight(int clusterId, int blockId)
{
Cluster c = clusterList[clusterId].GetComponent<Cluster>();
if (c != null)
{
c.DecreaseBlockHeight(blockId);
}
}
/// <summary>
/// Increases the height of a certain Block from a certain Cluster.
/// </summary>
public void IncreaseBlockHeight(int clusterId, int blockId)
{
Cluster c = clusterList[clusterId].GetComponent<Cluster>();
if (c != null)
{
c.IncreaseBlockHeight(blockId);
}
}
#endregion
#region COROUTINES
/// <summary>
/// Generates a new world based on the settings made either by the MasterClient on the
/// Ingame Control Panel or after receiving the new settings from the Custom Room Properties update.
/// </summary>
private IEnumerator GenerateWorld()
{
Debug.Log(string.Format("<b>Procedural Demo</b>: Creating world using Seed: {0}, World Size: {1}, Cluster Size: {2} and World Type: {3}", Seed, WorldSize, ClusterSize, WorldType));
Simplex.Noise.Seed = Seed;
int clusterId = 0;
// Instantiating all necessary clusters at their target position
for (int x = 0; x < (int) WorldSize; x += (int) Mathf.Sqrt((int) ClusterSize))
{
for (int z = 0; z < (int) WorldSize; z += (int) Mathf.Sqrt((int) ClusterSize))
{
GameObject cluster = new GameObject();
cluster.name = "Cluster " + clusterId;
cluster.transform.SetParent(transform);
cluster.transform.position = new Vector3(x, 0.0f, z);
Cluster clusterComponent = cluster.AddComponent<Cluster>();
clusterComponent.ClusterId = clusterId;
clusterList.Add(clusterId++, cluster);
}
}
yield return new WaitForEndOfFrame();
// Instantiating all necessary blocks as a child of a certain cluster
foreach (GameObject cluster in clusterList.Values)
{
Vector3 clusterPosition = cluster.transform.position;
int blockId = 0;
for (int x = 0; x < (int) Mathf.Sqrt((int) ClusterSize); ++x)
{
for (int z = 0; z < (int) Mathf.Sqrt((int) ClusterSize); ++z)
{
float noiseValue = Simplex.Noise.CalcPixel2D((int) clusterPosition.x + x, (int) clusterPosition.z + z, 0.02f);
int height = (int) noiseValue / (int) (256.0f / (float) WorldType);
int materialIndex = (int) noiseValue / (int) (256.0f / WorldMaterials.Length);
GameObject block = GameObject.CreatePrimitive(PrimitiveType.Cube);
block.name = "Block " + blockId;
block.transform.SetParent(cluster.transform);
block.transform.localScale = new Vector3(1.0f, height, 1.0f);
block.transform.position = new Vector3(clusterPosition.x + x, height / 2.0f, clusterPosition.z + z);
block.GetComponent<MeshRenderer>().material = WorldMaterials[materialIndex];
Block blockComponent = block.AddComponent<Block>();
blockComponent.BlockId = blockId;
blockComponent.ClusterId = cluster.GetComponent<Cluster>().ClusterId;
cluster.GetComponent<Cluster>().AddBlock(blockId++, block);
}
}
yield return new WaitForEndOfFrame();
}
// Applying modifications made to the world when joining the room later or while it is created
foreach (DictionaryEntry entry in PhotonNetwork.CurrentRoom.CustomProperties)
{
if (entry.Value == null)
{
continue;
}
string key = entry.Key.ToString();
if ((key == SeedPropertiesKey) || (key == WorldSizePropertiesKey) || (key == ClusterSizePropertiesKey) || (key == WorldTypePropertiesKey))
{
continue;
}
int indexOfBlank = key.IndexOf(' ');
key = key.Substring(indexOfBlank + 1, (key.Length - (indexOfBlank + 1)));
int.TryParse(key, out clusterId);
GameObject cluster;
if (clusterList.TryGetValue(clusterId, out cluster))
{
Cluster c = cluster.GetComponent<Cluster>();
if (c != null)
{
Dictionary<int, float> clusterModifications = (Dictionary<int, float>) entry.Value;
foreach (KeyValuePair<int, float> pair in clusterModifications)
{
c.SetBlockHeightRemote(pair.Key, pair.Value);
}
}
}
}
}
#endregion
}
}

View File

@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 4190307f26497ca49b67855340776e0a
timeCreated: 1521730317
licenseType: Store
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: