Skip to content

Commit d8f478e

Browse files
Add support for passing pc.ScriptType into more functions (playcanvas#1980)
* improve pc.ScriptComponent#has * improve pc.ScriptComponent#get * improve pc.ScriptComponent#create * improve pc.ScriptComponent#destroy * improve pc.ScriptComponent#swap * improve pc.ScriptComponent#move * improve pc.ScriptRegistry#has * improve pc.ScriptRegistry#remove * improve pc.ScriptRegistry#add * fix issue when nameOrType is undefined Co-authored-by: Will Eastcott <will@playcanvas.com>
1 parent 2faa719 commit d8f478e

File tree

2 files changed

+145
-82
lines changed

2 files changed

+145
-82
lines changed

src/framework/components/script/component.js

Lines changed: 102 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ Object.assign(pc, function () {
1010
* @param {pc.Entity} entity - The Entity that this Component is attached to.
1111
* @property {pc.ScriptType[]} scripts An array of all script instances attached to an entity. This Array shall not be modified by developer.
1212
*/
13-
1413
var ScriptComponent = function ScriptComponent(system, entity) {
1514
pc.Component.call(this, system, entity);
1615

@@ -460,41 +459,63 @@ Object.assign(pc, function () {
460459
}
461460
},
462461

462+
/* eslint-disable jsdoc/no-undefined-types */
463463
/**
464464
* @function
465465
* @name pc.ScriptComponent#has
466-
* @description Detect if script is attached to an entity using name of {@link pc.ScriptType}.
467-
* @param {string} name - The name of the Script Type.
466+
* @description Detect if script is attached to an entity.
467+
* @param {string|Class<pc.ScriptType>} nameOrType - The name or type of {@link pc.ScriptType}.
468468
* @returns {boolean} If script is attached to an entity.
469469
* @example
470470
* if (entity.script.has('playerController')) {
471471
* // entity has script
472472
* }
473473
*/
474-
has: function (name) {
475-
return !!this._scriptsIndex[name];
474+
/* eslint-enable jsdoc/no-undefined-types */
475+
has: function (nameOrType) {
476+
if (typeof nameOrType === 'string') {
477+
return !!this._scriptsIndex[nameOrType];
478+
}
479+
480+
if (!nameOrType) return false;
481+
var scriptType = nameOrType;
482+
var scriptName = scriptType.__name;
483+
var scriptData = this._scriptsIndex[scriptName];
484+
var scriptInstance = scriptData && scriptData.instance;
485+
return scriptInstance instanceof scriptType; // will return false if scriptInstance undefined
476486
},
477487

488+
/* eslint-disable jsdoc/no-undefined-types */
478489
/**
479490
* @function
480491
* @name pc.ScriptComponent#get
481-
* @description Get a script instance (if attached) using name of {@link pc.ScriptType}.
482-
* @param {string} name - The name of the Script Type.
492+
* @description Get a script instance (if attached).
493+
* @param {string|Class<pc.ScriptType>} nameOrType - The name or type of {@link pc.ScriptType}.
483494
* @returns {pc.ScriptType|null} If script is attached, the instance is returned. Otherwise null is returned.
484495
* @example
485496
* var controller = entity.script.get('playerController');
486497
*/
487-
get: function (name) {
488-
var index = this._scriptsIndex[name];
489-
return (index && index.instance) || null;
498+
/* eslint-enable jsdoc/no-undefined-types */
499+
get: function (nameOrType) {
500+
if (typeof nameOrType === 'string') {
501+
var data = this._scriptsIndex[nameOrType];
502+
return data ? data.instance : null;
503+
}
504+
505+
if (!nameOrType) return null;
506+
var scriptType = nameOrType;
507+
var scriptName = scriptType.__name;
508+
var scriptData = this._scriptsIndex[scriptName];
509+
var scriptInstance = scriptData && scriptData.instance;
510+
return scriptInstance instanceof scriptType ? scriptInstance : null;
490511
},
491512

492513
/* eslint-disable jsdoc/no-undefined-types */
493514
/**
494515
* @function
495516
* @name pc.ScriptComponent#create
496-
* @description Create a script instance using name of a {@link pc.ScriptType} and attach to an entity script component.
497-
* @param {string|Class<pc.ScriptType>} name - The name of the Script Type (or alternatively the {@link pc.ScriptType} to instantiate).
517+
* @description Create a script instance and attach to an entity script component.
518+
* @param {string|Class<pc.ScriptType>} nameOrType - The name or type of {@link pc.ScriptType}.
498519
* @param {object} [args] - Object with arguments for a script.
499520
* @param {boolean} [args.enabled] - If script instance is enabled after creation. Defaults to true.
500521
* @param {object} [args.attributes] - Object with values for attributes (if any), where key is name of an attribute.
@@ -511,12 +532,12 @@ Object.assign(pc, function () {
511532
* });
512533
*/
513534
/* eslint-enable jsdoc/no-undefined-types */
514-
create: function (name, args) {
535+
create: function (nameOrType, args) {
515536
var self = this;
516537
args = args || { };
517538

518-
var scriptType = name;
519-
var scriptName = name;
539+
var scriptType = nameOrType;
540+
var scriptName = nameOrType;
520541

521542
// shorthand using script name
522543
if (typeof scriptType === 'string') {
@@ -526,7 +547,7 @@ Object.assign(pc, function () {
526547
}
527548

528549
if (scriptType) {
529-
if (!this._scriptsIndex[scriptType.__name] || !this._scriptsIndex[scriptType.__name].instance) {
550+
if (!this._scriptsIndex[scriptName] || !this._scriptsIndex[scriptName].instance) {
530551
// create script instance
531552
var scriptInstance = new scriptType({
532553
app: this.system.app,
@@ -542,22 +563,22 @@ Object.assign(pc, function () {
542563

543564
this._insertScriptInstance(scriptInstance, ind, len);
544565

545-
this._scriptsIndex[scriptType.__name] = {
566+
this._scriptsIndex[scriptName] = {
546567
instance: scriptInstance,
547568
onSwap: function () {
548-
self.swap(scriptType.__name);
569+
self.swap(scriptName);
549570
}
550571
};
551572

552-
this[scriptType.__name] = scriptInstance;
573+
this[scriptName] = scriptInstance;
553574

554575
if (!args.preloading)
555576
scriptInstance.__initializeAttributes();
556577

557-
this.fire('create', scriptType.__name, scriptInstance);
558-
this.fire('create:' + scriptType.__name, scriptInstance);
578+
this.fire('create', scriptName, scriptInstance);
579+
this.fire('create:' + scriptName, scriptInstance);
559580

560-
this.system.app.scripts.on('swap:' + scriptType.__name, this._scriptsIndex[scriptType.__name].onSwap);
581+
this.system.app.scripts.on('swap:' + scriptName, this._scriptsIndex[scriptName].onSwap);
561582

562583
if (!args.preloading) {
563584

@@ -592,45 +613,48 @@ Object.assign(pc, function () {
592613
return null;
593614
},
594615

616+
/* eslint-disable jsdoc/no-undefined-types */
595617
/**
596618
* @function
597619
* @name pc.ScriptComponent#destroy
598620
* @description Destroy the script instance that is attached to an entity.
599-
* @param {string} name - The name of the Script Type.
621+
* @param {string|Class<pc.ScriptType>} nameOrType - The name or type of {@link pc.ScriptType}.
600622
* @returns {boolean} If it was successfully destroyed.
601623
* @example
602624
* entity.script.destroy('playerController');
603625
*/
604-
destroy: function (name) {
605-
var scriptName = name;
606-
var scriptType = name;
626+
/* eslint-enable jsdoc/no-undefined-types */
627+
destroy: function (nameOrType) {
628+
var scriptName = nameOrType;
629+
var scriptType = nameOrType;
607630

608631
// shorthand using script name
609632
if (typeof scriptType === 'string') {
610633
scriptType = this.system.app.scripts.get(scriptType);
611-
if (scriptType)
612-
scriptName = scriptType.__name;
634+
} else if (scriptType) {
635+
scriptName = scriptType.__name;
613636
}
614637

615638
var scriptData = this._scriptsIndex[scriptName];
616639
delete this._scriptsIndex[scriptName];
617640
if (!scriptData) return false;
618641

619-
if (scriptData.instance && !scriptData.instance._destroyed) {
620-
scriptData.instance.enabled = false;
621-
scriptData.instance._destroyed = true;
642+
var scriptInstance = scriptData.instance;
643+
if (scriptInstance && !scriptInstance._destroyed) {
644+
scriptInstance.enabled = false;
645+
scriptInstance._destroyed = true;
622646

623647
// if we are not currently looping through our scripts
624648
// then it's safe to remove the script
625649
if (!this._isLoopingThroughScripts) {
626-
var ind = this._removeScriptInstance(scriptData.instance);
650+
var ind = this._removeScriptInstance(scriptInstance);
627651
if (ind >= 0) {
628652
this._resetExecutionOrder(ind, this._scripts.length);
629653
}
630654
} else {
631655
// otherwise push the script in _destroyedScripts and
632656
// remove it from _scripts when the loop is over
633-
this._destroyedScripts.push(scriptData.instance);
657+
this._destroyedScripts.push(scriptInstance);
634658
}
635659
}
636660

@@ -639,23 +663,37 @@ Object.assign(pc, function () {
639663

640664
delete this[scriptName];
641665

642-
this.fire('destroy', scriptName, scriptData.instance || null);
643-
this.fire('destroy:' + scriptName, scriptData.instance || null);
666+
this.fire('destroy', scriptName, scriptInstance || null);
667+
this.fire('destroy:' + scriptName, scriptInstance || null);
644668

645-
if (scriptData.instance)
646-
scriptData.instance.fire('destroy');
669+
if (scriptInstance)
670+
scriptInstance.fire('destroy');
647671

648672
return true;
649673
},
650674

651-
swap: function (script) {
652-
var scriptType = script;
675+
/* eslint-disable jsdoc/no-undefined-types */
676+
/**
677+
* @private
678+
* @function
679+
* @name pc.ScriptComponent#swap
680+
* @description Swap the script instance.
681+
* @param {string|Class<pc.ScriptType>} nameOrType - The name or type of {@link pc.ScriptType}.
682+
* @returns {boolean} If it was successfully swapped.
683+
*/
684+
/* eslint-enable jsdoc/no-undefined-types */
685+
swap: function (nameOrType) {
686+
var scriptName = nameOrType;
687+
var scriptType = nameOrType;
653688

654689
// shorthand using script name
655-
if (typeof scriptType === 'string')
690+
if (typeof scriptType === 'string') {
656691
scriptType = this.system.app.scripts.get(scriptType);
692+
} else if (scriptType) {
693+
scriptName = scriptType.__name;
694+
}
657695

658-
var old = this._scriptsIndex[scriptType.__name];
696+
var old = this._scriptsIndex[scriptName];
659697
if (!old || !old.instance) return false;
660698

661699
var scriptInstanceOld = old.instance;
@@ -675,8 +713,8 @@ Object.assign(pc, function () {
675713

676714
// add to component
677715
this._scripts[ind] = scriptInstance;
678-
this._scriptsIndex[scriptType.__name].instance = scriptInstance;
679-
this[scriptType.__name] = scriptInstance;
716+
this._scriptsIndex[scriptName].instance = scriptInstance;
717+
this[scriptName] = scriptInstance;
680718

681719
// set execution order and make sure we update
682720
// our update and postUpdate lists
@@ -697,8 +735,8 @@ Object.assign(pc, function () {
697735

698736
this._scriptMethod(scriptInstance, ScriptComponent.scriptMethods.swap, scriptInstanceOld);
699737

700-
this.fire('swap', scriptType.__name, scriptInstance);
701-
this.fire('swap:' + scriptType.__name, scriptInstance);
738+
this.fire('swap', scriptName, scriptInstance);
739+
this.fire('swap:' + scriptName, scriptInstance);
702740

703741
return true;
704742
},
@@ -799,31 +837,42 @@ Object.assign(pc, function () {
799837
}
800838
},
801839

840+
/* eslint-disable jsdoc/no-undefined-types */
802841
/**
803842
* @function
804843
* @name pc.ScriptComponent#move
805844
* @description Move script instance to different position to alter update order of scripts within entity.
806-
* @param {string} name - The name of the Script Type.
845+
* @param {string|Class<pc.ScriptType>} nameOrType - The name or type of {@link pc.ScriptType}.
807846
* @param {number} ind - New position index.
808847
* @returns {boolean} If it was successfully moved.
809848
* @example
810849
* entity.script.move('playerController', 0);
811850
*/
812-
move: function (name, ind) {
851+
/* eslint-enable jsdoc/no-undefined-types */
852+
move: function (nameOrType, ind) {
813853
var len = this._scripts.length;
814854
if (ind >= len || ind < 0)
815855
return false;
816856

817-
var scriptName = name;
857+
var scriptType = nameOrType;
858+
var scriptName = nameOrType;
818859

819-
if (typeof scriptName !== 'string')
820-
scriptName = name.__name;
860+
if (typeof scriptName !== 'string') {
861+
scriptName = nameOrType.__name;
862+
} else {
863+
scriptType = null;
864+
}
821865

822866
var scriptData = this._scriptsIndex[scriptName];
823867
if (!scriptData || !scriptData.instance)
824868
return false;
825869

826-
var indOld = this._scripts.indexOf(scriptData.instance);
870+
// if script type specified, make sure instance of said type
871+
var scriptInstance = scriptData.instance;
872+
if (scriptType && !(scriptInstance instanceof scriptType))
873+
return false;
874+
875+
var indOld = this._scripts.indexOf(scriptInstance);
827876
if (indOld === -1 || indOld === ind)
828877
return false;
829878

@@ -835,8 +884,8 @@ Object.assign(pc, function () {
835884
this._updateList.sort();
836885
this._postUpdateList.sort();
837886

838-
this.fire('move', scriptName, scriptData.instance, ind, indOld);
839-
this.fire('move:' + scriptName, scriptData.instance, ind, indOld);
887+
this.fire('move', scriptName, scriptInstance, ind, indOld);
888+
this.fire('move:' + scriptName, scriptInstance, ind, indOld);
840889

841890
return true;
842891
}

0 commit comments

Comments
 (0)