using Duality; using Duality.Components; using Duality.Components.Renderers; using Duality.Resources; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace BackGroundScroller_Example { //BackgroundScroller - Maintains/Creates/Moves layerss public class BackgroundScroller : Component, ICmpInitializable { //vertical offset can be defined private float z_PosFront; private float z_PosMid; private float z_PosBack; public float zOffsetFront { get { return this.z_PosFront; } set { this.z_PosFront = value; } } public float zOffsetMid { get { return this.z_PosMid; } set { this.z_PosMid = value; } } public float zOffsetBack { get { return this.z_PosBack; } set { this.z_PosBack = value; } } //due to vertical offset some layers might need a upscale private float scaleFront; private float scaleMid; private float scaleBack; public float ScaleFrontLayer { get { return this.scaleFront; } set { this.scaleFront = value; } } public float ScaleMidLayer { get { return this.scaleMid; } set { this.scaleMid = value; } } public float ScaleBackLayer { get { return this.scaleBack; } set { this.scaleBack = value; } } //Load Prefabs used to generate the spawning background -> further in developement this will be removed for //an automation which pics the created prefab due to a master level plan given by the level handler private ContentRef frontLayerPrefab; private ContentRef midLayerPrefab; private ContentRef backLayerPrefab; public ContentRef FrontLayerPrefab { get { return this.frontLayerPrefab; } set { this.frontLayerPrefab = value; } } public ContentRef MidLayerPrefab { get { return this.midLayerPrefab; } set { this.midLayerPrefab = value; } } public ContentRef BackLayerPrefab { get { return this.backLayerPrefab; } set { this.backLayerPrefab = value; } } //Layerlists to maintain and iterate through all on a certain z-level Dictionary> FrontLayers; Dictionary> MidLayers; Dictionary> BackLayers; public void OnInit(InitContext context) { FrontLayers = new Dictionary>(); MidLayers = new Dictionary>(); BackLayers = new Dictionary>(); } public void OnShutdown(ShutdownContext context) { } public void Update(float camSpeed, Camera mainCam) { //Copy of bluebrints given by levelHandler to enable on the fly prefab changing //Check if LayerList is empty, if yes startscreen has to be initialized if (BackLayers.Count == 0 && MidLayers.Count == 0 && FrontLayers.Count == 0) { Vector3 tmpPos = new Vector3(); GameObject tmpLayer; float textureWidth; float tmpScale; //The startconstellation is a mainscreen, a 1 x left offscreen layer and 1 x rightoffscreen layer //FrontLayers Preset (3 : 1 x LeftOffscreen, 1 x Mainscreen, 1 x RightOffscreen) GameObject newFront = FrontLayerPrefab.Res.Instantiate(); textureWidth = newFront.GetComponent().SharedMaterial.Res.MainTexture.Res.Size.X; tmpScale = scaleFront; tmpPos.Z = zOffsetFront; //LeftOffscreen-Front tmpPos.X = -textureWidth * tmpScale; tmpLayer = createLayer(FrontLayerPrefab, tmpPos,tmpScale, "Front"); FrontLayers.Add(tmpLayer, FrontLayerPrefab); //MainScreen-Front tmpPos.X = 0; tmpLayer = createLayer(FrontLayerPrefab, tmpPos, tmpScale, "Front"); FrontLayers.Add(tmpLayer, FrontLayerPrefab); //RightOffscreen-Front tmpPos.X = textureWidth * tmpScale; tmpLayer = createLayer(FrontLayerPrefab, tmpPos, tmpScale, "Front"); FrontLayers.Add(tmpLayer, FrontLayerPrefab); //MidLayers Preset (3 : 1 x LeftOffscreen, 1 x Mainscreen, 1 x RightOffscreen) GameObject newMid = MidLayerPrefab.Res.Instantiate(); textureWidth = newMid.GetComponent().SharedMaterial.Res.MainTexture.Res.Size.X; tmpScale = scaleMid; tmpPos.Z = zOffsetMid; //LeftOffscreen-Mid tmpPos.X = -textureWidth * tmpScale; tmpLayer = createLayer(MidLayerPrefab, tmpPos, tmpScale, "Mid"); MidLayers.Add(tmpLayer, MidLayerPrefab); //MainScreen-Mid tmpPos.X = 0; tmpLayer = createLayer(MidLayerPrefab, tmpPos, tmpScale, "Mid"); MidLayers.Add(tmpLayer, MidLayerPrefab); //RightOffscreen-Mid tmpPos.X = textureWidth * tmpScale; tmpLayer = createLayer(MidLayerPrefab, tmpPos, tmpScale, "Mid"); MidLayers.Add(tmpLayer, MidLayerPrefab); //BackLayers Preset (3 : 1 x LeftOffscreen, 1 x Mainscreen, 1 x RightOffscreen) GameObject newBack = BackLayerPrefab.Res.Instantiate(); textureWidth = newBack.GetComponent().SharedMaterial.Res.MainTexture.Res.Size.X; tmpPos.Z = zOffsetBack; tmpScale = scaleBack; //LeftOffscreen-Back tmpPos.X = -textureWidth * tmpScale; tmpLayer = createLayer(BackLayerPrefab, tmpPos, tmpScale, "Back"); BackLayers.Add(tmpLayer, BackLayerPrefab); //MainScreen-Back tmpPos.X = 0; tmpLayer = createLayer(BackLayerPrefab, tmpPos, tmpScale, "Back"); BackLayers.Add(tmpLayer, BackLayerPrefab); //RightOffscreen-Back tmpPos.X = textureWidth * tmpScale; tmpLayer = createLayer(BackLayerPrefab, tmpPos, tmpScale, "Back"); BackLayers.Add(tmpLayer, BackLayerPrefab); } // check if layers need to be killed/created by iterating through //them and check their position relativ to the cam UpdatePosition(mainCam, camSpeed); } // Mechanisms to instantiate from the given prefabs and to add the new objects to the handled lists private GameObject createLayer(ContentRef Prefab, Vector3 StartPos,float scale, string LayerName) { GameObject newLayer = Prefab.Res.Instantiate(); newLayer.Transform.MoveToAbs(StartPos*scale); newLayer.Transform.Scale = scale; newLayer.Parent = this.GameObj.ChildByName(LayerName); return newLayer; } private void UpdatePosition(Camera cam, float speed) { //temporal list to still be able to delete objects while iterating through Dictionary> LayersToMove = new Dictionary>(); //Enlist all layers from all lists to prepare for iteration foreach (KeyValuePair> KeyPair in BackLayers) { if (KeyPair.Key != null) { LayersToMove.Add(KeyPair.Key, KeyPair.Value); } } foreach (KeyValuePair> KeyPair in MidLayers) { if (KeyPair.Key != null) { LayersToMove.Add(KeyPair.Key, KeyPair.Value); } } foreach (KeyValuePair> KeyPair in FrontLayers) { if (KeyPair.Key != null) { LayersToMove.Add(KeyPair.Key, KeyPair.Value); } } //Dictionary of layers is iterated and each is checked for leaving visible area + extra safety screen foreach (KeyValuePair> KeyPair in LayersToMove) { //Calculate the spritesize for the recreation process float screenWidth = 1366f; //has to be the actual screensize float textureWidth; float tmpZOffset = 0f; float tmpScale = 1f; string layerName = ""; //if offscreen the object is erased from the list and disposed at the next cicle if (KeyPair.Key.Transform.Pos.X <= cam.GameObj.Transform.Pos.X - (2 * screenWidth * KeyPair.Key.Transform.Scale) || KeyPair.Key.Transform.Pos.X >= cam.GameObj.Transform.Pos.X + (2 * screenWidth * KeyPair.Key.Transform.Scale)) { KeyPair.Key.DisposeLater(); //Create new Layer based on destructed one Vector3 tmpPos = new Vector3(); textureWidth = KeyPair.Key.GetComponent().SharedMaterial.Res.MainTexture.Res.Size.X * KeyPair.Key.GetComponent().Scale; //Find type of layer in the whole list and set its config to create a similar layer if (BackLayers.ContainsKey(KeyPair.Key)) { BackLayers.Remove(KeyPair.Key); layerName = "Back"; tmpZOffset = z_PosBack; tmpScale = scaleBack; } if (MidLayers.ContainsKey(KeyPair.Key)) { MidLayers.Remove(KeyPair.Key); layerName = "Mid"; tmpZOffset = z_PosMid; tmpScale = scaleMid; } if (FrontLayers.ContainsKey(KeyPair.Key)) { FrontLayers.Remove(KeyPair.Key); layerName = "Front"; tmpZOffset = z_PosFront; tmpScale = scaleFront; } //Determine which side the layer has to be knitted onto if (KeyPair.Key.Transform.Pos.X <= cam.GameObj.Transform.Pos.X - (2 * screenWidth * tmpScale)) tmpPos.X = KeyPair.Key.Transform.Pos.X + 3 * textureWidth * tmpScale; else tmpPos.X = KeyPair.Key.Transform.Pos.X - 3 * textureWidth * tmpScale; tmpPos.Z = tmpZOffset; //Temporary GameObject for Instantiation and temporary Keypair for adding to the dictionary GameObject tmpLayer; tmpLayer = createLayer(KeyPair.Value, tmpPos, tmpScale, layerName); KeyValuePair> tmpKeyPair = new KeyValuePair>(tmpLayer, KeyPair.Value); switch (layerName) { case "Front": FrontLayers.Add(tmpKeyPair.Key, tmpKeyPair.Value); break; case "Mid": MidLayers.Add(tmpKeyPair.Key, tmpKeyPair.Value); break; case "Back": BackLayers.Add(tmpKeyPair.Key, tmpKeyPair.Value); break; } } } } } }