word creation game - click on moving circle - HTML5 canvas / JavaScript

How do i set it up so I can click on a moving circle and the mouse down generates an event I can respond to?


$(function () {

    var i = 0;

    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    

    var one = {
        x: 500,
        origX: 500,
        step: 7,
        y: 300,
        color: '#3B653D',
        useletter: 'G'        
    };

    var two = {
        x: 2800,
        origX: 2800,
        step: 7,
        y: 60,
        color: '#3B653D',
        useletter: 'T'        
    };

    _myCircleArray = [one, two];

    window.requestAnimFrame = (function (callback) {
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
    })();

    function drawTextBubble(myCircle, context) {
        //the circle
        context.beginPath();
        context.arc(myCircle.x, myCircle.y, 50, 0, Math.PI * 2, false);
        context.fillStyle = myCircle.color;
        context.fill();
        context.strokeStyle = '#FFF';
        context.stroke();

        //the letter inside the circle
        context.beginPath();
        context.fillStyle = '#FFF';
        context.fill();
        context.font = "40px Grunge Handwriting";
        context.fillText(myCircle.useletter, myCircle.x - 10, myCircle.y + 10);
        context.strokeStyle = '#FFF';
        context.stroke();
    }

    function animate(canvas, context, startTime) {
        var time = (new Date()).getTime() - startTime;
        context.clearRect(0, 0, canvas.width, canvas.height); // only clear once
        for (var a = 0; a < _myCircleArray.length; a++) {
            var myCircle = _myCircleArray[a];           
            myCircle.x = myCircle.x - myCircle.step;

            if (myCircle.x < -50) {
                myCircle.x = myCircle.origX;
            }

            drawTextBubble(myCircle, context);
        }
        requestAnimFrame(function () {
            animate(canvas, context, startTime);
        });
    }

    // wait one second before starting animation
    setTimeout(function () {
        var startTime = (new Date()).getTime();
        animate(canvas, context, startTime);
    }, 1000);

});

Open in new window



Program "letter bubbles" going from right to left across the screen during game play:

text bubble
LVL 5
Tom KnowltonWeb developerAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Tom KnowltonWeb developerAuthor Commented:
The idea being to "capture" the letter (  "T" or "G" above ) to create words...
0
Robert SchuttSoftware EngineerCommented:
Try this. Note that I added a "visible" property to hide the clicked bubbles.
<!DOCTYPE html>
<html>
<head>
<title> EE Q_28650692 </title>
<script src="http://code.jquery.com/jquery.min.js"></script>
<script>

$(function () {

    var i = 0;

    var canvas = document.getElementById("myCanvas");
    var context = canvas.getContext("2d");

    var one = {
        visible: true,
        x: 500,
        origX: 500,
        step: 7,
        y: 300,
        color: '#3B653D',
        useletter: 'G'        
    };

    var two = {
        visible: true,
		x: 2800,
        origX: 2800,
        step: 7,
        y: 60,
        color: '#3B653D',
        useletter: 'T'        
    };

    _myCircleArray = [one, two];

	var currentBubble = null, mouse_x, mouse_y;

    window.requestAnimFrame = (function (callback) {
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
    })();

    function drawTextBubble(myCircle, context) {
		
        //the circle
        context.beginPath();
        context.arc(myCircle.x, myCircle.y, 50, 0, Math.PI * 2, false);
		if (context.isPointInPath(mouse_x, mouse_y)) {
			currentBubble = myCircle;
		}
        context.fillStyle = myCircle.color;
        context.fill();
        context.strokeStyle = currentBubble == myCircle ? '#F00' : '#FFF';
        context.stroke();

        //the letter inside the circle
        context.beginPath();
        context.fillStyle = '#FFF';
        context.fill();
        context.font = "40px Grunge Handwriting";
        context.fillText(myCircle.useletter, myCircle.x - 10, myCircle.y + 10);
        context.strokeStyle = '#FFF';
        context.stroke();
    }

    function animate(canvas, context, startTime) {
        var time = (new Date()).getTime() - startTime;
        context.clearRect(0, 0, canvas.width, canvas.height); // only clear once
		currentBubble = null;
        for (var a = 0; a < _myCircleArray.length; a++) {
            var myCircle = _myCircleArray[a];           
            if (myCircle.visible) {
                myCircle.x = myCircle.x - myCircle.step;

                if (myCircle.x < -50) {
                    myCircle.x = myCircle.origX;
                }

                drawTextBubble(myCircle, context);
            }
        }
        requestAnimFrame(function () {
            animate(canvas, context, startTime);
        });
    }

    // wait one second before starting animation
    setTimeout(function () {
        var startTime = (new Date()).getTime();
		$('#myCanvas').on("mousemove", mouseHandler1);
		$('#myCanvas').on("mousedown", mouseHandler2);
        animate(canvas, context, startTime);
    }, 1000);

	function mouseHandler1(e) {
		mouse_x = e.offsetX;
		mouse_y = e.offsetY;
	}
	function mouseHandler2(e) {
		if (currentBubble != null) {
			$('#word').val($('#word').val() + currentBubble.useletter);
            currentBubble.visible = false;
		}
	}

});

</script>
<style>

#myCanvas {
	background-color: rgb(59, 101, 61);
	border: 1px solid red;
}

</style>
</head>
<body>
<canvas id="myCanvas" width="750" height="600">no canvas support</canvas>
<br><input id="word">
</body>
</html>

Open in new window


Live example here: http://schutt.nl/ee/Q_28650692/
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Slick812Commented:
greetings knowlton, , Looked at your question parts, and looked at your code, although you say -
"Program "letter bubbles" going from right to left across the screen during game play"
    and
"so I can click on a moving circle and the mouse down generates an event I can respond to"

Since you are using a Canvas, the HTML canvas is a single page element, so any and all of your moving circles, do NOT have any browser DOM identity, they are just unknown colors on the single canvas. So to detect a positional Click (on a mover circle) you will need to do the Math, to calculate the rectangles that all of the circles occupy at the time of click, and then test to see if the click point is inside of any of the circle "click area rectangles" at that time. However,since these are circles, you may want to NOT detect the corners of the click rectangle OUTSIDE of the circle, which requires even more math.
If your moving Circles, do not change their Y (horizontal) position, then you can use the "height" and add the Offset from top (the Y position) to get an unchanging Y click range for the rectangle, the math for the X click range, is more work, as you need to use the current X position for ALL movers and set the range by adding the circle width, and then use an IF test on ALL circle click rectangles, to see which rectangle (if any) has the click point in it's range (both X and Y).

I beleive if I were doing this I would Not use a Canvas, just a container div, and then use several mover <div> animated within the container <div>, that way you can just set the "onclick" (or the "onmousedown") for each of the mover <div>, so the browser does all of the position detection math and click point for you.
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

Tom KnowltonWeb developerAuthor Commented:
I beleive if I were doing this I would Not use a Canvas, just a container div, and then use several mover <div> animated within the container <div>, that way you can just set the "onclick" (or the "onmousedown") for each of the mover <div>, so the browser does all of the position detection math and click point for you


How long would it take you to create a small example I can test....like what Robert Schutt provided?
0
Slick812Commented:
I'll see if I have time, but doing any movement game web interface is not an easy or fast development try.
0
Slick812Commented:
OK here it is, I took some code chunks from other projects, and pieced this together, I ran it in firefox and chrome, and It did not have th smoothest animation, but It looked good enough to be usable.
<!DOCTYPE HTML>
<html lang="en"><head><title>Click Mover Circles</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<script>/* <![CDATA[ */
function id2ob(elmt1){return document.getElementById(elmt1);}
if(document.all)id2ob=function(elmt1){return document.all[elmt1];}
var ani = 0;
/* ]]> */</script>
<style>
body{background:#f0e8ff;margin:4px 1px;}

.title {
  position:relative;
  top: 1em;
  width: 15em;
  padding: 1px;
  background: #dc3;
  text-align: center;
  margin-left: 182px;
  border:2px solid #c00;
  border-radius:10px;
  z-index: 2;
  }
  
.aniCont {
  position: relative;
  width:600px;
  height:400px;
  text-align: center;
  background: #8b8;
  border:2px solid #c00;
  overflow:hidden;
  }
  
.mover {
  display: none;
  position: absolute;
  top: 2px;
  left: 2px;
  width: 93px;
  height: 93px;
  color: #fff;
  line-height: 2em;
  font-family:comic sans ms,arial,helvetica,sans-serif;
  border:2px solid #fff;
  border-radius:47px;
  font-size: 270%;
  }

</style>
</head><body><h2 style="padding-left:6.8em;">Click Mover Circles Letters</h2>
<button style="margin-left:14.5em;" onclick="startGame()">Start Go Move</button> - - - <button onclick="ani = 0;">Stop movers</button>
<div class="title">Click Letters to spell "GOOD"</div>
<div class="aniCont">
<div id="mv1" class="mover">G</div>
<div id="mv2" class="mover">D</div>
<div id="mv3" class="mover">O</div>
</div>
<div id="speller" class="title" style="top:-1em;">- - -</div>


<script>/* <![CDATA[ */
window.requestAnimFrame = (function (callback) {
        return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
        function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
  })();
		
function move() {
if(ani==2) {
  ani = 1;
  for (var i=0; i < movAry.length; ++i)
    movAry[i].style.display = "block";
  }
for (var i=0; i < movAry.length; ++i) {
  var newL = movAry[i].m0left - 3;
  if (newL < -101) newL = 608;
  movAry[i].style.left = newL+"px";
  movAry[i].m0left = newL;
  }

if (ani) requestAnimFrame(function () {move();});
}

function addLetter(mv) {
speller.m0text += mv.m0letter;
speller.innerHTML = speller.m0text;
mv.style.borderColor="#e00";
if(speller.m0text.length == 4) {
  ani=0;
  for (var i=0; i < movAry.length; ++i)
    movAry[i].style.display = "none";

  if (speller.m0text == "GOOD") {
    speller.innerHTML = "YES, You Got the Word - <b>"+speller.m0text+"</b>";
    } else {
    speller.innerHTML = 'NO! <b>"'+speller.m0text+'"</b> is NOT GOOD';
    }
  
  }
}

function startGame() {
if(ani) return;
if (speller.m0text.length > 0) {
  for (var i=0; i < movAry.length; ++i)
    movAry[i].style.borderColor="#fff";
  speller.m0text = "";
  speller.innerHTML = "- - -";
  }
ani=2; 
move();
}

var speller = id2ob("speller");
speller.m0text = "";
var movAry = [id2ob("mv1"), id2ob("mv2"), id2ob("mv3")];

movAry[0].style.top = "21px";
movAry[0].style.left = "170px";
movAry[0].style.backgroundColor = "#009";
movAry[0].m0left = 170;
movAry[0].m0letter = "G";
movAry[1].style.top = "131px";
movAry[1].style.left = "570px";
movAry[1].style.backgroundColor = "#909";
movAry[1].m0left = 570;
movAry[1].m0letter = "D";
movAry[2].style.top = "241px";
movAry[2].style.left = "350px";
movAry[2].style.backgroundColor = "#900";
movAry[2].m0left = 350;
movAry[2].m0letter = "O";

for (var i=0; i < movAry.length; ++i) {
movAry[i].onmousedown = function() {addLetter(this);};
}
var startTime = (new Date()).getTime();

/* ]]> */</script>
</body></html>

Open in new window


I do not have time to explain what I did here, but I will say that the ARRAY -
   var movAry
contains the 3 DOM objects for the mover <div>
I do not have time to do a flexible design, so I just added the 3 mover div properties with code like-
   movAry[0].style.top = "21px";

I assign the OnMouseDown event to the 3 movers with -
     movAry[j].onmousedown = function() {addLetter(this);};

the function addLetter(mv)  will get the Letter of the mover and add it to the speller title <div> innerHtml.

the function  move(), is what does the movers repositioning with a style left change.

As I said, this does not have many options, but it does respond to the mouse correctly.
0
Tom KnowltonWeb developerAuthor Commented:
Thank you both!

Tom
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Game Programming

From novice to tech pro — start learning today.