Setting inner property of an object with an inner method - JavaScript - javascript

I started this project just for fun (inspired by the Conway's Game of Life). In my project, I have a file for the cell (defined as an object) and other for the game (universe) where the rules are set so the cell can play. The cell object is defined like this:
const cell = {
x_birth: 0,
y_birth: 0,
alive: false,
live: function() {
fill(100);
square((WIDTH/F)*x, (HIGH/F)*y, (WIDTH/F), (HIGH/F));
},
die: function() {
fill(255);
square((WIDTH/F)*x, (HIGH/F)*y, (WIDTH/F), (HIGH/F));
},
move: function(x_var, y_var) {
if (this.alive == false){
x = this.x_birth;
y = this.y_birth;
this.alive = true; // Bug?
this.live();
} else { //... }}}
WIDTH, HIGH and F are global constants from the other main file.
The problem I have is that when I create two objects with 'Object.create(cell)' in the main file, just one of the cells moves. It appears that when one of the cells executes its function 'move()', it does it correctly, setting it's property 'alive' to 'true' when the other cell (object) doesn't. I though that this may be the problem, but then I searched and I didn't find why this should be the issue.
If you want, you can download the files from my repo: https://github.com/Atotem/Game.git . There you will understand what i mean. I'm open to all suggestions.
PD: I'm using p5.js libraries.

Related

Phaser 3 Tweens with changing variable value

I'm building an HTML5 game with Phaser 3. I have a counter tween that I add to the scene upon a certain if condition being met on click of a game object. (It is a text value that flashes red if the card's maximum stat value is lower than the player's value of that stat.)
First, I set the variable based on which card was clicked:
if (this == action1_card) {
action = action1
energy_cost = action1_energy_cost
max_suspicion = action1_suspicion_threshold
selected_card = action1_card_selected
} else if (this == action2_card) {
action = action2
energy_cost = action2_energy_cost
max_suspicion = action2_suspicion_threshold
selected_card = action2_card_selected
}
Once I have the values I want (max suspicion is the relevant variable in this case), I then apply the flashing color animation to it if the condition is met.
if (action.suspicion_threshold < game_data.player.stats.suspicion) {
t.tweens.addCounter({
from: 0,
to: 100,
duration: 250,
repeat: 1,
yoyo: true,
ease: Phaser.Math.Easing.Sine.InOut,
onUpdate: function(tween) {
const value = Math.floor(tween.getValue());
const colorObject = Phaser.Display.Color.Interpolate.ColorWithColor(
Phaser.Display.Color.ValueToColor('#000000'),
Phaser.Display.Color.ValueToColor('#FF0000'),
100,
value
)
const color = Phaser.Display.Color.RGBToString(colorObject.r, colorObject.g, colorObject.b)
max_suspicion.setColor(color);
}
});
The issue is that, if I was to click on card 1 and then card 2 before the animation was finished on card 1, the animation from card 1's text would resume on card 2. This makes sense, as the variable "max_suspicion" was reassigned to the text object on card 2, and the tween's onUpdate function is continuing as it should.
How do I either:
1) prevent this from being reassigned (e.g. setting max_suspicion to permanently represent card 1's text object for the scope of the tween)
or
2) reset card 1's value to it's original color and end the tween prematurely so it doesn't carry over to card 2?
I will gladly clarify anything as needed. Thank you so much for any help on this!
It depends on your code, what the best solution is. (and ofcourse the desired gameplay)
I personally would put the tween in a variable:
this.mytween = scene.tweens.addCounter(...);
and stop it on click before i do anything else
if(this.mytween) {// just checking if it exists
this.mytween.stop();
... // may be reset the color
}

ChartJS hover/tooltips: selecting the correct points in the datasets based on x-value

I'm using ChartJS (v 2.9.4) and I want the hover interaction / tooltip system (they work the same way from what I can tell) to select the point nearest (relative to the x axis) to the mouse pointer on all datasets.
Now, if the x-axis of the chart is operating in the default category mode (i.e.: data points with the same index in the dataset have the same position on the x-axis) this is easily achieved with this configuration:
options: {
hover: {
mode: 'index',
intersect: false
}
//other options...
}
However, if the x-axis is of type linear (i.e.: each data point in each dataset has a specific x-value) this doesn't work properly, since the decision on which point to select is based on its index in the dataset, rather than its x-axis value.
I've created an example here:
https://jsfiddle.net/parhwv73/5/
as you can see by hovering the mouse around, you can easily find yourself in situations like this, where the points selected in the two datasets are very far apart:
while what I would like is this:
in other words: I would like to select the point in each dataset nearest to the mouse pointer (relative to the x-axis).
I've tried playing around with the mode and intersect options, but I found no combination that works, mainly because most other modes only select a point in one single dataset, rather than all of them, index mode is the closest one to being correct, but not quite as I've explained.
Is there a way to achieve this natively?
Or if there isn't, can anyone give some pointers on how to implement a plugin of some sort that can achieve this?
If someone has the same problem in a more recent version (like 3.7.0), you can just modify the interaction mode: instead of 'index', use this:
options: {
interaction: {
intersect: false,
mode: 'nearest',
axis: 'x'
},
}
found on the docs
Well, in the end I had to modify the ChartJS source code to achieve this. Fortunately, it wasn't too hard. All I had to do was add this function to the core.interaction.js file:
function xPositionMode(chart, e, options) {
var position = getRelativePosition(e, chart);
// Default axis for index mode is 'x' to match old behaviour
options.axis = options.axis || 'x';
var distanceMetric = getDistanceMetricForAxis(options.axis);
var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);
var elements = [];
if (!items.length) {
return [];
}
const findClosestByX = function(array, element) {
let minDiff = -1;
let ans;
for (let i = 0; i < array.length; i++) {
var m = Math.abs(element._view.x - array[i]._view.x);
if (minDiff === -1 || m < minDiff) {
minDiff = m;
ans = array[i];
}
}
return ans;
}
chart._getSortedVisibleDatasetMetas().forEach(function(meta) {
var element = findClosestByX(meta.data, items[0]);
// don't count items that are skipped (null data)
if (element && !element._view.skip) {
elements.push(element);
}
});
return elements;
}
This is basically a modified version of the indexMode function present in the same file, but instead of searching items by their index in the dataset it searches the closest items by their horizontal position on the canvas (see the findClosestByX inner function for the search algorithm)
To make this usable, you also have to add the new mode in the list of exports (in the same file):
module.exports = {
// Helper function for different modes
modes: {
xPosition: xPositionMode,
//Rest of the original code...
}
}
Once this is done, recompile the ChartJS library and use it instead of the original one. Now you can use the new mode like this:
options: {
hover: {
mode: 'xPosition',
intersect: false
}
//other options...
}
Note: all code in this answer refers to the 2.9.4 version of the ChartJS library, it might not work the same for 3.x versions.

Aframe raycaster does not hit after changing enabled or objects properties

I want my raycaster to look for intersections only when the trigger of my vive controller is pressed.
I thought to initialize the raycaster with a fake class in objects, change it to the real one .prop and gather the intersectedEls
let rightHand = document.getElementById('rightController');
rightHand.setAttribute('line', 'color: purple; opacity: 1;');
rightHand.setAttribute('raycaster', { showLine: true, objects: '.none' });
rightHand.setAttribute('cursor', { downEvents: ['triggerdown'], upEvents: ['triggerup'], rayOrigin: 'entity', fuse: false });
let scene = document.getElementById('scene');
scene.addEventListener('triggerdown', this.myTriggerDown);
scene.addEventListener('triggerup', this.myTriggerUp);
myTriggerDown() {
let rightHand = document.getElementById('rightController');
rightHand.setAttribute('raycaster', { showLine: true, objects: '.prop' });
rightHand.components['raycaster'].refreshObjects();
let raycaster = rightHand.components['raycaster'];
let intersectedEls = raycaster.intersectedEls;
if (typeof intersectedEls !== 'undefined' && intersectedEls.length > 0) {
scene.components['resize'].enableResize(intersectedEls[0]);
} else {
console.log('1234 no intersections')
}
}
myTriggerUp() {
let rightHand = document.getElementById('rightController');
rightHand.setAttribute('raycaster', { showLine: true, objects: '.none' });
}
Unfortunately I keep getting the console.log('1234 no intersections') message.
I tried adding the refreshObjects() line with no effects.
I tried toggling the enabled property instead of changing the objects, but had still the same result.
Any help would be appreciated. Thanks
edit:
if I look for intersections in the triggerup part it works. but this is a workaround which also deprives me of using the intersected element and doing things while keeping the trigger pressed . I'd still like to know why it does not work to enable the ray/change target objects and immediately look for intersections.
I recommend using the raycaster.enabled property versus swapping to a dummy class.
The raycaster checks for intersections once per frame (or whatever the raycaster.interval is). On trigger down, you enable the raycaster, but you have to wait until the next frame for it to pick up intersections.
You can manually invoke intersection check via raycaster.checkIntersections() or run a setTimeout before checking.

Error 1105: Target of Assignment must be a Reference Value

Flash says the code is on my second line, but I've done some reading and it says this error is mainly due to me trying to assign a value to a value, and I've looked back over my code, and I can't seem to find any instance of this.
Here is my code:
this.mc=new MovieClip();
addChild(mc)=("myButton1", this.DisplayOBjectContainer.numChildren());
myButton1.createEmptyMovieClip("buttonBkg", myButton1.getNextHighestDepth());
myButton1.buttonBkg.lineStyle(0, 0x820F26, 60, true, "none", "square", "round");
myButton1.buttonBkg.lineTo(120, 0);
myButton1.buttonBkg.lineTo(120, 30);
myButton1.buttonBkg.lineTo(0, 30);
myButton1.buttonBkg.lineTo(0, 0);
Thanks!
Check what you are trying to in these lines:
addChild(mc)=("myButton1", this.DisplayOBjectContainer.numChildren());
myButton1.createEmptyMovieClip("buttonBkg", myButton1.getNextHighestDepth());
To create an empty MovieClip, you can just create a new display object w/o linking it to a clip in the library like this:
addChild(mc);
var myButton1:MovieClip = new MovieClip(); // creates an empty MovieClip
addChildAt(myButton1, numChildren); // adds the MovieClip at a defined level (on this case, the numChildren added on stage
Your code is very confusing. You mix AS2 methods (createEmptyMovieClip, getNextHighestDepth) with AS3 methods (addChild). Here is what you are trying to do:
const MC:Sprite = new Sprite(); // Sprite container
this.addChild(MC);
const MYBUTTON1:Sprite = new Sprite(); // button in container
MC.addChild(MYBUTTON1);
const BUTTONBKG:Shape = new Shape(); // background in button
MYBUTTON1.addChild(BUTTONBKG);
const BTG:* = BUTTONBKG.graphics;
BTG.beginFill(0x86B1FB);
BTG.lineStyle(0, 0x820F26, 0.6, true, "none", "square", "round");
BTG.lineTo(120, 0);
BTG.lineTo(120, 30);
BTG.lineTo(0, 30);
BTG.lineTo(0, 0);
MYBUTTON1.addEventListener(MouseEvent.CLICK, pressButton);
function pressButton(e:MouseEvent):void {
trace('I click on you');
}
Notes : the alpha value in AS3 is between 0 and 1. If you want your button to be clickable, you should use beginfill method.

Save series chart type for later use

This may be more of a scope question than a HighCharts question.
I have a function that changes the chart type, please see below:
function ChangeChartType(chart, newType) {
newType = newType.toLowerCase();
var numberofseries = chart.series.length;
var i = 0;
if (newType == 'reset') {
for (i; i < numberofseries; i++) {
if (typeof chart.series[i].defaulttype == 'string') {
chart.series[i].update({
type: chart.series[i].defaulttype
});
}
}
} else {
for (i; i < numberofseries; i++) {
if (typeof chart.series[i].defaulttype != 'string') {
chart.series[i].defaulttype = chart.series[i].type; //The new property does not survive
}
chart.series[i].update({
type: newType
});
}
}
}
I am trying to create a new property on the series objects named "defaulttype" in order to save the chart type that was set when the chart was created. When a "Reset" button is clicked I want to change the chart type back to what is stored in the property.
The problem is the new property disappears outside of the function. What am I missing? Any help would be appreciated.
I created a fiddle to demonstrate the entire issue. http://jsfiddle.net/xeRRS/9/
You can also setup a default type in the chart object, then in your custom function refer to the Highcharts.charts[0] object (keeping your chart), extracting default serie from userOptions.
Highcharts.charts[0].userOptions.chart.defaultType
Example: http://jsfiddle.net/xeRRS/8/
Based on your code, a simple way to achieve your objective is to store the "defaultType" (camel casing helps see in the desert) property against the chart variable as it looks like the series array is overwritten somewhere inside the library. Here is the working version of your code http://jsfiddle.net/4ecHP/
On a different note, adding a property to an object where it is not clear on what is happening inside that object is a bit dangerous (the chart object may have a defaultType property already), instead you can store the defaultType as a global variable or create a _settings object in the window object and store all your chart settings there like
_settings={
height: 500,
spacingLeft: -35,
spacingRight: 12,
type: 'line',
zoomType: 'xy',
defaultType: null
}
In this case, on reset you can call chart.series[i].update({type: _settings.defaultType});

Categories