P5.JS Random Walk Always Ends Up On the Top Border - javascript

I am learning P5.JS with "The Nature of Code", and trying out the first example code.
https://github.com/nature-of-code/noc-examples-p5.js/tree/master/chp00_introduction/NOC_I_01_RandomWalkTraditional
let walker;
let bg_color_x = 255;
let bg_color_y = 51;
let bg_color_z = 153;
let stroke_color_x = 51;
let stroke_color_y = 51;
let stroke_color_z = 204;
let stroke_weight = 10;
let random_number_for_walking = 5;
function setup() {
var cnv = createCanvas(windowWidth, windowHeight);
cnv.style('display', 'block');
background(bg_color_x, bg_color_y, bg_color_z);
walker = new Walker();
}
function draw() {
walker.step();
walker.render();
}
class Walker {
constructor() {
this.x = width / 2;
this.y = height / 2;
}
render() {
stroke(stroke_color_x, stroke_color_y, stroke_color_z);
strokeWeight(stroke_weight);
point(this.x, this.y);
}
step() {
var choice = floor(random(random_number_for_walking));
if (choice === 0) {
// this.x++;
this.x = this.x + stroke_weight;
} else if (choice == 1) {
// this.x--;
this.x = this.x - stroke_weight;
} else if (choice == 2) {
// this.y++;
this.y = this.y + stroke_weight;
} else {
// this.y--;
this.y = this.y - stroke_weight;
}
this.x = constrain(this.x, 0, width - stroke_weight);
this.y = constrain(this.y, 0, height - stroke_weight);
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
background(bg_color_x, bg_color_y, bg_color_z);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
However, no matter how many times I run it, the art settles at the top of the window. For example, like this.
How can I fix this? Is there a way to make it go left or right when it hits one of the four borders?

Your random_number_for_walking is wrong!
Your step function has 4 paths:
step() {
var choice = floor(random(random_number_for_walking));
if (choice === 0) {
// Right
} else if (choice == 1) {
// Left
} else if (choice == 2) {
// Down
} else {
// Up
}
// ...
}
But your random_number_for_walking is 5 and random(number) gives you a number between [0, number), so in your case: 0, 1, 2, 3, 4.
And if you look closer, you do not handle choice == 3, with that else you are actually handling choice == 3 || choice == 4.
This makes it so its more probable that your Walker moves up than down.
Handling correctly the last choice and reducing random_number_for_walking to 4 will solve the issue.

Related

Make movement more smooth on Java Script Game | JavaScript Canvas

I am working on very simple java script game. there's a falling random object (trash) and another object for catch the falling object (trash bin). everything seems fine but i wanted to make the movement of the trash bin more smooth. Do you have any idea to fix this? Thanks in Advance
this is my code
window.onload = function(){
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
var canvasBack = document.getElementById("backgroundCanvas");
var contextBack = canvasBack.getContext("2d");
var timer;
//mengatur hiscore
var hiscore = 0;
//Background image, musik and arrays musik.
var background = new Image();
background.src = 'assets/bgw2.jpg';
var catchSounds = [];
var catchSoundCounter = 0;
for(var i = 0; i < 5; i++)
{
var catchSound = new Audio();
catchSound.src = 'Audio/bleep.wav';
catchSounds.push(catchSound);
}
var music = new Audio();
music.src = 'Audio/MarimbaBoy.wav';
music.loop = true;
var smashSounds = [];
var smashCounter = 0;
for(var i = 0; i < 5; i++)
{
var smash = new Audio();
smash.src = 'Audio/smash.mp3';
smashSounds.push(smash);
}
var player;
var fruits = [];
var numberOfFruits = 15;
//Player constructor
function Player()
{
this.gameOver = false;
this.score = 0;
this.fruitsCollected = 0;
this.fruitsMissed = 0;
this.playerWidth = 150;
this.playerHeight = 90;
this.playerSpeed = 10;
this.x = canvas.width / 2;
this.y = canvas.height - this.playerHeight;
this.playerImage = new Image();
this.playerImage.src = 'assets/binn.png';
//Draws the player
this.render = function()
{
context.drawImage(this.playerImage, this.x, this.y);
}
//Moves the player left
this.moveLeft = function()
{
if(this.x > 0)
{
this.x -= this.playerSpeed;
}
}
//Moves the player right
this.moveRight = function()
{
if(this.x < canvas.width - this.playerWidth)
{
this.x += this.playerSpeed;
}
}
}
//Fruit constructor
function Fruit()
{
this.fruitNumber = Math.floor(Math.random() * 5);
this.fruitType = "";
this.fruitScore = 0;
this.fruitWidth = 50;
this.fruitHeight = 50;
this.fruitImage = new Image();
this.fruitSpeed = Math.floor(Math.random() * 2 + 1);
this.x = Math.random() * (canvas.width - this.fruitWidth);
this.y = Math.random() * -canvas.height - this.fruitHeight;
//Creates a different kind of fruit depending on the fruit number
//which is generated randomly
this.chooseFruit = function()
{
if(this.fruitNumber == 0)
{
this.fruitType = "pisang";
this.fruitScore = 5 * this.fruitSpeed;
this.fruitImage.src = 'assets/pisang.png';
}
else if(this.fruitNumber == 1)
{
this.fruitType = "rubbish";
this.fruitScore = 10 * this.fruitSpeed;
this.fruitImage.src = 'assets/rubbish.png';
}
else if(this.fruitNumber == 2)
{
this.fruitType = "botol";
this.fruitScore = 15 * this.fruitSpeed;
this.fruitImage.src = 'assets/botol.png';
}
else if(this.fruitNumber == 3)
{
this.fruitType = "coke";
this.fruitScore = 20 * this.fruitSpeed;
this.fruitImage.src = 'assets/coke.png';
}
else if(this.fruitNumber == 4)
{
this.fruitType = "apple";
this.fruitScore = 25 * this.fruitSpeed;
this.fruitImage.src = 'assets/apple.png';
}
else if(this.fruitNumber == 5)
{
this.fruitType = "papikra";
this.fruitScore = 30 * this.fruitSpeed;
this.fruitImage.src = 'assets/papikra.png';
}
}
//Makes the fruit descend.
//While falling checks if the fruit has been caught by the player
//Or if it hit the floor.
this.fall = function()
{
if(this.y < canvas.height - this.fruitHeight)
{
this.y += this.fruitSpeed;
}
else
{
smashSounds[smashCounter].play();
if(smashCounter == 4)
{
smashCounter = 0;
}
else
{
smashCounter++;
}
player.fruitsMissed += 1;
this.changeState();
this.chooseFruit();
}
this.checkIfCaught();
}
//Checks if the fruit has been caught by the player
//If it is caught, the player score and fruit counter is increased, and
//the current fruit changes its state and becomes a different fruit.
this.checkIfCaught = function()
{
if(this.y >= player.y)
{
if((this.x > player.x && this.x < (player.x + player.playerWidth)) ||
(this.x + this.fruitWidth > player.x && this.x + this.fruitWidth < (player.x + player.playerWidth)))
{
catchSounds[catchSoundCounter].play();
if(catchSoundCounter == 4)
{
catchSoundCounter = 0;
}
else
{
catchSoundCounter++;
}
player.score += this.fruitScore;
player.fruitsCollected += 1;
this.changeState();
this.chooseFruit();
}
}
}
//Randomly updates the fruit speed, fruit number, which defines the type of fruit
//And also changes its x and y position on the canvas.
this.changeState = function()
{
this.fruitNumber = Math.floor(Math.random() * 5);
this.fruitSpeed = Math.floor(Math.random() * 2 + 1);
this.x = Math.random() * (canvas.width - this.fruitWidth);
this.y = Math.random() * -canvas.height - this.fruitHeight;
}
//Draws the fruit.
this.render = function()
{
context.drawImage(this.fruitImage, this.x, this.y);
}
}
//Adds controls. Left arrow to move left, right arrow to move right.
//ENTER to restart only works at the game over screen.
window.addEventListener("keydown", function(e){
e.preventDefault();
if(e.keyCode == 37)
{
player.moveLeft();
}
else if(e.keyCode == 39)
{
player.moveRight();
}
else if(e.keyCode == 13 && player.gameOver == true)
{
main();
window.clearTimeout(timer);
}
});
main();
//Fills an array of fruits, creates a player and starts the game
function main()
{
contextBack.font = "bold 20px Dominique";
contextBack.fillStyle = "WHITE";
player = new Player();
fruits = [];
for(var i = 0; i < numberOfFruits; i++)
{
var fruit = new Fruit();
fruit.chooseFruit();
fruits.push(fruit);
}
startGame();
}
function startGame()
{
updateGame();
window.requestAnimationFrame(drawGame);
}
//Checks for gameOver and makes each fruit in the array fall down.
function updateGame()
{
music.play();
if(player.fruitsMissed >= 10)
{
player.gameOver = true;
}
for(var j = 0; j < fruits.length; j++)
{
fruits[j].fall();
}
timer = window.setTimeout(updateGame, 30);
}
//Draws the player and fruits on the screen as well as info in the HUD.
function drawGame()
{
if(player.gameOver == false)
{
context.clearRect(0, 0, canvas.width, canvas.height);
contextBack.clearRect(0, 0, canvasBack.width, canvasBack.height);
contextBack.drawImage(background, 0, 0);
player.render();
for(var j = 0; j < fruits.length; j++)
{
fruits[j].render();
}
contextBack.fillText("SCORE: " + player.score, 30, 50);
contextBack.fillText("HIGHEST SCORE: " + hiscore, 140, 50);
contextBack.fillText("FRUIT CAUGHT: " + player.fruitsCollected, 320, 50);
contextBack.fillText("FRUIT MISSED: " + player.fruitsMissed, 490, 50);
}
else
{
//Different screen for game over.
for(var i = 0; i < numberOfFruits; i++)
{
console.log("Speed was" + fruits[fruits.length - 1].fruitSpeed);
fruits.pop();
}
if(hiscore < player.score)
{
hiscore = player.score;
contextBack.fillText("NEW HI SCORE: " + hiscore, (canvas.width / 2) - 80, canvas.height / 2);
}
contextBack.fillText("PRESS ENTER TO RESTART", (canvas.width / 2) - 100, canvas.height / 2 + 50);
context.clearRect(0, 0, canvas.width, canvas.height);
}
window.requestAnimationFrame(drawGame);
}
}
First of all, just use one requestAnimationFrame and no other setTimeout code. These can start to run out of sync with each other and it's hard to pause them all when the player wants to pause the game.
Instead, use a counter instead of timeout.
let fruitCounter = 0
function drawGame() {
// all your draw code here
...
// every 60 frames drop a new fruit
fruitCounter++
if(fruitCounter > 60){
fruitCounter = 0
dropNewFruit()
}
// request the new frame unless its game over
if(!gameOver) {
requestAnimationFrame(drawGame)
}
}
Also, if you use keyboard events like this, it will always be choppy because there is a delay when typing on the keyboard (just press a letter for a long time in a text field, you will see that it takes a while until more letters appear)
You can fix this by setting a variable once a key gets pressed.
window.addEventListener("keydown", function(e){
if(e.keyCode == 37){
moveLeft = 1
}
}
window.addEventListener("keyup", function(e){
if(e.keyCode == 37){
moveLeft = 0
}
}
Then, you can use that variable in your animation code
function drawGame() {
// all your draw code here
player.x += moveLeft
// request the new frame unless its game over
if(!gameOver) {
requestAnimationFrame(drawGame)
}
}
These are just a few tips! This has always worked for me when I build a javascript game.

Why isn't my condition working?

In javascript, I'm making an HTML canvas game, and in that game I have an object type/constructor called gamePiece. gamePiece has a function called checkCollision:
this.checkCollision = function(piece){
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y <= this.y && piece.y <= (this.y - this.height);
if(collisionX || collisionY){
return true;
} else {
return false;
}
}
which is called by update()
function update(){
context.clearRect(0, 0, game.width, game.height);
for(var i = 0; i < gamePieces.length; i++){
gamePieces[i].update();
for(var mi = 0; mi < gamePieces.length; mi++){
gamePieces[i].checkCollision(gamePieces[mi]);
if(gamePieces[i].checkCollision(gamePieces[mi]) == true){
gamePieces[i].collisionFunction();
}
}
}
}
setInterval(function(){update();}, 1);
I have another object that is supposed to give a speed boost upon colliding with another game piece, and it logs every time it gives a speed boost.
var speedBooster = new gamePiece(25,25,"red",300,300,0);
speedBooster.collisionFunction = function(){
for(var whichpiece = 0; whichpiece < gamePieces.length; whichpiece++){
if(speedBooster.checkCollision(gamePieces[whichpiece]) == true && gamePieces[whichpiece] != this){
gamePieces[whichpiece].speed += 10;
console.log("gamePieces[" + whichpiece + "] has been given a speed boost.");
}
}
}
But it gives a speed boost whenever a piece is behind it, and I put the "piece.x >= this.x &&" there for a reason. Why is JavaScript ignoring the condition I gave it?
Try
var collisionX = piece.x >= this.x && piece.x <= (this.x + this.width);
var collisionY = piece.y >= this.y && piece.y <= (this.y + this.height);
if(collisionX && collisionY){
return true;
} else {
return false;
}
To test if two objects overlap. Where the object has x,y as the top left and w,h as width and height
//Returns true if any part of box1 touches box2
function areaTouching(box1,box2){
return ! (box1.x > box2.x + box2.w ||
box1.x + box1.w < box2.x ||
box1.y > box2.y + box2.h ||
box1.y + box1.h < box2.y)
}

Processing Loop

int objectX = width/2;
int objectY = height/2;
int snelheidY = 1;
int score = 0;
int richting = 1;
int positiebal;
int bal = ellipse(objectX, objectY, 50, 50);
lost = false;
void setup() {
size(400, 400);
positiebal = height/2;
textSize(12);
}
void draw() {
background(0, 0, 0);
ellipse(positiebal, objectY, 50, 50);
if(objectY > 375)
snelheidY = -snelheidY;
if(objectY<25)
snelheidY = -snelheidY;
objectY = objectY + snelheidY;
text("score = " +score,4,10);
if (score < 0)
{ textSize(20);
text("play again",50,50);
noLoop();
lost = true;
textSize = 13;
}
}
void mousePressed() {
int distance = dist(200, objectY, mouseX, mouseY);
if (distance<=25)
//score hoger maken met 1 punt
{ score=score+1;
if (snelheidY < 0)
{ snelheidY = snelheidY -1; }
{ snelheidY = snelheidY+1; }
}
// score met 1 punt lager maken
else
{ score = score - 1;
if (snelheidY > 1)
{ snelheidY = snelheidY -1; }
}
if (lost == true)
{ snelheidY = 1;
score = 0;
positiebal = height/2;
richting = 1;
lost= false;
loop();}
}
I made a loop for the whole process to restart after the score<0, but it doesn't work the second time. The first time it works fine, but the second time it just stops the game without showing the restart text and without restarting.
I wouldn't use loop() and noLoop() for this. Instead, store your state in a set of variables, and use those variables to draw each frame. Here's a simple example:
boolean start = true;
boolean play = false;
boolean end = false;
void draw() {
background(0);
if (start) {
text("start", 20, 20);
} else if (play) {
text("play", 20, 20);
} else if (end) {
text("end", 20, 20);
}
}
void mousePressed() {
if (start) {
start = false;
play = true;
} else if (play) {
play = false;
end = true;
} else if (end) {
end = false;
start = true;
}
}

Make a sprite move left or right in p5.play.js

I'm trying to make my sprite be able to move left or right. It can jump, but not move. I have tried different approaches, but I'm clearly missing something.
I'm using p5.js and its addon p5.play.js.
Here's my code:
p5.prototype.print = p5.prototype.println;
var asterisk;
var platform;
var GRAVITY = 1;
var JUMP = 15;
function setup() {
createCanvas(800, 600);
asterisk = createSprite(30, 200, 20, 60);
//if defined, the collider will be used for mouse events
asterisk.setCollider("circle", 0,0,33);
platform = createSprite(200, 585, 500, 20);
}
function draw() {
background(51);
asterisk.velocity.y += GRAVITY;
if(asterisk.collide(platform)) {
asterisk.velocity.y = 0;
}
if(keyWentDown("UP_ARROW") || mouseWentDown(LEFT)){
asterisk.velocity.y = -JUMP;
}
function keyReleased() {
if (key != ' '){
asterisk.setDir(0);
}
}
function keyPressed(){
if (keyCode === RIGHT_ARROW){
asterisk.setDir(1);
}else if (keyCode === LEFT_ARROW){
asterisk.setDir(-1);
}
}
drawSprites();
}

How to determine what JavaScript causes a browser crash?

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.

Categories

Resources