I am trying to make a very simple helicopter game in javascript and I'm currently using css positions to move the objects. but I wanted to know if there was a better/other method for moving objects (divs) when a user is pressing a button
here's a code i've got so far..
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Game 2 helicopter</title>
<script type="text/javascript">
function num(x){
return parseInt(x.replace(/([^0-9]+)/g,''));
}
function getPos(x, y){
var inum=Math.floor(Math.random()*(y+1-x)) + x;
inum=inum;
return inum;
}
function setTop(x,y){ x.style.top = y+'px'; }
function setBot(x,y){ x.style.bottom = y+'px'; }
function setLeft(x,y){ x.style.left = y+'px'; }
function setRight(x,y){ x.style.right = y+'px'; }
function getTop(x){ return num(x.style.top); }
function getBot(x){ return num(x.style.bottom); }
function getLeft(x){ return num(x.style.left); }
function getRight(x){ return num(x.style.right); }
function moveLeft(x,y){
var heli = document.getElementById('heli');
var obj = document.getElementById('obj');
var poss = [20,120,350,400];
var r_pos = getPos(1,4);
var rand_pos = poss[r_pos];
xleft = getLeft(x)-y;
if(xleft>0){
xleft=xleft;
}
else{
xleft=800;
setTop(x,rand_pos);
}
setLeft(x,xleft);
setTimeout(function(){moveLeft(x,y)},10);
checkGame(heli,obj);
}
var heli;
var obj;
function checkGame(x,y){
var obj_right = getLeft(x) + 100;
var yt = getTop(y);
var yb = (getTop(y)+100);
if(getTop(x) >= yt && getTop(x) <= yb && obj_right==getLeft(y)){
endGame();
}
}
function func(){
var x = document.getElementById('heli');
var y = document.getElementById('obj');
alert(getTop(x)+' '+getTop(y)+' '+(getTop(y)+200));
}
function startGame(e){
document.getElementById('park').style.display='block';
document.getElementById('newgame').style.display='none';
heli = document.getElementById('heli');
obj = document.getElementById('obj');
hp = heli.style.top;
op = obj.style.top;
setTop(heli,20);
setLeft(heli,20);
setLeft(obj,800);
setTop(obj,20);
moveLeft(obj,5);
}
function newGameLoad(){
document.getElementById('park').style.display='none';
document.getElementById('newgame').style.display='block';
}
function gamePos(e){
heli = document.getElementById('heli');
obj = document.getElementById('obj');
var keynum;
var keychar;
var numcheck;
if(window.event){ // IE
keynum = e.keyCode;
}
else if(e.which){ // Netscape/Firefox/Opera
keynum = e.which;
}
keychar = String.fromCharCode(keynum); // up=38 down=40 left=37 right=39
/*if(keynum==37){ //left
tl=tl-20;
db.style.left = tl + 'px';
}
if(keynum==39){ //right
//stopPos();
tl=tl+20;
db.style.left = tl + 'px';
}*/
curb = getTop(heli);
if(keynum==38){ //top
setTop(heli,curb-10);
//alert(curb+10);
}
if(keynum==40){ //bottom
setTop(heli,curb+10);
//alert(curb-10);
}
}
function endGame(){
clearTimeout();
newGameLoad();
}
</script>
<style type="text/css">
.play{position:absolute;color:#fff;} #heli{background:url(http://classroomclipart.com/images/gallery/Clipart/Transportation/Helicopter/TN_00-helicopter2.jpg);width:150px;height:59px;}
#obj{background:red;width:20px;height:200px;}
.park{height:550px;border:5px solid brown;border-left:none;border-right:none;}
#newgame{display:none;}
</style>
</head>
<body onload="startGame();" onkeydown="gamePos(event);">
<div class="park" id="park">
<div id="heli" class="play"></div>
<div id="obj" class="play"></div>
</div>
<input type="button" id="newgame" style="position:absolute;top:25%;left:25%;" onclick="startGame();" value="New Game" />
</body>
</html>
Some general comments:
parseInt() already ignores trailing non-numerics, so there's no need for your num() function. If there were, you could write that regex more simply as /\D+/g.
If speed is critical, a marginally faster way to floor a number is x<<0.
All of getPos should just be: return Math.floor(...)+x;. I have no idea why you declare and set a variable, set it to itself, and then return it.
Instead of re-getting the heli and obj items each call to moveLeft(), you should set them once (after the document as loaded) and let moveLeft() be a closure that references them. Same with poss.
You forgot to var your xleft variable, which makes it a global.
You have if (xleft>0){ xleft=xleft; }. This doesn't do anything.
You can declare multiple variables on the same line, e.g. var heli, obj;
Instead of using alert for debugging, use console.log (or better yet, actual breakpoints and stepping through your code). You will find your life far, far easier. Look up Developer Tools for Safari/Chrome or Firebug for Firefox.
There are more global variables such as hp and op.
You should look into a library like jQuery which will make your code easier to develop. For example, you don't have to do the browser-specific tests for events, as it normalizes them.
Use a switch() statement to process your keycodes instead of multiple if statements.
Remove the onload and onkeydown handlers from your body, and instead register them programmatically from your script.
Remove the style attribute from your HTML, and put it in your stylesheet.
Yes do not use a Timer to poll if a event has happened. Use javascript's addEventListener or jQuery's event functions.I would use recommend jQuery as it would probably make writing other parts of your code faster as well.
Related
I'm currently learning JS and i'm working on my own first library, however a problem i stumbled upon is:
When someone else uses my library he/she will get a name conflict while using 'alerts' in there code.
What is the best methode or how can i best solve this issue?
Thanks in advance!!
body {
font-family: sans-serif;
background: white;
font-size: 150px;
color: #333;
}
jQuery(document).ready(function( $ ){
function alerts (alert1, alert2, alert3, alert4) { //function calling all alerts
var hours = new Date().getHours(); //get time by hours
if (alert1 == undefined) { // if statement that fills the alert if undefined
alert1=0;
}
if (alert2 == undefined) {
alert2=12;
}
if (alert3 == undefined) {
alert3=17;
}
if (alert4 == undefined) {
alert4=24;
}
if (hours >= alert1 && hours < alert2) { //check if the time is between alert1 and alert 2, if than so execute
document.body.style.backgroundColor = "blue";
} else if (hours >= alert2 && hours < alert3) {
document.body.style.backgroundColor = "red";
} else if (hours >= alert3 && hours < alert4) {
document.body.style.backgroundColor = "green";
} else {
}
}
alerts(a, b, c, d);
}); //end Jquery
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>timeofday</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script src='http://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script> <!-- Includes Jquery -->
<script>
var a = 0;
var b = 17;
var c = 18;
var d = 24;
</script>
<script src="js/index.js">
</script> <!-- Includes the script for background change -->
</body>
</html>
You can encapsulate / namespace your JS in various ways. I personally like this scheme:
var myns = {
send: function () {
// your code
},
receive: function (sender) {
// your code
},
save: function () {
// your code
}
};
it has no limitations as far as i know and you can use nice short names :-) simply call for example this from outside:
myns.receive(this);
You should rename alerts(...) to something else. Try to name it so that when another programmer reads it, he/she directly knows by just the name of the function, what the function will probably do (of course this isn't always fully possible, but try to). The current name isn't really describing what it does, and aside from that also giving you conflicts. Something you could do is naming it adjustBackgroundColorAccordingToTime or setBackgroundForCurrentTime. Something else may work for you too of course :)
Do not name your library that normal, and make the name longer.
Then, you can explode a function such as noConflict to explode your lib just like jQuery.noConflict does.
For example:
The full name of your lib is MyAwesomeAlerts, and you would like to make a short name alerts.
The end of your code, you should detect whether your short name exists in current scope, execute statement window.alerts = MyAwesomeAlerts if not exists; otherwise, do nothing, and the end users can invoke var awesomeAlerts = MyAwesomeAlerts.noConflict(); to name it.
In function noConflict, just like this:
```
MyAwesomeAlerts.noConflict = function() {
return MyAwesomeAlerts
}
```
Ok so I've revised the markup/code to make it easier to understand. Using JavaScript I want to know how to create a text slider that changes a paragraph in html5 either "forwards" or "backwards" on click?
I only want one div to show at a time and the first div (div_1) needs to be visible at the beginning as a default setting. I also want to be able to add more text divs to it in the future. I'm new to JavaScript so I want to keep it as simple as possible.
I've had a go creating it in JavaScript which hasn't worked, I'm not sure if I'm going about this the right way.
<!DOCTYPE html>
<html lang="en">
<head>
<style type="text/css">
.showHide {
display: none;
}
</style>
<script type="text/javascript">
var sdivs = [document.getElementById("div_1"),
document.getElementById("div_2"),
document.getElementById("div_3"),
document.getElementById("div_4")];
function openDiv(x) {
//I need to keep div_1 open as a starting point
sdivs[0].style.display ="block";
var j;
for (var j = 0; j < sdivs.length; j++) {
if (j === x) {
continue;
}
else {
sdivs[j].style.display = "none";
}
}
}
</script>
<title>text</title>
</head>
<body>
forward
backwards
<div id="text_holder">
<div id="div_1" class="showHide">One</div>
<div id="div_2" class="showHide">Two</div>
<div id="div_3" class="showHide">Three</div>
<div id="div_4" class="showHide">Four</div>
</div>
</body>
</html>
When dealing with multiple elements like this, I've found CSS alone to be insufficient (though its brilliant for modifying simple hover states or whatever). This one method here is pretty simple and specific to this one set of markup (so modify as you see fit). More importantly - its to illustrate how to set up a simple javascript "class" to handle your logic.
http://jsfiddle.net/1z13qb58/
// use a module format to keep the DOM tidy
(function($){
// define vars
var _container;
var _blurbs;
var _blurbWidth;
var _index;
var _clicks;
// initialize app
function init(){
console.log('init');
// initialize vars
_container = $('#text_holder .inner');
_blurbs = $('.blurb');
_blurbWidth = $(_blurbs[0]).innerWidth();
_clicks = $('.clicks');
_index = 0;
// assign handlers and start
styles();
addEventHandlers();
}
// initialize styles
function styles(){
_container.width(_blurbs.length * _blurbWidth);
}
// catch user interaction
function addEventHandlers(){
_clicks.on({
'click': function(el, args){
captureClicks( $(this).attr('id') );
}
});
}
// iterate _index based on click term
function captureClicks(term){
switch(term){
case 'forwards':
_index++;
if(_index > _blurbs.length - 1){
_index = 0;
}
break;
case 'backwards':
_index--;
if(_index < 0){
_index = _blurbs.length - 1;
}
break;
}
updateView();
}
// update the _container elements left value
function updateView(){
//_container.animate({
//'left' : (_index * _blurbWidth) * -1
//}, 500);
_container.css('left', ((_index * _blurbWidth) * -1) + 'px');
}
init();
})(jQuery);
I'm using jQuery to handle event binding and animation, but, again - there are lots of options (including a combination of vanilla javascript and CSS3 transitions).
I'll note also that this is all html4 and css2 (save your doctype).
Hopefully that helps -
I've got a button with an image inside that I want to swap when clicked. I got that part working, but now I also want it to change back to the original image when clicked again.
The code I'm using:
<button onClick="action();">click me<img src="images/image1.png" width="16px" id="ImageButton1"></button>
And the Javascript:
function action() {
swapImage('images/image2.png');
};
var swapImage = function(src) {
document.getElementById("ImageButton1").src = src;
}
Thanks in advance!
While you could use a global variable, you don't need to. When you use setAttribute/getAttribute, you add something that appears as an attrib in the HTML. You also need to be aware that adding a global simply adds the variable to the window or the navigator or the document object (I don't remember which).
You can also add it to the object itself (i.e as a variable that isn't visible if the html is viewed, but is visible if you view the html element as an object in the debugger and look at it's properties.)
Here's two alternatives. 1 stores the alternative image in a way that will cause it to visible in the html, the other doesn't.
<!DOCTYPE html>
<html>
<head>
<script>
function byId(e){return document.getElementById(e);}
window.addEventListener('load', mInit, false);
function mInit()
{
var tgt = byId('ImageButton1');
tgt.secondSource = 'images/image2.png';
}
function byId(e){return document.getElementById(e);}
function action()
{
var tgt = byId('ImageButton1');
var tmp = tgt.src;
tgt.src = tgt.secondSource;
tgt.secondSource = tmp;
};
function action2()
{
var tgt = byId('imgBtn1');
var tmp = tgt.src;
tgt.src = tgt.getAttribute('src2');
tgt.setAttribute('src2', tmp);
}
</script>
<style>
</style>
</head>
<body>
<button onClick="action();">click me<img src="images/image1.png" width="16px" id="ImageButton1"></button>
<br>
<button onClick="action2();">click me<img id='imgBtn1' src="images/image1.png" src2='images/image2.png' width="16px"></button>
</body>
</html>
You need to store the old value in a global variable.
For example:
var globalVarPreviousImgSrc;
var swapImage = function(src)
{
var imgBut = document.getElementById("ImageButton1");
globalVarPreviousImgSrc = imgBut.src;
imgBut.src = src;
}
Then in the action method you can check if it was equal to the old value
function action()
{
if(globalVarPreviousImgSrc != 'images/image2.png')
{
swapImage('images/image2.png');
}else{
swapImage(globalVarPreviousImgSrc);
}
}
It's not a good idea to use global variables in javascripts use a closure or object literal. You can do something like using a closure
(function(){
var clickCounter = 0;
var imgSrc1 = "src to first image";
var imgSrc2 = "src to second image"
functions swapImage (src)
{
var imgBut = document.getElementById("ImageButton1");
imgBut.src = src;
}
function action()
{
if(clickCounter === 1)
{
swapImage(imgSrc1);
--clickCounter;
}else{
swapImage(imgSrc2);
++clickCounter;
}
}
})();
(I haven't run this code though)
This nice w3documentation gives you best practices.
Check this a working example just copy paste and run-
HTML
<button onClick="action();">click me<img src="http://dummyimage.com/200x200/000000/fff.gif&text=Image+1" width="200px" id="ImageButton1"></button>
JAVASCRIPT
<script>
function action()
{
if(document.getElementById("ImageButton1").src == 'http://dummyimage.com/200x200/000000/fff.gif&text=Image+1' )
document.getElementById("ImageButton1").src = 'http://dummyimage.com/200x200/dec4ce/fff.gif&text=Image+2';
else
document.getElementById("ImageButton1").src = 'http://dummyimage.com/200x200/000000/fff.gif&text=Image+1';
}
</script>
Check this working example - http://jsfiddle.net/QVRUG/4/
I have a page with 2 javascript events, one triggered from the mouse, the other from the keyboard. When I load the page I can get one or the other to work, but not both. If I press a key first that function will run, but then I cannot do the mouse click or another keystroke. And vice versa. I know jQuery makes this easier, but I'd rather not have my users download that for each page, so I'm trying to do this the old fashioned way. I have read as much about javascript events as I can find but I'm stuck here with this one ...
thanks in advance, Brad.
NOTE: in Chrome and Safari I get the above results, Firefox and Opera will only work with the keystroke function
<html>
<head>
<script>
function create(event) {
var x=event.clientX-14;
var y=event.clientY-33;
var output = document.write("<p id=\"text\" style=\"background-color: white; position: absolute; top:" + y + "px;left:" + x + "px;\";>You're Text, your M#jesty!</p>");
}
function type(event)
{
var letter_in = event.keyCode;
var letter = String.fromCharCode(letter_in);
//var shift = event.shiftKey;
//if (shift === false) {letter = String.toLowerCase;}
document.write(letter);
}
</script>
</head>
<body onmousedown="create(event)" onkeydown="type(event)">
</body>
</html>
It's because you're using document.write() which clears everything else on the page, including your handlers.
Calling document.write() after the document has been loaded implicitly calls document.open(), which clears the document.
So to fix this, you want to use something like innerHTML to only update the contents of an element within your page.
See this example:
<html>
<head>
</head>
<body onmousedown="create(event)" onkeydown="type(event)">
<div id="foo"></div>
<script>
function create(event) {
var x=event.clientX-14;
var y=event.clientY-33;
var output = document.getElementById("foo").innerHTML = "<p id=\"text\" style=\"background-color: white; position: absolute; top:" + y + "px;left:" + x + "px;\";>You're Text, your M#jesty!</p>";
}
function type(event)
{
var letter_in = event.keyCode;
var letter = String.fromCharCode(letter_in);
//var shift = event.shiftKey;
//if (shift === false) {letter = String.toLowerCase;}
document.getElementById("foo").innerHTML = letter;
}
</script>
</body>
</html>
I have recently made the switch from HTML to XHTML... don't get me started on the "why" - let's just say it wasn't an option. Anyhoo...
This function worked fine in IE and FF when I was HTML, but now with XHTML I get the following error in FF:
heightElement is undefined
now here is the statement where I define heightElement
function revBars(isEFBOutput, isIXPPreview) {
if (!isIXPPreview) isIXPPreview = false;
var heightElement =
$('<div id="resizeDetectingElement" style="position:absolute; left:-9999999px height:1em;"> </div>')
.prependTo('body')
.get(0);
heightElement.currentHeight = heightElement.offsetHeight; // FireBug says the error is here.
insert();
window.onresize = refresh;
setInterval(
function() {
if (heightElement.currentHeight != heightElement.offsetHeight) {
heightElement.currentHeight = heightElement.offsetHeight; refresh();
}
}, 500);
function insert() {
var px = "px";
var color = (document.styleSheets[0].href.match("ftidStyleDay")) ? "black" : "white";
$revMarks = $('.RevMark').removeClass('RevMark').addClass('UnMarked');
if (!$revMarks.length) $revMarks = $('.UnMarked');
$revMarks.each(function() {
$('<div class="RevBar" />').css({
'background-color': color,
'width': '2px', 'position': 'absolute',
'left': (isEFBOutput && !isIXPPreview ? '.25em' : '-.75em'),
'height': this.offsetHeight,
'top': offset(this) + px
}).prependTo('body');
});
}
function refresh() { $('.RevBar').remove(); insert(); }
function offset(obj) {
var top = 0;
if (obj.offsetParent) {
do {
top += obj.offsetTop;
} while (obj = obj.offsetParent);
}
if (document.all && (!isEFBOutput || (isEFBOutput && isIXPPreview))) top -= 15;
return top;
}
}
any ideas why this is throwing an error in XHTML in FF? It still works in IE.
EDIT: Again, this code worked perfectly in FF and IE until I switched to XHTML. Firefox still creates a DOM for XHTML, right?
I rewrote some of your example, as you have errors and is incomplete with function calls that are not in the example:
$(document).ready( function(){
function revBars(isEFBOutput, isIXPPreview){
var test = "<div id=\"someElement\">whatever</div>";
$('body').prepend(test).get(0);
var heightElement = $('#someElement');
console.log( heightElement);
}
revBars();
});
At this point the heigthElement exists and the div is added to DOM.
Please provide correct problems in order to get them solved.
UPDATES
//var heightElement = $('<div id="resizeDetectingElement">whatever</div>').prependTo('body').get(0);
// this statement doesn't work
var heightElement = $('body').prepend('<div id="resizeDetectingElement">whatever</div>');
// this does
console.log(heightElement);
This is basically the same as first example.
The request that you made is to add a div before the element body and then get the first element of the body. The prependTo already returns the matched items so the get was irelevant. And you are attaching an element before the body so is normal that your variable will be empty.
Try my code and remove the downvote as not to many people had this kind of patience with your supercode.
UPDATE 2
This is an usage example for prepend() and prependTo().
<html>
<head>
<script type="text/javascript" src="../lib/jquery/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
$(document).ready( function(){
$("#test_A").prepend('<div id=\'test_B\'>B</div>');
$("#test_C").prependTo( $('#test_A'));
var x = $('<div id="resizeDetectingElement">D</div>').prependTo('body').get(0);
console.log( x ); // returns the div
$(x).append('some text'); //works
});
</script>
</head>
<body>
<div id='test_A'>A</div>
<div id='test_C'>C</div>
</body>
</html>
I hope this will help to make your code work. USE $(heightElement) not just heightElement which is the div not the jQuery object.