Not Looping? HTML5 and JavaScript - javascript

I have no idea why this code does not loop as it should. My mind is blown and hopefully someone can give me a hand. This is my first attempt into the HTML5 and JavaScript world and my first StackOverflow post. My background is in java so that should explain the quirks in my code. By the way, if you run the code the canvas and balls will show up, just not move.
First off, here is the HTML5
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>ChainReaction5</title>
<script type="text/javascript" src="chain_reaction.js"></script>
</head>
<body>
<body onLoad="init();">
<canvas id="myCanvas" width="500" height="400">
Your browser dosen't support the HTML5 canvas.</canvas><br />
</body>
</html>
Secondly here is the js
//gobal vars
var context;
var box;
var balls;
var defaultBallX=240;
var defaultBallY=190;
var defaultBallRad=6;
var defaultBallV=5;
var defaultNumBalls=10;
//box class
function Box() {
var boxx=20;
var boxy=20;
var boxWidth=460;
var boxHeight=360;
this.getX = function() {return boxx;}
this.getY = function() {return boxy;}
this.getWidth = function() {return boxWidth;}
this.getHeight = function() {return boxHeight;}
this.getBalls = function() {return ball;}
this.paintMe = function() {
context.fillStyle = "black";
context.strokeRect(boxx, boxy, boxWidth, boxHeight);
}
}
/* Box Class
* this class is sloppy but more memory efficent
*/
function Ball(x, y, radius, vx, vy, color) {
this.x=x;
this.y=y;
this.radius=radius;
this.vx=vx;
this.vy=vy;
this.color=color;
this.paintMe = function() {
context.beginPath();
context.arc(this.x, this.y, radius, 0, 2*Math.PI, true);
context.fillStyle = this.color;
context.fill();
}
}
Array.prototype.appendBalls = new function(array) {}
Array.prototype.clearBalls = new function() {}
Array.prototype.appendBalls = function(array) {
for (var i = 0; i < array.length; i++) {
balls.push(array[i]);
}
}
Array.prototype.clearBalls = function() {
balls = new Array();
}
// begin program
function init() {
context = document.getElementById("myCanvas").getContext("2d");
box = new Box();
balls = new Array();
balls.appendBalls(createBalls(box, defaultNumBalls));
setInterval(moveBall(balls, box), 100);
}
function createBalls(box, numBalls) {
var locBalls = new Array(numBalls);
for (var i = 0; i < numBalls; i++) {
var randx = randp(50, 400)
var randy = randp(50, 300);
var randr = Math.random()*defaultBallRad+1;
var randvx = randv();
var randvy = randv();
var randc = randColor();
locBalls[i] = new Ball(randx, randy, randr, randvx, randvy, randc);
}
return locBalls;
function randv() {
var neg = 1;
if (Math.random()>.5) neg = -neg;
return Math.random()*defaultBallV*neg;
}
function randp(low, hight) {
if (low < 0) low = 0;
var p = -1;
while (p > hight || p < low) {
p = Math.random()*hight;
}
return p;
}
function randColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
}
function moveBall(balls, box) {
clear(this.box);
this.box.paintMe();
for (var i = 0; i < this.balls.length; i++) {
moveAndCheck(this.balls[i], this.box);
}
}
function moveAndCheck(b, box) {
if ((b.x+b.vx+b.radius-1)>(this.box.boxWidth+this.box.boxx) || b.x+b.vx-b.radius<this.box.boxx+1) {
b.vx = -b.vx;
}
if ((b.y+b.vy+b.radius-1)>(this.box.boxHeight+this.box.boxy) || b.y+b.vy-b.radius<this.box.boxy+1) {
b.vy = -b.vy;
}
b.x += b.vx;
b.y += b.vy;
b.paintMe();
}
function clear(box) {
context.clearRect(this.box.boxx, this.box.boxy,
this.box.boxWidth, this.box.boxHeight);
}

The first time I tried running it I got the following in the Firebug console:
useless setInterval call (missing quotes around argument?)
[Break On This Error] setInterval(moveBall(balls, box), 100);
Putting quotes around 'moveBalls(balls, box)' animates things.
Incidentally, you can use prototype inhertiance to make your function a bit more efficient, the methods in Box are given to each instance. To have them inherit the methods, put them on the constructor's prototype:
Box.prototype = {
getX: function() {return this.boxx;},
getY: function() {return this.boxy;},
getWidth: function() {return this.boxWidth;},
getHeight: function() {return this.boxHeight;},
getBalls: function() {return this.ball;},
paintMe: function() {
context.fillStyle = "black";
context.strokeRect(this.boxx, this.boxy, this.boxWidth, this.boxHeight);
}
};
Note that in javascript, a function's this keyword is set by the call, it is not set by how you declare the function (though you can use ES5 bind, but that is not widely supported yet).
Some other hints:
In the Box constructor you are making local variables but you really want to assign them to the new Box instance, so use this instead of var:
function Box() {
this.boxx=20;
this.boxy=20;
this.boxWidth=460;
this.boxHeight=360;
}
In the clearBox function, you are using this when it is not set in the call, so it references window. Just get rid of it, you pass box to the function so reference it directly:
function clear(box) {
context.clearRect(box.boxx, box.boxy,
box.boxWidth, box.boxHeight);
}
Same applies to the moveBall and moveAndCheck functions, just get rid of this (I think you should do some research on how this is handled in javascript, there are many articles on it, it's quite different to Java).
Now the balls will bounce around nicely inside the box.

I want to thank the people who contributed to my question and it has been helpful in resolving the issue and the answer I selected was current in a way, but it fixed the problem for a different reason.
Incorrect:
Putting quotes around 'moveBalls(balls, box)' animates things.
What actually fixes the problem is removing the arguments and parentheses from the call to the moveball function. I discovered this when rewriting other parts of my code as the poster suggested.
So for future notice to other people with a similar problem if you need to remove the arguments and use a wrapper function or global variables.

Related

how to prevent overlapping of 2 components

how to prevent overlapping of 2 components, please help me to make them follow Mouse but not overlap. i am not expert in coding, please explain in simple language.
function component(x,y,r) {
var randomcolor = ["violet","indigo","blue","green","yellow","orange","red"];
this.pos=createVector(x,y);
this.r=r;
this.color=randomcolor[Math.floor(Math.random()*randomcolor.length)];
this.show=function() {
fill(this.color);
stroke(241,241,241);
ellipse(this.pos.x,this.pos.y,this.r*2,this.r*2);
}
this.crash = function(other) {
var d = p5.Vector.dist(this.pos,other.pos);
if (d<this.r+other.r) {
this.r+=other.r/20;
return true;}
}
this.move=function(){
this.pos.x=lerp(this.pos.x,mouseX,0.1);
this.pos.y=lerp(this.pos.y,mouseY,0.1);
this.pos.x = constrain(this.pos.x,this.r,width-this.r)
this.pos.y = constrain(this.pos.y,this.r,height-this.r)
}
}
To make multiple objects move without running into each other you will need to
keep track of the current location of all objects
be able to identify each object so that the collision method does not detect a collision of an object with itself
check to make sure there will not be a collision before attempting to move an object
For your example code this is one possibility for making multiple components move towards the mouse without running into each other. I rewrote your crash function and added some global variables. This is not elegant but I think it answers your question in a way that you can understand how this kind of problem can be approached.
var ids = 0;
var allComponents = [];
function setup(){
createCanvas(600,600);
new component(10,10,10);
new component(590,10,10);
}
function draw(){
background(255);
for (let i = 0; i < allComponents.length; i++){
allComponents[i].show();
allComponents[i].move();
}
}
function component(x,y,r) {
var randomcolor = ["violet","indigo","blue","green","yellow","orange","red"];
this.pos=createVector(x,y);
this.r=r;
this.id = ids++;
allComponents[allComponents.length] = this;
this.color=randomcolor[Math.floor(Math.random()*randomcolor.length)];
this.show=function() {
fill(this.color);
stroke(241,241,241);
ellipse(this.pos.x,this.pos.y,this.r*2,this.r*2);
}
this.crash = function(other) {
var d = p5.Vector.dist(this.pos,other.pos);
if (d< this.r + other.r) {
return true;
}
return false;
}
this.move=function(){
let originalX = this.pos.x;
let originalY = this.pos.y;
this.pos.x=lerp(this.pos.x,mouseX,0.1);
this.pos.y=lerp(this.pos.y,mouseY,0.1);
this.pos.x = constrain(this.pos.x,this.r,width-this.r);
this.pos.y = constrain(this.pos.y,this.r,height-this.r);
for (let i = 0; i < allComponents.length; i++){
let other = allComponents[i];
if (this.id !== other.id && this.crash(other)){
this.pos.x = originalX;
this.pos.y = originalY;
break;
}
}
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.7.3/p5.min.js"></script>

Loading Image in P5.js

Hey I hope somebody can help me out with this question, well basically I am trying to upload a picture in my canvas through the p5.js library. And as soon as I load my html file I get this:
I am using brackets, I already tried to set up a web server with wamp server but same thing happened. Here is the code:
//HomePage.js
var rect = [];
var rooms = [];
function preload() {
for (var i = 0; i <= 1; i++){
rooms[i] = loadImage("Raeume/" + i + ".jpg");
}
}
function setup() {
cnv = createCanvas(1000, 600);
}
function mousePressed() {
var r = floor(random(0, rooms.length));
var b = new Raeume(mouseX, mouseY, rooms[r]);
rooms.push(b);
}
function draw() {
background(0);
for (var i = rooms.length-1; i >= 0; i--) {
rooms[i].update();
rooms[i].display();
}
}
//Raeume.js
function Room (x, y, img) {
this.x = x;
this.y = y;
this.img = img;
this.display = function () {
imageMode(CENTER);
image(img, this.x, this.y, 100, 100);
}
<!DOCTYPE html>
<html>
<head>
</head>
<body>
<h1>Raum 007</h1>
<script src="p5/p5.min.js"></script>
<script src="HomePage.js"></script>
<script src="Raeume.js"></script>
</body>
</html>
I really hope you guys can help me on this one! Thanks!
Well, for one, your rooms array is holding first two images (assuming those are the right urls), and then you also add a Raeume object onto the end on mousePressed. Thus, when you call update and display on each entity in the array, it might throw some errors. It's very hard to tell what's the real problem since you don't have an example, but I would say the most likely problem is that your images aren't actually named 0.jpg and 1.jpg. If that's not the prob, then you could try running it in firefox, as I think it's more friendly with p5.js.

Using Keyboard input for 2 objects

edit: SOLVED
I'm a highschool student in Japan trying to learn how to program.
I recently viewed https://vimeo.com/105955605 this video, and decided I could use the beginning section to start building pong in javascript.
I'm pretty much a complete novice with programming and/or javascript and I still have a long way to go.
I got Player1 (left paddle) to work on its own, so I figured I could just copy paste, mess with a couple things, and make Player2. However, now Player2 moves when I press w/s, but Player1 no longer moves.
I've tried creating 2 separate keyboarder() functions, using this.keyboarder from Player1 in player2 (Player2.keyboarder = Player1.keyboarder() ), and declaring/calling keyboarder() before doing anything else.
HTML:
<html>
<head>
<meta charset="UTF-8">
<title>Pong</title>
<link type="text/css" rel="stylesheet" href="css/stylesheet.css">
</head>
<body>
<canvas id="screen" width="310" height="210"></canvas>
<script src="js/pong.js"></script>
</body>
</html>
JavaScript:
;(function(){
//Main game function
//tells objects in bodies array to update.
//stores gameSize pulled from canvasId
var Game = function(canvasId){
var canvas = document.getElementById(canvasId);
var screen = canvas.getContext('2d');
var gameSize = {x: canvas.width, y: canvas.height};
var self = this;
//bodies array
this.bodies = [new Player1(this, gameSize), new Player2(this, gameSize)];
//update function
var tick = function(){
self.update();
self.draw(screen,gameSize);
requestAnimationFrame(tick);
};
tick();
};
//constructer for game() function. tells bodies to update, and draw
Game.prototype = {
update: function(){
for(var i =0 ; i < this.bodies.length; i++){
this.bodies[i].update();
}
},
draw:function(screen,gameSize){
screen.clearRect(0,0,gameSize.x,gameSize.y);
for(var i =0 ; i < this.bodies.length; i++){
drawRect(screen, this.bodies[i]);
}
}
};
//P1 object, declares size and start position of P1
var Player1= function(game, gameSize){
this.size = {x:30,y:gameSize.y / 3};
this.game = game;
this.gameSize = gameSize;
this.center = {x: 0, y:gameSize.y/2};
this.keyboarder = new Keyboarder();
requestAnimationFrame(this.update);
};
//constructor for P1, updates position based on keyboard input
Player1.prototype = {
update:function(){
if (this.keyboarder.isDown(this.keyboarder.KEYS.DOWN) && this.center.y < (5*this.gameSize.y / 6)){
this.center.y += 4;
}else if(this.keyboarder.isDown(this.keyboarder.KEYS.UP) && this.center.y > this.size.y /2 ){
this.center.y -= 4;
}
}
};
//P2, same as P1 aside from position
var Player2= function(game, gameSize){
this.size = {x:30,y:gameSize.y / 3};
this.game = game;
this.gameSize = gameSize;
this.center = {x: gameSize.x, y:gameSize.y/2};
this.keyboarder = new Keyboarder();
requestAnimationFrame(this.update);
};
//constructor for P2, same as P1
Player2.prototype = {
update:function(){
if (this.keyboarder.isDown(this.keyboarder.KEYS.S) && this.center.y < (5*this.gameSize.y / 6)){
this.center.y += 4;
}else if(this.keyboarder.isDown(this.keyboarder.KEYS.W) && this.center.y > this.size.y /2 ){
this.center.y -= 4;
}
}
};
//Draw function, draws object
var drawRect = function(screen, body){
screen.fillRect(body.center.x - body.size.x /2,
body.center.y - body.size.y /2, body.size.x,body.size.y);
};
//Keyboard input function
//reads if keys are being pressed and takes the event code
//isDown() returns boolean of key down = true, key up = false
var Keyboarder = function(
){
var keyState = {};
window.onkeydown = function(e){
keyState[e.keyCode] = true;
};
window.onkeyup = function(e){
keyState[e.keyCode] = false;
};
this.KEYS = {DOWN: 37, UP:39,W:87 , S: 83};
this.isDown = function(keyCode){
return keyState[keyCode] === true;
};
};
//calls game() function when the page has loaded.
window.onload = function(){
new Game("screen")
};
})();
Sorry if this is bad protocol for using stackoverflow, I'm also new to asking questions here.
The problem is you have two Keyboarder instances, and they're both binding to the key events by assigning a handler directly to them - this will overwrite any other handlers. There's two ways to fix it:
1: Don't assign directly, instead use addEventListener, eg:
window.addEventListener('keydown', function(e){
keyState[e.keyCode] = true;
});
2: Use the same keyboarder instance for both players:
var kb = new Keyboarder();
this.bodies = [new Player1(this, gameSize, kb), new Player2(this, gameSize, kb)];
and in your player object assign it to this 3rd parameter. Even if you go this route, I would still advise on using addEventListener as well simply to ensure that the events can be bound to in multiple places if needed.
On another point, you should also be able to refactor your players into a single function and create two instances of it with different parameters, but that sort of thing is better dealt with over on Code Review.
When you create two Keyboarder instances, one collides with the other, because of this:
window.onkeydown = function(e){
keyState[e.keyCode] = true;
};
window.onkeyup = function(e){
keyState[e.keyCode] = false;
};
When you create one Keyboarder, the event listeners the previous one attached are overriden. Try something like this:
window.addEventListener('keydown', function(e){
keyState[e.keyCode] = true;
});
window.addEventListener('keyup', function(e){
keyState[e.keyCode] = false;
});
This ensures there are listeners for every instance of the Keyboarder.

EaselJs: Objects, Classes, and Making A Square Move

Although I have used Javascript extensively in the past, I have never used classes and objects in my programs. This is also the first for me using the HTML5 canvas element with an extra Javascript library. The library I'm using is EaselJS.
Short and sweet, I'm trying to make a square move with keyboard input, using object-oriented programming. I've already looked over sample game files, but I've never been able to properly get one to work.
The following is my classes script:
/*global createjs*/
// Shorthand createjs.Shape Variable
var Shape = createjs.Shape;
// Main Square Class
function square(name) {
this.name = name;
this.vX = 0;
this.vY = 0;
this.canMove = false;
this.vX = this.vY = 0;
this.canMove = false;
this.body = new Shape();
this.body.graphics.beginFill("#ff0000").drawRect(0, 0, 100, 100);
}
And below is my main script:
/*global createjs, document, window, square, alert*/
// Canvas and Stage Variables
var c = document.getElementById("c");
var stage = new createjs.Stage("c");
// Shorthand Create.js Variables
var Ticker = createjs.Ticker;
// Important Keycodes
var keycode_w = 87;
var keycode_a = 65;
var keycode_s = 83;
var keycode_d = 68;
var keycode_left = 37;
var keycode_right = 39;
var keycode_up = 38;
var keycode_down = 40;
var keycode_space = 32;
// Handle Key Down
window.onkeydown = handleKeyDown;
var lfHeld = false;
var rtHeld = false;
// Create Protagonist
var protagonist = new square("Mr. Blue");
// Set Up Ticker
Ticker.setFPS(60);
Ticker.addEventListener("tick", stage);
if (!Ticker.hasEventListener("tick")) {
Ticker.addEventListener("tick", tick);
}
// Init Function, Prepare Protagonist Placement
function init() {
protagonist.x = c.width / 2;
protagonist.y = c.height / 2;
stage.addChild(protagonist);
}
// Ticker Test
function tick() {
if (lfHeld) {
alert("test");
}
}
// Handle Key Down Function
function handleKeyDown(event) {
switch(event.keyCode) {
case keycode_a:
case keycode_left: lfHeld = true; return false;
case keycode_d:
case keycode_right: rtHeld = true; return false;
}
}
This is the error I get in the Developer Tools of Chrome:
Uncaught TypeError: undefined is not a function
easeljs-0.7.0.min.js:13
In case you're wondering, the order of my script tags is the EaselJS CDN, followed by my class, followed by the main script file.
I would really like closure on this question. Thank you in advance.
I figured it out. I was adding the entire protagonist instance to the stage. I've fixed by adding the protagonist.body to the stage.

javascript game: why return init: init?

I'm following a tutorial on how to make a javascript game, but i'm stuck on the return part. Why are is there { }, and what is the init: init for? Any help would be appreciated. Thanks.
var JS_SNAKE = {};
JS_SNAKE.game = (function () {
var ctx;
var xPosition = 0;
var yPosition = 0;
var frameLength = 500; //new frame every 0.5 seconds
function init() {
$('body').append('<canvas id="jsSnake">');
var $canvas = $('#jsSnake');
$canvas.attr('width', 100);
$canvas.attr('height', 100);
var canvas = $canvas[0];
ctx = canvas.getContext('2d');
gameLoop();
}
function gameLoop() {
xPosition += 2;
yPosition += 4;
ctx.clearRect(0, 0, 100, 100); //clear the canvas
ctx.fillStyle = '#fe57a1';
ctx.fillRect(xPosition, yPosition, 30, 50); //a moving rect
setTimeout(gameLoop, frameLength); //do it all again
}
return {
init: init
};
})();
$(document).ready(function () {
JS_SNAKE.game.init();
});
The {} is an object literal in JavaScript. The statement
return {
init: init
}
returns an object with one property. That property's key is init and value is whatever value the variable named init has (in this case, a function).
In case that syntax is confusing, this is equivalent and might be clearer:
JS_SNAKE.game = (function () {
// snip...
function performInitialization() {
// snip...
}
// snip ...
return {
init: performInitialization
};
})();
That is something that is called a module pattern - where you enclose your "class" (or represent it, if you will) with an anonymous function.
The function returns the JS object that can be used to access "class" methods and variables, but only those that are exposed (public) - such as init.
{} is object literal - it is used here to declare an empty JS_SNAKE object - which will serve as a namespace for the following "class" declaration.

Categories

Resources