How To Create an Archery Game using HTML, CSS, and JavaScript

codinglabsolution

 Learn how to make an exciting archery game from scratch using HTML, CSS, and JavaScript. Perfect for beginners in game development.



Create an Archery Game using HTML, CSS, and JavaScript




Welcome to our in-depth tutorial on creating an archery game using HTML, CSS, and JavaScript. Whether you're new to coding or an experienced developer looking to dive into game development, this guide will walk you through the process step by step.


Archery games have long been a favorite among gamers for their combination of skill and precision. By the end of this tutorial, you'll have the skills and knowledge to build your own browser-based archery game that's both engaging and fun to play.


We'll cover everything you need to know, from setting up the basic HTML structure to adding interactive elements using JavaScript. Don't worry if you're new to programming – we'll explain each concept clearly and provide plenty of examples along the way.


By following this guide, you'll not only create a fully functional archery game but also gain a deeper understanding of web development and game design principles. So, let's grab our virtual bows and arrows and embark on this exciting coding adventure together! Are you ready to hit the target? Let's get started!

Source Code

Step 1 (HTML Code):


Let's begin by setting up the HTML structure for our archery game. Below is the breakdown of each part of the code:


1. `<!DOCTYPE html>`: This declaration specifies that the document is an HTML5 document.


2. `<html lang="en">`: This opening tag indicates the start of the HTML document and specifies the language as English.


3. `<head>`: This section contains meta-information about the document, such as the title and character encoding.


    - `<title>Archery Game</title>`: Sets the title of the web page to "Archery Game."

    - `<meta charset="UTF-8" />`: Defines the character encoding for the document as UTF-8.

    - `<meta name="viewport" content="width=device-width" />`: Configures the viewport to be responsive to the device's width.

    - `<link rel="stylesheet" href="styles.css" />`: Links an external CSS stylesheet named "styles.css" to apply styles to the HTML content.


4. `<body>`: This section contains the main content of the web page.


    - `<svg id="game" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 400" overflow="visible">`: This SVG element defines the game area, specifying a viewBox for scaling and positioning graphics.

        - `<linearGradient id="ArcGradient">`: Defines a linear gradient with the ID "ArcGradient" for filling shapes with gradient colors.

        - `<path id="arc" ...>`: Represents an arc in the game, using the gradient defined earlier for its stroke color and specifying attributes like stroke width.

        - `<defs>`: Contains reusable definitions within the SVG.

        - `<g id="arrow">`, `<g id="target">`, `<g id="bow" ...>`: Define groups for drawing arrow, target, and bow graphics.

        - `<g class="arrow-angle">`: References the "arrow" group and positions it at specific coordinates.

        - `<clipPath id="mask">`: Defines a clipping path used for masking certain elements.

        - `<g class="arrows" ...>`, `<g class="miss" ...>`, `<g class="bullseye" ...>`, `<g class="hit" ...>`: Define groups for displaying arrows, misses, bullseyes, and hits.

        - `<span>Draw back an arrow and launch it!</span>`: Provides instructions or information to the user.

        - `<script>`: Includes references to external JavaScript files for interactivity and animations.


This HTML structure sets the foundation for our archery game. Next, we'll move on to styling it using CSS.

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Archery Game</title>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width" />
    <link rel="stylesheet" href="styles.css" />
  </head>
  <body>
    <svg id="game" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 400" overflow="visible">
      <linearGradient id="ArcGradient" >
          <stop offset="0"  stop-color="#fff" stop-opacity=".2"/>
          <stop offset="50%" stop-color="#fff" stop-opacity="0"/>
      </linearGradient>
        <path id="arc" fill="none" stroke="url(#ArcGradient)" stroke-width="4" d="M100,250c250-400,550-400,800,0"  pointer-events="none"/>
        <defs>
            <g id="arrow">
                <line x2="60" fill="none" stroke="#888" stroke-width="2" />
                <polygon fill="#888" points="64 0 58 2 56 0 58 -2" />
                <polygon fill="#88ce02" points="2 -3 -4 -3 -1 0 -4 3 2 3 5 0" />
            </g>
        </defs>
        <g id="target">
            <path fill="#FFF" d="M924.2,274.2c-21.5,21.5-45.9,19.9-52,3.2c-4.4-12.1,2.4-29.2,14.2-41c11.8-11.8,29-18.6,41-14.2 C944.1,228.3,945.7,252.8,924.2,274.2z" />
            <path fill="#F4531C" d="M915.8,265.8c-14.1,14.1-30.8,14.6-36,4.1c-4.1-8.3,0.5-21.3,9.7-30.5s22.2-13.8,30.5-9.7 C930.4,235,929.9,251.7,915.8,265.8z" />
            <path fill="#FFF" d="M908.9,258.9c-8,8-17.9,9.2-21.6,3.5c-3.2-4.9-0.5-13.4,5.6-19.5c6.1-6.1,14.6-8.8,19.5-5.6 C918.1,241,916.9,250.9,908.9,258.9z" />
            <path fill="#F4531C" d="M903.2,253.2c-2.9,2.9-6.7,3.6-8.3,1.7c-1.5-1.8-0.6-5.4,2-8c2.6-2.6,6.2-3.6,8-2 C906.8,246.5,906.1,250.2,903.2,253.2z" />
        </g>
        <g id="bow" fill="none" stroke-linecap="round" vector-effect="non-scaling-stroke" pointer-events="none">
          <polyline fill="none" stroke="#ddd" stroke-linecap="round" points="88,200 88,250 88,300"/>
          <path fill="none" stroke="#88ce02" stroke-width="3" stroke-linecap="round" d="M88,300 c0-10.1,12-25.1,12-50s-12-39.9-12-50"/>
        </g>
      <g class="arrow-angle"><use x="100" y="250" xlink:href="#arrow"/></g>
      <clipPath id="mask">
        <polygon opacity=".5" points="0,0 1500,0 1500,200 970,290 950,240 925,220 875,280 890,295 920,310 0,350" pointer-events="none"/>
      </clipPath>
      <g class="arrows" clip-path="url(#mask)"  pointer-events="none">
      </g>
      <g class="miss" fill="#aaa" opacity="0" transform="translate(0, 100)">
        <path d="M358 194L363 118 386 120 400 153 416 121 440 119 446 203 419 212 416 163 401 180 380 160 381 204"/>
        <path d="M450 120L458 200 475 192 474 121"/>
        <path d="M537 118L487 118 485 160 515 162 509 177 482 171 482 193 529 199 538 148 501 146 508 133 537 137"/>
        <path d="M540 202L543 178 570 186 569 168 544 167 546 122 590 116 586 142 561 140 560 152 586 153 586 205"/>
        <path d="M595,215l5-23l31,0l-5,29L595,215z M627,176l13-70l-41-0l-0,70L627,176z"/>
      </g>
      <g class="bullseye" fill="#F4531C" opacity="0">
        <path d="M322,159l15-21l-27-13l-32,13l15,71l41-14l7-32L322,159z M292,142h20l3,8l-16,8 L292,142z M321,182l-18,9l-4-18l23-2V182z"/>
        <path d="M340 131L359 125 362 169 381 167 386 123 405 129 392 183 351 186z"/>
        <path d="M413 119L402 188 450 196 454 175 422 175 438 120z"/>
        <path d="M432 167L454 169 466 154 451 151 478 115 453 113z"/>
        <path d="M524 109L492 112 466 148 487 155 491 172 464 167 463 184 502 191 513 143 487 141 496 125 517 126z"/>
        <path d="M537 114L512 189 558 199 566 174 533 175 539 162 553 164 558 150 543 145 547 134 566 148 575 124z"/>
        <path d="M577 118L587 158 570 198 587 204 626 118 606 118 598 141 590 112z"/>
        <path d="M635 122L599 198 643 207 649 188 624 188 630 170 639 178 645 162 637 158 649 143 662 151 670 134z"/>
        <path d="M649,220l4-21l28,4l-6,25L649,220z M681,191l40-79l-35-8L659,184L681,191z"/>
      </g>
      <g class="hit" fill="#ffcc00" opacity="0" transform="translate(180, -80) rotate(12) ">
        <path d="M383 114L385 195 407 191 406 160 422 155 418 191 436 189 444 112 423 119 422 141 407 146 400 113"/>
        <path d="M449 185L453 113 477 112 464 186"/>
        <path d="M486 113L484 130 506 130 481 188 506 187 520 131 540 135 545 119"/>
        <path d="M526,195l5-20l22,5l-9,16L526,195z M558,164l32-44l-35-9l-19,51L558,164z"/>
      </g>
    <!-- 	<line x1= "875", y1= "280", x2= "925", y2= "220" stroke="red"/>

    <circle class="point" r="7" fill="purple" opacity=".4"/> -->
    </svg>

    <span>Draw back an arrow and launch it!</span>
    <script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/1.19.1/TweenMax.min.js'></script>
<script src='//s3-us-west-2.amazonaws.com/s.cdpn.io/16327/MorphSVGPlugin.min.js'></script>
    <script src="script.js"></script>
  </body>
</html>

Step 2 (CSS Code):


Let's add some styles to our archery game using CSS. Below is the breakdown of each part of the CSS code:


1. `body`: This rule targets the `<body>` element of the HTML document.


    - `background: #222;`: Sets the background color of the entire webpage to a dark gray color (#222).

    - `margin: 20px;`: Adds a 20-pixel margin to all sides of the `<body>` element, creating space between the content and the edges of the page.


2. `svg`: This rule targets all `<svg>` elements on the page, which are used for drawing graphics in the game.


    - `width: 100%;`: Sets the width of the SVG element to 100% of its containing parent, ensuring it spans the entire width of the viewport.

    - `height: 100%;`: Sets the height of the SVG element to 100% of its containing parent, ensuring it spans the entire height of the viewport.

    - `position: fixed;`: Sets the position of the SVG element to "fixed," meaning it is positioned relative to the viewport and will not scroll with the rest of the page.

    - `top: 0; left: 0;`: Positions the top-left corner of the SVG element at the top-left corner of the viewport.


3. `span`: This rule targets all `<span>` elements on the page, which may be used for displaying text or other inline content.


    - `color: white;`: Sets the text color to white, ensuring good visibility against the dark background.

    - `font-family: sans-serif;`: Specifies a generic sans-serif font family for the text.

    - `opacity: 0.3;`: Sets the opacity of the text to 0.3, making it semi-transparent for a subtle effect.


These CSS styles enhance the visual presentation of our archery game, providing a dark background and styling text elements for better readability. Make sure to create a CSS file named "styles.css" and include these styles in it to apply them to your HTML document.

body{
	background:#222;
	margin:20px;
}
svg{
	width:100%;
	height:100%;
	position:fixed;
	top:0;
	left:0;
}
span{
	color:white;
	font-family:sans-serif;
	opacity:.3;
}

Step 3 (JavaScript Code):


Let's break down the JavaScript code step by step:


1. Selecting SVG Element: The code begins by selecting the SVG element from the DOM using `document.querySelector("svg")`. This SVG element is assumed to contain the graphics for the game.


2. Creating SVG Point: It creates an SVG point called `cursor` using `svg.createSVGPoint()`. This point will be used to track the mouse cursor's position within the SVG.


3. Initialization: The code selects an element with the class "arrows" and initializes a variable `randomAngle` to zero. This likely represents the arrows in the game and the initial angle of the bow.


4. Defining Objects:

    - `target`: Represents the center of the target.

    - `lineSegment`: Represents a line segment used for target intersection.

    - `pivot`: Represents the rotation point of the bow.


5. Aim Function: The `aim` function is defined, which takes an event object `e` (likely a mouse event) as an argument. It calculates and updates various animations and transforms for the bow and arrow based on the mouse position. This function handles aiming the bow.


6. Draw Function: The `draw` function is defined, which is called when the mouse is clicked (`mousedown` event). It initializes the arrow drawing process, sets up event listeners for mouse movement (`mousemove`) and mouse release (`mouseup`), and calls the `aim` function to start aiming the bow.


7. Loose Function: The `loose` function is defined, which is called when the mouse button is released (`mouseup` event). It releases the arrow, removes event listeners for mouse movement and release, animates the bow's return to its original position, duplicates the arrow, and animates the arrow's flight along a path.


8. HitTest Function: The `hitTest` function checks for collisions between the arrow and the target. It uses mathematical calculations to determine if the arrow hits the target or misses it. Depending on the result, it calls the `showMessage` function with a selector for the appropriate message (e.g., "hit," "bullseye," or "miss").


9. OnMiss Function: The `onMiss` function is called when the arrow misses the target. It displays a "miss" message using the `showMessage` function.


10. ShowMessage Function: The `showMessage` function handles the animation of text messages. It uses TweenMax (likely from the GSAP animation library) to animate the appearance and disappearance of messages.


11. Utility Functions: Two utility functions, `getMouseSVG` and `getIntersection`, are defined. `getMouseSVG` normalizes the mouse position within the SVG, and `getIntersection` calculates the intersection point between two line segments and checks if the point is on either segment.


Ensure you create a JavaScript file named "script.js" and include these codes in it. Make sure it's linked properly to your HTML document so that the scripts are executed on the page.

var svg = document.querySelector("svg");
var cursor = svg.createSVGPoint();
var arrows = document.querySelector(".arrows");
var randomAngle = 0;

// center of target
var target = {
	x: 900,
	y: 249.5
};

// target intersection line segment
var lineSegment = {
	x1: 875,
	y1: 280,
	x2: 925,
	y2: 220
};

// bow rotation point
var pivot = {
	x: 100,
	y: 250
};
aim({
	clientX: 320,
	clientY: 300
});



// set up start drag event
window.addEventListener("mousedown", draw);

function draw(e) {
	// pull back arrow
	randomAngle = (Math.random() * Math.PI * 0.03) - 0.015;
	TweenMax.to(".arrow-angle use", 0.3, {
		opacity: 1
	});
	window.addEventListener("mousemove", aim);
	window.addEventListener("mouseup", loose);
	aim(e);
}



function aim(e) {
	// get mouse position in relation to svg position and scale
	var point = getMouseSVG(e);
	point.x = Math.min(point.x, pivot.x - 7);
	point.y = Math.max(point.y, pivot.y + 7);
	var dx = point.x - pivot.x;
	var dy = point.y - pivot.y;
	// Make it more difficult by adding random angle each time
	var angle = Math.atan2(dy, dx) + randomAngle;
	var bowAngle = angle - Math.PI;
	var distance = Math.min(Math.sqrt((dx * dx) + (dy * dy)), 50);
	var scale = Math.min(Math.max(distance / 30, 1), 2);
	TweenMax.to("#bow", 0.3, {
		scaleX: scale,
		rotation: bowAngle + "rad",
		transformOrigin: "right center"
	});
	var arrowX = Math.min(pivot.x - ((1 / scale) * distance), 88);
	TweenMax