mirror of
https://github.com/wassname/cardsforscience.git
synced 2026-06-27 18:23:07 +08:00
242 lines
9.0 KiB
JavaScript
242 lines
9.0 KiB
JavaScript
/** Manages the detector animation in the canvas of the detector pane **/
|
|
|
|
var Detector = function(){
|
|
|
|
|
|
return {
|
|
elements: new GameObjects.Cards(),
|
|
|
|
visible: true,
|
|
|
|
width: 400,
|
|
height: 400,
|
|
|
|
ratio: 1,
|
|
|
|
lastRender: 0,
|
|
|
|
bubblr: undefined,
|
|
|
|
init: function()
|
|
{
|
|
// this.initBubbles();
|
|
// this.initFlame();
|
|
},
|
|
|
|
initBubbles: function(){
|
|
// init the test tube animation
|
|
var bubblrElem = $('#detector-core').bubblr({
|
|
backgroundColor: '#e8e8e8',
|
|
bubbleColor: "#bfbfbf",
|
|
bubbleMinSize: 3,
|
|
bubbleMaxSize: 5,
|
|
bubbleMaxSpeed: 2,
|
|
bubbleMinSpeed: 1,
|
|
animationSpeed: 20,
|
|
// bubbleXposMultiplier allows us to position bubbles on the x-axis
|
|
bubbleXposMultiplier: 2,
|
|
// bubbleYpopLimit determines how far in pixels from the canvas's
|
|
// top edge bubbles will disappear
|
|
bubbleYpopLimit: 10
|
|
});
|
|
this.bubblr = bubblrElem.data('plugin_bubblr');
|
|
},
|
|
|
|
// initFlame: function(){
|
|
// var flameElem = $('#detector-flame').flame();
|
|
// this.flamer = flameElem.data('plugin_flame')
|
|
// },
|
|
|
|
bindOnResize: function(){
|
|
// HACK
|
|
$(window).on('resize',this.onResize.bind(this));
|
|
},
|
|
|
|
// onResize: function(){
|
|
// // TODO, do one, schedule a check and then prevent firing until then
|
|
// if ($(window).width() >= 1200) {
|
|
// if (this.width != 500) {
|
|
// $('#detector').width(500).height(500);
|
|
// this.init(500);
|
|
// }
|
|
// } else if ($(window).width() < 768 && $(window).height() - 90 < 300) {
|
|
// var newWidth = $(window).width() - Math.max($(window).width() - ($(window).height() - 90 + 10), 300) - 10;
|
|
// if (this.width != newWidth) {
|
|
// $('#detector').width(newWidth).height(newWidth);
|
|
// this.init(newWidth);
|
|
// }
|
|
// } else if ($(window).width() < 992) {
|
|
// if (this.width != 300) {
|
|
// $('#detector').width(300).height(300);
|
|
// this.init(300);
|
|
// }
|
|
// } else {
|
|
// if (this.width != 400) {
|
|
// $('#detector').width(400).height(400);
|
|
// this.init(400);
|
|
// }
|
|
// }
|
|
//
|
|
// this.bubblr.onResize();
|
|
// this.flamer.onResize();
|
|
// },
|
|
|
|
/** When a user clicks the detector **/
|
|
addEvent: function()
|
|
{
|
|
// this.bubblr.bubble(); // bubble for 500ms, TODO make one bubble
|
|
},
|
|
|
|
/** When a worker clicks the detector **/
|
|
addEventExternal: function(numWorkers)
|
|
{
|
|
// this.bubblr.genBubbles(numWorkers);
|
|
},
|
|
|
|
/** Draw current events **/
|
|
draw: function(duration)
|
|
{
|
|
// this.bubblr.bubble();
|
|
},
|
|
|
|
/** Clear an element back to element Store **/
|
|
storeElementBy: function(qObject,game){
|
|
var i = _.findIndex(this.elements,qObject);
|
|
var removedElement = this.elements.splice(i,1)[0];
|
|
return game.elements.get(removedElement.key).state.amount+=1;
|
|
},
|
|
|
|
clearAll: function(game){
|
|
var hashKeys = this.elements.map(function(e){return e.$$hashKey;});
|
|
for (var i = 0; i < hashKeys.length; i++) {
|
|
this.storeElementBy({'$$hashKey': hashKeys[i]}, game);
|
|
}
|
|
},
|
|
|
|
onDrop: function(event, ui, game){
|
|
var self=this;
|
|
console.debug('onDrop',arguments);
|
|
var $draggable = angular.element(ui.draggable),
|
|
$droppable = angular.element(event.target);
|
|
|
|
// if the dragger came from the elements panels, clone it to here
|
|
var newElement;
|
|
if ($draggable.hasClass('element-store')){
|
|
|
|
var elementStore = game.elements.filter(function(e){return e.key==$draggable.data('element');})[0];
|
|
elementStore.state.amount-=1;
|
|
newElement = angular.copy(elementStore);
|
|
newElement.state.top=$draggable.offset().top;
|
|
newElement.state.left=$draggable.offset().left;
|
|
this.elements.push(newElement);
|
|
}
|
|
|
|
|
|
// get everything intersecting the drop
|
|
var draggableTop = $draggable.offset().top;
|
|
var draggableHeight = $draggable.height();
|
|
var draggableBottom = draggableTop + draggableHeight;
|
|
var draggableLeft = $draggable.offset().left;
|
|
var draggableWidth = $draggable.height();
|
|
var draggableRight = draggableLeft + draggableWidth;
|
|
var detectorDOMElems = angular.element('#detector').find('.element').not('.element-store'); // replace with detector.elements
|
|
var intersectingDOMElems = detectorDOMElems.filter( function() {
|
|
var $elem = angular.element(this);
|
|
var top = $elem.offset().top;
|
|
var height = $elem.height();
|
|
var bottom = top + height;
|
|
|
|
var left = $elem.offset().left;
|
|
var width = $elem.width();
|
|
var right = left + width;
|
|
|
|
var isCoveredByDraggable = top <= draggableBottom && bottom >= draggableTop
|
|
&& left <= draggableRight && right >= draggableLeft;
|
|
return isCoveredByDraggable;
|
|
});
|
|
|
|
// We have the DOM's in the area (maybe missing the newly dropped one)
|
|
// var droppedModel = game.elements.getByHashKey($draggable.data('hashkey'));
|
|
var intersectingElements = intersectingDOMElems.toArray().map(function(input){
|
|
return self.elements.getByHashKey(angular.element(input).data('hashkey'));
|
|
});
|
|
|
|
// make sure we include the dropped element as in some cases
|
|
// it wont have DOM object yet so it wont be picked up as intersecting
|
|
if (newElement && intersectingElements.indexOf(newElement)===-1) intersectingElements.push(newElement);
|
|
|
|
|
|
var uniqueElems = _(intersectingElements).map('key').uniq().value().length;
|
|
if (intersectingElements.length==2 && uniqueElems>1){
|
|
var observation = this.experiment({inputs:intersectingElements,location:$draggable.offset()},game);
|
|
console.log('intersectingElements', intersectingElements.length, observation);
|
|
return observation;
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
|
|
},
|
|
|
|
/** Run an experiment depending on reactants and conditions **/
|
|
experiment: function(options,game) {
|
|
var inputs = options.inputs || [];
|
|
var inputKeys = inputs.map(function(e){return e.key;});
|
|
inputKeys.sort(); // this makes reaction be independant of order
|
|
|
|
var result = game.testRules(inputKeys);
|
|
if (result) {
|
|
this.reaction(inputs,result.reactants,result.results, options.location, game);
|
|
} else {
|
|
result = {
|
|
reactants: [],
|
|
catalysts: [],
|
|
conditions: [],
|
|
results: [],
|
|
inputs: inputKeys
|
|
};
|
|
}
|
|
return result;
|
|
},
|
|
|
|
/** Remove reactants and make results with animations **/
|
|
reaction: function(inputs,reactants,results,location,game){
|
|
|
|
// remove reactants from detector
|
|
for (var i = 0; i < reactants.length; i++) {
|
|
// get the uuid from inputs
|
|
var ingredient = inputs.filter(function(e){return e.key===reactants[i];})[0];
|
|
var j = _.findIndex(this.elements,{uuid:ingredient.uuid});
|
|
var removed = this.elements.splice(j,1);
|
|
}
|
|
|
|
// TODO use angular effects to remove in puff of fade
|
|
|
|
// add results and discover them
|
|
for (var i = 0; i < results.length; i++) {
|
|
var resultKey = results[i];
|
|
|
|
// make sure it's discovered
|
|
var elementStore = game.elements.get(resultKey);
|
|
if (!elementStore.state.discovered){
|
|
// old discoveries are not interesting
|
|
game.elements.map(function(e){e.state.interesting=false;});
|
|
// a new discovery is interesting
|
|
elementStore.state.interesting=true;
|
|
elementStore.state.discovered=true;
|
|
}
|
|
|
|
// add new element to beaker
|
|
var newElem = elementStore.spawn();
|
|
newElem.state=location;
|
|
|
|
this.elements.push(newElem);
|
|
}
|
|
|
|
// effects
|
|
// this.bubblr.bubble();
|
|
|
|
},
|
|
};
|
|
};
|