HTMLButtonElement.onclick ReferenceError in HTML/JavaScript, and nested functions - javascript

I am currently trying to code this extremely basic text-based golf game for practice. There's no trigonometry to it, there's just a randomness to how hard you hit the ball, and then how many shots it takes to reach the hole. At the end, it will mark your score as "Birdie" or "Par" or whatever. I'm not at that endstage yet though.
So my logic for the program is, start() is called through an onclick HTML attribute, and then we run through things from there. Everything is embodied in start(). The game's intro text is displayed with some DOM innerHTML.
The idea is that once start() has been activated, you can click swing() and it will swing and update the value and therefore the current position.
But I don't get what problem it's having with this nested function and the onclick. The error it says it has is at index.html line 1. But also, line 1 of my index.HTML is . I don't even know what this other index file is.
image 1; images not necessary but might help explain what I'm talking about
In VS Code, the nested function says it never even gets called. Is it just reading the lines and exiting too fast? Should I use setInterval or something to keep it reading?
function start() {
let introText = "It is a beautiful sunny day on Golf Island. The cobalt waters are great. There is no wind. You stand at the tee and get ready to strike. There's only one hole to go.<br>"
document.getElementById("textarea").innerHTML += introText;
holeDistance = 350;
function swing() {
swingValue = Math.floor(Math.random() * 100);
currentValue = String(holeDistance - swingValue);
return document.getElementById("textarea").innerHTML += "Hole position: " + currentValue;
}
}
<button id="start" onclick="start()">Start game</button>
<div id="textarea">
<button onclick='swing()'>Swing</button>
</div>
Here's the Codepen.

There are a few issues:
your function is within another function
you assign values to variables that you have never declared before. A variable needs to be declared with var/let and can only be assigned afterward or at the same instance:
Issues to fix the game:
You declare a variable within the function of hole distance with 350. Every time you click the button you reset the variable to 350 and roll the dice on that 350. You need to move the variable outside of the function and subtract the randomize shooting distance from the hole distance:
let holeDistance = 350;
function start() {
let introText = "It is a beautiful sunny day on Golf Island. The cobalt waters are great. There is no wind. You stand at the tee and get ready to strike. There's only one hole to go.<br>"
document.getElementById("textarea").innerHTML += introText;
}
function swing() {
let swingValue = Math.floor(Math.random() * 100);
holeDistance = holeDistance - swingValue;
return document.getElementById("textarea").innerHTML += `Hole position: ${holeDistance}`;
}
<button id="start" onclick="start()">Start game</button>
<div id="textarea">
<button onclick='swing()'>Swing</button>
</div>

Related

.onclick button not executing function

I have a problem with my .onclick function not executing the function specified in my script file. Here's my code:
JAVASCRIPT:
var quotes = [
["“If you are distressed by anything external, the pain is not due to the thing itself, but to your estimate of it; and this you have the power to revoke at any moment.”", "Marcus Aurelius"],["“The average man is a conformist, accepting miseries and disasters with the stoicism of a cow standing in the rain.”", "Colin Wilson"],
["“Never let the future disturb you. You will meet it, if you have to, with the same weapons of reason which today arm you against the present.”", "Marcus Aurelius"],
["“Warriors should suffer their pain silently.”","Erin Hunter"],
["“Complaining does not work as a strategy. We all have finite time and energy. Any time we spend whining is unlikely to help us achieve our goals. And it won't make us happier.”", "Randy Pausch"],
["“It is the power of the mind to be unconquerable.”", "Seneca"],
["“How do you defeat terrorism? Don’t be terrorized.”", "Salman Rushdie"],
["“It is not the man who has too little that is poor, but the one who hankers after more.”", "Seneca"],
["“What really frightens and dismays us is not external events themselves, but the way in which we think about them. It is not things that disturb us, but our interpretation of their significance.”", "Epictetus"],
["“For death remembered should be like a mirror, who tells us life’s but breath, to trust it error.”", "Shakespeare"],
["“No one saves us but ourselves. No one can and no one may. We ourselves must walk the path.”", "Buddha"],
["“You only lose what you cling to.”", "Buddha"],
["“Man suffers only because he takes seriously what the gods made for fun.”", "Alan W. Watts"],
["“If there is any religion that could respond to the needs of modern science, it would be Buddhism.”", "Albert Einstein"],
["“We are not going in circles, we are going upwards. The path is a spiral; we have already climbed many steps.”", "Hermann Hesse"],
["“Treat every moment as your last. It is not preparation for something else.”", "Shunryu Suzuki"],
["“Better than a thousand hollow words is one word that brings peace.”", "Buddha"],
["“Life is painful. It has thorns, like the stem of a rose. Culture and art are the roses that bloom on the stem. The flower is yourself, your humanity. Art is the liberation of the humanity inside yourself.”", "Daisaku Ikeda"],
["“Learning to let go should be learned before learning to get. Life should be touched, not strangled. You’ve got to relax, let it happen at times, and at others move forward with it.”", "Ray Bradbury"]
];
var randomInt = Math.floor((Math.random() * quotes.length) + 1);
// Generate random number
// Get number's position from array
var aQuote = function() {
return quotes[randomInt][0] + "";
};
var aQuoteAuthor = function() {
return quotes[randomInt][1] + "";
};
// Change textblock into quote + author
// Display quote on page
// Display author on page
function changeButton() {
document.getElementById('quote').innerHTML = aQuote();
document.getElementById('quoteAuthor').innerHTML = aQuoteAuthor();
};
// Register button press
document.getElementById('aButton').onclick = changeButton();
And this is my html:
<div class="container">
<div class="row">
<div class="u-full-width">
<div class="quotediv">
<h5 id="quote" class="text-primary-color">“Imagine smiling after a slap in the face. Then think of doing it twenty-four hours a day.”</h5>
<p id="quoteAuthor" class="light-primary-color">Markus Zusak<p>
<button id="aButton" type="button button-primary" class="primary-text-color"> NEW QUOTE</button>
</div>
</div>
</div>
</div>
<script src ="scripts/script.js"></script>
The first weird thing is that the function changeButton() gets invoked automatically on page load without a function call. So on every page load there's a new quote generated and displayed. The second weird thing is that the button itself does not generate and change the quote via the function changeButton().
Could anyone point me in the right direction?
P.S. I'm a coding newbie. This is my first question on SO. I tried to follow the guidelines for specificity but if you have any tips or comments on my question formulation, please let me know! :)
The problem is that you are executing the function and assigning the return value to onclick.
document.getElementById('aButton').onclick = changeButton();
You should be assigning the function itself to onclick like so (Note it doesnt have "()" at the end)
document.getElementById('aButton').onclick = changeButton;
Even better would be to use addEventListener like so
document.getElementById('aButton').addEventListener('click', changeButton);
Try to do it like that:
document.getElementById('aButton').onclick = changeButton
what you were doing is binding event and simultaneously executing it.
document.getElementById('aButton').onclick = changeButton
function changeButton() {
console.log("yes");
}
<button id="aButton">
Button
</button>
You can call the onClick listener using
document.getElementById('aButton').addEventListener("click", changeButton);
Using:
document.getElementById('aButton').onclick = changeButton();
You just assign the return value of the function rather than assign the function to the click event! This line:
document.getElementById('aButton').onclick = changeButton;
Actually assigns the function to the click event (note, no brackets so it isn't executed, it's assigned as a variable).
function changeButton() {
alert("Hello")
}
document.getElementById('aButton').addEventListener("click", changeButton);
<button id="aButton">Click Me</button>
move your script to head section it will work fine.
<!DOCTYPE html>
<html>
<head>
<script>
var quotes = [
["“If you are distressed by anything external, the pain is not due to the thing itself, but to your estimate of it; and this you have the power to revoke at any moment.”", "Marcus Aurelius"],["“The average man is a conformist, accepting miseries and disasters with the stoicism of a cow standing in the rain.”", "Colin Wilson"],
["“Never let the future disturb you. You will meet it, if you have to, with the same weapons of reason which today arm you against the present.”", "Marcus Aurelius"],
["“Warriors should suffer their pain silently.”","Erin Hunter"],
["“Complaining does not work as a strategy. We all have finite time and energy. Any time we spend whining is unlikely to help us achieve our goals. And it won't make us happier.”", "Randy Pausch"],
["“It is the power of the mind to be unconquerable.”", "Seneca"],
["“How do you defeat terrorism? Don’t be terrorized.”", "Salman Rushdie"],
["“It is not the man who has too little that is poor, but the one who hankers after more.”", "Seneca"],
["“What really frightens and dismays us is not external events themselves, but the way in which we think about them. It is not things that disturb us, but our interpretation of their significance.”", "Epictetus"],
["“For death remembered should be like a mirror, who tells us life’s but breath, to trust it error.”", "Shakespeare"],
["“No one saves us but ourselves. No one can and no one may. We ourselves must walk the path.”", "Buddha"],
["“You only lose what you cling to.”", "Buddha"],
["“Man suffers only because he takes seriously what the gods made for fun.”", "Alan W. Watts"],
["“If there is any religion that could respond to the needs of modern science, it would be Buddhism.”", "Albert Einstein"],
["“We are not going in circles, we are going upwards. The path is a spiral; we have already climbed many steps.”", "Hermann Hesse"],
["“Treat every moment as your last. It is not preparation for something else.”", "Shunryu Suzuki"],
["“Better than a thousand hollow words is one word that brings peace.”", "Buddha"],
["“Life is painful. It has thorns, like the stem of a rose. Culture and art are the roses that bloom on the stem. The flower is yourself, your humanity. Art is the liberation of the humanity inside yourself.”", "Daisaku Ikeda"],
["“Learning to let go should be learned before learning to get. Life should be touched, not strangled. You’ve got to relax, let it happen at times, and at others move forward with it.”", "Ray Bradbury"]
];
var randomInt = Math.floor((Math.random() * quotes.length) + 1);
// Generate random number
// Get number's position from array
var aQuote = function() {
return quotes[randomInt][0] + "";
};
var aQuoteAuthor = function() {
return quotes[randomInt][1] + "";
};
// Change textblock into quote + author
// Display quote on page
// Display author on page
function changeButton() {
alert();
document.getElementById('quote').innerHTML = aQuote();
document.getElementById('quoteAuthor').innerHTML = aQuoteAuthor();
};
</script>
</head>
<body>
<div class="container">
<div class="row">
<div class="u-full-width">
<div class="quotediv">
<h5 id="quote" class="text-primary-color">“Imagine smiling after a slap in the face. Then think of doing it twenty-four hours a day.”</h5>
<p id="quoteAuthor" class="light-primary-color">Markus Zusak<p>
<button id="aButton" type="button button-primary" class="primary-text-color"> NEW QUOTE</button>
</div>
</div>
</div>
</div>
</body>
</html>

Raycasting to make an enemy jump

As stated above, I am trying to build a simple game, but I can't seem to get the enemies moving correctly. The game is a Minecraft style block-based game. The code I am using so far makes the enemy start following me when I get within a certain distance and stop following once I get a certain distance away.
The problem I am having with this script is that the enemy sort of floats off into the distance when I escape him. More importantly, I cannot for the life of me get the enemy to jump. I know that I should be using two Raycasts for this: one to detect a block in front which will make the enemy jump and another to detect below the enemy and let him fall to the level below if there is no collier at his feet? I have no idea how to go about implementing this and some help would be greatly appreciated.
The code I have thus far can be seen below:
var target : Transform; //the enemy's target
var moveSpeed = 3; //move speed
var rotationSpeed = 3; //speed of turning
var range : float=10f;
var range2 : float=10f;
var stop : float=0;
var myTransform : Transform; //current transform data of this enemy
function Awake() {
myTransform = transform; //cache transform data for easy access/preformance
}
function Start() {
target = GameObject.FindWithTag("1Player").transform; //target the player
}
function Update () {
//rotate to look at the player
var distance = Vector3.Distance(myTransform.position, target.position);
if (distance<=range2 && distance>=range) {
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
} else if (distance <= range && distance > stop) {
//move towards the player
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
} else if (distance <= stop) {
myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
Quaternion.LookRotation(target.position - myTransform.position),
rotationSpeed*Time.deltaTime);
}
//lock rotation on x and y axis to zero
myTransform.eulerAngles = new Vector3(0f, myTransform.eulerAngles.y, 0);
}
The design can change really a lot. It depends how clever AI do you want ? And how realistic it should be. Firstly you should check distance and as I saw you did that. The question is what if there is a wall or something ? Maybe they are so close to each other but there is a wall between them. This is why you need raycast. So you send a raycast from enemy to player. If there is no obstacle between them AI can decide that "aye I should come after you". But here is another problem for being realistic. What if its not looking to you ? If the AI can spot the player when it looks somewhere else, it is not that cool right ? So you also check if the player is in front of the AI. Maybe we can do it like this :
var heading = target.position - transform.position;
var dot: float = Vector3.Dot(heading, transform.forward);
so if dot is -1 we can say it is directly behind and +1 means in front of it. Well, now another problem. If player should be in front of the AI to be spotted then AI can not stand right ? It should move and turn around randomly. We can work on that later if you gonan need it.
Now another problem what if you hide after an object ? What it should do ? I mean when you are running if something came between you and AI, since raycast will fail it will stop following you right ? What we can do for it ? My sugesstion store the last position of the player which AI saw. And at least go to there to check if AI can find the player there. If it cant, it may keep moving randomly. By doing this it will looks more realistic I believe.
Edit: Lol I realised that i just improved you design and forgot to answer what exactly you asked.
Firstly AI shoudl know if it is grounded or not. What we need to know first distance to ground when we send raycast we gonan need it.
var distanceToGround = GetComponent<Collider>().bounds.extents.y;
function boolean isGrounded(){
return Physics.Raycast(transform.position, -Vector3.up, distanceToGround + 0, 1);
}
AI should send a raycast not from its head more like below the knees. Not send it too far away just a little distance will be enough. It is just to understand it there is an obstacle. And also send another raycast but this time now below the knees. From the jump height. And if it dont hit anything we can decide that there is an obstacle (first raycast says that) but AI can jump over it (second raycast says that). After deciding it, if AI also grounded that means it can jump and pass trough the obstacle.
Lets say this is the part 1. If you want me to keep telling, I can write another part for you. Have a nice day !

requestAnimationFrame calling at more than 60FPS

I'm making a simple game and I'm having a problem where after minimizing the window for a few seconds, upon return the game runs at twice the framerate, and even more after that, adding 60 each time. My game loop looks like this:
function disp(){
update();
draw();
requestAnimationFrame(disp);
}
requestAnimationFrame(disp);
With both update and draw not including requestAnimationFrame. I have tried this on both firefox and chrome with the same results. Any ideas why this is happening? I've used this same method tons of times and this is the first time this has ever happened.
EDIT: You can find a fiddle of it at http://jsfiddle.net/5ttGs/
It's really simple so far as this kinda paused my progress. Click it a couple times and enjoy 10000+FPS gameplay
Fixed the problem with the help of cocco. Basically the onclick event called the disp function every time the canvas was clicked. Because the disp function had a requestAnimationFrame frame in it, it called it twice as much every second, resulting in the influx of frames. In order to fix I simply got rid of the disp in
canvas.addEventListener
function mouse_up() {
var matches = 0;
var overlap = 69;
mouse.up = false;
console.log("clicked", mouse.x,mouse.y);
disp();
}
You can find the result here: http://jsfiddle.net/5ttGs/

variable doesn't update when function restarts (javascript)

I'm going to try my best to ask this question without a huge wall of code. Basically I have written a very simple math quiz game. In this game you select a difficulty, the number of questions you want, and the game starts. It asks that number of questions and then you get a score and then the game is over. However, you can restart the game. When you restart, it simply returns you to the home screen, then you can select your options again. The only problem is, we need to keep track of the number of questions remaining in the quiz, the first time around, it works well. We pass numQuestions to the game function. The second time, however, even if I pass numQuestions=10, the value remains 0 from the first time I played the game. Here is the game function:
function startGame(difficulty,numQuestions,score){
// begins game, excluded that come its just some acsii art
// asks question
var q = new question(difficulty);
$("#gameInside").html(q.string);
$("#gameInside").data('answer',q.answer);
// gives answer options
for (var ii=0;ii<=3;ii++){
$("#answers").append("<button class='answerButton'>"+q.answerArray[ii]+"</button>")
}
// starts timer
var b = document.getElementById("timer");
timer = new stopWatch(b, {delay: 100});
timer.start();
},5500)
// when answer is clicked, go here
$("#gameScreen").on("click",".answerButton",function() {
// this seems to be the problem: on the second time I play the game, numQuestions remains the value from the first game and continues to go down (-1,-2) and since my selector is (>0), the else statement fires.
numQuestions--;
var time = parseFloat($("#timer span").html());
var correct = parseFloat($("#gameInside").data('answer'));
var userAnswer = parseFloat($(this).html());
if (correct==userAnswer)
tempScore = Math.round(calculateScore(time)*100)/100;
else
tempScore = 0;
score += tempScore;
$("#score").html(Math.round(score*100)/100);
if (numQuestions > 0) {
var q = new question(difficulty);
$("#gameInside").html(q.string);
$("#gameInside").data('answer',q.answer);
$("#answers").empty();
for (var ii=0;ii<=3;ii++){
$("#answers").append("<button class='answerButton'>"+q.answerArray[ii]+"</button>")
}
timer.reset();
} else {
$("#answers").empty();
$("#gameInside").html('Game Over! Thanks for Playing!');
timer.stop();
}
});
}
any ideas? Thanks
edit:
$(".numberQButton").click(function(){
numQuestions = parseFloat($(this).html());
$("#numQuestionsScreen").hide();
$("#gameScreen").show();
$("#score").html(0);
startGame(difficulty,numQuestions,score);
});
You're problem (I think) lies in closures. When you declare a function in javascript, any accessing of a variable from outside it's own scope generates what is called a closure. In this case, numQuestions is accessed from inside your event function, creating a closure. The effect of this is that any accessing of the variable numQuestions inside your event functions references the variable as it was from the moment your javascript interpreter came across the event function itself- ie, the first time you play your game.
Have a look at these to get an idea of where it's going wrong.
It sounds like you need to instantiate a new Game object when the game is restarted.
Where do you define the on click listener? If it triggers two times, it seems like you are defining the on click listener in such way, that after you completed one game and start all over, a new listener will be registered so you got 2 in the end.

Collision/overlapping in a for loop in javascript

I'm writing a space invaders game on Khan Academy for a school project and I can't figure out how to put in a collision between bullets and the aliens and then get rid of the alien that the bullet collided with. It's very basic JS and as much as I've tried, I don't really understand how to put the other answers on this topic into my code. If anyone could help me on this I would be so grateful.
Here's a link to the game: http://www.khanacademy.org/cs/space-invaders/1087897437
I have another game with the same problem here: http://www.khanacademy.org/cs/brick/1176464164
In both cases, the game needs to run in a while loop. Basically, each iteration moves the game forward one 'frame'. One of the things to be calculated from one frame to the next, is whether or not a bullet has touched an alien.
Both a bullet and an alien have occupy a physical space. So you could effectively loop through all of the bullets and have a function that checks if a bullet has hit an alien.
function has_hit_alien(bullet) {
for(var i = aliens.size; i > 0; i--){
if(same_space(bullet, aliens[i]) {
return aliens[i]
}
}
}
Now you need to implement the same_space function to check if any of the outer pixels of argument 1 are inside of argument 2.

Categories

Resources