From d88135c85f716832819039c511117730aa3e5987 Mon Sep 17 00:00:00 2001 From: cha0s Date: Thu, 27 Jun 2024 15:08:30 -0500 Subject: [PATCH] fun: planties! --- app/ecs-components/plant.js | 58 +++++++++++++++++++ app/ecs-systems/plant-growth.js | 27 +++++++++ app/engine.js | 28 +++++++++ public/assets/tomato-plant/grow.js | 13 +++++ public/assets/tomato-plant/may-grow.js | 1 + public/assets/tomato-plant/tomato-plant.json | 1 + public/assets/tomato-plant/tomato-plant.png | Bin 0 -> 1725 bytes 7 files changed, 128 insertions(+) create mode 100644 app/ecs-components/plant.js create mode 100644 app/ecs-systems/plant-growth.js create mode 100644 public/assets/tomato-plant/grow.js create mode 100644 public/assets/tomato-plant/may-grow.js create mode 100644 public/assets/tomato-plant/tomato-plant.json create mode 100644 public/assets/tomato-plant/tomato-plant.png diff --git a/app/ecs-components/plant.js b/app/ecs-components/plant.js new file mode 100644 index 0000000..dd8fe93 --- /dev/null +++ b/app/ecs-components/plant.js @@ -0,0 +1,58 @@ +import Component from '@/ecs/component.js'; +import Script from '@/util/script.js'; + +export default class Plant extends Component { + instanceFromSchema() { + const {ecs} = this; + const Instance = super.instanceFromSchema(); + return class PlantInstance extends Instance { + mayGrow() { + return this.mayGrowScriptInstance.evaluateSync(); + } + grow() { + const {Ticking} = ecs.get(this.entity); + Ticking.addTickingPromise(this.growScriptInstance.tickingPromise()); + } + }; + } + async load(instance) { + // heavy handed... + if ('undefined' !== typeof window) { + return; + } + const {readAsset} = this.ecs; + await readAsset(instance.growScript) + .then(async (code) => { + if (code.byteLength > 0) { + const context = { + ecs: this.ecs, + plant: instance, + }; + instance.growScriptInstance = await Script.fromCode((new TextDecoder()).decode(code), context); + } + }); + + await readAsset(instance.mayGrowScript) + .then(async (code) => { + if (code.byteLength > 0) { + const context = { + ecs: this.ecs, + plant: instance, + }; + instance.mayGrowScriptInstance = await Script.fromCode((new TextDecoder()).decode(code), context); + } + }); + } + // heavy handed... + markChange() {} + static properties = { + growScript: {type: 'string'}, + growth: {type: 'uint16'}, + mayGrowScript: {type: 'string'}, + stage: {type: 'uint8'}, + stages: { + type: 'array', + subtype: {type: 'uint16'}, + }, + }; +} diff --git a/app/ecs-systems/plant-growth.js b/app/ecs-systems/plant-growth.js new file mode 100644 index 0000000..868b3a4 --- /dev/null +++ b/app/ecs-systems/plant-growth.js @@ -0,0 +1,27 @@ +import {System} from '@/ecs/index.js'; + +export default class PlantGrowth extends System { + + static queries() { + return { + default: ['Plant'], + }; + } + + tick(elapsed) { + for (const {Plant} of this.select('default')) { + if (65535 === Plant.growth || !Plant.mayGrow()) { + continue; + } + const stage = Math.floor(Plant.stage); + Plant.growth = Math.min( + Plant.growth + (((Math.random() + 0.5) * elapsed) / Plant.stages[stage]) * 65535, + 65535, + ); + if (65535 === Plant.growth) { + Plant.grow(); + } + } + } + +} diff --git a/app/engine.js b/app/engine.js index 5c86e63..66e6324 100644 --- a/app/engine.js +++ b/app/engine.js @@ -118,11 +118,39 @@ export default class Engine { ], }, }); + const plant = { + Plant: { + growScript: '/assets/tomato-plant/grow.js', + mayGrowScript: '/assets/tomato-plant/may-grow.js', + stages: [300, 300, 300, 300, 300], + }, + Sprite: { + anchor: {x: 0.5, y: 0.75}, + animation: 'stage/0', + frame: 0, + frames: 1, + source: '/assets/tomato-plant/tomato-plant.json', + speed: 0, + }, + Ticking: {}, + VisibleAabb: {}, + }; + const promises = []; + for (let y = 0; y < 10; ++y) { + for (let x = 0; x < 10; ++x) { + promises.push(ecs.create({ + ...plant, + Position: {x: 8 + x * 16, y: 8 + y * 16}, + })); + } + } + await Promise.all(promises); const defaultSystems = [ 'ResetForces', 'ApplyControlMovement', 'ApplyForces', 'ClampPositions', + 'PlantGrowth', 'FollowCamera', 'CalculateAabbs', 'UpdateSpatialHash', diff --git a/public/assets/tomato-plant/grow.js b/public/assets/tomato-plant/grow.js new file mode 100644 index 0000000..f6eea88 --- /dev/null +++ b/public/assets/tomato-plant/grow.js @@ -0,0 +1,13 @@ +const {Sprite} = ecs.get(plant.entity); + +if (plant.stage < 3) { + plant.stage += 1 +} +if (4 === plant.stage) { + plant.stage = 3 +} +if (3 !== plant.stage) { + plant.growth = 0 +} + +Sprite.animation = ['stage', plant.stage].join('/') diff --git a/public/assets/tomato-plant/may-grow.js b/public/assets/tomato-plant/may-grow.js new file mode 100644 index 0000000..dc36c3b --- /dev/null +++ b/public/assets/tomato-plant/may-grow.js @@ -0,0 +1 @@ +3 !== plant.stage diff --git a/public/assets/tomato-plant/tomato-plant.json b/public/assets/tomato-plant/tomato-plant.json new file mode 100644 index 0000000..13e165f --- /dev/null +++ b/public/assets/tomato-plant/tomato-plant.json @@ -0,0 +1 @@ +{"animations":{"stage/0":["tomato-plant/tomato-plant/0"],"stage/1":["tomato-plant/tomato-plant/1"],"stage/2":["tomato-plant/tomato-plant/2"],"stage/3":["tomato-plant/tomato-plant/3"],"stage/4":["tomato-plant/tomato-plant/4"]},"frames":{"tomato-plant/tomato-plant/0":{"frame":{"x":0,"y":0,"w":16,"h":32},"spriteSourceSize":{"x":0,"y":0,"w":16,"h":32},"sourceSize":{"w":16,"h":32}},"tomato-plant/tomato-plant/1":{"frame":{"x":16,"y":0,"w":16,"h":32},"spriteSourceSize":{"x":0,"y":0,"w":16,"h":32},"sourceSize":{"w":16,"h":32}},"tomato-plant/tomato-plant/2":{"frame":{"x":32,"y":0,"w":16,"h":32},"spriteSourceSize":{"x":0,"y":0,"w":16,"h":32},"sourceSize":{"w":16,"h":32}},"tomato-plant/tomato-plant/3":{"frame":{"x":48,"y":0,"w":16,"h":32},"spriteSourceSize":{"x":0,"y":0,"w":16,"h":32},"sourceSize":{"w":16,"h":32}},"tomato-plant/tomato-plant/4":{"frame":{"x":64,"y":0,"w":16,"h":32},"spriteSourceSize":{"x":0,"y":0,"w":16,"h":32},"sourceSize":{"w":16,"h":32}}},"meta":{"format":"RGBA8888","image":"./tomato-plant.png","scale":1,"size":{"w":80,"h":32}}} \ No newline at end of file diff --git a/public/assets/tomato-plant/tomato-plant.png b/public/assets/tomato-plant/tomato-plant.png new file mode 100644 index 0000000000000000000000000000000000000000..de7985b6ce5f60e2e68afb4e5fe575af13dee883 GIT binary patch literal 1725 zcmV;u215CXP)EX>4Tx04R}tkv&MmKpe$i)0T=>MC>5qkfAzR5EXIMDionYs1;guFuC*#nlvOS zE{=k0!NHHks)LKOt`4q(Aou~|=;Wm6A|?K>DYS_3;J6>}?mh0_0YbgZG%GL;Xu55t z5^*t;T@^#G2qJ(U^kYC~mN6$uNqCO0d-(Wz7vovp=l&eMYR+PSPb8jYhG`RT5KnK~ z2Iqa^2rJ4e@j3CBNf#u3?RNSu0mr>z@3D;hes*%ypW>NMI35kRU=q6(y8mBSx!EiiH&I$36T*O}|7gg=bb;{@ zj20++-Q(R|oxS~grq$mM`vh`#{u1@>00006VoOIv0RI600RN!9r;`8x010qNS#tmY z3ljhU3ljkVnw%H_000McNliru<^=={Hw4u?*HHif1iDE?K~!ko-C50R8%G>{yAr6F zn2lltrAm=Z9E@G0gRyi_h)qEb?ZM;}`%sE8_|Q`N7x-Wd>7l*0AwJ|_B~C!}C@7^i zD0Wdr;dptrO8=J)a5tN@3O@Pb!i z=dy{4&~3cnG~#|(oKgTF**t_46t($kvB^cERlM72QI~8UUYYj=1o#3joXASo@uJgG zRtkz*COT}*E9hJf)-40$fG!hQVHOvOD zA(c7@09?0-SINDsfsRdK0638qoX83e$~6GM^Q{V`a0EN@7^HASZ4!WDhF|(L1OT{s zN7P6inRd18&W?$|SF5MO9-xd*cx>afMuNkZ{~4Kf;dr~@+z3nqINGo4=BnAhb)USA zgm*ZKz-2&419)^nA|aHJ$C7K*OxVFjouivbCN_ETEsx}a7f4i)rifeSFc1Iz+2kg% zF9{@te%Yo|ijEE-iV!ln8lJ@SC~WatIMQtg{d^Ws=tuItoA6*NGypqZ_I_+q*Cn$9 zc^x5U*SH^>RHCEm+L>I<6yKLMkkl~Z3P@dQW$@Wio++R_Q$XQ%9_5*WCP#R$QJyIv zldB<QEHo}YjL|!Le zmL{7n`fnQ*06;2ruDKB_c)B*WBEN4Uuv0Hfy9x53snogZL@s2E6pmnReHSrKyc861 zR%*7bn|)UUeE~s}5yU| z*KXpW|9@bEjFz$oLjaVH$O<_`$S-;uNixL?TMF?+jr0dGuVmepD=LV!5S-ck8 zdCg>u0vkJRv?yr;q%gCD8WGOQh-E;qBC4aK14u7U;n99wN7&JR9cdGRPNdJg7{ZOs zVX%#jN5*V)LkuSwUr9HJc7sTWgBK0lltt?izllroW0Sz%KRPQ%?48*LvK`n+#<;uf zOzy4>DM@M(t6j8}g!ujszXAY1-zy2c8$dSem-ipTH-0J1(MAVqGG?i$;otq{!Jxmc zk=SVyQ2;zMOTm$8SIZ7+)=RqvoJ7moMZ{H2$TPx|y4MXI_$`3P0KPU8 zqGX(v)Rg9_VXszC1=b6nm4KDSV+{J$`osHfmyP22M8(qK1dBIX*J=c=SxIxUW61?C zmyZR2-&ck(J9|wxXT{4BDMX*`eHHiON!)8mO40b?xK|mDw_dkrI`DYALA{jWdwAN* zk`kbL*{0!PCp~^#J;jbZh8=lKH&4oe5ecl2{^H-yxba4J^o?CPL+>DYDZ}&dMqZRO z03$ETj@RqEy5Ap3^(!^i$}qzl)xgJg7Nf;*^>+SBD)VlDopV3{hylVLpuAq+1s1%z zI&7CfGrZX5pw+gddHI(-NB@>L+;iDPMKB|Rbn5IwQHPgYz6ZQ(#{l6=mrsW;r`>a; zobcTHPfy=+<9k*E