{"id":178,"date":"2021-02-14T17:38:16","date_gmt":"2021-02-14T17:38:16","guid":{"rendered":"https:\/\/therenaissanceraven.com\/?p=178"},"modified":"2021-02-14T17:38:16","modified_gmt":"2021-02-14T17:38:16","slug":"project-hasseu-tutorial-1-programming-a-machine-gun-projectile-launcher","status":"publish","type":"post","link":"https:\/\/therenaissanceraven.com\/?p=178","title":{"rendered":"Project Hasseu &#8211; Tutorial 1 &#8211; Programming a machine gun \/ projectile launcher"},"content":{"rendered":"<p>Welcome to the first tutorial as I develop Project Hasseu &#8211; programming a machine gun or projectile launcher, probably the core mechanic in shoot-em-up games. Below you see the the YouTube video to watch this tutorial, if not interested, the text based one is below!<\/p>\n<p><iframe loading=\"lazy\" title=\"Unity Machine Gun Tutorial\" width=\"640\" height=\"360\" src=\"https:\/\/www.youtube.com\/embed\/tSEneoUKXlc?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe><\/p>\n<p>Two pull this off you need two objects, the projectile (bullet) and the firing source (person, tower, etc.).<\/p>\n<p><strong>Bullet:<\/strong><br \/>\nYou first will need to attach a rigidbody to the bullet and then make it a prefab.<br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008800; font-weight: bold;\">using<\/span> <span style=\"color: #0e84b5; font-weight: bold;\">System.Collections<\/span>;\r\n<span style=\"color: #008800; font-weight: bold;\">using<\/span> <span style=\"color: #0e84b5; font-weight: bold;\">System.Collections.Generic<\/span>;\r\n<span style=\"color: #008800; font-weight: bold;\">using<\/span> <span style=\"color: #0e84b5; font-weight: bold;\">UnityEngine<\/span>;\r\n\r\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> <span style=\"color: #008800; font-weight: bold;\">class<\/span> <span style=\"color: #bb0066; font-weight: bold;\">BulletController<\/span> : MonoBehaviour\r\n{\r\n    <span style=\"color: #008800; font-weight: bold;\">public<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> speed = <span style=\"color: #6600ee; font-weight: bold;\">160f<\/span>;\r\n    <span style=\"color: #008800; font-weight: bold;\">public<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> bullet_spread = <span style=\"color: #6600ee; font-weight: bold;\">0.01f<\/span>;\r\n    <span style=\"color: #008800; font-weight: bold;\">public<\/span> Vector2 trajectory = <span style=\"color: #008800; font-weight: bold;\">new<\/span> Vector2(<span style=\"color: #6600ee; font-weight: bold;\">0f<\/span>,<span style=\"color: #6600ee; font-weight: bold;\">1f<\/span>);\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> Rigidbody2D rb;\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> distanceTravelled = <span style=\"color: #6600ee; font-weight: bold;\">0f<\/span>;\r\n    <span style=\"color: #008800; font-weight: bold;\">public<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> maxDistance = <span style=\"color: #6600ee; font-weight: bold;\">100f<\/span>;\r\n\r\n    <span style=\"color: #888888;\">\/\/ Start is called before the first frame update<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">Start<\/span>()\r\n    {\r\n        <span style=\"color: #888888;\">\/\/ get rigidbody reference<\/span>\r\n        rb = <span style=\"color: #008800; font-weight: bold;\">this<\/span>.GetComponent&lt;Rigidbody2D&gt;();\r\n    }\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">FixedUpdate<\/span>()\r\n    {\r\n        <span style=\"color: #888888;\">\/\/ get current position<\/span>\r\n        Vector2 currentPosition = rb.position;\r\n\r\n        <span style=\"color: #888888;\">\/\/ move bullet by trajectory by speed and deltaTime<\/span>\r\n        rb.MovePosition(<span style=\"color: #008800; font-weight: bold;\">new<\/span> Vector2(currentPosition.x + speed * trajectory.x * Time.deltaTime, currentPosition.y + speed * trajectory.y * Time.deltaTime));\r\n\r\n        <span style=\"color: #888888;\">\/\/ running sum of distance travelled and destory if more than max distance<\/span>\r\n        distanceTravelled += speed * Time.deltaTime;\r\n        <span style=\"color: #008800; font-weight: bold;\">if<\/span> (distanceTravelled &gt; maxDistance)\r\n        {\r\n            Destroy(<span style=\"color: #008800; font-weight: bold;\">this<\/span>.gameObject);\r\n        }\r\n    }\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">public<\/span> <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">SetTrajectory<\/span>(Vector2 trajectory)\r\n    {\r\n        <span style=\"color: #888888;\">\/\/ normalize so speed is not a function of trajectory magnitude<\/span>\r\n        trajectory.Normalize();\r\n\r\n        <span style=\"color: #888888;\">\/\/ give some random spreading to bullet spray<\/span>\r\n        trajectory.x += Random.Range(bullet_spread, -<span style=\"color: #6600ee; font-weight: bold;\">1f<\/span> * bullet_spread);\r\n        trajectory.y += Random.Range(bullet_spread, -<span style=\"color: #6600ee; font-weight: bold;\">1f<\/span> * bullet_spread);\r\n\r\n        <span style=\"color: #888888;\">\/\/ saving trajectory to object<\/span>\r\n        <span style=\"color: #008800; font-weight: bold;\">this<\/span>.trajectory = trajectory;\r\n\r\n        <span style=\"color: #888888;\">\/\/ altering starting position of bullet with little magic to increase visual density (e.g. bullets not rendering at same distance each frame)<\/span>\r\n        <span style=\"color: #333399; font-weight: bold;\">float<\/span> random = Random.Range(<span style=\"color: #6600ee; font-weight: bold;\">1f<\/span>, <span style=\"color: #6600ee; font-weight: bold;\">0f<\/span>);\r\n        <span style=\"color: #008800; font-weight: bold;\">this<\/span>.transform.position +=  <span style=\"color: #008800; font-weight: bold;\">new<\/span> Vector3(random * trajectory.x, random * trajectory.y, <span style=\"color: #6600ee; font-weight: bold;\">0f<\/span>);\r\n\r\n        <span style=\"color: #888888;\">\/\/ converting trajectory into rotation angle and setting<\/span>\r\n        <span style=\"color: #333399; font-weight: bold;\">float<\/span> angle = Mathf.Atan2(trajectory.y,trajectory.x)*<span style=\"color: #6600ee; font-weight: bold;\">360f<\/span>\/(<span style=\"color: #6600ee; font-weight: bold;\">2f<\/span>*Mathf.PI)-<span style=\"color: #6600ee; font-weight: bold;\">90f<\/span>;\r\n        <span style=\"color: #008800; font-weight: bold;\">this<\/span>.transform.rotation = Quaternion.Euler(<span style=\"color: #6600ee; font-weight: bold;\">0f<\/span>,<span style=\"color: #6600ee; font-weight: bold;\">0f<\/span>,angle);\r\n\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n<p><strong>Player:<\/strong><br \/>\nFor the player I have attached a rigidbody and some code to move the player, but the core functionality is to get mouse input in the Update frame and execute the FireProjectile function.<br \/>\n<!-- HTML generated using hilite.me --><\/p>\n<div style=\"background: #ffffff; overflow: auto; width: auto; border: solid gray; border-width: .1em .1em .1em .8em; padding: .2em .6em;\">\n<pre style=\"margin: 0; line-height: 125%;\"><span style=\"color: #008800; font-weight: bold;\">using<\/span> <span style=\"color: #0e84b5; font-weight: bold;\">System.Collections<\/span>;\r\n<span style=\"color: #008800; font-weight: bold;\">using<\/span> <span style=\"color: #0e84b5; font-weight: bold;\">System.Collections.Generic<\/span>;\r\n<span style=\"color: #008800; font-weight: bold;\">using<\/span> <span style=\"color: #0e84b5; font-weight: bold;\">UnityEngine<\/span>;\r\n\r\n<span style=\"color: #008800; font-weight: bold;\">public<\/span> <span style=\"color: #008800; font-weight: bold;\">class<\/span> <span style=\"color: #bb0066; font-weight: bold;\">PlayerController<\/span> : MonoBehaviour\r\n{\r\n    <span style=\"color: #888888;\">\/\/ reference to bullet prefab<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">public<\/span> GameObject bulletPreFab;\r\n\r\n    <span style=\"color: #888888;\">\/\/ for movement variables<\/span>\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> horizontalInput;\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> verticalInput;\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> <span style=\"color: #333399; font-weight: bold;\">float<\/span> speed = <span style=\"color: #6600ee; font-weight: bold;\">10f<\/span>;\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> Rigidbody2D rigidbody;\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">Start<\/span>()\r\n    {\r\n        rigidbody = <span style=\"color: #008800; font-weight: bold;\">this<\/span>.GetComponent&lt;Rigidbody2D&gt;();\r\n    }\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">Update<\/span>()\r\n    {\r\n        <span style=\"color: #888888;\">\/\/ when mouse left button is down<\/span>\r\n        <span style=\"color: #008800; font-weight: bold;\">if<\/span> (Input.GetMouseButton(<span style=\"color: #6600ee; font-weight: bold;\">0<\/span>))\r\n        {\r\n            FireProjectile();\r\n        }\r\n\r\n        horizontalInput = Input.GetAxis(<span style=\"background-color: #fff0f0;\">\"Horizontal\"<\/span>);\r\n        verticalInput = Input.GetAxis(<span style=\"background-color: #fff0f0;\">\"Vertical\"<\/span>);\r\n    }\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">FixedUpdate<\/span>()\r\n    {\r\n        rigidbody.MovePosition(rigidbody.position += <span style=\"color: #008800; font-weight: bold;\">new<\/span> Vector2(speed * horizontalInput * Time.deltaTime, speed * verticalInput * Time.deltaTime));\r\n    }\r\n\r\n    <span style=\"color: #008800; font-weight: bold;\">private<\/span> <span style=\"color: #008800; font-weight: bold;\">void<\/span> <span style=\"color: #0066bb; font-weight: bold;\">FireProjectile<\/span>()\r\n    {\r\n        <span style=\"color: #888888;\">\/\/ create the new bullet<\/span>\r\n        GameObject newObject = Instantiate(bulletPreFab);\r\n\r\n        <span style=\"color: #888888;\">\/\/ setting starting position of bullet at character<\/span>\r\n        newObject.transform.position = <span style=\"color: #008800; font-weight: bold;\">this<\/span>.transform.position;\r\n\r\n        <span style=\"color: #888888;\">\/\/ direction to shoot (mouse coordinates - player)<\/span>\r\n        Vector2 trajectory = (Vector2)Camera.main.ScreenToWorldPoint(Input.mousePosition) - (Vector2)<span style=\"color: #008800; font-weight: bold;\">this<\/span>.transform.position;\r\n\r\n        <span style=\"color: #888888;\">\/\/ give trajectory to object<\/span>\r\n        newObject.GetComponent&lt;BulletController&gt;().SetTrajectory(trajectory);\r\n    }\r\n}\r\n<\/pre>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Welcome to the first tutorial as I develop Project Hasseu &#8211; programming a machine gun or projectile launcher, probably the core mechanic in shoot-em-up games. Below you see the the YouTube video to watch this tutorial, if not interested, the text based one is below! Two pull this off you need two objects, the projectile&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-178","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=\/wp\/v2\/posts\/178","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=178"}],"version-history":[{"count":1,"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=\/wp\/v2\/posts\/178\/revisions"}],"predecessor-version":[{"id":179,"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=\/wp\/v2\/posts\/178\/revisions\/179"}],"wp:attachment":[{"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=178"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=178"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/therenaissanceraven.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=178"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}