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 61 - OOP Enemy Classes Continued