Looking for feedback about best practices


#1

Had an interesting discussion with some of your about the need to ‘re-use’ pc.Vec3s and pc,Quats instead of constantly instantiating new ones. It made me think that my way of writing scripts in PlayCanvas may not be optimal and following best practices. I like to get your feedback on what I could change to improve performance, readability and composability. Here is a script I just wrote, it’s a simple implementation of the kinematic ‘arrive’ movement behavior. Looking forward to your feedback.

const KinematicArrive = pc.createScript('kinematicArrive');

KinematicArrive.steering = {
    velocity: new pc.Vec3(), 
    rotation: new pc.Quat() 
}

KinematicArrive.prototype.initialize = function() {
    this.position = this.entity.getPosition();
    
    this.target = this.position.clone();
    this.targetOffset = new pc.Vec3(0, this.position.y, 0);
    this.radius = 0.1;
    this.timeToTarget = 0.5;
    this.turnSpeed = 5;
    this.maxSpeed = 10;
    this.rb = this.entity.rigidbody;

    // Listen to mouse raycast hit and set target
    this.app.on('mouseHitPosition', function(targetPos: pc.Vec3) {
        this.target.copy(targetPos.add(this.targetOffset));
    }, this);
}

KinematicArrive.prototype.update = function(dt: number) {
    this.setOrientation(this.getSteering(), dt);
}

KinematicArrive.prototype.getSteering = function() {
    const steering = KinematicArrive.steering;
    const position = this.position;


    // get direction to the target
    steering.velocity.sub2(this.target, this.entity.getPosition());
    
    // check if in radius
    if(steering.velocity.length() < this.radius) {
        steering.velocity.copy(pc.Vec3.ZERO);
        steering.rotation.copy(this.entity.getRotation());
        return steering;
    }

    // we need to move target. get there in timeToTarget seconds
    steering.velocity.scale(1/this.timeToTarget);
    
    // limit speed to max
    if(steering.velocity.length() > this.maxSpeed) {
        steering.velocity.normalize();
        steering.velocity.scale(this.maxSpeed);
    }
    
    // update the rotation to face target
    steering.rotation.lookAt(position, this.target);

    return steering;
}

KinematicArrive.prototype.setOrientation = function(steering: {velocity: pc.Vec3, rotation: pc.Quat}, dt: number) {
    // update the player velocity
    this.rb.linearVelocity = steering.velocity;
    // Slowly update the rotation over the timeToTarget time    
    this.entity.setRotation(new pc.Quat().slerp(this.entity.getRotation(), steering.rotation, dt * this.turnSpeed));
}

#2

Yeah try to reuse objects as much as possible - avoid allocating memory at runtime. Try to allocate all your memory in the initialization phase and then reuse objects at runtime.