I have a game I am making: http://www.taffatech.com/DarkOrbit.html
What I want to be able to do is when I kill a certain amount of enemies it will level up. This part is working, however I also want the spawn amount to increase when you level up.
In my loop function:
function Loop()
{
if (isPlaying == true)
{
updateLevel(); //this updates the level but it calls it every frame which might be bad.
Player1.draw();
drawAllEnemies();
updateStats();
requestAnimFrame(Loop);
}
The update level function:
function updateLevel()
{
if(Player1.enemiesKilled <3)
{
level = 1;
}
else if(Player1.enemiesKilled > 3 && Player1.enemiesKilled <= 9)
{
level = 2;
}
else if(Player1.enemiesKilled > 9 && Player1.enemiesKilled <=18)
{
level = 3;
}
else if(Player1.enemiesKilled > 18 && Player1.enemiesKilled <= 38)
{
level = 4;
}
else if(Player1.enemiesKilled > 38 && Player1.enemiesKilled <= 70)
{
level = 5;
s
}
else if (Player1.enemiesKilled > 120)
{
level = 6;
}
if(level == 1)
{
spawnAmount = 1;
}
else if(level == 2)
{
spawnAmount = 2;
}
else if(level == 3)
{
spawnAmount = 3;
}
else if(level == 4)
{
spawnAmount = 4;
}
else if(level == 5)
{
spawnAmount = 5;
}
else if(level == 6)
{
spawnAmount = 6;
}
}
spawn enemy function:
function spawnEnemy(number) //total enemies starts at 0 and every-time you add to array
{
for (var x = 0; x < number; x++)
{
enemies[enemies.length] = new Enemy();
}
}
My init:
function init()
{
spawnEnemy(spawnAmount);
drawMenu();
sndIntro.play();
document.addEventListener('click', mouseClicked ,false);
}
I tried adding: spawnEnemy(spawnAmount); to after I change the spawn amount global var in the updateLevel function but as this gets called every frame it makes hundreds of enemies fly at me. How can I solve this problem?
If I try something like this hundreds of enemies are genrated, I assume because it gets called every frame:
if(level == 1)
{
spawnAmount = 1;
spawnEnemy(spawnAmount);
}
If your intent is to increase the spawn rate on each level, I'd suggest you start off with a spawnRate first. Let spawnRate represent the number of game updates in between enemy spawns. Every time an enemy spawns, decrement another variable (say spawnRateCountdown), until that variable reaches 0, Then spawn an enemy. Reset the variable back up to the spawnRate. Rinse and repeat.
spawnRate = 60; /* one enemy every 60 updates. */
spawnRateCountdown = spawnRate;
function updateLoop() {
spawnRateCountdown--;
if (spawnRateCountdown == 0) {
spawnRateCountdown = spawnRate;
spawnEnemy();
}
}
After that, you can just update your spawnRate variable as you see fit.
The problem is that you don't create new enemies from time to time, but just shift the same enemy further away on its explosion (i.e. call recycleEnemy method). This single enemy is spawned only once: spawnEnemy function is called in init method only with argument 1.
You should rework enemy spawning algorithm. Below is a pretty good sample, which increases enemy spawning rate:
Remove number argument from spawnEnemy function: spawn only one enemy
Change Enemy.prototype.recycleEnemy function to remove this from enemies. Be cautious: if you'll call this function inside a loop by enemies, you will need to decrease counter to make sure that you won't skip next enemy: --i
Add a function getSpawnCooldown() { return 100 / spawnAmount; } (100 is approximate constant, you can variate it to change initial spawning rate)
Add a variable time which means the number of effective Loop calls from the beginning, defaults to 0
Add a variable lastSpawnTime, set it to 0
Inside if block of Loop function, add lines:
++time
if (time >= lastSpawnTime + getSpawnCooldown()) spawnEnemy();
In spawnEnemy function, add a line: lastSpawnTime += getSpawnCooldown()
Generally, you should better structurize your code. At least, split it to several js files which are responsible for different parts of your application.
Related
Im trying to finetune the controls of a javascript game (p5 library).
keyIsDown() is the type of control/feel im looking for but it's timing is too fast.
By timing is too fast, I mean when I hold down the key, the key repeats too fast. Im trying to control the timing speed of the key repeat when holding down the key.
I tried to make my own vertion with keytyped() and setInterval to time my move function. Then stopping it with keyReleased(). But it jams up.
I have also tried setTimeout but could not get it to work on keyboard input like this.
var controlInterval;
function keyReleased() {
if (key === 'a') {
clearInterval(controlInterval);
} else if (key === 'd') {
clearInterval(controlInterval);
}
//return false; // prevent any default behavior
}
function keyTyped() {
if (key === 'a') {
controlInterval = setInterval(left, 50);
} else if (key === 'd') {
controlInterval = setInterval(right, 50);
}
}
function left(){
var x = -1;
move(x);
}
function right(){
var x = 1;
move(x);
}
code I prefer to use:
if (keyIsDown(LEFT_ARROW)){
var west = -1;
move(west);
}
if (keyIsDown(RIGHT_ARROW)){
var east = 1;
move(east);
Take a look at debouncing and throttling principles which I think is what you are looking for here - limit the execution count of event.
The best explanation IMHO related to this subject is this article.
There are already libraries to help you like lodash. Go to their documentation page and search the functions - debounce or throttle and it there will be examples how to use them.
someDiv.addEventListener('keyup', _.debounce(handleKeyUp, 300));
function handleKeyUp(event) {
if (event.keyCode === 65 /* A */) left();
...
}
Arrow keys can be used to signal a direction, frame rate can be used to control speed and a delta variable used to control the amount of movement.
var xPos = 0;
var xDelta = 1;
function setup(){
createCanvas(200,200);
frameRate(10); // 10 frames per second, increase to move faster
}
function draw(){
background(100);
if (keyIsDown(LEFT_ARROW)){
var west = -1;
move(west);
}
if (keyIsDown(RIGHT_ARROW)){
var east = 1;
move(east);
}
rect(xPos, 100, 10,10);
}
function move(dir){
if (dir == -1){
xPos = xPos - xDelta;
}
else {
xPos = xPos + xDelta;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/0.8.0/p5.min.js"></script>
function draw() {
background(51);
balloon.show();
balloon.update();
score.time();
var state = 0;
if (frameCount % 100 == 0) {
blocks.push(new Blocks());
}
while (state != 1) {
for (var i = blocks.length-1; i >= 0; i--) {
blocks[i].show();
blocks[i].update();
if (blocks[i].offscreen()) {
blocks.splice(i, 1);
}
if (blocks[i].hits(balloon)) {
blocks = null
console.log("hitted");
state = 1;
}
}
}
}
So basically I just want the blocks array to stop drawing themselves on the screen once the "balloon" object hits one of them. I get no error after running it, and I get the text written on the console, so the collision is working as intended. Any ideas why the loop doesn't stop?
I have a script for a gambling site.
What I need is that after 2 calls to the function multiply, it bets the maximum stake possible and after that calls the function reset, I mean in each two sequential loss it bets the full balance in my account reset for the minimum stake and continue playing, Because I realized that in odds of 1.1 on 'manual bet' in each 2 loss the next will be a won.
It is like: after 2 multiplyCalls bet the full balance (it is the "MAX" button in the image below) and reset the game to continue playing. Am I being clear enough?
I tried to create a function for this but did not work
The "Maximum stake" button element code is:
MAX
this is the printscreen
The part of the script I want to modify is this, the multiplyCalls function is already created. I changed the var multiply = (current * 2).toFixed(8); to var multiply = (current * 1).toFixed(8); because my strategy does not have martingale.
function multiply(){
if(multiplyCalls < 2){ // test multiply
var current = $('#double_your_btc_stake').val();
var multiply = (current * 2).toFixed(8);
$('#double_your_btc_stake').val(multiply);
multiplyCalls++; // increment
}else{
reset();
console.log('=== RESETING ===');
}
}
This is the full script:
var startValue = '0.00000001', // Don't lower the decimal point more than 4x of current balance
stopPercentage = 0.001, // In %. I wouldn't recommend going past 0.08
maxWait = 500, // In milliseconds
stopped = false,
stopBefore = 3; // In minutes
multiplyCalls = 0; // <--- Added this global
var $loButton = $('#double_your_btc_bet_lo_button'),
$hiButton = $('#double_your_btc_bet_hi_button');
function multiply(){
if(multiplyCalls < 2){ // test multiply
var current = $('#double_your_btc_stake').val();
var multiply = (current * 1).toFixed(8);
$('#double_your_btc_stake').val(multiply);
multiplyCalls++; // increment
}else{
reset();
console.log('=== RESETING ===');
}
}
function getRandomWait(){
var wait = Math.floor(Math.random() * maxWait ) + 100;
console.log('Waiting for ' + wait + 'ms before next bet.');
return wait ;
}
function startGame(){
console.log('Game started!');
reset();
$loButton.trigger('click');
}
function stopGame(){
console.log('Game will stop soon! Let me finish.');
stopped = true;
}
function reset(){
$('#double_your_btc_stake').val(startValue);
}
// quick and dirty hack if you have very little bitcoins like 0.0000001
function deexponentize(number){
return number * 1000000;
}
function iHaveEnoughMoni(){
var balance = deexponentize(parseFloat($('#balance').text()));
var current = deexponentize($('#double_your_btc_stake').val());
return ((balance*2)/100) * (current*2) > stopPercentage/100;
}
function stopBeforeRedirect(){
var minutes = parseInt($('title').text());
if( minutes < stopBefore )
{
console.log('Approaching redirect! Stop the game so we don\'t get redirected while loosing.');
stopGame();
return true;
}
return false;
}
// Unbind old shit
$('#double_your_btc_bet_lose').unbind();
$('#double_your_btc_bet_win').unbind();
// Loser
$('#double_your_btc_bet_lose').bind("DOMSubtreeModified",function(event){
if( $(event.currentTarget).is(':contains("lose")') )
{
console.log('You LOST! Multiplying your bet and betting again.');
multiply();
setTimeout(function(){
$loButton.trigger('click');
}, getRandomWait());
//$loButton.trigger('click');
}
});
// Winner
$('#double_your_btc_bet_win').bind("DOMSubtreeModified",function(event){
if( $(event.currentTarget).is(':contains("win")') )
{
if( stopBeforeRedirect() )
{
return;
}
if( iHaveEnoughMoni() )
{
console.log('You WON! But don\'t be greedy. Restarting!');
reset();
if( stopped )
{
stopped = false;
return false;
}
}
else
{
console.log('You WON! Betting again');
}
setTimeout(function(){
$loButton.trigger('click');
}, getRandomWait());
multiplyCalls = 0; // reset value
}
});startGame
So basically, you want to max the bet after two losses. Because multiply calls only occur after a loss, we can assume that the if(multiplyCalls < 2) bit takes care of that. So in the following else, all you really need to do is hit max bet instead of call reset(). Based on what I understand the code to be doing, this should be sufficient, correct?
function multiply(){
if(multiplyCalls < 2){ // test multiply
var current = $('#double_your_btc_stake').val();
var multiply = (current * 1).toFixed(8);
$('#double_your_btc_stake').val(multiply);
multiplyCalls++; // increment
}else{
//reset(); /* instead of resetting here, let's max the bet. */
$('#double_your_btc_max').trigger('click');
console.log('=== RESETING ===');
}
}
I'm making a game where if the player hits the enemy from top, after 1 sec period,(that is to show dying animation), the enemy will splice out of the array.
It works fine while killing each enemy one by one, but when two enemies get killed at the same time, a problem occurs.
For example, if the enemies were in position 2 and 3 of the array when killed. After splicing it, the position 3 comes to position 2.
The second splice doesn't work as the position is already changed.
Is there a fix to this or a different method, or is my logic just plain invalid.
for (var i = 0; i < enemies.length; i++) {
var collWithPlayer= that.collisionCheck(enemies[i], player);
if (collWithPlayer == 't') { //kill enemies if collision is from top
enemies[i].state = 'dead';
player.velY = -((player.speed));
score.totalScore += 1000;
score.updateTotalScore();
//immediately-invoked function for retaining which enemy died
(function(i){
setTimeout(function() { //show squashed enemy for a brief moment then splice
enemies.splice(i, 1);
}, 1000);
})(i);
So what I did was use a filter function on the enemy array that returns a new array containing only enemies that are still alive, or have only been dead for a little while.
Creating a delay between 'dead' and 'remove' can be done with a 'decay' property on an object. You can update/increase the value of this decay-property on every game-tick.
// inside a gametick loop
var enemyCollisions = [];
enemies = enemies.filter(function (item) {
collisionWithPlayer = that.collisionCheck(item, player);
if (collisionWithPlayer === 't') {
item.state = 'dead';
item.decay = 0;
enemyCollisions.push({
direction: collisionWithPlayer,
with: item
});
}
if (typeof item.decay === 'number') {
item.decay = item.decay + 1;
}
return (item.state !== 'dead' && item.decay > 62);
});
enemyCollisions.forEach(function (item) {
if (item.direction === 't') {
player.velY = -((player.speed));
score.totalScore += 1000;
score.updateTotalScore();
} else {
//TODO deal with collisions other then 't'
}
});
Use a reverse for loop.
for (var i = enemies.length; i--;){
// your stuff here
// hopefully the timeout isn't necessary, or this still has a chance of not working, considering race conditions
enemies.splice(i, 1);
}
// if it is, do the timeout outside of the for loop
That way, when you splice, you splice behind you instead of in front of you.
You could also filter the array like below.
function myfunc(){
var enemies = [1,2,3,4,5];
var elementToRemove = 3;
enemies = enemies.filter(function(val){
return (val !== elementToRemove ? true : false);
},elementToRemove);
alert('[' + enemies.join(' , ') + ']');
}
<button id="btn" onclick="myfunc();">Go</button>
You could simply capture the actual enemies[i] object instead of i to remove it correctly from the array once the post-mortem dislay is done no matter what the index will be at that time:
(function(e){
setTimeout(function(){
enemies.splice(enemies.indexOf(e), 1);
}, 1000);
})(enemies[i]);
I have a for loop outside of these two big if´s. My problem seems to be that the second function seems to fire off with a short delay. Should´t First function be done and then second will run?
Can´t figure the problem out why second start before first one is finished. When second function fires aswell it will increase the orignal number from zero to 60.
if(activeSlideBoolean && activeSlide < i){
step = 0;
div[activeSlide].className = 'slide left';
animateHalfLeft(activeSlide);
function animateHalfLeft(activeSlide){
if(step < -60){
return;
}
div[activeSlide].style.left = step+'em';
step -= 6;
setTimeout (function(){ animateHalfLeft(activeSlide);},100);
}
activeSlideBoolean = false;
}
if((activeSlideBoolean === false) && (RestOfSlides)){
step = 60;
animateTotalLeft(RestOfSlides);
function animateTotalLeft(RestOfSlides){
f(step < -60){
return;
}
div[RestOfSlides].style.left = step+'em';
step -= 6;
setTimeout (function(){ animateTotalLeft(RestOfSlides);},100);
}
}
Your function animateHalfLeft and animateTotalLeft are exactly the same except for one thing the argument activeSlide and RestOfSlides.
I suggest first to create a separate function :
function animateToLeft(whatToSlide){
if(step < -60){
return;
}
div[whatToSlide].style.left = step+'em';
step -= 6;
setTimeout (function(){ animateToLeft(whatToSlide);},100);
}
}
But the function is still finishing before setTimeout ends (or even starts).
Javascript is a functional language. Use it :
function animateToLeft(whatToSlide, step, callback){
if(step < -60){
if (typeof callback === 'function') {
callback();
}
return;
}
div[whatToSlide].style.left = step+'em';
step -= 6;
setTimeout (function(){
animateToLeft(whatToSlide , step, callback);
},100);
}
}
if(activeSlideBoolean && activeSlide < i){
var isStarted = false;
animateToLeft(activeSlide, 0, function() {
if (isStarted) {
return;
}
isStarted = true;
if (RestOfSlides) {
animateToLeft(RestOfSlides, 60, null);
// Finishing order 3
}
});
// Finishing order 1
}
if(activeSlideBoolean === false && RestOfSlides){
animateToLeft(RestOfSlides, 60, null);
// finishing order 2
}
I don't know if it works for you (don't copy/paste idiotly) but for me, it's a good start.