2023-12-24 09:14:46 -06:00
function obj _unique _name ( name , obj )
{
name = name . replaceAll ( '.' , '_' ) ;
if ( ! ( name in obj ) ) return name ;
var t = 1 ;
var n = name + t ;
while ( n in obj ) {
t ++ ;
n = name + t ;
}
return n ;
}
2023-11-07 12:45:52 -06:00
var actor = { } ;
2023-11-29 12:40:13 -06:00
actor . spawn = function ( script , config ) {
if ( typeof script !== 'string' ) return ;
var padawan = Object . create ( actor ) ;
compile _env ( script , padawan , "script" ) ;
2023-11-07 12:45:52 -06:00
2023-11-29 12:40:13 -06:00
if ( typeof config === 'object' )
Object . merge ( padawan , config ) ;
2023-11-29 17:31:41 -06:00
padawan . padawans = [ ] ;
padawan . timers = [ ] ;
padawan . master = this ;
Object . hide ( padawan , "master" , "timers" ) ;
this . padawans . push ( padawan ) ;
2023-11-29 12:40:13 -06:00
return padawan ;
} ;
actor . die = function ( actor ) {
} ;
2023-11-29 17:31:41 -06:00
actor . timers = [ ] ;
actor . kill = function ( ) {
this . timers . forEach ( t => t . kill ( ) ) ;
this . master . remove ( this ) ;
this . padawans . forEach ( p => p . kill ( ) ) ;
this . _ _dead _ _ = true ;
2023-11-29 12:40:13 -06:00
} ;
2023-12-24 09:14:46 -06:00
2023-11-29 12:40:13 -06:00
actor . delay = function ( fn , seconds ) {
2023-11-29 17:31:41 -06:00
var t = Object . create ( timer ) ;
t . remain = seconds ;
t . kill = ( ) => {
timer . kill . call ( t ) ;
this . timers . remove ( t ) ;
}
t . fire = ( ) => {
if ( this . _ _dead _ _ ) return ;
fn ( ) ;
t . kill ( ) ;
} ;
Register . appupdate . register ( t . update , t ) ;
2023-11-29 12:40:13 -06:00
this . timers . push ( t ) ;
return function ( ) { t . kill ( ) ; } ;
} ;
actor . clock = function ( fn ) { } ;
2023-11-29 17:31:41 -06:00
actor . master = undefined ;
actor . padawans = [ ] ;
actor . remaster = function ( to ) {
this . master . padawans . remove ( this ) ;
this . master = to ;
to . padawans . push ( this ) ;
} ;
2023-12-24 09:14:46 -06:00
var gameobject _impl = {
get pos ( ) {
Debug . assert ( this . level , ` Entity ${ this . toString ( ) } has no level. ` ) ;
return this . level . world2this ( this . worldpos ( ) ) ;
} ,
set pos ( x ) {
Debug . assert ( this . level , ` Entity ${ this . toString ( ) } has no level. ` ) ;
this . set _worldpos ( this . level . this2world ( x ) ) ;
} ,
get angle ( ) {
Debug . assert ( this . level , ` No level set on ${ this . toString ( ) } ` ) ;
return this . worldangle ( ) - this . level . worldangle ( ) ;
} ,
set angle ( x ) {
var diff = x - this . angle ;
this . objects . forEach ( function ( x ) {
x . rotate ( diff ) ;
x . pos = Vector . rotate ( x . pos , diff ) ;
} ) ;
this . sworldangle ( x - this . level . worldangle ( ) ) ;
} ,
get scale ( ) {
Debug . assert ( this . level , ` No level set on ${ this . toString ( ) } ` ) ;
2023-12-26 15:39:46 -06:00
var pscale ;
if ( typeof this . _ _proto _ _ . scale === 'object' )
pscale = this . _ _proto _ _ . scale ;
else
pscale = [ 1 , 1 , 1 ] ;
return this . gscale ( ) . map ( ( x , i ) => x / ( this . level . gscale ( ) [ i ] * pscale [ i ] ) ) ;
2023-12-24 09:14:46 -06:00
} ,
set scale ( x ) {
if ( typeof x === 'number' )
x = [ x , x ] ;
var pct = this . scale . map ( ( s , i ) => x [ i ] / s ) ;
this . spread ( pct ) ;
/* TRANSLATE ALL SUB OBJECTS */
this . objects . forEach ( obj => {
obj . spread ( pct ) ;
obj . pos = obj . pos . map ( ( x , i ) => x * pct [ i ] ) ;
} ) ;
} ,
2023-12-26 15:39:46 -06:00
2023-12-24 09:14:46 -06:00
get draw _layer ( ) { return cmd ( 171 , this . body ) ; } ,
set draw _layer ( x ) { cmd ( 172 , this . body , x ) ; } ,
set layer ( x ) { cmd ( 75 , this . body , x ) ; } ,
get layer ( ) { cmd ( 77 , this . body ) ; } ,
set mass ( x ) { set _body ( 7 , this . body , x ) ; } ,
get mass ( ) {
if ( ! ( this . phys === Physics . dynamic ) )
return this . _ _proto _ _ . mass ;
return q _body ( 5 , this . body ) ;
} ,
get elasticity ( ) { return cmd ( 107 , this . body ) ; } ,
set elasticity ( x ) { cmd ( 106 , this . body , x ) ; } ,
get friction ( ) { return cmd ( 109 , this . body ) ; } ,
set friction ( x ) { cmd ( 108 , this . body , x ) ; } ,
set gravity ( x ) { cmd ( 167 , this . body , x ) ; } ,
get gravity ( ) { return cmd ( 159 , this . body ) ; } ,
set timescale ( x ) { cmd ( 168 , this . body , x ) ; } ,
get timescale ( ) { return cmd ( 169 , this . body ) ; } ,
set phys ( x ) { set _body ( 1 , this . body , x ) ; } ,
get phys ( ) { return q _body ( 0 , this . body ) ; } ,
get velocity ( ) { return q _body ( 3 , this . body ) ; } ,
set velocity ( x ) { set _body ( 9 , this . body , x ) ; } ,
get damping ( ) { return cmd ( 157 , this . body ) ; } ,
set damping ( x ) { cmd ( 156 , this . body , x ) ; } ,
get angularvelocity ( ) { return Math . rad2turn ( q _body ( 4 , this . body ) ) ; } ,
set angularvelocity ( x ) { set _body ( 8 , this . body , Math . turn2rad ( x ) ) ; } ,
get max _velocity ( ) { return cmd ( 152 , this . body ) ; } ,
set max _velocity ( x ) { cmd ( 151 , this . body , x ) ; } ,
get max _angularvelocity ( ) { return cmd ( 155 , this . body ) ; } ,
set max _angularvelocity ( x ) { cmd ( 154 , this . body , x ) ; } ,
get _moi ( ) { return q _body ( 6 , this . body ) ; } ,
set _moi ( x ) {
if ( x <= 0 ) {
Log . error ( "Cannot set moment of inertia to 0 or less." ) ;
return ;
}
set _body ( 13 , this . body , x ) ;
} ,
} ;
2023-09-08 12:35:06 -05:00
var gameobject = {
2023-12-20 09:19:04 -06:00
get _comp _by _name ( name ) {
var comps = [ ] ;
for ( var c of Object . values ( this . components ) )
if ( c . comp === name ) comps . push ( c ) ;
if ( comps . length ) return comps ;
return undefined ;
} ,
2023-12-18 17:12:05 -06:00
check _dirty ( ) {
this . _ed . urdiff = this . json _obj ( ) ;
this . _ed . dirty = ! this . _ed . urdiff . empty ;
var lur = ur [ this . level . ur ] ;
if ( ! lur ) return ;
var lur = lur . objects [ this . toString ( ) ] ;
var d = ediff ( this . _ed . urdiff , lur ) ;
if ( ! d || d . empty )
this . _ed . inst = true ;
else
this . _ed . inst = false ;
} ,
2023-12-24 11:50:01 -06:00
_ed : {
selectable : false ,
dirty : false
} ,
2023-12-18 17:12:05 -06:00
namestr ( ) {
var s = this . toString ( ) ;
if ( this . _ed . dirty )
if ( this . _ed . inst ) s += "#" ;
else s += "*" ;
return s ;
} ,
2023-11-29 12:40:13 -06:00
full _path ( ) {
return this . path _from ( Primum ) ;
} ,
2023-10-17 12:22:06 -05:00
path _from ( o ) {
var p = this . toString ( ) ;
var c = this . level ;
while ( c && c !== o && c !== Primum ) {
p = c . toString ( ) + "." + p ;
c = c . level ;
}
if ( c === Primum ) p = "Primum." + p ;
return p ;
} ,
2023-10-06 12:38:49 -05:00
clear ( ) {
2023-10-16 09:40:43 -05:00
for ( var k in this . objects ) {
this . objects [ k ] . kill ( ) ;
} ;
2023-10-06 12:38:49 -05:00
this . objects = { } ;
} ,
2023-11-07 12:45:52 -06:00
delay ( fn , seconds ) {
2023-12-26 15:39:46 -06:00
var t = timer . delay ( fn . bind ( this ) , seconds ) ;
2023-12-19 15:34:36 -06:00
this . timers . push ( t ) ;
return t ;
2023-11-17 15:16:13 -06:00
} ,
tween ( prop , values , def ) {
var t = Tween . make ( this , prop , values , def ) ;
t . play ( ) ;
var k = function ( ) { t . pause ( ) ; }
this . timers . push ( k ) ;
return k ;
} ,
cry ( file ) {
2023-11-27 14:29:55 -06:00
var p = Sound . play ( file , Sound . bus . sfx ) ;
var killfn = p . kill . bind ( p ) ;
2023-11-27 17:04:04 -06:00
p . end = killfn ;
2023-11-27 14:29:55 -06:00
this . timers . push ( killfn ) ;
return killfn ;
2023-11-07 12:45:52 -06:00
} ,
2023-11-06 07:05:27 -06:00
set torque ( x ) { if ( ! ( x >= 0 && x <= Infinity ) ) return ; cmd ( 153 , this . body , x ) ; } ,
2023-10-06 12:38:49 -05:00
gscale ( ) { return cmd ( 103 , this . body ) ; } ,
2023-11-14 09:20:09 -06:00
sgscale ( x ) {
if ( typeof x === 'number' )
2023-11-15 16:42:39 -06:00
x = [ x , x ] ;
cmd ( 36 , this . body , x )
2023-11-14 09:20:09 -06:00
} ,
2023-12-18 17:12:05 -06:00
2023-12-24 09:14:46 -06:00
phys _material ( ) {
var mat = { } ;
mat . elasticity = this . elasticity ;
mat . friction = this . friction ;
return mat ;
2023-09-21 08:38:23 -05:00
} ,
2023-10-02 17:03:01 -05:00
worldpos ( ) { return q _body ( 1 , this . body ) ; } ,
set _worldpos ( x ) {
2023-11-15 16:42:39 -06:00
var poses = this . objects . map ( x => x . pos ) ;
2023-10-02 07:58:17 -05:00
set _body ( 2 , this . body , x ) ;
2023-11-15 16:42:39 -06:00
this . objects . forEach ( ( o , i ) => o . set _worldpos ( this . this2world ( poses [ i ] ) ) ) ;
2023-09-25 16:34:48 -05:00
} ,
2023-12-18 06:45:27 -06:00
screenpos ( ) { return world2screen ( this . worldpos ( ) ) ; } ,
2023-09-14 17:37:04 -05:00
2023-12-24 09:14:46 -06:00
worldangle ( ) { return Math . rad2turn ( q _body ( 2 , this . body ) ) ; } ,
sworldangle ( x ) { set _body ( 0 , this . body , Math . turn2rad ( x ) ) ; } ,
2023-11-29 12:40:13 -06:00
2023-10-10 17:37:58 -05:00
spawn _from _instance ( inst ) {
2023-10-11 17:22:41 -05:00
return this . spawn ( inst . ur , inst ) ;
2023-10-10 17:37:58 -05:00
} ,
2023-10-11 17:22:41 -05:00
2023-10-10 17:37:58 -05:00
spawn ( ur , data ) {
2023-09-19 12:35:12 -05:00
if ( typeof ur === 'string' )
ur = prototypes . get _ur ( ur ) ;
2023-10-02 07:58:17 -05:00
if ( ! ur ) {
2023-10-18 17:20:23 -05:00
Log . error ( "Failed to make UR from " + ur ) ;
2023-10-02 07:58:17 -05:00
return undefined ;
}
2023-10-10 17:37:58 -05:00
var go = ur . make ( this , data ) ;
2023-10-26 11:48:02 -05:00
Object . hide ( this , go . toString ( ) ) ;
2023-10-02 07:58:17 -05:00
return go ;
2023-09-19 12:35:12 -05:00
} ,
2023-10-10 17:37:58 -05:00
/* Reparent 'this' to be 'parent's child */
2023-10-04 17:57:37 -05:00
reparent ( parent ) {
2023-12-18 17:12:05 -06:00
Debug . assert ( parent , ` Tried to reparent ${ this . toString ( ) } to nothing. ` ) ;
2023-12-26 15:39:46 -06:00
if ( this . level === parent ) {
console . warn ( "not reparenting ..." ) ;
console . warn ( ` ${ this . level } is the same as ${ parent } ` ) ;
2023-10-10 17:37:58 -05:00
return ;
2023-12-26 15:39:46 -06:00
}
2023-10-10 17:37:58 -05:00
this . level ? . remove _obj ( this ) ;
2023-10-04 17:57:37 -05:00
this . level = parent ;
2023-10-10 17:37:58 -05:00
function unique _name ( list , obj ) {
var str = obj . toString ( ) . replaceAll ( '.' , '_' ) ;
var n = 1 ;
var t = str ;
2023-10-17 12:22:06 -05:00
while ( t in list ) {
2023-10-10 17:37:58 -05:00
t = str + n ;
n ++ ;
}
return t ;
} ;
2023-10-17 12:22:06 -05:00
var name = unique _name ( parent , this . ur ) ;
2023-10-10 17:37:58 -05:00
parent . objects [ name ] = this ;
2023-10-17 12:22:06 -05:00
parent [ name ] = this ;
2023-10-10 17:37:58 -05:00
this . toString = function ( ) { return name ; } ;
2023-10-04 17:57:37 -05:00
} ,
2023-10-10 17:37:58 -05:00
2023-10-04 17:57:37 -05:00
remove _obj ( obj ) {
2023-10-10 17:37:58 -05:00
if ( this [ obj . toString ( ) ] === this . objects [ obj . toString ( ) ] )
delete this [ obj . toString ( ) ] ;
delete this . objects [ obj . toString ( ) ] ;
2023-10-17 12:22:06 -05:00
delete this [ obj . toString ( ) ] ;
2023-10-04 17:57:37 -05:00
} ,
2023-11-30 10:47:59 -06:00
2023-10-10 17:37:58 -05:00
components : { } ,
objects : { } ,
2023-10-04 17:57:37 -05:00
level : undefined ,
2023-11-06 07:05:27 -06:00
2023-12-18 17:12:05 -06:00
pulse ( vec ) { set _body ( 4 , this . body , vec ) ; } ,
shove ( vec ) { set _body ( 12 , this . body , vec ) ; } ,
shove _at ( vec , at ) { set _body ( 14 , this . body , vec , at ) ; } ,
world2this ( pos ) { return cmd ( 70 , this . body , pos ) ; } ,
this2world ( pos ) { return cmd ( 71 , this . body , pos ) ; } ,
this2screen ( pos ) { return world2screen ( this . this2world ( pos ) ) ; } ,
2023-12-19 15:34:36 -06:00
screen2this ( pos ) { return this . world2this ( screen2world ( pos ) ) ; } ,
2023-11-16 09:27:04 -06:00
dir _world2this ( dir ) { return cmd ( 160 , this . body , dir ) ; } ,
dir _this2world ( dir ) { return cmd ( 161 , this . body , dir ) ; } ,
2023-12-18 17:12:05 -06:00
alive ( ) { return this . body >= 0 ; } ,
in _air ( ) { return q _body ( 7 , this . body ) ; } ,
2023-10-26 11:48:02 -05:00
2023-12-18 17:12:05 -06:00
hide ( ) { this . components . forEach ( x => x . hide ( ) ) ; this . objects . forEach ( x => x . hide ( ) ) ; } ,
2023-10-04 17:57:37 -05:00
show ( ) { this . components . forEach ( function ( x ) { x . show ( ) ; } ) ; this . objects . forEach ( function ( x ) { x . show ( ) ; } ) ; } ,
width ( ) {
var bb = this . boundingbox ( ) ;
return bb . r - bb . l ;
} ,
height ( ) {
var bb = this . boundingbox ( ) ;
return bb . t - bb . b ;
} ,
2023-12-24 11:50:01 -06:00
/* Moving, rotating, scaling functions, world relative */
move ( vec ) { this . set _worldpos ( this . worldpos ( ) . add ( vec ) ) ; } ,
2023-12-24 09:14:46 -06:00
rotate ( x ) { this . sworldangle ( this . worldangle ( ) + x ) ; } ,
spread ( vec ) { this . sgscale ( this . gscale ( ) . map ( ( x , i ) => x * vec [ i ] ) ) ; } ,
2023-10-09 13:03:12 -05:00
2023-10-04 17:57:37 -05:00
/* Make a unique object the same as its prototype */
revert ( ) {
2023-10-30 17:41:32 -05:00
var jobj = this . json _obj ( ) ;
2023-11-16 09:27:04 -06:00
var lobj = this . level . _ _proto _ _ . objects [ this . toString ( ) ] ;
2023-10-30 17:41:32 -05:00
delete jobj . objects ;
Object . keys ( jobj ) . forEach ( function ( x ) {
2023-11-16 09:27:04 -06:00
if ( lobj && x in lobj )
this [ x ] = lobj [ x ] ;
else
this [ x ] = this . _ _proto _ _ [ x ] ;
2023-10-30 17:41:32 -05:00
} , this ) ;
2023-10-10 17:37:58 -05:00
this . sync ( ) ;
2023-10-04 17:57:37 -05:00
} ,
check _registers ( obj ) {
Register . unregister _obj ( obj ) ;
if ( typeof obj . update === 'function' )
Register . update . register ( obj . update , obj ) ;
if ( typeof obj . physupdate === 'function' )
Register . physupdate . register ( obj . physupdate , obj ) ;
if ( typeof obj . collide === 'function' )
obj . register _hit ( obj . collide , obj ) ;
if ( typeof obj . separate === 'function' )
obj . register _separate ( obj . separate , obj ) ;
if ( typeof obj . draw === 'function' )
Register . draw . register ( obj . draw , obj ) ;
if ( typeof obj . debug === 'function' )
Register . debug . register ( obj . debug , obj ) ;
2023-11-07 12:45:52 -06:00
if ( typeof obj . gui === 'function' )
Register . gui . register ( obj . gui , obj ) ;
2023-11-22 03:51:43 -06:00
for ( var k in obj ) {
if ( ! k . startswith ( "on_" ) ) continue ;
var signal = k . fromfirst ( "on_" ) ;
Event . observe ( signal , obj , obj [ k ] ) ;
} ;
2023-10-04 17:57:37 -05:00
obj . components . forEach ( function ( x ) {
if ( typeof x . collide === 'function' )
register _collide ( 1 , x . collide , x , obj . body , x . shape ) ;
} ) ;
} ,
2023-11-29 12:40:13 -06:00
2023-11-15 16:42:39 -06:00
flipx ( ) { return this . scale . x < 0 ; } ,
flipy ( ) { return this . scale . y < 0 ; } ,
mirror ( plane ) {
this . scale = Vector . reflect ( this . scale , plane ) ;
} ,
2023-10-04 17:57:37 -05:00
save : true ,
selectable : true ,
ed _locked : false ,
2023-11-29 12:40:13 -06:00
disable ( ) { this . components . forEach ( function ( x ) { x . disable ( ) ; } ) ; } ,
enable ( ) { this . components . forEach ( function ( x ) { x . enable ( ) ; } ) ; } ,
sync ( ) {
this . components . forEach ( function ( x ) { x . sync ( ) ; } ) ;
this . objects . forEach ( function ( x ) { x . sync ( ) ; } ) ;
} ,
2023-10-04 17:57:37 -05:00
2023-09-19 12:35:12 -05:00
/* Bounding box of the object in world dimensions */
boundingbox ( ) {
var boxes = [ ] ;
2023-12-20 17:20:29 -06:00
boxes . push ( {
t : 0 ,
r : 0 ,
b : 0 ,
l : 0
} ) ;
2023-09-19 12:35:12 -05:00
for ( var key in this . components ) {
if ( 'boundingbox' in this . components [ key ] )
boxes . push ( this . components [ key ] . boundingbox ( ) ) ;
}
2023-09-29 13:16:59 -05:00
for ( var key in this . objects )
boxes . push ( this . objects [ key ] . boundingbox ( ) ) ;
2023-09-19 12:35:12 -05:00
2023-12-20 17:20:29 -06:00
var bb = boxes . shift ( ) ;
2023-09-19 12:35:12 -05:00
2023-12-20 17:20:29 -06:00
boxes . forEach ( function ( x ) { bb = bb _expand ( bb , x ) ; } ) ;
bb = movebb ( bb , this . pos ) ;
2023-09-19 12:35:12 -05:00
return bb ? bb : cwh2bb ( [ 0 , 0 ] , [ 0 , 0 ] ) ;
} ,
2023-12-24 09:14:46 -06:00
/* The unique components of this object. Its diff. */
2023-10-02 17:03:01 -05:00
json _obj ( ) {
2023-10-05 17:30:17 -05:00
var d = ediff ( this , this . _ _proto _ _ ) ;
2023-12-24 09:14:46 -06:00
2023-10-09 18:10:10 -05:00
d ? ? = { } ;
var objects = { } ;
this . _ _proto _ _ . objects ? ? = { } ;
2023-10-10 17:37:58 -05:00
var curobjs = { } ;
for ( var o in this . objects )
curobjs [ o ] = this . objects [ o ] . instance _obj ( ) ;
var odiff = ediff ( curobjs , this . _ _proto _ _ . objects ) ;
if ( odiff )
d . objects = curobjs ;
2023-10-09 18:10:10 -05:00
2023-10-05 08:02:12 -05:00
delete d . pos ;
delete d . angle ;
2023-12-26 15:39:46 -06:00
delete d . scale ;
2023-10-05 08:02:12 -05:00
delete d . velocity ;
delete d . angularvelocity ;
return d ;
2023-09-25 16:34:48 -05:00
} ,
2023-10-26 11:48:02 -05:00
2023-12-24 09:14:46 -06:00
/* The object needed to store an object as an instance of a level */
2023-10-10 17:37:58 -05:00
instance _obj ( ) {
2023-12-24 09:14:46 -06:00
var t = this . transform ( ) ;
var j = this . json _obj ( ) ;
Object . assign ( t , j ) ;
2023-10-10 17:37:58 -05:00
t . ur = this . ur ;
return t ;
} ,
2023-09-26 13:34:02 -05:00
transform ( ) {
var t = { } ;
2023-12-24 09:14:46 -06:00
t . pos = this . pos ;
2023-12-27 17:28:10 -06:00
if ( t . pos . every ( x => x === 0 ) ) delete t . pos ;
2023-12-27 10:34:14 -06:00
t . angle = Math . places ( this . angle , 4 ) ;
2023-12-27 17:28:10 -06:00
if ( t . angle === 0 ) delete t . angle ;
2023-12-24 09:14:46 -06:00
t . scale = this . scale ;
2023-12-24 11:50:01 -06:00
t . scale = t . scale . map ( ( x , i ) => x / this . _ _proto _ _ . scale [ i ] ) ;
2023-12-27 10:34:14 -06:00
t . scale = t . scale . map ( x => Math . places ( x , 3 ) ) ;
2023-12-27 17:28:10 -06:00
if ( t . scale . every ( x => x === 1 ) ) delete t . scale ;
2023-09-26 13:34:02 -05:00
return t ;
} ,
2023-12-24 09:14:46 -06:00
/* Velocity and angular velocity of the object */
2023-10-02 07:58:17 -05:00
phys _obj ( ) {
var phys = { } ;
2023-12-24 09:14:46 -06:00
phys . velocity = this . velocity ;
phys . angularvelocity = this . angularvelocity ;
2023-10-02 07:58:17 -05:00
return phys ;
} ,
2023-09-26 08:37:19 -05:00
dup ( diff ) {
2023-10-04 17:57:37 -05:00
var n = this . level . spawn ( this . _ _proto _ _ ) ;
2023-12-24 09:14:46 -06:00
Object . totalmerge ( n , this . instance _obj ( ) ) ;
2023-09-26 08:37:19 -05:00
return n ;
2023-09-15 22:40:19 -05:00
} ,
2023-10-11 17:22:41 -05:00
2023-11-29 12:40:13 -06:00
kill ( ) {
this . timers . forEach ( t => t ( ) ) ;
2023-12-18 17:12:05 -06:00
this . timers = undefined ;
2023-11-29 12:40:13 -06:00
if ( this . level ) {
this . level . remove _obj ( this ) ;
this . level = undefined ;
}
2023-09-14 17:37:04 -05:00
2023-11-29 12:40:13 -06:00
Player . do _uncontrol ( this ) ;
Register . unregister _obj ( this ) ;
2023-10-30 17:41:32 -05:00
2023-12-18 17:12:05 -06:00
this . _ _proto _ _ . instances . remove ( this ) ;
2023-10-16 09:40:43 -05:00
2023-11-29 12:40:13 -06:00
for ( var key in this . components ) {
Register . unregister _obj ( this . components [ key ] ) ;
this . components [ key ] . kill ( ) ;
2023-12-19 15:34:36 -06:00
this . components [ key ] . gameobject = undefined ;
2023-12-18 17:12:05 -06:00
delete this . components [ key ] ;
2023-11-29 12:40:13 -06:00
}
2023-09-14 17:37:04 -05:00
2023-11-29 12:40:13 -06:00
this . clear ( ) ;
2023-12-18 17:12:05 -06:00
this . objects = undefined ;
2023-12-20 17:20:29 -06:00
Event . rm _obj ( this ) ;
2023-10-17 12:22:06 -05:00
2023-11-29 12:40:13 -06:00
if ( typeof this . stop === 'function' )
this . stop ( ) ;
} ,
2023-09-14 17:37:04 -05:00
2023-12-24 09:14:46 -06:00
up ( ) { return [ 0 , 1 ] . rotate ( this . angle ) ; } ,
down ( ) { return [ 0 , - 1 ] . rotate ( this . angle ) ; } ,
right ( ) { return [ 1 , 0 ] . rotate ( this . angle ) ; } ,
left ( ) { return [ - 1 , 0 ] . rotate ( this . angle ) ; } ,
2023-10-05 08:02:12 -05:00
2023-10-10 17:37:58 -05:00
make ( level , data ) {
2023-10-04 17:57:37 -05:00
var obj = Object . create ( this ) ;
2023-12-24 09:14:46 -06:00
2023-10-17 12:22:06 -05:00
obj . make = undefined ;
2023-12-24 09:14:46 -06:00
Object . mixin ( obj , gameobject _impl ) ;
2023-11-30 10:47:59 -06:00
2023-10-30 17:41:32 -05:00
if ( this . instances )
this . instances . push ( obj ) ;
2023-11-20 15:57:23 -06:00
2023-09-25 16:34:48 -05:00
obj . body = make _gameobject ( ) ;
2023-11-29 12:40:13 -06:00
2023-09-25 16:34:48 -05:00
obj . components = { } ;
2023-09-29 13:16:59 -05:00
obj . objects = { } ;
2023-11-17 15:16:13 -06:00
obj . timers = [ ] ;
2023-12-18 17:12:05 -06:00
2023-10-06 12:38:49 -05:00
obj . _ed = {
selectable : true ,
dirty : false ,
2023-10-26 11:48:02 -05:00
inst : false ,
urdiff : { } ,
2023-10-06 12:38:49 -05:00
} ;
2023-11-29 12:40:13 -06:00
2023-10-05 17:30:17 -05:00
obj . ur = this . toString ( ) ;
2023-12-26 15:39:46 -06:00
obj . level = undefined ;
2023-11-30 10:47:59 -06:00
obj . reparent ( level ) ;
2023-12-18 17:12:05 -06:00
2023-09-20 13:33:11 -05:00
cmd ( 113 , obj . body , obj ) ; // set the internal obj reference to this obj
2023-12-24 09:14:46 -06:00
2023-12-18 17:12:05 -06:00
for ( var [ prop , p ] of Object . entries ( this ) ) {
2023-12-19 15:34:36 -06:00
if ( ! p ) continue ;
2023-12-24 11:50:01 -06:00
if ( component . isComponent ( p ) ) {
2023-10-05 13:33:43 -05:00
obj [ prop ] = p . make ( obj ) ;
2023-12-18 17:12:05 -06:00
obj . components [ prop ] = obj [ prop ] ;
2023-09-20 17:58:18 -05:00
}
2023-10-10 17:37:58 -05:00
} ;
2023-10-18 17:20:23 -05:00
2023-12-18 17:12:05 -06:00
Object . hide ( obj , 'ur' , 'body' , 'components' , 'objects' , '_ed' , 'level' , 'timers' ) ;
2023-10-26 11:48:02 -05:00
if ( this . objects )
2023-10-11 17:22:41 -05:00
obj . make _objs ( this . objects ) ;
2023-10-09 18:10:10 -05:00
2023-10-05 13:33:43 -05:00
Object . dainty _assign ( obj , this ) ;
2023-10-10 17:37:58 -05:00
obj . sync ( ) ;
2023-10-04 17:57:37 -05:00
gameobject . check _registers ( obj ) ;
2023-10-02 17:03:01 -05:00
2023-10-30 17:41:32 -05:00
if ( data )
Object . dainty _assign ( obj , data ) ;
2023-12-24 09:14:46 -06:00
if ( typeof obj . load === 'function' ) obj . load ( ) ;
2023-10-11 17:22:41 -05:00
if ( Game . playing ( ) && typeof obj . start === 'function' ) obj . start ( ) ;
2023-12-18 17:12:05 -06:00
2023-09-08 12:35:06 -05:00
return obj ;
} ,
2023-10-09 18:10:10 -05:00
make _objs ( objs ) {
for ( var prop in objs ) {
2023-10-11 17:22:41 -05:00
var newobj = this . spawn _from _instance ( objs [ prop ] ) ;
2023-10-09 18:10:10 -05:00
if ( ! newobj ) continue ;
this . rename _obj ( newobj . toString ( ) , prop ) ;
}
} ,
2023-10-02 17:03:01 -05:00
rename _obj ( name , newname ) {
if ( ! this . objects [ name ] ) {
Log . warn ( ` No object with name ${ name } . Could not rename to ${ newname } . ` ) ;
return ;
}
2023-10-26 11:48:02 -05:00
if ( name === newname ) {
Object . hide ( this , name ) ;
return ;
}
2023-10-06 12:38:49 -05:00
if ( this . objects [ newname ] )
2023-10-02 17:03:01 -05:00
return ;
this . objects [ newname ] = this . objects [ name ] ;
2023-10-17 12:22:06 -05:00
this [ newname ] = this [ name ] ;
this [ newname ] . toString = function ( ) { return newname ; } ;
2023-10-26 11:48:02 -05:00
Object . hide ( this , newname ) ;
2023-10-02 17:03:01 -05:00
delete this . objects [ name ] ;
2023-10-17 12:22:06 -05:00
delete this [ name ] ;
2023-10-02 17:03:01 -05:00
return this . objects [ newname ] ;
} ,
2023-12-24 09:14:46 -06:00
add _component ( comp , data ) {
data ? ? = undefined ;
2023-11-29 12:40:13 -06:00
if ( typeof comp . make !== 'function' ) return ;
2023-12-24 09:14:46 -06:00
var name = obj _unique _name ( comp . toString ( ) , this ) ;
this [ name ] = comp . make ( this . body ) ;
Object . assign ( this [ name ] , data ) ;
return this [ name ] ;
2023-11-02 17:25:00 -05:00
} ,
2023-09-08 12:35:06 -05:00
register _hit ( fn , obj ) {
2023-12-20 17:20:29 -06:00
obj ? ? = this ;
2023-09-08 12:35:06 -05:00
Signal . obj _begin ( fn , obj , this ) ;
} ,
register _separate ( fn , obj ) {
2023-12-20 17:20:29 -06:00
obj ? ? = this ;
2023-09-08 12:35:06 -05:00
Signal . obj _separate ( fn , obj , this ) ;
} ,
2023-12-27 10:34:14 -06:00
obj _descend ( fn ) {
fn ( this ) ;
for ( var o in this . objects )
this . objects [ o ] . obj _descend ( fn ) ;
} ,
2023-09-08 12:35:06 -05:00
}
2023-12-24 09:14:46 -06:00
Object . mixin ( gameobject , gameobject _impl ) ;
2023-09-08 12:35:06 -05:00
2023-11-29 12:40:13 -06:00
gameobject . body = make _gameobject ( ) ;
cmd ( 113 , gameobject . body , gameobject ) ;
Object . hide ( gameobject , 'timescale' ) ;
gameobject . spawn . doc = ` Spawn an entity of type 'ur' on this entity. Returns the spawned entity. ` ;
2023-09-20 13:33:11 -05:00
2023-10-23 08:08:11 -05:00
gameobject . doc = {
doc : "All objects in the game created through spawning have these attributes." ,
pos : "Position of the object, relative to its level." ,
angle : "Rotation of this object, relative to its level." ,
velocity : "Velocity of the object, relative to world." ,
angularvelocity : "Angular velocity of the object, relative to the world." ,
scale : "Scale of the object, relative to its level." ,
2023-11-15 16:42:39 -06:00
flipx : "Check if the object is flipped on its x axis." ,
flipy : "Check if the object is flipped on its y axis." ,
2023-10-23 08:08:11 -05:00
elasticity : ` When two objects collide, their elasticities are multiplied together. Their velocities are then multiplied by this value to find their resultant velocities. ` ,
friction : ` When one object touches another, friction slows them down. ` ,
2023-11-06 07:05:27 -06:00
gravity : 'True if this object should be affected by gravity.' ,
2023-10-23 08:08:11 -05:00
mass : ` The higher the mass of the object, the less forces will affect it. ` ,
phys : ` Set to 0, 1, or 2, representing static, kinematic, and dynamic. ` ,
worldpos : ` Function returns the world position of the object. ` ,
set _worldpos : ` Function to set the position of the object in world coordinates. ` ,
worldangle : ` Function to get the angle of the entity in the world. ` ,
rotate : ` Function to rotate this object by x degrees. ` ,
2023-12-18 17:12:05 -06:00
move : 'Move an object by x,y,z. If the first parameter is an array, uses up to the first three array values.' ,
2023-10-23 08:08:11 -05:00
pulse : ` Apply an impulse to this body in world coordinates. Impulse is a short force. ` ,
shove : ` Apply a force to this body in world coordinates. Should be used over many frames. ` ,
2023-11-06 07:05:27 -06:00
shove _at : 'Apply a force to this body, at a position relative to itself.' ,
max _velocity : 'The max linear velocity this object can travel.' ,
max _angularvelocity : 'The max angular velocity this object can rotate.' ,
2023-10-23 08:08:11 -05:00
in _air : ` Return true if the object is in the air. ` ,
on _ground : ` Return true if the object is on the ground. ` ,
spawn : ` Create an instance of a supplied ur-type on this object. Optionally provide a data object to modify the created entity. ` ,
hide : ` Make this object invisible. ` ,
show : ` Make this object visible. ` ,
width : ` The total width of the object and all its components. ` ,
height : ` The total height of the object. ` ,
move : ` Move this object the given amount. ` ,
boundingbox : ` The boundingbox of the object. ` ,
dup : ` Make an exact copy of this object. ` ,
transform : ` Return an object representing the transform state of this object. ` ,
kill : ` Remove this object from the world. ` ,
level : "The entity this entity belongs to." ,
2023-11-07 12:45:52 -06:00
delay : 'Run the given function after the given number of seconds has elapsed.' ,
2023-11-17 15:16:13 -06:00
cry : 'Make a sound. Can only make one at a time.' ,
2023-12-24 09:14:46 -06:00
add _component : 'Add a component to the object by name.' ,
2023-10-23 08:08:11 -05:00
} ;
2023-09-12 17:19:46 -05:00
/* Default objects */
var prototypes = { } ;
2023-10-17 12:22:06 -05:00
prototypes . ur _ext = ".jso" ;
2023-09-12 17:19:46 -05:00
prototypes . ur = { } ;
prototypes . save _gameobjects = function ( ) { slurpwrite ( JSON . stringify ( gameobjects , null , 2 ) , "proto.json" ) ; } ;
2023-09-26 13:34:02 -05:00
/* Makes a new ur-type from disk. If the ur doesn't exist, it searches on the disk to create it. */
2023-09-12 17:19:46 -05:00
prototypes . from _file = function ( file )
{
2023-09-26 13:34:02 -05:00
var urpath = file ;
2023-09-26 08:37:19 -05:00
var path = urpath . split ( '.' ) ;
2023-09-26 13:34:02 -05:00
if ( path . length > 1 && ( path . at ( - 1 ) === path . at ( - 2 ) ) ) {
2023-09-27 17:40:04 -05:00
urpath = path . slice ( 0 , - 1 ) . join ( '.' ) ;
return prototypes . get _ur ( urpath ) ;
2023-09-26 13:34:02 -05:00
}
2023-10-04 17:57:37 -05:00
var upperur = gameobject ;
2023-09-26 13:34:02 -05:00
2023-09-26 08:37:19 -05:00
if ( path . length > 1 ) {
2023-11-20 07:49:14 -06:00
var upur = undefined ;
2023-09-26 08:37:19 -05:00
var upperpath = path . slice ( 0 , - 1 ) ;
2023-11-20 07:49:14 -06:00
while ( ! upur && upperpath ) {
upur = prototypes . get _ur ( upperpath . join ( '/' ) ) ;
upperpath = upperpath . slice ( 0 , - 1 ) ;
2023-09-26 13:34:02 -05:00
}
2023-11-20 07:49:14 -06:00
if ( upur ) upperur = upur ;
2023-09-26 08:37:19 -05:00
}
2023-09-12 17:19:46 -05:00
2023-10-10 17:37:58 -05:00
var newur = { } ;
2023-10-04 17:57:37 -05:00
2023-09-26 13:34:02 -05:00
file = file . replaceAll ( '.' , '/' ) ;
2023-09-12 17:19:46 -05:00
2023-10-17 12:22:06 -05:00
var jsfile = prototypes . get _ur _file ( urpath , prototypes . ur _ext ) ;
2023-09-29 08:27:34 -05:00
var jsonfile = prototypes . get _ur _file ( urpath , ".json" ) ;
2023-09-12 17:19:46 -05:00
2023-09-26 13:34:02 -05:00
var script = undefined ;
var json = undefined ;
2023-09-12 17:19:46 -05:00
2023-09-29 08:27:34 -05:00
if ( jsfile ) script = IO . slurp ( jsfile ) ;
2023-10-09 13:03:12 -05:00
try {
if ( jsonfile ) json = JSON . parse ( IO . slurp ( jsonfile ) ) ;
} catch ( e ) {
2023-10-10 17:37:58 -05:00
Log . warn ( ` Unable to create json from ${ jsonfile } ` ) ;
2023-10-09 13:03:12 -05:00
}
2023-09-19 17:37:54 -05:00
2023-09-26 13:34:02 -05:00
if ( ! json && ! script ) {
Log . warn ( ` Could not make ur from ${ file } ` ) ;
return undefined ;
}
if ( script )
compile _env ( script , newur , file ) ;
2023-09-19 17:37:54 -05:00
2023-09-26 13:34:02 -05:00
json ? ? = { } ;
Object . merge ( newur , json ) ;
2023-10-05 13:33:43 -05:00
Object . entries ( newur ) . forEach ( function ( [ k , v ] ) {
if ( Object . isObject ( v ) && Object . isObject ( upperur [ k ] ) )
v . _ _proto _ _ = upperur [ k ] ;
} ) ;
Object . values ( newur ) . forEach ( function ( v ) {
if ( typeof v !== 'object' ) return ;
if ( ! v . comp ) return ;
v . _ _proto _ _ = component [ v . comp ] ;
} ) ;
2023-10-04 17:57:37 -05:00
newur . _ _proto _ _ = upperur ;
newur . instances = [ ] ;
2023-10-05 17:30:17 -05:00
Object . hide ( newur , 'instances' ) ;
2023-10-04 17:57:37 -05:00
2023-09-26 13:34:02 -05:00
prototypes . list . push ( urpath ) ;
2023-09-26 08:37:19 -05:00
newur . toString = function ( ) { return urpath ; } ;
2023-09-26 13:34:02 -05:00
ur [ urpath ] = newur ;
2023-09-20 08:11:14 -05:00
2023-10-18 17:20:23 -05:00
return newur ;
2023-09-12 17:19:46 -05:00
}
prototypes . from _file . doc = "Create a new ur-type from a given script file." ;
prototypes . list = [ ] ;
prototypes . list _ur = function ( )
{
var list = [ ] ;
function list _obj ( obj , prefix )
{
prefix ? ? = "" ;
var list = [ ] ;
for ( var e in obj ) {
list . push ( prefix + e ) ;
list . concat ( list _obj ( obj [ e ] , e + "." ) ) ;
}
return list ;
}
return list _obj ( ur ) ;
}
2023-09-29 08:27:34 -05:00
prototypes . ur2file = function ( urpath )
{
return urpath . replaceAll ( '.' , '/' ) ;
}
2023-09-26 13:34:02 -05:00
prototypes . file2ur = function ( file )
2023-09-26 08:37:19 -05:00
{
2023-09-26 13:34:02 -05:00
file = file . strip _ext ( ) ;
2023-09-26 08:37:19 -05:00
file = file . replaceAll ( '/' , '.' ) ;
2023-09-26 13:34:02 -05:00
return file ;
2023-09-26 08:37:19 -05:00
}
2023-09-26 13:34:02 -05:00
/ * R e t u r n s a n u r , o r m a k e s i t , f o r a n y g i v e n t y p e o f p a t h
could be a file on a disk like ball / big . js
could be an ur path like ball . big
* /
2023-09-12 17:19:46 -05:00
prototypes . get _ur = function ( name )
{
2023-10-03 17:16:38 -05:00
if ( ! name ) {
Log . warn ( ` Can't get ur from an undefined. ` ) ;
return ;
}
2023-09-26 13:34:02 -05:00
var urpath = name ;
if ( urpath . includes ( '/' ) )
urpath = prototypes . file2ur ( name ) ;
if ( ! prototypes . ur [ urpath ] ) {
var ur = prototypes . from _file ( urpath ) ;
if ( ur )
return ur ;
else {
2023-09-26 08:37:19 -05:00
Log . warn ( ` Could not find prototype using name ${ name } . ` ) ;
return undefined ;
}
2023-09-12 17:19:46 -05:00
} else
2023-09-26 13:34:02 -05:00
return prototypes . ur [ urpath ] ;
2023-09-12 17:19:46 -05:00
}
2023-09-29 08:27:34 -05:00
prototypes . get _ur _file = function ( path , ext )
{
var urpath = prototypes . ur2file ( path ) ;
var file = urpath + ext ;
if ( IO . exists ( file ) ) return file ;
file = urpath + "/" + path . split ( '.' ) . at ( - 1 ) + ext ;
if ( IO . exists ( file ) ) return file ;
return undefined ;
}
2023-09-12 17:19:46 -05:00
prototypes . generate _ur = function ( path )
{
2023-10-17 12:22:06 -05:00
var ob = IO . glob ( "**" + prototypes . ur _ext ) ;
2023-09-26 13:34:02 -05:00
ob = ob . concat ( IO . glob ( "**.json" ) ) ;
ob = ob . map ( function ( path ) { return path . set _ext ( "" ) ; } ) ;
ob . forEach ( function ( name ) { prototypes . get _ur ( name ) ; } ) ;
2023-09-12 17:19:46 -05:00
}
var ur = prototypes . ur ;
2023-10-04 17:57:37 -05:00
prototypes . resavi = function ( ur , path )
{
2023-10-05 13:33:43 -05:00
if ( ! ur ) return path ;
if ( path [ 0 ] === '/' ) return path ;
2023-10-04 17:57:37 -05:00
2023-10-05 13:33:43 -05:00
var res = ur . replaceAll ( '.' , '/' ) ;
var dir = path . dir ( ) ;
if ( res . startsWith ( dir ) )
return path . base ( ) ;
return path ;
2023-10-04 17:57:37 -05:00
}
prototypes . resani = function ( ur , path )
{
if ( ! path ) return "" ;
2023-10-05 13:33:43 -05:00
if ( ! ur ) return path ;
if ( path [ 0 ] === '/' ) return path . slice ( 1 ) ;
var res = ur . replaceAll ( '.' , '/' ) ;
var restry = res + "/" + path ;
while ( ! IO . exists ( restry ) ) {
res = res . updir ( ) + "/" ;
if ( res === "/" )
return path ;
restry = res + path ;
}
return restry ;
2023-10-04 17:57:37 -05:00
}
2023-11-17 15:16:13 -06:00
prototypes . ur _dir = function ( ur )
{
var path = ur . replaceAll ( '.' , '/' ) ;
Log . warn ( path ) ;
Log . warn ( IO . exists ( path ) ) ;
Log . warn ( ` ${ path } does not exist; sending ${ path . dir ( ) } ` ) ;
}
prototypes . ur _json = function ( ur )
{
var path = ur . replaceAll ( '.' , '/' ) ;
if ( IO . exists ( path ) )
path = path + "/" + path . name ( ) + ".json" ;
else
path = path + ".json" ;
return path ;
}
prototypes . ur _stem = function ( ur )
{
var path = ur . replaceAll ( '.' , '/' ) ;
if ( IO . exists ( path ) )
return path + "/" + path . name ( ) ;
else
return path ;
}
prototypes . ur _file _exts = [ '.jso' , '.json' ] ;
prototypes . ur _folder = function ( ur )
{
var path = ur . replaceAll ( '.' , '/' ) ;
return IO . exists ( path ) ;
}
prototypes . ur _pullout _folder = function ( ur )
{
if ( ! prototypes . ur _folder ( ur ) ) return ;
var stem = prototypes . ur _stem ( ur ) ;
/ * p r o t o t y p e s . u r _ f i l e _ e x t s . f o r E a c h ( f u n c t i o n ( e ) {
var p = stem + e ;
if ( IO . exists ( p ) )
* /
}
prototypes . ur _pushin _folder = function ( ur )
{
}