|
||
| Inside Technique : DHTML Darts This is my fourth Arcade game. Be sure to also check out Pacman, BreakOut, and Space Bounty Hunter. Like these other games, we use various internet languages, notably VML, DVML (Dynamic VML), and advanced DHTML to create Darts. The rules of match the rules for basic 501 darts game, i.e. throw darts at the board to reduce your score to zero. You must finish with a double or the inner bull to leave exactly zero. You can score zero points with a dart if you miss the board, hit the wire or hit another dart. You get three darts in your turn. Play DartsIE5 only The CodeThis section of code tells Internet Explorer that the document contains VML, the Vector Markup Language which is used to create graphics. We also define the position for the input elements the represent the player's scores.
<HTML>
<HEAD>
<TITLE>Darts</TITLE>
<xml:namespace ns="urn:schemas-microsoft-com:vml" prefix="v"/>
<STYLE>
v\:* {behavior:url(#default#VML);position:absolute}
input {position:absolute;top:50}
</STYLE>
The opening code initializes a few global variables:
The rnd(n) function is slightly extended from my usual rnd defintion, this rnd function produces a range of integers from (-n+1)/2 to (n-1)/2, e.g. if n is 31, then the rnd function returns -15<=x<=15.
<SCRIPT>
x=385;
y=305;
dtr=1/180*Math.PI;
rtd=1/dtr;
ps=new Array(501,501);
nd=new Array(0,0);
pl=0;
dl=3;
ssf=0;
status='';
bd=new Array(200,186,128,114);
clr=new Array();
ds=new Array(10,15,2,17,3,19,7,16,8,11,14,9,12,5,20,1,18,4,13,6);
rs=new Array(2,1,3,1);
ptgf=0;
legs=new Array(0,0);
df=new Array('#00ff00','#ffff00');
function rnd(n) {
return Math.floor(Math.random()*n)-Math.floor(n/2);
}
The movescope function repositions the main scope for the dart board. The first line of this function enables the code to distinguish between a user-initiated event (i.e. the event object exists), or a function call from the setInterval function which we met later (in which case there is no event object). The rnd function calls provide the erratic movement that the player has to contend with. The if statements keep the scope with a valid range.
function movescope() {
if (event) {
x=event.clientX-17+rnd(31);
y=event.clientY-17+rnd(31);
}
x+=rnd(11);
y+=rnd(11);
if (x<110) x=110;
if (x>600) x=600;
if (y<0) y=0;
if (y>410) y=410;
scope.style.left=x;
scope.style.top=y;
}
This next lengthy function positions the dart on the board and determines the score for the turn. It also changes the player's score, checks for an 'out shot' (a double or bull for a finish), announces a 'No score' (player overscored) or a 180 (the maximum score possible with three darts). This function also tracks the total number of darts the player has so far used (the quickest victory in darts is with 9 darts - 180, 180, 60, 3*17, 2*15 for example). It also calls the change function which clears the board and changes the player.
function dart() {
clearInterval(ms);
scope.style.zIndex=-1;
d=document.createElement('v:oval');
d.fillcolor=df[pl];
d.id='d'+dl;
dy=11+rnd(31);
dx=11+rnd(31);
with (d.style) {
top=y+dy;
left=x+dx;
height=8;
width=8;
}
xd=x+dx+4;
yd=y+dy+4;
sf=document.elementFromPoint(xd,yd).id;
dbody.appendChild(d);
switch (sf) {
case 'w':{sf=0;break;}
case 'scope':{sf=0;break;}
case 'd1':{sf=0;break;}
case 'd2':{sf=0;break;}
case 'd3':{sf=0;break;}
default:{
sfm=sf.substr(1,1)*1;
sf=sf.substr(2)*1;
if (sfm==2) sf*=2;
if (sfm==3) sf*=3;
}
}
status+=sf+((dl>1)?':':'');
ssf+=sf;
ps[pl]-=sf;
nd[pl]++;
dl--;
scope.style.zIndex=1;
if (ps[pl]==0 && (sfm==2 || sf==50)) {
if (pl==0) p0.value=ps[pl]; else p1.value=ps[pl];
winner(pl);
return false;
}
if (ps[pl]<2) {dl=0;ps[pl]+=ssf;ssf=0;alert('No score.');}
if (dl==0) {
if (ssf==180) alert('One Hundred and Eighty!!!!');
dbody.onclick=null;
setTimeout('change()',750);
}
else ms=setInterval('movescope()',10);
}
The change function performs the changeover of player. This involves changing the scope color (the DVML bit), adjusting the score boards, changing the player, removing any existing old darts, and restoring the event handler to the onclick event and setInterval function.
function change() {
scope.fillcolor=df[1-pl];
if (pl==0) {
p0.value=ps[pl];
p0.style.backgroundColor='white';
p1.style.backgroundColor=df[1-pl];
}
else {
p1.value=ps[pl];
p0.style.backgroundColor=df[1-pl];
p1.style.backgroundColor='white';
}
dl=3;
pl=1-pl;
if (document.all['d3']) dbody.removeChild(d3);
if (document.all['d2']) dbody.removeChild(d2);
if (document.all['d1']) dbody.removeChild(d1);
ssf=0;
status='';
dbody.onclick=dart;
ms=setInterval('movescope()',10);
}
Something simple at last - this function announces the winner of a game, how many darts it took, and the overall score.
function winner() {
clearInterval(ms);
dbody.onmousemove=null;
dbody.onclick=null;
document.all['p'+pl].style.backgroundColor='#ffcccc';
alert('Player '+eval(pl+1)+' wins in '+nd[pl]+' darts.');
if (document.all['d3']) dbody.removeChild(d3);
if (document.all['d2']) dbody.removeChild(d2);
if (document.all['d1']) dbody.removeChild(d1);
legs[pl]++;
alert('Legs :\nPlayer 1 : '+legs[0]+'\nPlayer 2 : '+legs[1]);
newgame();
}
The newgame function resets all the variables and displays for a new game.
function newgame() {
x=385;
y=305;
ptgf=1-ptgf;
pl=ptgf;
if (pl==0) {
p0.style.backgroundColor=df[pl];
p1.style.backgroundColor='white';
}
else {
p0.style.backgroundColor='white';
p1.style.backgroundColor=df[pl];
}
dl=3;
ps[0]=501;
ps[1]=501;
p0.value=501;
p1.value=501;
nd[0]=0;
nd[1]=0;
scope.fillcolor=df[pl];
ssf=0;
status='';
dbody.onmousemove=movescope;
dbody.onclick=dart;
ms=setInterval('movescope()',10);
}
The init function initializes all the variables, displays, and event handlers for a new game. It also sets the setInterval in motion which calls the movescope() function every 0.01 seconds to make throwing the dart more difficult.
function init() {
dbody.style.cursor='crosshair';
wires();
if (pl==0) {
p0.style.backgroundColor=df[pl];
p1.style.backgroundColor='white';
}
else {
p0.style.backgroundColor='white';
p1.style.backgroundColor=df[pl];
}
p0.value=501;
p1.value=501;
dbody.onmousemove=movescope;
dbody.onclick=dart;
ms=setInterval('movescope()',10);
}
The next function, wires, is a massive function. This function draws the dart board. This involves creating VML elements during run-time. This approach offers simplicity and control over the drawing process. The dart scores are assigned through the id elements which are parsed and converted into a score in the dart function.
function wires() {
//board
for (i=9;i<360;i+=18) {
ci=Math.cos(i*dtr);
si=Math.sin(i*dtr);
cin=Math.cos((i+18)*dtr);
sin=Math.sin((i+18)*dtr);
clr[0]=(((i-9)%36==0)?'red':'black');
clr[1]=((clr[0]=='black')?'red':'black');
for (r=0;r<4;r++) {
sz=bd[r];
sz2=sz*2;
oo=r%2;
wid='b'+rs[r]+eval(ds[(i-9)/18]);
co=clr[oo];
w=document.createElement('v:arc');
w.id=wid;
w.fillcolor=co;
w.strokecolor='#CCCCCC';
with (w.style) {
position='absolute';
top=220-sz;
left=370-sz;
height=sz2;
width=sz2;
}
w.startangle=90+i;
w.endangle=i+108;
dbody.appendChild(w);
w=document.createElement('v:polyline');
w.id=wid;
w.fillcolor=co;
w.strokecolor=co;
w.points='"360 205 '+eval(360+sz*ci)
+' '+eval(205+sz*si)
+' '+eval(360+sz*cin)
+' '+eval(205+sz*sin)+'"';
dbody.appendChild(w);
}//end r
}//end i
//outer bull
w=document.createElement('v:oval');
w.id='b125';
w.fillcolor='black'
w.strokecolor='#CCCCCC';
with (w.style) {
position='absolute';
top=195;
left=345;
height=50;
width=50;
}
dbody.appendChild(w);
//inner bull
w=document.createElement('v:oval');
w.id='b150';
w.fillcolor='red';
w.strokecolor='#CCCCCC';
with (w.style) {
position='absolute';
top=210;
left=360;
height=20;
width=20;
}
dbody.appendChild(w);
//wires
for (i=9;i<360;i+=18) {
w=document.createElement('v:line');
w.id='w';
ci=Math.cos(i*dtr);
si=Math.sin(i*dtr);
w.strokecolor='#CCCCCC';
w.from='"'+eval(360+200*ci)+','+eval(205+200*si)+'"';
w.to='"'+eval(360+25*ci)+','+eval(205+25*si)+'"';
dbody.appendChild(w);
w=document.createElement('SPAN');
w.innerText=ds[(i-9)/18];
si=Math.sin((i+9)*dtr);
ci=Math.cos((i+9)*dtr);
with (w.style) {
position='absolute';
fontWeight=700;
top=205+220*si+((si<0)?15:0);
left=360+220*ci+((ci<0)?5:0);
}
dbody.appendChild(w);
}
}
</SCRIPT>
</HEAD>
Last is the small amount of HTML necessary to bring this together.
<BODY ID="dbody" onload="init();">
<v:oval ID="scope" fillcolor="#00FF00"
style="top:20;left:170;width:30;height:30;
z-index:1;filter:alpha(opacity=50)" />
<input type=text id="p0" readonly size=3 style="left:80">
<input type=text id="p1" readonly size=3 style="left:600">
</BODY>
</HTML>
Play DartsIE5 Only Jon Perry is a freelance Author and Programmer from England. © 1997-2000 InsideDHTML.com, LLC. All rights reserved. |