Approach to modifying mutable objects? - javascript

Given that functional programming is best when sticking to immutable variables as much as possible, and that Ramda always makes shallow copies, how are objects that must be mutable dealt with in a mostly-purely functional framework?
For example, consider PIXI.Sprite (in pixi.js). The display system has an inherent hierarchy that is linked together and has its own way of tracking objects so it can re-use textures, etc. Garbage collecting them could be a real problem.
What sort of approaches can be taken to deal with this (alongside a robust frp system like sodium-typescript)?
Specifically, can this approach be improved:
Having some sort of unsafePerformIO() function that will modify the heavy objects. All modification of those objects is only done through that function.
Lightweight meta-information objects carry all the logic around.
Those lightweight information objects reference the heavy objects directly
Here is a full code sample in Typescript to demonstrate it in action (just need to import PIXI and Ramda). The key lines are in gameLoop():
let app = new PIXI.Application(window.innerWidth, window.innerHeight);
document.body.appendChild(app.view);
let ball = new PIXI.Graphics();
ball.beginFill(0xFF0000);
ball.drawCircle(0,0,40);
ball.endFill();
ball.y = app.stage.height/2;
app.stage.addChild(ball); //app
let ticker = new PIXI.ticker.Ticker();
ticker.add(gameLoop);
ticker.start();
let ballReference = {
ptr: ball,
x: 0
}
function performUnsafeIO(reference) {
reference.ptr.x = reference.x;
}
function gameLoop(deltaTime:number) {
//this version breaks!
//ball = R.assoc('x', ball.position.x + deltaTime * 1, ball);
//This works fine... but are there any gotchas?
ballReference = R.assoc('x', ballReference.x + deltaTime * 1, ballReference);
performUnsafeIO(ballReference);
}
(note, this conversation found via Google is a good reference point: https://web.archive.org/web/20100410001213/http://itmmetelko.com/blog/2008/02/23/functional-programming-immutable-objects-explained-irc-style/)

Related

PixiJS consuming enormous amounts of GPU

So I have a scene in Pixi, with about 7-8 textures in it. A couple are just looping simple transforms (e.g spinning like a fan, etc), some are static.
Without interacting with it at all (it's in a separate window to this), the mere presence of it makes my 16BG i7 MacBook Pro heat up like crazy and it's occupying 50% CPU.
Here's an example of how I'm setting up one of the spinning animations. Does anything in there look suspicious? I can't believe how much power it's consuming, and I'm about to throw out all my Pixi code and just use CSS as it seems much more efficient.
rotorPositions.forEach((rotor, index) => {
const sprite = new PIXI.Sprite(resources.rotor.texture)
sprite.position.set(foregroundContainer.width/100 * rotor[0], foregroundContainer.height/100 * rotor[1])
foregroundContainer.addChild(sprite)
sprite.anchor.x = 0.5
sprite.anchor.y = 0.616
let speed = 0.03
sprite.zIndex = 3
if(index == 1){
speed = 0.04
sprite.rotation = 0.5
}
app.ticker.add(() => {
sprite.rotation += speed
})
})
Preload your textures and try using cacheAsBitmap property. It takes snapshot of the display object resulting in better performance.
Here is an example: multiple textures example with cacheAsBitmap
Edit: You are using foreach loop. Loops can be very tricky, maybe use console.log and print a counter variable to see how many times the loop executes.

How to implement basic LOD mechanism on a 3D json asset

I am not able to implement LOD to a 3d Object with json data.
Here is my implementation:
loader.load('models/robot-threejs/robot.json', function(object){
var lod = new THREE.LOD(object);
for (var i=1; i<=3;i++) {
console.log("this"+i);
lod.addLevel(object,i);
}
lod.updateMatrix();
lod.matrixAutoUpdate = false;
// lod.updateMatrix();
// lod.matrixAutoUpdate = false;
scene.add(lod);
//scene.add(object);
// object.position.set(30, 30, 30);
})
You're implementing THREE.LOD wrong.
The constructor does not take any parameters, so when you do this: new THREE.LOD(object);, it does nothing. You just have to use new THREE.LOD();
You're adding the same mesh to LOD 3 times, so you're not gonna see any difference. You need to create separate meshes with different geometries if you want to see any change in detail. Keep in mind that you have to generate these geometries yourself. Three.js doesn't automatically change the geometry for you. But you could use the SimplifyModifier for this.
Not sure why you're playing with matrix updates. There's no reason for this here.
You also need to call lod.update(camera) on your render loop if you want to see the change in detail.
I strongly recommend you read the documentation for LOD and read through the code in this example to better understand how it works.

Instancing Multiple Objects Lowers Framerate of WEBGL Application

I am developing a THREE.JS WebGL application where I need to render multiple objects with the same geometry and I've stumbled upon a bottleneck. It seems that my instancing of objects has some issue, that I can't really understand/realize, maybe someone can help me with that. For context, I have a PointCloud with normals, that gives me information about where to position my instanced objects, and also the orientation of the object through the normal quaternion. Then, I loop through this array, and place each instanced object accordingly. After looking at various posts about instancing, merging, etc, I can't figure out what I'm doing wrong.
I attach the code snippet of the method in question :
bitbucket.org/snippets/electricganesha/Mdddz
After reviewing it multiple times, I'm really wondering what is wrong here, and why does this particular method slow down my application from 60fps to 20fps.
You might be overcompensating with the optimization.
In your loop where you merge all these geometries try to add something like this
var maxVerts = 1 << 16;
//if merging a new object causes the vert number to go over 2^16 push the merged geometry somewhere, and make a new one for the next batch
if( singleGeometry.vertices.length + newObject.geometry.vertices.length > maxVerts ){
scene.add(singleGeometry);
singleGeometry = new Geometry();
}
singleGeometry.merge(newObject.geometry, newObject.matrix);

Circular dependencies of EventStreams in FRP

All examples uses Ramda as _ (it's clear what methods do in examples contexts) and kefir as frp (almost same API as in bacon.js)
I have a stream, that describes change of position.
var xDelta = frp
.merge([
up.map(_.multiply(1)),
down.map(_.multiply(-1))
])
.sampledBy(frp.interval(10, 0))
.filter();
It emits +1 when I press UP key, and -1 on DOWN.
To get position I scan this delta
var x = xDelta
.scan(_.add)
.toProperty(0);
That's work as expected. But I want to limit value of x from 0 to 1000.
To solve this problem I found two solution:
Change function in scan
var x = xDelta.scan(function (prev, next) {
var newPosition = prev + next;
if (newPosition < 0 && next < 0) {
return prev;
}
if (newPosition > 1000 && next > 0) {
return prev;
}
return newPosition;
}, 0);
It looks Ok, but later, as new rules will be introduced, this method will grow. So I mean it doesn't look composable and FRPy.
I have current position. And delta. I want to apply delta to current, only if current after applying will not be out of limits.
current depends on delta
delta depends on current after applying
current after applying depends on current
So it looks like circular dependency. But I solved it using flatMap.
var xDelta = frp
.merge([
up.map(_.multiply(1)),
down.map(_.multiply(-1))
])
.sampledBy(frp.interval(10, 0))
.filter();
var possibleNewPlace = xDelta
.flatMap(function (delta) {
return x
.take(1)
.map(_.add(delta));
});
var outOfLeftBoundFilter = possibleNewPlace
.map(_.lte(0))
.combine(xDelta.map(_.lte(0)), _.or);
var outOfRightBoundFilter = possibleNewPlace
.map(_.gte(1000))
.combine(xDelta.map(_.gte(0)), _.or);
var outOfBoundFilter = frp
.combine([
outOfLeftBoundFilter,
outOfRightBoundFilter
], _.and);
var x = xDelta
.filterBy(outOfBoundFilter)
.scan(_.add)
.toProperty(0);
You can see full code example at iofjuupasli/capture-the-sheep-frp
And it's working demo gh-pages
It works, but using circular dependencies is probably anti-pattern.
Is there a better way to solve circular dependency in FRP?
The second more general question
With Controller it's possible to read some values from two Model and depending on it's values update both of them.
So dependencies looks like:
---> Model
Controller ---|
---> Model
With FRP there is no Controller. So Model value should be declaratively calculated from other Model. But what if Model1 calculating from another Model2 which is the same, so Model2 calculates from Model1?
Model ----->
<----- Model
For example two players with collision detection: both players have position and movement. And movement of first player depends on position of second, and vice versa.
I'm still newbie in all this stuff. It's not easy to start think in declarative FRP style after years of imperative coding. Probably I'm missing something.
using circular dependencies is probably anti-pattern
Yes and no. From the difficulties you had with implementing this, you can see that it's hard to create a circular dependency. Especially in a declarative way. However, if we want to use pure declarative style, we can see that circular dependencies are invalid. E.g. in Haskell you can declare let x = x + 1 - but it will evaluate to an exception.
current depends on delta, delta depends on current after applying,
current after applying depends on current
If you look closely, it doesn't. If this were a true circular dependency, current never had any value. Or threw an exception.
Instead, current does depend on its previous state. This is a well-known pattern in FRP, the stepper. Taking from this answer:
e = ((+) <$> b) <#> einput
b = stepper 0 e
Without knowing what <$> and <#> exactly do, you can probably tell how the events e and the behaviour ("property") b depend on the events einput. And much better, we can declaratively extend them:
e = ((+) <$> bound) <#> einput
bound = (min 0) <$> (max 1000) <$> b
b = stepper 0 e
This is basically what Bacon does in scan. Unfortunately it forces you to do all of this in a single callback function.
I haven't seen a stepper function in any JS FRP library1. In Bacon and Kefir, you'll probably have to use a Bus if you want to implement this pattern. I'd be happy to be proven wrong :-)
[1]: Well, except in the one I have implemented myself because of this (it's not presentable yet). But using Stepper still felt like jumping through hoops, as JavaScript doesn't support recursive declarations.
There is a new framework/library called cyclejs that works off exactly the circular mechanism you describe, but in that case for a webfrontend library similar to Facebook's new React.
The basic idea is to have a Model that is a stream of "state" values, a view stream that renders those, a user-interaction stream that emits the user interactions coming from the sideeffect of the view (the browser DOM) and an "intent" stream that creates high level events from the user and feeds into the model which creates new values.
It's still in early development, but it's a pretty neat idea and works well so far.

Which is better for massive amounts of Variables

So after reading massively into JS the past few days (I'm just starting with it) I have come upon 3 viable options for my project, which is a game btw. There will be about 200 items in my game, with a total of about 30 stats/properties. But since the program has to know that a Sword doesn't give Spell damage than I have to give each item all those 30 properties even if 90% will be 0. So here is what I came up with, any advice is greatly appreciated:
var prop, obj = { Item1: "Boots", Item2: "Gloves", Item3: "Sword", Item4: "Cape" };
// Pretty sure I'd have to remake this somehow to put properties in there, this might not be as useable
function Item(hp, mp, dmg, spd, luk) {
this.hp = hp;
this.mp = mp;
this.dmg = dmg;
this.spd = spd;
this.luk = luk;
}
var BigSword = new Item(0, 0, 50, 20, 10)
//I think this might be my best option so there are as few variables as possible? or does that not matter as much? I figured with this option whenever I update totalHp and totalMp and totalDmg etc in the updating function I can create a local variable called theItem = BigSword and then just do theItem.hp, theItem.mp and that way it doesn't have to search much for the variable and should run relatively faster? Sorry for the newbie question but does JS even have local variables in functions? As in if I do var theItem = whatever, then theItem will be null outside the function?
itemNames = [ "Boots", "Gloves", "Sword", "Cape" ];
itemHp = [ 0, 0, 0, 50 ];
itemMp = [ 0, 30, 0, 0 ];
itemDmg = [ 0, 0, 50, 0 ];
itemSpd = [ 50, 0, 0, 0];
//This is the other option that I came up with, a little uglier but if it's faster or better to just use arrays I don't mind that much.
But please keep in mind, like I said, 200~ish total items, each item will have around 30 properties. What do you think?
Thanks a lot for reading and for any information provided, it's greatly appreciated! Thanks in advance
Your best bet is to have a constructor, as you have in your first example. However, I'd change a few things. First of all, for the constructor, you're simply passing in a lot of numbers. This is bad, because it's very easy to forget the order in which your numbers go. A better way to go would be to pass in an object to your constructor, so you can label each property:
function Item(props) {
this.hp = props.hp;
this.mp = props.mp;
this.dmg = props.dmg;
this.spd = props.spd;
this.luk = props.luk;
}
var BigSword = new Item({
hp: 0,
mp: 0, 5
dmg: 0,
spd: 20,
luk: 10
});
This is nice, but still a pain, because you have all sorts of different items, and as you said, you'd have to define 30 properties for each item, which gets both messy and time-consuming. At this point you get into the realm of more complex object oriented stuff. From here you have basically two options: inheritance and construction.
Inheritance
Using object inheritance to properly define objects is one probably the more common of the two, and is fairly straightforward. In essence, you have a "class" of object, and then sub-classes of each class. So you might have Magical Items and Non-Magical Items as two classes. If you had a magic belt, perhaps, you'd want to make it inherit the properties of the Magical Item class. On the other hand, if you had a basic un-charmed sword, you'd want to make it inherit from the Non-Magical Item class.
But say you have magical scrolls and magical potions. Those are both magical items, right? So you'd want to make a class called Potions and a class called Scrolls, which both inherit from the Magical Item class. Then you might have certain types of potions. Healing potions, maybe--"Magical Potion of Heal Allies" and "Magical Potion Of Heal Self". So you'd need different classes for those--and so on and so forth.
Inheritance in Javascript can be done a number of different ways and it's possible to get very in-depth, so I'm not going to discuss it in my post. Here are a few useful links to get you started with inheritance, though, if you want to go that route:
David Crockford on Inheritance
MDN on Inheritance and MDN Inheritance Revisted
Alex Sexton on Inheritance
Composition
Composition is a concept that borrows heavily from other loosely-typed languages, such as Python, which employs it quite extensively. The basic idea behind composition is that you have a base object class, and whenever you need a certain specific type of object, you add behaviors, or members, to that base class. This isn't quite as well-known as inheritance, but it's definitely the one I prefer.
In Javascript, it works by having a base constructor, Item, and then having other constructors which add the necessary behaviors to your Item. Let's take a look at the example I used for composition--creating a Magical Potion of Heal Allies. You have several distinct properties here: Magical Item, Potion, Healing. With inheritance you'd do something like Item -> Magical -> Potion -> Healing Potions -> Allies. However, with composition, you can add several behaviors to a base Item class, without having to set up a huge prototype chain: Affect Allies, Potion, Healing.
Since composition is a bit simpler than inheritance (and, I'll admit it, I'm biased) I'll set up a quick example in psuedo-code:
// base item class
function Item(props) {
this.someProperty = props.someProperty;
this.someOtherProperty = props.someOtherProperty;
}
// potion behavior
function Potion(props) {
this.amount = props.amount; // IDK what amount means, just some random potion property
this.color = "green";
}
// healing behavior
function Healing(props) {
this.amountToHeal = props.amountToHeal;
this.cooldown = props.cooldown;
}
// behavior to affect allies
function AffectAllies(props) {
this.allies = props.allies;
for(ally in this.allies) {
this.allies[ally].affect(props.affact);
}
}
// at this point we have the various behaviors set up and we can create the Magical Potion of Heal Allies constructor:
function MassHealingPotion(props) {
var self = this;
this.amount = props.amount;
this.potion = new Potion(props);
this.effect = new Healing(props);
this.AffectAllies = new AffectAllies({
affect: function(ally) {
self.potion.affect;
},
allies: player.allies;
});
}
// you can now create a mass healing potion:
var potion = new MassHealingPotion({
weight: 50,
someProp: "someValue",
someOtherProp: "someOtherValue"
// and so on and so forth with whatever properties you want the potion to have
});
Well, that turned out a bit longer than I expected and probably contains proportionally more errors than I'd like, but I hope that conveys the basic idea of composition.
Now, simpler object creation isn't even the best part of composition, which is that you can re-use different behaviors. Consider you have a magical sword that whenever you make an attack it heals your allies. All you have to do is give it the Healing member and the AffectAllies member and boom--magical sword of heal buddies. With inheritance, you'd have to create a Swords class in the Magical Items class (and then you'd have two different Swords classes-one for Non Magical Swords and the other for Magical Swords! Ew!), then extend that with Healing Swords, and so on and so forth.
You can go either way, inheritance or object composition. Both are equally effective for what you want to achieve.
But what about performance?
200 items with 30 properties a piece? Not a problem. Stick them all in one giant array/object, boil 'em, mash 'em, stick 'em in a stew. The browser don't care. Your best bet is probably an object, though:
var itemList = {
bigSword: new BigSword(...);
smallSword: new SmallSword(...);
}
I would prefer Objects. I would start with a simple, generic "Item" and then build specific items by "inherit" from the generic one with prototyping.
That probably may reduce code redundancy and increase maintainability dramatically.
Speedwise I don't have a clue but I think iterating through 200*30 array values isn't also that fast.
You need to do a serious design effort first. If you just start coding (as many developers do), you will only get so far and realise your design has a fundamental flaw and the application needs to be rewritten. That doesn't matter in the early stages, but once you've written a few hundred lines of code it gets quite tedious.
By all means write code to prototype things, but all you should expect to get from it are design hints, the code should be thrown away.
Your items list (or catalogue) should be an object with methods to add, remove and update items. Each player (character, avatar, whatever) then just needs a list of their items and their state. There should be a global update damage or health or whatever function that gets items of a specific type and applies them to players of a specific type (e.g. weapons damage enemies, food revives the player and friends, etc.).
Only once you know all the players and items and their attributes and actions, you can start to design the interfaces and methods, and finally write some code.
Keep your eye on the objective, which should be to develop an engaging game, not to just write a few thousand lines of code.

Categories