You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

307 lines
12 KiB
C#

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<Prefab> frontLayerPrefab;
private ContentRef<Prefab> midLayerPrefab;
private ContentRef<Prefab> backLayerPrefab;
public ContentRef<Prefab> FrontLayerPrefab
{
get { return this.frontLayerPrefab; }
set { this.frontLayerPrefab = value; }
}
public ContentRef<Prefab> MidLayerPrefab
{
get { return this.midLayerPrefab; }
set { this.midLayerPrefab = value; }
}
public ContentRef<Prefab> BackLayerPrefab
{
get { return this.backLayerPrefab; }
set { this.backLayerPrefab = value; }
}
//Layerlists to maintain and iterate through all on a certain z-level
Dictionary<GameObject, ContentRef<Prefab>> FrontLayers;
Dictionary<GameObject, ContentRef<Prefab>> MidLayers;
Dictionary<GameObject, ContentRef<Prefab>> BackLayers;
public void OnInit(InitContext context)
{
FrontLayers = new Dictionary<GameObject, ContentRef<Prefab>>();
MidLayers = new Dictionary<GameObject, ContentRef<Prefab>>();
BackLayers = new Dictionary<GameObject, ContentRef<Prefab>>();
}
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<SpriteRenderer>().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<SpriteRenderer>().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<SpriteRenderer>().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> 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<GameObject, ContentRef<Prefab>> LayersToMove = new Dictionary<GameObject, ContentRef<Prefab>>();
//Enlist all layers from all lists to prepare for iteration
foreach (KeyValuePair<GameObject, ContentRef<Prefab>> KeyPair in BackLayers)
{
if (KeyPair.Key != null)
{
LayersToMove.Add(KeyPair.Key, KeyPair.Value);
}
}
foreach (KeyValuePair<GameObject, ContentRef<Prefab>> KeyPair in MidLayers)
{
if (KeyPair.Key != null)
{
LayersToMove.Add(KeyPair.Key, KeyPair.Value);
}
}
foreach (KeyValuePair<GameObject, ContentRef<Prefab>> 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<GameObject, ContentRef<Prefab>> 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<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X *
KeyPair.Key.GetComponent<Transform>().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<GameObject, ContentRef<Prefab>> tmpKeyPair = new KeyValuePair<GameObject, ContentRef<Prefab>>(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;
}
}
}
}
}
}