Last active
July 4, 2018 19:19
-
-
Save AndreiRudenko/87787bbaf60d6d3ce787ea53dd841ba9 to your computer and use it in GitHub Desktop.
Source code for my OMGJAM 4 entiry
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // author: Andrei Rudenko (https://github.com/RudenkoArts) | |
| // desc: omgjam4 | |
| // script: wren | |
| // you can use this code in TIC-80 0.70 version (current git version) | |
| // TIC-80 starting with 0.70 support wren language | |
| // https://github.com/nesbox/TIC-80 | |
| import "random" for Random | |
| // utils | |
| class DynamicPool { | |
| construct new(size, create_cb) { | |
| _items = [] | |
| _cf = create_cb | |
| _sz = size | |
| for (i in 0...size) { | |
| _items.add(_cf.call()) | |
| } | |
| } | |
| get() { _items.count > 0 ? _items.removeAt(-1) : _cf.call() } | |
| put(item) { | |
| if(_items.count < _sz) { | |
| _items.add(item) | |
| } | |
| } | |
| } | |
| class Timer { | |
| static time(){ 0} | |
| static init(){ | |
| __timers = [] | |
| } | |
| static add(t){ | |
| __timers.add(t) | |
| return t | |
| } | |
| static remove(t){ | |
| var ot = null | |
| for (i in 0...__timers.count) { | |
| if (ot == __timers[i]) { | |
| __timers.removeAt(i) | |
| break | |
| } | |
| } | |
| } | |
| static schedule(tl){ schedule_from(0, tl, null) } | |
| static schedule(tl, cb){ schedule_from(0, tl, cb) } | |
| static schedule_from(ct, tl){ schedule_from(ct, tl, null) } | |
| static schedule_from(ct, tl, cb){ | |
| var t = Timer.new() | |
| t.start_from(ct, tl, cb) | |
| return t | |
| } | |
| static update(dt){ | |
| for (t in __timers) { | |
| if (t.active && !t.finished && t.time_limit >= 0){ | |
| t.update(dt) | |
| } | |
| } | |
| } | |
| time_limit { _time_limit } | |
| time_limit=(v) { _time_limit = v } | |
| loops { _loops } | |
| loops=(v) { _loops = v } | |
| active { _active } | |
| active=(v) { _active = v } | |
| elapsed_time { _time } | |
| elapsed_time=(v) { _time = v } | |
| use_timescale { _use_ts } | |
| use_timescale=(v) { _use_ts = v } | |
| finished { _finished } | |
| elapsed_loops { _loops_counter } | |
| time_left { _time_limit - _time } | |
| loops_left { _loops - _loops_counter } | |
| progress { (_time_limit > 0) ? (_time / _time_limit) : 0 } | |
| construct new(){ | |
| _time = 0 | |
| _time_limit = 0 | |
| _start_time = 0 | |
| _loops = 0 | |
| _loops_counter = 0 | |
| _inarray = false | |
| _active = true | |
| _use_ts = true | |
| _finished = false | |
| } | |
| start(tl) { start_from(0, tl, null) } | |
| start(tl, cb) { start_from(0, tl, cb) } | |
| start_from(st, tl) { start_from(st, tl, null) } | |
| start_from(st, tl, cb) { | |
| stop(false) | |
| if (!_inarray) { | |
| Timer.add(this) | |
| _inarray = true | |
| } | |
| _active = true | |
| _finished = false | |
| if(cb != null){ | |
| _oncomplete = cb | |
| } | |
| _time_limit = tl.abs | |
| _start_time = (_time_limit..st).min | |
| _time = _start_time | |
| _loops = 1 | |
| _loops_counter = 0 | |
| return this | |
| } | |
| stop() { stop(true) } | |
| stop(finish) { | |
| if(!_finished) { | |
| _finished = true | |
| _active = false | |
| if (_inarray){ | |
| Timer.remove(this) | |
| _inarray = false | |
| } | |
| if (finish && _oncomplete != null) { | |
| _oncomplete.call() | |
| } | |
| } | |
| } | |
| oncomplete(cb){ | |
| _oncomplete = cb | |
| return this | |
| } | |
| update(dt){ | |
| if (_use_ts) dt = dt * Game.timescale | |
| _time = _time + dt | |
| while (!_finished && _time_limit < _time) { | |
| _loops_counter = _loops_counter + 1 | |
| if (_loops > 0 && (_loops_counter >= _loops)) { | |
| stop() | |
| break | |
| } | |
| _time = _time - _time_limit | |
| } | |
| } | |
| } | |
| class Vector { | |
| construct new() { | |
| _x = 0 | |
| _y = 0 | |
| } | |
| construct new(x,y) { | |
| _x = x | |
| _y = y | |
| } | |
| x=(v) { _x = v } | |
| y=(v) { _y = v } | |
| length=(v) { normalize().multiply(v) } | |
| x { _x } | |
| y { _y } | |
| length { ( x * x + y * y ).sqrt } | |
| lengthsq { x * x + y * y } | |
| copy(o) { | |
| _x = o.x | |
| _y = o.y | |
| return this | |
| } | |
| set(x, y) { | |
| _x = x | |
| _y = y | |
| return this | |
| } | |
| normalize() { divide( length ) } | |
| dot(o) { x * o.x + y * o.y } | |
| add(o) { | |
| if (o is Num) { | |
| _x = _x + o | |
| _y = _y + o | |
| } else{ | |
| _x = _x + o.x | |
| _y = _y + o.y | |
| } | |
| return this | |
| } | |
| add(x, y) { | |
| _x = _x + x | |
| _y = _y + y | |
| return this | |
| } | |
| subtract(o) { | |
| if (o is Num) { | |
| _x = _x - o | |
| _y = _y - o | |
| } else{ | |
| _x = _x - o.x | |
| _y = _y - o.y | |
| } | |
| return this | |
| } | |
| subtract(x, y) { | |
| _x = _x - x | |
| _y = _y - y | |
| return this | |
| } | |
| multiply(o) { | |
| if (o is Num) { | |
| _x = _x * o | |
| _y = _y * o | |
| } else{ | |
| _x = _x * o.x | |
| _y = _y * o.y | |
| } | |
| return this | |
| } | |
| multiply(x, y) { | |
| _x = _x * x | |
| _y = _y * y | |
| return this | |
| } | |
| divide(o) { | |
| if (o is Num) { | |
| _x = _x / o | |
| _y = _y / o | |
| } else{ | |
| _x = _x / o.x | |
| _y = _y / o.y | |
| } | |
| return this | |
| } | |
| divide(x, y) { | |
| _x = _x / x | |
| _y = _y / y | |
| return this | |
| } | |
| toString { "{ x:%(x), y:%(y) }" } | |
| } | |
| class Utils { | |
| static list_remove(l,v){ | |
| for (i in 0...l.count) { | |
| if (l[i] == v) { | |
| l.removeAt(i) | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| static elegant_pair(x, y) { | |
| var z = (x >= y) ? (x * x + x + y) : (y * y + x) | |
| if(z < 0) { | |
| Fiber.abort("pairing error") | |
| } | |
| return z | |
| } | |
| static random_point_in_unit_circle(into) { | |
| var r = Game.random.float().sqrt | |
| var t = (-1 + (2 * Game.random.float())) * 6.283185307179586 // two PI | |
| into.x = r * t.cos | |
| into.y = r * t.sin | |
| return into | |
| } | |
| static rotate(cx,cy,angle,p) { | |
| var rad = angle*Num.pi/180 | |
| var s = rad.sin | |
| var c = rad.cos | |
| p.x = p.x - cx | |
| p.y = p.y - cy | |
| var xnew = p.x * c - p.y * s | |
| var ynew = p.x * s + p.y * c | |
| p.x = xnew + cx | |
| p.y = ynew + cy | |
| return p | |
| } | |
| } | |
| class Maths { | |
| static get_sphere_mass(r,d){ (4/3 * Num.pi * r.pow(3)) * d } | |
| static distance(x1,y1,x2,y2) { | |
| var x = x2-x1 | |
| var y = y2-y1 | |
| return ( x * x + y * y ).sqrt | |
| } | |
| static clamp(value, a, b) { | |
| return ( value < a ) ? a : ( ( value > b ) ? b : value ) | |
| } | |
| static mod(a,b) { | |
| var r = a % b | |
| return r < 0 ? r + b : r | |
| } | |
| static lerp(value, target, t) { | |
| t = Maths.clamp(t, 0, 1) | |
| return (value + t * (target - value)) | |
| } | |
| } | |
| class Pow { | |
| static require(x) { | |
| if(x == 0) return 1 | |
| x = x - 1 | |
| x = x | x >> 1 | |
| x = x | x >> 2 | |
| x = x | x >> 4 | |
| x = x | x >> 8 | |
| x = x | x >> 16 | |
| return x + 1 | |
| } | |
| static to_pow(num) { ((num.log)/(2).log).round } | |
| } | |
| class Space { | |
| x { _x } | |
| y { _y } | |
| w { _w } | |
| h { _h } | |
| objects { _objs } | |
| count { _count } | |
| construct new(x,y,w,h) { | |
| _x = x | |
| _y = y | |
| _w = w | |
| _h = h | |
| _hw = w*0.5 | |
| _hh = h*0.5 | |
| _objs = {} | |
| _count = 0 | |
| } | |
| check(b) { | |
| if (!_objs.containsKey(b.entity)) { | |
| if (Collision.circle_rect_fast(b.x,b.y,b.r,_x,_y,_x+_w,_y+_h)) { | |
| _objs[b.entity] = b | |
| _count = _count + 1 | |
| } | |
| } else if(!Collision.circle_rect_fast(b.x,b.y,b.r,_x,_y,_x+_w,_y+_h)) { | |
| _objs.remove(b.entity) | |
| _count = _count - 1 | |
| } | |
| } | |
| remove(b) { | |
| if (_objs.remove(b.entity) != null) { | |
| _count = _count - 1 | |
| } | |
| } | |
| draw() { | |
| var c = 11 | |
| TIC.print("contacts:%(_count)", 0, 8, 11) | |
| TIC.rectb(x, y, w, h, c) | |
| for (o in _objs.values) { | |
| TIC.circb(o.x, o.y, o.r, 12) | |
| } | |
| } | |
| } | |
| class Collision { | |
| static circle_circle(c1x,c1y,c1r,c2x,c2y,c2r,ci) { | |
| ci.reset() | |
| var dx = c1x-c2x | |
| var dy = c1y-c2y | |
| var r = c1r + c2r | |
| var dist2 = dx*dx+dy*dy | |
| if(dist2 >= r*r) return false | |
| var dist = dist2.sqrt | |
| if(dist < 0.001) return false | |
| var mtd_x = dx * (r - dist) / dist | |
| var mtd_y = dy * (r - dist) / dist | |
| ci.separation = (mtd_x * mtd_x + mtd_y * mtd_y).sqrt | |
| ci.normal.set(mtd_x, mtd_y).divide(ci.separation) | |
| return true | |
| } | |
| static circle_circle_fast(c1x,c1y,c1r,c2x,c2y,c2r) { | |
| var dx = c1x - c2x | |
| var dy = c1y - c2y | |
| var r = c1r + c2r | |
| return (dx * dx + dy * dy) < (r * r) | |
| } | |
| static circle_rect_fast(cx,cy,cr,minx,miny,maxx,maxy) { | |
| var cx_ = cx | |
| var cy_ = cy | |
| if (cx < minx) cx = minx | |
| if (cx > maxx) cx = maxx | |
| if (cy < miny) cy = miny | |
| if (cy > maxy) cy = maxy | |
| var dx = cx_ - cx | |
| var dy = cy_ - cy | |
| return ( dx * dx + dy * dy < cr * cr ) | |
| } | |
| static aabb_aabb_fast(b1x,b1y,b1w,b1h,b2x,b2y,b2w,b2h ){ | |
| if((b1x - b2x).abs > (b1w + b2w)) return false | |
| if((b1y - b2y).abs > (b1h + b2h)) return false | |
| return true | |
| } | |
| static solve_pos(c,p) { | |
| p.x = p.x + c.separation * c.normal.x | |
| p.y = p.y + c.separation * c.normal.y | |
| } | |
| static solve_vel(c,v,r) { | |
| var vn = v.x * c.normal.x + v.y * c.normal.y | |
| if (vn < 0) { | |
| var j = -(1 + r) * vn | |
| v.x = v.x + c.normal.x * j | |
| v.y = v.y + c.normal.y * j | |
| } | |
| } | |
| static get_contacts(b,into) { | |
| var cid = -1 | |
| var c = null | |
| for (oth in Game.space.objects.values) { | |
| if (oth != b) { | |
| if (Collision.circle_circle_fast(b.x,b.y,b.r,oth.x,oth.y,oth.r)) { | |
| cid = Utils.elegant_pair(b.entity,oth.entity) | |
| c = into[cid] | |
| if (c == null) { | |
| c = Game.contacts_pool.get() | |
| c.id = cid | |
| c.entity = b.entity | |
| c.other = oth.entity | |
| into[cid] = c | |
| } else { | |
| c.remove = false | |
| } | |
| } | |
| } | |
| } | |
| // clear contacts | |
| for (c in into.values) { | |
| if (c.remove) { | |
| Game.contacts_pool.put(c) | |
| into.remove(c.id) | |
| c.clear() | |
| } else { | |
| c.remove = true | |
| } | |
| } | |
| } | |
| static get_contacts2(b,into) { | |
| for (oth in Game.space.objects.values) { | |
| if (oth != b) { | |
| var c = Game.contacts_pool.get() | |
| c.entity = b.entity | |
| c.other = oth.entity | |
| into.add(c) | |
| } | |
| } | |
| } | |
| static remove_contacts2(into) { | |
| for (c in into) { | |
| Game.contacts_pool.put(c) | |
| } | |
| into.clear() | |
| } | |
| } | |
| class CollisionInfo { | |
| id { _id } | |
| entity { _entity } | |
| other { _other } | |
| normal { _norm } | |
| separation { _sep } | |
| remove { _rem } | |
| id=(v) { _id=v } | |
| entity=(v) { _entity=v } | |
| other=(v) { _other=v } | |
| normal=(v) { _norm=v } | |
| separation=(v) { _sep=v } | |
| remove=(v) { _rem=v } | |
| construct new() { | |
| _norm = Vector.new() | |
| _id = -1 | |
| _sep = 0 | |
| _rem = false | |
| } | |
| reset() { | |
| _norm.set(0,0) | |
| _sep = 0 | |
| } | |
| clear() { | |
| reset() | |
| _id = -1 | |
| _rem = false | |
| _entity = null | |
| _other = null | |
| } | |
| } | |
| // renderer | |
| class Drawable { | |
| x { _x } | |
| y { _y } | |
| x=(v) { _x = v } | |
| y=(v) { _y = v } | |
| ox { _ox } | |
| oy { _oy } | |
| ox=(v) { _ox = v } | |
| oy=(v) { _oy = v } | |
| visible { _visible } | |
| visible=(v) { _visible = v } | |
| layer { _layer } | |
| layer=(v) { | |
| if (_rl != null) { | |
| _rl.remove(this) | |
| _layer = v | |
| _rl = Game.renderer.add(this) | |
| } else { | |
| _layer = v | |
| } | |
| } | |
| depth { _depth } | |
| depth=(v) { _depth = v } | |
| construct new() { | |
| _visible = true | |
| _layer = 0 | |
| _depth = 0 | |
| _x = 0 | |
| _y = 0 | |
| _ox = 0 | |
| _oy = 0 | |
| _rl = null | |
| } | |
| init() { | |
| _rl = Game.renderer.add(this) | |
| } | |
| draw() {} | |
| destroy() { | |
| if (_rl != null) { | |
| _rl.remove(this) | |
| } | |
| } | |
| } | |
| class RenderLayer { | |
| construct new() { | |
| _objects = [] | |
| } | |
| add(e) { | |
| _objects.add(e) | |
| } | |
| remove(e) { | |
| Utils.list_remove(_objects, e) | |
| } | |
| draw() { | |
| for (e in _objects){ | |
| if (e.visible) { | |
| e.draw() | |
| } | |
| } | |
| } | |
| } | |
| class Renderer { | |
| color { _color } | |
| color=(v) { _color=v } | |
| construct new() { | |
| _color = 0 | |
| _layers_list = [] | |
| _layers = {} | |
| } | |
| create_layer(idx) { | |
| if (_layers.containsKey(idx)) return | |
| var rl = RenderLayer.new() | |
| _layers[idx] = rl | |
| if (_layers_list.count == 0) { | |
| _layers_list.add(idx) | |
| } else { | |
| insert_sorted_key(_layers_list, idx) | |
| } | |
| } | |
| destroy_layer(idx) { | |
| if (_layers.containsKey(idx)) { | |
| _layers.remove(idx) | |
| Utils.list_remove(_layers_list, idx) | |
| } | |
| } | |
| add(e) { | |
| var rl = _layers[e.layer] | |
| if (rl != null) rl.add(e) | |
| return rl | |
| } | |
| remove(e) { | |
| var rl = _layers[e.layer] | |
| if (rl != null) rl.remove(e) | |
| return rl | |
| } | |
| process() { | |
| TIC.cls(_color) | |
| for (lid in _layers_list){ | |
| _layers[lid].draw() | |
| } | |
| } | |
| insert_sorted_key(list, key) { | |
| var result = 0 | |
| var mid = 0 | |
| var min = 0 | |
| var max = list.count - 1 | |
| while (max >= min) { | |
| mid = min + ((max - min) / 2).floor | |
| result = list[mid] - key | |
| if (result > 0) { | |
| max = mid - 1 | |
| } else if(result < 0) { | |
| min = mid + 1 | |
| } else { | |
| return | |
| } | |
| } | |
| list.insert(result > 0 ? mid : mid + 1, key) | |
| } | |
| } | |
| // particles | |
| class ParticleList is Sequence { | |
| length { _len } | |
| capacity { _cp } | |
| construct new(n) { | |
| _idxs = [] | |
| _buff = [] | |
| for (i in 0...n) { | |
| _idxs.add(i) | |
| _buff.add(Particle.new(i)) | |
| } | |
| _cp = n | |
| _len = 0 | |
| _wridx = 0 | |
| } | |
| [i]{_buff[i]} | |
| ensure() { | |
| var p = _buff[_len] | |
| _len = _len+1 | |
| return p | |
| } | |
| wrap() { | |
| var lidx = _len-1 | |
| swap(_wridx, lidx) | |
| _wridx = (_wridx+1)%(_cp-1) | |
| return _buff[lidx] | |
| } | |
| remove(p) { | |
| var idx = _idxs[p.id] | |
| var lidx = _len-1 | |
| if(idx != lidx) swap(idx, lidx) | |
| _len = _len-1 | |
| } | |
| swap(a, b) { | |
| var ia = _buff[a] | |
| var ib = _buff[b] | |
| _idxs[ia.id] = b | |
| _idxs[ib.id] = a | |
| _buff[a] = ib | |
| _buff[b] = ia | |
| } | |
| clear () { | |
| for (i in 0..._cp) { | |
| _idxs[i] = i | |
| _buff[i] = Particle.new(i) | |
| } | |
| _len = 0 | |
| } | |
| iterate(i) { | |
| if (i == null) i = 0 else i = i + 1 | |
| return i >= _len ? null : i | |
| } | |
| iteratorValue(i) { _buff[i] } | |
| toString { | |
| var lst = [] | |
| for (i in 0..._len) { | |
| lst.add(_buff[i].id) | |
| } | |
| return lst.toString | |
| } | |
| } | |
| class Particle { | |
| id { _id } | |
| x { _x } | |
| y { _y } | |
| vx { _vx } | |
| vy { _vy } | |
| w { _w } | |
| h { _h } | |
| color { _clr } | |
| life { _lf } | |
| stlife { _slf } | |
| phase { _ph } | |
| x=(v) { _x=v } | |
| y=(v) { _y=v } | |
| vx=(v) { _vx=v } | |
| vy=(v) { _vy=v } | |
| w=(v) { _w=v } | |
| h=(v) { _h=v } | |
| color=(v) { _clr=v } | |
| life=(v) { _lf=v } | |
| stlife=(v) { _slf=v } | |
| phase=(v) { _ph=v } | |
| construct new(id) { | |
| _id = id | |
| _x = 0 | |
| _y = 0 | |
| _vx = 0 | |
| _vy = 0 | |
| _w = 2 | |
| _h = 2 | |
| _clr = 11 | |
| _lf = 1 | |
| _ph = 0 | |
| _slf = 1 | |
| } | |
| } | |
| class ParticleSystem is Drawable { | |
| active { _active } | |
| active=(v) { _active=v } | |
| emitters { _ems } | |
| construct new() { | |
| super() | |
| _active = true | |
| _ems = [] | |
| } | |
| add(em) { | |
| _ems.add(em) | |
| em.init(this) | |
| return this | |
| } | |
| update(dt) { | |
| if (_active) _ems.each{|e|e.update(dt)} | |
| } | |
| start() { _ems.each{|e|e.start()} } | |
| stop() {stop(false)} | |
| stop(kill) { _ems.each{|e|e.stop(kill)} } | |
| draw() { _ems.each{|e|e.draw()} } | |
| } | |
| class ParticleEmitter { | |
| x { _x } | |
| y { _y } | |
| enabled { _en } | |
| particles { _prts } | |
| modules { _mds } | |
| rendrer { _rend } | |
| system { _ps } | |
| duration { _dr } | |
| duration_max { _drm } | |
| cache_size { _cs } | |
| cache_wrap { _cwr } | |
| rate { _rate } | |
| rate_max { _ratemx } | |
| life { _life } | |
| life_max { _lifemx } | |
| count { _count } | |
| count_max { _countmx } | |
| random { _rnd } | |
| x=(v) { _x=v } | |
| y=(v) { _y=v } | |
| enabled=(v) { _en=v } | |
| duration=(v) { | |
| _dr=v | |
| calc_dur() | |
| } | |
| duration_max=(v) { | |
| _drm=v | |
| calc_dur() | |
| } | |
| cache_wrap=(v) { _cwr=v } | |
| rate=(v) { | |
| _rate=v | |
| _invrt = v>0 ? 1/v : 0 | |
| } | |
| rate_max=(v) { | |
| _ratemx=v | |
| _invrtmx = v>0 ? 1/v : 0 | |
| } | |
| life=(v) { _life=v } | |
| life_max=(v) { _lifemx=v } | |
| count=(v) { _count=v } | |
| count_max=(v) { _countmx=v } | |
| construct new(cs,mds,rend) { | |
| _cs = cs | |
| _en = true | |
| _cwr = false | |
| _x = 0 | |
| _y = 0 | |
| rate = 10 | |
| rate_max = 0 | |
| _life = 1 | |
| _lifemx = 0 | |
| _count = 1 | |
| _countmx = 0 | |
| _dr = -1 | |
| _drm = 0 | |
| _cdr = -1 | |
| _mds = mds | |
| _rend = rend | |
| _prts = ParticleList.new(_cs) | |
| _rnd = Random.new() | |
| _frt = 0 | |
| _invrt = 0 | |
| _invrtmx = 0 | |
| _time = 0 | |
| } | |
| init(ps) { | |
| _ps = ps | |
| for (m in _mds) { | |
| m.setup(this) | |
| m.init() | |
| } | |
| _rend.setup(this) | |
| } | |
| start() {start(null)} | |
| start(d) { | |
| _en = true | |
| _time = 0 | |
| _frt = 0 | |
| if(d == null) { | |
| calc_dur() | |
| } else { | |
| _cdr = d | |
| } | |
| } | |
| stop() {stop(false)} | |
| stop(k) { | |
| _en = false | |
| _time = 0 | |
| _frt = 0 | |
| if(k) unspawn_all() | |
| } | |
| emit() { | |
| var cnt = 0 | |
| if(_countmx > 0) { | |
| cnt = random.int(_count, _countmx) | |
| } else { | |
| cnt = _count | |
| } | |
| cnt = cnt > _cs ? _cs : cnt | |
| for (i in 0...cnt) { | |
| spawn() | |
| } | |
| } | |
| spawn() { | |
| if(_prts.length < _prts.capacity) { | |
| spawn_p_(_prts.ensure()) | |
| } else if(cache_wrap) { | |
| var p = _prts.wrap() | |
| unspawn_p_(p) | |
| spawn_p_(p) | |
| } | |
| } | |
| unspawn(p) { | |
| _prts.remove(p) | |
| unspawn_p_(p) | |
| } | |
| unspawn_all() { | |
| for (p in _prts) { | |
| for (m in _mds) { | |
| m.onunspawn(p) | |
| } | |
| } | |
| _prts.clear() | |
| } | |
| spawn_p_(p) { | |
| for (m in _mds) { | |
| p.stlife = _lifemx > 0 ? random.float(_life, _lifemx) : _life | |
| p.life = 0 | |
| p.phase = 0 | |
| m.onspawn(p) | |
| } | |
| } | |
| unspawn_p_(p) { _mds.each{|m|m.onunspawn(p)} } | |
| update(dt) { | |
| var p = null | |
| var i = 0 | |
| var len = _prts.length | |
| while(i < len) { | |
| p = _prts[i] | |
| p.life = p.life + dt | |
| p.phase = p.life / p.stlife | |
| if(p.life >= p.stlife) { | |
| unspawn(p) | |
| len = _prts.length | |
| } else { | |
| i = i+1 | |
| } | |
| } | |
| if(_en && _rate > 0) { | |
| _frt = _frt + dt | |
| var ir = 0 | |
| while(_frt > 0) { | |
| emit() | |
| ir = _ratemx > 0 ? random.float(_invrt, _invrtmx) : _invrt | |
| if(ir == 0) { | |
| _frt = 0 | |
| break | |
| } | |
| _frt = _frt-ir | |
| } | |
| _time = _time + dt | |
| if(_cdr >= 0 && _time >= _cdr) stop() | |
| } | |
| for (m in _mds) { | |
| m.update(dt) | |
| } | |
| for (p in _prts) { | |
| p.x = p.x+p.vx*dt | |
| p.y = p.y+p.vy*dt | |
| } | |
| } | |
| draw() { | |
| _rend.draw() | |
| } | |
| calc_dur() { | |
| if(_dr >= 0 && _drm > _dr) { | |
| _cdr = random.float(_dr, _drm) | |
| } else { | |
| _cdr = _dr | |
| } | |
| } | |
| random_1_to_1() { random.float() * 2 - 1 } | |
| } | |
| class ParticleModule { | |
| enabled { _enabled } | |
| emitter { _emtr_ } | |
| particles { _prts_ } | |
| construct new() { | |
| _enabled = true | |
| } | |
| init() {} | |
| setup(e) { | |
| _emtr_= e | |
| _prts_= _emtr_.particles | |
| } | |
| ondestroy() {} | |
| onspawn(p) {} | |
| onunspawn(p) {} | |
| update(dt) {} | |
| } | |
| class RadialSpawnModule is ParticleModule { | |
| radius { _r } | |
| radius=(v) { _r=v } | |
| construct new(r) { | |
| super() | |
| _r = r | |
| _rnd_point = Vector.new() | |
| } | |
| onspawn(p) { | |
| Utils.random_point_in_unit_circle(_rnd_point) | |
| p.x = emitter.system.x + emitter.x + _rnd_point.x * _r | |
| p.y = emitter.system.y + emitter.y + _rnd_point.y * _r | |
| } | |
| } | |
| class ColorLifeModule is ParticleModule { | |
| colors { _colors } | |
| colors=(v) { _colors=v } | |
| construct new(cl) { | |
| super() | |
| _colors = cl | |
| } | |
| update(dt) { | |
| var clen = _colors.count | |
| particles.each{|p|p.color = _colors[(p.phase*clen).floor]} | |
| } | |
| } | |
| class ScaleLifeModule is ParticleModule { | |
| construct new(ss,es) { | |
| super() | |
| _ss = ss | |
| _es = es | |
| } | |
| update(dt) { | |
| for (p in particles) { | |
| var s = (1-p.phase)*_ss+p.phase*_es | |
| p.w = s | |
| p.h = s | |
| } | |
| } | |
| } | |
| class VelocityModule is ParticleModule { | |
| construct new(vx,vy) { | |
| super() | |
| _vx = vx | |
| _vy = vy | |
| } | |
| construct new(vx,vy,mvx,mvy) { | |
| super() | |
| _vx = vx | |
| _vy = vy | |
| _mvx = mvx | |
| _mvy = mvy | |
| } | |
| onspawn(p) { | |
| if (_mvx != null) { | |
| p.vx = emitter.random.int(_vx,_mvx) | |
| p.vy = emitter.random.int(_vy,_mvy) | |
| } else { | |
| p.vx = _vx | |
| p.vy = _vy | |
| } | |
| } | |
| } | |
| class VelocityLifeModule is VelocityModule { | |
| construct new(vx,vy,evx,evy) { | |
| super(vx,vy) | |
| _evx = evx | |
| _evy = evy | |
| } | |
| onspawn(p) { | |
| p.vx = _vx | |
| p.vy = _vy | |
| } | |
| update(dt) { | |
| for (p in particles) { | |
| var vx = (1-p.phase)*_vx+p.phase*_evx | |
| var vy = (1-p.phase)*_vy+p.phase*_evy | |
| p.vx = vx | |
| p.vy = vy | |
| } | |
| } | |
| } | |
| class GravityModule is ParticleModule { | |
| x { _x } | |
| y { _y } | |
| x=(v) { _x=v } | |
| y=(v) { _y=v } | |
| construct new(x,y) { | |
| super() | |
| _x = x | |
| _y = y | |
| } | |
| update(dt) { | |
| for (p in particles) { | |
| p.vx = p.vx + _x * dt | |
| p.vy = p.vy + _y * dt | |
| } | |
| } | |
| } | |
| class ParticleRenderer { | |
| emitter { _emtr_ } | |
| particles { _prts_ } | |
| construct new() {} | |
| setup(e) { | |
| _emtr_= e | |
| _prts_= _emtr_.particles | |
| } | |
| } | |
| class CircleDrawModule is ParticleRenderer { | |
| construct new() { super() } | |
| draw() { particles.each{|p|TIC.circ(p.x-Camera.x, p.y-Camera.y, p.w*0.5, p.color)} } | |
| } | |
| class FPS { | |
| static value { __vl } | |
| static init() { | |
| __vl = 0 | |
| __frms = 0 | |
| __lt = 0 | |
| } | |
| static update() { | |
| if (TIC.time() - __lt <= 1000) { | |
| __frms = __frms+1 | |
| } else { | |
| __vl = __frms | |
| __frms = 0 | |
| __lt = TIC.time() | |
| } | |
| } | |
| } | |
| // ecs | |
| class IdBuffer { | |
| used { _used } | |
| construct new(n) { | |
| _cp = n | |
| _used = 0 | |
| _mask = n - 1 | |
| _head = 0 | |
| _tail = 0 | |
| if((_mask & n) != 0) Fiber.abort("capacity %(n) must be power of two") | |
| _buffer = List.filled(n, 0) | |
| for (i in 0...n) { | |
| _buffer[i] = i | |
| } | |
| } | |
| pop() { | |
| if(_used >= _cp) Fiber.abort("Out of entities, max allowed %(_cp)") | |
| _used = _used + 1 | |
| var ppat = _head | |
| _head = ppat + 1 | |
| _head = _head & _mask | |
| return _buffer[ppat] | |
| } | |
| push(v) { | |
| _used = _used - 1 | |
| var plat = _tail | |
| _buffer[plat] = v | |
| plat = plat + 1 | |
| _tail = plat & _mask | |
| } | |
| clear(){ | |
| _head = 0 | |
| _tail = 0 | |
| _buffer = List.filled(_cp, 0) | |
| for (i in 0..._cp) { | |
| _buffer[i] = i | |
| } | |
| } | |
| } | |
| class BitVector { | |
| construct new(count) { | |
| _list = List.filled((count/32).ceil, 0) | |
| _lrs = Fn.new { |x,n|(x >> n) & ~(((0x1 << 32) >> n) << 1) } | |
| } | |
| [i]{ | |
| var adress = _lrs.call(i, 5) | |
| var mask = 0x1 << (i & 0x1F) | |
| return (_list[adress] & mask) != 0 | |
| } | |
| [i]=(v){ | |
| var adress = _lrs.call(i, 5) | |
| var mask = 0x1 << (i & 0x1F) | |
| _list[adress] = v ? _list[adress] | mask : _list[adress] & ~mask | |
| } | |
| clear () { | |
| for (i in 0..._list.count) { | |
| _list[i] = 0 | |
| } | |
| } | |
| } | |
| class IntVector is Sequence { | |
| construct new(n) { | |
| _idxs = List.filled(n, -1) | |
| _buff = List.filled(n, 0) | |
| _len = 0 | |
| } | |
| length { _len } | |
| add(id){ | |
| _buff[_len] = id | |
| _idxs[id] = _len | |
| _len = _len + 1 | |
| } | |
| has(idx){_idxs[idx] != -1} | |
| [i]{_buff[i]} | |
| remove(id){ | |
| var idx = _idxs[id] | |
| var last_idx = _len - 1 | |
| if(idx != last_idx) { | |
| var last_id = _buff[last_idx] | |
| _buff[idx] = last_id | |
| _idxs[last_id] = idx | |
| } | |
| _idxs[id] = -1 | |
| _len = _len - 1 | |
| } | |
| clear () { | |
| _idxs.each {|id| id = -1 } // bug | |
| _len = 0 | |
| } | |
| iterate(i) { | |
| if (i == null) i = 0 else i = i + 1 | |
| return i >= _len ? null : i | |
| } | |
| iteratorValue(i) { _buff[i] } | |
| toString { | |
| var lst = [] | |
| for (i in 0..._len) { | |
| lst.add(_buff[i]) | |
| } | |
| return lst.toString | |
| } | |
| } | |
| class BitFlag { | |
| bits0 { _b0 } | |
| bits1 { _b1 } | |
| construct new() { | |
| _b0 = 0 | |
| _b1 = 0 | |
| } | |
| set_true(b) { | |
| if (b < 33) { | |
| _b0 = _b0 | 1 << (b - 1) | |
| } else if(b < 65) { | |
| _b1 = _b1 | 1 << (b - 33) | |
| } | |
| } | |
| set_false(b) { | |
| if (b < 33) { | |
| _b0 = _b0 & ~(1 << (b - 1 )) | |
| } else if (b < 65) { | |
| _b1 = _b1 & ~(1 << (b - 33)) | |
| } | |
| } | |
| flip() { | |
| _b0 = ~_b0 | |
| _b1 = ~_b1 | |
| } | |
| clear() { | |
| _b0 = 0 | |
| _b1 = 0 | |
| } | |
| contains(f) { | |
| if (_b0 & f.bits0 == f.bits0 && | |
| _b1 & f.bits1 == f.bits1) { | |
| return true | |
| } | |
| return false | |
| } | |
| } | |
| class Signal { | |
| length { _lsn.count } | |
| construct new() { | |
| _lsn = [] | |
| _chk = false | |
| } | |
| add(h){ | |
| if (h is Fn) { | |
| if (!has(h)) { | |
| _lsn.add(h) | |
| } else { | |
| Fiber.abort("Signal: attempted to add the same listener twice") | |
| } | |
| } | |
| } | |
| remove(h){ | |
| for (i in 0..._lsn.count) { | |
| if (_lsn[i] == h) { | |
| _lsn[i] = null | |
| _chk = true | |
| break | |
| } | |
| } | |
| } | |
| has(h){ _lsn.contains(h) } | |
| emit(args){ | |
| var idx = 0 | |
| var count = _lsn.count | |
| var fn = null | |
| while(idx < count) { | |
| fn = _lsn[idx] | |
| if(fn != null) fn.call(args) | |
| idx = idx + 1 | |
| } | |
| if (_chk) { | |
| while(count > 0) { | |
| if(_lsn[count-1] == null) _lsn.removeAt(count-1) | |
| count = count - 1 | |
| } | |
| _chk = false | |
| } | |
| } | |
| clear(){ | |
| _lsn.clear() | |
| _chk = false | |
| } | |
| } | |
| class World { | |
| static current { __cw } | |
| static init(n) { __cw = World.new_(n) } | |
| static empty() { __cw.empty() } | |
| static update(dt) { __cw.update(dt) } | |
| capacity { _capacity } | |
| comp_flags { _comp_flags } | |
| comp_types { _comp_types } | |
| construct new_(n) { | |
| _inited = false | |
| _capacity = n | |
| _eid_pool = IdBuffer.new(n) | |
| _entities = IntVector.new(n) | |
| _alive_mask = BitVector.new(n) | |
| _changed_mask = BitVector.new(n) | |
| _comp_flags = List.filled(n, null) | |
| _comp_types = {} | |
| _comps = [] | |
| _families = {} | |
| _processors = {} | |
| _active_processors = [] | |
| _changed = [] | |
| _destroyed = [] | |
| // private functions | |
| _destroy_entity = Fn.new{|e| | |
| _entities.remove(e) | |
| _eid_pool.push(e) | |
| _comp_flags[e] = null | |
| } | |
| init() // todo | |
| } | |
| init() { | |
| _inited = true | |
| for (p in _processors.values) { | |
| p.init() | |
| } | |
| } | |
| empty() { | |
| for (e in 0..._capacity) { | |
| if (_alive_mask[e]) { | |
| entity_destroy(e) | |
| } | |
| } | |
| upd_() | |
| } | |
| // entity | |
| entity_create() { | |
| var id = _eid_pool.pop() | |
| _alive_mask[id] = true | |
| _entities.add(id) | |
| _comp_flags[id] = BitFlag.new() | |
| return id | |
| } | |
| entity_destroy(e) { | |
| if (!entity_alive(e)) Fiber.abort("entity %(e) destroying repeatedly") | |
| _alive_mask[e] = false | |
| _comps.each {|c| c.remove(e)} | |
| _destroyed.add(e) | |
| } | |
| entity_alive(e) { _alive_mask[e] } | |
| entity_changed(e){ | |
| if (!_changed_mask[e]) { | |
| _changed_mask[e] = true | |
| _changed.add(e) | |
| } | |
| } | |
| // component | |
| component_set(e,comp, ctype){ | |
| if (comp is List) { | |
| for (c in comps) { | |
| ctype = c is Class ? ctype = c : ctype = c.type | |
| _comps[comp_get_type(ctype)].set_(e,c, false) | |
| } | |
| entity_changed(e) | |
| } else { | |
| if (ctype == null) ctype = comp is Class ? ctype = comp : ctype = comp.type | |
| _comps[comp_get_type(ctype)].set_(e,comp,true) | |
| } | |
| } | |
| oncompadded(e, ct, ev) { | |
| _comp_flags[e].set_true(ct + 1) | |
| if (ev) entity_changed(e) | |
| } | |
| oncompremoved(e, ct) { | |
| _comp_flags[e].set_false(ct + 1) | |
| entity_changed(e) | |
| } | |
| comp_get_type(comp_class){ | |
| var ct = -1 | |
| var cname = comp_class.name | |
| if(_comp_types.containsKey(cname)) { | |
| ct = _comp_types[cname] | |
| } else { | |
| ct = _comps.count | |
| if (ct > 64) Fiber.abort("Cant't have more than 64 type of components") | |
| _comp_types[cname] = ct | |
| _comps.add(Components.new(this, ct)) | |
| } | |
| return ct | |
| } | |
| comps_get(comp_class){ _comps[comp_get_type(comp_class)] } | |
| // family | |
| family_create(name, incl, excl) { | |
| if (_families.containsKey(name)) Fiber.abort("Family named: %(name) already exists") | |
| var f = Family.new_(this, name, incl, excl) | |
| _families[f.name] = f | |
| return f | |
| } | |
| family_remove(f){ // does i need this? | |
| _families.remove(f.name) | |
| } | |
| family_get(fname){ _families[fname] } | |
| // processors | |
| processor_add(p, prior, enabled){ | |
| var pc = p.type | |
| p.priority = prior | |
| _processors[pc.name] = p | |
| p.setup_(this) | |
| p.onadded() | |
| if(_inited) p.init() | |
| if(enabled) processor_enable(pc) | |
| return p | |
| } | |
| processor_get(pc){ _processors[pc.name] } | |
| processor_remove(pc){ | |
| var p = _processors[pc.name] | |
| if (p != null) { | |
| if(p.active) processor_disable(pc) | |
| p.onremoved() | |
| p.setup_(null) | |
| _processors.remove(pc.name) | |
| return p | |
| } | |
| return null | |
| } | |
| processor_enable(pc){ | |
| var p = processor_get(pc) | |
| if (p != null && !p.active) { | |
| p.onenabled() | |
| p.active = true | |
| if (_active_processors.isEmpty) { | |
| _active_processors.add(p) | |
| } else { | |
| var added = false | |
| for (i in 0..._active_processors.count) { | |
| if (p.priority <= _active_processors[i].priority) { | |
| _active_processors.insert(i,p) | |
| added = true | |
| break | |
| } | |
| } | |
| if (!added) _active_processors.add(p) | |
| } | |
| } | |
| } | |
| processor_disable(pc){ | |
| var p = processor_get(pc) | |
| if (p != null && p.active) { | |
| p.ondisabled() | |
| p.active = false | |
| for (i in 0..._active_processors.count) { | |
| if (_active_processors[i] == p) { | |
| _active_processors.removeAt(i) | |
| break | |
| } | |
| } | |
| } | |
| } | |
| upd_() { | |
| if (_changed.count > 0) { | |
| _changed.each {|e| | |
| for (f in _families.values) { | |
| f.check(e) | |
| } | |
| } | |
| _changed_mask.clear() | |
| _changed.clear() | |
| } | |
| for (c in _comps) { | |
| c.update() | |
| } | |
| if (_destroyed.count > 0) { | |
| _destroyed.each {|e| _destroy_entity.call(e)} | |
| _destroyed.clear() | |
| } | |
| } | |
| update(dt) { | |
| upd_() | |
| _active_processors.each {|p| p.update(dt)} | |
| upd_() | |
| } | |
| } | |
| class Components { | |
| static get(ccl) { World.current.comps_get(ccl) } | |
| static set(e,comp) { set(e,comp,null) } | |
| static set(e,comp,ctype) { World.current.component_set(e,comp,ctype) } | |
| construct new(world, ctype) { | |
| _world = world | |
| _type = ctype | |
| _comps = List.filled(_world.capacity, null) | |
| _removed_mask = BitVector.new(_world.capacity) | |
| _removed = [] | |
| } | |
| set(e, c){ set_(e, c, true) } | |
| set_(e, c, ev){ | |
| remove(e) | |
| _comps[e] = c | |
| _world.oncompadded(e, _type, ev) | |
| } | |
| get(e){ _comps[e] } | |
| has(e){ _comps[e] != null } | |
| remove(e){ | |
| if (has(e)) { | |
| _world.oncompremoved(e, _type) | |
| if (!_removed_mask[e]) { | |
| _removed_mask[e] = true | |
| _removed.add(e) | |
| } | |
| // _comps[e] = null | |
| } | |
| } | |
| clear(){ | |
| for (i in 0..._comps.length) { | |
| if(_comps[i] != null) { | |
| world.oncompremoved(i, _type) | |
| _comps[i] = null | |
| } | |
| } | |
| } | |
| update() { | |
| if (_removed.count > 0) { | |
| for (e in _removed) { | |
| _comps[e] = null | |
| } | |
| _removed_mask.clear() | |
| _removed.clear() | |
| } | |
| } | |
| toString { | |
| var cname = "" | |
| for (t in _world.comp_types.keys) { | |
| if (_type == _world.comp_types[t]) cname = t | |
| } | |
| var comps = 0 | |
| var arr = [] | |
| for (j in 0..._comps.count) { | |
| if(_comps[j] != null) { | |
| arr.add(j) | |
| comps = comps + 1 | |
| } | |
| } | |
| return "%(cname): ents:%(comps) %(arr)" | |
| } | |
| } | |
| class Family is Sequence { | |
| static create(name, incl) { create(name, incl, null) } | |
| static create(name, incl, excl) { World.current.family_create(name, incl, excl) } | |
| static get(name) { World.current.family_get(name) } | |
| static remove(name) { World.current.family_remove(name) } | |
| name { _name } | |
| onadded { _onadd } | |
| onremoved { _onrem } | |
| construct new_(world, name, incl, excl) { | |
| _world = world | |
| _name = name | |
| _onadd = Signal.new() | |
| _onrem = Signal.new() | |
| _incl = BitFlag.new() | |
| _excl = BitFlag.new() | |
| _excl.flip() | |
| _ents = IntVector.new(_world.capacity) | |
| incl.each {|c| _incl.set_true(_world.comp_get_type(c)+1) } | |
| if (excl != null) excl.each {|c| _incl.set_false(_world.comp_get_type(c)+1) } | |
| // private functions | |
| _match_entity = Fn.new{|e| | |
| var flags = _world.comp_flags[e] | |
| return flags.contains(_incl) && _excl.contains(flags) | |
| } | |
| } | |
| has(e) { _ents.has(e) } | |
| check(e) { | |
| if(!has(e)) { | |
| if(_match_entity.call(e)){ | |
| _ents.add(e) | |
| _onadd.emit(e) | |
| } | |
| } else if(!_match_entity.call(e)) { | |
| _onrem.emit(e) | |
| _ents.remove(e) | |
| } | |
| } | |
| remove(e) { | |
| if(has(e)) { | |
| _onrem.emit(e) | |
| _ents.remove(e) | |
| } | |
| } | |
| iterate(i) { | |
| if (i == null) i = 0 else i = i + 1 | |
| return i >= _ents.length ? null : i | |
| } | |
| iteratorValue(i) { _ents[i] } | |
| toString { "%(_name):%(_ents.toString)" } | |
| } | |
| class Processor { | |
| static add(p) { add(p,null,true) } | |
| static add(p,pr) { add(p,pr,true) } | |
| static add(p,pr,en) { World.current.processor_add(p,pr,en)} | |
| static get(pc) { World.current.processor_get(pc) } | |
| static remove(pc) { World.current.processor_remove(pc) } | |
| active{_active} | |
| active=(v){_active = v} | |
| priority{_priority} | |
| priority=(v){_priority = v} | |
| construct new() { | |
| _priority = 0 | |
| _active = false | |
| } | |
| setup_(w) { _world = w } | |
| init(){} | |
| onadded(){} | |
| onremoved(){} | |
| onenabled(){} | |
| ondisabled(){} | |
| update(dt){} | |
| } | |
| class Entity { | |
| static create() { World.current.entity_create() } | |
| static destroy(e) { World.current.entity_destroy(e) } | |
| static has(e) { World.current.entity_alive(e) } | |
| } | |
| // components | |
| class Bounds { | |
| entity { _e } | |
| x { _x } | |
| y { _y } | |
| r{ _r } | |
| x=(v) { _x=v } | |
| y=(v) { _y=v } | |
| r=(v) { _r=v } | |
| contacts {_cnt} | |
| tag {_tp} | |
| construct new(e,x,y,r,tp) { | |
| _e = e | |
| _x = x | |
| _y = y | |
| _r = r | |
| _tp = tp | |
| _cnt = {} | |
| } | |
| } | |
| class Star { | |
| paralax { _p } | |
| construct new(p) { | |
| _p = p | |
| } | |
| } | |
| class Planet { | |
| density { _d } | |
| radius { _r } | |
| radius=(v) { _r=v } | |
| grav_radius { _gr } | |
| mass { _m } | |
| construct new(r,d) { | |
| _r = r | |
| _gr = r+(d) | |
| _d = d | |
| _m = Maths.get_sphere_mass(r,1) | |
| } | |
| update_mass() { | |
| _m = Maths.get_sphere_mass(_r,1) | |
| } | |
| } | |
| class Comet is Planet { | |
| polarity { _pol } | |
| polarity=(v) { _pol=v } | |
| hitcd { _hcd } | |
| hitcd=(v) { _hcd=v } | |
| sunhit { _sh } | |
| sunhit=(v) { _sh=v } | |
| construct new(r,d) { | |
| super(r,d) | |
| _pol = -1 | |
| _hcd = 0 | |
| _sh = 0 | |
| } | |
| } | |
| class Text { | |
| x { _x } | |
| y { _y } | |
| scale { _sc } | |
| color { _clr } | |
| text { _txt } | |
| x=(v) { _x=v } | |
| y=(v) { _y=v } | |
| scale=(v) { _sc=v } | |
| color=(v) { _clr=v } | |
| text=(v) { _txt=v } | |
| construct new(txt,x,y,clr,sc) { | |
| _txt = txt | |
| _x = x | |
| _y = y | |
| _sc = sc | |
| _clr = clr | |
| } | |
| draw() { | |
| TIC.print(_txt,_x,_y,_clr,false,_sc) | |
| } | |
| } | |
| class Lines is Drawable { | |
| lines { _lns } | |
| lines2 { _lns2 } | |
| color { _c } | |
| color2 { _c2 } | |
| color=(v) { _c=v } | |
| color2=(v) { _c2=v } | |
| construct new(n,c,c2) { | |
| super() | |
| _c = c | |
| _c2 = c2 | |
| _lns = [] | |
| _lns2 = [] | |
| for (i in 0...n) { | |
| _lns.add(Vector.new()) | |
| _lns2.add(Vector.new()) | |
| } | |
| } | |
| draw() { | |
| _lns2.each{|d| TIC.pix(d.x-Camera.x, d.y-Camera.y, color2) } | |
| _lns.each{|d| TIC.pix(d.x-Camera.x, d.y-Camera.y, color) } | |
| } | |
| } | |
| class PlanetImage is Drawable { | |
| radius { _r } | |
| radius2 { _r2 } | |
| color { _c } | |
| color2 { _c2 } | |
| radius2=(v) { _r2=v } | |
| radius=(v) { _r=v } | |
| color=(v) { _c=v } | |
| color2=(v) { _c2=v } | |
| construct new(r,r2,c,c2) { | |
| super() | |
| _r = r | |
| _r2 = r2 | |
| _c = c | |
| _c2 = c2 | |
| layer = 2 | |
| } | |
| draw() { | |
| TIC.circb(x, y, radius2, color2) | |
| TIC.circ(x, y, radius, color) | |
| } | |
| } | |
| class BlackholeImage is Drawable { | |
| radius { _r } | |
| radius2 { _r2 } | |
| color { _c } | |
| color2 { _c2 } | |
| radius2=(v) { _r2=v } | |
| radius=(v) { _r=v } | |
| color=(v) { _c=v } | |
| color2=(v) { _c2=v } | |
| construct new(r,r2,c,c2) { | |
| super() | |
| _r = r | |
| _r2 = r2 | |
| _c = c | |
| _c2 = c2 | |
| layer = 2 | |
| } | |
| draw() { | |
| for (i in radius..radius2) { | |
| if (i%4 == 0) { | |
| TIC.circb(x, y, i, color2) | |
| } | |
| } | |
| TIC.circ(x, y, radius, color) | |
| } | |
| } | |
| class IceImage is Drawable { | |
| radius { _r } | |
| color { _c } | |
| color=(v) { _c=v } | |
| construct new(r,c) { | |
| super() | |
| _r = r | |
| _c = c | |
| layer = 2 | |
| _tvert = [ | |
| Vector.new(-1,-1), | |
| Vector.new(1,-1), | |
| Vector.new(1,1), | |
| Vector.new(-1,1), | |
| ] | |
| _tind = [ | |
| 3,0,1, | |
| 1,2,3 | |
| ] | |
| _tmpvec = Vector.new() | |
| for (v in _tvert) { | |
| Utils.random_point_in_unit_circle(_tmpvec).multiply(0.25) | |
| v.add(_tmpvec) | |
| } | |
| _av = Game.random.int(-60,60) | |
| } | |
| draw() { | |
| for (v in _tvert) { | |
| Utils.rotate(0,0, _av/60, v) | |
| } | |
| var n = 0 | |
| for (i in 0...(_tind.count/3).floor) { | |
| n = i*3 | |
| TIC.tri(_tvert[_tind[n]].x*_r+x, _tvert[_tind[n]].y*_r+y, _tvert[_tind[n+1]].x*_r+x, _tvert[_tind[n+1]].y*_r+y,_tvert[_tind[n+2]].x*_r+x, _tvert[_tind[n+2]].y*_r+y, color) | |
| } | |
| } | |
| } | |
| class Circle is Drawable { | |
| radius { _r } | |
| color { _c } | |
| radius=(v) { _r=v } | |
| color=(v) { _c=v } | |
| construct new(r,c,l) { | |
| super() | |
| _r = r | |
| _c = c | |
| layer = l | |
| } | |
| draw() { | |
| TIC.circ(x-ox, y-oy, radius, color) | |
| } | |
| } | |
| class CometImage is Drawable { | |
| radius { _r } | |
| color { _c } | |
| angvel { _av } | |
| radius=(v) { _r=v } | |
| color=(v) { _c=v } | |
| angvel=(v) { _av=v } | |
| construct new(r,c,l) { | |
| super() | |
| _r = r | |
| _c = c | |
| layer = l | |
| _tvert = [ | |
| Vector.new(-0.7,-0.7), | |
| Vector.new(0,-1), | |
| Vector.new(0.7,-0.7), | |
| Vector.new(1,0), | |
| Vector.new(0.7,0.7), | |
| Vector.new(0,1), | |
| Vector.new(-0.7,0.7), | |
| Vector.new(-1,0) | |
| ] | |
| _tind = [ | |
| 7,0,1, | |
| 1,2,3, | |
| 3,4,5, | |
| 5,6,7, | |
| 5,7,1, | |
| 1,3,5 | |
| ] | |
| _tmpvec = Vector.new() | |
| for (v in _tvert) { | |
| Utils.random_point_in_unit_circle(_tmpvec).multiply(0.25) | |
| v.add(_tmpvec) | |
| } | |
| _av = Game.random.int(-60,60) | |
| } | |
| draw() { | |
| if (_av.abs > 30) { | |
| _av = _av * 0.999 | |
| } | |
| for (v in _tvert) { | |
| Utils.rotate(0,0, _av/60, v) | |
| } | |
| var n = 0 | |
| for (i in 0...(_tind.count/3).floor) { | |
| n = i*3 | |
| TIC.tri(_tvert[_tind[n]].x*_r+x, _tvert[_tind[n]].y*_r+y, _tvert[_tind[n+1]].x*_r+x, _tvert[_tind[n+1]].y*_r+y,_tvert[_tind[n+2]].x*_r+x, _tvert[_tind[n+2]].y*_r+y, color) | |
| } | |
| } | |
| } | |
| class Position is Vector { | |
| construct new(x,y) { | |
| super(x,y) | |
| } | |
| } | |
| class Velocity is Vector { | |
| damping { _damp } | |
| damping=(v) { _damp=v } | |
| construct new(x,y, d) { | |
| super(x,y) | |
| _damp = d | |
| } | |
| } | |
| // processors | |
| class DrawProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _ln_comps = Components.get(Lines) | |
| _draw_comps = Components.get(Drawable) | |
| _star_comps = Components.get(Star) | |
| _pos_comps = Components.get(Position) | |
| _ps_comps = Components.get(ParticleSystem) | |
| _cm_comps = Components.get(Comet) | |
| _comets = Family.get("comets") | |
| _planets = Family.get("planets") | |
| _stars = Family.get("stars") | |
| _particles = Family.get("particles") | |
| _draw_added = Fn.new {|e| | |
| var p = _pos_comps.get(e) | |
| var d = _draw_comps.get(e) | |
| var s = _star_comps.get(e) | |
| if (s != null) { | |
| d.x = (p.x - (Camera.x*s.paralax)).floor | |
| d.y = (p.y - (Camera.y*s.paralax)).floor | |
| } else { | |
| d.x = (p.x - Camera.x).floor | |
| d.y = (p.y - Camera.y).floor | |
| } | |
| d.init() | |
| } | |
| _cm_added = Fn.new {|e| | |
| var p = _pos_comps.get(e) | |
| var d = _draw_comps.get(e) | |
| d.x = (p.x - Camera.x).floor | |
| d.y = (p.y - Camera.y).floor | |
| _ln_comps.get(e).init() | |
| d.init() | |
| } | |
| _cm_removed = Fn.new {|e| | |
| _ln_comps.get(e).destroy() | |
| _draw_comps.get(e).destroy() | |
| } | |
| _ps_added = Fn.new {|e| | |
| var d = _ps_comps.get(e) | |
| d.init() | |
| } | |
| _draw_removed = Fn.new {|e| | |
| _draw_comps.get(e).destroy() | |
| } | |
| _planets.onadded.add(_draw_added) | |
| _planets.onremoved.add(_draw_removed) | |
| _comets.onadded.add(_cm_added) | |
| _comets.onremoved.add(_cm_removed) | |
| _stars.onadded.add(_draw_added) | |
| _stars.onremoved.add(_draw_removed) | |
| _particles.onadded.add(_ps_added) | |
| } | |
| ondisabled() { | |
| _planets.onadded.remove(_draw_added) | |
| _planets.onremoved.remove(_draw_removed) | |
| _comets.onadded.remove(_cm_added) | |
| _comets.onremoved.remove(_cm_removed) | |
| _stars.onadded.remove(_draw_added) | |
| _stars.onremoved.remove(_draw_removed) | |
| _particles.onadded.remove(_ps_added) | |
| } | |
| set_dr_pos(e) { | |
| var p = _pos_comps.get(e) | |
| var d = _draw_comps.get(e) | |
| d.x = (p.x - Camera.x).floor | |
| d.y = (p.y - Camera.y).floor | |
| } | |
| update(dt) { | |
| var d | |
| var p | |
| var s | |
| for (e in _comets) { | |
| set_dr_pos(e) | |
| } | |
| for (e in _planets) { | |
| set_dr_pos(e) | |
| } | |
| for (e in _stars) { | |
| p = _pos_comps.get(e) | |
| d = _draw_comps.get(e) | |
| s = _star_comps.get(e) | |
| d.x = (p.x - (Camera.x*s.paralax)).floor | |
| d.y = (p.y - (Camera.y*s.paralax)).floor | |
| } | |
| } | |
| } | |
| class CometProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _comet_comps = Components.get(Comet) | |
| _ln_comps = Components.get(Lines) | |
| _b_comps = Components.get(Bounds) | |
| _planet_comps = Components.get(Planet) | |
| _dr_comps = Components.get(Drawable) | |
| _pos_comps = Components.get(Position) | |
| _vel_comps = Components.get(Velocity) | |
| _ps_comps = Components.get(ParticleSystem) | |
| _comets = Family.get("comets") | |
| _planets = Family.get("planets") | |
| _nsup = 1024 | |
| _btmp = Bounds.new(0,0,0,0,null) | |
| _vtmp = Vector.new(0,0) | |
| _ptmp = Vector.new(0,0) | |
| _cont = [] | |
| } | |
| ondisabled() { | |
| _planet_comps = null | |
| _comet_comps = null | |
| _pos_comps = null | |
| _vel_comps = null | |
| _planets = null | |
| _comets = null | |
| } | |
| hit(e, burst) { | |
| Camera.shake(6) | |
| var cm = _comet_comps.get(e) | |
| var ps = _ps_comps.get(e) | |
| var dr = _dr_comps.get(e) | |
| var b = _b_comps.get(e) | |
| cm.radius = cm.radius -1 | |
| if (cm.radius <= 0) { | |
| cm.radius = 1 // dead | |
| burst = true | |
| _comet_comps.remove(e) | |
| ps.stop() | |
| TIC.sfx(20,20,-1,1,15) | |
| TIC.sfx(16,20,-1,0,15) | |
| Timer.schedule(1,Fn.new { | |
| Game.fsm.set("gameover") | |
| }) | |
| } else { | |
| TIC.sfx(19,20,-1,1,15) | |
| } | |
| b.r = cm.radius | |
| ps.emitters[0].modules[0].radius = cm.radius | |
| ps.emitters[2].modules[0].radius = cm.radius+2 | |
| dr.radius = cm.radius | |
| dr.angvel = Game.random.int(-360,360) | |
| if (burst) { | |
| ps.emitters[1].emit() | |
| } | |
| Game.remove_score(4) | |
| cm.hitcd = 1 | |
| cm.update_mass() | |
| } | |
| grow(e, burst) { | |
| var cm = _comet_comps.get(e) | |
| var ps = _ps_comps.get(e) | |
| var dr = _dr_comps.get(e) | |
| var b = _b_comps.get(e) | |
| cm.radius = cm.radius + 0.5 | |
| if (cm.radius > 28) { | |
| cm.radius = 28 | |
| } | |
| b.r = cm.radius | |
| ps.emitters[0].modules[0].radius = cm.radius | |
| ps.emitters[2].modules[0].radius = cm.radius+2 | |
| dr.radius = cm.radius | |
| Game.add_score(8) | |
| TIC.sfx(18,30,-1,1,15) | |
| cm.update_mass() | |
| } | |
| update(dt) { | |
| var vel | |
| var pos | |
| var pos_b | |
| var pl | |
| var cm | |
| var dr | |
| var dist | |
| var ps | |
| var b | |
| var ln | |
| var contacts | |
| Game.speed = Maths.lerp(Game.chances[0][8], Game.chances[1][8], Game.prog) * Game.gravity | |
| for (e in _comets) { | |
| cm = _comet_comps.get(e) | |
| pos = _pos_comps.get(e) | |
| vel = _vel_comps.get(e) | |
| ps = _ps_comps.get(e) | |
| b = _b_comps.get(e) | |
| dr = _dr_comps.get(e) | |
| ln = _ln_comps.get(e) | |
| contacts = b.contacts | |
| vel.x = Game.speed | |
| if (TIC.btn(4)) { | |
| cm.polarity = -1 | |
| TIC.sfx(1,24,8,0,2) | |
| } else { | |
| cm.polarity = 1 | |
| } | |
| Collision.get_contacts(b,contacts) | |
| if (cm.hitcd > 0) { | |
| cm.hitcd = cm.hitcd - dt | |
| } else { | |
| cm.hitcd = 0 | |
| } | |
| var grmodule = ps.emitters[2].modules[3] | |
| grmodule.x = 0 | |
| grmodule.y = 0 | |
| ps.emitters[2].enabled = false | |
| var gf = Game.gravity | |
| var at_sun = false | |
| var other = null | |
| var velb = null | |
| for (c in contacts.values) { | |
| velb = _vel_comps.get(c.other) | |
| other = _b_comps.get(c.other) | |
| pl = _planet_comps.get(c.other) | |
| pos_b = _pos_comps.get(c.other) | |
| if (other.tag == "planet" || other.tag == "sun" || other.tag == "blackhole" || other.tag == "ice") { | |
| if (Collision.circle_circle(pos.x,pos.y,cm.radius,pos_b.x,pos_b.y,pl.grav_radius,c)) { | |
| var ima = 1 / cm.mass | |
| var imb = 1 / pl.mass | |
| var ims = ima + imb | |
| var imp_n = c.separation / pl.grav_radius / ims | |
| if (other.tag == "sun") { | |
| ps.emitters[2].enabled = true | |
| grmodule.x = grmodule.x + c.normal.x * imp_n * ima * 1000 * gf | |
| grmodule.y = grmodule.y + c.normal.y * imp_n * ima * 1000 * gf | |
| at_sun = true | |
| } | |
| var sign = pos.y > pos_b.y ? 1 : -1 | |
| if (other.tag == "blackhole") { | |
| vel.y = vel.y - imp_n * ims * sign * Settings.bh_force * gf | |
| if (cm.polarity < 0) { | |
| vel.y = vel.y + imp_n * ims * sign * Settings.bh_revforce * gf | |
| } | |
| TIC.sfx(21,24,16,0,15) | |
| } else if(other.tag == "sun" || other.tag == "planet"){ | |
| var f_ = 1 | |
| if (cm.polarity < 0) f_ = Settings.pl_factor | |
| vel.y = vel.y - imp_n * ima * sign * cm.polarity * f_ * Settings.pl_force * gf | |
| if (other.tag == "sun") TIC.sfx(17,60,16,0,10) | |
| } else if(other.tag == "ice"){ | |
| velb.x = velb.x + c.normal.x * ims * imp_n * Settings.ice_force * gf | |
| velb.y = velb.y + c.normal.y * ims * imp_n * Settings.ice_force * gf | |
| } | |
| if (c.separation > pl.grav_radius - pl.radius){ | |
| if (other.tag == "blackhole") { | |
| cm.radius = cm.radius - (4..cm.radius*0.5).max.floor | |
| if (cm.hitcd == 0) hit(e,true) | |
| } else if (other.tag == "ice") { | |
| grow(e, false) | |
| Entity.destroy(c.other) | |
| } else { | |
| if (pl.radius < cm.radius) { | |
| Game.add_score(pl.radius) | |
| var ps_other = _ps_comps.get(c.other) | |
| ps_other.x = pos_b.x | |
| ps_other.y = pos_b.y | |
| ps_other.emitters[0].emit() | |
| TIC.sfx(22,10,-1,1,15) | |
| _dr_comps.remove(c.other) | |
| _b_comps.remove(c.other) | |
| contacts.remove(c.id) | |
| } else { | |
| c.separation = c.separation - (pl.grav_radius - pl.radius) | |
| Collision.solve_vel(c,vel,Settings.comet_rest) | |
| Collision.solve_pos(c,pos) | |
| if (cm.hitcd == 0) hit(e,true) | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } | |
| if (at_sun) { | |
| cm.sunhit = cm.sunhit - dt | |
| if (cm.sunhit <= 0) { | |
| cm.sunhit = Settings.sun_hittime | |
| hit(e,false) | |
| } | |
| } else { | |
| if (cm.sunhit < Settings.sun_hittime) { | |
| cm.sunhit = cm.sunhit + dt | |
| } else { | |
| cm.sunhit = Settings.sun_hittime | |
| } | |
| } | |
| if (vel.y.abs < 0.1) vel.y = 0 | |
| var lim = Settings.camera_limit | |
| // cam | |
| if (pos.y-Camera.y < cm.radius+lim) { | |
| Camera.y = Camera.y - (cm.radius+lim-pos.y+Camera.y) | |
| } else if (pos.y-Camera.y > Screen.height-cm.radius-lim) { | |
| Camera.y = Camera.y - (Screen.height-cm.radius-lim-pos.y+Camera.y) | |
| } | |
| ps.x = pos.x | |
| ps.y = pos.y | |
| if (cm.polarity > 0) { | |
| dr.color = 11 | |
| } else { | |
| dr.color = 3 | |
| } | |
| ps.emitters[0].modules[2].colors[0] = dr.color | |
| Camera.x = pos.x - Settings.comet_dist | |
| // var cl = System.clock | |
| // trajectory stuff | |
| Collision.get_contacts2(_btmp,_cont) | |
| getnextpos(pos,vel,cm,cm.polarity,ln.lines) | |
| getnextpos(pos,vel,cm,cm.polarity*-1,ln.lines2) | |
| Collision.remove_contacts2(_cont) | |
| // TIC.trace("elapsed: %(System.clock-cl)") | |
| } | |
| } | |
| getnextpos(p,v,cm,pol,into) { | |
| var damp = v.damping | |
| var gf = Game.gravity | |
| _ptmp.set(p.x,p.y) | |
| _vtmp.set(v.x,v.y) | |
| _btmp.x = p.x - Camera.x | |
| _btmp.y = p.y - Camera.y | |
| _btmp.r = cm.radius | |
| var other | |
| var pl | |
| var pos_b | |
| var ni = 0 | |
| var dead = false | |
| for (i in 0...into.count*4) { | |
| _vtmp.y = _vtmp.y * damp | |
| _ptmp.x = _ptmp.x + _vtmp.x * Game.dt | |
| _ptmp.y = _ptmp.y + _vtmp.y * Game.dt | |
| _btmp.x = _ptmp.x - Camera.x | |
| _btmp.y = _ptmp.y - Camera.y | |
| _vtmp.x = Game.speed | |
| if (_vtmp.y.abs < 0.1) _vtmp.y = 0 | |
| for (c in _cont) { | |
| other = _b_comps.get(c.other) | |
| if (other.tag == "planet" || other.tag == "sun" || other.tag == "blackhole") { | |
| pl = _planet_comps.get(c.other) | |
| pos_b = _pos_comps.get(c.other) | |
| if (Collision.circle_circle(_ptmp.x,_ptmp.y,cm.radius,pos_b.x,pos_b.y,pl.grav_radius,c)) { | |
| var ima = 1 / cm.mass | |
| var imb = 1 / pl.mass | |
| var ims = ima + imb | |
| var imp_n = c.separation / pl.grav_radius / ims | |
| var sign = _ptmp.y > pos_b.y ? 1 : -1 | |
| if (other.tag == "blackhole") { | |
| _vtmp.y = _vtmp.y - imp_n * ims * sign * Settings.bh_force * gf | |
| if (pol < 0) { | |
| _vtmp.y = _vtmp.y + imp_n * ims * sign * Settings.bh_revforce * gf | |
| } | |
| } else if(other.tag == "sun" || other.tag == "planet"){ | |
| var f_ = 1 | |
| if (pol < 0) f_ = Settings.pl_factor | |
| _vtmp.y = _vtmp.y - imp_n * ima * sign * pol * f_ * Settings.pl_force * gf | |
| } | |
| } | |
| } | |
| } | |
| if (i%4 == 0) { | |
| into[ni].set(_ptmp.x, _ptmp.y) | |
| ni = ni+1 | |
| } | |
| } | |
| } | |
| } | |
| class PosVelProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _pos_comps = Components.get(Position) | |
| _vel_comps = Components.get(Velocity) | |
| _pos_vel = Family.get("pos_vel") | |
| } | |
| update(dt) { | |
| var p | |
| var v | |
| for (e in _pos_vel) { | |
| p = _pos_comps.get(e) | |
| v = _vel_comps.get(e) | |
| v.x = v.x * v.damping | |
| v.y = v.y * v.damping | |
| p.x = p.x + v.x * dt | |
| p.y = p.y + v.y * dt | |
| } | |
| } | |
| } | |
| class SpawnProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _planet_comps = Components.get(Planet) | |
| _pos_comps = Components.get(Position) | |
| _star_comps = Components.get(Star) | |
| _planets = Family.get("planets") | |
| _stars = Family.get("stars") | |
| _snextdist = 0 | |
| var ch = Game.chances[0] | |
| _pnextdist = Game.random.int(ch[0],ch[1]) | |
| _sunnext = Game.random.int(ch[2],ch[3]) | |
| _dhnext = Game.random.int(ch[4],ch[5]) | |
| _icenext = Game.random.int(ch[6],ch[7]) | |
| _last_star = null | |
| _last_cam = 0 | |
| } | |
| ondisabled() { | |
| _planet_comps = null | |
| _pos_comps = null | |
| _planets = null | |
| } | |
| update(dt) { | |
| var pos | |
| var pl | |
| var s | |
| var ch = Game.chances | |
| var cp = Camera.x | |
| var t = Game.prog | |
| var spp = Camera.x+Screen.width | |
| var rmin = 0 | |
| var rmax = 0 | |
| while (_pnextdist < spp) { | |
| var r = Game.random.int(2,8) | |
| var d = Game.random.int(8*r,16*r) | |
| var gr = r+d | |
| var sy = Game.random.int(Camera.y-Screen.height*1.5,Camera.y+Screen.height+Screen.height*1.5) | |
| var sx = _pnextdist+gr | |
| var e = EntityCreator.planet(sx,sy,r,d) | |
| rmin = Maths.lerp(ch[0][0],ch[1][0],t) | |
| rmax = Maths.lerp(ch[0][1],ch[1][1],t) | |
| _pnextdist = _pnextdist + Game.random.int(rmin,rmax) | |
| } | |
| while (_sunnext < spp) { | |
| var r = Game.random.int(8,24) | |
| var d = Game.random.int(4*r,8*r) | |
| var gr = r+d | |
| var sy = Game.random.int(Camera.y-(Screen.height*1.5),Camera.y+Screen.height+(Screen.height*1.5)) | |
| var sx = _sunnext+gr | |
| var e = EntityCreator.sun(sx,sy,r,d) | |
| rmin = Maths.lerp(ch[0][2],ch[1][2],t) | |
| rmax = Maths.lerp(ch[0][3],ch[1][3],t) | |
| _sunnext = _sunnext + Game.random.int(rmin,rmax) | |
| } | |
| while (_dhnext < spp) { | |
| var r = Game.random.int(1,4) | |
| var d = Game.random.int(16*r,32*r) | |
| var gr = r+d | |
| var sy = Game.random.int(Camera.y-(Screen.height*1.5),Camera.y+Screen.height+(Screen.height*1.5)) | |
| var sx = _dhnext+gr | |
| var e = EntityCreator.blackhole(sx,sy,r,d) | |
| rmin = Maths.lerp(ch[0][4],ch[1][4],t) | |
| rmax = Maths.lerp(ch[0][5],ch[1][5],t) | |
| _dhnext = _dhnext + Game.random.int(rmin,rmax) | |
| } | |
| while (_icenext < spp) { | |
| var sy = Game.random.int(Camera.y-(Screen.height*1.5),Camera.y+Screen.height+(Screen.height*1.5)) | |
| var sx = _icenext+87 | |
| var e = EntityCreator.ice(sx,sy) | |
| rmin = Maths.lerp(ch[0][6],ch[1][6],t) | |
| rmax = Maths.lerp(ch[0][7],ch[1][7],t) | |
| _icenext = _icenext + Game.random.int(rmin,rmax) | |
| } | |
| while (_snextdist < spp) { | |
| var sy = Game.random.int(Camera.y-(Screen.height*0.5),Camera.y+Screen.height+(Screen.height*0.5)) | |
| var sx = _snextdist+4 | |
| var e = EntityCreator.star(0,0) | |
| var s = _star_comps.get(e) | |
| var spos = _pos_comps.get(e) | |
| spos.x = Camera.x*s.paralax+(sx-Camera.x) | |
| spos.y = Camera.y*s.paralax+(sy-Camera.y) | |
| _snextdist = _snextdist + Game.random.int(32,96) | |
| } | |
| for (e in _planets) { | |
| pos = _pos_comps.get(e) | |
| pl = _planet_comps.get(e) | |
| if (pos.x+pl.grav_radius < Camera.x-4) { | |
| Entity.destroy(e) | |
| } | |
| } | |
| for (e in _stars) { | |
| pos = _pos_comps.get(e) | |
| s = _star_comps.get(e) | |
| if (pos.x-Camera.x*s.paralax < -4) { | |
| Entity.destroy(e) | |
| } | |
| } | |
| } | |
| } | |
| class ParticlesProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _ps_comps = Components.get(ParticleSystem) | |
| _particles = Family.get("particles") | |
| _ps_added = Fn.new {|e| | |
| } | |
| _ps_removed = Fn.new {|e| | |
| var ps = _ps_comps.get(e) | |
| ps.stop(true) | |
| } | |
| _particles.onadded.add(_ps_added) | |
| _particles.onremoved.add(_ps_removed) | |
| } | |
| ondisabled() { | |
| _particles.onadded.remove(_ps_added) | |
| _particles.onremoved.remove(_ps_removed) | |
| _particles = null | |
| _ps_comps = null | |
| } | |
| update(dt) { | |
| for (e in _particles) { | |
| _ps_comps.get(e).update(dt) | |
| } | |
| } | |
| } | |
| class BoundsProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _b_comps = Components.get(Bounds) | |
| _p_comps = Components.get(Position) | |
| _bounds = Family.get("bounds") | |
| _b_added = Fn.new {|e| | |
| var b = _b_comps.get(e) | |
| var p = _p_comps.get(e) | |
| b.x = p.x | |
| b.y = p.y | |
| Game.space.check(b) | |
| } | |
| _b_removed = Fn.new {|e| | |
| var b = _b_comps.get(e) | |
| Game.space.remove(b) | |
| } | |
| _bounds.onadded.add(_b_added) | |
| _bounds.onremoved.add(_b_removed) | |
| } | |
| ondisabled() { | |
| _bounds.onadded.remove(_b_added) | |
| _bounds.onremoved.remove(_b_removed) | |
| _b_comps = null | |
| _p_comps = null | |
| _bounds = null | |
| } | |
| update(dt) { | |
| var p | |
| var b | |
| for (e in _bounds) { | |
| b = _b_comps.get(e) | |
| p = _p_comps.get(e) | |
| b.x = p.x - Camera.x | |
| b.y = p.y - Camera.y | |
| Game.space.check(b) | |
| } | |
| } | |
| } | |
| class CameraProcessor is Processor { | |
| construct new() { | |
| super() | |
| } | |
| onenabled() { | |
| _shake_vector = Vector.new() | |
| } | |
| update(dt) { | |
| if (Camera.shaking) { | |
| Utils.random_point_in_unit_circle(_shake_vector) | |
| _shake_vector.multiply(Camera.shake_amount) | |
| Camera.shake_amount = Camera.shake_amount * 0.9 | |
| if (Camera.shake_amount < 0.1) { | |
| Camera.shaking = false | |
| } | |
| Camera.x = Camera.x + _shake_vector.x | |
| Camera.y = Camera.y + _shake_vector.y | |
| } | |
| } | |
| } | |
| class Screen { | |
| static width { 240 } | |
| static height { 136 } | |
| } | |
| class Camera { | |
| static x { __x } | |
| static y { __y } | |
| static shaking { __shaking } | |
| static shake_amount { __shake_amount } | |
| static shake_amount=(v) { __shake_amount=v } | |
| static shaking=(v) { __shaking=v } | |
| static x=(v) { __x=v } | |
| static y=(v) { __y=v } | |
| static init() { | |
| __x = 0 | |
| __y = 0 | |
| __shaking = false | |
| __shake_amount = 0 | |
| } | |
| static shake(v) { | |
| __shaking = true | |
| __shake_amount = v | |
| } | |
| } | |
| // create | |
| class EntityCreator { | |
| static planet(x,y,r,d) { | |
| var e = Entity.create() | |
| var gr = r+d | |
| var c = 7 | |
| var rnd = Game.random.float() | |
| if (rnd < 0.25) { | |
| c = 6 | |
| } else if (rnd < 0.5) { | |
| c = 9 | |
| } else if (rnd < 0.75) { | |
| c = 1 | |
| } else if (rnd < 0.85) { | |
| c = 6 | |
| } | |
| Components.set(e, Planet.new(r,d)) | |
| Components.set(e, Position.new(x,y)) | |
| Components.set(e, Velocity.new(0,0,0.99)) | |
| Components.set(e, PlanetImage.new(r,gr,c,15), Drawable) | |
| Components.set(e, Bounds.new(e,0,0,gr,"planet")) | |
| var ps = ParticleSystem.new() | |
| var em2 = ParticleEmitter.new( | |
| 128, | |
| [ | |
| RadialSpawnModule.new(r), | |
| ScaleLifeModule.new(r/3,1), | |
| ColorLifeModule.new([4,3,2]), | |
| VelocityModule.new(-100,-100,100,100), | |
| ], | |
| CircleDrawModule.new() | |
| ) | |
| em2.count = 128 | |
| em2.life = 0.8 | |
| em2.enabled = false | |
| ps.add(em2) | |
| ps.layer = 3 | |
| Components.set(e, ps) | |
| return e | |
| } | |
| static sun(x,y,r,d) { | |
| var e = Entity.create() | |
| var gr = r+d | |
| Components.set(e, Planet.new(r,d)) | |
| Components.set(e, Position.new(x,y)) | |
| Components.set(e, Velocity.new(0,0,0.99)) | |
| Components.set(e, PlanetImage.new(r,gr,4,4), Drawable) | |
| Components.set(e, Bounds.new(e,0,0,gr,"sun")) | |
| var ps = ParticleSystem.new() | |
| var em2 = ParticleEmitter.new( | |
| 128, | |
| [ | |
| RadialSpawnModule.new(r), | |
| ScaleLifeModule.new(r/3,1), | |
| ColorLifeModule.new([4,3,2]), | |
| VelocityModule.new(-100,-100,100,100), | |
| ], | |
| CircleDrawModule.new() | |
| ) | |
| em2.count = 128 | |
| em2.life = 0.8 | |
| em2.enabled = false | |
| ps.add(em2) | |
| ps.layer = 3 | |
| Components.set(e, ps) | |
| return e | |
| } | |
| static ice(x,y) { | |
| var e = Entity.create() | |
| var r = 2 | |
| var gr = r+48 | |
| var hgs = Game.speed * 0.5 | |
| Components.set(e, Planet.new(r+2,gr)) | |
| Components.set(e, Position.new(x,y)) | |
| Components.set(e, Velocity.new(Game.random.int(-hgs,hgs),Game.random.int(-hgs,hgs),0.99)) | |
| Components.set(e, IceImage.new(r,10), Drawable) | |
| Components.set(e, Bounds.new(e,0,0,gr,"ice")) | |
| return e | |
| } | |
| static blackhole(x,y,r,d) { | |
| var e = Entity.create() | |
| var gr = r+d | |
| Components.set(e, Planet.new(r,d)) | |
| Components.set(e, Position.new(x,y)) | |
| Components.set(e, Velocity.new(0,0,0.99)) | |
| Components.set(e, BlackholeImage.new(r,gr,14,14), Drawable) | |
| Components.set(e, Bounds.new(e,0,0,gr,"blackhole")) | |
| return e | |
| } | |
| static star(x,y) { | |
| var e = Entity.create() | |
| var s = Star.new(Game.random.float(0.05,0.15)) | |
| Components.set(e, s) | |
| Components.set(e, Position.new(x ,y)) | |
| Components.set(e, Circle.new(Game.random.int(0,2),13,1), Drawable) | |
| return e | |
| } | |
| static comet(r) { | |
| var e = Entity.create() | |
| Components.set(e, Comet.new(r,1)) | |
| Components.set(e, Position.new(48,Screen.height/2)) | |
| Components.set(e, Velocity.new(0,0,0.99)) | |
| Components.set(e, CometImage.new(r,15,3), Drawable) | |
| Components.set(e, Bounds.new(e,0,0,r,"comet")) | |
| Components.set(e, Lines.new((((0..Game.vis-Game.diff).max)*10).floor,9,15)) | |
| var ps = ParticleSystem.new() | |
| var em = ParticleEmitter.new( | |
| 512, | |
| [ | |
| RadialSpawnModule.new(r), | |
| ScaleLifeModule.new(2,4), | |
| ColorLifeModule.new([1,10,10,9,9]), | |
| VelocityModule.new(0,-12,0,12), | |
| ], | |
| CircleDrawModule.new() | |
| ) | |
| var em2 = ParticleEmitter.new( | |
| 128, | |
| [ | |
| RadialSpawnModule.new(r), | |
| ScaleLifeModule.new(3,1), | |
| ColorLifeModule.new([4,3,2]), | |
| VelocityModule.new(-100,-100,100,100), | |
| ], | |
| CircleDrawModule.new() | |
| ) | |
| var em3 = ParticleEmitter.new( | |
| 512, | |
| [ | |
| RadialSpawnModule.new(r), | |
| ScaleLifeModule.new(2,4), | |
| ColorLifeModule.new([4,3]), | |
| GravityModule.new(0,0), | |
| VelocityModule.new(0,0,0,0), | |
| ], | |
| CircleDrawModule.new() | |
| ) | |
| em.cache_wrap = true | |
| em.rate = 200 | |
| em.life = 0.2 | |
| em.life_max = 1 | |
| em2.count = 64 | |
| em2.life = 0.8 | |
| em2.enabled = false | |
| em3.enabled = false | |
| ps.add(em) | |
| ps.add(em2) | |
| ps.add(em3) | |
| ps.layer = 3 | |
| Components.set(e, ps) | |
| return e | |
| } | |
| } | |
| class FSM { | |
| current { _current } | |
| states { _states } | |
| construct new() { | |
| _states = {} | |
| } | |
| add(s) { | |
| if (_states.containsKey(s.name)) { | |
| Fiber.abort("state with name: %(s.name) already exists") | |
| } | |
| _states[s.name] = s | |
| s.init() | |
| } | |
| remove(n) { | |
| var s = _states[n] | |
| if (s != null) { | |
| if (_current == s) { | |
| _current.onleave(null) | |
| _current = null | |
| } | |
| _states.remove(n) | |
| } | |
| } | |
| set(n) {set(n,null,null)} | |
| set(n,ed) {set(n,ed,null)} | |
| set(n,ed,ld) { | |
| var s = _states[n] | |
| if (s != null) { | |
| if (_current != null) { | |
| _current.onleave(ld) | |
| } | |
| s.onenter(ed) | |
| _current = s | |
| } | |
| } | |
| update(dt){ | |
| if (_current != null) { | |
| _current.update(dt) | |
| } | |
| } | |
| draw() { | |
| if (_current != null) { | |
| _current.draw() | |
| } | |
| } | |
| } | |
| class State { | |
| name { _name } | |
| construct new(n) { | |
| _name = n | |
| } | |
| init() { } | |
| onenter(d) { } | |
| onleave(d) { } | |
| update(dt) { } | |
| draw() { } | |
| } | |
| class MenuState is State { | |
| construct new() { | |
| super("menu") | |
| } | |
| init(){ | |
| } | |
| onenter(d){ | |
| _sel = 0 | |
| _title = Text.new("KOMET",84,40,5,2) | |
| _s = Circle.new(2,11,3) | |
| _s.ox = -2 | |
| _s.oy = -2 | |
| _s.x = 78 | |
| _s.y = 80 | |
| _p1 = Text.new("play",88,80,11,1) | |
| _diff = Text.new("difficulty 0",88,90,11,1) | |
| _vis = Text.new("visibility 0",88,100,11,1) | |
| _mustxt = Text.new("music %(Game.music ? "on" : "off")",88,110,11,1) | |
| _ps = ParticleSystem.new() | |
| var em = ParticleEmitter.new( | |
| 512, | |
| [ | |
| RadialSpawnModule.new(3), | |
| ScaleLifeModule.new(2,4), | |
| ColorLifeModule.new([11,10,10,9,9]), | |
| VelocityModule.new(-100,-12,0,12), | |
| ], | |
| CircleDrawModule.new() | |
| ) | |
| em.cache_wrap = true | |
| em.rate = 200 | |
| em.life = 0.2 | |
| em.life_max = 1 | |
| _ps.add(em) | |
| _ps.x = _s.x+2 | |
| _ps.y = _s.y+2 | |
| upd() | |
| } | |
| upd() { | |
| _diff.text = "difficulty %(Game.diff)" | |
| _vis.text = "visibility %(Game.vis)" | |
| _mustxt.text = "music %(Game.music ? "on" : "off")" | |
| } | |
| update(dt) { | |
| if(TIC.keyp(50) || TIC.btnp(4)) { // z | |
| Game.fsm.set("play") | |
| } | |
| if(TIC.btnp(0)) { | |
| _sel = Maths.mod(_sel-1, 4) | |
| _s.y = 80 + _sel*10 | |
| } else if(TIC.btnp(1)) { | |
| _sel = (_sel+1)%4 | |
| _s.y = 80 + _sel*10 | |
| } else if(TIC.btnp(2)) { | |
| if (_sel == 1) { | |
| Game.diff = Game.diff - 1 | |
| if (Game.diff < 0) { | |
| Game.diff = 0 | |
| } | |
| upd() | |
| } else if (_sel == 2) { | |
| Game.vis = Game.vis - 1 | |
| if (Game.vis < 0) { | |
| Game.vis = 0 | |
| } | |
| upd() | |
| } else if (_sel == 3) { | |
| Game.music = false | |
| upd() | |
| } | |
| } else if(TIC.btnp(3)) { | |
| if (_sel == 1) { | |
| Game.diff = Game.diff + 1 | |
| if (Game.diff > 3) { | |
| Game.diff = 3 | |
| } | |
| upd() | |
| } else if (_sel == 2) { | |
| Game.vis = Game.vis + 1 | |
| if (Game.vis > 3) { | |
| Game.vis = 3 | |
| } | |
| upd() | |
| } else if (_sel == 3) { | |
| Game.music = true | |
| upd() | |
| } | |
| } | |
| } | |
| draw() { | |
| _title.color = 11 | |
| _title.y = 41 | |
| _title.draw() | |
| _title.color = 10 | |
| _title.y = 40 | |
| _title.draw() | |
| _title.color = 9 | |
| _title.y = 39 | |
| _title.draw() | |
| _s.draw() | |
| _p1.draw() | |
| _diff.draw() | |
| _vis.draw() | |
| _mustxt.draw() | |
| _ps.x = _s.x+2 | |
| _ps.y = _s.y+2 | |
| _ps.update(1/60) | |
| _ps.draw() | |
| } | |
| } | |
| class GameOverState is State { | |
| construct new() { | |
| super("gameover") | |
| } | |
| onenter(d){ | |
| _texts = [] | |
| _main = Text.new("GAME OVER",64,28,2,2) | |
| _score = Text.new("score: %(Game.score.floor)",90,50,11,1) | |
| _playtext = Text.new("press z to play again",62,100,11,1) | |
| _menutext = Text.new("press s to menu",62,110,11,1) | |
| _texts.add(_main) | |
| _texts.add(_score) | |
| _texts.add(_playtext) | |
| _texts.add(_menutext) | |
| } | |
| update(dt) { | |
| if(TIC.btnp(4)) { | |
| Game.fsm.set("play") | |
| } else if(TIC.btnp(7)) { | |
| Game.fsm.set("menu") | |
| } | |
| } | |
| draw() { | |
| for (t in _texts) { | |
| t.draw() | |
| } | |
| } | |
| } | |
| class PlayState is State { | |
| construct new() { | |
| super("play") | |
| } | |
| init(){ | |
| _dist_text = Text.new("Score: 0",0,0,12,1) | |
| } | |
| onenter(d){ | |
| Camera.x = 0 | |
| Camera.y = 0 | |
| Game.score = 0 | |
| Game.time = 0 | |
| _last_cam = Camera.x | |
| Processor.add(SpawnProcessor.new(), 1) | |
| Processor.add(PosVelProcessor.new(), 8) | |
| Processor.add(BoundsProcessor.new(), 9) | |
| Processor.add(CometProcessor.new(), 10) | |
| Processor.add(CameraProcessor.new(), 11) | |
| Processor.add(ParticlesProcessor.new(), 100) | |
| Processor.add(DrawProcessor.new(), 999) | |
| EntityCreator.comet(3) | |
| } | |
| onleave(d){ | |
| Camera.x = 0 | |
| Camera.y = 0 | |
| World.empty() | |
| Processor.remove(SpawnProcessor) | |
| Processor.remove(PosVelProcessor) | |
| Processor.remove(BoundsProcessor) | |
| Processor.remove(CometProcessor) | |
| Processor.remove(CameraProcessor) | |
| Processor.remove(ParticlesProcessor) | |
| Processor.remove(DrawProcessor) | |
| } | |
| update(dt) { | |
| Game.time = Game.time + dt | |
| _last_cam = Camera.x | |
| World.update(Game.dt) | |
| var dist = Camera.x - _last_cam | |
| Game.score = Game.score + (dist * 0.001) | |
| _dist_text.text = "Score: %(Game.score.floor)" | |
| if(TIC.btn(7)) { | |
| Game.fsm.set("menu") | |
| // World.empty() | |
| } | |
| } | |
| draw() { | |
| Game.renderer.process() | |
| _dist_text.draw() | |
| } | |
| } | |
| class Settings { | |
| static camera_limit { 40 } | |
| static comet_dist { 48 } | |
| static comet_rest { 0.5 } | |
| static ice_force { 8 } | |
| static sun_hittime { 3 } | |
| static pl_force { 4 } | |
| static pl_factor { 1.5 } | |
| static bh_force { 8 } | |
| static bh_revforce { 10 } | |
| } | |
| // game | |
| class Game is TIC { | |
| static dt { __dt } | |
| static prog { __tm/__tm_max } | |
| static time { __tm } | |
| static space { __space } | |
| static renderer { __renderer } | |
| static random { __rnd } | |
| static speed { __spd } | |
| static speed=(v) { __spd=v } | |
| static contacts_pool { __cpool } | |
| static diff { __diff } | |
| static diff=(v) { | |
| __gr = 1 + v*0.25 | |
| __diff=v | |
| } | |
| static vis { __vis } | |
| static vis=(v) { __vis=v } | |
| static music { __mus } | |
| static music=(v) { | |
| if (v) { | |
| TIC.music(0) | |
| } else { | |
| TIC.music() | |
| } | |
| __mus = v | |
| } | |
| static fsm { __fsm } | |
| static score { __score } | |
| static score=(v) { __score=v } | |
| static timescale { __ts } | |
| static timescale=(v) { __ts=v } | |
| static time=(v) { __tm=v } | |
| static chances { __ch } | |
| static gravity { __gr } | |
| construct new(){ | |
| __mus = true | |
| TIC.music(0) | |
| __tm_max = 10*60 // 10 mins | |
| __gr = 1 | |
| __tm = 0 | |
| __vis = 3 | |
| __ts = 1 | |
| __diff = 0 | |
| __score = 0 | |
| __spd = 100 | |
| __dt = 1/60 | |
| var m = 64 | |
| __ch = [ | |
| [ | |
| 0.8,1.0, // planet | |
| 11.0,13.0, // sun | |
| 10.0,16.0, // blackhole | |
| 2.0,4.0, // ice | |
| 1.0 // speed | |
| ], | |
| [ | |
| 0.1,0.2, // planet | |
| 3.5,6.0, // sun | |
| 3.0,8.0, // blackhole | |
| 0.4,0.8, // ice | |
| 1.75 // speed | |
| ] | |
| ] | |
| for (i in 0...__ch.count) { | |
| for (j in 0...__ch[i].count) { | |
| __ch[i][j] = __ch[i][j] * m | |
| } | |
| } | |
| Timer.init() | |
| __rnd = Random.new() | |
| // FPS.init() | |
| __cpool = DynamicPool.new(32, Fn.new { CollisionInfo.new() }) | |
| __space = Space.new(40,0,Screen.width-40,Screen.height) | |
| __renderer = Renderer.new() | |
| Camera.init() | |
| // create Layers | |
| __renderer.create_layer(0) // bg | |
| __renderer.create_layer(1) // stars | |
| __renderer.create_layer(2) // planets | |
| __renderer.create_layer(3) // comet | |
| __renderer.create_layer(4) // fg | |
| World.init(4096) | |
| Family.create("planets", [Planet, Drawable, Position]) | |
| Family.create("comets", [Comet, Drawable, Position]) | |
| Family.create("particles", [ParticleSystem, Position]) | |
| Family.create("bounds", [Bounds, Position]) | |
| Family.create("pos_vel", [Position,Velocity]) | |
| Family.create("stars", [Star, Drawable, Position]) | |
| __fsm = FSM.new() | |
| __fsm.add(GameOverState.new()) | |
| __fsm.add(MenuState.new()) | |
| __fsm.add(PlayState.new()) | |
| __fsm.set("menu") | |
| // __fsm.set("play") | |
| } | |
| static add_score(v) { | |
| __score = __score + v | |
| } | |
| static remove_score(v) { | |
| __score = __score - v | |
| if (__score < 0) { | |
| __score = 0 | |
| } | |
| } | |
| TIC(){ | |
| __fsm.update(Game.dt) | |
| Timer.update(Game.dt) | |
| TIC.cls(0) | |
| __fsm.draw() | |
| // __space.draw() | |
| // TIC.trace(__space) | |
| // FPS.update() | |
| // TIC.print("FPS : %(FPS.value)",196,4,3) | |
| } | |
| } | |
| // <WAVES> | |
| // 000:0123456789abcdeffedcba9876543210 | |
| // 001:000012111555558cddd99deeeeefffff | |
| // 002:0000000000000000ffffffffffffffff | |
| // 003:3211000000001123cdeeffffffffeedc | |
| // 004:75321100001123578acdeeffffeedca6 | |
| // 005:2223456789abcddffedcba9876543222 | |
| // 006:89bcdeefffeedcb98754322111223457 | |
| // 008:75321100000000578acdeeffffeedca6 | |
| // 010:00112233445566778899aabbccddeeff | |
| // 011:7010100000000000fffffffffffffffa | |
| // 012:75321100001123578acdeeffffeedca8 | |
| // 015:0123456789abcdeffedcba9876543210 | |
| // </WAVES> | |
| // <SFX> | |
| // 000:060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600340000080808 | |
| // 001:000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000 | |
| // 002:0e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e000e00000000000000 | |
| // 016:0207020602050204020312021201220032005200520062007200820092009200b200b200c200d200e200f200f200f200f200f200f200f200f200f200900000000000 | |
| // 017:d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900d900f00000000000 | |
| // 018:020012012202420352046205720682069205b204c203d202e201e200e200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200a00000000000 | |
| // 019:0207120622054204520472039201a200b200c200d200e200e200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200f200900000000000 | |
| // 020:1207120622053205420452046203620362037202820282029202a201a201b201b201c200c200c200d200d200d200e200e200e200e200f200f200f200800000000000 | |
| // 021:c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200c200100000000000 | |
| // 022:020722063205520469038902a902b903c904d905e906f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907f907900000000000 | |
| // </SFX> | |
| // <PATTERNS> | |
| // 000:4d00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dd0004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dd0004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
| // 004:8d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
| // 005:8d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008d00060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
| // 008:ba0006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 | |
| // </PATTERNS> | |
| // <TRACKS> | |
| // 000:0001410001810000000000000000000000000000000000000000000000000000000000000000000000000000000000004c0000 | |
| // </TRACKS> | |
| // <PALETTE> | |
| // 000:1a1c2c572956b14156ee7b58ffd079a0f07238b86e276e7b29366f405bd04fa4f786ecf8f4f4f493b6c1557185324056 | |
| // </PALETTE> | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment