I am learning javascript and making a snake game. I am stuck with rotation. The rotation happens on the whole snake element which is the exact thing I am doing and it looks very bad and I am lost of ideas that makes the animation look good.
code:
let direction = 'right';
let snakearray = [1,2,3];
window.addEventListener("keydown", function (event) {
if (event.defaultPrevented) {
return;
}
switch (event.key) {
case "ArrowDown":
if(direction === 'up')
{
return;
}
direction = 'down'
rotateSnake(direction);
break;
case "ArrowUp":
if(direction === 'down')
{
return;
}
direction = 'up'
rotateSnake(direction);
break;
case "ArrowLeft":
if(direction === 'right')
{
return;
}
direction = 'left';
rotateSnake(direction);
break;
case "ArrowRight":
if(direction === 'left')
{
return;
}
direction = 'right'
rotateSnake(direction);
break;
default:
return;
}
event.preventDefault();
}, true);
move = function (direction, distance) {
let topOrleft = direction == 'left' || direction == 'right' ? 'left' : 'top';
let snake = document.getElementById('snake');
if (direction == 'left' || direction == 'up') {
distance *= -1;
}
let snakeBoundingRect = snake.getBoundingClientRect();
let snakeCurrentCoordinates = direction === 'left' || direction === 'right' ? snakeBoundingRect.left : snakeBoundingRect.top;
snake.style[topOrleft] = (snakeCurrentCoordinates + distance) + 'px';
}
drawSnake = function()
{
for (let index = 0; index < snakearray.length; index++) {
let span = document.createElement('span');
let snake = document.getElementById('snake');
span.style.left = 0 + (index * -16) + 'px';
span.style.top = '0px';
span.classList.add('square');
span.id = 'id-' + (index + 1);
snake.appendChild(span);
snake.style.position = 'absolute';
}
}
rotateSnake = function(direction)
{
let snake = document.getElementById('snake');
let snakenodes = document.getElementById('snake').childNodes;
console.log(snakenodes);
let rotation = null;
switch(direction)
{
case 'down':
rotation = 'rotate(90deg)';
break;
case 'up':
rotation = 'rotate(270deg)';
break;
case 'left':
rotation = 'rotate(180deg)';
break;
case 'right':
rotation = 'rotate(0deg)';
break;
}
snake.style.transform = rotation;
}
drawSnake();
let moveInterval = setInterval(() => move(direction, 5), 1000 / 5);
<!DOCTYPE html>
<html>
<head>
<title>Snake Movements</title>
<style>
.square {
position: absolute;
height: 15px;
width: 15px;
background-color: blue;
}
</style>
</head>
<body>
<span id="snake"></span>
</body>
</html>
help me with the rotation of the snake with code explanation, thank you.
you are trying to rotate whole snake, i think that is a bad idea, you need to rotate each of pieces.
function dibujar() {
let apple = new Apple(Math.random(),Math.random());
console.log('Aples '+apple.position.x);
if (contador === snake.size) {
snake.body.splice(0, 1);
contador = snake.size - 1;
}
if (contador < snake.size) {
contador++;
if (direccion === 0) {
y += -10;
snake.move(x, y);
}
if (direccion === 1) {
x += 10;
snake.move(x, y);
}
if (direccion === 2) {
y += 10;
snake.move(x, y);
}
if (direccion === 3) {
x += -10;
snake.move(x, y);
}
}
ctx.fillStyle = pat;
ctx.fillRect(area.x1, area.y1, area.x2, area.y2);
ctx.fillStyle = "rgb(255,100,0)";
ctx.beginPath();
area.paintTerrain(ctx, area.x2, area.y2, "rgb(36,23,23)");
ctx.fillRect(apple.position.x,apple.position.y,10,10);
for (let i = 0; i < snake.body.length; i++) {
ctx.fillRect(snake.body[i].x, snake.body[i].y, x2/50, y2/50);
}
}
move(stepX, stepY) {
let paso = {};
paso.x = stepX;
paso.y = stepY;
this.body.push(paso);
}
Related
The ship simulator must take in a string of letters(e.g "RAALALL" where R is turn right, A is Advance and L is left) that represent a planned flight path for a given rocket ship. Also L is -x, R is +x, up is -y and down is +y. The Return Value format is {x: X, y: Y, direction: 'down'}.
I tried for loop to iterate over the string given as parameter plus if and if else statement. The return expected was {x: 2, y: 1, direction = 'down'} but I got {x: 1, : 0, direction = 'left'}
function my_spaceship(flightParam) {
var pathLenth = flightParam.length;
var result ="";
const Direction = {
Up: 'up',
Down: 'down',
Left: 'left',
Right: 'right'
};
current_direction = Direction.Up;
currentX = 0;
currentY = 0;
for(i = 0; i < pathLength; i++) {
if(flightParam[i] === "R") {
cmd = flightParam[i];
switch(cmd){
case 'L':
if(current_direction == Dirrection.Up) {
current_direction = Direction.Left;
} else if(current_direction == Direction.Left) {
current_direction = Direction.Down;
} else if(current_direction == Direction.Down) {
current_direction = Direction.Right;
} else if(current_direction == Direction.Right) {
current_direction = Direction.Up;
}
break;
case 'R':
if(current_direction == Direction.Up){
current_direction = Direction.Right;
} else if(current_direction == Direction.Right) {
current_direction = Direction.Down;
} else if(current_direction == Direction.Down) {
current_direction = Direction.Left;
} else if(current_direction = Direction.Left) {
current_direction = Direction.Up;
}
break;
case 'A':
if(current_direction == Direction.Up) {
currentY -= 1;
} else if(current_direction == Direction.Right) {
currentX += 1;
} else if(current_direction == Direction.Down) {
currentY += 1;
} else if(current_direction == Direction.Left) {
currentX -= 1;
}
break;
}
}
result = {x: " "+ currentX+ " ", y: " "+ currentY + " ", direction: " "+ current_direction + "''"};
return result;
}
console.log(my_spaceship("RAALALL"));
console.log(my_spaceship("AAAA"));
console.log(my_spaceship(""));
console.log(my_spaceship("RAARA"));
I am building a JavaScript game, based on Mario.
I have already implemented "physics" for lava, so when the character would fall into it, they would lose 1 life. What I am trying to achieve is that lava drops would act the same, so on contact they would hurt the character and make it respawn at the start of the area / level.
The code can be found here and seen below:
//////////////////////////////
// This is only a demo code //
//////////////////////////////
var LEVELS = [
[" ",
" ",
" ",
" ",
" xxx ",
" xx!xx ",
" x!!!x ",
" xx!xx ",
" x xvx ",
" x x",
" x x",
" x x",
" x x",
" x x",
" x # xxxxx o x",
" xxxxxx xxxxxxxxx xxxxxxxxxx",
" x x ",
" x!!!!!x ",
" x!!!!!x ",
" xxxxxxx ",
" "]
];
var life = 3;
document.getElementById("life").innerHTML = ("Lives left: " + life);
function Vector(x, y) {
this.x = x; this.y = y;
}
Vector.prototype.plus = function(other) {
return new Vector(this.x + other.x, this.y + other.y);
};
Vector.prototype.times = function(scale) {
return new Vector(this.x * scale, this.y * scale);
};
// Note: uppercase words are used that means constructor are values
var actorchars = {
"#": Player,
"o": Coin,
"|": Lava,
"v": Lava
};
function Player(pos) {
this.pos = pos.plus(new Vector(0, -.5));
this.size = new Vector(.5, 1);
this.speed = new Vector(0, 0);
}
Player.prototype.type = "player";
function Lava(pos, ch) {
this.pos = pos;
this.size = new Vector(1, 1);
if (ch === "|")
this.speed = new Vector(0, 2);
else if (ch === 'v'){
this.speed = new Vector(0, 3);
this.repeatPos = pos;
}
}
Lava.prototype.type = "Lava";
function Coin(pos) {
this.basePos = this.pos = pos;
this.size = new Vector(.6, .6);
// take a look back
this.wobble = Math.random() * Math.PI * 2;
}
Coin.prototype.type = "coin";
Level.prototype.isFinished = function() {
return this.status !== null && this.finishDelay < 0;
};
function Level(plan) {
this.width = plan[0].length;
this.height = plan.length;
this.grid = [];
this.actors = [];
for (var y = 0; y < this.height; y++) {
var line = plan[y], gridLine = [];
for (var x = 0; x < this.width; x++) {
var ch = line[x], fieldType = null;
var Actor = actorchars[ch];
if (Actor)
this.actors.push(new Actor(new Vector(x, y), ch));
else if (ch === "x")
fieldType = "wall";
else if (ch === "!")
fieldType = "lava";
else if (ch === "|")
fieldType = "lava";
else if (ch === "v"){
fieldType = "lava";
console.log(fieldType);
}
gridLine.push(fieldType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(function(actor) {
return actor.type === "player";
})[0];
this.status = this.finishDelay = null;
}
function element(name, className) {
var elem = document.createElement(name);
if(className) elem.className = className;
return elem;
}
function DOMDisplay(parent, level) {
this.wrap = parent.appendChild(element("div", "game"));
this.level = level;
this.wrap.appendChild(this.drawBackground());
this.actorLayer = null;
this.drawFrame();
}
var scale = 15;
DOMDisplay.prototype.drawBackground = function() {
var table = element("table", "background");
table.style.width = this.level.width * scale + "px";
table.style.height = this.level.height * scale + "px";
this.level.grid.forEach(function(row) {
var rowElement = table.appendChild(element("tr"));
rowElement.style.height = scale + "px";
row.forEach(function(type) {
rowElement.appendChild(element("td", type));
});
});
return table;
};
DOMDisplay.prototype.drawActors = function() {
var wrap = element("div");
this.level.actors.forEach(function(actor) {
var rect = wrap.appendChild(element("div", "actor " + actor.type));
rect.style.width = actor.size.x * scale + "px";
rect.style.height = actor.size.y * scale + "px";
rect.style.left = actor.pos.x * scale + "px";
rect.style.top = actor.pos.y * scale + "px";
});
return wrap;
};
DOMDisplay.prototype.drawFrame = function() {
if (this.actorLayer)
this.wrap.removeChild(this.actorLayer);
this.actorLayer = this.wrap.appendChild(this.drawActors());
this.wrap.className = "game " + (this.level.status || "");
this.scrollPlayerIntoView();
};
// clear it later
DOMDisplay.prototype.scrollPlayerIntoView = function() {
var width = this.wrap.clientWidth;
var height = this.wrap.clientHeight;
var margin = width / 3;
// The viewport
var left = this.wrap.scrollLeft, right = left + width;
var top = this.wrap.scrollTop, bottom = top + height;
var player = this.level.player;
var center = player.pos.plus(player.size.times(0.5))
.times(scale);
if (center.x < left + margin)
this.wrap.scrollLeft = center.x - margin;
else if (center.x > right - margin)
this.wrap.scrollLeft = center.x + margin - width;
if (center.y < top + margin)
this.wrap.scrollTop = center.y - margin;
else if (center.y > bottom - margin)
this.wrap.scrollTop = center.y + margin - height;
};
DOMDisplay.prototype.clear = function() {
this.wrap.parentNode.removeChild(this.wrap);
};
Level.prototype.obstacleAt = function(pos, size) {
var xStart = Math.floor(pos.x);
var xEnd = Math.ceil(pos.x + size.x);
var yStart = Math.floor(pos.y);
var yEnd = Math.ceil(pos.y + size.y);
if (xStart < 0 || xEnd > this.width || yStart < 0)
return "wall";
if (yEnd > this.height)
return "lava";
for (var y = yStart; y < yEnd; y++) {
for (var x = xStart; x < xEnd; x++) {
var fieldType = this.grid[y][x];
if (fieldType) return fieldType;
}
}
};
Level.prototype.actorAt = function(actor) {
for (var i = 0; i < this.actors.length; i++) {
var other = this.actors[i];
if (other != actor &&
actor.pos.x + actor.size.x > other.pos.x &&
actor.pos.x < other.pos.x + other.size.x &&
actor.pos.y + actor.size.y > other.pos.y &&
actor.pos.y < other.pos.y + other.size.y)
return other;
}
};
var maxStep = 0.05;
Level.prototype.animate = function(step, keys) {
if (this.status !== null)
this.finishDelay -= step;
while (step > 0) {
var thisStep = Math.min(step, maxStep);
this.actors.forEach(function(actor) {
actor.act(thisStep, this, keys);
}, this);
step -= thisStep;
}
};
Lava.prototype.act = function(step, level) {
var newPos = this.pos.plus(this.speed.times(step));
if (!level.obstacleAt(newPos, this.size))
this.pos = newPos;
else if (this.repeatPos)
this.pos = this.repeatPos;
else
this.speed = this.speed.times(-1);
};
var wobbleSpeed = 8, wobbleDist = 0.07;
Coin.prototype.act = function(step) {
this.wobble += step * wobbleSpeed;
var wobblePos = Math.sin(this.wobble) * wobbleDist;
this.pos = this.basePos.plus(new Vector(0, wobblePos));
};
var playerXSpeed = 10;
Player.prototype.moveX = function(step, level, keys) {
this.speed.x = 0;
if (keys.left) this.speed.x -= playerXSpeed;
if (keys.right) this.speed.x += playerXSpeed;
var motion = new Vector(this.speed.x * step, 0);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle)
level.playerTouched(obstacle);
else
this.pos = newPos;
};
var gravity = 30;
var jumpSpeed = 17;
Player.prototype.moveY = function(step, level, keys) {
this.speed.y += step * gravity;
var motion = new Vector(0, this.speed.y * step);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle) {
level.playerTouched(obstacle);
if (keys.up && this.speed.y > 0)
this.speed.y = -jumpSpeed;
else
this.speed.y = 0;
} else {
this.pos = newPos;
}
};
Player.prototype.act = function(step, level, keys) {
this.moveX(step, level, keys);
this.moveY(step, level, keys);
var otherActor = level.actorAt(this);
if (otherActor)
level.playerTouched(otherActor.type, otherActor);
// Losing animation
if (level.status == "lost") {
this.pos.y += step;
this.size.y -= step;
}
};
Level.prototype.playerTouched = function(type, actor) {
if (type == "lava" && this.status === null) {
this.status = "lost";
life -= 1;
console.log(life);
document.getElementById("life").innerHTML = ("Lives left: " + life);
if(life < 0) {
sessionStorage.setItem("reloading", "true");
document.location.reload();
}
this.finishDelay = 1;
} else if (type == "coin") {
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
}
};
var arrowCodes = {37: "left", 38: "up", 39: "right"};
function trackKeys(codes) {
var pressed = Object.create(null);
function handler(event) {
if (codes.hasOwnProperty(event.keyCode)) {
var down = event.type == "keydown";
pressed[codes[event.keyCode]] = down;
event.preventDefault();
}
}
addEventListener("keydown", handler);
addEventListener("keyup", handler);
return pressed;
}
function runAnimation(frameFunc) {
var lastTime = null;
function frame(time) {
var stop = false;
if (lastTime !== null) {
var timeStep = Math.min(time - lastTime, 100) / 1000;
stop = frameFunc(timeStep) === false;
}
lastTime = time;
if (!stop)
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
var arrows = trackKeys(arrowCodes);
function runLevel(level, Display, andThen) {
var display = new Display(document.body, level);
runAnimation(function(step) {
level.animate(step, arrows);
display.drawFrame(step);
if (level.isFinished()) {
display.clear();
if (andThen)
andThen(level.status);
return false;
}
});
}
var lives = function() {
ctx.font = "20px Courier";
ctx.fontFamily = "monospace";
ctx.fillStyle = "#666";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Lives left: " + life, 10, 10);
};
function runGame(plans, Display) {
function startLevel(n) {
runLevel(new Level(plans[n]), Display, function(status) {
if (status == "lost") {
startLevel(n);
} else if (n < plans.length - 1)
startLevel(n + 1);
else
alert("You win!");
});
}
startLevel(0);
}
runGame(LEVELS, DOMDisplay);
body {
background: #222;
}
h2 {
color: #666;
font-family: monospace;
text-align: center;
}
.background {
table-layout: fixed;
border-spacing: 0;
}
.background td {
padding: 0;
}
.lava, .actor {
background: #e55;
}
.wall {
background: #444;
border: solid 3px #333;
box-sizing: content-box;
}
.actor {
position: absolute;
}
.coin {
background: #e2e838;
border-radius: 50%;
}
.player {
background: #335699;
box-shadow: none;
}
.lost .player {
background: #a04040;
}
.won .player {
background: green;
}
.game {
position: relative;
overflow: hidden;
}
#life {
font = 20px;
font-family: monospace;
color: #666;
text-align: left;
baseline: top;
margin-left: 30px;
font-weight: bold;
}
<h2>Simple JavaScript Game</h2>
<div id="life"></div>
So just a quick explanation, the following elements act as:
"x" represents a wall
"#" acts as a character
"!", "v" act as lava
"o" is a coin, which finishes the level by being collected
Current code:
Level.prototype.playerTouched = function(type, actor) {
if (type == "lava" && this.status === null) {
The problem is that you use different types for the "lava pool" and "lava drops".
The last one type is 'Lava' and not 'lava' as the first. So if you want to keep it that way is as simple as that:
Level.prototype.playerTouched = function(type, actor) {
if ((type == "lava" || type == "Lava") && this.status === null) {
With regards,
Chris Karanikas.
I have another question about game creation, that I already reached out for.
As I continued developing the game and tried to implement point counter I have encountered another issue.
It seems that sometimes the points are being counter instead of +1 to +2 or even +3.
I am suspecting incorrect placement of the code-part expo += 1 as it would (probably) get looped 2 (or multiple) times instead of once, but frankly, I am not sure.
The code can be found here or below:
var LEVELS = [
[" x x",
" xx x",
" xxx x x",
" xx!xx x ox",
" x!!!x x xx",
" xx!xx x x",
" x xvx x x",
" x xx x",
" x x x",
" x x x",
" x x xx",
" x x",
" x # xxxxx o x",
" xxxxxx xxxxxxxxx xxxxxxxxxxxxx",
" x x ",
" x!!!!!x ",
" x!!!!!x ",
" xxxxxxx ",
" "],
];
var life = 3;
var expo = 0;
document.getElementById("life").innerHTML = ("Lives left: " + life);
document.getElementById("expo").innerHTML = ("Points: " + expo);
function Vector(x, y) {
this.x = x; this.y = y;
}
Vector.prototype.plus = function(other) {
return new Vector(this.x + other.x, this.y + other.y);
};
Vector.prototype.times = function(scale) {
return new Vector(this.x * scale, this.y * scale);
};
// Note: uppercase words are used that means constructor are values
var actorchars = {
"#": Player,
"o": Coin,
"=": Lava,
"|": Lava,
"v": Lava,
"#": Lava
};
function Player(pos) {
this.pos = pos.plus(new Vector(0, -.5));
this.size = new Vector(.5, 1);
this.speed = new Vector(0, 0);
}
Player.prototype.type = "player";
function Lava(pos, ch) {
this.pos = pos;
this.size = new Vector(1, 1);
if (ch === "=")
this.speed = new Vector(2, 0);
else if (ch === '|')
this.speed = new Vector(0, 2);
else if (ch === 'v'){
this.speed = new Vector(0, 5); // new Vector(0, 3);
this.repeatPos = pos;
} else if (ch === '#'){
this.speed = new Vector(0, 10);
}
}
Lava.prototype.type = "lava"
//Lava.prototype.type = "Lava";
function Coin(pos) {
this.basePos = this.pos = pos;
this.size = new Vector(.6, .6);
// take a look back
this.wobble = Math.random() * Math.PI * 2;
}
Coin.prototype.type = "coin";
Level.prototype.isFinished = function() {
return this.status !== null && this.finishDelay < 0;
};
function Level(plan) {
this.width = plan[0].length;
this.height = plan.length;
this.grid = [];
this.actors = [];
for (var y = 0; y < this.height; y++) {
var line = plan[y], gridLine = [];
for (var x = 0; x < this.width; x++) {
var ch = line[x], fieldType = null;
var Actor = actorchars[ch];
if (Actor)
this.actors.push(new Actor(new Vector(x, y), ch));
else if (ch === "x")
fieldType = "wall";
else if (ch === "!")
fieldType = "lava";
else if (ch === "|")
fieldType = "lava";
else if (ch === "=")
fieldType = "lava";
else if (ch === "#")
fieldType = "lava";
else if (ch === "v"){
fieldType = "lava";
console.log(fieldType);
}
gridLine.push(fieldType);
}
this.grid.push(gridLine);
}
this.player = this.actors.filter(function(actor) {
return actor.type === "player";
})[0];
this.status = this.finishDelay = null;
}
function element(name, className) {
var elem = document.createElement(name);
if(className) elem.className = className;
return elem;
}
function DOMDisplay(parent, level) {
this.wrap = parent.appendChild(element("div", "game"));
this.level = level;
this.wrap.appendChild(this.drawBackground());
this.actorLayer = null;
this.drawFrame();
}
var scale = 15;
DOMDisplay.prototype.drawBackground = function() {
var table = element("table", "background");
table.style.width = this.level.width * scale + "px";
table.style.height = this.level.height * scale + "px";
this.level.grid.forEach(function(row) {
var rowElement = table.appendChild(element("tr"));
rowElement.style.height = scale + "px";
row.forEach(function(type) {
rowElement.appendChild(element("td", type));
});
});
return table;
};
DOMDisplay.prototype.drawActors = function() {
var wrap = element("div");
this.level.actors.forEach(function(actor) {
var rect = wrap.appendChild(element("div", "actor " + actor.type));
rect.style.width = actor.size.x * scale + "px";
rect.style.height = actor.size.y * scale + "px";
rect.style.left = actor.pos.x * scale + "px";
rect.style.top = actor.pos.y * scale + "px";
});
return wrap;
};
DOMDisplay.prototype.drawFrame = function() {
if (this.actorLayer)
this.wrap.removeChild(this.actorLayer);
this.actorLayer = this.wrap.appendChild(this.drawActors());
this.wrap.className = "game " + (this.level.status || "");
this.scrollPlayerIntoView();
};
// clear it later
DOMDisplay.prototype.scrollPlayerIntoView = function() {
var width = this.wrap.clientWidth;
var height = this.wrap.clientHeight;
var margin = width / 3;
// The viewport
var left = this.wrap.scrollLeft, right = left + width;
var top = this.wrap.scrollTop, bottom = top + height;
var player = this.level.player;
var center = player.pos.plus(player.size.times(0.5))
.times(scale);
if (center.x < left + margin)
this.wrap.scrollLeft = center.x - margin;
else if (center.x > right - margin)
this.wrap.scrollLeft = center.x + margin - width;
if (center.y < top + margin)
this.wrap.scrollTop = center.y - margin;
else if (center.y > bottom - margin)
this.wrap.scrollTop = center.y + margin - height;
};
DOMDisplay.prototype.clear = function() {
this.wrap.parentNode.removeChild(this.wrap);
};
Level.prototype.obstacleAt = function(pos, size) {
var xStart = Math.floor(pos.x);
var xEnd = Math.ceil(pos.x + size.x);
var yStart = Math.floor(pos.y);
var yEnd = Math.ceil(pos.y + size.y);
if (xStart < 0 || xEnd > this.width || yStart < 0)
return "wall";
if (yEnd > this.height)
return "lava";
for (var y = yStart; y < yEnd; y++) {
for (var x = xStart; x < xEnd; x++) {
var fieldType = this.grid[y][x];
if (fieldType) return fieldType;
}
}
};
Level.prototype.actorAt = function(actor) {
for (var i = 0; i < this.actors.length; i++) {
var other = this.actors[i];
if (other != actor &&
actor.pos.x + actor.size.x > other.pos.x &&
actor.pos.x < other.pos.x + other.size.x &&
actor.pos.y + actor.size.y > other.pos.y &&
actor.pos.y < other.pos.y + other.size.y)
return other;
}
};
var maxStep = 0.05;
Level.prototype.animate = function(step, keys) {
if (this.status !== null)
this.finishDelay -= step;
while (step > 0) {
var thisStep = Math.min(step, maxStep);
this.actors.forEach(function(actor) {
actor.act(thisStep, this, keys);
}, this);
step -= thisStep;
}
};
Lava.prototype.act = function(step, level) {
var newPos = this.pos.plus(this.speed.times(step));
if (!level.obstacleAt(newPos, this.size))
this.pos = newPos;
else if (this.repeatPos)
this.pos = this.repeatPos;
else
this.speed = this.speed.times(-1);
};
var wobbleSpeed = 8, wobbleDist = 0.07;
Coin.prototype.act = function(step) {
this.wobble += step * wobbleSpeed;
var wobblePos = Math.sin(this.wobble) * wobbleDist;
this.pos = this.basePos.plus(new Vector(0, wobblePos));
};
var playerXSpeed = 10;
Player.prototype.moveX = function(step, level, keys) {
this.speed.x = 0;
if (keys.left) this.speed.x -= playerXSpeed;
if (keys.right) this.speed.x += playerXSpeed;
var motion = new Vector(this.speed.x * step, 0);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle)
level.playerTouched(obstacle);
else
this.pos = newPos;
};
var gravity = 30;
var jumpSpeed = 17;
Player.prototype.moveY = function(step, level, keys) {
this.speed.y += step * gravity;
var motion = new Vector(0, this.speed.y * step);
var newPos = this.pos.plus(motion);
var obstacle = level.obstacleAt(newPos, this.size);
if (obstacle) {
level.playerTouched(obstacle);
if (keys.up && this.speed.y > 0)
this.speed.y = -jumpSpeed;
else
this.speed.y = 0;
} else {
this.pos = newPos;
}
};
Player.prototype.act = function(step, level, keys) {
this.moveX(step, level, keys);
this.moveY(step, level, keys);
var otherActor = level.actorAt(this);
if (otherActor)
level.playerTouched(otherActor.type, otherActor);
// Losing animation
if (level.status == "lost") {
this.pos.y += step;
this.size.y -= step;
}
};
Level.prototype.playerTouched = function(type, actor) {
//if (type == "lava" || type == "Lava" && this.status === null) { //DOESN'T SEEM TO WORK, FIND OUT WHY MASS DAMAGE
if (type == "lava" && this.status === null) {
this.status = "lost";
life -= 1;
console.log(life);
expo = 0;
document.getElementById("expo").innerHTML = ("Points: " + expo);
document.getElementById("life").innerHTML = ("Lives left: " + life);
if(life < 0) {
sessionStorage.setItem("reloading", "true");
document.location.reload();
}
this.finishDelay = 1;
} else if (type == "coin") {
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
console.log("coin picked up")
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
}
};
var arrowCodes = {37: "left", 38: "up", 39: "right"};
function trackKeys(codes) {
var pressed = Object.create(null);
function handler(event) {
if (codes.hasOwnProperty(event.keyCode)) {
var down = event.type == "keydown";
pressed[codes[event.keyCode]] = down;
event.preventDefault();
}
}
addEventListener("keydown", handler);
addEventListener("keyup", handler);
return pressed;
}
function runAnimation(frameFunc) {
var lastTime = null;
function frame(time) {
var stop = false;
if (lastTime !== null) {
var timeStep = Math.min(time - lastTime, 100) / 1000;
stop = frameFunc(timeStep) === false;
}
lastTime = time;
if (!stop)
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
}
var arrows = trackKeys(arrowCodes);
function runLevel(level, Display, andThen) {
var display = new Display(document.body, level);
runAnimation(function(step) {
level.animate(step, arrows);
display.drawFrame(step);
if (level.isFinished()) {
display.clear();
if (andThen)
andThen(level.status);
return false;
}
});
}
var lives = function() {
ctx.font = "20px Courier";
ctx.fontFamily = "monospace";
ctx.fillStyle = "#666";
ctx.textAlign = "left";
ctx.textBaseline = "top";
ctx.fillText("Lives left: " + life, 10, 10);
};
function runGame(plans, Display) {
function startLevel(n) {
runLevel(new Level(plans[n]), Display, function(status) {
if (status == "lost") {
startLevel(n);
} else if (n < plans.length - 1)
startLevel(n + 1);
else
alert("You win!");
});
}
startLevel(0);
}
function restart() {
sessionStorage.setItem("reloading", "true");
document.location.reload();
}
runGame(LEVELS, DOMDisplay);
body {
background: #222;
}
h2 {
color: #666;
font-family: monospace;
text-align: center;
}
.background {
table-layout: fixed;
border-spacing: 0;
}
.background td {
padding: 0;
}
.lava, .actor {
background: #e55;
}
.wall {
background: #444;
border: solid 3px #333;
box-sizing: content-box;
}
.actor {
position: absolute;
}
.coin {
background: #e2e838;
border-radius: 50%;
}
.player {
background: #335699;
box-shadow: none;
}
.lost .player {
background: #a04040;
}
.won .player {
background: green;
}
.game {
position: relative;
overflow: hidden;
}
#life, #expo {
font = 20px;
font-family: monospace;
color: #666;
text-align: left;
baseline: top;
margin-left: 30px;
font-weight: bold;
}
input {
margin-left: 30px;
float: right;
position: relative;
top: -30px;
}
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>game</title>
</head>
<body>
<h2>Simple JavaScript Game</h2>
<div id="life"></div>
<div id="expo"></div>
<div>
<input type="button" onclick="restart()" value="Restart"/>
</div>
</body>
</html>
I have already tried some options and quite interesting, was that if I removed all "lava sources" as variants or/and all collisions of those, the counter would work as it should.
Another level, that might get some ideas about my findings, found here.
I will really appreciate any help, Thanks
EDIT::
I would like to mess with the existing code as minimal as possible, if not, I will have to scrap the code and redo most of it (at least that's the only option I saw).
OK, so it seems that what fixed my issue was incorrect placement of the following sentences:
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
The placement of code before:
else if (type == "coin") {
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
console.log("coin picked up")
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
The correct placement of the code:
else if (type == "coin") {
expo += 1;
document.getElementById("expo").innerHTML = ("Points: " + expo);
this.actors = this.actors.filter(function(other) {
return other != actor;
});
if (!this.actors.some(function(actor) {
console.log("coin picked up")
return actor.type == "coin";
})) {
life += 1;
document.getElementById("life").innerHTML = ("Lives left: " + life);
this.status = "won";
this.finishDelay = 1;
}
I have another question. When I move the main player image Left or Right it moves great except for when you are moving right and then you hurry and press the left key while the right key is still down, the image stops for a second and then it decides to move left. Vise-Versa.
Main.js
var getPlatF1POSX = 0;
var getPlatF1POSY = 0;
var addVar = 0;
var addVar2 = 0;
var addVar3 = 0;
function loadGame() {
document.getElementsByTagName("DIV")[4].style.visibility = "visible";
addEventListener('mousemove', getData, false);
addEventListener('keydown', movePlayer, false);
addEventListener('keyup', stopPlayer, false);
movePlat();
moveP();
document.getElementById("player").style.left = xPos + "px";
document.getElementById("player").style.top = yPos + "px";
}
function getData(gData) {
}
var thisThis = 1;
var moveBlock1 = 350;
var stLandT = 0;
var gPos = "";
var rightPos = false;
var leftPos = false;
function movePlat() {
}
function movePlayer(mPlayer) {
switch (mPlayer.keyCode) {
case 39: // RIGHT
if (stLandT == 0 && gPos == "" && rightPos == false) {
setThis = setTimeout(landT, 500);
thisSet = setTimeout(moveLand, 30);
stLandT = 1;
}
gPos = "RIGHT";
rightPos = true;
leftPos = false;
break;
case 37: // LEFT
if (stLandT == 0 && gPos == "" && leftPos == false) {
setThis = setTimeout(landT, 500);
thisSet = setTimeout(moveLand, 30);
stLandT = 1;
}
gPos = "LEFT";
rightPos = false;
leftPos = true;
break;
case 38: // UP
break;
case 40: // DOWN
break;
}
}
function stopPlayer(sPlayer) {
switch (sPlayer.keyCode) {
case 39:
clearTimeout(setThis);
clearTimeout(thisSet);
stLandT = 0;
gPos = "";
rightPos = false;
leftPos = false;
break;
case 37:
clearTimeout(setThis);
clearTimeout(thisSet);
stLandT = 0;
gPos = "";
rightPos = false;
leftPos = false;
break;
}
}
Move Land And Player
var cTAdd = 0;
var setThis = 1;
var GAPlayer = 3;
function landT() {
setThis = setTimeout(landT, 500);
if (xPos >= 500) {
cTAdd = Math.floor(Math.random() * 100 + 1);
var block00 = document.createElement("img");
if (cTAdd > 0 && cTAdd < 25) {
block00.src = "images/sep2.png";
}
if (cTAdd > 25 && cTAdd < 50) {
block00.src = "images/sep1.png";
}
if (cTAdd > 50 && cTAdd < 100) {
block00.src = "images/platform00.png";
}
document.getElementById("land01").appendChild(block00);
var block01 = document.createElement("img");
var getB = block01.getBoundingClientRect();
if (cTAdd > 0 && cTAdd < 25) {
block01.src = "images/platform00.png";
}
if (cTAdd > 25 && cTAdd < 50) {
block01.src = "images/sep2.png";
}
if (cTAdd > 50 && cTAdd < 100) {
block01.src = "images/sep1.png";
}
document.getElementById("land00").appendChild(block01);
GAPlayer = GAPlayer + 2;
}
}
var thisSet = 1;
var cPlayer = 0;
var moveSpeed = 5;
var xPos = 50;
var yPos = 300;
function moveLand() {
thisSet = setTimeout(moveLand, 30);
if (xPos >= 500) {
moveBlock1 = moveBlock1 - 10;
document.getElementById("land00").style.left = moveBlock1 + "px";
document.getElementById("land01").style.left = moveBlock1 + "px";
}
cPlayer++;
if (cPlayer >= 4)
cPlayer = 0;
document.images[GAPlayer].src = gPlayer[cPlayer].src;
}
function moveP() {
var setThis = setTimeout(moveP, 10);
if (leftPos == false) {
xPos = xPos + moveSpeed;
}
if (rightPos == false) {
xPos = xPos - moveSpeed;
}
document.getElementById("player").style.left = xPos + "px";
document.getElementById("player").style.top = yPos + "px";
if (xPos >= 500) {
xPos = 500;
}
if (xPos <= 50) {
xPos = 50;
}
}
This is because you stop your player no matter what key is up. You should store what key down is last pressed, than on key up you need to check if last key is released.
It was hard to me to debug your code, so I made it in jQuery (and had same troubles as you had):
var game = {
settings: {
moveSpeed: 5, // 5 milliseconds, 200fps
moveBy: 2 // 2 pixels
},
land: null,
landWidth: null,
landLeft: null,
viewport: null,
viewportWidth: null,
landMinLeft: null,
init: function() {
game.land = $('.land');
game.landWidth = game.land.width();
game.landLeft = game.land.position().left;
game.viewport = $('.viewport');
game.viewportWidth = game.viewport.width();
game.landMinLeft = -(game.landWidth-game.viewportWidth);
},
movingInterval: null,
lastKey: null,
keyDown: function (e) {
switch (e.keyCode) {
case 39: // RIGHT
game.lastKey = e.keyCode;
clearInterval( game.movingInterval );
game.movingInterval = setInterval( function() {
game.move('right');
}, game.settings.moveSpeed);
break;
case 37: // LEFT
game.lastKey = e.keyCode;
clearInterval( game.movingInterval );
game.movingInterval = setInterval( function() {
game.move('left');
}, game.settings.moveSpeed);
break;
}
},
keyUp: function(e) {
if( e.keyCode==game.lastKey ) {
game.stopMoving();
};
},
move: function( direction ) {
switch( direction ) {
case 'left':
var newLeft = game.land.position().left+game.settings.moveBy;
if( newLeft>0 ) newLeft=0;
game.land.css({
'left': newLeft+'px'
});
break;
case 'right':
var newLeft = game.land.position().left-game.settings.moveBy;
if( newLeft<game.landMinLeft ) newLeft=game.landMinLeft;
game.land.css({
'left': newLeft+'px'
});
break;
};
},
stopMoving: function() {
clearInterval( game.movingInterval );
}
};
game.init();
$(window).on('keydown', game.keyDown);
$(window).on('keyup', game.keyUp);
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body, html, .viewport {
width: 100%;
height: 100%;
}
.viewport {
position: relative;
overflow: hidden;
}
.land {
position: absolute;
left: 0;
top: 0;
width: 2300px;
height: 200px;
background: url('//dummyimage.com/2300x400/000/fff&text=Mario+is+great!+Mario+is+our+hero!+We+love+you+mario!') no-repeat center center;
background-size: cover;
will-change: left;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="viewport">
<div class="land"></div>
</div>
Also on Playground.
This is how you do it in Javascript/HTML5
theGame.js
var getPlatF1POSX = 0;
var getPlatF1POSY = 0;
var addVar = 0;
var addVar2 = 0;
var addVar3 = 0;
var thisThis = 1;
var moveBlock1 = 350;
var stLandT = 0;
var moveRight = false;
var moveLeft = false;
var movePL = 0;
var movePR = 0;
//////////////////////////////////////////////////////////
//
// LOAD PLATFORMS/SET KEY UP AND DOWN/SET PLAYER POS
function loadGame() {
document.getElementsByTagName("DIV")[4].style.visibility = "visible";
addEventListener('mousemove', getData, false);
addEventListener('keydown', movePlayer, false);
addEventListener('keyup', stopPlayer, false);
moveP();
document.getElementById("player").style.left = xPos + "px";
document.getElementById("player").style.top = yPos + "px";
}
function getData(gData) {
}
//////////////////////////////////////////////////////////
//
// KEY DOWN TO MOVE PLAYER
function movePlayer(mPlayer) {
switch (mPlayer.keyCode) {
case 39: // RIGHT
if (stLandT == 0) {
setThis = setTimeout(landT, 500);
thisSet = setTimeout(moveLand, 30);
stLandT = 1;
}
movePL = 0;
movePR = 1;
break;
case 37: // LEFT
if (stLandT == 0) {
setThis = setTimeout(landT, 500);
thisSet = setTimeout(moveLand, 30);
stLandT = 1;
}
movePL = 1;
movePR = 0;
break;
case 38: // UP
break;
case 40: // DOWN
break;
}
}
//////////////////////////////////////////////////////////
//
// KEY UP TO STOP PLAYER/VOID STOP AND GO GLITCH
function stopPlayer(sPlayer) {
if (sPlayer.keyCode == 39) {
clearTimeout(setThis);
clearTimeout(thisSet);
stLandT = 0;
movePR = 0;
}
if (sPlayer.keyCode == 37) {
clearTimeout(setThis);
clearTimeout(thisSet);
stLandT = 0;
movePL = 0;
}
}
landThis.js/ MOVE PLAYER AND PLATFORMS
var cTAdd = 0;
var setThis = 1;
var GAPlayer = 3;
//////////////////////////////////////////////////////////
//
// SHOW PLATFORMS TO MOVE
function landT() {
setThis = setTimeout(landT, 500);
if (xPos >= 500) {
cTAdd = Math.floor(Math.random() * 100 + 1);
var block00 = document.createElement("img");
if (cTAdd > 0 && cTAdd < 25) {
block00.src = "images/sep2.png";
}
if (cTAdd > 25 && cTAdd < 50) {
block00.src = "images/sep1.png";
}
if (cTAdd > 50 && cTAdd < 100) {
block00.src = "images/platform00.png";
}
document.getElementById("land01").appendChild(block00);
var block01 = document.createElement("img");
var getB = block01.getBoundingClientRect();
if (cTAdd > 0 && cTAdd < 25) {
block01.src = "images/platform00.png";
}
if (cTAdd > 25 && cTAdd < 50) {
block01.src = "images/sep2.png";
}
if (cTAdd > 50 && cTAdd < 100) {
block01.src = "images/sep1.png";
}
document.getElementById("land00").appendChild(block01);
GAPlayer = GAPlayer + 2;
}
}
//////////////////////////////////////////////////////////
//
// MOVE PLATFORMS
var thisSet = 1;
var cPlayer = 0;
var moveSpeed = 5;
var xPos = 50;
var yPos = 300;
function moveLand() {
thisSet = setTimeout(moveLand, 30);
if (xPos >= 500) {
moveBlock1 = moveBlock1 - 10;
document.getElementById("land00").style.left = moveBlock1 + "px";
document.getElementById("land01").style.left = moveBlock1 + "px";
}
}
//////////////////////////////////////////////////////////
//
// MOVE PLAYER
var setP = 1;
function moveP() {
setP = setTimeout(moveP, 10);
if (movePR == 1) {
xPos = xPos + moveSpeed;
cPlayer++;
if (cPlayer >= 4)
cPlayer = 0;
document.images[GAPlayer].src = gPlayer[cPlayer].src;
}
if (movePL == 1) {
xPos = xPos - moveSpeed;
cPlayer++;
if (cPlayer >= 4)
cPlayer = 0;
document.images[GAPlayer].src = gPlayer[cPlayer].src;
}
document.getElementById("player").style.left = xPos + "px";
document.getElementById("player").style.top = yPos + "px";
if (xPos >= 500) {
xPos = 500;
}
if (xPos <= 50) {
xPos = 50;
}
}
I'm brand new to JavaScript, and have a crashing application. I have no idea what would cause the crash.
Here is the code:
<script>
//constants
var Col = 20, Rows = 20;
var cellHeight = 25;
var cellWidth = 25;
var foodX;
var score;
var foodY;
var Nothing = 0, Snake = 1, Food = 2;
var Left = 37, Up = 38, Right = 39, Down = 40;
var canvas = document.getElementById('snakeCanvas');
var context = canvas.getContext('2d');
var dead = "false";
var snakeDirection = null;
var keystate;
var snake = [];
function start() //this is where we begin the long journey
{
init();
Tick();
}
function init() {
snake = [{ x: 5, y: 5 }];
snakeDirection = null;
score = 0;
document.getElementById("score").innerHTML = "Score: " + score;
setFood();
keystate = null;
}
function Tick() // just liker a timer tick
{
document.addEventListener("keydown", function (evt) {
keystate = evt.keyCode; // checks key presses
});
//document.addEventListener("keyup", function (evt) {
//delete keystate[evt.keyCode];
//});
update(); //after we check for a key press we update alllll the
stuff
setTimeout(Tick, 300);
//}
}
function update()
{
checkKey(); // checks what key has been pressed
for (var i = snake.length-1; i > 0; i--) {
snake[i].y = snake[i-1].y;
snake[i].x = snake[i-1].x
}
switch (snakeDirection) { // keys
case "DOWN":
snake[0].y++;
break;
case "UP":
snake[0].y--;
break;
case "RIGHT":
snake[0].x++;
break;
case "LEFT":
snake[0].x--;
break;
}
draw(); //draws all the stuff like food and snake
checkCollisions(); // self explaintory name
}
function checkKey() //Change the direction of the snake cant go
backwards too
{
if (keystate == Left && snakeDirection != "RIGHT" )
{
snakeDirection = "LEFT";
}
if (keystate == Up && snakeDirection != "DOWN")
{
snakeDirection = "UP";
}
if (keystate == Right && snakeDirection != "LEFT")
{
snakeDirection = "RIGHT";
}
if (keystate == Down && snakeDirection != "UP")
{
snakeDirection = "DOWN";
}
}
function setFood()
{ //WE ARE RUNNING OUT OF FOOD WE NEED NEW PROVISIONS
var next = "true"
do {
foodX = Math.floor((Math.random() * Rows));
foodY = Math.floor((Math.random() * Col));
for (var i = 0; i < snake.length; i++) { // IT SUCKS WHEN I
CANT EAT FOOD BECAUSE ITS ALREADY INSIDE OF ME
if (snake[i].x == foodX && snake[i].y == foodY) {
next = "false"
}
}
}
while (next == "false")
draw(); // Pretty pictures
}
function checkCollisions()
{
for (var i = 1; i < snake.length; i++) { // STOP hitting
yourself
if (snake[0].x == snake[i].x && snake[0].y == snake[i].y) {
init();
}
}
if (snake[0].y < 0 || snake[0].y > Rows || snake[0].x < 0 ||
snake[0].x > Col) // you are forbidon to veture from the canvas
{
init();
}
if (snake[0].x == foodX && snake[0].y == foodY) { //Yummy FOOD EAT
EAT EAT
score++;
document.getElementById("score").innerHTML = "Score: " + score;
setFood();
snake.push({ x: null, y: null }); // I got fatter
}
}
function draw()
{
context.clearRect(0, 0, canvas.width, canvas.height); // clears
canvas
context.fillStyle = "#FF0000"; // pretty colour for the head of
the snake
context.fillRect(snake[0].x * cellWidth, snake[0].y * cellWidth,
cellWidth, cellHeight);
context.fillStyle = "#09F";
for (var i = 1; i < snake.length; i++)
{
context.fillRect(snake[i].x * cellWidth, snake[i].y * cellWidth,
cellWidth, cellHeight);
}
context.fillStyle = "#F90"; // FOOD FOOD FOOD FOOD
context.fillRect(foodX * cellWidth, foodY * cellWidth, cellWidth,
cellHeight);
}
start(); // starts hence the name start
</script>
OK not bad for a beginer if you wrote it all your self.
Your problem is with the keydown event. You are creating a new handler each time you tick. This will lead to a crash. You only need to create the event handler once for the page, it will remain active until you leave the page.
To fix your problem move adding the keyDown listener to just above the function Start, as shown below.
var snake = [];
document.addEventListener("keydown", function (evt) {
keystate = evt.keyCode; // checks key presses
});
function start(){
init();
Tick();
}
Also just a because to me it looks weird. true and false are not strings you dont need to put quotes around them. Though using them as strings still works.
You have
function setFood() { //WE ARE RUNNING OUT OF FOOD WE NEED NEW PROVISIONS
var next = "true"
do {
foodX = Math.floor((Math.random() * Rows));
foodY = Math.floor((Math.random() * Col));
for (var i = 0; i < snake.length; i++) {
if (snake[i].x == foodX && snake[i].y == foodY) {
next = "false"
}
}
} while (next == "false")
draw();
}
would be better written as follows
function setFood() {
var next = true; // removed the qoutes
do {
foodX = Math.floor((Math.random() * Rows));
foodY = Math.floor((Math.random() * Col));
for (var i = 0; i < snake.length; i++) {
if (snake[i].x == foodX && snake[i].y == foodY) {
next = false; // removed the quotes.
// no point continuing the for loop as you know you need to
// reposition the food so use the break token
break; // breaks out of the closest loop
}
}
} while ( !next ) // removed next == "false" and replaced with
// ! next. "!" means "Not". do while next not true
// you have the draw here but you draw every tick so it would be best if
// you removed it as the next draw is less than 1/3 of a second away anyways
// draw(); // removed needless draw
}
Good work. Hope you get a good mark for it.