Adam's Lair Forum

game development and casual madness
It is currently 2017/05/23, 07:05

All times are UTC + 1 hour [ DST ]




Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: 2017/05/01, 12:15 
Novice Member
Novice Member

Joined: 2017/04/23, 09:34
Posts: 14
Location: Germany
Role: Hobbyist
Hey there fellow duality coders ;)

in this topic i want to ask for some code improvement tipps by you guys.
I am a coder apprentice and in order to evolve in coding skills, i would like you guys to criticize my code as good as posible and show me ways to achieve the same results and functionality with better approach and/or better performance.

Therefor here is my current project : A background-scroller

It is a component meant to create a fluent and if needed endless scolling screen created from prefabs. For example if you use a logic or a component to feed this scroller with prefabs you can scroll without loading screens into different environments depenting on how much prefabs you build and connect to the logic.
In this code i use a self build WASD-Listener to detect key input which the scroller uses to move all enlisted layers to the desired direction and on the fly create and simultaniously destroy new and old layers.

So any constructive critics with some advice is very appreciated and thanks beforehand ;)
(Sorry for the long post in advance)

LevelHandler(Mechanism to feed the prefabs to the scroller):
Code:
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
{

     [RequiredComponent(typeof(Camera))]

     //LevelHandler is used for maintaining anything level related like backgrounds (tileMaps, character- and objectspawner in future)
     //LevelHandler wird für die Wartung und Bereitstellung für levelbasierte Daten genutzt wie Hindergrund-Sprites (TileMaps, Charakterspawner etc)
    public class LevelHandler : Component, ICmpUpdatable
    {
        //Prefab-Schablonen zur dynamischen Layer-Erstellung
        //Prefab blueprints for dynamic layer-creation
        private ContentRef<Prefab> FrontLayer;
        private ContentRef<Prefab> MidLayer;
        private ContentRef<Prefab> BackLayer;

        public ContentRef<Prefab> FrontLayerPrefab
        {
            get { return this.FrontLayer; }
            set { this.FrontLayer = value; }
        }

        public ContentRef<Prefab> MidLayerPrefab
        {
            get { return this.MidLayer; }
            set { this.MidLayer = value; }
        }

        public ContentRef<Prefab> BackLayerPrefab
        {
            get { return this.BackLayer; }
            set { this.BackLayer = value; }
        }

        // Basicspeed-Multiplikator of the current ground (speed the ground should be multiplied with)
        // [1 = basic, in the scroller defined speed]
        // Basisspeed-Multiplikator des aktuellen Bodens (Geschwindigkeit mit die das Umfeld sich bewegt)
        // [1 = Normale im Scroller festgelegte Geschwindigkeit]
        private float horSpeedMultiplicator;
       
        public float MultiplikatorUmfeldSpeed
        {
            get { return this.horSpeedMultiplicator; }
            set { this.horSpeedMultiplicator = value; }
        }
       
        private BackgroundScroller bgScroller;
       
        public BackgroundScroller BackgroundScroller
        {
            get { return this.bgScroller; }
            set { this.bgScroller = value; }
        }

        public void OnUpdate()
        {
            //Ruft Update-Logik des BackGround-Scrollers auf um Layers zu generieren und zu bewegen
            //An dieser Stelle kann eine Logik zum Wechseln der Prefabs eingebaut werden um dynamisch die Hintergrundschichten umbauen zu können
            //Calls update-logic of the scroller to generate and move the different layers
            //At this point a logic to change the defined prefabs can be introduced to enable a dynamic layer change
            this.bgScroller.Update(horSpeedMultiplicator, FrontLayerPrefab,MidLayerPrefab,BackLayerPrefab);
        }
    }
}


BackGroundScroller (Creates/Destroys, enlists and moves the layers):
Code:
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
{
    [RequiredComponent(typeof(WASDListener))]

    //BackgroundScroller - Maintains/Creates/Moves layerss
    //Verwaltet, erzeugt und bewegt Hintergrundschichten
    public class BackgroundScroller : Component , ICmpInitializable
    {
        //Horizontale und vertikale Geschwindigkeiten sind einstellbar
        //Horizontal and vertical speed can be defined
        private float horizontalSpeed;
        private float verticalSpeed;

        public float HorSpeed
        {
            get { return this.horizontalSpeed; }
            set { this.horizontalSpeed = value; }
        }

        public float VertSpeed
        {
            get { return this.verticalSpeed; }
            set { this.verticalSpeed = value; }
        }
     
        //Layerlisten zur Verwaltung und Durcharbeiten aller Sprites auf einer Schicht
        //Layerlists to maintain and iterate through all on a certain z-level
        List<GameObject> FrontLayers;
        List<GameObject> MidLayers;
        List<GameObject> BackLayers;
         
        public void OnInit(InitContext context)
        {
            FrontLayers = new List<GameObject>();
            MidLayers = new List<GameObject>();
            BackLayers = new List<GameObject>();
        }

        public void OnShutdown(ShutdownContext context)
        {
           
        }


        public void Update(float speedMultiplikator, ContentRef<Prefab> FrontPrefab, ContentRef<Prefab> MidPrefab, ContentRef<Prefab> BackPrefab)
        {
            //Kopieren der Vorlagen zur dynamischen Schicht generierung -> Szenenwechsel on the Fly möglich
            //Levelhandler muss nur neue LayerPrefabs bekommen
            //Copy of bluebrints given by levelHandler to enable on the fly prefab changing
           
            //Check ob LayerListe leer ist, wenn ja dann muss erste Konstellation hinzugefügt werden
            //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;

                //The startconstellation is a mainscreen, a 2 x left offscreen layer and 2 x rightoffscreen layer

                //FrontLayers Preset (3 : 1 x LinksOffscreen, 1 x Hauptscreen, 1 x RechtsOffscreen)
                GameObject newFront = FrontPrefab.Res.Instantiate();
                textureWidth = newFront.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;
               
                //LinksOffscreen-Front
                tmpPos.X = -textureWidth;
                tmpLayer = createLayer(FrontPrefab, tmpPos, "Front");
                FrontLayers.Add(tmpLayer);

                //MainScreen-Front
                tmpPos.X = 0;
                tmpLayer = createLayer(FrontPrefab, tmpPos, "Front");
                FrontLayers.Add(tmpLayer);

                //RechtsOffscreen-Front
                tmpPos.X = textureWidth;
                tmpLayer = createLayer(FrontPrefab, tmpPos, "Front");
                FrontLayers.Add(tmpLayer);
                               
                //MidLayers Preset (3 : 1 x LinksOffscreen, 1 x Hauptscreen, 1 x RechtsOffscreen)
                GameObject newMid = MidPrefab.Res.Instantiate();
                textureWidth = newMid.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;
               
                //LinksOffscreen-Mid
                tmpPos.X = -textureWidth;
                tmpLayer = createLayer(MidPrefab, tmpPos, "Mid");
                MidLayers.Add(tmpLayer);

                //MainScreen-Mid
                tmpPos.X = 0;
                tmpLayer = createLayer(MidPrefab, tmpPos, "Mid");
                MidLayers.Add(tmpLayer);

                //RechtsOffscreen-Mid
                tmpPos.X = textureWidth;
                tmpLayer = createLayer(MidPrefab, tmpPos, "Mid");
                MidLayers.Add(tmpLayer);
                               
                //BackLayers Preset (3 : 1 x LinksOffscreen, 1 x Hauptscreen, 1 x RechtsOffscreen)
                GameObject newBack = BackPrefab.Res.Instantiate();
                textureWidth = newBack.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;

                //LinksOffscreen-Back
                tmpPos.X = -textureWidth;
                tmpLayer = createLayer(BackPrefab, tmpPos, "Back");
                BackLayers.Add(tmpLayer);

                //MainScreen-Back
                tmpPos.X = 0;
                tmpLayer = createLayer(BackPrefab, tmpPos, "Back");
                BackLayers.Add(tmpLayer);

                //RechtsOffscreen-Back
                tmpPos.X = textureWidth;
                tmpLayer = createLayer(BackPrefab, tmpPos, "Back");
                BackLayers.Add(tmpLayer);
               
            }
           
            // Updaten der Schichten gemäß Levelumfeld und eingestelltem Speed
            // Während der Entwicklung sind Pixelfehler beim annähen der Schichten entstanden weshalb eine Mechanik zur korrektur eingeplant war
            // update layers according to defined speed
            // while development pixel errors occured while knitting the layers together so i tried fixing the problem by using a mechanism to correct the positions
            UpdatePosition(ref BackLayers, (speedMultiplikator *  horizontalSpeed) / 8f, "Back");
            //checkPixelOffset(BackLayers);

            UpdatePosition(ref MidLayers, (speedMultiplikator *  horizontalSpeed) / 4f, "Mid");
            //checkPixelOffset(MidLayers);

            UpdatePosition(ref FrontLayers, (speedMultiplikator * horizontalSpeed) / 2f, "Front");
            //checkPixelOffset(FrontLayers);
           
        }

        /*Überprüfen ob neu angefügte Layer Positionsfehler durch Rundungsfehler hat
        //Check for layer positioning errors due to rounding mistakes
        private void checkPixelOffset(List<GameObject> layerList)
        {
           
            //Untersucht alle Layer-Objekte in der jeweiligen Liste
            for (int i = 0; i < layerList.Count()-1; i++)
            {
                float textureWidth = layerList.ElementAt(i).GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;
                GameObject tmpObj = new GameObject();
                GameObject matchObj = new GameObject();

                tmpObj = layerList[i];
                matchObj = layerList[i + 1];
               
                // wenn Differenz zwischen 1. Layer und 2. dann Korrektur nach Rechts
                if (tmpObj.Transform.Pos.X != matchObj.Transform.Pos.X - textureWidth && i == 0)
                {
                    correctPixelOffset(layerList, i, 1);
                }

                // wenn Differenz zwischen Vorletzer Layer und Letzter dann Korrektur nach Links
                if (tmpObj.Transform.Pos.X != matchObj.Transform.Pos.X - textureWidth && i == layerList.Count() - 1)
                {
                    correctPixelOffset(layerList, i, -1);
                }
            }
           
        }
        */
        /*Korrektur der PixelPosition
        // Correcting pixelpositions
        private void correctPixelOffset(List<GameObject> layerList, int index, int Richtung)
        {
            float textureWidth = layerList.ElementAt(index).GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;
            if (Richtung < 0)
                textureWidth = -textureWidth;

           if(layerList.ElementAt(index).GetComponent<Transform>().Pos.X != layerList.ElementAt(index).GetComponent<Transform>().Pos.X + textureWidth)
            {
                Vector3 tmpPos = new Vector3();
                tmpPos.X = layerList.ElementAt(index).GetComponent<Transform>().Pos.X + textureWidth;
                layerList.ElementAt(index).GetComponent<Transform>().MoveToAbs(tmpPos);
            }
        }
        */

        // Mechanismus zur Instanzierung der Prefabs und ein tragen in die bearbeiteten Listen
        // 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, string LayerName)
        {
            GameObject newLayer = Prefab.Res.Instantiate();
            newLayer.Transform.MoveToAbs(StartPos);
            newLayer.LinkToPrefab(Prefab);
            newLayer.Parent = this.GameObj.ChildByName(LayerName);
            return newLayer;
        }


        private void UpdatePosition(ref List<GameObject> layerList, float speed,string layer)
        {
            //genererierter WASDListener wird zugewiesen
            // generated wasdlistener is assigned
            var wasdListener = this.GameObj.GetComponent<WASDListener>();
           
            //Temporäre Liste um Listen bestandteile weiterhin löschen zu können während durch die Routine gefahren wird
            //temporal list to still be able to delete objects while iterating through
            List<GameObject> LayersToMove = new List<GameObject>();
           
            foreach (GameObject layerToAdd in layerList)
            {
                if (layerToAdd != null)
                {
                    LayersToMove.Add(layerToAdd);
                }
            }

            //Logik für rechts Bewegung(Schichten bewegen sich links)
            //Logic for right movement(layers are moving left)
            if (wasdListener.dIsPressed)
            {
                //Liste der Layers wird durchgegangen und jeweils um den selben Betrag verschoben
                //List of layers is iterated and each is moved by calculated speed
                foreach (GameObject obj in LayersToMove)
                {
                   
                    Vector3 deltaPos = new Vector3();

                    deltaPos.X = -speed;
                    deltaPos.X *= Time.MsPFMult * Time.TimeMult / 1000;
                                                           
                    obj.Transform.MoveBy(deltaPos);
                   
                    //Berechnen der breite des Aktuellen Sprites
                    //Calculate the spritesize for the knitting process
                    float textureWidth = obj.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;

                    //Sobald nicht mehr Sichtbar wird aus der Liste entfernt und beim nächsten Updatezyklus gelöscht
                    //if offscreen the object is erased from the list and disposed at the next cicle
                    if (obj.Transform.Pos.X < 2 * -textureWidth )
                    {
                       
                        Vector3 tmpPos = new Vector3();
                        textureWidth = obj.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;
                        tmpPos.X = obj.Transform.Pos.X + 3 * textureWidth ;
                       
                        layerList.Remove(obj);
                        obj.DisposeLater();

                        GameObject tmpLayer;
                       
                        tmpLayer = createLayer(obj.PrefabLink.Prefab, tmpPos, layer);
                        layerList.Insert(layerList.Count,tmpLayer);
                       
                    }
                }
               
            }

            //Logik für links Bewegung(Schichten bewegen sich rechts)
            //Logic for left movement(layers are moving rechts)
            if (wasdListener.aIsPressed)
            {
                //Liste der Layers wird durchgegangen und jeweils um den selben Betrag verschoben
                //List of layers is iterated and each is moved by calculated speed
                foreach (GameObject obj in LayersToMove)
                {
 
                    Vector3 deltaPos = new Vector3();

                    deltaPos.X = speed;
                    deltaPos.X *= Time.MsPFMult * Time.TimeMult / 1000;

                    obj.Transform.MoveBy(deltaPos);

                    //Berechnen der breite des Aktuellen Sprites
                    //Calculate the spritesize for the knitting process
                    float textureWidth = obj.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;

                    //Sobald nicht mehr Sichtbar wird aus der Liste entfernt und beim nächsten Updatezyklus gelöscht
                    //if offscreen the object is erased from the list and disposed at the next cicle
                    if (obj.Transform.Pos.X > 2 * textureWidth)
                    {
                       
                        Vector3 tmpPos = new Vector3();
                        textureWidth = obj.GetComponent<SpriteRenderer>().SharedMaterial.Res.MainTexture.Res.Size.X;
                        tmpPos.X = obj.Transform.Pos.X - 3 * textureWidth;
                       
                        layerList.Remove(obj);
                        obj.DisposeLater();
                       
                        GameObject tmpLayer;

                        tmpLayer = createLayer(obj.PrefabLink.Prefab, tmpPos, layer);
                        layerList.Insert(0, tmpLayer);

                    }
                }
               
            }

        }
       
    }
}


For completion WASD-Listener (Checks for WASD-Key input):
Code:
using Duality;
using Duality.Components;
using Duality.Components.Renderers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;


namespace BackGroundScroller_Example
{
     //Listener for WASD-Controls
    public class WASDListener : Component, ICmpInitializable, ICmpUpdatable
    {
        // Puts out boolean "Pressed" states of the wasd-controls
        // Gibt Flags für gedrückt Zustand der WASD-Tasten zurück
        private bool wPressed;
        private bool aPressed;
        private bool sPressed;
        private bool dPressed;

        //Properties
        public bool wIsPressed
        {
            get { return this.wPressed; }
            set { this.wPressed = value; }
        }

        public bool aIsPressed
        {
            get { return this.aPressed; }
            set { this.aPressed = value; }
        }

        public bool sIsPressed
        {
            get { return this.sPressed; }
            set { this.sPressed = value; }
        }

        public bool dIsPressed
        {
            get { return this.dPressed; }
            set { this.dPressed = value; }
        }

        //Initialisierung
        //Initializiation
        public void OnInit(InitContext context)
        {
           
            wIsPressed = false;
            aIsPressed = false;
            sIsPressed = false;
            dIsPressed = false;
           
        }

        public void OnShutdown(ShutdownContext context)
        {
           
        }

        //Update-Mechanik je Frame
        //Update-Mechaniy called every frame
        public void OnUpdate()
        {
             
            //W Handling
            if (DualityApp.Keyboard.KeyPressed(Duality.Input.Key.W))
                wIsPressed = true;
            else
                wIsPressed = false;
            //A Handling
            if (DualityApp.Keyboard.KeyPressed(Duality.Input.Key.A))
                aIsPressed = true;
            else
                aIsPressed = false;
            //S Handling
            if (DualityApp.Keyboard.KeyPressed(Duality.Input.Key.S))
                sIsPressed = true;
            else
                sIsPressed = false;
            //D Handling
            if (DualityApp.Keyboard.KeyPressed(Duality.Input.Key.D))
                dIsPressed = true;
            else
                dIsPressed = false;

        }
    }
}


Top
 Profile  
 
PostPosted: 2017/05/02, 18:17 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 1958
Location: Germany
Role: Professional
Hey there!

Asking others to review your code is a great idea when you're still learning, so :+1: for that! However, in a somewhat complex example like this, it helps a lot when you provide a sample project where people can actually execute your code easily in order to grasp what's going on without the guesswork up front.

Here are some things I noticed while reading the code. This is not an in-depth review, just a few thoughts:

  • Multi-Language comments: Commenting in more than one language seems unnecessary, and it also increases your workload, since you now have to keep twice the amount of text in sync with what's happening in code when making changes. My recommendation: Just comment stuff in English.
  • Multi-Language code: Similar to the multi-language comments, I'd recommend to strictly keep all code in one language. English is kind of an obvious choice, since pretty much all libraries and frameworks are already in English.
  • The only thing WASDListener seems to do is copy values from DualityApp.Keyboard without adding much else. Why the redundancy? Recommend to remove it and just call the keyboard API directly when you need it.
  • Similarly, the LevelHandler currently only stores some Prefab ContentRefs and calls the scroller's update method - both of which could be done by the scroller itself? Maybe there's something more to it, but it looks like this separation isn't needed given the code alone.
  • Calling LinkToPrefab after instantiating a Prefab isn't usually needed, looks a bit like an accident in this case. Remove when possible!
  • I'm not sure I understand the movement and instantiate code fully, but at a glance it seems like you're scrolling the background objects when pressing WASD movement keys. Wouldn't it make more sense to move the camera, rather than all objects in the opposite direction?

Hope this helps a little. ^^

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2017/05/04, 16:20 
Novice Member
Novice Member

Joined: 2017/04/23, 09:34
Posts: 14
Location: Germany
Role: Hobbyist
Quote:
it helps a lot when you provide a sample project where people can actually execute your code easily in order to grasp what's going on without the guesswork up front.


ow surely ... didn't thought for that one :D here is a link to the source code on my one-drive. Feel free to inspect and/or use it for own coding projects ;) :
https://1drv.ms/u/s!AnJZtUH4r073gTxFitfUL0twnWB6

Quote:
Multi-Language comments

yeah i thought maybe some people would get my point on doing several things and what a try to achieve a little better but on that point of view your right it is a lot more workload and i guess i should reduce to pure english ^^

Quote:
WASDListener seems to do is copy values from DualityApp.Keyboard without adding much else


yep that was intendet to do so^^ on the long shot i was planing to create a larger key listener state machine and it is still in it's infancy but i am considering using the basic Duality.Keyboard api until i expand the listener to a greater size with additional states.

Quote:
LevelHandler currently only stores some Prefab ContentRefs and calls the scroller's update method


yes same as the WASDListener, this handler is planed to be a overall handler of different mechanisms like the scroller , a soon to be completet tilegenerater and some world/level specific object generaters. I want to build it as a master component to these mechanics feeding and controling their data and behaviors so they never get out of sync and do something unintended. Therefore if there is an issue with the data i am sending in, i only have to check on one place even if i corrupted multiple systems at once so i thought why not a controlling handler for all the world related mechanisms ^^

Quote:
Calling LinkToPrefab after instantiating a Prefab isn't usually needed, looks a bit like an accident in this case. Remove when possible!


ow i thought i need a reference to that prefab as a object because after generating the layers i recognized them havin no link to the prefab so i relinkt them in order to be able to pause the editor and still have them linkt to that prefab ^^ but if this is not necessary i will remove that one. What downsides could it have instanciating from prefabs but not linking them to that prefab ?

Quote:
I'm not sure I understand the movement and instantiate code fully, but at a glance it seems like you're scrolling the background objects when pressing WASD movement keys. Wouldn't it make more sense to move the camera, rather than all objects in the opposite direction?


yes i actually move the background layers in stead of the camera. While planing this mechanic i thought if in future i want to integrate more objects that can move or should be moved due to movement from the player it would be easier to handle if i keep the camera static and only move the surroundings like backgrounds, tiles, enemies, or interactive objects. Therefor for example i would not have the problem of pre generating levels on the screen and could only spawn objects and sprites if the player would reach a certain logical position.
For example this would be used in a 2d plattformer where the player could run across a country without any loading screen. The player would need a certain "locater" coordinate (which i still have to develope) which tells the mechanisms where the player currently is on the planed "world map" and because of this point the machanisms could create and generate on the fly what the player should see at this coordinates. Like for example the players coordinate is something like (WestCounty,City,EasternEntrance) then this information is given to the mechanisms like the backgroundscroller and for example a tilehandler or object spawner so they can create the environment as needed.

On the other hand i wanted to implement a quite complex movement handling mechanism for the player movement and animations and i, additionaly to the reason on top, thougt a camera focused moving would mess a lot up while creating and handling the movepatterns. Like if there are several different move patterns like dashing or different jump styles which involve special camera positions to look nicer i thought it would be easier to move the player or the environment to the needed position instead of moving the camera. (also to reduce possible camera glitches where the camera movement is manipulated by to many sources and could glitch out on a fancy unintended way ^^ )


And thanks alot for the awesome help on improving ;) on my day to day coding job i have little to no possibilities to expand in modern coding languages like c# because at work i code in the reeealy oldschool-ish COBOL :D which means no object instancing, no classes and no memory allocation which makes the possible coding projects quite limited or realy complicated for a "rookie" ;) Therefore big thanks to all supporters of awesome ideas ;)


Top
 Profile  
 
PostPosted: 2017/05/04, 18:17 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 1958
Location: Germany
Role: Professional
4lexKidd wrote:
Quote:
Calling LinkToPrefab after instantiating a Prefab isn't usually needed, looks a bit like an accident in this case. Remove when possible!


ow i thought i need a reference to that prefab as a object because after generating the layers i recognized them havin no link to the prefab so i relinkt them in order to be able to pause the editor and still have them linkt to that prefab ^^ but if this is not necessary i will remove that one. What downsides could it have instanciating from prefabs but not linking them to that prefab ?

Let's turn this question around: Why would you want an object to be linked to a Prefab? Because that connection is what allows you to modify the Prefab and propagate the changes to all of its instances, right? So far so good - but this is primarily an editor / design-time operation!

In a regular game it makes little sense to re-apply Prefabs at runtime to objects jumping around in your world simulation. This is the reason why, by default, instantiating a Prefab keeps the link in edit mode, but does not keep the link at runtime. And also why objects automatically unlink themselves after loading a scene in the sandbox or launcher. Instantiating a Prefab at runtime is basically just cloning a canned version of the object. All the link magic is just to make editing easier.

4lexKidd wrote:
Quote:
I'm not sure I understand the movement and instantiate code fully, but at a glance it seems like you're scrolling the background objects when pressing WASD movement keys. Wouldn't it make more sense to move the camera, rather than all objects in the opposite direction?


yes i actually move the background layers in stead of the camera. <...>

I must admit, I didn't understand your post in its entirety, but I'm 90% certain that you can achieve the same things in a scenario with a fixed world and a moving camera.

Take the no-loading-screen world for example: Instead of spawning the right things around the player, like you would "the background scroller way", why not spawn them at their actual position while the player moves around? What the players sees should be very similar, except that all your game logic now has a static coordinate system, and not a moving one, which should simplify a lot of code on your side.

Also, I imagine that complex movement handling for the player character should be a lot easier when your world doesn't move this way and that way while he's doing that. xD

What I'm not sure about is what you think of when you say "camera focused moving" - you are aware that how the camera moves can be completely independent from how the player character moves, right? There's no need to always have the player in the middle or so and no need to dash the camera when the player character does a dash-forward. Check our the camera controller sample project in the package manager! It demonstrates a few camera behaviors, and it comes with source code if you want to take a closer look :)

4lexKidd wrote:
And thanks alot for the awesome help on improving ;) on my day to day coding job i have little to no possibilities to expand in modern coding languages like c# because at work i code in the reeealy oldschool-ish COBOL :D which means no object instancing, no classes and no memory allocation which makes the possible coding projects quite limited or realy complicated for a "rookie" ;) Therefore big thanks to all supporters of awesome ideas ;)

Wow, COBOL? Sounds wild. xD

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2017/05/04, 21:09 
Novice Member
Novice Member

Joined: 2017/04/23, 09:34
Posts: 14
Location: Germany
Role: Hobbyist
Quote:
Let's turn this question around: Why would you want an object to be linked to a Prefab? Because that connection is what allows you to modify the Prefab and propagate the changes to all of its instances, right? So far so good - but this is primarily an editor / design-time operation!

In a regular game it makes little sense to re-apply Prefabs at runtime to objects jumping around in your world simulation. This is the reason why, by default, instantiating a Prefab keeps the link in edit mode, but does not keep the link at runtime. And also why objects automatically unlink themselves after loading a scene in the sandbox or launcher. Instantiating a Prefab at runtime is basically just cloning a canned version of the object. All the link magic is just to make editing easier.


Aaahh this explains a lot ^^ i thought in order to be able to dynamicly change the prefabs i would have to link them but if this is not necessary or even quite counter intuitive on runtime then i guess i will not force that link after creation ;) are there good examples of where it is needed or maybe usefull to provide a prefab link to an object? i could imagine situations where you change the properties of objects or a object/enemy type in generell ingame so they somehow have to change and their prefabs with them?
*Edit: after looking at my code again i found the reason why i should keep that link in the first place:
Code:
GameObject tmpLayer;

                        tmpLayer = createLayer(obj.PrefabLink.Prefab, tmpPos, layer);
                        layerList.Insert(0, tmpLayer);


In the createLayer-Method i create a layer based on the prefab of the destructed old layer therefore the new one needs to know which the old one was and i do not know a other way than calling it's link to gain access to the prefab again no matter which layer and therefore which prefab must be used ^^

Quote:
I must admit, I didn't understand your post in its entirety, but I'm 90% certain that you can achieve the same things in a scenario with a fixed world and a moving camera.


hmm while keeping in mind that the amount of different objects in the game could increase dramaticly i guess moving around a camera instead of 10s to 100s of objects correctly might be a little more easier or more intuative and easier to maintain :D

Quote:
What I'm not sure about is what you think of when you say "camera focused moving"


:D aahh bad choice of words even in a non-mothertongue language xD i meand a pined camera behavior like in a situation where camera and player are pined to the middle and the rest moves arround them like in the oldschool puppet-theatres ^^ but i guess implementing a follower camera around a player would also feel more natural or intuative to the user and therefore i should more lean the developement to that direction ;)

Quote:
Check our the camera controller sample project in the package manager!


I allready saw the manager having that one in store so i think i will check that package out in the next weeks or months ;) My tilegenerator project and the now upcomming recode of the scroller has some kind of priority ^^

Quote:
Wow, COBOL? Sounds wild. xD

And it is but hey that language is more than 30 years old xD but some old thinking companys espacialy in germany like the old, reliable way of coding :D when i applied for that apprenticement they brought up the argument that cobol is so old and un-used in the broad society that there are nearly no hacks or viruses around dealing with programms of such an age or even for a IBM-system that old xD in our company we use several IBM-AS400 Servers for our programms and employees to be able to work properly :D only a few teams had the oportunity to code in modern languages like c++ because the plugins or modules they work on don't need the basic system integration and can function as stand-alones :D But yep wild language absolutely hits it ^^


Top
 Profile  
 
PostPosted: 2017/05/04, 22:28 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 1958
Location: Germany
Role: Professional
4lexKidd wrote:
are there good examples of where it is needed or maybe usefull to provide a prefab link to an object? i could imagine situations where you change the properties of objects or a object/enemy type in generell ingame so they somehow have to change and their prefabs with them?

I don't recall a single use case where you'd have to re-create a prefab link at runtime so far, so I think it's safe to say that this would be highly unusual. ^^

4lexKidd wrote:
In the createLayer-Method i create a layer based on the prefab of the destructed old layer therefore the new one needs to know which the old one was and i do not know a other way than calling it's link to gain access to the prefab again no matter which layer and therefore which prefab must be used

This isn't Duality-specific advice, but when you need to create a mapping from object type A to object type B, have a look at the Dictionary<T,U> class. Not necessarily the best choice in all cases, but worth a look! You'll find plenty of docs on that one.

Anyway, hope this helped a bit :+1:

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2017/05/04, 23:30 
Novice Member
Novice Member

Joined: 2017/04/23, 09:34
Posts: 14
Location: Germany
Role: Hobbyist
Quote:
I don't recall a single use case where you'd have to re-create a prefab link at runtime so far, so I think it's safe to say that this would be highly unusual. ^^


Ok fair enough i guess it will be safe to throw them out ;)

Quote:
This isn't Duality-specific advice, but when you need to create a mapping from object type A to object type B, have a look at the Dictionary<T,U> class. Not necessarily the best choice in all cases, but worth a look! You'll find plenty of docs on that one.


Hmm interesting... on my first approach i used a dictionary to store those but i never used dictionaries to map object A to object B hmmm nice approach though ;) i will use that technique more rather than recreating prefab links and rebuilding them from this link ^^ at a long shot i will anyway need to consider a different approach because the mechanic as it is planed currently, will get the list of which prefabs to use at which cam position a.k.a. a "world map" from the soon to be proper levelHandler.

Quote:
Anyway, hope this helped a bit :+1:

Absolutely ;) any advice even non duality related is good coding advice for me to improve on :+1:


Top
 Profile  
 
PostPosted: 2017/05/08, 13:05 
Novice Member
Novice Member

Joined: 2017/04/23, 09:34
Posts: 14
Location: Germany
Role: Hobbyist
Ok switching the handling from moving the layers to the camera, i thumbled across a logical problem... How can i maintain the paralax effect of the layers?

If i move the camera and check or create/delete the layers depending on the camera position, how can i ensure the background layers (especially the not front layers, because the front can stay in sync to the camera) move on different speeds away from the camera?
I thought of a method in which i still move the 2 further away layers by adding fractions of the camera speed to their posion and go with that but i am not sure if this is the best approach...

is there another way of solving this problem ?


Top
 Profile  
 
PostPosted: 2017/05/08, 17:58 
Site Admin
Site Admin
User avatar

Joined: 2013/05/11, 22:30
Posts: 1958
Location: Germany
Role: Professional
4lexKidd wrote:
is there another way of solving this problem ?


To make an object appear farther away while the camera moves, it should be sufficient to assign a higher value to its Z position.

Parallax rendering is the default in Duality: Create a few SpriteRenderers and place them at different Z positions, then scroll a bit with the camera - you should see a parallax effect where the far away objects "move slower" (in screen space) than objects near the camera.

Since your background layer creates regular objects, it should be possible to use this in order to create a parallax effect.

_________________
Blog | GitHub | Twitter (@Adams_Lair)


Top
 Profile  
 
PostPosted: 2017/05/09, 22:25 
Novice Member
Novice Member

Joined: 2017/04/23, 09:34
Posts: 14
Location: Germany
Role: Hobbyist
Quote:
Parallax rendering is the default in Duality: Create a few SpriteRenderers and place them at different Z positions, then scroll a bit with the camera - you should see a parallax effect where the far away objects "move slower" (in screen space) than objects near the camera.


OMG that saves a lot of finnicy detail work big thanks ;) absolutely works fine but i have to crank up that z-value and scale to get the paralax i am aiming for but hey at least no extra code logic which could mess up alot ;)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next

All times are UTC + 1 hour [ DST ]


Who is online

Users browsing this forum: No registered users and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group