View Full Version : Make enemy move when not on screen
MikeBriganti
06-29-2012, 02:46 PM
Hello, I need to make a script for enemy AI that only has the enemy move when they are behind the player, and not on the screen at all. Basically if the player can see them at all they should remain frozen in place. I'm not really sure where to even start with this, so any code examples or links would be greatly appreciated.
Thanks!
MagnumAI
06-29-2012, 04:23 PM
To be honest not many people will understand what you are asking. I believe what you are looking for is how to AI movement while the player is not there. This is actually accomplished by the engine and depending on your game type. The players will still move and follow the player, but since they are not in the camera's view they simply just not rendered until they move into the cameras viewing area. Trying to code the players to appear at once when the player turns around can result in a jerking affect as the AI player is "popped" into place. Depending on your game are you wanting them to literally be "frozen" like status or pause and play an animation like looking around, or like one game have the AI bots actually take a bathroom break:)
Having said that it sounds like you need to read up (use the search) on basic AI in general, then look at the UDK tutorials that around that provide code examples of how to move the AI. I have a feeling the game engine will already handle the situation in its basic rendering code for what you are looking for.
MikeBriganti
06-29-2012, 04:50 PM
I believe there is a bit of misunderstanding here. Using some tutorials, I have an enemy that simply moves towards the player. I just need the enemy to stop moving once the player looks at them. (Basically when they appear on the screen at all since the game has a first person camera). I'm basically lost on how I would accomplish something like that.
LordOfOats
06-29-2012, 11:18 PM
Something like this could work in your bot's Controller class:
// Called when the bot sees the player
event SeePlayer(Pawn SeenPlayer)
{
// Freeze the bot
Pawn.CustomTimeDilation = 0.0f;
// Set a timer to resume the bot
SetTimer(1.0f, false 'ResumeBot');
}
function ResumeBot()
{
// Resume the bot
Pawn.CustomTimeDilation = 1.0f;
}
Written off the top of my head so it may not work but give it a shot.
staticvoidlol
06-30-2012, 10:14 AM
Please correct me if I'm wrong, but as I understand it, you're looking for a way to check whether the enemy is in the player's field of view, and if not, you allow the enemy to run around, otherwise it is frozen in place.
You can accomplish this with a bit of vector math. You can create a function on your enemy that polls the player pawn at regular intervals.
You then need to retrieve the player's location and viewdireciton. <Insert some vector math including the camera FOV> and you can figure out whether the enemy is in the player's FOV.
Have a look here: http://wiki.beyondunreal.com/Legacy:UnrealScript_Vector_Maths
MikeBriganti
06-30-2012, 02:16 PM
Thanks for the code LordOfOats. I haven't been able to try out the code yet, but I'll look through some scripts and see how those functions work.
Staticvoid, that's exactly what I'm trying to do. I'm a pretty bad programmer but I'll try go through that documentation and see if I can get something working. Thanks again.
Acecutter69
06-30-2012, 09:30 PM
Local array<botclass> bots, visbots;
Local botclass bot;
Foreach worldinfo.allactors (class'botclass', bot)
{
Bots.add(bot);
}
Foreach visibleactors(class'botclass', bot)
{
Visbits.add(bot);
}
For(i=0; i<bots.lenght; i++)
{
If(visbots.find(bots[i]) )
Bots[i].gotostate'frozen';
Else
Bots[i].gotostate'moving';
}
Basically use 2 iterators, one to get all the bots and the other to get the visible ones. Then iterate through the bots and if they visible stop moving, if not then dont move. Check out documentation on iterators
Or you could have a variable in the bots that you change, rick it to have your player do that intead of the enemy because
The enemy may nit see you even when ur not looking at them.
Im assuming u wanna make weaping angels :D
Acecutter69
06-30-2012, 09:42 PM
something like:
8716
Angel_Mapper
06-30-2012, 10:02 PM
Use LineOfSightTo and a dot product like so (this is from the AIController code's point of view assuming it has a reference to the PlayerController):
if(PlayerController.LineOfSightTo(Pawn) && normal(Pawn.Location - PlayerController.Pawn.Location) dot normal(vector(Pawn.Rotation)) > 0.7)
// Code to stop movement here.
else
// Code to resume movement here.
The 0.7 might need adjustment, 1.0 = straight ahead, 0.0 = directly left or right, 0.7 is about a 45 degree angle.
Solid Snake
06-30-2012, 11:43 PM
A much simpler method in my opinion, is this:
function Tick(float DeltaTime)
{
Super.Tick();
if (WorldInfo.TimeSeconds - LastRenderTime > 0.1f)
{
GotoState('Frozen');
}
else
{
GotoState('Thawing');
}
}
LastRenderTime is set to a value whenever the engine renders any pixels belonging to the Actor. Thus if the time difference between the current WorldInfo.TimeSeconds and the Actor's LastRenderTime is greater than 0.1f, then the player hasn't seen the actor for at least 0.1 seconds. Nice simply comparison, no need to run any line checks etc.
MikeBriganti
07-01-2012, 10:52 AM
Thank you everyone! All your responses were very good and it's great as someone trying to learn to program to see all these different ways of doing a similar task. It really is a great way to learn. I'm going to try and get this working using your examples now and I'll post back later if I run into any issues.
MikeBriganti
07-01-2012, 01:10 PM
Solid Snake, I am attempting to use your code at the moment, and it is not working. Basically the enemy is always in the "Seeking" state even if they aren't on the screen (So they shouldn't be rendered, right?). I'm probably doing something wrong, so here is my code:
class Myosis_BasicAuger extends Myosis_Actor
placeable;
var Pawn Enemy;
var float FollowDistance;
var float AttackDistance;
var float MovementSpeed;
auto state Seeking
{
function Tick(float DeltaTime)
{
local vector NewLocation;
`log("I am seeking");
if(Enemy == none)
GetEnemy();
if(Enemy != none)
{
NewLocation = Location;
NewLocation += normal(Enemy.Location - Location) * MovementSpeed * DeltaTime;
SetLocation(NewLocation);
if(VSize(NewLocation - Enemy.Location) < AttackDistance)
GoToState('Attacking');
}
}
}
state Attacking
{
function Tick(float DeltaTime)
{
`log("I am attacking");
if(Enemy == none)
GetEnemy();
if(Enemy != none)
{
Enemy.Bump(self, CollisionComponent, vect(0,0,0));
if(VSize(Location - Enemy.Location) > AttackDistance)
GoToState('Seeking');
}
}
}
state Frozen
{
function Tick(float DeltaTime)
{
`log("I am frozen");
}
}
function GetEnemy()
{
local Myosis_PlayerController PC;
foreach LocalPlayerControllers(class'Myosis_PlayerControll er', PC)
{
if(PC.Pawn != none)
Enemy = PC.Pawn;
}
}
function Freeze()
{
GoToState('Frozen');
}
function Tick(float DeltaTime)
{
Super.Tick(DeltaTime);
if (WorldInfo.TimeSeconds - LastRenderTime > 0.1f)
{
GotoState('Frozen');
`log("I should be frozen");
}
else
{
GotoState('Seeking');
`log("I should be seeking");
}
}
defaultproperties
{
FollowDistance=512.0
AttackDistance=96.0
MovementSpeed=256.0
bBlockActors=True
bCollideActors=True
Begin Object Class=DynamicLightEnvironmentComponent Name=MyLightEnvironment
bEnabled=True
End Object
Components.Add(MyLightEnvironment)
Begin Object Class=StaticMeshComponent Name=PickupMesh
StaticMesh=StaticMesh'UN_SimpleMeshes.TexPropCube_ Dup'
Materials(0)=Material'EditorMaterials.WidgetMateri al_X'
LightEnvironment=MyLightEnvironment
Scale3D=(X=0.25,Y=0.25,Z=0.5)
End Object
Components.Add(PickupMesh)
Begin Object Class=CylinderComponent Name=CollisionCylinder
CollisionRadius=32.0
CollisionHeight=64.0
BlockNonZeroExtent=true
BlockZeroExtent=true
BlockActors=true
End Object
CollisionComponent=CollisionCylinder
Components.Add(CollisionCylinder)
}
MikeBriganti
07-04-2012, 08:14 PM
Bumping. Still need help.
Spoof
07-05-2012, 03:40 AM
Your global tick function never gets called.
Functions defined in states override global functions defined in the class (no state). Each of your states provides it's own Tick() function, so they prevent your visibility code from being called.
You can either convert your global tick into a utility function to ChangeStateBasedOnVisibility(), and call it directly from the ticks in each state (preferred option). Or you can call the global tick using the global keyword: global.Tick(DeltaTime);
Edit:
You should really be moving your actors using Move(deltaPosition) rather than SetLocation(position)
Angel_Mapper
07-05-2012, 08:21 AM
Hey I recognize that code, glad my book's helping! :D Spoof's right about your global Tick not being called.
MikeBriganti
07-05-2012, 04:55 PM
Thanks spoof! I'll make the necessary changes when I get home. And Angel_Mapper, your book was amazing. I just wish I took your advice and read through the source code myself a bit more when learning because there are lots of functions I don't really know about.
Powered by vBulletin® Version 4.2.0 Copyright © 2013 vBulletin Solutions, Inc. All rights reserved.