Functions return NaN in JavaScript [closed] - javascript

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to write a game in JavaScript, and it has some simple car physics that determines that RPM, torque, speed of the car, etc. I have some functions that convert RPM/hp values into different units, and when the RPM gets past a certain point the gear is incremented. However, for some reason, when the car passes the RPM at which it's supposed to shift up on the final gear, the functions start returning NaN and the object disappears from the canvas. What could be the problem? Here is the code:
function gameObject(width, height, color, x, y) {
this.width = width;
this.height = height;
this.speedX = 0;
this.speedY = 0;
this.x = x;
this.y = y;
this.weight = 2500;
this.health = 100;
this.hp = 276;
this.accelTime = 1;
this.gearRatios = [1.98, 1.64, 1.4, 1.23, 1.04];
this.gear = 1;
this.RPM = 0;
this.shiftUpRPM = 7000;
this.shiftDownRPM = 1100;
ctx = game.canvas.getContext('2d');
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
this.update = function() {
if (this.RPM >= this.shiftUpRPM && this.gear < 5) {
this.RPM = 1400;
this.gear += 1;
} else if (this.RPM <= this.shiftDownRPM && this.gear > 1) {
this.RPM = 5200;
this.gear -= 1;
}
ctx = game.context;
ctx.fillStyle = color;
ctx.fillRect(this.x, this.y, this.width, this.height);
}
this.newPos = function() {
this.x += this.speedX;
this.y += this.speedY;
};
}
var torqueToNewton = function(torque) {
return torque * 1.36;
}
var calculateTorqueOutput = function(hp, RPM) {
console.log("cTO:" + (hp * 5252) / RPM)
return (hp * 5252) / RPM;
}
var velocity = function(kn_energy, mass) {
var v = Math.sqrt(2*kn_energy/mass);
return v;
}
var detectCollision = function(object1, object2) {
object1.left = object1.x;
object1.right = object1.x + object1.width;
object1.bottom = object1.y
object1.top = object1.y + object1.height;
object2.left = object2.x;
object2.right = object2.x + object2.width;
object2.bottom = object2.y
object2.top = object2.y + object2.height;
}
var updateGame = function() {
game.clear();
if (window.key && window.key == 83) {
yourObject.speedX = -1;
}
if (window.key && window.key == 87) {
yourObject.RPM += 1;
nm_s = torqueToNewton(calculateTorqueOutput(yourObject.hp, yourObject.RPM));
yourObject.speedX += velocity(nm_s, yourObject.weight)/10;
yourObject.RPM /= (1/yourObject.gearRatios[yourObject.gear]);
console.log(yourObject.speedX + ":" + yourObject.RPM + ":" + yourObject.gear);
}
else {
if (yourObject.RPM > 0 && yourObject.speedX > 0) {
yourObject.RPM -= yourObject.speedX * (.25 / yourObject.speedX);
yourObject.speedX -= .25;
console.log(yourObject.speedX + ":" + yourObject.RPM + ":" + yourObject.gear);
} else {
yourObject.RPM = 0;
yourObject.speedX = 0;
}
}
if (window.key && window.key == 38) {yourObject.speedY = -1; }
if (window.key && window.key == 39) {yourObject.speedY = 1; }
yourObject.newPos();
yourObject.update();

While I didn't inspect all your code, one bug is certainly here:
&& this.gear < 5
This would allow the gear to go up to 5, while the last gear you defined is 4 (you have a total of 5 gears, and since the indexing is zero based, the last one is not 5, but 4).
To fix it, change it to
&& this.gear < 4

Related

collision detection between moving objects

If all my NPCs are stationary, the collision detection works as expected. However, when they are moving, the objects move through each other. I don't understand the difference between the moving object and the stationary object. I am tracking the hitboxes of all the NPCs and I'm pretty sure they're accurate. Maybe someone has some insight. Thanks in advance.
function Hero(map, x, y, facing, image, chars, type) {
this.map = map;
this.x = x;
this.y = y;
this.width = map.tsize;
this.height = map.tsize;
this.chars = chars
// facing = R=0 U=1 L=2 D=3
this.facing = facing
this.image = Loader.getImage(image)
this.type = type
}
Hero.prototype.hitBox = function(type){
if (this.type === "hero"){
return {
left: this.x - this.width/2,
right: this.x + this.width/2 -1,
top: this.y + this.height/2,
bottom: this.y + this.height -1
}
} else if (this.type === "npc") {
return {
left: this.x - this.width/2,
right: this.x + this.width/2 -1,
top: this.y - this.height/2,
bottom: this.y + this.height -1
}
}
};
Hero.SPEED = 256; // pixels per second
Hero.prototype.move = function (delta, dirx, diry) {
// move hero
this.x += dirx * Hero.SPEED * delta;
this.y += diry * Hero.SPEED * delta;
// clamp values
var maxX = (this.map.cols-2) * this.map.tsize;
var maxY = (this.map.rows-2) * this.map.tsize;
this.x = Math.max(0, Math.min(this.x, maxX));
this.y = Math.max(0, Math.min(this.y, maxY));
// check if we walked into a non-walkable tile
this._collide(delta, dirx, diry);
};
Hero.prototype.objCollision = function (obj){
let objHitBox = obj.hitBox()
let heroHitBox = this.hitBox()
if (objHitBox.left < heroHitBox.right&&
objHitBox.right > heroHitBox.left &&
objHitBox.top < heroHitBox.bottom &&
objHitBox.bottom > heroHitBox.top) {
return true
} else {
return false
}
}
Hero.prototype._collide = function (delta, dirx, diry) {
let row, col;
// check for collisions on sprite sides
let collision =
this.map.isSolidTileAtXY(this.hitBox()["left"], this.hitBox()["top"]) ||
this.map.isSolidTileAtXY(this.hitBox()["right"], this.hitBox()["top"]) ||
this.map.isSolidTileAtXY(this.hitBox()["right"], this.hitBox()["bottom"]) ||
this.map.isSolidTileAtXY(this.hitBox()["left"], this.hitBox()["bottom"])
//loop through all hexes with NPCs
let objCollision = this.chars.all.reduce(function (res, obj) {
let tmp;
if (obj !== this) {
tmp = this.objCollision(obj)
}
else {
return false
}
return res || tmp;
}.bind(this), false)
if (!collision && !objCollision) { return; }
if (diry > 0) {
row = this.map.getRow(this.hitBox()["bottom"]);
this.y = -Hero.SPEED*delta + this.y
}
else if (diry < 0) {
row = this.map.getRow(this.hitBox()["top"]);
this.y = Hero.SPEED*delta + this.y
}
else if (dirx > 0) {
col = this.map.getCol(this.hitBox()["right"]);
this.x = -Hero.SPEED*delta+ this.x;
}
else if (dirx < 0) {
col = this.map.getCol(this.hitBox()["left"]);
this.x = Hero.SPEED*delta + this.x;
}
};
aiMove(delta) {
switch(this.facing){
case 0:
this.dirx= 1
this.diry= 0
break;
case 1:
this.dirx= 0
this.diry= -1
break;
case 2:
this.dirx= -1
this.diry= 0
break;
case 3:
this.dirx= 0
this.diry= 1
break;
}
if (!this.waiting && this.moveTimer < 1) {
//Random direction
this.facing = Math.floor(Math.random() * Math.floor(4))
//random time
this.restStepTimer();
} else if (!this.waiting && this.moveTimer > 0) {
//Move to preset direction
this.move(delta, this.dirx, this.diry)
//subtract timer
this.moveTimer--;
//if timer is empty, switch to waiting and reset timer.
if (this.moveTimer <= 0) {
this.waiting = true;
this.restStepTimer();
}
} else if (this.waiting && this.moveTimer > 0) {
//while waiting, we lower the timer.
this.moveTimer--;
//when the timer runs out, we flip the flag back to not waiting and start again.
if (this.moveTimer <= 0) {
this.waiting = false;
}
}
};
restStepTimer() {
this.moveTimer = Math.floor(Math.random() * 50 + 20);
};
};

Javascript Collision (Not Collision Detection)

I'm trying to make a platforming game, and I've been working on the collision for the past 2 weeks. The collision detection is working, but the collision itself (as in, keeping the player out of the tile) is not, no matter what I try. I've tried looking up how to do this, but all I'm finding is how to do the detection part, which I already have done. What do I do after I detect collision?
It was written from scratch, and the player is rectangular, and so are the tiles.
Here's the basic code:
var Player = function(hue, x, y, xSize, ySize, health) {
this.hue = hue;
this.position = new PVector(x, y);
this.originalPosition = new PVector(x, y);
//this.previousPosition = new PVector(x, y);
//this.ppp = new PVector(x, y);
//this.virtualPosition = new PVector(x, y);
//this.predictedPosition = new PVector(x, y);
this.velocity = new PVector(0, 0);
//this.predictedVelocity = new PVector(0, 0);
this.acceleration = new PVector(0, 0);
}
/*Player.prototype.testCollision = function(tile) {
if (this.predictedPosition.y < tile.position.y + tile.size.y && this.predictedPosition.y + this.size.y > tile.size.y && this.predictedPosition.x < tile.position.x + tile.size.x && this.predictedPosition.x + tile.size.x > tile.position.x) {
return false;
} else {
return true;
}
};*/
Player.prototype.ifColliding = function(tile) {
if (this.position.x < tile.position.x + tile.size.x && this.position.x + tile.size.x > tile.position.x) {
/*if (this.position.x + this.size.x > tile.position.x) {
this.position.set(tile.position.x - this.size.x, this.position.y);
} else if (this.position.x < tile.position.x + tile.size.x) {
this.position.set(tile.position.x + tile.size.x, this.position.y);
}*/
this.velocity.set(0, this.velocity.y);
//this.acceleration.set(0, this.acceleration.y);
/*if (this.ppp.x < tile.position.x + tile.size.x && this.ppp.x + tile.size.x > tile.position.x) {
if (this.ppp.x + this.size.x > tile.position.x) {
this.position.set(tile.position.x - this.size.x, this.position.y);
} else if (this.ppp.x < tile.position.x + tile.size.x) {
this.position.set(tile.position.x + tile.size.x, this.position.y);
}
} else if (this.previousPosition.x < tile.position.x + tile.size.x && this.previousPosition.x + tile.size.x > tile.position.x) {
this.position.set(this.ppp.x, this.position.y);
} else {
this.position.set(this.previousPosition.x, this.position.y);
}*/
}
if (this.position.y < tile.position.y + tile.size.y && this.position.y + this.size.y > tile.size.y) {
this.velocity.set(this.velocity.x, 0);
this.acceleration.set(this.acceleration.x, 0);
this.yColliding = true;
/*if (this.position.y + this.size.y > tile.position.y) {
this.position.set(this.position.x, tile.position.y - this.size.y);
rect(0, 20, 0, 0);
} else if (this.position.y < tile.position.y + tile.size.y) {
this.position.set(this.position.x, tile.position.y + tile.size.y);
rect(20, 20, 0, 0);
}*/
}
}
Player.prototype.update = function(tiles) {
//this.ppp.set(this.previousPosition.x, this.previousPosition.y);
//this.previousPosition.set(this.position.x, this.position.y);
this.velocity.add(this.acceleration);
/*this.predictedVelocity.set(this.velocity.x, this.velocity.y);
this.predictedVelocity.add(this.acceleration);
this.virtualPosition.set(this.position.x, this.position.y);
this.virtualPosition.add(this.velocity);
this.predictedPosition.set(this.virtualPosition.x, this.virtualPosition.y);
this.predictedPosition.add(this.predictedVelocity);
var collDcted = false;
for (var i = 0; i < tiles.length; i++) {
if (this.testCollision(tiles[i], true) === false) {
collDcted = false;
}
}*/
//if (collDcted) {
this.position.add(this.velocity);
//}
}
The commented out code is failed attempts. The non-commented code is the closest I could get it to working.
This is a sample collision I made:
<!DOCTYPE html>
<html>
<body>
<p id="Health">Health</p>
<canvas id="gameCanvas" width="600" height="480" style = "border:1px solid gray"></canvas>
<script>
// Adding keyboard evt listener
document.addEventListener("keydown", keyPressed);
document.addEventListener("keyup", keyReleased);
//defining canvas
var canvas;
var canvasContext;
//defining Player variables
var PLAYER_X = 100;
var PLAYER_Y = 100;
var PLAYER_WIDTH = 20;
var PLAYER_HEIGHT = 20;
var PLAYER_HEALTH = 100;
//defining keypress codes
var KEY_LEFT = 37;
var KEY_RIGHT = 39;
var KEY_UP = 38;
var KEY_DOWN = 40;
//variables used to test movement
var keyHeld_Up = false;
var keyHeld_Down = false;
var keyHeld_Left = false;
var keyHeld_Right = false;
//Keypress?
function keyPressed(evt) {
if(evt.keyCode == KEY_UP) {
keyHeld_Up = true;
}
if(evt.keyCode == KEY_DOWN) {
keyHeld_Down = true;
}
if(evt.keyCode == KEY_LEFT) {
keyHeld_Left = true;
}
if(evt.keyCode == KEY_RIGHT) {
keyHeld_Right = true;
}
//prevents page from scrolling when arrow keys are pressed
evt.preventDefault();
}
//Key Released?
function keyReleased(evt) {
if(evt.keyCode == KEY_UP) {
keyHeld_Up = false;
}
if(evt.keyCode == KEY_DOWN) {
keyHeld_Down = false;
}
if(evt.keyCode == KEY_LEFT) {
keyHeld_Left = false;
}
if(evt.keyCode == KEY_RIGHT) {
keyHeld_Right = false;
}
}
//Initialize Canvas and Game Loop
window.onload = function() {
console.log("Is this thing on?");
canvas = document.getElementById('gameCanvas');
canvasContext = canvas.getContext('2d');
var framesPerSecond = 30;
setInterval(function() {
drawObjects();
movePlayer();
damageTest();
}, 1000/framesPerSecond);
}
// Drawing function
function colorRect(x,y, width,height, color, health) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.color = color;
this.health = health;
this.update = function() {
this.draw();
}
this.draw = function() {
canvasContext.beginPath();
canvasContext.rect(this.x, this.y, this.width, this.height);
canvasContext.fillStyle = this.color;
canvasContext.fill();
canvasContext.closePath();
}
};
// Creating Objects
var Screen = new colorRect( 0, 0, 600, 480, 'black', 0);
var Player = new colorRect( PLAYER_X, PLAYER_Y, PLAYER_WIDTH, PLAYER_HEIGHT, 'red', PLAYER_HEALTH);
var Box = new colorRect( 200, 200, 30, 30, 'green', 0);
var Spike = new colorRect( 300, 300, 25, 25, 'white', 0);
// Drawing Objects
function drawObjects() {
Screen.update();
Spike.update();
Player.update();
Box.update();
}
//Collision Test
function collides( a, b ) {
return a.x < b.x + b.width &&
a.x + a.width > b.x &&
a.y < b.y + b.height &&
a.y + a.height > b.y;
}
//Movement based on keypress events
function movePlayer() {
if(collides( Player, Box ) === false) {
if(keyHeld_Up) {
Player.y -= 2;
}
if(keyHeld_Down) {
Player.y += 2;
}
if(keyHeld_Left) {
Player.x -= 2;
}
if(keyHeld_Right) {
Player.x += 2;
}
}
}
//Testing Collision for damage
function damageTest() {
if(collides( Player, Spike ) === true) {
Player.health -= 1;
}
//Displaying Health in <body>
document.getElementById("Health").innerHTML = "Health: " + Player.health;
}
</script>
</body>
</html>
The code I made stops the player in its tracks completely when hitting the box, but you could create individual collision circumstances for when objects collide on each side of another object, and use those to detect collision.
I hope this helped! If you have any questions regarding this code, just ask! (To run code snippet you might want to go full screen and click inside canvas)

HTML JS Canvas Game: Tile Collision Bug Makes Player Teleport Up

I'm a beginner at game development and have been struggling with getting collision done right between an array of tiles and a player rectangle. This game features jumping and gravity. First of all the collision works, but is very clunky. Sometimes when the player ends up on top of a tile and a little to the edge, it will instantly teleport to either the right or left side (depending on what edge/corner) and fall of it. This also happens when colliding with the bottom of the tile; the player will instantly teleport to the side and go up further. From what I understand the tile collision detector confuses the collision with one or the other side because when the player hits the edge of a tile the detector reads it as if it collided with both and decides to place the player elsewhere base on the highest coordinate velocity (aka speedX and speedY). I figured this out by setting speedY = 0 every time it hits the top of a tile, which fixed the issue, but another one came out of it. Now, if the player is on top of a tile and then falls of and shortly strafe back, it doesn't collide with the tile's side, but it rather quickly goes back on top of it again.
I just need some tips on how i should resolve this, because everything I try leads to another problem. I've heard this is a common bug among developing 2D tile based games.
Here is a jsfiddle with the code in action: https://jsfiddle.net/8121u356/
And here is the display of my entire code:
function startGame() {
gameArea.start();
actor = new player(32, 32, "green", 32, 32);
}
var mapArray = [
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,0,0,0,0],
[0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,1,1,1,0,0,0,1,1,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
];
var levelRows = 20;
var levelCols = 20;
var gameArea = {
canvas : document.getElementById('canvas'),
start : function() {
this.context = this.canvas.getContext("2d");
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
requestAnimationFrame(updateGameArea);
window.addEventListener('keydown', function (e) {
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = true;
});
window.addEventListener('keyup', function (e) {
gameArea.keys = (gameArea.keys || []);
gameArea.keys[e.keyCode] = false;
})
},
clear : function(){
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
},
render : function() {
context = this.canvas.getContext("2d");
var tileSize = 32;
for(i=0;i<levelRows;i++){
for(j=0;j<levelCols;j++){
if(mapArray[i][j]==1){
context.fillStyle = "gray";
context.fillRect(j*tileSize,i*tileSize,tileSize,tileSize);
}
}
}
}
};
function TileCollisionManager(object) {
let tileSize = 32;
let baseCol = Math.floor(object.x / tileSize);
let baseRow = Math.floor(object.y / tileSize);
let colOverlap = object.x % tileSize;
let rowOverlap = Math.floor(object.y % tileSize);
if (object.speedX > 0) {
if ((mapArray[baseRow][baseCol + 1] && !mapArray[baseRow][baseCol]) ||
(mapArray[baseRow + 1][baseCol + 1] && !mapArray[baseRow + 1][baseCol] && rowOverlap)) {
object.x = baseCol * tileSize;
}
}
if (object.speedX < 0) {
if ((!mapArray[baseRow][baseCol + 1] && mapArray[baseRow][baseCol]) ||
(!mapArray[baseRow + 1][baseCol + 1] && mapArray[baseRow + 1][baseCol] && rowOverlap)) {
object.x = (baseCol + 1) * tileSize;
}
}
if (object.speedY > 0) {
if ((mapArray[baseRow + 1][baseCol] && !mapArray[baseRow][baseCol]) ||
(mapArray[baseRow + 1][baseCol + 1] && !mapArray[baseRow][baseCol + 1] && colOverlap)) {
object.y = ((baseRow) * tileSize);
object.jumping = false;
object.speedY = 0;
}
}
if (object.speedY < 0) {
if ((!mapArray[baseRow + 1][baseCol] && mapArray[baseRow][baseCol]) ||
(!mapArray[baseRow + 1][baseCol + 1] && mapArray[baseRow][baseCol + 1] && colOverlap)) {
object.y = (baseRow + 1) * tileSize;
object.speedY = 5;
}
}
}
function updateGameArea() {
gameArea.clear();
gameArea.render();
actor.update();
actor.newPos();
actor.speedX = 0;
actor.speedY += actor.gravity;
if (gameArea.keys && gameArea.keys[39]) {
actor.speedX = 4;
}
if (gameArea.keys && gameArea.keys[37]) {
actor.speedX = -4;
}
if (gameArea.keys && gameArea.keys[32]) {
if (!actor.jumping) {
actor.jumping = true;
actor.speedY = -actor.speed * 3;
}
}
TileCollisionManager(actor);
requestAnimationFrame(updateGameArea);
}
function player (width, height, color, x, y) {
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX=0;
this.speedY=0;
this.gravity=0.3;
this.speed=3;
this.jumping=false;
this.color = color;
this.update = function () {
ctx = gameArea.context;
ctx.fillStyle = this.color;
ctx.fillRect(
this.x,
this.y,
this.width, this.height);
};
this.newPos = function () {
this.x += this.speedX;
this.y += this.speedY;
};
A quick fix for you.
I have seen you post this question for the 3rd time. You are not getting an answer because the best solution is rather a lot of code, complex, and requires a lot of changes to your code.
So what I have done is create a very quick and simple solution.
Solve collisions in the correct order.
Rather than check the position at the end of a move, I changed the code to check at every pixel moved. This is needed as you have to find the collisions in the correct order as the player moves from one position to the next. If you hit a wall on the side before the top or bottom, or the other way around it makes a difference, and is what is causing you to have problems. You checked x first then y, which for many situation is the wrong way around.
I also added a object to the actor called canMove It has 4 properties that are set at the start of each frame and are used to prevent the player moving in a direction that is blocked. If you let the player move in a blocked direction it will get stuck on the wall while you have the key down in that direction.
I hacked into your code
Sorry I made a bit of a mess but am short on time.
Also to help me write the changes I made a few other mods, I scaled that game to fit the window (the scaling and resize is all done in the clear function). I changed the keyboard interface to prevent default on keys pressed and set up arrow to jump as well as space (I hate using space to jump :P). Also change the map to use strings as it is a pain typing in changes as an array.
I was not sure how you wanted the actor to react when it is hit on the head. I made it so that it bounces down at the same speed as it moves up, but it does make it harder to jump and slide into narrow passages.
So I think I have most of it done, so you can move on with your game.
If you have questions, ask in the comments.
// NOTE var | 0 is the same as Math.floor(var)
var mapArray = [
"# #",
"# #",
"# ### #",
"# # #",
"# ## ##### #",
"# #",
"# #",
"# ## #",
"# ## #",
"# #",
"# ##### #",
"# #",
"# #",
"# ##### #",
"# #",
"# #",
"# # ## #",
"# ### #",
"# ##### ## #",
"####################",
].map(row => row.split("").map(cell=>cell==="#" ? 1 : 0));
var levelRows = 20;
var levelCols = 20;
var tileX = 32;
var tileY = 32;
var gameArea = {
canvas : document.getElementById('canvas'),
ctx : document.getElementById('canvas').getContext("2d"),
keys : { // set them here so that can block defaults
"37" : false,
"38" : false, // also jump
"39" : false,
"32" : false, // jump
},
start : function() {
document.body.insertBefore(this.canvas, document.body.childNodes[0]);
requestAnimationFrame(updateGameArea);
function keyEvent(e) {
if(gameArea.keys["" + e.keyCode] !== undefined){
gameArea.keys["" + e.keyCode] = e.type === "keydown"
e.preventDefault();
}
}
addEventListener('keydown', keyEvent);
addEventListener('keyup', keyEvent);
focus();
},
clear(){
var minSize = Math.min(innerWidth,innerHeight);
if (this.ctx.canvas.width !== minSize|| this.ctx.canvas.height !== minSize) {
this.ctx.canvas.width = minSize;
this.ctx.canvas.height = minSize;
}
this.ctx.setTransform(1,0,0,1,0,0);
this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
// the next line scales the canvas rendering to fit.
this.ctx.setTransform(
minSize / (levelCols * tileX),
0,
0,
minSize/ (levelRows * tileY),
0,0
);
},
render() {
var ctx = this.ctx;
for(i=0;i<levelRows;i++){
for(j=0;j<levelCols;j++){
if(mapArray[i][j]==1){
ctx.fillStyle = "gray";
ctx.fillRect(j*tileX,i*tileY,tileX,tileY);
}
}
}
}
};
function updateGameArea() {
gameArea.clear();
actor.canMove.check();
actor.speedX = 0;
if(actor.canMove.down){
actor.speedY += actor.gravity;
}
if (gameArea.keys[39] && actor.canMove.right) {
actor.speedX = 4;
}
if (gameArea.keys[37] && actor.canMove.left) {
actor.speedX = -4;
}
if (actor.canMove.up && (gameArea.keys[32] || gameArea.keys[38])) { //jump
if (!actor.jumping) {
actor.jumping = true;
actor.speedY = -actor.speed * 3;
}
}
actor.move(); // collision is done here
gameArea.render();
actor.draw();
requestAnimationFrame(updateGameArea);
}
function Player (width, height, color, x, y) { //player component
this.width = width;
this.height = height;
this.x = x;
this.y = y;
this.speedX=0;
this.speedY=0;
this.gravity=0.3;
this.speed=3;
this.jumping=false;
this.color = color;
this.canMove = {
left : true,
right : true,
up : true,
down : true,
actor : this,
clear(){
this.left = true;
this.right = true;
this.up = true;
this.down = true;
},
check(){
this.clear();
var x = this.actor.x | 0;
var y = this.actor.y | 0;
var cx = x / tileX | 0;
var cy = y / tileY | 0;
if(x % tileX === 0){
if(getMap(cx-1,cy) === 1){
this.left = false;
if(y % tileY !== 0 && getMap(cx-1,cy +1) === 1){
this.left = false;
}
}
if(getMap(cx+1,cy) === 1){
this.right = false;
if(y % tileY !== 0 && getMap(cx+1,cy +1) === 1){
this.right = false;
}
}
}
if(y % tileY === 0){
if(getMap(cx,cy-1) === 1){
this.up = false;
if(x % tileX !== 0 && getMap(cx+1,cy -1) === 1){
this.up = false;
}
}
if(getMap(cx,cy+1) === 1){
this.down = false;
if(x % tileX !== 0 && getMap(cx+1,cy +1) === 1){
this.down = false;
}
}
}
}
};
this.draw = function () {
var ctx = gameArea.ctx;
ctx.fillStyle = this.color;
ctx.fillRect( this.x,this.y, this.width, this.height);
};
this.move = function() {
var x = this.x;
var y = this.y;
var sx = this.speedX;
var sy = this.speedY;
var speed = Math.sqrt(sx * sx + sy * sy);
if(speed > 0){
sx /= speed;
sy /= speed;
for(var i = 0; i < speed; i++){
var xx = (x + sx * i) | 0;
var yy = (y + sy * i) | 0;
var cx = xx / tileX | 0;
var cy = yy / tileY | 0;
if(sy > 0){
if(getMap(cx,cy+1) === 1 || (xx % tileX !== 0 && getMap(cx + 1,cy+1))){
this.y = y = cy * tileY;
this.speedY = sy = speed < 4 ? 0 : -3;
this.jumping = false;
}
}else if(sy < 0){
if(getMap(cx,cy) === 1 || (xx % tileX !== 0 && getMap(cx + 1,cy))){
cy += 1;
this.y = y = cy * tileY;
this.speedY = sy = -sy; // changing -sy to 0 will stick momentarily to the roof.
}
}
if(sx > 0){
if(getMap(cx+1,cy) === 1 || (yy % tileY !== 0 && getMap(cx + 1,cy+1))){
this.x = x = cx * tileX;
this.speedX = sx = 0;
}
}else if(sx < 0){
if(getMap(cx,cy) === 1 || (yy % tileY !== 0 && getMap(cx,cy+1))){
cx += 1;
this.x = x = cx * tileX;
this.speedX = sx = 0;
}
}
}
}
this.x += this.speedX;
this.y += this.speedY;
}
}
function getMap(x,y){
if(y < 0 || y >= levelRows || x < 0 || x >= levelCols){
return 1;
}
return mapArray[y][x];
}
gameArea.start();
actor = new Player(32, 32, "green", 32, 32);
canvas {
position : absolute;
top : 0px;
left : 0px;
}
<canvas id = "canvas" width="640" height="640"></canvas>

Rewrite of an vanilla JS Pong with the help of PixiJS

I tried to rewrite a vanilla JavaScript Pong game in addition with PixiJS, mainly because I had resizing issues to get the canvas responsive.
The resizing works fine with PixiJS, but all the objects started to have trailing paths: Fiddle1
I figured that's because added new instances on update instead of just updating the position, so I tried to rework it from scratch again. The movement of the player works so far but I can't manage to get the ball working...I am kinda lost and willed to learn. Help is much appreciated ...Thanks a lot!
Fiddle2
import 'pixi.js';
// define gamne variables
const appWidth = window.innerWidth;
const appHeight = window.innerHeight;
const paddleWidth = 150;
const paddleHeight = 30;
const ballSize = 15;
const halfBall = ballSize / 2;
const appWidthHalf = appWidth / 2;
const appHeightHalf = appHeight / 2;
const paddleWidthHalf = paddleWidth / 2;
const pongColor = 0x57dfbf;
const bgColor = 0x282625;
const computerPositionX = appWidthHalf - paddleWidthHalf;
const computerPositionY = 50;
const playerPositionX = computerPositionX;
const playerPositionY = appHeight - computerPositionY - paddleHeight;
const ballPositionX = appWidthHalf - halfBall;
const ballPositionY = appHeightHalf - halfBall;
const playerSpeed = 4;
const computerSpeed = 4;
const ballSpeed = 3;
// Setup the ticker and the root stage PIXI.Container.
const app = new PIXI.Application(appWidth, appHeight, {
antialias: false,
backgroundColor: bgColor,
transparent: false,
resolution: 1,
});
// append app to body
document.body.appendChild(app.view);
// create graphic elements
const player = new PIXI.Graphics();
const computer = new PIXI.Graphics();
const ball = new PIXI.Graphics();
// Player
player
.beginFill(pongColor)
.drawRect(playerPositionX, playerPositionY, paddleWidth, paddleHeight)
.endFill();
// Computer
computer
.beginFill(pongColor)
.drawRect(computerPositionX, computerPositionY, paddleWidth, paddleHeight)
.endFill();
// Ball
ball
.beginFill(pongColor)
.drawRect(ballPositionX, ballPositionY, ballSize, ballSize)
.endFill();
// Player Movement
player.update = function () {
for (const key in keysDown) {
const value = Number(key);
if (value === 37) {
player.move(-playerSpeed, 0);
} else if (value === 39) {
player.move(playerSpeed, 0);
} else {
player.move(0, 0);
}
}
};
player.move = function (x, y) {
this.x += x;
this.y += y;
this.x_speed = x;
this.y_speed = y;
if (this.x < -appWidthHalf + paddleWidthHalf) {
this.x = -appWidthHalf + paddleWidthHalf;
this.x_speed = 0;
} else if (this.x + this.width - paddleWidthHalf > appWidthHalf) {
this.x = appWidthHalf - this.width + paddleWidthHalf;
this.x_speed = 0;
}
};
// computer Movement
// eslint-disable-next-line
computer.update = function(ball) {
const x_pos = ball.x;
let diff = -(computer.x + paddleWidthHalf - x_pos);
if (diff < 0 && diff < -computerSpeed) {
diff = -ballSize;
} else if (diff > 0 && diff > computerSpeed) {
diff = ballSize;
}
computer.position.set(diff, 0);
if (computer.x < 0) {
computer.x = 0;
} else if (computer.x + paddleWidthHalf > appWidth) {
computer.x = appWidth - paddleWidthHalf;
}
};
// Ball Movement
ball.update = function (paddle1, paddle2) {
this.x += this.x_speed;
this.y += this.y_speed;
const top_x = this.x - ballSize;
const top_y = this.y - ballSize;
const bottom_x = this.x + ballSize;
const bottom_y = this.y + ballSize;
if (this.x - ballSize < 0) {
this.x = ballSize;
this.x_speed = -this.x_speed;
} else if (this.x + ballSize > appWidth) {
this.x = appWidth - ballSize;
this.x_speed = -this.x_speed;
}
if (this.y < 0 || this.y > appHeight) {
this.x_speed = 0;
this.y_speed = ballSpeed;
this.x = appWidthHalf;
this.y = appHeightHalf;
}
if (top_y > appHeightHalf) {
if (
top_y < paddle1.y + paddle1.height &&
bottom_y > paddle1.y &&
top_x < paddle1.x + paddle1.width &&
bottom_x > paddle1.x
) {
this.y_speed = -ballSpeed;
this.x_speed += paddle1.x_speed / 2;
this.y += this.y_speed;
}
} else if (
top_y < paddle2.y + paddle2.height &&
bottom_y > paddle2.y &&
top_x < paddle2.x + paddle2.width &&
bottom_x > paddle2.x
) {
this.y_speed = ballSpeed;
this.x_speed += paddle2.x_speed / 2;
this.y += this.y_speed;
}
};
// controls
const keysDown = {};
window.addEventListener('keydown', (event) => {
keysDown[event.keyCode] = true;
});
window.addEventListener('keyup', (event) => {
delete keysDown[event.keyCode];
});
// update function
function update() {
player.update();
computer.update(ball);
ball.update(player, computer);
}
// append childs to app
app.stage.addChild(player);
app.stage.addChild(computer);
app.stage.addChild(ball);
// game loop
app.ticker.add(update);
Fiddle 1 definitely had issue, as you were not changing the ball.x and y there, but instead changing the graphics object, in fiddle2 it seemed, you were doing
good job with it. You just have some logical errors in the code, regarding setting the x- and y-coordinates and the ball movement.
So if you add console.log(this.x, this.y) inside the ball.update function in fiddle2, you will notice the NaN values.
To see the ball moving, if you set the initial values with:
ball.x_speed = 0;
ball.y_speed = 0;
And then
paddle.x_speed
paddle.y_speed
To
paddle.x
paddle.y
You see the ball moving at least (though collision logic doesn't work), (modified example in the fiddle below)
https://jsfiddle.net/4L6zbd01/

Javascript canvas game

I have a problem with my canvas game. I try to make it jump but I have some troubles with it. Everything is working fine but if I touch an object from the bottom, it throw me up to the object.
Problem may be with LastColison. Can someone help me ? GIF Image link.
function Block(x, y) {
var size = 80
GameObject.call(this, x*size, y*size, size)
this.img = document.getElementById("block")
this.class = "block"
}
// Dedi vlastnosti z GameObject
Block.prototype = Object.create(GameObject.prototype)
Block.prototype.draw = function() {
ctx.fillStyle = "green"
ctx.drawImage(this.img,this.x,this.y,this.size,this.size)
}
function Player(x, y) {
var size = 120
this.dx = Math.random() * 50 - 25
this.dy = Math.random() * 50 - 25
GameObject.call(this, x*size, y*size, size)
// this.player = document.getElementById("player")
this.img = [document.getElementById("player"),document.getElementById("ball_r"),document.getElementById("ball_l"),document.getElementById("ball_j")]
this.player = this.img[0]
this.class = "player"
}
// Dedi vlastnosti z GameObject
Player.prototype = Object.create(GameObject.prototype)
Player.prototype.move = function() {
var x = this.x
var y = this.y
//ak dam this.y = y -5 môžem pohnuť aj so stlačenou sipkou dole
this.player = this.img[0]
// Posun
if ( keys[37] )
{
if(level == 0){
x -= 4;
}
if (level == 1) {
x -= 8;
}
this.player = this.img[2];
this.y = y;
}
if ( keys[39])
{
if (level == 0) {
x += 4;
}
if (level == 1) {
x += 8;
}
this.player = this.img[1];
}
if ( keys[38] )
{ this.player = this.img[3], this.dy = -10; }
// ak nedam else if mozem ouzzivat naraz viac tlacidiel takze upravit potom
// Test novej pozicie
var collision = false
for (i in scene) {
var obj = scene[i]
if (obj.class == "cloud") { continue; }
if (obj.class == "ladder") { continue; }
if (obj.class == "touched") { continue; }
if (obj.class == "dirt") { this.x = x; this.y = y }
if (obj.class == "block") { this.x = x; this.y = y }
if (obj.class == "enemy") { this.x = x; this.y = y}
var test = x +30 >= obj.x + obj.size || x + this.size - 40<= obj.x /* kolide right*/|| y >= obj.y + obj.size /*kolizia up*/|| y + 40 + this.size <= obj.y /*kolizia bottom*/
if (!test) {
collision = true;
var touch = 0;
if (obj.class == "enemy") {
touch = 1;
if (touch == 1) {
health -= 20; console.log(health);
this.x = x - 250;
if (klik % 2 == 0){
var hit = new Audio('snd/Hit_Hurt15.wav')
hit.play()
}
}
if (health == 0) { health = 0; console.log("GAMEOVER");scene = []}
}
if (obj.class == "coin") {
score += 10; obj.class = "touched";
if (klik % 2 == 0) {
var hrahra = new Audio('snd/pickcoin.wav')
hrahra.play()
}
}
else { touch = 0; }
if (obj.class == "touched") {}
break;
}
}
if (score >= 200 && score <= 200) {
if (klik % 2 == 0) {
var levelup = new Audio('snd/Powerup9.wav')
levelup.loop = false;
levelup.play()
}
level = 1;
health = 100;
score += 1;
}
// Ladder
// if(collision){score += 1,scene.pop() }
// Posun bez kolizie
if (!collision) {
this.x = x
this.y = y + this.dy
this.dy += 0.3;
}
**else {
if (obj.class == this.LastColl) {
this.dy = 0;
this.y = obj.y -160
}
this.dy = 0;
this.LastColl = obj.class
}**
}
Player.prototype.draw = function() {
ctx.fillStyle = "blue"
ctx.beginPath()
ctx.drawImage(this.player,this.x, this.y, 110,160)
ctx.shadowColor = "rgba( 0, 0, 0, 0.3 )";
ctx.shadowOffsetX = -10;
ctx.shadowOffsetY = 0
ctx.shadowBlur = 3;
ctx.drawImage(this.player,this.x,this.y,110,160)
ctx.closePath()
ctx.fill()
}
I can't currently access the GIF you provided. But from what i can gather these lines are your problem:
if (!collision) {
this.x = x
this.y = y + this.dy
this.dy += 0.3;
}
**else {
if (obj.class == this.LastColl) {
this.dy = 0;
this.y = obj.y -160
}
This line - this.y = obj.y -160
Looks like you're telling it to move up -160 pixels on the canvas.
Does this answer your question?
Just a note too - I'd recommend using semicolons at the end of each statement. Don't sometimes use them and other times don't - it will cause problems for you and is bad practice :)
I don't know much about canvas right now, but I noticed that you don't have any semicolons to end your statements...
example:
var x = this.x;
etc.
Another thing that I noticed... The score checks for both greater than or equal to and less than or equal to 200...
if (score >= 200 && score <= 200)
{
...
}

Categories