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?
 
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
 
Tom KnowltonWeb developerAuthor Commented:
The idea being to "capture" the letter (  "T" or "G" above ) to create words...
0
 
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
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

 
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
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.