2024-03-13 03:51:44 -05:00
function obj _unique _name ( name , obj ) {
2023-12-24 09:14:46 -06:00
name = name . replaceAll ( '.' , '_' ) ;
if ( ! ( name in obj ) ) return name ;
var t = 1 ;
var n = name + t ;
while ( n in obj ) {
t ++ ;
2024-03-13 03:51:44 -05:00
n = name + t ;
2023-12-24 09:14:46 -06:00
}
return n ;
}
var gameobject _impl = {
get pos ( ) {
2024-03-11 15:11:39 -05:00
assert ( this . master , ` Entity ${ this . toString ( ) } has no master. ` ) ;
2024-02-29 13:54:33 -06:00
return this . master . world2this ( this . worldpos ( ) ) ;
2023-12-24 09:14:46 -06:00
} ,
set pos ( x ) {
2024-03-11 15:11:39 -05:00
assert ( this . master , ` Entity ${ this . toString ( ) } has no master. ` ) ;
2024-02-29 13:54:33 -06:00
this . set _worldpos ( this . master . this2world ( x ) ) ;
2023-12-24 09:14:46 -06:00
} ,
get angle ( ) {
2024-03-11 15:11:39 -05:00
assert ( this . master , ` No master set on ${ this . toString ( ) } ` ) ;
2024-02-29 13:54:33 -06:00
return this . worldangle ( ) - this . master . worldangle ( ) ;
2023-12-24 09:14:46 -06:00
} ,
2024-03-13 03:51:44 -05:00
2023-12-24 09:14:46 -06:00
set angle ( x ) {
var diff = x - this . angle ;
this . objects . forEach ( function ( x ) {
x . rotate ( diff ) ;
x . pos = Vector . rotate ( x . pos , diff ) ;
} ) ;
2024-03-13 03:51:44 -05:00
this . sworldangle ( x - this . master . worldangle ( ) ) ;
2023-12-24 09:14:46 -06:00
} ,
get scale ( ) {
2024-03-11 15:11:39 -05:00
assert ( this . master , ` No master set on ${ this . toString ( ) } ` ) ;
2024-03-13 03:51:44 -05:00
var pscale = [ 1 , 1 , 1 ] ;
return this . gscale ( ) . map ( ( x , i ) => x / ( this . master . gscale ( ) [ i ] * pscale [ i ] ) ) ;
2023-12-24 09:14:46 -06:00
} ,
set scale ( x ) {
if ( typeof x === 'number' )
2024-03-13 03:51:44 -05:00
x = [ x , x ] ;
2023-12-24 09:14:46 -06:00
2024-03-13 03:51:44 -05:00
var pct = this . scale . map ( ( s , i ) => x [ i ] / s ) ;
2024-03-05 22:23:38 -06:00
this . grow ( pct ) ;
2024-03-13 03:51:44 -05:00
2023-12-24 09:14:46 -06:00
/* TRANSLATE ALL SUB OBJECTS */
this . objects . forEach ( obj => {
2024-03-05 22:23:38 -06:00
obj . grow ( pct ) ;
2024-03-13 03:51:44 -05:00
obj . pos = obj . pos . map ( ( x , i ) => x * pct [ i ] ) ;
2023-12-24 09:14:46 -06:00
} ) ;
} ,
2023-12-26 15:39:46 -06:00
2024-03-13 03:51:44 -05:00
get draw _layer ( ) { return this . body . drawlayer ; } ,
set draw _layer ( x ) { this . body . drawlayer = x ; } ,
set layer ( x ) { this . body . layer = x ; } ,
get layer ( ) { return this . body . layer ; } ,
set warp _layer ( x ) { this . body . warp _filter = x ; } ,
get warp _layer ( ) { return this . body . warp _filter ; } ,
2023-12-24 09:14:46 -06:00
2024-03-13 03:51:44 -05:00
set mass ( x ) { set _body ( 7 , this . body , x ) ; } ,
2023-12-24 09:14:46 -06:00
get mass ( ) {
2024-02-25 17:31:48 -06:00
if ( ! ( this . phys === physics . dynamic ) )
2024-01-14 10:24:31 -06:00
return undefined ;
2023-12-24 09:14:46 -06:00
return q _body ( 5 , this . body ) ;
} ,
2024-03-13 03:51:44 -05:00
get elasticity ( ) { return this . body . e ; } ,
set elasticity ( x ) { this . body . e = x ; } ,
get friction ( ) { return this . body . f ; } ,
set friction ( x ) { this . body . f = x ; } ,
set timescale ( x ) { this . body . timescale = x ; } ,
get timescale ( ) { return this . body . timescale ; } ,
2023-12-24 09:14:46 -06:00
set phys ( x ) { set _body ( 1 , this . body , x ) ; } ,
2024-03-13 03:51:44 -05:00
get phys ( ) { return q _body ( 0 , this . body ) ; } ,
2023-12-24 09:14:46 -06:00
get velocity ( ) { return q _body ( 3 , this . body ) ; } ,
set velocity ( x ) { set _body ( 9 , this . body , x ) ; } ,
2024-03-13 03:51:44 -05:00
get damping ( ) { return this . body . damping ; } ,
set damping ( x ) { this . body . damping = x } ,
get angularvelocity ( ) { return Math . rad2turn ( q _body ( 4 , this . body ) ) ; } ,
2023-12-24 09:14:46 -06:00
set angularvelocity ( x ) { set _body ( 8 , this . body , Math . turn2rad ( x ) ) ; } ,
2024-03-13 03:51:44 -05:00
get max _velocity ( ) { return this . body . maxvelocity ; } ,
set max _velocity ( x ) { this . body . maxvelocity = x ; } ,
get max _angularvelocity ( ) { return this . body . maxangularvelocity ; } ,
set max _angularvelocity ( x ) { this . body . maxangularvelocity = x ; } ,
2023-12-24 09:14:46 -06:00
get _moi ( ) { return q _body ( 6 , this . body ) ; } ,
set _moi ( x ) {
2024-03-13 03:51:44 -05:00
if ( x <= 0 ) {
2024-02-25 17:31:48 -06:00
console . error ( "Cannot set moment of inertia to 0 or less." ) ;
2023-12-24 09:14:46 -06:00
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 ( ) ;
2024-02-19 20:31:26 -06:00
this . _ed . dirty = ! Object . empty ( this . _ed . urdiff ) ;
2024-03-01 11:45:06 -06:00
return ; // TODO: IMPLEMENT
2024-02-29 13:54:33 -06:00
var lur = ur [ this . master . ur ] ;
2023-12-18 17:12:05 -06:00
if ( ! lur ) return ;
var lur = lur . objects [ this . toString ( ) ] ;
2024-03-13 03:51:44 -05:00
var d = ediff ( this . _ed . urdiff , lur ) ;
2024-02-19 20:31:26 -06:00
if ( ! d || Object . empty ( d ) )
2023-12-18 17:12:05 -06:00
this . _ed . inst = true ;
else
this . _ed . inst = false ;
} ,
2023-12-24 11:50:01 -06:00
_ed : {
selectable : false ,
dirty : false
} ,
2024-03-13 03:51:44 -05:00
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 ;
} ,
2024-02-29 13:54:33 -06:00
urstr ( ) {
2024-03-13 03:51:44 -05:00
if ( this . _ed . dirty ) return "*" + this . ur ;
2024-02-29 13:54:33 -06:00
return this . ur ;
} ,
2024-03-13 03:51:44 -05:00
2023-11-29 12:40:13 -06:00
full _path ( ) {
2024-02-29 13:54:33 -06:00
return this . path _from ( world ) ;
2023-11-29 12:40:13 -06:00
} ,
2023-12-28 17:38:17 -06:00
/* pin this object to the to object */
pin ( to ) {
2024-03-13 03:51:44 -05:00
var p = cmd ( 222 , this . body , to . body ) ;
2023-12-28 17:38:17 -06:00
} ,
2024-01-01 07:44:43 -06:00
slide ( to , a , b , min , max ) {
2024-03-13 03:51:44 -05:00
a ? ? = [ 0 , 0 ] ;
b ? ? = [ 0 , 0 ] ;
2024-01-01 07:44:43 -06:00
min ? ? = 0 ;
max ? ? = 50 ;
2024-03-13 03:51:44 -05:00
var p = cmd ( 229 , this . body , to . body , a , b , min , max ) ;
2024-01-14 10:24:31 -06:00
p . max _force = 500 ;
p . break ( ) ;
2024-01-01 07:44:43 -06:00
} ,
2023-12-28 17:38:17 -06:00
pivot ( to , piv ) {
piv ? ? = this . worldpos ( ) ;
2024-03-13 03:51:44 -05:00
var p = cmd ( 221 , this . body , to . body , piv ) ;
2023-12-28 17:38:17 -06:00
} ,
2024-01-01 07:44:43 -06:00
/* groove is on to, from local points a and b, anchored to this at local anchor */
groove ( to , a , b , anchor ) {
2024-03-13 03:51:44 -05:00
anchor ? ? = [ 0 , 0 ] ;
2024-01-01 07:44:43 -06:00
var p = cmd ( 228 , to . body , this . body , a , b , anchor ) ;
} ,
damped _spring ( to , length , stiffness , damping ) {
length ? ? = Vector . length ( this . worldpos ( ) , to . worldpos ( ) ) ;
stiffness ? ? = 1 ;
damping ? ? = 1 ;
2024-03-13 03:51:44 -05:00
var dc = 2 * Math . sqrt ( stiffness * this . mass ) ;
var p = cmd ( 227 , this . body , to . body , [ 0 , 0 ] , [ 0 , 0 ] , stiffness , damping * dc ) ;
2024-01-01 07:44:43 -06:00
} ,
damped _rotary _spring ( to , angle , stiffness , damping ) {
angle ? ? = 0 ;
stiffness ? ? = 1 ;
damping ? ? = 1 ;
/* calculate actual damping value from the damping ratio */
/* damping = 1 is critical */
2024-03-13 03:51:44 -05:00
var dc = 2 * Math . sqrt ( stiffness * this . get _moi ( ) ) ; /* critical damping number */
2024-01-01 07:44:43 -06:00
/* zeta = actual/critical */
2024-03-13 03:51:44 -05:00
var p = cmd ( 226 , this . body , to . body , angle , stiffness , damping * dc ) ;
2024-01-01 07:44:43 -06:00
} ,
rotary _limit ( to , min , max ) {
2024-03-13 03:51:44 -05:00
var p = cmd ( 225 , this . body , to . body , Math . turn2rad ( min ) , Math . turn2rad ( max ) ) ;
2024-01-01 07:44:43 -06:00
} ,
2024-03-13 03:51:44 -05:00
ratchet ( to , ratch ) {
2024-01-01 07:44:43 -06:00
var phase = this . angle - to . angle ;
var p = cmd ( 230 , this . body , to . body , phase , Math . turn2rad ( ratch ) ) ;
} ,
gear ( to , ratio ) {
2023-12-28 17:38:17 -06:00
phase ? ? = 1 ;
ratio ? ? = 1 ;
2024-01-01 07:44:43 -06:00
var phase = this . angle - to . angle ;
2024-03-13 03:51:44 -05:00
var p = cmd ( 223 , this . body , to . body , phase , ratio ) ;
2023-12-28 17:38:17 -06:00
} ,
2024-01-01 07:44:43 -06:00
motor ( to , rate ) {
var p = cmd ( 231 , this . body , to . body , rate ) ;
} ,
2024-03-13 03:51:44 -05:00
path _from ( o ) {
var p = this . toString ( ) ;
var c = this . master ;
while ( c && c !== o && c !== world ) {
p = c . toString ( ) + "." + p ;
c = c . master ;
}
if ( c === world ) p = "world." + p ;
return p ;
} ,
clear ( ) {
for ( var k in this . objects ) {
this . objects [ k ] . kill ( ) ;
} ;
this . objects = { } ;
} ,
delay ( fn , seconds ) {
2024-03-15 10:51:04 -05:00
var timescale = this . timescale ;
var timers = this . timers ;
var thisfn = fn . bind ( this ) ;
var rm _register ;
var ud = function ( dt ) {
seconds -= dt * timescale ;
if ( seconds <= 0 ) {
thisfn ( ) ;
rm _register ( ) ;
rm _register = undefined ;
thisfn = undefined ;
}
}
rm _register = Register . update . register ( ud ) ;
return rm _register ;
2024-03-13 03:51:44 -05: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 ) {
return ;
this . crying = audio . sound . play ( file , audio . sound . bus . sfx ) ;
var killfn = ( ) => { this . crying = undefined ;
console . warn ( "killed" ) ; }
this . crying . hook = killfn ;
return killfn ;
} ,
set torque ( x ) { if ( ! ( x >= 0 && x <= Infinity ) ) return ;
cmd ( 153 , this . body , x ) ; } ,
gscale ( ) { return cmd ( 103 , this . body ) ; } ,
sgscale ( x ) {
if ( typeof x === 'number' )
x = [ x , x ] ;
cmd ( 36 , this . body , x )
} ,
phys _material ( ) {
var mat = { } ;
mat . elasticity = this . elasticity ;
mat . friction = this . friction ;
return mat ;
} ,
worldpos ( ) { return q _body ( 1 , this . body ) ; } ,
set _worldpos ( x ) {
var poses = this . objects . map ( x => x . pos ) ;
set _body ( 2 , this . body , x ) ;
this . objects . forEach ( ( o , i ) => o . set _worldpos ( this . this2world ( poses [ i ] ) ) ) ;
} ,
screenpos ( ) { return Window . world2screen ( this . worldpos ( ) ) ; } ,
worldangle ( ) { return Math . rad2turn ( q _body ( 2 , this . body ) ) ; } ,
sworldangle ( x ) { set _body ( 0 , this . body , Math . turn2rad ( x ) ) ; } ,
get _ur ( ) {
// if (this.ur === 'empty') return undefined;
return Object . access ( ur , this . ur ) ;
} ,
/ * s p a w n a n e n t i t y
2024-02-29 13:54:33 -06:00
text can be :
2024-03-13 03:51:44 -05:00
the file path of a script
an ur object
nothing
2024-02-29 13:54:33 -06:00
* /
2024-03-13 03:51:44 -05:00
spawn ( text ) {
var ent = Object . create ( gameobject ) ;
if ( typeof text === 'object' )
text = text . name ;
if ( typeof text === 'undefined' )
ent . ur = "empty" ;
else if ( typeof text !== 'string' ) {
console . error ( ` Must pass in an ur type or a string to make an entity. ` ) ;
return ;
} else {
if ( Object . access ( ur , text ) )
ent . ur = text ;
else if ( io . exists ( text ) )
ent . ur = "script" ;
else {
console . warn ( ` Cannot make an entity from ' ${ text } '. Not a valid ur. ` ) ;
return ;
}
}
Object . mixin ( ent , gameobject _impl ) ;
ent . body = make _gameobject ( ) ;
ent . warp _layer = [ true ] ;
ent . phys = 2 ;
ent . components = { } ;
ent . objects = { } ;
ent . timers = [ ] ;
ent . reparent ( this ) ;
ent . _ed = {
selectable : true ,
dirty : false ,
inst : false ,
urdiff : { } ,
} ;
cmd ( 113 , ent . body , ent ) ; // set the internal obj reference to this obj
Object . hide ( ent , 'ur' , 'body' , 'components' , 'objects' , '_ed' , 'timers' , 'master' ) ;
if ( ent . ur === 'empty' ) {
if ( ! ur . empty . proto ) ur . empty . proto = json . decode ( json . encode ( ent ) ) ;
return ent ;
}
if ( ent . ur === 'script' )
eval _env ( io . slurp ( text ) , ent , ent . ur ) ;
else
apply _ur ( ent . ur , ent ) ;
for ( var [ prop , p ] of Object . entries ( ent ) ) {
if ( ! p ) continue ;
if ( typeof p !== 'object' ) continue ;
if ( component . isComponent ( p ) ) continue ;
if ( ! p . comp ) continue ;
ent [ prop ] = component [ p . comp ] . make ( ent ) ;
Object . merge ( ent [ prop ] , p ) ;
ent . components [ prop ] = ent [ prop ] ;
} ;
check _registers ( ent ) ;
ent . components . forEach ( function ( x ) {
if ( typeof x . collide === 'function' )
register _collide ( 1 , x . collide . bind ( x ) , ent . body , x . shape ) ;
} ) ;
if ( typeof ent . load === 'function' ) ent . load ( ) ;
if ( Game . playing ( ) )
if ( typeof ent . start === 'function' ) ent . start ( ) ;
var mur = ent . get _ur ( ) ;
if ( mur && ! mur . proto )
mur . proto = json . decode ( json . encode ( ent ) ) ;
ent . sync ( ) ;
if ( ! Object . empty ( ent . objects ) ) {
var o = ent . objects ;
delete ent . objects ;
for ( var i in o ) {
say ( ` MAKING ${ i } ` ) ;
var n = ent . spawn ( ur [ o [ i ] . ur ] ) ;
ent . rename _obj ( n . toString ( ) , i ) ;
delete o [ i ] . ur ;
Object . assign ( n , o [ i ] ) ;
}
}
this . body . phys = this . body . phys ; // simple way to sync
return ent ;
} ,
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 ) {
2024-03-11 15:11:39 -05:00
assert ( parent , ` Tried to reparent ${ this . toString ( ) } to nothing. ` ) ;
2024-02-29 13:54:33 -06:00
if ( this . master === parent ) {
2023-12-26 15:39:46 -06:00
console . warn ( "not reparenting ..." ) ;
2024-02-29 13:54:33 -06:00
console . warn ( ` ${ this . master } 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
2024-02-29 13:54:33 -06:00
this . master ? . remove _obj ( this ) ;
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
this . master = parent ;
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
function unique _name ( list , name ) {
name ? ? = "new_object" ;
var str = name . replaceAll ( '.' , '_' ) ;
2023-10-10 17:37:58 -05:00
var n = 1 ;
var t = str ;
2024-03-01 11:45:06 -06:00
while ( list . indexOf ( t ) !== - 1 ) {
2023-10-10 17:37:58 -05:00
t = str + n ;
2024-03-13 03:51:44 -05:00
n ++ ;
2023-10-10 17:37:58 -05:00
}
return t ;
} ;
2024-03-01 11:45:06 -06:00
2024-02-29 13:54:33 -06:00
var name = unique _name ( Object . keys ( parent . objects ) , this . ur ) ;
2023-10-17 12:22:06 -05:00
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
} ,
2024-03-13 03:51:44 -05:00
remove _obj ( obj ) {
if ( this [ obj . toString ( ) ] === this . objects [ obj . toString ( ) ] )
delete this [ obj . toString ( ) ] ;
delete this . objects [ obj . toString ( ) ] ;
delete this [ obj . toString ( ) ] ;
} ,
2023-11-30 10:47:59 -06:00
2023-10-10 17:37:58 -05:00
components : { } ,
objects : { } ,
2024-02-29 13:54:33 -06:00
master : undefined ,
2024-03-13 03:51:44 -05: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 Window . world2screen ( this . this2world ( pos ) ) ; } ,
screen2this ( pos ) { return this . world2this ( Window . screen2world ( pos ) ) ; } ,
dir _world2this ( dir ) { return cmd ( 160 , this . body , dir ) ; } ,
dir _this2world ( dir ) { return cmd ( 161 , this . body , dir ) ; } ,
alive ( ) { return this . body >= 0 ; } ,
in _air ( ) { return q _body ( 7 , this . body ) ; } ,
hide ( ) { this . components . forEach ( x => x . hide ? . ( ) ) ;
this . objects . forEach ( x => x . hide ? . ( ) ) ; } ,
show ( ) { this . components . forEach ( function ( x ) { x . show ? . ( ) ; } ) ;
this . objects . forEach ( function ( x ) { x . show ? . ( ) ; } ) ; } ,
2023-10-04 17:57:37 -05:00
width ( ) {
var bb = this . boundingbox ( ) ;
return bb . r - bb . l ;
} ,
height ( ) {
var bb = this . boundingbox ( ) ;
2024-03-13 03:51:44 -05:00
return bb . t - bb . b ;
2023-10-04 17:57:37 -05:00
} ,
2023-12-24 11:50:01 -06:00
/* Moving, rotating, scaling functions, world relative */
move ( vec ) { this . set _worldpos ( this . worldpos ( ) . add ( vec ) ) ; } ,
2024-03-13 03:51:44 -05:00
rotate ( x ) { this . sworldangle ( this . worldangle ( ) + x ) ; } ,
grow ( 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 ( ) ;
2024-02-29 13:54:33 -06:00
var lobj = this . master . _ _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
} ,
2024-02-29 13:54:33 -06:00
toString ( ) { return "new_object" ; } ,
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
flipx ( ) { return this . scale . x < 0 ; } ,
flipy ( ) { return this . scale . y < 0 ; } ,
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
mirror ( plane ) {
this . scale = Vector . reflect ( this . scale , plane ) ;
2023-10-04 17:57:37 -05:00
} ,
2024-03-13 03:51:44 -05:00
save : true ,
selectable : true ,
ed _locked : false ,
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 ? . ( ) ; } ) ;
} ,
/* Bounding box of the object in world dimensions */
boundingbox ( ) {
var boxes = [ ] ;
boxes . push ( {
t : 0 ,
r : 0 ,
b : 0 ,
l : 0
} ) ;
for ( var key in this . components ) {
if ( 'boundingbox' in this . components [ key ] )
boxes . push ( this . components [ key ] . boundingbox ( ) ) ;
}
for ( var key in this . objects )
boxes . push ( this . objects [ key ] . boundingbox ( ) ) ;
var bb = boxes . shift ( ) ;
boxes . forEach ( function ( x ) { bb = bbox . expand ( bb , x ) ; } ) ;
bb = bbox . move ( bb , this . pos ) ;
return bb ? bb : bbox . fromcwh ( [ 0 , 0 ] , [ 0 , 0 ] ) ;
} ,
/* The unique components of this object. Its diff. */
json _obj ( ) {
var u = this . get _ur ( ) ;
if ( ! u ) return { } ;
var proto = u . proto ;
var thiso = json . decode ( json . encode ( this ) ) ; // TODO: SLOW. Used to ignore properties in toJSON of components.
var d = ediff ( thiso , proto ) ;
d ? ? = { } ;
var objects = { } ;
proto . objects ? ? = { } ;
var curobjs = { } ;
for ( var o in this . objects )
curobjs [ o ] = this . objects [ o ] . instance _obj ( ) ;
var odiff = ediff ( curobjs , proto . objects ) ;
if ( odiff )
d . objects = curobjs ;
delete d . pos ;
delete d . angle ;
delete d . scale ;
delete d . velocity ;
delete d . angularvelocity ;
return d ;
} ,
/* The object needed to store an object as an instance of a master */
instance _obj ( ) {
var t = this . transform ( ) ;
t . ur = this . ur ;
return t ;
} ,
proto ( ) {
var u = this . get _ur ( ) ;
if ( ! u ) return { } ;
return u . proto ;
} ,
transform ( ) {
var t = { } ;
t . pos = this . pos ;
if ( t . pos . every ( x => x === 0 ) ) delete t . pos ;
t . angle = Math . places ( this . angle , 4 ) ;
if ( t . angle === 0 ) delete t . angle ;
t . scale = this . scale ;
t . scale = t . scale . map ( ( x , i ) => x / this . proto ( ) . scale [ i ] ) ;
t . scale = t . scale . map ( x => Math . places ( x , 3 ) ) ;
if ( t . scale . every ( x => x === 1 ) ) delete t . scale ;
return t ;
} ,
/* Velocity and angular velocity of the object */
phys _obj ( ) {
var phys = { } ;
phys . velocity = this . velocity ;
phys . angularvelocity = this . angularvelocity ;
return phys ;
} ,
dup ( diff ) {
var n = this . master . spawn ( this . _ _proto _ _ ) ;
Object . totalmerge ( n , this . instance _obj ( ) ) ;
return n ;
} ,
2023-10-11 17:22:41 -05:00
2023-11-29 12:40:13 -06:00
kill ( ) {
2023-12-28 12:49:48 -06:00
if ( this . _ _kill ) return ;
this . _ _kill = true ;
2024-03-13 03:51:44 -05:00
2023-11-29 12:40:13 -06:00
this . timers . forEach ( t => t ( ) ) ;
2024-01-03 14:26:42 -06:00
this . timers = [ ] ;
2024-01-03 17:19:13 -06:00
Event . rm _obj ( this ) ;
Player . do _uncontrol ( this ) ;
register _collide ( 2 , undefined , this . body ) ;
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
if ( this . master ) {
this . master . remove _obj ( this ) ;
this . master = undefined ;
2023-11-29 12:40:13 -06:00
}
2024-03-13 03:51:44 -05:00
2023-12-28 17:38:17 -06:00
if ( this . _ _proto _ _ . instances )
2024-02-19 20:31:26 -06:00
delete this . _ _proto _ _ . instances [ this . toString ( ) ] ;
2023-10-16 09:40:43 -05:00
2023-11-29 12:40:13 -06:00
for ( var key in this . components ) {
2024-03-13 03:51:44 -05:00
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 ] ;
2024-03-15 10:51:04 -05:00
delete this [ 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 ;
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
if ( typeof this . stop === 'function' ) this . stop ( ) ;
if ( typeof this . die === 'function' ) this . die ( ) ;
2023-11-29 12:40:13 -06:00
} ,
2023-09-14 17:37:04 -05:00
2024-03-13 03:51:44 -05: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-09 18:10:10 -05:00
make _objs ( objs ) {
for ( var prop in objs ) {
2024-02-29 13:54:33 -06:00
say ( ` spawning ${ json . encode ( objs [ prop ] ) } ` ) ;
var newobj = this . spawn ( objs [ prop ] ) ;
2023-10-09 18:10:10 -05:00
}
} ,
2023-10-02 17:03:01 -05:00
rename _obj ( name , newname ) {
if ( ! this . objects [ name ] ) {
2024-02-25 17:31:48 -06:00
console . warn ( ` No object with name ${ name } . Could not rename to ${ newname } . ` ) ;
2023-10-02 17:03:01 -05:00
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 ] ;
} ,
2024-02-29 13:54:33 -06:00
add _component ( comp , data , name ) {
2023-12-24 09:14:46 -06:00
data ? ? = undefined ;
2023-11-29 12:40:13 -06:00
if ( typeof comp . make !== 'function' ) return ;
2024-02-29 13:54:33 -06:00
name ? ? = comp . toString ( ) ;
name = obj _unique _name ( name , this ) ;
2023-12-28 12:49:48 -06:00
this [ name ] = comp . make ( this ) ;
this [ name ] . comp = comp . toString ( ) ;
this . components [ name ] = this [ name ] ;
if ( data )
Object . assign ( this [ name ] , data ) ;
2023-12-24 09:14:46 -06:00
return this [ name ] ;
2023-11-02 17:25:00 -05:00
} ,
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
}
2024-03-13 03:51:44 -05:00
Object . mixin ( gameobject , gameobject _impl ) ;
2023-09-08 12:35:06 -05:00
2023-11-29 12:40:13 -06:00
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." ,
2024-02-29 13:54:33 -06:00
pos : "Position of the object, relative to its master." ,
angle : "Rotation of this object, relative to its master." ,
2023-10-23 08:08:11 -05:00
velocity : "Velocity of the object, relative to world." ,
angularvelocity : "Angular velocity of the object, relative to the world." ,
2024-02-29 13:54:33 -06:00
scale : "Scale of the object, relative to its master." ,
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. ` ,
mass : ` The higher the mass of the object, the less forces will affect it. ` ,
2024-03-09 18:22:06 -06:00
phys : ` Set to 0, 1, or 2, representing dynamic, kinematic, and static. ` ,
2023-10-23 08:08:11 -05:00
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. ` ,
2024-02-29 13:54:33 -06:00
master : "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.' ,
2024-01-01 07:44:43 -06:00
pin : 'Pin joint to another object. Acts as if a rigid rod is between the two objects.' ,
slide : 'Slide joint, similar to a pin but with min and max allowed distances.' ,
pivot : 'Pivot joint to an object, with the pivot given in world coordinates.' ,
groove : 'Groove joint. The groove is on to, from to local coordinates a and b, with this object anchored at anchor.' ,
damped _spring : 'Damped spring to another object. Length is the distance it wants to be, stiffness is the spring constant, and damping is the damping ratio. 1 is critical, < 1 is underdamped, > 1 is overdamped.' ,
damped _rotary _spring : 'Similar to damped spring but for rotation. Rest angle is the attempted angle.' ,
rotary _limit : 'Limit the angle relative to the to body between min and max.' ,
ratchet : 'Like a socket wrench, relative to to. ratch is the distance between clicks.' ,
gear : 'Keeps the angular velocity ratio of this body and to constant. Ratio is the gear ratio.' ,
2024-03-01 11:45:06 -06:00
motor : 'Keeps the relative angular velocity of this body to to at a constant rate. The most simple idea is for one of the bodies to be static, to the other is kept at rate.' ,
layer : 'Bitmask for collision layers.' ,
draw _layer : 'Layer for drawing. Higher numbers draw above lower ones.' ,
warp _layer : 'Bitmask for selecting what warps should affect this entity.' ,
2023-10-23 08:08:11 -05:00
} ;
2024-03-04 11:15:55 -06:00
global . ur = { } ;
2024-03-02 00:00:35 -06:00
if ( io . exists ( ".prosperon/ur.json" ) )
ur = json . decode ( io . slurp ( ".prosperon/ur.json" ) ) ;
else {
ur = { } ;
ur . _list = [ ] ;
}
2024-02-29 13:54:33 -06:00
/ * U R O B J E C T
ur {
name : fully qualified name of ur
text : file path to the script
data : file path to data
proto : resultant object of a freshly made entity
2023-11-17 15:16:13 -06:00
}
2024-02-29 13:54:33 -06:00
* /
2023-11-17 15:16:13 -06:00
2024-02-29 13:54:33 -06:00
/* Apply an ur u to an entity e */
/* u is given as */
2024-03-13 03:51:44 -05:00
function apply _ur ( u , e ) {
2024-03-14 09:33:15 -05:00
console . info ( ` Applying ur named ${ u } . ` ) ;
2024-02-29 13:54:33 -06:00
if ( typeof u !== 'string' ) {
console . warn ( "Must give u as a string." ) ;
return ;
}
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
var urs = u . split ( '.' ) ;
var config = { } ;
var topur = ur ;
for ( var i = 0 ; i < urs . length ; i ++ ) {
topur = topur [ urs [ i ] ] ;
if ( ! topur ) {
console . warn ( ` Ur given by ${ u } does not exist. Stopped at ${ urs [ i ] } . ` ) ;
return ;
}
2023-11-17 15:16:13 -06:00
2024-03-02 23:34:41 -06:00
if ( topur . text ) {
var script = Resources . replstrs ( topur . text ) ;
eval _env ( script , e , topur . text ) ;
}
2024-03-13 03:51:44 -05:00
2024-03-02 23:34:41 -06:00
if ( topur . data ) {
var jss = Resources . replstrs ( topur . data ) ;
Object . merge ( config , json . decode ( jss ) ) ;
}
2024-02-29 13:54:33 -06:00
}
Object . merge ( e , config ) ;
2023-11-17 15:16:13 -06:00
}
2024-03-13 03:51:44 -05:00
function file2fqn ( file ) {
2024-02-29 13:54:33 -06:00
var fqn = file . strip _ext ( ) ;
if ( fqn . folder _same _name ( ) )
fqn = fqn . up _path ( ) ;
2023-11-17 15:16:13 -06:00
2024-03-13 03:51:44 -05:00
fqn = fqn . replace ( '/' , '.' ) ;
2024-02-29 13:54:33 -06:00
var topur ;
2024-03-13 03:51:44 -05:00
if ( topur = Object . access ( ur , fqn ) ) return topur ;
2023-11-17 15:16:13 -06:00
2024-02-29 13:54:33 -06:00
var fqnlast = fqn . split ( '.' ) . last ( ) ;
2024-03-13 03:51:44 -05:00
if ( topur = Object . access ( ur , fqn . tolast ( '.' ) ) ) {
2024-02-29 13:54:33 -06:00
topur [ fqnlast ] = {
name : fqn
} ;
ur . _list . push ( fqn ) ;
2024-03-13 03:51:44 -05:00
return Object . access ( ur , fqn ) ;
2024-02-29 13:54:33 -06:00
}
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
fqn = fqnlast ;
2024-03-13 03:51:44 -05:00
2024-02-29 13:54:33 -06:00
ur [ fqn ] = {
name : fqn
} ;
ur . _list . push ( fqn ) ;
return ur [ fqn ] ;
2023-11-17 15:16:13 -06:00
}
2024-03-04 11:15:55 -06:00
Game . loadurs = function ( ) {
ur = { } ;
ur . _list = [ ] ;
/* FIND ALL URS IN A PROJECT */
for ( var file of io . glob ( "**.jso" ) ) {
if ( file [ 0 ] === '.' || file [ 0 ] === '_' ) continue ;
var topur = file2fqn ( file ) ;
topur . text = file ;
}
2024-02-27 10:09:15 -06:00
2024-03-04 11:15:55 -06:00
for ( var file of io . glob ( "**.json" ) ) {
if ( file [ 0 ] === '.' || file [ 0 ] === '_' ) continue ;
var topur = file2fqn ( file ) ;
topur . data = file ;
}
2024-03-02 00:00:35 -06:00
2024-03-04 11:15:55 -06:00
ur . empty = {
name : "empty"
} ;
2024-03-01 11:45:06 -06:00
} ;
2024-02-27 10:09:15 -06:00
return {
2024-03-04 11:15:55 -06:00
gameobject
2024-03-13 03:51:44 -05:00
}