I am following exactly this tutorial on
Youtube :
https://www.youtube.com/watch?v=ohlrknEwobs&list=PLE10sFVGtI1ejzPFmX5CebHrTMhaCx2oI&index=31
The concept is to make an avoid-er game in which 3 objects fall vertically, one of which will increase point score, and the other two which will end the game.
I have created 4 objects within an array which are as follows:
var:objects Array = [new BlueBird(),new RedBird(),new Goomba(),new Ham()]
// objects[0] = Is a Blue Bird which jumps to scene 3 ("Death Scene")
// objects[1] = Is a Red Bird which jumps to scene 3 ("Death Scene")
// objects[2] = Is a Goomba which jumps to scene 3 ("Death Scene")
// objects[3] = Is an piece of Ham which adds Points
Here is the statement that I am having trouble with. I can't get the object[3], the piece of Ham, to test for else if statement. I coded in && objectsIndex == 3, but it did not work:
if((Pig.hit).hitTestObject(objects[objectsIndex]))
{
// Reset objects to y positions
objects[objectsIndex].x = randomRange(0,3) * 50
objects[objectsIndex].y = -50;
stage.removeEventListener(KeyboardEvent.KEY_DOWN,pressedButton);
stage.removeEventListener(Event.ENTER_FRAME,CollisionSensor);
stage.frameRate = 24;
gotoAndStop(1,"GG WP");
//trace ("you died!");
}
else if((Pig.hit).hitTestObject(objects[objectsIndex]) && objectsIndex == 3)
{
score = score + 1; //increase score by 1 point
text1.text = String(score); // Score is now a string value
// Since text1 is a text box, it must be denotated as a string
// Reset the objects to y positions
objects[objectsIndex].x = randomRange(0,3) * 50;
objects[objectsIndex].y = -50
}
Here is the entire Projects Code for Reference:
stop();
import flash.events.Event;
stage.focus = this;
stage.addEventListener(KeyboardEvent.KEY_DOWN, pressedButton);
stage.addEventListener(Event.ENTER_FRAME, CollisionSensor);
var score:Number = 0; //Player Score
var enemy_velocity:Number = 5;
var objects:Array = [new RedBird(),new Goomba,new BlueBird(),new Ham()];
// objects[0] is a RedBird
// objects[1] is a Goomba
// objects[2] is a BlueBird
// objects[3] is an piece of Ham
var objectsIndex:Number = randomRange(0,3); //Randomizer
//Picks a random array value
for (var i:int=0; i<objects.length; i++)
{
objects[i].x = randomRange(0,3) * 50;
objects[i].y = -50;
//Brings objects to stage
stage.addChild(objects[i]);
}
//Generate a ranodom number from minNum to maxNum including the endpoints
function randomRange(minNum:Number, maxNum:Number):Number
{
return (Math.floor(Math.random() * (maxNum - minNum + 1)) + minNum);
}
function CollisionSensor(e:Event)
{
objects[objectsIndex].y = objects[objectsIndex].y + enemy_velocity;
// check if enemy objects have gone past the bottom of the game screen
if (objects[objectsIndex].y > stage.stageHeight)
{
objects[objectsIndex].y = -50; //Resets objects in array and parameters
// To enter frame in a repeated loop
//Randomizes a random x position for Objects
var num:Number = randomRange(0,3);
//This creates 4 random x positions - 0,50,100,150 To randomly place
//The array objects in
objects[objectsIndex].x = num * 50;
// now pick a random object
objectsIndex = randomRange(0,3);
// objects[0] is a RedBird
// objects[1] is a Goomba
// objects[2] is a BlueBird
// objects[3] is an piece of Ham
if(stage.frameRate <= 60)
{
stage.frameRate = stage.frameRate + 5;
}
else
{
stage.frameRate = 60;
if (enemy_velocity <= 25)
{
enemy_velocity += 1;
}
else
{
enemy_velocity = 25;
}
}
}
//check contanct with enemy objects
if((Pig.hit).hitTestObject(objects[objectsIndex]))
{
// Reset objects to y positions
objects[objectsIndex].x = randomRange(0,3) * 50
objects[objectsIndex].y = -50;
stage.removeEventListener(KeyboardEvent.KEY_DOWN,pressedButton);
stage.removeEventListener(Event.ENTER_FRAME,CollisionSensor);
stage.frameRate = 24;
gotoAndStop(1,"GG WP");
//trace ("you died!");
}
else if((Pig.hit).hitTestObject(objects[objectsIndex]) && objectsIndex == 3)
{
score = score + 1;
//increase score by 1 point
`text1.text = String(score);` // Score is now a string value
// Since text1 is a text box, it must be denotated as a string
// Reset the objects to y positions
objects[objectsIndex].x = randomRange(0,3) * 50;
objects[objectsIndex].y = -50
}
}
function pressedButton(event:KeyboardEvent):void
{
if (event.keyCode == Keyboard.LEFT && Pig.x >= 0)
{
Pig.x = Pig.x - 50;
}
else if (event.keyCode == Keyboard.RIGHT && Pig.x <= 150)
{
Pig.x = Pig.x + 50;
}
}
Thank you, and as always, have a nice day :)
You might have other issues with your code but this does look right
if((Pig.hit).hitTestObject(objects[objectsIndex]))
it should be..
if((Pig).hitTestObject(objects[0]))
where objects[0] would be the index in the array to access for testing against. But that might even have issues so get specific names of what you added on stage try this in your for loop that adds objects to stage
//Brings objects to stage
stage.addChild(objects[i]);
trace ("added object name : " + objects[i] );
Whatever name you got there is what you test against if( (Pig).hitTestObject(namehere) )
Related
I have a flappy bird game built with p5.js, every bird in my game is a neural network with 4 inputs, 4 hidden nodes, and 1 output.
if the output is bigger than 0.5, the bird should jump.
I use the genetics algorithm to improve the neural network, and I mostly select the neural networks(birds) with the best weights and biases, which are determined by the fitness score, crossover the parents, mutate by a low rate, and pass the offspring on to the next generation.
So for total of 10 birds, in the next generation, there should be 10 offspring that are somewhat better than the last 10 birds' generation.
After printing the fitness scores of my birds, seems like even after 300 generations, there is no improvement in the fitness score of each individual bird.
The way I calculate fitness is by the score itself, the score is incrementing every frame for each bird, and the longer the bird stays alive, the higher the score is.
My first approach was to look for anything that could overwrite the next generation with a brand new array of birds, but I couldn't spot anything that does it.
nextGeneration():
const nextGeneration = () => {
calculateFitness();
for (let i = 0; i < TOTAL; i++) {
// Select the most fit bird
let bird1 = rouletteWheelSelection();
print("Bird 1: " + bird1.fitness)
// Select another most fit bird
let bird2 = rouletteWheelSelection();
print("Bird 2: " + bird2.fitness)
// Use the crossover function to create an offspring from bird1 and bird2
let offspringBrain = crossOver(bird1, bird2);
// Mutate the offspring's brain with a small probability
offspringBrain.mutate(0.1);
// Add the offspring to the new population of birds
birds[i] = new Bird(offspringBrain);
}
// Clear the saved birds for the next generation
savedBirds = [];
}
rouletteWheelSelection():
const rouletteWheelSelection = () => {
//Sum of total fitness
let totalFitness = 0
savedBirds.forEach( element => {
totalFitness += element.fitness
});
// Generate a random number between 0 and the total fitness
const rand = Math.random() * totalFitness;
// Select the chromosome with the corresponding fitness
let fitnessSum = 0;
for (let i = 0; i < savedBirds.length; i++) {
fitnessSum += savedBirds[i].fitness;
if (fitnessSum >= rand) return savedBirds[i];
}
}
crossOver():
const crossOver = (bird1, bird2) => {
// Create a new NeuralNetwork by cloning bird1's brain
let offspring = bird1.brain.copy()
// Select a random point to split the weights and biases
let splitPoint = Math.floor(Math.random() * offspring.weights_ih.data.length);
// Cross over the weights and biases of bird1 and bird2 at the split point
for (let i = splitPoint; i < offspring.weights_ih.data.length; i++) {
offspring.weights_ih.data[i] = bird2.brain.weights_ih.data[i];
offspring.weights_ho.data[i] = bird2.brain.weights_ho.data[i];
offspring.bias_h.data[i] = bird2.brain.bias_h.data[i];
offspring.bias_o.data[i] = bird2.brain.bias_o.data[i];
}
return offspring;
}
draw() in the main sketch.js file:
function draw() {
if (counter % 150 == 0) {
pipes.push(new Pipe());
}
counter++;
for (var i = pipes.length - 1; i >= 0; i--) {
pipes[i].update();
for (let j = birds.length - 1; j >= 0; j--) {
if (pipes[i].hits(birds[j])) {
savedBirds.push(birds.splice(j, 1)[0]);
}
if (pipes[i].offscreen()) {
pipes.splice(i, 1);
}
}
}
for (let bird of birds) {
bird.think(pipes);
bird.update();
}
if (birds.length == 0 ) {
counter = 0;
nextGeneration();
pipes = [];
}
background(bgImg);
for (let bird of birds) {
bird.show();
}
for (let pipe of pipes) {
pipe.show();
}
}
Another approach I had in mind, was to look at the game side itself, and see if there's any issue in the way that the birds try to predict the output, but it does seem like the input nodes are correct.
think() in Bird.js:
think(pipes) {
//Find closest pipe
let closest = null;
let closestD = Infinity;
for (let i = 0; i < pipes.length; i++) {
let d = pipes[i].x - this.x;
if (d < closestD && d > 0) {
closest = pipes[i];
closestD = d;
}
}
let inputs = [];
inputs[0] = this.y / height; // bird's y
inputs[1] = closest.top / height; // top pipe's y
inputs[2] = closest.bottom / height; // bottom pipe's y
inputs[3] = closest.x / width; // pipes' x
let output = this.brain.predict(inputs); // predict if bird should jump
if (output[0] > 0.5) {
this.up()
}
}
What am I missing?
I have this function ( feel free to use it if you guys need it) that generates monsters for me in random positions outside the play area. After the monster is generated, the monster then follows a way to the character.
But, the problem is that, the monsters are generated all at the same time. What i am trying to do is put some time delay between spawns. Like, 1st monster is generated at the start of the game; second monster i want to be generated after 1 second. Any ideeas how can i achieve this?
I've tried making a time variable that iterates and then spawn an enemy if counter > time. But that dosen't seem to work proprely
function init(){
}
function update(dt){
}
function signal(name, value){
let x1 = 6;
let x2 = -6;
let y1 = 20;
let y2 = 1;
let cadran = Math.floor(Math.random() * (+4 - +1)) + +1;
if(value){
for(i=0;i<5;i++){
if(cadran == 1){
monsterGenerator(this,x2,x1,y1 ,1);
}
if(cadran == 2){
monsterGenerator(this,x2,x1,y2,2);
}
if(cadran == 3){
monsterGenerator(this,y2,y1,x1,3);
}
if(cadran == 4){
monsterGenerator(this,y2,y1,x2,4);
}
cadran++;
if(cadran==5){
cadran = 1;
}
}
}
}
function monsterGenerator(ob,min,max,stat,rand) {
let assetName = ob.attribute('Asset Name');
let ent = ob.scene().create(assetName);
if(ent == null) error('Asset "'+assetName+'" does not exist');
let pos = ob.entity().worldPosition();
let rot = ob.entity().rotation();
let scl = ob.entity().scale();
let random = Math.floor(Math.random() * (+max - +min)) + +min;
if(rand==1){
ent.setPosition(pos.x = random, pos.y =stat , pos.z);
}
if(rand==2){
ent.setPosition(pos.x = random, pos.y =stat , pos.z);
}
if(rand==3){
ent.setPosition(pos.x = stat, pos.y =random , pos.z);
}
if(rand==4){
ent.setPosition(pos.x = stat, pos.y =random , pos.z);
}
ent.setRotation(rot.x, rot.y, rot.z);
ent.setScale(scl.x, scl.y, scl.z);
}
I am coding a lil js game for a university project.
I have a 2d map and I can move my player with arrows. Enemies are spawned every 5 seconds and they are guided by the function:
enemy.updatePosition = function() {
if(enemy.isAttacking === false) {
var diffX = Math.floor(player.x - enemy.x);
var diffY = Math.floor(player.y - enemy.y);
//security distance by player --> superEnemy type 1 uses arrows
var distance = getDistanceBetweenEntities(player, enemy);
var gap = 20;
enemy.pressingRight = diffX > gap;
enemy.pressingLeft = diffX < -gap;
enemy.pressingDown = diffY > gap;
enemy.pressingUp = diffY < -gap;
enemy.isStopped = false;
if(enemy.speedX < 0)
enemy.speedX = - enemy.speedX;
if(enemy.speedY < 0)
enemy.speedY = - enemy.speedY;
//bumpers check if hitting a wall or end of map
var rightBumper = {x:enemy.x + 15, y:enemy.y};
var leftBumper = {x:enemy.x - 15, y:enemy.y};
var upBumper = {x:enemy.x, y:enemy.y - 25};
var downBumper = {x:enemy.x, y:enemy.y + 20};
if(currentMap.isPositionWall(rightBumper)) {
enemy.x -= 1;
} else {
if(enemy.pressingRight)
enemy.x += enemy.speedX;
}
if(currentMap.isPositionWall(leftBumper)) {
enemy.x += 1;
} else {
if(enemy.pressingLeft)
enemy.x -= enemy.speedX;
}
if(currentMap.isPositionWall(downBumper)) {
enemy.y -= 1;
} else {
if(enemy.pressingDown)
enemy.y += enemy.speedY;
}
if(currentMap.isPositionWall(upBumper)) {
enemy.y += 1;
} else {
if(enemy.pressingUp)
enemy.y -= enemy.speedY;
}
//set position again if the center of the draw
//of enemy goes out of map's limits
if(enemy.x < enemy.width/2)
enemy.x = enemy.width/2;
if(enemy.x > currentMap.width - enemy.width/2)
enemy.x = currentMap.width - enemy.width/2;
if(enemy.y < enemy.height/2)
enemy.y = enemy.height/2;
if(enemy.y > currentMap.height - enemy.height/2)
enemy.y = currentMap.height - enemy.height/2;
}
}
}
So my enemies follow the player with the values of diffX and diffY. Each enemy has it own speedX and speedY, something like:
var random = 1 + Math.random()*7; //from 1 to 8
enemy.speedX = random;
enemy.speedY = random;
The result is that enemies start to overlap, expecially when they are performing an attack(x and y don't changes during attack). Is there a simple way to avoid that without checking a lot of collision? Thanks everyone
There are more options for you, but here is one simple collision detection.
First you will need to make every enemy unique like giving everyone of them a unique name. This doesn't need to be complicated just like enemy1, enemy2, .... enemy223. You can do it at the point where you spawn the enemy, like this:
enemy['name'] = 'enemy' + i++;
so you can access it like this:
enemy.name;
Important: you should write some kind position that updates everytime the 'enemy' changes position or every tick.
enemy['position'] = enemy.x+','+enemy.y;
make an array into that you can write the positions of every enemy. I know this is not the best option but it's simple and will work for now.
var pstns = [];
After that write every enemy into the array (just do it at spawn). I would like to mention that the following is not good practice.
var pstnsObj = {};
pstnsObj[enemy.name] = enemy.position;
pstns.push(pstnsObj);
Next you need to update the position in the array every tick with every enemy. This is only one example you can do it multiple ways or even automate this process.
function updatePstns(id, position){
pstns[id][Object.keys(pstns[id])[0]] = position;
//just in case:
return pstns;
}
//updating first enemy:
updatePstns(0, enemy.position);
now for the collision:
function checkCollision(){
var count = 0;
pstns.forEach(function(e){
for(i=0; i<pstns.length; i++){
if(pstns[e][Object.keys(pstns[e])[0]] == pstns[i][Object.keys(pstns[i])[0]]){
count++;
}
}
if(count > 1){
console.log('enemy ' + pstns[e] + 'collides with ' + count + 'enemies');
}
});
}
So I've been working on re-producing the slider found here https://www.skylight.io/ ( Scroll down to find the price slider ).
So far Ive managed to create something similiar, but some numbers are hard coded, making it difficult to change and not very re-usable.
I've been researching around and I think I need to use Math.log() and Math.exp() together to achieve something like in the link above but I'm not sure.
Heres a jsfiddle of what I have so far https://jsfiddle.net/7wrvpb34/.
I feel that its the maths part of this problem that is halting me I think, so any help would be greatly appreciated.
Javascript code below:
var slider = document.getElementById("slider")
var sliderFill = document.getElementById("slider-fill")
var knob = document.getElementById("knob")
var mouseDown;
var mousePos = {x:0};
var knobPosition;
var minPrice = 20;
var price = 0;
var minRequests = 50;
var requests = 50 + ",000";
var incrementSpeed = 2;
var incrementModifier = 20;
var incrementValue = 1;
var minMillionCount = 1;
var millionCount = 1;
var previousRequestAmount = 0;
document.getElementById("price").innerHTML = price;
document.getElementById("requests").innerHTML = requests;
highlightTable(1);
document.addEventListener('mousemove', function(e) {
if(mouseDown) {
updateSlider(e);
}
})
function updateSlider(event) {
mousePos.x = event.clientX - slider.getBoundingClientRect().left;
mousePos.x -= knob.offsetWidth / 2;
console.log(mousePos.x);
if(mousePos.x < 0) {
knob.style.left = "0px";
sliderFill.style.width = "0px";
price = 0;
requests = 50 + ",000";
document.getElementById("price").innerHTML = price;
document.getElementById("requests").innerHTML = requests;
return
}
if(mousePos.x > slider.offsetWidth - 20) {
return
}
sliderFill.style.width = mousePos.x + 10 + "px";
knob.style.left = mousePos.x + "px";
//Increase requests by using X position of mouse
incrementSpeed = mousePos.x / incrementModifier;
requests = minRequests + (mousePos.x * incrementSpeed);
//Round to nearest 1
requests = Math.round(requests / incrementValue) * incrementValue;
if (requests >= 1000){
var m = requests/ 1000;
m = Math.round(m / 1) * 1;
//Problem, lower the modifier depending on requests
incrementModifier = 20 * 0.95;
document.getElementById("requests").innerHTML = m + " million";
//Adjust Prices
if(( requests >= 1000) && (requests < 10000)) {
var numOfMillions = requests / 100;
//Round to closest 10.
//10 * number of millions
var rounded = Math.round(numOfMillions / 10) * 10;
price = minPrice + rounded;
highlightTable(3);
}
//Adjust Prices
if(requests >= 10000) {
var numOfMillions = requests / 1000;
var rounded = Math.round(numOfMillions / 1) * 1;
var basePrice = minPrice * 6;
price = basePrice + rounded;
highlightTable(4);
}
} else {
incrementModifier = 20;
document.getElementById("requests").innerHTML = requests + ",000"
if(requests < 100) {
highlightTable(1);
price = 0;
} else {
highlightTable(2);
price = 20;
}
}
previousRequestAmount = requests;
document.getElementById("price").innerHTML = price;
}
knob.addEventListener('mousedown', function() {
mouseDown = true;
});
document.addEventListener('mouseup', function() {
mouseDown = false;
});
function highlightTable(rowNum) {
var table = document.getElementById("payment-table")
for(var i = 0; i < table.rows.length; ++i) {
var row = table.rows[i]
if(i == rowNum) {
row.style.background = "grey"
} else {
row.style.background = "white";
}
}
}
Thank you for your time.
If you want it to be reusable you need to create a mathematical function that assigns a result to the number of requests. I will give you a very easy example.
If you want a different result for 1,10,100,100,10000 etc
var d = Math.log10(requests);
if(d<1){
doSomething();
}else if(d<2){
doSomethingElse();
} //etc
This way if you want to change the specific values that create certain results, all you need to do is change the function.
This only works if your tiers of requests follow a math function, if they don't you need to hard code it.
However if say they don't follow a math function, but you know how you would like them to change based on a value then you can do this.
var changingValue = 4;
if(requests < 400*changingValue){
doSomthing();
}else if(requests <= 400*changingValue*changingValue){
doSomethingElse();
}else{// the requests is greater than any of the above
doTheOtherThing();
}
Edit:
For the second one you need to make sure that each condition if always larger than the other from top to bottom.
The description "increasingly increasing" matches an arbitrary number of functions. I assume you also want it to be continuous, since you already have a non-continuous solution.
TL;DR
Use an exponential function.
Generic approach
Assuming imin and imax are the minimal and maximal values of the slider (i for input) and omin and omax are the minimal and maximal values to be displayed, the simplest thing I can think of would be a multiplication by something based on the input value:
f(x)
{
return omin + (omax - omin) * g((x - imin) / (imax - imin));
}
This will pass 0 to g if x == imin and 1 if x == imax.
The return value r of g(y) should be
r == 0 for y == 0
r == 1 for y == 1
0 < r < y for 0 < y < 1
The simplest function that I can think of that fulfills this is an exponential function with exponent > 1.
An exponent of 1 would be a linear function.
An exponent of 2 would be make the middle of the slider display one fourth of the maximum price instead of half of it.
But you really need to find that exponent yourself, based on your needs.
I have a simple javascript animation, where two cowboys (iamges) 'race' each other based on a random interval number.
What I can't find out how to do is for the script to take a decision on who is the winner, meaning if a cowboy reaches a pre-defined distance first, the script will know and will show an alert on who won.
Here is a screen shot to show an example:
This is the code I have so far: http://pastebin.com/Cmt4N8c9
Can give me some directions?
Thanks,
Brian
In your move() function you should do something like
if (x >= dest_x) {
alert('player 1 won');
} else if (x2 >= dest_x2) {
alert('player 2 won');
} else {
... continue the loop ...
}
You'd most likely put that behind
document.getElementById("cowboy").style.top = y+'px';
document.getElementById("cowboy").style.left = x+'px';
document.getElementById("cowboytwo").style.top = y2+'px';
document.getElementById("cowboytwo").style.left = x2+'px';
You might want to check your code on duplicate variables too, by the way.
AFAIK dest_x and dest_x2 are both the same for example.
Simple move
/* Y is not relevant since you only move it on X axis */
var position1 = 100;
var position2 = 100;
var dest = 800; //Or any given value
function move() {
var step1 = Math.floor(1 + (10 * Math.random() ) );
var step2 = Math.floor(1 + (10 * Math.random() ) );
position1 += step1;
position2 += step2;
document.getElementById("cowboy").style.left = position1+'px';
document.getElementById("cowboytwo").style.left = position2+'px';
if(position1 < dest && position2 < dest) {
window.setTimeout('move()',100);
} else {
//We have the winner
if(position1 > dest) alert("Winner is Cowboy1");
if(position2 > dest) alert("Winner is Cowboy2");
//Its also possible that both of them pass target value at the same step
}
}