I am programming a game and am having trouble with variables and inheritance, whenever I try to access them in the inherited class they come up as undefined. I have tried using super to help with the problem but that has not worked, this may be because I am relatively new to JavaScript.
The variables work in the base class but do not work in the subclass.
This is the inherited class
This is the Base Class.
Just to clarify the question I am asking why the variables come up as undefined in the subclass but not in the base class and how I can fix this. Thanks!
The code is clearer in the pictures.
class charachter {
constructor(xPos, yPos) {
this.rightVelocity = 0;
this.leftVelocity = 0;
this.upVelocity = 0;
this.downVelocity = 0;
this.xyCordsRaw = [xPos, yPos];
this.xyCordsBlock = [Math.round(this.xyCordsRaw[0] / 50),
Math.round(this.xyCordsRaw[1] / 100)
]
}
updateCharachter() {
ctx.drawImage(charachterRight, this.xyCordsRaw[0],
this.xyCordsRaw[1])
}
findTileStandingOnType() {
return
solidObjects.includes(biome[this.xyCordsBlock[1] + 1][this.xyCordsBlock[0]])
}
isOnTheGround() {
return this.findTileStandingOnType() == true &&
this.xyCordsRaw[1] == (this.xyCordsBlock[1] * 100) + 25
}
isTileAbove() {
return solidObjects.includes(biome[this.xyCordsBlock[1] - 1]
[this.xyCordsBlock[0]])
}
isTouchingTileAbove() {
return this.isTileAbove() == true && this.xyCordsBlock[1] * 100 == this.xyCordsRaw[1]
}
isWallLeft() {
return solidObjects.includes(biome[this.xyCordsBlock[1]][this.xyCordsBlock[0] - 1])
}
isWallRight() {
return solidObjects.includes(biome[this.xyCordsBlock[1]][this.xyCordsBlock[0] + 1])
}
isTouchingWallRight() {
return this.isWallRight() == true && this.xyCordsBlock[0] * 50 == this.xyCordsRaw[0]
}
isTouchingWallLeft() {
return this.isWallLeft() == true && this.xyCordsBlock[0] * 50 == this.xyCordsRaw[0]
}
}
class playerChar extends charachter {
constructor(xPos, yPos, leftVelocity, rightVelocity, upVelocity, downVelocity, xyCordsRaw, xyCordsBlock) {
super(xPos, yPos, leftVelocity, rightVelocity, upVelocity, downVelocity, xyCordsRaw, xyCordsBlock);
document.addEventListener('keydown', this.takeInput);
}
takeInput(e) {
if (e.code == 'KeyA') {
console.log(this.leftVelocity);
}
if (e.code == 'KeyW') {
console.log("The letter W was pressed");
}
if (e.code == 'KeyD') {
console.log(this.xyCordsRaw);
}
}
}
var player = new playerChar(150, 325);
The immediate problem that presents itself is the use of this in event listeners.
document.addEventListener('keydown', this.takeInput);
passes a reference to the takeInput function object when calling addEventListener, and because it's an event handler of document, takeInput will have a this value of document when called. Try
document.addEventListener('keydown', this.takeInput.bind(this));
to begin with to see what difference it makes.
The next error to correct is to the line feed after return in
findTileStandingOnType(){
return
solidObjects.includes(biome[this.xyCordsBlock[1]
This should be
findTileStandingOnType(){
return solidObjects.includes(biome[this.xyCordsBlock[1] + 1][this.xyCordsBlock[0]])}
Return statements without a semi-colon separator only continue on the next line if it would be a syntax error if they didn't. That is not the
case here.
Related
I want the user to be able to press a+d once and my game should increase the score, not hold it to increase score, similar to when pressing a+d causes a special effect to occur in a game.
This code did not work so I didn't bother to call it fail attempts test.
function keyPressed() {
if (key == 'a' && key == 'd')
score += 1;
}
This is my first failing attempt:
function keyPressed() {
if (key == 'a' || key == 'd')
score += 1;
}
This is my second failing attempt.
The reason for it is because when I press 1 button, it still increases the score and when pressing 2 buttons and holding them to increase faster but does not stop, which is not what I have in mind.
Score2keypress.js:
let RightButtom = false;
let LeftButtom = false;
let character = {
"score": 0
}
function setup() {
createCanvas(600, 600);
}
function draw() {
background(220);
// draw score character
fill(0, 0, 255); //move6
text("Score: " + character.score, 20, 120);
// update score increase character
if (RightButtom) {
character.score += 1;
} //move8
if (LeftButtom) {
character.score += 1;
} //move10
/////////////ScoreExtra
// show boolean values onscreen for clarity
textSize(20);
text("RightButtom = " + RightButtom +
"\nLeftButtom = " + LeftButtom, 10, 10, width / 2, height / 2);
}
//////////////ScoreExtra
function keyPressed() {
if (key == 'a') {
LeftButtom = true;
}
if (key == 'd') {
RightButtom = true;
}
}
function keyReleased() {
if (key == 'a') {
LeftButtom = false;
}
if (key == 'd') {
RightButtom = false;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.1/p5.js"></script>
There are a few approaches. The event-driven approach is using p5's keyPressed and keyReleased callbacks, pulling the key's code string from the native KeyboardEvent object. Adding and removing these key codes to a pressed set lets you implement variants of single-trigger logic.
const character = {score: 0};
const pressed = new Set();
function setup() {
createCanvas(600, 600);
textSize(20);
}
function draw() {
background(220);
text("Score: " + character.score, 20, 50);
}
function keyPressed(evt) {
const {code} = evt;
if (!pressed.has(code)) {
pressed.add(code);
if (pressed.has("KeyA") && pressed.has("KeyD")) {
character.score++;
}
}
}
function keyReleased(evt) {
pressed.delete(evt.code);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
If you want to detect and take action purely in draw, p5.js provides keyIsDown which accepts a parameter keycode.
const character = {score: 0};
const pressed = new Set();
function setup() {
createCanvas(600, 600);
textSize(20);
}
function draw() {
background(220);
text("Score: " + character.score, 20, 50);
if (keyIsDown(65) && keyIsDown(68)) {
if ((keyIsDown(65) && !pressed.has(68)) ||
(!pressed.has(65) && keyIsDown(68))) {
character.score++;
}
pressed.add(65);
pressed.add(68);
}
if (!keyIsDown(65)) {
pressed.delete(65);
}
if (!keyIsDown(68)) {
pressed.delete(68);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
As mentioned, there are multiple behavioral variants you can implement. Here's a variant that prevents retriggers with the same key:
const character = {score: 0};
const pressed = new Set();
function setup() {
createCanvas(600, 600);
textSize(20);
}
function draw() {
background(220);
text("Score: " + character.score, 20, 50);
if (keyIsDown(65) && !pressed.has(65) && // 'a' and 'd'
keyIsDown(68) && !pressed.has(68)) {
character.score++;
pressed.add(65);
pressed.add(68);
}
if (!keyIsDown(65)) {
pressed.delete(65);
}
if (!keyIsDown(68)) {
pressed.delete(68);
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.5.0/p5.js"></script>
In all above cases, the behavior lets the user press and hold one key indefinitely, then press the other. If you want these keys to be pressed on the exact same frame, or within n frames, you could remove the key from the set after it's been in there for n frames and add it to a requireRetrigger set that will prevent it from firing an action until it's been released. keyReleased might be handy here.
To detect to keys pressed together you need to monitor their state using keydown and keyup events.
var obj_down = {}
window.addEventListener("keydown", function(ev) {
if (obj_down[event.key]) {
// prevent multiple triggering
return
}
obj_down[event.key] = true;
if (obj_down["a"] && obj_down["d"]) {
console.log("a and d were pressed together! score++");
}
})
window.addEventListener("keyup", function(ev) {
delete obj_down[event.key];
})
Focus me with mouse then you can press "a" and "d" together
I have this code which makes a square move, but when i for example press the right arrow key then the left arrow key and release the right arrow key, the square pauses for a while and then just moves the left.
is there a way to get rid of this pause?
this is the code i have now:
let velocity = 10
let x = 375
let y = 225
setInterval(function(){
document.getElementById("square").style.left = x + "px";
document.getElementById("square").style.top = y + "px";
}, 1)
var direction = ""
function currentDirection(movingToDirection){
if(movingToDirection != direction){
return true
}
else {
return false
}
}
function Sup() {
if(currentDirection("Sup")){
direction = "Sup";
var Sloopup = setInterval(function(){
y -= velocity/10
}, 1)
window.Sloopup = Sloopup
}
}
function Sdown() {
if(currentDirection("Sdown")){
direction = "Sdown";
var Sloopdown = setInterval(function(){
y += velocity/10
}, 1)
window.Sloopdown = Sloopdown
}
}
function Sleft() {
if(currentDirection("Sleft")){
direction = "Sleft";
var Sloopleft = setInterval(function(){
x -= velocity/10
}, 1)
window.Sloopleft = Sloopleft
}
}
function Sright() {
if(currentDirection("Sright")){
direction = "Sright";
var Sloopright = setInterval(function(){
x += velocity/10
}, 1)
window.Sloopright = Sloopright
}
}
function Break(Function) {
direction = ""
if (Function = "Sup") {
clearInterval(window.Sloopup)
} if (Function = "Sdown") {
clearInterval(window.Sloopdown)
} if (Function = "Sleft") {
clearInterval(window.Sloopleft)
} if (Function = "Sright") {
clearInterval(window.Sloopright)
}
}
document.addEventListener("keydown", event => {
if(event.key==="ArrowUp") {Sup()}
if(event.key==="ArrowDown") {Sdown()}
if(event.key==="ArrowLeft") {Sleft()}
if(event.key==="ArrowRight") {Sright()}
})
document.addEventListener("keyup", event => {
if(event.key==="ArrowUp") {Break("Sup")}
if(event.key==="ArrowDown") {Break("Sdown")}
if(event.key==="ArrowLeft") {Break("Sleft")}
if(event.key==="ArrowRight") {Break("Sright")}
})
and I also have a online example:
Online example
Any help is very appreciated!
Try this:
var Keys = {
up: false,
down: false,
left: false,
right: false
};
let y = 10;
let x = 10;
document.addEventListener("keydown", (event) => {
if (event.key === "ArrowLeft") Keys.left = true;
else if (event.key === "ArrowUp") Keys.up = true;
else if (event.key === "ArrowRight") Keys.right = true;
else if (event.key === "ArrowDown") Keys.down = true;
});
document.addEventListener("keyup", (event) => {
if (event.key === "ArrowLeft") Keys.left = false;
else if (event.key === "ArrowUp") Keys.up = false;
else if (event.key === "ArrowRight") Keys.right = false;
else if (event.key === "ArrowDown") Keys.down = false;
});
setInterval(() => {
if (Keys.up) {
y -= 1;
} else if (Keys.down) {
y += 1;
}
if (Keys.left) {
x -= 1;
} else if (Keys.right) {
x += 1;
}
}, 1);
setInterval(() => {
document.getElementById("app").style.left = x + "px";
document.getElementById("app").style.top = y + "px";
}, 1);
There might be some delay when you clear and set a new interval. Here I set 2 interval that keep listening to keydown, which you will need to clear later when the game ends
Here's the sandbox
so below my suggestion if I understand well your problem:
document.addEventListener("keydown", event => {
// the issue occurs here, you have to disable all current keydown event
Break("Sup");Break("Sdown");Break("Sleft");Break("Sright");
if(event.key==="ArrowUp") {Sup()}
if(event.key==="ArrowDown") {Sdown()}
if(event.key==="ArrowLeft") {Sleft()}
if(event.key==="ArrowRight") {Sright()}
})
BTW i tested it & it works, i hope that it helps you.
Good luck!
as well as we separate content from style same concept applies in different layers of the engine you need to separate the logic from the engine as well. The idea is separation so you can implement/debug much easier. Example code below:
const velocity = {x:0, y:0}
const position = {x:375, y:225}
const keys = { ArrowLeft:false, ArrowRight:false, ArrowUp:false, ArrowDown:false }
function UpdatePlayerInput()
{
velocity.x = ((+keys.ArrowRight) - (+keys.ArrowLeft)) * 10;
velocity.y = ((+keys.ArrowDown) - (+keys.ArrowUp)) * 10;
}
function PyhsicsUpdate(){
position.x += velocity.x / 10;
position.y += velocity.y / 10;
}
function RenderUpdate() {
if (document.getElementById("square").style.left !== position.x + "px")
document.getElementById("square").style.left = position.x + "px";
if (document.getElementById("square").style.top !== position.y + "px")
document.getElementById("square").style.top = position.y + "px";
}
setInterval(PyhsicsUpdate, 1)
setInterval(RenderUpdate, 10)
document.addEventListener("keydown", event => {
keys[event.key] = true;
UpdatePlayerInput();
})
document.addEventListener("keyup", event => {
keys[event.key] = false;
UpdatePlayerInput();
})
Javascript is a heavily event-driven, often asynchronous language.
window.setTimeout(() => console.log(1), 0);
console.log(2);
The above will log 2, then 1, despite the timeout having been set to 0 milliseconds. setTimeout and setTimeout delay execution of the passed function until the first tick of the event loop, after the specified interval / timeout having been exceeded. It is not expected to be immediately invoked, even with a zero-value time argument.
is there a way to get rid of this pause?
Several approaches exist.
Whichever you end up choosing, the key adjustments you have to make is to (a) separate application state from input state and (b) only update input state as a direct result from event handlers, derive position and velocity on the following (regularly scheduled) view state update. Have one data structure hold the current state of the key(s) pressed and another positional arguments.
Prior to writing code, formalize the expected outcome. What is supposed to happen, if for instance both left and right are pressed? No acceleration in either direction, because inputs cancel? Bail early and save yourself the superfluous zero-sum arithmetic.
First (last) pressed takes precedence? Don't use an object with boolean values to represent pressed keys, use a Set (or array if unavailable) and add / remove (push / prune) to it, encode order by time of insertion.
// wrap the pure string representations of keys in a common data structure
const Key = {
DOWN: 'ArrowDown',
LEFT: 'ArrowLeft',
RIGHT: 'ArrowRight',
UP: 'ArrowUp'
}
// holds currently pressed keys
const inputState = new Set([])
function handleKeyDown(event) {
inputState.add(event.key)
}
function handleKeyUp(event) {
inputState.delete(event.key)
}
document.addEventListener('keydown', handleKeyDown)
document.addEventListener('keyup', handleKeyUp)
const viewState = {
velocity: {
x: 10,
y: 10
},
position: {
x: 375,
y: 225
}
}
const targetDomNode = document.getElementById('square')
function updateTargetDomNode(x, y) {
targetDomNode.style.left = `${x}px`
targetDomNode.style.top = `${y}px`
}
function renderViewState() {
updateTargetDomNode(
viewState.position.x,
viewState.position.y
)
}
// you could abstract more, obviously
function accelerate() {
viewState.velocity.x += inputState.has(Key.LEFT) ? -1 : 0
viewState.velocity.x += inputState.has(Key.RIGHT) ? 1 : 0
viewState.velocity.y += inputState.has(Key.UP) ? -1 : 0
viewState.velocity.y += inputState.has(Key.DOWN) ? 1 : 0
}
function updatePosition(timeSinceLastUpdate) {
viewState.position.x += viewState.velocity.x * timeSinceLastUpdate
viewState.position.y += viewState.velocity.y * timeSinceLastUpdate
}
const UPDATE_INTERVAL = 50
setInterval(() => {
accelerate()
// note, this will be slightly more than 50ms,
// if you care for accuracy, use a measurement,
// rather than a static value
updatePosition(UPDATE_INTERVAL)
renderViewState()
}, UPDATE_INTERVAL)
I know this could be a stupid question, but I can't figure out what's happening with my code in p5.js (I use the online editor).
I'm making a simple snake game but when I call the function to add a certain value to move the head (for now just the head) it returns the value I want but does it another time when I release the key despite I also called this:
function keyReleased(){
return false;
}
These are the functions that I call in the sketch file.
let w = 87;
let a = 65;
let s = 83;
let d = 68;
let stepToDo = 10;
function keyPressed(axis){
if (axis === 0){
if(keyCode === a){
keyCode = 0;
return -stepToDo;
} else if(keyCode === d){
keyCode = 0;
return stepToDo;
} else {
return 0;
}
} else if (axis === 1) {
if(keyCode === w){
keyCode = 0;
return -stepToDo;
} else if(keyCode === s){
keyCode = 0;
return stepToDo;
} else {
return 0;
}
}
}
function keyReleased(){
return false;
}
This is the sketch file.
let arrTest = [200, 200];
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
arrTest[0] = arrTest[0] + keyPressed(0);
arrTest[1] = arrTest[1] + keyPressed(1);
keyReleased();
//console.log(arrTest);
rect (arrTest[0], arrTest[1], 10, 10);
}
Link to the sketch itself https://editor.p5js.org/antolab/sketches/_Lzz41cos
The keyPressed() function is an event listener.
You don't have to call it from your main draw() loop; instead, it is automatically called every time a key is pressed. That way you can use it to change your position array depending on the input key. For example as follows:
function keyPressed() {
if (keyCode === a) {
arrTest[0] = arrTest[0] - stepToDo;
} else if (keyCode === d) {
arrTest[0] = arrTest[0] + stepToDo;
} else if (keyCode === w) {
arrTest[1] = arrTest[1] - stepToDo;
} else if (keyCode === s) {
arrTest[1] = arrTest[1] + stepToDo;
}
}
Note that because we do not define a new arrTest variable within the keyPressed() function it will automatically access the variable that you defined further above.
Here is the corresponding modified sketch.
The reason the keyPressed() function was seemingly executed ``twice'' in your code is that it got executed as part of every iteration of the draw() loop and automatically upon pressing a key.
I am trying to move a sprite using arrow keys. Below is the logic that SHOULD cause the sprite to move diagonally if two keys are pressed. However, that is not the case. It will only move in one direction a a time. Since I am saving each keyCode as a Boolean within an object property whenever I press a button, I would think that this should not be an issue, but I can't get it to work. I have also tried using an array to store these Booleans, and checking those values instead. No luck.
I am at my wit's end and would greatly appreciate some help. I've scoured stackoverflow and many different blogs on building 2d games, but but nothing that I try works.
var keyState = {};
window.onkeydown = window.onkeyup = function(e) {
keyState[e.keyCode] = e.type == 'keydown';
// checks for up and left
if (keyState[38] && keyState[37]) {
player.pos.x -= 2;
player.pos.y -= 2;
}
// checks for up and right
else if (keyState[38] && keyState[39]) {
player.pos.x += 2;
player.pos.y += 2;
}
// checks for down and left
else if (keyState[40] && keyState [37]) {
player.pos.x -= 2;
player.pos.y -= 2;
}
// checks for down and right
else if(keyState[40] && keyState [39]) {
player.pos.x += 2;
player.pos.y -= 2;
}
// checks for up
else if (keyState[38]) {
player.animation.y = 64;
player.pos.y -= 2;
}
};
You should explicitly set the object key values as booleans and you should toggle them in separate keydown/keyup handlers:
let keysdown = {};
window.addEventListener('keydown', function(evt) {
keysdown[evt.which] = true;
if (keysdown["38"] === true && keysdown["37"] === true) {
console.log('up & left');
} else if (keysdown["38"] === true && keysdown["39"] === true) {
console.log('up & right');
} else if (keysdown["40"] === true && keysdown["37"] === true) {
console.log('down and left');
} else if (keysdown["40"] === true && keysdown["39"] === true) {
console.log('down and right');
} else if (keysdown["38"] === true) {
console.log('up');
}
}, false);
window.addEventListener('keyup', function(evt) {
keysdown[evt.which] = false;
}, false);
This logs all the correct key combinations for me.
You need to move the movement logic out of the event listener. Have the key event just log the current state of each key (up or down) then in the main loop check the state and move the play as needed.
As I am unsure if you want the movement to be constant or only on the press I have included the option to change the behaviour with the constant flag MOVE_ONLY_ON_PRESS if true movement only when a press is first detected. So that no key strokes are missed I clear the key flag in the main loop.
The following is an example of how to interface with the keyboard for a game.
// global key log;
var keyState = [];
const KEY_UP = 38;
const KEY_DOWN = 40;
const KEY_LEFT = 37;
const KEY_RIGHT = 39;
// Player
var player = {};
player.x = 100;
player.y = 100;
const MOVE_SPEED = 2;
const MOVE_ONLY_ON_PRESS = false; // This will toggle constant movement or only on press
// from your code
window.onkeydown = window.onkeyup = function (e) {
if (MOVE_ONLY_ON_PRESS) {
if (e.type === 'keydown') {
keyState[e.keyCode] = true;
}
} else {
keyState[e.keyCode] = e.type == 'keydown';
}
}
// in the main loop;
function update(timer) {
// you dont need to test for the combinations (ie up left) when its just simple movement
if (keyState[KEY_UP]) {
player.y -= MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_UP] = false; }
}
if (keyState[KEY_DOWN]) {
player.y += MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_DOWN] = false; }
}
if (keyState[KEY_LEFT]) {
player.x -= MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_LEFT] = false; }
}
if (keyState[KEY_RIGHT]) {
player.x += MOVE_SPEED;
if (MOVE_ONLY_ON_PRESS) { keyState[KEY_RIGHT] = false; }
}
requestAnimationFrame(update);
}
requestAnimationFrame(update);
Bit fields.
Another way to simplify the arrow keys is to set the first 4 bits of a number to correspond to a key, one bit per key, then it is easy to test for combinations of keys as each of the 16 possible combinations has a unique number. You Could map many more keys this way but it becomes a little impractical when you go to far.
This is how to set them
var arrowBits = 0; // the value to hold the bits
const KEY_BITS = [4,1,8,2]; // left up right down
const KEY_MASKS = [0b1011,0b1110,0b0111,0b1101]; // left up right down
window.onkeydown = window.onkeyup = function (e) {
if(e.keyCode >= 37 && e.keyCode <41){
if(e.type === "keydown"){
arrowKeys |= KEY_BITS[e.keyCode - 37];
}else{
arrowKeys &= KEY_MASKS[e.keyCode - 37];
}
}
}
These are 8 of the 16 possible combinations
// postfix U,D,L,R for Up down left right
const KEY_U = 1;
const KEY_D = 2;
const KEY_L = 4;
const KEY_R = 8;
const KEY_UL = KEY_U + KEY_L; // up left
const KEY_UR = KEY_U + KEY_R; // up Right
const KEY_DL = KEY_D + KEY_L; //
const KEY_DR = KEY_D + KEY_R; //
This is how you test for then
if ((arrowBits & KEY_UL) === KEY_UL) { // is UP and LEFT only down
if (arrowBits & KEY_UL) { // is Up left down (down and right may also be down)
if ((arrowBits & KEY_U) === KEY_U) { // is Up only down
if (arrowBits & KEY_U) { // is Up down (any other key may be down)
if (!(arrowBits & KEY_U)) { // is Up up (any other key may be down)
if (!arrowBits) { // no keys are down
if (arrowBits) { // any one or more keys are down
I cannot tell you why your code doesn't work. If I replace the player-movements with console-logs, it works for me.
Although it's pretty primitive.
First separate the keystate-manager from the movement-logic.
var isKeyDown = (function(alias){
for(var i=0, a=Object.create(null); i<256;) a[i++]=false;
for(var k in alias) i=0|alias[k], i>0 && i<256 && Object.defineProperty(a,k,{get:Function("return this["+i+"]")});
function keyStateHandler(e){
a[e.which||e.keyCode] = e.type==="keydown"
}
addEventListener("keydown", keyStateHandler, false);
addEventListener("keyup", keyStateHandler, false);
return a;
})({
//add some aliases for more readable code
up: 38,
left: 37,
right: 39,
down: 40
});
once, because the update-interval of the keydown-event is not reliable, varies between browsers, and is not sync with the update-interval of the brwoser wich will cause flickering.
Now create a main loop for your game, and take account for the timing. Although requestAnimationFrame aims for a constant framerate you may have lags, and you don't want to see your player move at different speeds during these lags.
var lastCall = Date.now();
function tick(){
requestAnimationFrame(tick);
var now = Date.now(),
time = (now - lastCall) / 1000; //time in seconds
//because it's easier to think in terms like 2px/s
//than 0.002px/ms or 0.0333 px/frame
lastCall = now;
move(time);
}
tick();
now the actual movement:
//the speed of your player: it would be better if this would be
//a property of the player than hardcoded like you did, or global like this
var speed = 2; // 2px/second
function move( time ){
//accounts for varying framerates
//opposite directions cancel each other out
var dx = (isKeyDown.right - isKeyDown.left) * time,
dy = (isKeyDown.down - isKeyDown.up) * time;
//taking account for diagonals
if(dx && dy) dx /= Math.SQRT2, dy /= Math.SQRT2;
player.pos.x += dx * speed;
player.pos.y += dy * speed;
}
Based on skyline3000 answer I tried to make it work also in down, left and right. Appart from adding the other options I had to change window to document to make it work:
let keysdown = {};
document.addEventListener('keydown', function (evt) {
keysdown[evt.which] = true;
if (keysdown["38"] === true && keysdown["37"] === true) {
prota.moveUp();
prota.moveLeft();
// console.log('up & left');
} else if (keysdown["38"] === true && keysdown["39"] === true) {
prota.moveUp();
prota.moveRight();
// console.log('up & right');
} else if (keysdown["40"] === true && keysdown["37"] === true) {
prota.moveDown();
prota.moveLeft();
// console.log('down and left');
} else if (keysdown["40"] === true && keysdown["39"] === true) {
prota.moveDown();
prota.moveRight();
// console.log('down and right');
} else if (keysdown["38"] === true) {
prota.moveUp();
// console.log('up');
} else if (keysdown["40"] === true) {
prota.moveDown();
// console.log('down');
} else if (keysdown["39"] === true) {
prota.moveRight();
// console.log('right');
} else if (keysdown["37"] === true) {
prota.moveLeft();
// console.log('left');
}
}, false);
document.addEventListener('keyup', function (evt) {
keysdown[evt.which] = false;
}, false);
I'm doing this project trying to reproduce Schelling's Segregation model. I have a function(below) that is testing to see if the four immediate adjacent cells of the array are either the same or different or empty compared to the current cell being tested.
There are four possible spots to be tested for every cell in the array. But on corners and side spots, obviously you cant test spaces that are out of bounds. So in the function, if it finds one of the out of bounds spaces it decrements the number total around the cell. However, it keeps crashing telling me that I have an Uncaught Reference Error: Cannot read property '0' of undefined. I can't tell why its crashing.
The final lines of this code take the number of goods(similar cells) and the total number of cells around it (empty cells do not count) and gets a percentage similar.
Any help would be appreciated into telling me why it might be crashing and giving me an error? Thanks!
model.Test = function( i, j )
{
var numberToTest= 4;
var goods= 0;
if ((i - 1) >= 0)
{
if (model.BoardArray[i-1][j] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i-1][j])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
if((i + 1) < $("#BoardSizeValue").val())
{
if (model.BoardArray[i+1][j] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i+1][j])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
if ((j - 1) >= 0)
{
if (model.BoardArray[i][j-1] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i][j-1])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
if ((j + 1) < $("#BoardSizeValue").val())
{
if (model.BoardArray[i][j+1] != "E")
{
if (model.BoardArray[i][j] == model.BoardArray[i][j+1])
{
goods++;
}
}
else
{
numberToTest--;
}
}
else
{
numberToTest--;
}
var similar = $("#SimilarSlider").val()/100;
if (numberToTest == 0)
{
return false;
}
else
{
var needed = goods/numberToTest;
if (needed >= similar)
{
return false;
}
else
{
return true;
}
}
}
From looking at your code, you would only get a Reference Error: Cannot read property '0' of undefined. if i was out of the bounds of the array.
I think the problem might be in this part of the code:
if ((i - 1) >= 0) {
if (model.BoardArray[i-1][j] != "E") {
if (model.BoardArray[i][j] == model.BoardArray[i-1][j]) {
if i = $("#BoardSizeValue").val() and $("#BoardSizeValue").val() is a one-based index of the array size, then [i-1] would be okay, but not [i]. So try adjusting your code to this:
if ((i - 1) >= 0 && i < $("#BoardSizeValue").val()) {
if (model.BoardArray[i-1][j] != "E") {
if (model.BoardArray[i][j] == model.BoardArray[i-1][j]) {
This would also apply to the j comparisons as well.