So I'm currently working on a project that requires a grid/checkerboard. I've already made my grid in Javascript and I've also managed to center my grid.
The problem I'm having is that when I change my resolution with the device toolbar, the grid gets out of view. My goal is to make the whole grid visible no matter what phone or computer I use.
I would appreciate the help from you guys!
This is how I'm making my grid.
for (i = 0; i < row; i++) {
grid[i] = new Array(col);
}
//making a spot for every grid.
for (i = 0; i < row; i++) {
for (j = 0; j < col; j++) {
grid[i][j] = new Spot(i, j);
}
}
This is how I'm drawing the grid.
function Spot(i, j) {
this.x = i;
this.y = j;
this.show = function (color) {
fill(color);
rect(this.x * w, this.y * h, w - 1, h - 1);
}
}
w is the width of ONE single grid and h is the height of ONE single grid. col and row are the amount of rows and columns I want the grid to have.
I also call the function "this.show" every frame. The result looks like this:
The grid that is out of view
you need to check against the media type:
var l_strMobileMedia = '(max-width:320px)'
var mqList = window.matchMedia(l_strMobileMedia);
if(!mqList.matches){
l_strMobileMedia = '(max-width:481px)'
mqList = window.matchMedia(l_strMobileMedia);
}
if(!mqList.matches){
l_strMobileMedia = '(max-width:768px)'
mqList = window.matchMedia(l_strMobileMedia);
}
if(s_bIsMobile == null || s_bIsMobile != mqList.matches){
Session.set_mobile_layout(mqList.matches);
}
s_bIsMobile = mqList.matches;
return mqList.matches;
I hope this gets you started. If you want to do it in realtime, you need to hook to window resize event or set a timer that does the queries for you.
I have a game loop that refreshes ~20 times per second with the following condition, inside function growPlayerBlockCounterWinner():
if (obstacleArray[i][2] > canvas.height) {player.size += 5;}
That means: if black object goes outside the canvas area, player size will increase by 5 pixels.
The function normally executes once, but due to putting it in a game loop, it executes each time the game is refreshed, so player is growing continuously.
Previously i had it with the sign '=' instead od '>', but that was working well when black blocks were moving pixel by pixel and i want them to move faster.
You can inspect the problem and full code on the remote server: https://stacho163.000webhostapp.com/firstLevel.html
Below I paste only my obstacle functions:
// js game script //
let obstacle = {
size: 0,
posX: 0,
posY: 0,
speed: 0
}
let obstacleArray = new Array(100);
function generateObstacle() {
for (i = 0; i < obstacleArray.length; i++) {
obstacle.size = Math.round((Math.random() * 100) + 50);
obstacle.posX = Math.round((Math.random() * (canvas.width -
obstacle.size)));
obstacle.posY = -450 - (i * 100);
obstacle.speed = 5;
obstacleArray[i] = [obstacle.size, obstacle.posX, obstacle.posY,
obstacle.speed];
}
}
function drawObstacle() {
for (i = 0; i < obstacleArray.length; i++) {
ctx.fillStyle = "#000";
ctx.fillRect(obstacleArray[i][1], obstacleArray[i][2],
obstacleArray[i][0], obstacleArray[i][0]);
obstacleArray[i][2] += obstacleArray[i][3];
}
}
function growPlayerBlockCounterWinner() {
for (i = 0; i < obstacleArray.length; i++) {
// grow player
if (obstacleArray[i][2] > canvas.height) {
player.size += 5;
}
}
}
generateObstacle();
function game() {
drawObstacle();
growPlayerBlockCounterWinner();
requestAnimationFrame(game);
}
requestAnimationFrame(game);
I am looking for opinions, maybe my logic about that statement is incorrect or i should place that statement in other place.
Thanks for your tips :)
As you have a defined number of black boxes, you might be able to store, for which black box the player already increased size like this:
let obstacle = {...};
var affectedBlackBoxes = {};
//...//
function growPlayerBlockCounterWinner() {
for (i = 0; i < obstacleArray.length; i++) {
// grow player
if (obstacleArray[i][2] > canvas.height && !affectedBlackBoxes[i]) {
player.size += 5;
affectedBlackBoxes[i] = true;
}
}
}
I'm creating a small game in javascript and I'm using svg for the graphics. Right now I'm having a problem with updating the game in the middle of a game tick. If I exit my loop directly after I update the fill attribute with "setAttributeNS", it's redrawn, but if I don't do that, it isn't updated until after "game_tick" is over. Even worse, if I call "game_tick" multiple times in a row, the svg objects aren't updated until after I've run all of the "game_tick"s instead of being updated after each one.
function game_tick(){
num_grid_copy = num_grid.slice();
for (var x = 0; x < num_squares_x; x += 1) {
for (var y = 0; y < num_squares_x; y += 1) {
var n = get_neighbors(x,y);
var isAliveInNextGen = next_gen(n, num_grid[x*num_squares_x+y]);
num_grid_copy[x*num_squares_x+y] = isAliveInNextGen;
if (isAliveInNextGen == 1){
rect_grid[x*num_squares_x+y].setAttributeNS(null, 'fill', '#0099ff');
}
else {
rect_grid[x*num_squares_x+y].setAttributeNS(null, 'fill', '#fff');
}
}
}
num_grid = num_grid_copy;
}
Thanks to valuable input from Robert I realized that javascript execution and page rendering are done in the same thread. I changed the function to the following:
function start() {
var inc = 0,
max = 25;
delay = 100; // 100 milliseconds
var repeat = setInterval(function() {
game_tick();
if (++inc >= max)
clearInterval(repeat);
},
delay);
}
This works fine. I can set the delay and the number of times it repeats.
I'm in the process of building an entity system for a canvas game. This started from a simple particle emitter/updater which I am altering to accommodate a multi-particle/entity generator. Whilst I am usually ok with JavaScript/jQuery I am running into the limits of my experience as it concerns arrays and would gratefully accept any help on the following:
When I need a new particle/entity my current system calls a function to push an object into an array which contains variables for the entity updates.
Then the update function runs a for loop over the array, checking on the type variable to update the particle (position/colour/etc...). Previously I would then [array.splice] the particle, based on some condition. When I needed further particles/entities I would then push new particles.
What I would like to achieve here is:
In the makeParticle function, check over the particle array for any "dead" particles and if any are available reuse them, or push a new particle if not I have created a particleAlive var as a flag for this purpose.
var particles = [];
var playing = false;
function mousePressed(event) {
playing = !playing;
}
if(playing) {
makeParticle(1, 200, 200, 10, "blueFlame");
makeParticle(1, 300, 200, 10, "redFlame");
}
function makeParticle(numParticles, xPos, yPos, pRadius, pType) {
var i;
for (i = 0; i < numParticles; i++) {
var p = {
type : pType,
x : xPos,
y : yPos,
xVel : random(-0.5, 0.5),
yVel : random(-1, -3),
particleAlive : true,
particleRender : true,
size : pRadius
}; // close var P
particles.push(p);
// instead of pushing fresh particles all the time I would like the function, here, to check for free objects in the array
} // close for loop
} // close function makeParticle
function runtime() {
for(var i=0; i<particles.length; i++) {
var p = particles[i];
var thisType = p.type;
switch (thisType) {
case "blueFlame":
c.fillStyle = rgb(100,100,255);
c.fillCircle(p.x,p.y,p.size);
p.x += p.xVel;
p.y += p.yVel;
p.size*=0.9;
if (particles.size < 0.5) {
particleAlive = false;
particleRender = false;
} // close if
break;
case "redFlame":
c.fillStyle = rgb(255,100,100);
c.fillCircle(p.x,p.y,p.size);
p.x -= p.xVel;
p.y -= p.yVel;
p.size*=0.95;
if (particles.size < 0.5) {
particleAlive = false;
particleRender = false;
} // close if
break;
} // close switch
} // close function runtime
I've found previous answers to relate questions, but I've been unable to get it working within the makeParticle function, like how to assign the attributes of p to particle[j]:
var particleUseOldOrNew = function() {
for (var j = 0, len = particles.length; j < len; j++) {
if (particles[j].particleAlive === false)
// particles[j] = p;
return particle[j];
}
return null; // No dead particles found, create new "particles.push(p);" perhaps?
}
My personal opinion on the matter is that if you are making a new particle, it should be a new object, not a "re-using" of an old one with properties changed. Each new object should have a unique identifier, so if you need to track them (for development purposes, debugging, or later re-use), it is easy to do. Or at least keep a counter of the number of times you've re-used a particle object to represent a "new" particle! Though I guess if you've found that "re-using" improves performance (have you?), that's the way to go.
Anyway, enough pontificating, here is how I would do what you're asking (I assume speed is your main concern, so I did this with only native JS):
var particles = [];
//Function to create brand spanking new particle
function makeNewParticle(xPos, yPos, pRadius, pType){
return {
type : pType,
x : xPos,
y : yPos,
xVel : random(-0.5, 0.5),
yVel : random(-1, -3),
particleAlive : true,
particleRender : true,
size : pRadius
};
};
//Function to change the properties of an old particle to make a psuedo-new particle (seriously, why do you want to do this?)
function changeExistingParticle(existing, xPos, yPos, pRadius, pType){
existing.x = xPos;
existing.y = yPos;
existing.size = pRadius;
existing.type = pType;
return existing;
};
//Figure out the keys of dead particles in the particles[] array
function getDeadParticleKeys() {
var keys = [];
for(var p = 0; P < particles.length; p++) {
if (!particles[p].particleAlive) {
keys.push(p);
}
}
};
function makeParticle(numParticles, xPos, yPos, pRadius, pType) {
var d, i, deadParticles;
//Grab the "dead" particle keys
deadParticleKeys = getDeadParticleKeys();
numParticles -= deadParticleKeys.length;
//Replace each dead particle with a "live" one at a specified key
for (d = 0; d < deadParticleKeys.length; d++) {
particles[ deadParticleKeys[d] ] = changeExistingParticle(particles[ deadParticleKeys[d] ], xPos, yPos, pRadius, pType)
}
//If we had more particles than there were dead spaces available, add to the array
for (i = 0; i < numParticles; i++) {
particles.push( makeNewParticle(xPos, yPos, pRadius, pType) );
}
};
Now, here's how I recommend doing it: abandon the idea or "re-using" particles, make a separate constructor for each particle (will help immensely if you add methods to your particles in the future), and just scrap dead particles every time one is added:
//Make a constructor for a particle
var Particle = function(props){
if (typeof props === 'function') {
props = props();
}
this.type = props.type;
this.x = props.x;
this.y = props.y;
this.size = props.size;
};
Paticle.prototype.particleAlive = true;
Paticle.prototype.particleRender = true;
//Global particles list
var particles = [];
//Remove all dead element from a ParticleList
particles.clean = function(){
var p, keys;
for (p = this.length; p >= 0; p--) {
if (!p.particleAlive) {
this.splice(p, 1);
}
}
};
//Method for adding x amount of new particles - if num parameter isn't provided, just assume it to be 1
particles.add = function(props, num){
//First, clean out all the garbage!
this.clean();
//Now, append new particles to the end
var n, limit = (num && typeof num === 'number') ? num : 1;
for (n = 0; n < limit; n++){
particles.push( new Particle(props) );
}
};
//A couple examples
particles.add({ //Add a single blueFlame
type: "blueFlame",
size: 10,
x: 200,
y: 200
});
particles.add({ //Add 4 redFlames
type: "redFlame",
size: 10,
x: 300,
y: 200
}, 4);
particles.add(function(){//Add 4 greenFlames, with randomized XY cooridinates
this.x = Math.round(Math.random() * 1000);
this.y = Math.round(Math.random() * 1000);
this.size = 20;
this.type = "greenFlame";
}, 4);
Way less code to manage. I'm not sure which way is faster, but I'd bet the speed difference is negligible. Of course, you could check for yourself by making a quick jsPerf.
I'm building a game using HTML5 canvas.
You can find it here, along with the source code: www.techgoldmine.com.
I'd make a jsFiddle, but in all honesty my attention span is too short (and myself mostly too stupid) to learn how it works.
I'm currently stuck at a function that looks at the positioning of certain elements on either side of the canvas and moves them so that the y-axis area they cover does not overlap. I call them turbines, but thin white rectangles would be more accurate. I suggest refreshing a few times to visually understand what's going on.
This is the function that spawns the turbines:
function gameStateNewLevel(){
for (var i = 0; i < 4; i++){
turbine = {};
turbine.width = 10;
turbine.height = 150;
turbine.y = Math.floor(Math.random()*600)
if (Math.random()*10 > 5){
turbine.side = leftSide;
}else{
turbine.side = rightSide;
}
turbine.render = function (){
context.fillStyle = "#FFFFFF"
context.fillRect(turbine.side, turbine.y, turbine.width,turbine.height);
}
turbine.PositionTop = turbine.y;
turbine.PositionBottom = turbine.y + turbine.height;
turbines.push(turbine);
}
context.fillStyle = "#FFFFFF"
switchGameState(GAME_STATE_PLAYER_START);
}
So far I've built (with the help of you wonderful people) a function (that is part of a loop) picking out each of these turbines, and starts comparing them to one another. I'm completely stumped when it comes to understanding how I'll get them to move and stop when needed:
function updateTurbines(){
var l = turbines.length-1;
for (var i = 0; i < l; i++){
var tempTurbine1 = turbines[i];
tempTurbine1.PositionTop = tempTurbine1.y;
tempTurbine1.PositionBottom = tempTurbine1.y + tempTurbine1.height;
for (var j = 0; j < l; j++) {
var tempTurbine2 = turbines[j];
tempTurbine2.PositionTop = tempTurbine2.y;
tempTurbine2.PositionBottom = tempTurbine2.y + tempTurbine2.height;
if ((tempTurbine1 !== tempTurbine2) && FIXME == true){
if(tempTurbine1.PositionBottom >= tempTurbine2.PositionTop){
turbines[j].y -=2;
//A while loop breaks the browser :(
}
}
}FIXME = false;
}
}
Any ideas or requests for additional explanation and info are more than welcome. I also have a feeling I'm severely over complicating this. Goddamn my head hurts. Bless you.
I'm afraid your code is a little bit messy do I decided to begin with a clean slate.
Use getters/setters for bottom and right. You can calculate them given the left/width and top/height values, respectively. This will save you from altering the complementary variable right when modifying e.g. left.
You seem to be looking for a collison detection algorithm for rectangles. This is quite easy if the rectangles have the same x-coordinate - two such rectangles do not collide if the bottom of the first is above the top of the other, or if the top of the first is under the bottom of the other. Use this algorithm along with a while loop to generate a new turbine as long as they collide.
This is what I ended up with (it's a separate piece of code as I stated, so you'll have to blend it into your game): http://jsfiddle.net/eGjak/249/.
var ctx = $('#cv').get(0).getContext('2d');
var Turbine = function(left, top, width, height) {
this.left = left;
this.top = top;
this.width = width;
this.height = height;
};
Object.defineProperties(Turbine.prototype, {
bottom: {
get: function() {
return this.top + this.height;
},
set: function(v) {
this.top = v - this.height;
}
},
right: {
get: function() {
return this.left + this.width;
},
set: function(v) {
this.left = v - this.width;
}
}
});
var turbines = [];
function turbineCollides(tn) {
for(var i = 0; i < turbines.length; i++) {
var to = turbines[i];
// they do not collide if if one's completely under
// the other or completely above the other
if(!(tn.bottom <= to.top || tn.top >= to.bottom)) {
return true;
}
}
return false; // this will only be executed if the `return true` part
// was never executed - so they the turbine does not collide
}
function addTurbine() {
var t, h;
do { // do while loop because the turbine has to be generated at least once
h = Math.floor(Math.random() * 300);
t = new Turbine(0, h, 15, 100);
} while(turbineCollides(t));
turbines.push(t);
}
// add two of them (do not add more than 4 because they will always collide
// due to the available space! In fact, there may be no space left even when
// you've added 2.)
addTurbine();
addTurbine();
function draw() {
ctx.fillStyle = "black";
ctx.fillRect(0, 0, 400, 400);
ctx.fillStyle = "white";
for(var i = 0; i < turbines.length; i++) {
var turbine = turbines[i];
ctx.fillRect(turbine.left, turbine.top,
turbine.width, turbine.height);
}
}
draw();