Drawing more than 1 to canvas wont work? - javascript

I am trying to draw enemy ships to the canvas that will come from the right at a random x being the height of the canvas and a random y past the right side + 1000.
This works fine however I am trying to make it automated and the code runs run it just does not work on screen, only 1 is drawn? Any more info that you need just ask, It's really frying my brain I went line by line for around 3 hours and can't see an issue.
Before I added this code and just called one manually: http://www.taffatech.com/DarkOrbit.html
After I added this code for automatic: (it kinda looks like its overlapping)
http://www.taffatech.com/test.html
Globals:
var spawnInterval;
var totalEnemies = 0; //leave as is
var enemies = []; //array of enemy objects
var spawnRate = 2000; //every 2 seconds
var spawnAmount = 3; //amount of enemies spawned
Then my init() calls a startLoop:
function startLoop()
{
isPlaying = true;
Loop();
startSpawningEnemies();
}
function stopLoop()
{
isPlaying = false;
stopSpawningEnemies();
}
function Loop()
{
if (isPlaying == true)
{
Player1.draw();
requestAnimFrame(Loop);
drawAllEnemies();
}
then they use these functions:
function spawnEnemy(n) //total enemies starts at 0 and every-time you add to array
{
for (var x = 0; x < n; x++)
{
enemies[totalEnemies] = new Enemy();
totalEnemies++;
}
}
function drawAllEnemies()
{
ClearEnemyCanvas();
for(var i = 0; i < enemies.length; i++)
{
enemies[1].draw();
}
}
function startSpawningEnemies()
{
stopSpawningEnemies();
spawnInterval = setInterval(function() {spawnEnemy(spawnAmount);}, spawnRate); //this calls spawnEnemy every spawnRate
/////////spawn 'spawnAmount' enemies every 2 seconds
}
function stopSpawningEnemies()
{
clearInterval(
spawnInterval);
}
which in turn calls the Enemy class:
function Enemy() //Object
{
//////Your ships values
this.EnemyHullMax = 1000;
this.EnemyHull = 1000;
this.EnemyShieldMax = 1000;
this.EnemyShield = 347;
this.SpaceCrystalReward = 2684;
this.EnemySpeed = 2; //should be around 6 pixels every-time draw is called by interval, directly linked to the fps global variable
////////////
////Pick Ship
this.type = "Hover";
this.srcX = EnemySrcXPicker(this.type);
this.srcY = EnemySrcYPicker(this.type);
this.enemyWidth = EnemyWidthPicker(this.type);
this.enemyHeight = EnemyHeightPicker(this.type);
this.drawX = EnemydrawXPicker(this.type);
this.drawY = EnemydrawYPicker(this.type);
////
}
Enemy.prototype.draw = function()
{
this.drawX -= this.EnemySpeed;
ctxEnemy.globalAlpha=1;
ctxEnemy.drawImage(spriteImage,this.srcX,this.srcY,this.enemyWidth,this.enemyHeight,this.drawX,this.drawY,this.enemyWidth,this.enemyHeight);
}
function EnemySrcXPicker(type)
{
if (type == "Hover")
{
return 906;
}
}
function EnemySrcYPicker(type)
{
if (type == "Hover")
{
return 616;
}
}
function EnemydrawXPicker(type)
{
if (type == "Hover")
{
return Math.floor(Math.random() * 1000) + canvasWidthEnemy;
}
}
function EnemydrawYPicker(type)
{
if (type== "Hover")
{
return Math.floor(Math.random() * (canvasHeightEnemy - 72));
}
}
function EnemyWidthPicker(type)
{
if (type == "Hover")
{
return 90;
}
}
function EnemyHeightPicker(type)
{
if (type == "Hover")
{
return 72;
}
}

for(var i = 0; i < enemies.length; i++)
{
enemies[1].draw();
}
should probably be
for(var i = 0; i < enemies.length; i++)
{
enemies[i].draw();
}
...or you'll draw the same enemy over and over.

In your drawAllEnemies function, shouldn't
enemies[1].draw();
be
enemies[i].draw();
?

When you loop the enemies array you should use the index i that you setup so that it doesn't continually draw the same element:
for(var i = 0; i < enemies.length; i++)
{
enemies[i].draw();
}

Related

For-loop not working till the specified input

The loop in myFunctionlp, is not working to the specified user input through prompt which is round in this case. I want that loop to run until the input of the user which I am getting through prompt. myFunctionlp is being called by a button press.
var round = prompt("Enter number of rounds");
var defaultNumberOfRounds = 1;
var roundno = isNaN(Number(round)) ? defaultNumberOfRounds : round;
var images_arr = ["../img/paper.png", "../img/stone.png",
"../img/sisor.png"
];
var size = images_arr.length;
console.log(`round: ${round}, roundno: ${roundno}`);
function myFunctionlp() {
for (var i = 0; i < roundno; i++) { //this loop
console.log(i);
setInterval(function() {
var x = Math.floor(size * Math.random())
$('#random').attr('src', images_arr[x]); // JQuery
}, 1500);
setInterval(function() {
var sound = new Audio("../audio/audio.mp3");
sound.play();
if (s == 50) {
sound.pause();
} else {
alert("Hello");
}
}, 3000);
}
}
function stop() {
for (s = 0; s < 51; s++) {
console.log(s);
}
}
function extra() {
var music = new Audio("../audio/audio_3.mp3");
music.play();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button class="onClick" onclick="myFunctionlp()">Play</button>

Displaying frames properly in JavaScript

Okay, so I am developing a game in JavaScript. I have organized all the parts of the game in different JavaScript files. So, this is the Player.js file, every time I run this in my browser ( run from a html file of course), I come into this problem where the Player object flickers from a image to a transparent rectangle: heres the code:
function Player() {
this.frames = [];
this.right = true;
this.currentFrame = 0;
this.currentAction = "WALKING";
this.image = new Image();
this.x = 0;
this.y = 0;
this.setPosition = function(x, y) {
this.x = x;
this.y = y;
};
this.setVector = function(x, y) {
this.x += x;
this.y += y;
};
this.setAction = function(action) {
this.currentAction = action;
};
this.setRight = function(bool) {
this.right = bool;
}
this.draw = function(context) {
if(this.right == true) {
if(this.currentAction == "WALKING") {
this.frames = [ "res/playerRight.png" ];
}
} else if(this.right == false) {
if(this.currentAction == "WALKING") {
this.frames = [ "res/playerLeft.png" ];
}
}
if(this.currentFrame < this.frames.length) {
this.currentFrame += 1;
this.image.src = this.frames[this.currentFrame - 1];
context.drawImage(this.image, this.x,
this.y, 32, 32);
} else {
this.currentFrame = 0;
}
};
}
heres some images of what it does:
http://i.stack.imgur.com/1RcOC.png
http://i.stack.imgur.com/fxbNY.png
How about you preload all the images and you choose the correct one in your condition. Currently everytime you set the source the image is reloaded, and you are drawing it before it is ready.
// you can improve this part for your needs
var image1Loaded = false;
var image2Loaded = false;
this.preLoadImages = function (){
this.image1.onload = function (){
image1Loaded = true;
}
this.image2.onload = function (){
image2Loaded = true;
}
this.image1.src = "res/playerRight.png";
this.image2.src = "res/playerLeft.png";
}
now you can use the images directly in your draw method:
this.draw = function(context) {
var currentImage = "image1";
if(this.right == true) {
if(this.currentAction == "WALKING") {
currentImage = "image1";
}
} else if(this.right == false) {
if(this.currentAction == "WALKING") {
currentImage = "image2";
}
}
if(this.currentFrame < this.frames.length) {
this.currentFrame += 1;
var image = this[currentImage];
context.drawImage(image, this.x,
this.y, 32, 32);
} else {
this.currentFrame = 0;
}
};
Just make sure your images are already loaded before using them to draw on the canvas
Here's the bug:
if(this.currentFrame < this.frames.length) {
this.currentFrame += 1;
context.drawImage(); // <---------------- draw an image
} else {
this.currentFrame = 0; // <-------------- draw nothing!
}
So, let's run through this logic shall we. At the moment, frame length is 1.
currentFrame = 0
so we increment currentFrame
we draw the image
currentFrame = 1
currentFrame is not less than frames.length
we do not draw anything
we set current frame to 0
currentFrame = 0
so we increment currentFrame
we draw the image
repeat....
Result: flicker! If frame length is 2 it will flicker 33% of the time, if the frame length is 3 it will flicker 25% of the time etc.
The correct way to handle this:
this.currentFrame += 1;
if(this.currentFrame >= this.frames.length) {
this.currentFrame = 0;
}
this.image.src = this.frames[this.currentFrame]; // **
context.drawImage();
// **note: no need for -1 because currentFrame here is always
// less than frame.length
Or, if you're mathematical:
this.currentFrame = (this.currentFrame + 1) % this.frames.length;
this.image.src = this.frames[this.currentFrame];
context.drawImage();

Javascript Incrementing Numbers

What I'm after:
There are 5 counters on my page, they should all start from 0 and count upwards (increment) at the same time to different values that are set at different speeds. So for example I set 10, 25, 1500, 400, 500 in my variables I would like them all to reach these values.
• start at the same time
• all increment at different speeds
• stop at value set for each
My Problem
I can't figure out a good way to write some simple very efficient javascript to do this (going to be used on a mobile), currently I'm using setinterval which seems to start all the counters at different times and jerks/not smooth..
how far I've got so far
http://jsfiddle.net/95smH/
setInterval(f1,500);
setInterval(f2,1500);
setInterval(f3,500);
setInterval(f4,50);
var v1 = 0
, v2 = 0
, v3 = 0
, v4 = 0;
function f1() {
$('.count.v1').text(v1);
if ( v1 < 450 )
{
v1 ++;
}
}
function f2() {
$('.count.v2').text(v2);
if ( v2 < 50 )
{
v2 ++;
}
}
function f3() {
$('.count.v3').text(v3);
if ( v3 < 23 )
{
v3 ++;
}
}
function f4() {
$('.count.v4').text(v4);
if ( v4 < 4 )
{
v4 ++;
}
}
This would be my shot at a slightly more general way. It will also kill the setInterval once every counter has finished. Of course this will still have the typical inaccuracy of Javascript intervals.
var counter = new (function () {
'use strict';
var counters = [],
handler = null,
precision = 50;
this.addCounter = function (maxValue, interval, selector) {
counters.push({
maxValue: maxValue,
currentValue: 0,
interval: interval / precision,
intervalCounter: 0,
$output: $(selector)
});
return this;
};
this.start = function () {
handler = setInterval(function () {
var stillRunning = false;
for (var i = 0; i < counters.length; i++) {
var counter = counters[i];
counter.intervalCounter++;
if (counter.intervalCounter === counter.interval) {
counter.intervalCounter = 0;
counter.currentValue++;
if (counter.currentValue <= counter.maxValue) {
stillRunning = true;
counter.$output.val(counter.currentValue);
}
} else {
stillRunning = true;
}
}
if (!stillRunning) {
clearInterval(handler);
}
}, precision);
};
return this;
})();
counter
.addCounter(50, 250, '.v1')
.addCounter(25, 500, '.v2')
.start();
Demo fiddle: http://jsfiddle.net/s9AYz/1/
Note that precision must be set such that the interval of each counter is a multiple of it (Boris solution has the same requirement).
This is based on your own code style:
setInterval(tick,50);
var cusers = 0
, cawardshows = 0
, ccountries = 0
, cregions = 0;
var susers = 500
, sawardshows = 1500
, scountries = 500
, sregions = 50;
var i = 0;
function tick() {
$('.count.users').text(cusers);
if ( cusers < 450 && i % susers == 0)
{
cusers ++;
}
$('.count.awardshows').text(cawardshows);
if ( cawardshows < 50 && i % sawardshows == 0 )
{
cawardshows ++;
}
$('.count.countries').text(ccountries);
if ( ccountries < 23 && i % scountries == 0 )
{
ccountries ++;
}
$('.count.regions').text(cregions);
if ( cregions < 4 && i % sregions == 0)
{
cregions ++;
}
i += 50;
}
The idea is to have only one timer, so all updates will be synchronized to the same clock. Since values have different "speeds", you update some of them only every nth step.
Here is a solution quite cpu-friendly :
- you only have one setInterval using a base period that you decide.
- On each interval you iterate through your all counters doing very little work each time.
(i even avoided to use % ).
- The elements are cached.
jsbin is here :
http://jsbin.com/urUxojo/2/edit?html,js,console,output
window.onload=function() {
// this is the period of the base Interval in ms.
// The counters will be aligned on this base period
Counter.basePeriod = 50 ;
// constructor of a Counter
// ! initializes the counter display.
function Counter(id, period_ms, max, initialValue) {
this.element = document.getElementById(id);
this.period = Math.ceil(period_ms / Counter.basePeriod) || 1;
this.max = max ;
this.value = initialValue || 0 ;
this.last = 0;
this.element.value = (this.value);
return this;
};
// called on each basePeriod tick
// updates the element every period until it reaches its max value.
Counter.prototype.tick = function() {
this.last++;
if (this.last == this.period &&
this.value != this.max ) {
this.value++;
this.element.value = (this.value);
this.last=0;
}
};
Counter.counters = [];
Counter.start= function () {
function handleCounters() {
for (var i=0; i< Counter.counters.length; i++) { Counter.counters[i].tick(); }
}
Counter._interval = setInterval(handleCounters, Counter.basePeriod);
};
Counter.add = function() {
var newCounter = Object.create(Counter.prototype);
Counter.counters.push( Counter.apply(newCounter, arguments) );
}
// -------------------------------
Counter.add('cnt1' , 500 , 450 );
Counter.add('cnt2' , 400 , 40 );
Counter.add('topCounter', 1000 , 5 );
Counter.start();
}
Well, you always want to get rid of duplicity, so you can do:
function IntervalClass(selector, sleepTime, maxValue, startValue) {
var curValue = startValue;
this.tick = function () {
if (curValue < maxValue) {
curValue++;
}
$(selector).html(curValue);
};
this.start = function () {
setInterval(this.tick, sleepTime);
};
}
new IntervalClass(".count.users", 1000, 35, 0).start();
new IntervalClass(".count.awardshows", 500, 20, 0).start();
new IntervalClass(".count.countries", 1500, 15, 0).start();
new IntervalClass(".count.regions", 200, 100, 0).start();
JSFIDDLE

Does Canvas keep going if you leave the page?

Click this link, after around 2 seconds you will see some ships coming at you. Now go to a different window for like 15-20 seconds. then come back, you will see a huge wall of enimes coming at you. Now obviously this is because canvas keeps the loops going but is just not letting the came continue on?
So any help would be great, I know this is not an issue during gameplay but if anyone goes off the window then it kind of messes things up...
I tried to solve this by adding these listeners:
window.onblur = function() {
// Add logic to pause the game here...
stopLoop();
};
window.onfocus = function() {
// Add logic to pause the game here...
startLoop();
};
But it does not solve the issue...
The actual loops:
function init()
{
isPlaying = true;
drawBackground();
drawBars();
setUpListeners();
startLoop();
}
and then...
function Loop()
{
if (isPlaying == true)
{
Player1.draw();
requestAnimFrame(Loop);
drawAllEnemies();
}
}
function startLoop()
{
isPlaying = true;
Loop();
startSpawningEnemies();
}
function stopLoop()
{
isPlaying = false;
stopSpawningEnemies();
}
function spawnEnemy(n) //total enemies starts at 0 and every-time you add to array
{
for (var x = 0; x < n; x++)
{
enemies[totalEnemies] = new Enemy();
totalEnemies++;
}
}
function drawAllEnemies()
{
ClearEnemyCanvas();
for(var i = 0; i < enemies.length; i++)
{
enemies[i].draw();
}
}
function startSpawningEnemies()
{
stopSpawningEnemies();
spawnInterval = setInterval(function() {spawnEnemy(spawnAmount);}, spawnRate); //this calls spawnEnemy every spawnRate
/////////spawn 'spawnAmount' enemies every 2 seconds
}
function stopSpawningEnemies()
{
clearInterval(spawnInterval);
}
Actual methods for the enemy:
function Enemy() //Object
{
//////Your ships values
this.EnemyHullMax = 1000;
this.EnemyHull = 1000;
this.EnemyShieldMax = 1000;
this.EnemyShield = 347;
this.SpaceCrystalReward = 2684;
this.EnemySpeed = 2; //should be around 6 pixels every-time draw is called by interval, directly linked to the fps global variable
////////////
////Pick Ship
this.type = "Hover";
this.srcX = EnemySrcXPicker(this.type);
this.srcY = EnemySrcYPicker(this.type);
this.enemyWidth = EnemyWidthPicker(this.type);
this.enemyHeight = EnemyHeightPicker(this.type);
this.drawX = EnemydrawXPicker(this.type);
this.drawY = EnemydrawYPicker(this.type);
////
}
Enemy.prototype.draw = function()
{
this.drawX -= this.EnemySpeed;
ctxEnemy.globalAlpha=1;
ctxEnemy.drawImage(spriteImage,this.srcX,this.srcY,this.enemyWidth,this.enemyHeight,this.drawX,this.drawY,this.enemyWidth,this.enemyHeight);
}
function EnemySrcXPicker(type)
{
if (type == "Hover")
{
return 906;
}
}
function EnemySrcYPicker(type)
{
if (type == "Hover")
{
return 616;
}
}
function EnemydrawXPicker(type)
{
if (type == "Hover")
{
return Math.floor(Math.random() * 1000) + canvasWidthEnemy;
}
}
function EnemydrawYPicker(type)
{
if (type== "Hover")
{
return Math.floor(Math.random() * (canvasHeightEnemy - 72));
}
}
function EnemyWidthPicker(type)
{
if (type == "Hover")
{
return 90;
}
}
function EnemyHeightPicker(type)
{
if (type == "Hover")
{
return 72;
}
}
Depends on the loop.
If you use setTimeOut or setInterval, then yes. The loop will continue even when the window loses focus.
If you use requestFrameAnimation, then no, the loop will stop when the window loses focus.
requestFrameAnimation was created to solve issues like this. Having you PC burn CPU cycles for something not active is just silly.

mouseover timeout too fast

I'm using javascript to set my mouseover at the left nav. But the problem is, the timeout is faster than it should be. How do I make it longer on mouseover?
stuHover = function () {
var cssRule;
var newSelector;
for (var i = 0; i < document.styleSheets.length; i++) {
for (var x = 0; x < document.styleSheets[i].rules.length; x++) {
cssRule = document.styleSheets[i].rules[x];
if (cssRule.selectorText.indexOf("LI:hover") != -1) {
newSelector = cssRule.selectorText.replace(/LI:hover/gi, "LI.iehover");
document.styleSheets[i].addRule(newSelector, cssRule.style.cssText);
}
}
}
var getElm = document.getElementById("nav").getElementsByTagName("LI");
for (var i = 0; i < getElm.length; i++) {
getElm[i].onmouseover = function () {
this.className += " iehover";
}
getElm[i].onmouseout = function () {
this.className = this.className.replace(new RegExp("iehover\\\b"), "")
}
}
}
if (window.attachEvent) window.attachEvent("onload", stuHover);
You want something like this:
getElm[i].onmouseout = function() {
var t = this;
setTimeout(function() {
t.className = t.className.replace(" iehover","");
},5000); // 5 seconds
};
Although really, if I had to wait 5 seconds for something to disappear if I accidentally moved over the trigger area, I'd be annoyed. Try 250 instead (0.25 seconds).

Categories

Resources