DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Bennett Upfield
Bennett Upfield

Posted on

Instantiation Difference Over Class Difference

Creating A Single Class to Handle Multiple Types of Objects

In this little blog post I will be displaying a project that I have been working on in UnityVr. As I'm I've been meaning to push this blogpost for a while plz excuse the horrible or even non-modeled objects that you see in the presentation. The focus for this blog post will be how I designed the program to handle multiple types of objects underneath a single class by instantiating the class widely differently to have different results. The Two Objects that I intend to make in the project are a "fireball effect" and a "flamethrower effect" which are both handled by the same particle class.

Fireball

Ball Gif

Completely unmodeled or animated, the real effect would have more fireballs with different models and light sources layered on.

Flamethrower

Cone Gif

The Code

class Particle {
        public Vector3 oPos;
        public Vector3 postion;
        public Vector3 objectStart;
        public Vector3 velocity;
        public Vector3 sideVel;
        public Vector3 circleVel;
        public GameObject self1;

        public float time;
        public void update(Sprite mat, SwordController maths, float addti, int index, int index2){
            if(self1.GetComponent<SpriteRenderer>() == null){self1.AddComponent<SpriteRenderer>();}
            self1.GetComponent<SpriteRenderer>().sprite = mat;
            time += addti;
            self1.name = $"{index2}Particle{index}";
        }
        public void physicsUpdate(SwordController maths, float t, float adjustmentrate){
            Vector3 wholeVel = (velocity + sideVel + circleVel) * t;
            postion += wholeVel;
            Transform tr = self1.transform;
            tr.localPosition = postion;
            if(velocity != new Vector3()){
                Vector3 z = velocity + sideVel;
                Vector3 lineStart = oPos - velocity;
                float multiplier = (z.x * (lineStart.x - oPos.x) + z.y * (lineStart.y - oPos.y) + z.z * (lineStart.z - oPos.z)) / (Mathf.Pow(z.x , 2) + Mathf.Pow(z.y, 2) + Mathf.Pow(z.z, 2));
                Vector3 closestPoint = new Vector3(lineStart.x + z.x * multiplier, lineStart.y + z.y * multiplier, lineStart.z + z.z * multiplier);
                Vector3 zdirect = closestPoint - oPos;
                Vector3 cross = Vector3.Cross(zdirect, z);
                Vector3 cross2 = Vector3.Cross(z, cross);
                tr.localRotation = maths.fromForward(cross2.normalized,  zdirect.normalized);
            }
            else
            {
                tr.localRotation = maths.fromForward((postion - velocity * time - oPos).normalized, wholeVel);
            }
            if(circleVel != new Vector3() || sideVel != new Vector3()){
                Vector3 radius = (postion - velocity * time - oPos);
                if(circleVel != new Vector3()){
                    circleVel += -radius.normalized * (Mathf.Pow(circleVel.magnitude, 2) / radius.magnitude) * t;
                }
                if(sideVel != new Vector3()){
                    sideVel = radius.normalized * Mathf.Abs(sideVel.magnitude);
                }
            }
        }
        public void destroyObject(){
            Destroy(self1);
        }
    }
Enter fullscreen mode Exit fullscreen mode
(To be honest I did fail on two sections of creating the catch all class the two if statements. The first if statement is used to decide how the particle should be rotated, as I'm sad to say I couldn't figure out an ideal way to handle it, and the second is just because the unity Vector3 struct did not like taking a magnitude of 0.)

Both of these functions use the same particle class to operate (except for what I just mentioned), but because of how each is instantiated they provide objects that look completely different. Below are another two code Blocks that contain both the instantiation for the "fireball" and for the "flamethrower".

Fireball

void particleCircleInstatiater(float t, int howmany, GameObject fireball){
        for(int i = howmany; i > 0; i--){
            Vector3 oPos = new Vector3(fireball.transform.position.x, fireball.transform.position.y, fireball.transform.position.z);
            Vector3 forVel = new Vector3(Random.Range(-1f,1f), Random.Range(-1f,1f), Random.Range(-1f,1f)).normalized * Random.Range(.8f, 1f); //not actuall velocity but simply the direction to figure out the circular velocity
            Vector3 pos = new Vector3() + forVel; //might need to create a seperate object to attach the particles to... attached might need to change
            Vector3 sideVel = maths.XDirectionFinder(forVel, Random.Range(0, Mathf.PI * 2)); //Again not real velocity but just to find circlevel... might need to change to a not random range may look better
            Vector3 circleVel = Vector3.Normalize(Vector3.Cross(sideVel, forVel)) * Random.Range(rotateSpeed[0], rotateSpeed[1]); //The only actual velocity
            int nameNum = int.Parse(fireball.name.Remove(0, 8));
            System.Array.Resize<Particle>(ref partArr2[nameNum], partArr2[nameNum].Length + 1);
            GameObject particle = new GameObject(name: $"{nameNum}Particle{partArr2[nameNum].Length-1}");
            particle.transform.SetParent(fireball.transform);
            partArr2[nameNum][partArr2[nameNum].Length-1] = new Particle{postion = pos, oPos = new Vector3(), velocity = new Vector3(), sideVel = new Vector3(), circleVel = circleVel, time = 0, self1 = particle};
        }
    }
Enter fullscreen mode Exit fullscreen mode

"Flamethrower"

void particleLinearInstatiater(float t, int howmany){
        for(int i = howmany ;i > 0; i--){
            Vector3 oPos = new Vector3(attached.transform.position.x, attached.transform.position.y, attached.transform.position.z);
            float randomRadius = Random.Range(radius[0], radius[1]);
            Vector3 randomPos = ((new Vector3(Random.Range(-1f,1f), Random.Range(-1f,1f), Random.Range(-1f,1f)).normalized) * randomRadius) + oPos;
            float randomForward = Random.Range(speed[0], speed[1]);
            Vector3 forVel = attached.transform.forward * randomForward;
            float multiplier = (oPos.x - randomPos.x + oPos.y - randomPos.y + oPos.z - randomPos.z) / (Mathf.Pow(forVel.x , 2) + Mathf.Pow(forVel.y, 2) + Mathf.Pow(forVel.z, 2));
            Vector3 closestPoint = new Vector3(oPos.x + forVel.x * multiplier, oPos.y + forVel.y * multiplier, oPos.z + forVel.z * multiplier);
            Vector3 sideVel;
            float randomDepAngle = randomForward * (Random.Range(anglespeed[0], anglespeed[1]) / 100f); //anglespeed is a percentage of forward to deal with random issues
            if(randomRadius == 0){
                sideVel = maths.XDirectionFinder(forVel.normalized, Random.Range(0, Mathf.PI * 2)).normalized * randomDepAngle;
            }
            else{
                sideVel = (randomPos - closestPoint).normalized * randomDepAngle;
            }
            Vector3 circleVel = Vector3.Normalize(Vector3.Cross(sideVel, forVel)) * Random.Range(rotateSpeed[0], rotateSpeed[1]);
            if(sideVel != new Vector3(0,0,0)){
                circleVel = Vector3.Normalize(Vector3.Cross(sideVel, forVel)) * Random.Range(rotateSpeed[0], rotateSpeed[1]);
            }
            else{
                circleVel = Vector3.Normalize(Vector3.Cross((randomPos - closestPoint).normalized, forVel)) * Random.Range(rotateSpeed[0], rotateSpeed[1]);
            }
            if(randomRadius == 0 && anglespeed[1] == 0){
                circleVel = new Vector3(0, 0, 0);
                sideVel = new Vector3(0, 0, 0);
            }
            System.Array.Resize<Particle>(ref partArr2[partArr2.Length - 1], partArr2[partArr2.Length - 1].Length + 1);
            partArr2[partArr2.Length - 1][partArr2[partArr2.Length - 1].Length-1] = new Particle{postion = randomPos, oPos = closestPoint, objectStart = attached.transform.position, velocity = forVel, sideVel = sideVel, circleVel = circleVel, time = 0, self1 = new GameObject(name:${partArr2.Length1}Particle{partArr2[partArr2.Length - 1].Length-1}")};
        }
    }
Enter fullscreen mode Exit fullscreen mode

The only difference between these two objects is the difference between the instantiation code. For one it creates an object that orbits around a central point, and the next can create an object that spirals around a central point going forward. Just off a few changes to the way you create the object the class can will operate in the same way, but have different results.

Conclusion

To keep this little post little, I will end it here. Instead of creating different classes for every single object that you want to create you can take a different approach of creating an object, usually simpler, that can handle a larger range of possibilities. This is shown through the code examples I have above, but of course this way of coding does have its drawbacks. For example, every single different object I would have to create a different instatiator, instead of having it contained within the class. But, if you are working on creating a system with a lot of different uses coding such that instantiation creates the difference in objects instead of the class definitions can help reduce repeated code and be easier to program, as for each function you already have the base class programmed.

Top comments (0)

🌚 Life is too short to browse without dark mode