I’m writing a simple platformer game. I use tiled maps to create level layers for overlaps and collisions. I’m stuck with a problem: I’m trying to make player be able to climb the ladder when overlap with ladder tile happens.
I have a variable in gameSettings object playerMoveY: false (so by default player can only walk left or right)
When player overlaps the ladder tile he's able to climb but after that he's always able to climb because variable playerMoveY is still = true. I don't know how to switch it back. Maybe using the flag is not a good idea. I need advice. Thank you.
let gameSettings = {
playerSpeed: 60,
playerMoveY: false,
}
//here's the code from gameScene class
this.laddersLayer.setTileIndexCallback(29, this.allowClimb, this);
this.physics.add.overlap(this.player, this.laddersLayer);
movePlayerManager() {
if (this.cursorKeys.left.isDown) {
this.player.anims.play('playerWalkLeft', true);
this.player.setVelocityX(-gameSettings.playerSpeed);
} else if (this.cursorKeys.right.isDown) {
this.player.anims.play('playerWalkRight', true);
this.player.setVelocityX(gameSettings.playerSpeed);
} else {
this.player.setVelocityX(0);
this.player.anims.play('playerStand');
}
if (gameSettings.playerMoveY) {
if (this.cursorKeys.up.isDown) {
this.player.anims.play('playerClimb', true);
this.player.setVelocityY(-gameSettings.playerSpeed);
} else if (this.cursorKeys.down.isDown) {
this.player.anims.play('playerClimb', true);
this.player.setVelocityY(gameSettings.playerSpeed);
} else {
this.player.setVelocityY(0);
}
}
}
//and here's the callback function when overlap
allowClimb() {
gameSettings.playerMoveY = true;
}
You currently only check if the player is overlapping the ladder, and subsequently setting:gameSettings.playerMoveY = true;. You need a check for other types of tiles. I've never used tiled so I don't know how it works but I would suggest trying to implement something like this in the update function:
//this is just sudo code
if(player.byLadder() == true){
player.canClimb = true;
}else{
player.canClimb = false;
}
The player.byLadder() function would somehow have to return true at all times the player can climb (before climbing, while climbing, at the end of the climb). Again, I apologize for not having more concrete code as I've never touched Tiled.
Related
I'm currently trying to render a specific class across two lightning-badge components that is suppose to change both badges from inverse to success, but am getting this instead:
When the value on the left badge equals the value on the right (so in this case both are 3), they should both be green, otherwise they should both be grey. They should never be seperate colours.
The value on the left increases as the user saves a record and is checked on status of "Completed". For some reason only the class on the second badge is being updated with the new class that includes slds-theme_success. I may be missing something small, but just haven't been able to figure it out. Please see code below:
badgeClass = "slds-badge_inverse slds-var-m-horizontal_x-small slds-col";
get patientsCompleted() {
if(this.records) {
let completedArr = this.records.filter(value => value.fields.Status__c.value == "Completed");
if(completedArr.length === this.patientsTotal) {
this.badgeClass = "slds-badge_inverse slds-theme_success slds-var-m-horizontal_x-small slds-col";
}
return completedArr.length;
}
};
get patientsTotal(){
if(this.records) {
return this.records.length;
}
};
<span class="slds-col_bump-left">
<div class="slds-grid slds-gutters">
<lightning-badge class={badgeClass} label={patientsCompleted}></lightning-badge>
<div class="slds-col"> of </div>
<lightning-badge class={badgeClass} label={patientsTotal}></lightning-badge>
</div>
</span>
Have you tried moving badgeClass to a getter? Something like this:
get patientsCompleted() {
if(this.records) {
let completedArr = this.records.filter(value => value.fields.Status__c.value == "Completed");
// No longer needed
// if(completedArr.length === this.patientsTotal) {
// this.badgeClass = "slds-badge_inverse slds-theme_success slds-var-m-horizontal_x-small slds-col";
// }
return completedArr.length;
}
};
get patientsTotal(){
if(this.records) {
return this.records.length;
}
};
get badgeClass() {
let baseClass = "slds-badge_inverse slds-var-m-horizontal_x-small slds-col";
return this.patientsCompleted === this.patientsTotal ? `${baseClass} slds-theme_success` : `${baseClass}`
}
I suspect LWC field tracking has some precautionary mechanism and didn't trigger the update.
I am not sure but perhaps if 0 records are available you want the badges to remain gray? In that case include this.patientsTotal > 0 in the get badgeClass() {...}.
Happy coding.
I am using multiple off campus menus on my site. So as a user clicks on a certian link to a store they can get a off campus menu with information pertaining to that particular store. I am trying to minimize the JS code so that I don't have a open and close function for each span link that opens and closes a menu. I have tried to create one function that will different menus as to follow a DRY coding practice. I initially tried a switch statement but this only partially worked and I am left at a dead end. Any assistance would be appreciated. Thank you and have a blessed day.
// // prj 1
function workOpenNav() {
document.getElementById('prjOne').style.width = '100%';
}
function workCloseNav() {
document.getElementById('prjOne').style.width = '0%';
}
// // prj 2
function workTwoOpenNav() {
document.getElementById('prjTwo').style.width = '100%';
}
function workTwoCloseNav() {
document.getElementById('prjTwo').style.width = '0%';
}
// // prj 3
function workThreeOpenNav() {
document.getElementById('prjThree').style.width = '100%';
}
function workThreeCloseNav() {
document.getElementById('prjThree').style.width = '0%';
}
<span class="wrk-link span-title" style="cursor:pointer" onclick="workOpenNav()">
Store #1
</span>
<div id="prjOne" class="wrk-overlay overLay">
// Content
</div>
<span class="wrk-link span-title" style="cursor:pointer" onclick="workTwoOpenNav()">
Store #2
</span>
<div id="prjTwo" class="wrk-overlay overLay">
// Content
</div>
<span class="wrk-link span-title" style="cursor:pointer" onclick="workThreeOpenNav()">
Store #3
</span>
<div id="prjThree" class="wrk-overlay overLay">
// Content
</div>
Let's walk through this together. Take these first two functions:
function workOpenNav() {
document.getElementById('prjOne').style.width = '100%';
}
function workCloseNav() {
document.getElementById('prjOne').style.width = '0%';
}
Let's find what they have in common, and turn what they do not have in common into input variables. In this case, the percentage is the only thing different. So:
function workNav(pct) {
document.getElementById('prjOne').style.width = pct;
}
This one function now does the work of two. The other functions you have can similarly be combined into a single function with one input. Let's do that now:
function workTwoNav(pct) {
document.getElementById('prjTwo').style.width = pct;
}
function workThreeNav(pct) {
document.getElementById('prjThree').style.width = pct;
}
But we're not done! Notice that these three functions I've made have mostly everything in common, only the control ID is different. Let's turn that into another parameter!
function workNav(id, pct) {
document.getElementById(id).style.width = pct;
}
Now, all of your functions have been reduced to a single function, which can be called like so:
workNav("prjOne", "100%");
Now, we're still not quite done. Let's clean this up and make it more clear. Your function is intended to show or hide the indicated element, right? So let's rename it to make that intent more clear, and let's tweak the second parameter a bit:
function showNav(id, show) {
document.getElementById(id).style.width = show ? "100%" : "0%";
}
Now, it can be used accordingly. To show:
showNav("prjOne", true)
And to hide:
showNav("prjOne", false)
Why turn the second parameter into a true/false? It will be easier for the programmer to get right. "100%" it would be pretty easy to drop a 0, or the percentage sign. Those typos won't generate an error in your browsers console, but if you make a typo like tru, you'll get an error, which you can then fix. Things are easier to fix when the error is made apparent. Ultimately this change comes down to programmer preference, and isn't necessary to achieve your goals. Would you ever set the width to 50%, or is it always all-or-nothing? Clearer intent is achieved using the boolean.
Need to know how I could possibly save the state of the darkmode?
I got this js code right here:
$('#switch').on('click', () => {
if ($('#switch').prop('checked')) {
$('body').addClass('dark');
$('main').addClass('darklight');
$('footer').addClass('darklight');
$('.topnav').addClass('darklight');
$('.lightm').addClass('darklight');
$('section').addClass('darklight');
$('button').addClass('button');
$('.links').addClass('llinks');
} else {
$('body').removeClass('dark');
$('body').addClass('light');
$('main').removeClass('darklight');
$('main').addClass('light');
$('footer').removeClass('darklight');
$('footer').addClass('light');
$('.topnav').removeClass('darklight');
$('.topnav').addClass('light');
$('.lightm').removeClass('darklight');
$('.lightm').addClass('light');
$('section').removeClass('darklight');
$('section').addClass('light');
$('button').removeClass('button');
$('button').addClass('dbutton');
$('.links').removeClass('llinks');
$('.links').addClass('dlinks');
}
})
Here is the code in Codepen with the html and css things:
https://codepen.io/TRGYT/pen/eYmNBPo
Does anyone have idea on how to achieve this? And can this darkmode state also be saved for other sites I created?
Please find the site here:
https://15min.netlify.com
Sorry in advance for the bad code, I'm a beginner...
Welcome to the world of coding. Before we get to the problem, it will be of some use to you to get to grips with the DRY principle (Don't Repeat Yourself). Your code (20 or so lines) could easily be abbreviated to just four. For example:
$("#switch").on("click", () => {
$("body").toggleClass("dark"));
// Local storage. Will get to this later
});
You could then change your CSS to respond to whether or not the body tag has the dark class. Much cleaner.
As for saving the state of the dark mode: use window.localStorage like so:
if (window.localStorage) {
const darkMode = window.localStorage.getItem("darkMode");
if (darkMode) {
$("body").addClass("dark");
} else {
$("body").removeClass("dark");
}
}
I found a way that wored. The one answer I got helped me understand it, but I was too lazy to implement it. But still thank you!
function activateDarkMode() {
$('body').addClass('dark').removeClass('light');
$('main').addClass('darklight').removeClass('light');
$('footer').addClass('darklight').removeClass('light');
$('.topnav').addClass('darklight').removeClass('light');
$('.lightm').addClass('darklight').removeClass('light');
$('section').addClass('darklight').removeClass('light');
$('button').addClass('button').removeClass('button');
$('.links').addClass('llinks').removeClass('dlinks');
}
function deactivateDarkMode() {
$('body').removeClass('dark').addClass('light');
$('main').removeClass('darklight').addClass('light');
$('footer').removeClass('darklight').addClass('light');
$('.topnav').removeClass('darklight').addClass('light');
$('.lightm').removeClass('darklight').addClass('light');
$('section').removeClass('darklight').addClass('light');
$('button').removeClass('button').addClass('dbutton');
$('.links').removeClass('llinks').addClass('dlinks');
}
$('#switch').on('click', () => {
if ($('#switch').prop('checked')) {
activateDarkMode();
localStorage.setItem("darkmode", "enabled")
} else {
deactivateDarkMode();
localStorage.setItem("darkmode", "disabled")
}
});
let mode;
mode = localStorage.getItem("darkmode");
if (mode == 'enabled') {
activateDarkMode();
$('#switch').prop('checked', 'checked');
}
All I did was putting the addClass and removeClass into a function. He also added the localStorage and let the localStorage be in a variable called mode. After I created these things, I put them into an if to check if the darkmode is turned on or not.
Is there any simple way how to create undo redo function in Kineticjs ?
I have found a Undo Manager for HTML 5 in https://github.com/ArthurClemens/Javascript-Undo-Manager, but I don't know how to put in Kineticjs, please help me.
thank you.
I was able to implement a simple solution based on a post by Chtiwi Malek at CodiCode. I also used some of the code from this problem as an example to draw rectangles, so credits go to them and Chtiwi.
The only difference in my solution is I used toJSON() to store each layer state in an array instead of toDataURL() on the canvas. I think toJSON() is needed over toDataURL() to be able to serialize all the data necessary to store each action on the canvas, but I'm not 100% on this so if someone else knows please leave a comment.
function makeHistory() {
historyStep++;
if (historyStep < history.length) {
history.length = historyStep;
}
json = layer.toJSON();
history.push(json);
}
Call this function everytime you want to save a step to undo or redo. In my case, I call this function on every mouseup event.
Bind these 2 functions to the Undo/Redo events.
function undoHistory() {
if (historyStep > 0) {
historyStep--;
layer.destroy();
layer = Kinetic.Node.create(history[historyStep], 'container')
stage.add(layer);
}
}
function redoHistory() {
if (historyStep < history.length-1) {
historyStep++;
layer.destroy();
layer = Kinetic.Node.create(history[historyStep], 'container')
stage.add(layer);
}
}
Here's the jsfiddle. Don't forget to initialize the array and step counter up top. Good luck!
I am not familiar with KineticJS, but the approach should be similar to the provided demo (that also uses a canvas).
Perhaps another example helps. Let's say I have an app to create/move/delete colored shapes that represent musical notes. I have a way to click-drag and highlight a selection of notes. Pressing Delete on the keyboard invokes the function onDeleteGroup:
onDeleteGroup: function(gridModel) {
// collect all notes in an array
// ...
this._deleteGroup(notes);
this.undoManager.register(
this, this._createGroup, [notes], 'Undo delete',
this, this._deleteGroup, [notes], 'Redo delete'
);
}
All notes are deleted, and 2 methods are registered with the undo manager:
The undo function (undo of delete will be create)
The redo function (after undo/create will be delete again)
Both functions are straightforward:
_deleteGroup:function(notes) {
// removes each note from the model
// thereby removing them from the canvas
// ...
}
_createGroup:function(notes) {
// add each note to the model
// thereby adding them to the canvas
// ...
}
As you can see, the data object (array of notes) is passed around for creation and deleting. You can do the same for manipulating singular objects.
i have written a class for the functionality:
http://www.sebastianviereck.de/en/redo-undo-class-kinetic-js/
To solve event listeners problem, work on by making clones
$scope.makeHistory=function() {
$scope.historyStep++;
if ($scope.historyStep < $scope.history.length) {
$scope.history.length = $scope.historyStep;
}
var layerC = $scope.topLayer.clone();
$scope.history.push(layerC);
};
$scope.undoObject = function(){
if($scope.historyStep > 0) {
$scope.historyStep--;
$scope.topLayer.destroy();
if($scope.historyStep==0){
$scope.topLayerAdd(2); // will put empty layer
}
else{
var layer = $scope.history[$scope.historyStep-1].clone();
$scope.topLayerAdd(1,layer);
}
$scope.topLayer.draw();
}
};
$scope.redoObject = function(){
if($scope.historyStep <= $scope.history.length-1) {
$scope.historyStep++;
$scope.topLayer.destroy();
var layer = $scope.history[$scope.historyStep-1].clone();
if($scope.historyStep==0){
$scope.topLayerAdd(2); // will put empty layer
}
else{
$scope.topLayerAdd(1,layer);
}
$scope.topLayer.draw();
}
};
works perfectly for me.
I have made a simple accordion for my site using jQuery... It worked great, but I've recently started working on a change where if you click the currently opened segments title (the clickable area to slide up/down), it should close the current section.
var sideMenu = {
activated: {},
setup: function() {
$('.menu-category-heading').bind('click', function() {
sideMenu.slideMenu($('ul', $(this).parent()));
});
},
slideMenu: function(menuObj) {
if (sideMenu.activated == menuObj) {
$(sideMenu.activated).slideUp(400);
sideMenu.activated = null;
console.log('same');
} else {
$(sideMenu.activated).slideUp(400);
menuObj.slideDown(500);
sideMenu.activated = menuObj;
console.log('new');
}
}
}
For some reason the comparison is never working... it does if I add $(menuObj).attr('id') and the same for activated. But this is not ideal as not all items will have an id attribute.
Any suggestions as to make the object comparison work? Or any other tips?
Thank you!
You are probably saving a jQuery object (the result of a $ call) rather than the native element. Each time you do a $(myEl) a new object is created and the references will not match up, but the native element will. Try:
if (slideMenu.activated[0] == menuObj[0]) {
...
}