2DShooter Part1

By Eric Haines (a.k.a. Eric5h5)

Creating the enemy object
First, draw an enemy of some kind in your image editor of choice. The size of the graphic should be a power of two and reasonably large, such as 64x64 at least. You should make it as large as you're comfortable with, and then adjust the scaling down in Unity as necessary. This way you'll have a higher resolution image available should you need or want it later. 256x256 is probably fine. The graphic should have a transparent background, or better yet an alpha channel to define the transparency. The front of the enemy should be at the top of the graphic, since that will be the forward direction. When you're done, save this into the Textures folder in the 2DShooter folder and call it "enemy". The file format should be one that supports alpha channels (if you used an alpha channel) or transparency, such as Photoshop's native format.

Now switch to Unity and load the 2D Shooter project; you don't need to load any particular scene yet. In Unity's Project pane, find this texture, and single-click on it and then click on Settings. You can set the Max Texture Size here, depending how large your enemy is going to be. You can adjust it later once you've completed the enemy object, but you can try 64 or 128 to start with. The format should be DXT5, but if that generates visible compression artifacts that you don't like, you can use RGBA 16 bit or RGBA 32 bit, which don't use compression. You should turn off Generate Mip Maps, since this is a 2D game and the texture will never appear any farther away, so you might as well save on memory.

Open the Materials folder in the Project pane and duplicate one of the tile materials, such as the ship material. Rename the duplicate to "enemy", then scroll down to the Textures folder, and drag the enemy texture onto the texture square in the Inspector pane.

To make the enemy object, start by duplicating the Tile prefab that's in the Prefab folder, and rename it to Enemy. (You could make the prefab from scratch, but this saves a step or two.) Drag the Enemy prefab into the Hierarchy pane, and with the cursor in the Scene view, hit the F key to focus the view on the prefab object. The object should be at coordinates 0,0,0. Make sure the scene view is set to orthogonal, with a view from the top. Now drag the enemy material onto the enemy object in the Scene view or the Hierarchy. Select the enemy object and remove the mesh collider in the Inspector. This will lose the prefab connection, which is OK; we'll reestablish it later. Change the Layer on the object from Walls to Default--this is important for raycast collisions (discussed later) to work properly. Then go to the Component menu and choose Physics -> Rigidbody, and uncheck Use Gravity and check Is Kinematic.

Now we need some kind of collider, so it will collide with bullets and the player's ship. This is easiest if your graphic is round (like the turrets) or square, in which case you can simply go to the Component menu and choose Physics -> Box Collider or Sphere Collider. You can adjust the size or radius of the collider as necessary until it best matches the shape of your graphic. If you have a graphic that isn't easily defined by a circle or square, you can make a compound collider by adding additional objects, which have their own primitive colliders, as children of the enemy object. Thus you could build a collider out of two or more different squares or circles. Another option is to do something similar to the Ship prefab, which is built out of a convex mesh collider. In this case, you can make a shape in a 3D app which is similar to the outline of your graphic, and either make this convex mesh collider a child of the enemy object or else replace the Plane mesh filter with your custom mesh and map the graphic onto it directly, like was done with the ship. If you replace the Plane mesh, you'd have to UV map the shape properly in your 3D app.

We also want the enemy to collide with the walls in the level. Rather than using colliders built from 3D shapes, the walls are done quite differently. Instead, objects collide with the actual non-transparent parts of the graphic. This way you can draw whatever shape you like for the walls, and objects will collide with it, without having to build 3D colliders to match. The downside is that this isn't automatic, since Unity is not a 2D engine and doesn't have the ability to do "real" sprite collisions. Instead, this is accomplished with some trickery called raycasting, which samples a point on the screen and sees if something is there.

In order to determine the points that are used for raycasting, you need to add some transforms. You can do this by going to the GameObject menu and choosing Create Other -> Sphere. Make sure its coordinates are 0,0,0 if they aren't already, and remove the sphere collider from it. Then, in the Hierarchy view, drag it onto the enemy object so it becomes a child. Rename it from Sphere to RaycastPoint (the exact spelling and capitalization is important in this case, since this is what a script will be checking for). Now move it to a point near the edge of your graphic; the center of the sphere is where the raycast point will be. You can duplicate the RaycastPoint object a few times and move each one to another part near the edge of your graphic. The goal here is to generally define the shape of your graphic using these raycast points. The more points there are, the more computations have to be done, so it's best to keep the number of points as few as possible, probably 4-6 or so. The renderers for the spheres will be turned off automatically at run-time, so you can leave the spheres as they are for visual reference. You can also take a look at the Ship prefab to see how it's done.

When finished, click on the root of the enemy object, and go to the Component menu and select Scripts -> Raycast Check, or else find the RaycastCheck script and drag it onto the enemy object. When you've done that, with the enemy object selected, change the Layer Mask variable in the Raycast Check script in the Inspector from None to Walls. If you've used a convex mesh collider for your enemy, then check the Check In Update box. If you've used a primitive collider or compound colliders such as sphere or box, you can leave this unchecked. What this does, when selected, is to make the raycast check every frame. This is necessary for a convex mesh collider, since it won't activate the wall triggers, unlike a primitive collider. Thus it's a bit slower, since when Check In Update is not selected, the raycasting isn't done unless the object is actually intersecting a wall tile.

You may want to adjust the enemy object's scale. With the root object of your enemy object selected (not the children, if any), change all 3 elements of Scale in the Inspector from 1 to something like .3, which will make it a similar size compared to the player's ship. To see a direct comparison, you can drag the Ship prefab into the scene and position it next to the enemy object, and adjust the enemy's scale to suit.

When done, go to the GameObject menu and select Apply Changes To Prefab. You can now delete it from the Hierarchy (along with the ship object, if you put one there). The object is now finished and exists as a prefab, except for the script, which we'll add later. To make changes to this object in the future, you can either do so directly to the prefab, or by dragging it into the scene, making the changes (such as moving the raycast points), and then selecting Apply Changes To Prefab.

2D Shooter Index : Intro : Next Part