memory efficiency – Object pool implementation c++

I’ve been trying to find a way to implement an object pool for my game. I’ve found a few examples on the internet and most of them use std::lists and an example of it in a book; Game development patterns and best practices that also use std::list.

I’ve been told, however, that it’s kind of pointless to use lists for object pooling since returning an object back to the pool means that memory has to be allocated again.

I have also seen people utilize std::stack but I assume the same issue exists.

Here’s the code I made for an object pool class following the book’s example:

    /* This object has only an int data type (value).
       One method to se it and another one to print it. */
class Object
{
    public: 

        Object()
        {
            SetValue();
            std::cout << "Constructed/Reset." << std::endl;
        }

            // Copy constructor
        Object( Object& other )
        {
            this->mValue = other.mValue;
            std::cout << "Constructed." << std::endl;
        }

        ~Object()
        {
            std::cout << "Destroyed." << std::endl;
        }

        void SetValue( int val = -1 )
        {
            mValue = val;
        }

        void PrintValue()
        {
            std::cout << this->mValue << std::endl;
        }

    private:
        int mValue;

};

class Pool
{
    public:
        Pool()
        {
            std::cout << "Pool created!n";
        }

        ~Pool()
        {
            std::cout << "Pool destroyed!n";
        }

        void Fill( int size )
        {
            for( int i = 0; i < size; i++ )
            {
                Object* obj = new Object();
                pool.push_back( obj );
            }
            std::cout << "Objects created!" << "nObjects in pool: "
                      << pool.size() << std::endl;
        }

        Object* AquireObject()
        {
            if( !pool.empty() )
            {
                Object* obj = pool.back();
                pool.pop_back();
                
                std::cout << "Object aquired!"
                          << "nNumber of objects in pool: " << pool.size() << std::endl;

                return obj;
            }
            else
            {
                std::cout << "Object created and aquired!"
                          << "nNumber of objects in pool: " << pool.size() << std::endl;
                return new Object();
            }
        }

        void ReleaseObject( Object* returningObject )
        {
            returningObject->SetValue();
            pool.push_back( returningObject );
            std::cout << "Object returned to the pool!"
                      << "nNumber of objects in pool: " << pool.size() << std::endl;
        }

        void Clear()
        {
            while( !pool.empty() )
            {
                Object* obj = pool.back();
                pool.pop_back();
                delete obj;
            }
            std::cout << "Objects deleted!"
                      << "nNumber of objects in pool: " << pool.size() << std::endl;
        }

    private:
        std::list<Object*> pool;
};

I also made a slightly different version that uses unique pointers instead:

    /* This object has only an int data type (value).
       One method to se it and another one to print it. */
class Object
{
    public: 

        Object()
        {
            SetValue();
            std::cout << "Constructed/Reset." << std::endl;
        }

            // Copy constructor
        Object( Object& other )
        {
            this->mValue = other.mValue;
            std::cout << "Constructed." << std::endl;
        }

        ~Object()
        {
            std::cout << "Destroyed." << std::endl;
        }

        void SetValue( int val = -1 )
        {
            mValue = val;
        }

        void PrintValue()
        {
            std::cout << this->mValue << std::endl;
        }

    private:
        int mValue;

};

    // Object pool using std::list
class Pool
{
    public:
        Pool() = default;
        ~Pool() = default;

            /* Fills the pool (list) with a given size using an Object class (previously defined)
               as a reference using its copy constructor.*/
        void Fill( int size, Object* obj )
        {
            for( int i = 0; i < size; i++ )
            {
                std::unique_ptr<Object> object = std::make_unique<Object>( *obj );
                pool.push_back( std::move( object ) );
            }
        }

            // Clears all items in the list.
        void PoolIsClosed()
        {
            pool.clear();
        }

            // Returns an instance of an object within the list.
        std::unique_ptr<Object> GetObject()
        {
            if( !pool.empty() )
            {
                std::unique_ptr<Object> object = std::move( pool.front() );
                pool.pop_front();
                
                std::cout << "Object retrieved." << "nObjects in pool: "
                          << pool.size() << std::endl;
                
                return object;
            }
            else
            {
                /* "WARNING: NOT ALL CONTROL PATHS RETURN A VALUE." */
                std::cout << "Pool is empty." << std::endl;
            }
        }

            // Returns an instance back to the object list.
        void returnToPool( std::unique_ptr<Object> returningObject )
        {
            pool.push_back( std::move( returningObject ) );
            
            std::cout << "Object returned." << "nObjects in pool: "
                      << pool.size() << std::endl;
        }

    private:
        std::list<std::unique_ptr<Object>> pool;
};

I want to know if an implementation like this is really pointless and if so, is there a simple-ish way to implement a basic object pool class?

I know that the boost library has its own implementation of an object pool… Has anyone of you used it before? I would love to know more about it, is it hard to use?..

I also found this object pool library: https://github.com/mrDIMAS/SmartPool which looks promising and kind of easy to use but I don’t know how it works under the hood, it was a bit complicated for me to understand. Any opinions about this one?

opengl – GLSL Shader texture or procedural textures just rendering on top of object (LWJGL 2)

Recently, I have been making a 3D game.
I was messing with my shader files, when I ran into a problem. The “texture” I made for the fragment shader just renders on top of the object, and does not rotate with it or repeat on individual faces, but looks alright when I pass the gl_Vertex colors into gl_FragColor.

Here is the images to tell you what I am talking about
IMG1

While the vertex colors rotate with the object:
IMG2

I am pretty clueless as I’ve never really messed with GLSL shaders at all… I’ve researched a bit but I don’t know what this is called, so I didn’t get any good answers.

Here’s what I know:

  • Fragment shaders mess with all colors on screen
  • Vertex shaders well, mess with vertex point of the specified object you choose to start the shader for.

Should I Multiply the vertex positions with the texture? Should I add them? Do I have to do alot of matrices code to make this work? Does this deal with view and model matrices?

Here’s my code for Fragment:

#version 120 core

uniform float u_time;
uniform vec2 u_resolution;

varying vec4 verpos;

varying vec4 normals;

float plot(vec2 st) {
    return smoothstep(0.02, 0.0, abs(st.y - st.x));
}

void main(void)
{
    vec2 st = gl_FragCoord.xy/u_resolution;

    float y = st.x;
    
    vec3 color = vec3(y);
    
    float pct = plot(st);
    color = (1.0-pct) * color + pct * vec3(1.0, 0.0, 0.0);
    
    //gl_FragColor = vec4(color, 1.0);
    
    // gl_FragColor = vec4(verpos.xyzw);
    gl_FragColor = verpos;
}

And for Vertex:

#version 120 core

vec4 a = gl_Vertex;
varying vec4 verpos;
varying vec4 normals;

void main(void) 
{
    gl_Position = gl_ModelViewProjectionMatrix * a;
    verpos = gl_Vertex;
    normals = vec4(gl_Normal, 1.0);
}

Any help appreciated

Yes, I am using old methods and no VBOs and VAOs

~ Pale_Gray

object oriented – OOP in Javascript with classes

I am learning OOP in Javascript and I have done two small projecs which i have uploaded onto Github. I would really appreciate it if someone checks out my code and sees if it is adequate enough. The links are below.

https://github.com/bobaram/flash-OOp-project
https://github.com/bobaram/course-form-OOP-project-

1.Flash-OOP-project

const showBtn = document.getElementById("show-btn");
const questionCard = document.querySelector(".question-card");
const closeBtn = document.querySelector(".close-btn");
const form = document.getElementById("question-form");
const feedback = document.querySelector(".feedback");
const questionInput = document.getElementById("question-input");
const answerInput = document.getElementById("answer-input");
const questionList = document.getElementById("questions-list");

class Card {
  constructor(question, answer) {
    this.question = question;
    this.answer = answer;
  }

  createCard() {
    const html = ` 
      <div class="col-md-4">
      <div class="card card-body flashcard my-3">
     <h4 class="text-capitalize">${questionInput.value}</h4>
     <a href="#" class="text-capitalize my-3 show-answer">show/hide answer</a>
     <h5 class="answer mb-3">${answerInput.value}</h5>
     <div class="flashcard-btn d-flex justify-content-between">
      <a href="#" id="edit-flashcard" class=" btn my-1 edit-flashcard text-uppercase" data-id="">edit</a>
      <a href="#" id="delete-flashcard" class=" btn my-1 delete-flashcard text-uppercase">delete</a>
     </div>`;
    questionList.insertAdjacentHTML("afterbegin", html);
    form.reset();
  }
}

class App {
  constructor() {
    showBtn.addEventListener("click", this.showButton.bind(this));
    closeBtn.addEventListener("click", this.closeButton.bind(this));
    form.addEventListener("click", this.checkpressed.bind(this));
  }
  showButton(e) {
    e.preventDefault();
    questionCard.classList.add("showItem");
  }

  closeButton() {
    questionCard.classList.remove("showItem");
  }
  checkpressed(e) {
    e.preventDefault();
    const newCard = new Card(questionInput.value, answerInput.value);
    let clicked = e.target;
    if (clicked.classList.contains("submitBtn")) {
      if (newCard.question.length == 0 || newCard.answer.length == 0) {
        feedback.classList.add("showItem", "alert-danger");
        feedback.textContent = "cannot add empty values";
        setTimeout(function () {
          feedback.classList.remove("alert-danger", "showItem");
        }, 3000);
      } else if (!newCard.question.length == 0 && !newCard.answer.length == 0) {
        newCard.createCard();
      }
    }
    if (questionList.innerHTML.length > 0) {
      questionList.addEventListener("click", function (e) {
        e.preventDefault();
        if (e.target.classList.contains("show-answer")) {
          e.target.nextElementSibling.classList.toggle("showItem");
        } else if (e.target.classList.contains("edit-flashcard")) {
          questionInput.value =
            e.target.parentElement.parentElement.firstElementChild.textContent;
          answerInput.value =
            e.target.parentElement.parentElement.firstElementChild.nextElementSibling.nextElementSibling.textContent;
          e.target.parentElement.parentElement.parentElement.remove();
        } else if (e.target.classList.contains("delete-flashcard")) {
          e.target.parentElement.parentElement.parentElement.remove();
        }
      });
    }
  }
}
const newApp = new App();

2.Course-form-OOP

const nameInput = document.querySelector("#name");
const courseInput = document.querySelector("#course");
const authorInput = document.querySelector("#author");
const customerList = document.querySelector(".customer-list");
const form = document.querySelector("#customer-form");

class Card {
  constructor(name, course, author) {
    this.name = name;
    this.course = course;
    this.author = author;
  }

  checkInputFields() {
    if (
      !this.author.length == 0 ||
      !this.name.length == 0 ||
      !this.name.length == 0
    ) {
      this.createCard();
    } else {
      return;
    }
  }

  createCard() {
    this.random = Math.trunc(Math.random() * 5 + 1);
    this.html = `
          <div class="col-11 mx-auto col-md-6 col-lg-4 my-3">
        
          <div class="card text-left">
          <img src="https://codereview.stackexchange.com/./img/cust-${this.random}.jpg" class="card-img-top" alt="">
          <div class="card-body">
           <!-- customer name -->
           <h6 class="text-capitalize "><span class="badge badge-warning mr-2">name :</span><span id="customer-name">${this.name}</span></h6>
           <!-- end of customer name -->
           <!-- customer name -->
           <h6 class="text-capitalize my-3"><span class="badge badge-success mr-2">course :</span><span id="customer-course">
             ${this.course}
            </span></h6>
           <!-- end of customer name -->
           <!-- customer name -->
           <h6 class="text-capitalize"><span class="badge badge-danger mr-2">author :</span><span id="course-author">${this.author}</span></h6>
           <!-- end of customer name -->
          </div>
         </div>
         </div>`;
    customerList.insertAdjacentHTML("afterbegin", this.html);

    form.reset();
  }
}

class App {
  constructor() {
    form.addEventListener("click", this.checkPressed.bind(this));
  }
  checkPressed(e) {
    e.preventDefault();
    this.newCard = new Card(
      nameInput.value,
      courseInput.value,
      authorInput.value
    );
    if (
      e.target.classList.contains("submitBtn") &&
      this.newCard.checkInputFields()
    ) {
      this.newCard.checkInputFields();
    } else {
      delete this.newCard;
    }
    console.log(this.newCard);
  }
}

const run = new App();

usability – Communicate that an object in the toolbar cannot be added to the document a second time

I think the technique in your Picture A, disabling the button and showing a tooltip when you can place no more, looks fine. It is very similar to how the video game Super Mario Maker 2 handles this same problem.

Super Mario Maker 2’s UI for parts with limits

Super Mario Maker 2 is a game that lets you build custom levels by adding parts to your level from the library or from the toolbar. The toolbar is automatically populated with items you have recently placed. You can either select a part first, then tap the level to place it, or drag a part from the toolbar to the level.

Most parts can be added without limit, but some have a limit. For example, only one Checkpoint Flag may be placed. Here’s what it looks like when you select the Checkpoint Flag from the library of parts:

1 – Super Mario Maker 2 – select Checkpoint Flag in library

After confirming your selection, the Checkpoint Flag is selected in the toolbar (at the top right), ready to be placed:

2 – Super Mario Maker 2 – Checkpoint Flag selected at the right side of the toolbar at the top

After tapping the level to place the Checkpoint Flag, that part gets added to the right side of the toolbar, as it is the most recently used item. Also, since you have placed the maximum number of that part allowed, the square for that part turns gray to show it can’t be placed again:

3 – Super Mario Maker 2 – after placing a Checkpoint Flag in the level

Tapping on the screen to place another Checkpoint Flag or trying to drag a copy of that part from the toolbar does nothing but play a wood clunk sound effect.

If you open the library again, the Checkpoint Flag is grayed out there too. If you select it, the tooltip now includes “Part limit reached” in addition to the part name:

4 – Super Mario Maker 2 – Checkpoint Flag in the library after it has been placed

I found Super Mario Maker 2’s UI pretty clear when I built levels in it. However, the game assumes input with either an analog controller or a 6-inch touch screen. A UI for a desktop computer that requires a mouse may require some changes.

Still, for your specific design, I don’t see any flaws in your Picture A. It seems a fine way to communicate why you can’t place any more of a part and which part it is you have run out of.

SSS shader error (object goes pink) in Unity for Android

I am trying to get a manageable and not laggy SSS shader for an Android app made in unity, the problem is that while i run the game on the computer, everything works. Once i build the app and send it to the Android, the model turns pink as the shader is never detected.
Also, the camera in order to have the SSS visible has a shader attached to it as a script, everything works on the PC but when it transfers to apk the model goes pink.
Any help?>

unity – Why the object is not rotating slowly?

At the top

public float secondsToRotate;
private float secondsSoFar = 0.0f;

Then in the Update

private Update()
{
  secondsSoFar += Time.deltaTime;
  float t = secondsSoFar / secondsToRotate;
  Vector3 lerpPoint = Vector3.Lerp(transform.position, -transform.position, t);
  transform.rotation = Quaternion.LookRotation(lerpPoint);
}

but instead of slowly smooth rotating it’s just waiting X seconds then rotate too fast like rotating at once.
I wanted it to rotate slowly smooth. for example, if I set the secondsToRotate to 5 so the rotation will take 5 seconds.

object oriented – Google FooBar Prepare the Bunnies’ Escape Python

I’m currently working on the Foobar challenge, and I’m having difficulty with this problem.
My solution works with (all the cases that i’ve tested).

Prepare the Bunnies' Escape
===========================

You have maps of parts of the space station, each starting at a work area exit and ending at the door to an escape pod. The map is represented as a matrix of 0s and 1s, where 0s are passable space and 1s are impassable walls. The door out of the station is at the top left (0,0) and the door into an escape pod is at the bottom right (w-1,h-1). 

Write a function solution(map) that generates the length of the shortest path from the station door to the escape pod, where you are allowed to remove one wall as part of your remodeling plans. The path length is the total number of nodes you pass through, counting both the entrance and exit nodes. The starting and ending positions are always passable (0). The map will always be solvable, though you may or may not need to remove a wall. The height and width of the map can be from 2 to 20. Moves can only be made in cardinal directions; no diagonal moves are allowed.
class Points:
    def __init__(self, row, column):
        self.h = 0
        self.f = 0
        self.g = 0
        self.row = row
        self.column = column
        self.parent = None

# find the neighbours of each node in the matrix
def neighboursGet(map, row, column):
    neigh = ()
    colLength = len(map(0))
    rowLength = len(map)
    # loop to find the adjacent neighbours for each node not allowing diagonals
    for x in range(-1, 2, 2):
        if(0 <= row + x < rowLength):
            if(map(row + x)(column) != 1):
                neigh.append((row + x, column))
        if(0 <= column + x < colLength):
            if(map(row)(column + x) != 1):
                neigh.append((row, column + x))
    return neigh


# find manhattan distance from node to end point
def distance(map, row, column):
    # find the position of the final node
    rowFinal = len(map) - 1
    columnFinal = len(map(rowFinal)) - 1
    
    # find the absolute value of the manhattan distance
    manY = row - rowFinal
    if(manY < 0):
        manY *= -1
    manX = column - columnFinal
    if(manX < 0):
        manX *= -1
        
    return manX + manY

# implement A* algorithm
def AStar(map):
    colLength = len(map(0))
    rowLength = len(map)
    points = ((Points(j, i) for i in range(rowLength)) for j in range(colLength))
    openList = ()
    # calculate the distance from the end for each node
    for i in range(rowLength):
        for j in range(colLength):
            if(map(i)(j) != 1):
                points(i)(j).h = distance(map, i, j)
                points(i)(j).f = points(i)(j).h

    openList.append(points(0)(0))
    closedList = ()
    while len(openList) > 0:
        # find the node with the lowest f value
        lowPos = 0
        for i in range(len(openList)):
            if(openList(i).f < openList(lowPos).f):
                lowPos = i
        currentPosition = openList(lowPos)
        
        # find the position of the final node
        rowFinal = len(map) - 1
        columnFinal = len(map(rowFinal)) - 1
        endPosition = points(rowFinal)(columnFinal)
        # print(currentPosition.column, currentPosition.row, endPosition.row, endPosition.column)
        # backtrack to the beginning and return the length of this
        if currentPosition == endPosition:
            curr = currentPosition
            ret = ()
            while(curr.parent != None):
                ret.append(curr)
                curr = curr.parent
            return len(ret)

        openList.pop(lowPos)
        closedList.append(currentPosition)
        neighbours = neighboursGet(map, currentPosition.row, currentPosition.column)
        # print(neighbours)
        # check all the neighbours
        for i in range(len(neighbours)):
            neighbour = points(neighbours(i)(0))(neighbours(i)(1))

            # already checked
            if neighbour in closedList:
                continue

            gScore = currentPosition.g + 1
            gScoreBest = False
            if(neighbour not in openList):
                gScoreBest = True
                openList.append(neighbour)
            elif(gScore < neighbour.g):
                gScoreBest = True
            # if the neighbour is better than current position than make it
            # the currentPosition
            if(gScoreBest == True):
                neighbour.parent = currentPosition
                neighbour.g = gScore
                neighbour.f = neighbour.g + neighbour.h
def solution(map):
    # Your code here
    
    # count the number of ones in the matrix
    # and put there positions in a list
    # has initial position as a "One position" to make the position into a 0
    # which it already is
    countOnes = 0
    onePositions = ((0, 0))
    for x in range (len(map)):
        for y in range (len(map(x))):
            if(map(x)(y) == 1):
                countOnes += 1
                onePositions.append((x, y))
    
    # check every single solution by removing a one each time, 
    # and not removing one therefore countOnes + 1
    lowestValue = 10000
    for i in range(len(onePositions)):
        mapCopy = map
        onePosition = onePositions(i)
        mapCopy(onePosition(0))(onePosition(1)) = 0
        newValue = AStar(mapCopy)
        if(newValue == None):
            continue
        if(newValue < lowestValue):
            lowestValue = newValue
    # return value + 1 since the initial point counts as one as well
    
    return str(lowestValue + 1)

my solution uses the A* algorithm and it works pretty quick when I give it some cases but for some reason two of my cases fail. I think i’m missing a special case or something, can someone help?

list manipulation – Convert array object to a function

I want to make a function for fetching a value from some array by designating the entry(index) in mathematical style.

For example, I want to have a function fetchValue like this:

field1 = {{5,34,7},{9,77,11}}; (**)
field2 = {2,3,8,8,4,20,7,0,3}

fetchValue({1,2},field1) (* expected return: 34 *)
fetchValue({5},field2) (* expected return: 4 *)
fetchValue({55,1},field1) (* expected return: "Reference error. Check out the range of the array." *)
fetchValue({3,1,5,4},field1)(* expected return: "Reference error. Check out the dimension of the array." *)

What is the simplest way of doing this?

Any information would be appreciated.

My trial

Let me say we have the following two arrays:

  • the array field whose dimension is unknown(say d) and the size is n^d
  • the array position whose dimension is 1 and the size is d (the same with dimension of field)

Now, we want a function named fetchValue which takes

  • argument1 position : size d array (if d = 2, position = {2,5},{12,6},…)
  • argument2 field: size n^d array
fetchValue(position_, field_) := (
    width = Length(field);height = Length(field);
    dimension = Depth(field);
    index = 1;
    
    ret = field;
  
  While(level <= dimension,
   index = position((level));
 
   IF(1 <= index <= Length(ret), 
      ret = ret((index)), Return("Range is wrong")
    );
 
   level++;
 )

    Return (ret);
   );

This exactly returns the target entry of the field, but the data type of it is somehow a Symbol, not a Number, meaning I have to look for the way to convert Symbol to Number.

The background for this question

I’m in a project of calculating some fields on a discrete lattice and trying to use Mathematica.

The fields are not given as a analytical function, but all formed by computer calculation.

The fields are managed by array(list). So, if we want value of lattice point (1,2,5), we get the value by field((1))((2))((5)).

What I want is to make it easy to get access to the value of field on a certain lattice point like
field({1,2,5}).

javascript – Recorrer arreglo con ngFor en Angular me retorna [object Object],[object Object]

Tengo unos datos con esta estructura:

data = {
   test: [
     {
       nombre_cv: "test",
       bloque: "Articulos",
       atributo: "titulo",
       visible_cv_personalizado: true
     }
   ],
   convocatoria: [
     {
       nombre_cv: "test",
       bloque: "Articulos",
       atributo: "id",
       visible_cv_personalizado: true
     },
     {
       nombre_cv: "test",
       bloque: "Articulos", 
       atributo: "titulo", 
       visible_cv_personalizado: true
     }
   ]
 }

Quiero que se muestre el test y la convocatoria con sus propiedades, para ello uso ngFor de la siguiente forma:

 <div class="card" *ngFor="let item of data | keyvalue">
      Key: <b>{{item.key}},</b> value: <b> {{item.value}} |</b>
 </div>

Pero al momento de mostrar en pantalla me retorna esto: Key: convocatoria, value: [object Object] | Key: test, value: [object Object],[object Object]

Como pueden ver me retorna la llave, pero las propiedades salen con [object Object],[object Object].

Cómo puedo hacer que me muestre todas las propiedades de test y convocatoria? Agradezco de antemano espero me puedan ayudar.

unity – How can I draw a circle around a specific object, not necessarily the object the script is attached to?

I have this script that draws a circle around the object the script is attached to.

I would like also to use the centerObject variable as an option to draw another circle around the centerObject, or just only around the centerObject and not the transform the script is attached to. I’m not sure how to do it.

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

(ExecuteAlways)
(RequireComponent(typeof(UnityEngine.LineRenderer)))
public class DrawCircle : MonoBehaviour
{
    public GameObject centerObject;
    (Range(1, 50)) public int segments = 50;
    (Range(1, 500)) public float xRadius = 5;
    (Range(1, 500)) public float yRadius = 5;
    (Range(0.1f, 5)) public float width = 0.1f;
    (Range(0, 100)) public float height = 0;
    public bool controlBothXradiusYradius = false;
    public bool draw = true;

    (SerializeField) private LayerMask targetLayers;
    (SerializeField) private LineRenderer line;

    private void Start()
    {
        if (!line) line = GetComponent<LineRenderer>();

        if (draw)
            CreatePoints();
    }

    private void Update()
    {
        if (Physics.CheckSphere(transform.position, xRadius, targetLayers))
        {
            Debug.Log("player detected");
        }
        else
        {
            Debug.Log("player NOT detected");
        }
    }

    public void CreatePoints()
    {
        line.enabled = true;
        line.widthMultiplier = width;
        line.useWorldSpace = false;
        line.widthMultiplier = width;
        line.positionCount = segments + 1;

        float x;
        float y;

        var angle = 20f;
        var points = new Vector3(segments + 1);
        for (int i = 0; i < segments + 1; i++)
        {
            x = Mathf.Sin(Mathf.Deg2Rad * angle) * xRadius;
            y = Mathf.Cos(Mathf.Deg2Rad * angle) * yRadius;

            points(i) = new Vector3(x, height, y);

            angle += (380f / segments);
        }

        // it's way more efficient to do this in one go!
        line.SetPositions(points);
    }

#if UNITY_EDITOR
    private float prevXRadius, prevYRadius;
    private int prevSegments;
    private float prevWidth;
    private float prevHeight;

    private void OnValidate()
    {
        // Can't set up our line if the user hasn't connected it yet.
        if (!line) line = GetComponent<LineRenderer>();
        if (!line) return;

        if (!draw)
        {
            // instead simply disable the component
            line.enabled = false;
        }
        else
        {
            // Otherwise re-enable the component
            // This will simply re-use the previously created points
            line.enabled = true;

            if (xRadius != prevXRadius || yRadius != prevYRadius || segments != prevSegments || width != prevWidth || height != prevHeight)
            {
                CreatePoints();

                // Cache our most recently used values.
                prevXRadius = xRadius;
                prevYRadius = yRadius;
                prevSegments = segments;
                prevWidth = width;
                prevHeight = height;
            }

            if (controlBothXradiusYradius)
            {
                yRadius = xRadius;
            }
        }
    }
#endif
}

Screenshot of script in action