Tutorial Series: Introduction to Unity with C# Series
Previous Article | Next Article
So let's just continue and power through the rest of our enemies that inherit from the Enemy class. So we're going to want a Gigantor, which will be a giant enemy. In Start(), set its radius, so it’s Collider radius will be a bit larger. Set its transform.localScale much larger a Vector3, five units for x and y. We’ll also give it a greater gravity scale, so it's affected a little bit less by gravity. So two versus the default value of one, I believe. We’ll also want a reference to the CheeseHead for the direction for moving towards the CheeseHead. So we'll say cheeseHead, and then we'll find the GameObject and we’ll set the direction to… We’ll have a little ternary here, so we’ll say cheeseHead… Basically if it's to the left or to the right of the cheeseHead will determine it's moving toward the cheeseHead, the direction in other words. That’s how we’ll set the direction. Again, that squiggly so we’ll need a a protected override void MovementPattern(). It’s going to be really simple, Body.velocity, so we’ll need to put this in FixedUpdate() because we’re affecting velocity again. New Vector2, we’ll have the speed times direction. And pass in its y velocity. And in FixedUpdate, we’ll call this.
Now because the direction is specified in Start(), we actually don't need to specify direction at instantiation. So what we’ll want to do is make an overload for Initialize() in the base class to take in the two arguments we need for Gigantor. So we’ll say... We’ll have the same basic implementation but just take out the direction. And let's test in the EnemiesFactory. So I'm just going to temporarily comment this out so we can test out the Gigantor. We’ll say Enemy of type Gigantor call them the giantGeorge. We’ll say a new Enemy<Gigantor>(“GiantGeorge”). I’ll say get the ScriptComponent, run its Initialize() method, and we’ll run the overload of variant that has only the two arguments. So we’ll speed is 1… I don't like doing this on separate lines. So I’ll just do this again. Say speed: 1. Again, just temporarily want to test this out, so say 1, 1, 1.
And we’ll see if out Gigantor gets instantiated. Got to get rid of that curly brace. We’re not going to need this dummy anymore I don't think, so let's get rid of that. Right, we’ve got our Gigantor now. We’ll make another enemy, call it ghost. Then in Start(), remember this will be a ghost so we'll figure out how to handle this later, but we’ll know that it's not going to collide with much of anything other than our player. So we’ll figure that out later, but right now we'll just destroy the existing collider, and also want to destroy the RigidBody. And the Sprite, we’ll put the sorting order to 1, and the color, we’ll want some opacity on that, because it’s a ghost. So we’ll set the opacity to half, so 0.5f, and the scale we’ll go to the localScale and we’ll say new Vector3() and we’ll make it fairly large. For the movement pattern, we’ll kind of have it as we did in the previous project. So we’ll say protective override void MovementPattern(). Transform.position equals a Vector3.MoveTowards(), transformed position. We’ll find the CheeseHead and move towards it at this speed. We’ll call that in Update(), not FixedUpdate(), no physics stuff going on here so it's a void Update().
Here in EnemiesFactory, we’ll say Enemy of type Ghost, say ghostlyGayle. Initialize to these values. We also don't need the directions, so we'll use that overload like we did with the Gigantor enemy, say new Vector3(). Alright, try this out. We should have two ghosts now because we have to those two floor GameObjects. Now he's following us around. We'll make another enemy. Just to show the benefits code reuse, we're going to have quite a few enemies here. A couple more anyways. We’ll say we have a Lush enemy. A lot of this code is going to have to do with this enemy's movement, so it’s not too easy to explain what's going on here. I kind of messed around until I got a sort of wobbling motion. That's what my aim was here, so I'm just going to construct this Lush enemy, and you'll see how it behaves later. And use this method WorldToViewpoint, again, to determine part of its motion. Return a Vector3, this will access the X value. If it’s greater than 0.5 so basically if it’s on the right of the middle or the left of the middle, to determine its direction. So direction = -1, else direction equals 1. Could easily make these into a ternary, maybe you’d want to do that on your end. I thought it’d kind of end up in a long line so I’m doing it this way. And in Update() we’ll have a timer functionality that will change its wobble width basically. So we’ll say if (Timer < maxwobblewidth/2)="" horizontalmotion="1." don't="" have="" to="" say="" one,="" but="" so="" it="" looks="" visually="" more="" appealing,="" i’ll="" use="" that="" as="" a="" multiplier.="" if(timer="">< maxwobblewidth),="" so="" if="" iit's="" not="" that="" amount,="" but="" less.="" nonetheless.="" no="" pun="" intended.="" i’m="" full="" of="" unintended="" puns="" aren’t="" i?="" horizontalmotion="-1" times="" direction.="" else="" if="" (timer=""> MaxWobbleWidth) Timer = 0.
We’ll set timer here as Time.deltaTime times sixty. And we’ll want protected override void MovementPattern(). Sort of use something like inertial force here. So we’ll say Body.AddForce, say new Vector2() HorizontalMotion times Speed for X. We’ll pass in the Y velocity. We’ll say ForceMode2D.Force. I’ll write a comment: Cap inertial motion speed. So this was sort of the effect of the GameObject sort of sliding as if on ice, something like that. So if (Body.velocity.x < speed="" 2*="" -1),="" we’ll="" say="" body.velocity="new" vector2()="" speed="" divided="" by="" 2="" times="" -1.="" and="" again,="" we’ll="" pass="" in="" the="" y.="" if(body.velocity.x=""> Speed/2) then Body.velocity = new Vector2(), Speed/2, pass in the velocity for Y.
And then call this in FixedUpdate, so void FixedUpdate, then we’ll instantiate this in the EnemiesFactory. We’ll say Enemy type Lush, call her a lushyLinda. And we’ll say she has random speed, so unpredictable lushyLinda. Seems appropriate somehow. And position. Alright, let's see what lushyLinda is like. Trying to get out of the way of lushyLinda, let her play around wobbling around and everything, there’s little wobbling lushyLinda. Alright, let's move on to the next enemy. Call this one Torque. Part of all these different enemies is also to show you some different physics methods available to you. So with Torque, we’ll actually be using torque. So Torque is an enemy, and in Start() we’ll just set its collider. Set its MovementPattern() right there, say it’s protected override void MovementPattern(). As I mentioned, we’ll be using the torque method called AddTorque() for this GameObject’s movement. So say if (Body.velocit.y < 0).="" so="" basically,="" it’s="" moving="" downwsrds.="" bodyaddtorque(),="" like="" a="" wheel="" basically.="" speed="" divided="" by="" two="" times="" direction.="" and="" i’m="" going="" to="" cast="" it="" to="" float="" to="" make="" sure="" we="" get="" a="" float="" out="" of="" that="" and="" not="" an="" integer,="" which="" will="" truncate="" important="" decimal="" values.="" so="" else="" if(body.velocity.y="=" 0).="" basically="" if="" it="" hit="" the="" ground,="" we’ll="" give="" it="" addforce()="" upwards.="" so="" for="" that,="" one="" hundred.="">
And we'll call that here and in EnemiesFactory, again we’ll test this out, call torqyTom and initialize it. We're going to need direction for this one, because we didn’t set it in the class. So torqyTom, we’ll call its Initialize() method. Set its speed to 3, its direction randomly will be set at instantiation.Random. Range(0,2) * 2 – 1. That gives minus one or one for direction. And we’ll set these positions to something more specific when we deal with this in a later lesson, the actual instantiation of these objects for a game not just for testing. So it’ll be torqyTom. Basically like a wheel gone loose spiraling towards our CheeseHead.
I think we have one more enemy we're going to create, it's going to be called Tweaker. This guy is going to be pretty unpredictable, the most unpredictable of this bunch. Tweaker is going to be an enemy, and it's going to need a Timer. And public bool, I don’t know if this needs to be public or not. So we can see it in the inspector. In Start(), we’ll set its Collider.radius, and its material color, it’s going to be yellowish. It’s a yellowish eyeball. And in Update(), we’ll have this change the Timer. This will reset the Timer every thirty ticks and make TweakOut true. We’re going to want a protected override MovementPattern(), we’ll say if TweakOut is true, we’ll have a random X and Y which we’ll create here in a local variable. randomX = Random.Range(-29f,29f). For Y, and the range will be a little more pronounced.
It doesn't know if we're using the Random method from UnityEngine or System, so either prefix UnityEngine before these calls to these methods, or we just get rid of system here. I don't think we’ll need it. So we'll say Body.AddForce() new Vector2 with randomX times speed, whatever that ends up being. randomY times speed, and then we'll make TweakOut false till it tweaks out again. As we know it will with the timer, it will become true again every thirty ticks. And in FixedUpdate() call this MovementPattern(). Enemy of type Tweaker, call him tweakyTim. Tim the Tweaker. Equals new Enemy Tweaker, and initialize. It's going be a fairly fast character, unpredictable and fast. Say speed and position. Alright, let’s check out Tweaky Time. Yep, all over the place.
Lesson 1 - Who This Course is For
Lesson 2 - What to Expect from this Course
Lesson 3 - Installation and Getting Started
Lesson 4 - Starting the First Project
Lesson 8 - Prototyping Continued
Lesson 9 - C# Fundamentals and Hello World
Lesson 10 - Variables and Operations
Lesson 11 - Variables and Operations Continued
Lesson 12 - Floats, Bools and Casting
Lesson 13 - If Statement Conditionals
Lesson 14 - If Statements Continued
Lesson 15 - Complex Evaluations and States
Lesson 16 - Code Syntax vs. Style
Lesson 18 - Object-Oriented Programming Intro
Lesson 19 - OOP, Access Modifiers, Instantiation
Lesson 20 - Object Containment and Method Returns
Lesson 21 - "Has-A" Object Containment
Lesson 22 - "Is-A" Inheritance Containment
Lesson 23 - Static Fields and Methods
Lesson 24 - Method Inputs and Returns
Lesson 25 - Reference vs. Value Types
Lesson 26 - Introduction to Polymorphism
Lesson 27 - Navigating the Unity API
Lesson 28 - Applying What You've Learned and Refactoring
Lesson 29 - Constructors, Local Variables in the Update Method
Lesson 30 - Collecting Collectibles, Items and Powerups
Lesson 31 - Spawning and Managing Prefab Powerups
Lesson 32 - Implementing Powerup State Logic
Lesson 33 - Displaying Text, OnGUI, Method Overloading
Lesson 34 - Referencing Instantiated GameObjects, Parenting
Lesson 35 - Understanding the Lerp Method
Lesson 36 - Creating Pseudo Animations in Code
Lesson 37 - Understanding Generic Classes and Methods
Lesson 38 - Animations Using SpriteSheets and Animator
Lesson 39 - Working with Arrays and Loops
Lesson 40 - Debugging Unity Projects with Visual Studio
Lesson 41 - Camera Movement and LateUpdate
Lesson 42 - Playing Audio Clips
Lesson 43 - Routing Audio, Mixers and Effects
Lesson 44 - Adding Scoring Mechanics and Enhancements
Lesson 45 - Scene Loading and Game Over Manager
Lesson 46 - Understanding Properties
Lesson 47 - Controller Mapping and Input Manager
Lesson 48 - Understanding Enums
Lesson 49 - Dealing with Null References
Lesson 50 - Handling Variable Framerates with time.DeltaTime
Lesson 51 - Preparing the Project for Final Build
Lesson 52 - Final Build and Project Settings
Lesson 53 - Introduction to the Unity Physics Engine
Lesson 54 - Understanding FixedUpdate vs. Update
Lesson 55 - Movement Using Physics
Lesson 56 - Attack Script and Collision Events with OnCollisionEnter2D
Lesson 57 - Projectiles and Stomping Attack
Lesson 58 - Parallax Background and Scrolling Camera
Lesson 59 - Infinitely Tiling Background Sprites
Lesson 61 - OOP Enemy Classes Continued
Lesson 62 - Trigger Colliders and Causing Damage
Lesson 63 - Multi-Dimensional Arrays and Procedural Platforms