[Auto-Guiding Rockets] -- Beta 1
- sektor2111
- Godlike
- Posts: 6423
- Joined: Sun May 09, 2010 6:15 pm
- Location: On the roof.
Re: Auto-Guiding Rockets -- [WIP]
Is in the same stage as Air Smashing mutator, Tag Games, weapon Jump Node, etc. more exactly a work in progress...
- Gustavo6046
- Godlike
- Posts: 1462
- Joined: Mon Jun 01, 2015 7:08 pm
- Personal rank: Resident Wallaby
- Location: Porto Alegre, Brazil
- Contact:
Re: Auto-Guiding Rockets -- [WIP]
Nope, this is actually a finished project. The auto-rocket is good enough. I forgot to post the last verion 'w'
Code:
Fixing topic name.
EDIT: After another topic skim, maybe it's time to release a definitive last release, without dodging walls whenever target is there (as Nelsona said -- I probably didn't understand at the time lol), and adding small spacious normal calculation.
EDIT 2: My flawed try:
Code:
Code: Select all
//=============================================================================
// AutoRocket.
//=============================================================================
class AutoRocket expands UT_SeekingRocket;
var() float SeekAcceleration, SeekSpeed, TargetAcquiringRadius, WallAvoidSpeed, WallPredictionFactor, WallAvoidSlowdown, ShootDensity, ShootDistance, ShootDistanceFactor, MinHomePathDistance, MinWallAvoidNormal, TargetFindDensity, MaxPathDistance, FlockRadius, RotateRate, MinSeekAccel;
var() bool bShootAtTarget, bIgnoreIgnorers, bFlock, bLayBreadcrumbs;
var() class<Actor> ProjectileClass;
var Pawn User;
var Actor HomeTarget;
var BreadcrumbPath NavigationPath, TempCrumb;
var bool bFoundUser;
var WingedCrumb B, MyCrumb, TargetWC, TargetW;
var int Slew;
var enum GusNavType
{
NAV_None,
NAV_Default,
NAV_Crumbs
}
Navigation;
replication
{
reliable if ( Role == ROLE_Authority )
User,
bFoundUser;
}
simulated function float MinHomeNormal()
{
if ( Seeking != None && !Seeking.IsInState('Dying') )
return 0.5 * MinWallAvoidNormal;
else
return 0.1 * MinWallAvoidNormal;
}
simulated event bool PercentChance(float Percentage)
{
return FRand() * 100 < Percentage;
}
simulated event Vector EstimateLocation(Actor Other)
{
if ( Other == None )
return Location;
return Other.Location + (Other.Velocity / VSize(Velocity)) * 0.5;
}
simulated event HomeAt(Actor Other, optional bool bRotateOnly)
{
local Vector Est;
Est = EstimateLocation(Other);
if ( bRotateOnly )
{
Velocity += Vector(Rotation) + (Est - Location) * RotateRate;
}
else
{
Acceleration += ((Est - Location) * SeekSpeed);
Velocity *= (SeekAcceleration / (Velocity dot (Est - Location))) + MinSeekAccel;
}
}
simulated event Actor WillHitWall(optional out Vector Location, optional out Vector OutNormal)
{
return Trace(Location, OutNormal, Self.Location + Velocity * WallPredictionFactor);
}
simulated event bool MonsterFriendly(ScriptedPawn Other)
{
return Other != None && Other.AttitudeTo(User) == ATTITUDE_Friendly;
}
simulated event bool CheckSeekable(Pawn Other, Pawn FireAgent)
{
return (
Other != None
&&
(
FireAgent == None
^^
(
FastTrace(Other.Location)
&& Other != FireAgent
&& !Other.IsInState('Dying')
&&
(
!MonsterFriendly(ScriptedPawn(Other))
||
(
!Level.Game.bTeamGame
|| Other.PlayerReplicationInfo == None
|| FireAgent.PlayerReplicationInfo == None
|| Other.PlayerReplicationInfo.Team != FireAgent.PlayerReplicationInfo.Team
)
)
)
)
);
}
function BeginPlay()
{
if ( Owner == None )
return;
if ( Pawn(Owner) != None )
User = Pawn(Owner);
else
User = Pawn(Owner.Owner);
}
simulated function SetTarget(Pawn Other)
{
Seeking = Other;
}
simulated function WingedCrumb PathLocation()
{
if ( !bLayBreadcrumbs )
return None;
foreach RadiusActors(class'WingedCrumb', B, MaxPathDistance)
if ( FastTrace(Location, B.Location) )
return B;
return Spawn(class'WingedCrumb', self);
}
simulated function FindNavigationTarget()
{
while ( True )
{
if ( NavigationPath != None )
while ( VSize(Location - NavigationPath.Owner.Location) < 300 )
{
if ( WingedCrumb(NavigationPath.Next.Destination) == None )
break;
MyCrumb = WingedCrumb(NavigationPath.Next.Destination);
TempCrumb = NavigationPath;
NavigationPath = NavigationPath.Next;
TempCrumb.Destroy();
}
foreach RadiusActors(class'WingedCrumb', TargetWC, 768, Target.Location)
{
if ( TargetW == None || VSize(TargetWC.Location - TargetW.Location) < 256 )
TargetW = TargetWC;
}
if ( TargetW == None )
break;
NavigationPath = MyCrumb.FindPathToBreadcrumb(TargetW);
HomeTarget = NavigationPath.Next;
break;
}
}
simulated event Timer()
{
local Pawn P, Target;
local ut_spriteSmokePuff B;
local Actor A;
local AutoRocket AR;
local Vector WallNorm, WallLoc;
SetRotation(Rotator(Velocity));
A = WillHitWall(WallLoc, WallNorm);
if ( A != None && ( LevelInfo(A) != None || !CheckSeekable(Pawn(A), User) ) && ((VSize(WallLoc - Location) / VSize(Velocity * 0.1)) / 256) * MinHomeNormal() > (WallNorm dot Velocity) )
{
Velocity /= WallAvoidSlowdown;
Acceleration -= WallAvoidSpeed * 2 * (WallNorm dot Velocity) * WallNorm;
}
else if ( bFlock && Seeking == None )
{
foreach RadiusActors(class'AutoRocket', AR, FlockRadius)
{
HomeAt(AR, true);
}
}
if ( User != None )
bFoundUser = True;
MyCrumb = PathLocation();
if ( Seeking != None && !Seeking.IsInState('Dying') && CheckSeekable(Pawn(Seeking), User) )
{
HomeTarget = None;
if ( Navigation == NAV_Crumbs && ( FastTrace(Seeking.Location) && ( HomeTarget == None || !FastTrace(HomeTarget.Location) ) ) || ( HomeTarget != None && VSize(HomeTarget.Location - Location) < MinHomePathDistance && HomeTarget != Seeking ) )
FindNavigationTarget();
else if ( Navigation == NAV_Default && MyCrumb != None && ( !FastTrace(Seeking.Location) && ( HomeTarget == None || !FastTrace(HomeTarget.Location) ) ) || ( HomeTarget != None && VSize(HomeTarget.Location - Location) < MinHomePathDistance && HomeTarget != Seeking ) )
{
HomeTarget = Spawn(class'NavigationHelper');
NavigationHelper(HomeTarget).LoadPathToward(Seeking);
HomeTarget = NavigationHelper(HomeTarget).Helped(true);
}
else if ( FastTrace(Seeking.Location) )
HomeTarget = Seeking;
if ( HomeTarget != None )
{
HomeAt(HomeTarget);
if ( bShootAtTarget && PercentChance(ShootDensity) && ProjectileClass != None )
Spawn(ProjectileClass, Owner, '', Location + Vector(Rotation) * (CollisionRadius + ShootDistance + ProjectileClass.default.CollisionRadius) * ShootDistanceFactor);
}
}
else if ( PercentChance(TargetFindDensity) )
{
HomeTarget = None;
foreach RadiusActors(class'Pawn', P, TargetAcquiringRadius)
{
if ( Target == None || VSize(P.Location - Location) < VSize(Target.Location - Location) )
{
Target = P;
if ( CheckSeekable(Target, User) )
SetTarget(Target);
}
}
}
}
EDIT: After another topic skim, maybe it's time to release a definitive last release, without dodging walls whenever target is there (as Nelsona said -- I probably didn't understand at the time lol), and adding small spacious normal calculation.
EDIT 2: My flawed try:
Code: Select all
//=============================================================================
// AutoRocket.
//=============================================================================
class AutoRocket expands UT_SeekingRocket;
var() float SeekAcceleration, SeekSpeed, TargetAcquiringRadius, WallAvoidSpeed, WallPredictionFactor, WallAvoidSlowdown, ShootDensity, ShootDistance, ShootDistanceFactor, MinHomePathDistance, MinWallAvoidNormal, TargetFindDensity, MaxPathDistance, FlockRadius, RotateRate, MinSeekAccel, SpaceFollowRadius;
var() bool bShootAtTarget, bIgnoreIgnorers, bFlock, bLayBreadcrumbs;
var() class<Actor> ProjectileClass;
var Pawn User;
var Actor HomeTarget;
var BreadcrumbPath NavigationPath, TempCrumb;
var bool bFoundUser;
var WingedCrumb B, MyCrumb, TargetWC, TargetW;
var int Slew;
var enum GusNavType
{
NAV_None,
NAV_Default,
NAV_Crumbs
}
Navigation;
replication
{
reliable if ( Role == ROLE_Authority )
User,
bFoundUser;
}
simulated function float DistanceTo(Vector Other)
{
return VSize(Other - Location);
}
simulated function Vector SpaceNormal()
{
local float x, y, z;
local Vector v, cv, norm;
for ( x = -1; x <= 1; x += 0.5 )
for ( y = -1; y <= 1; y += 0.5 )
for ( z = -1; z <= 1; z += 0.5 )
{
v.x = x;
v.y = y;
v.z = z;
Trace(v, norm, v * SpaceFollowRadius);
cv += v;
}
cv = Normal(cv);
Log("Traced"@cv@as spaciest normal!);
return cv;
}
simulated function float MinHomeNormal()
{
return 0.1 * MinWallAvoidNormal;
}
simulated event bool PercentChance(float Percentage)
{
return FRand() * 100 < Percentage;
}
simulated event Vector EstimateLocation(Actor Other)
{
if ( Other == None )
return Location;
return Other.Location + (Other.Velocity / VSize(Velocity)) * 0.5;
}
simulated event HomeAt(Actor Other, optional bool bRotateOnly)
{
local Vector Est;
Est = EstimateLocation(Other);
if ( bRotateOnly )
{
Velocity += Vector(Rotation) + (Est - Location) * RotateRate;
}
else
{
Acceleration += ((Est - Location) * SeekSpeed);
Velocity *= (SeekAcceleration / (Velocity dot (Est - Location))) + MinSeekAccel;
}
}
simulated event HomeToward(Vector HomeNormal, float Intensity, float Speeding)
{
Velocity += Vector(Rotation) + Normal(HomeNormal) * RotateRate * Intensity;
Acceleration += Normal(HomeNormal) * Speeding;
}
simulated event Actor WillHitWall(optional out Vector Location, optional out Vector OutNormal)
{
if ( Seeking != None && FastTrace(Seeking.Location) )
return none;
return Trace(Location, OutNormal, Self.Location + Velocity * WallPredictionFactor);
}
simulated event bool MonsterFriendly(ScriptedPawn Other)
{
return Other != None && Other.AttitudeTo(User) == ATTITUDE_Friendly;
}
simulated event bool CheckSeekable(Pawn Other, Pawn FireAgent)
{
return (
Other != None
&&
(
FireAgent == None
^^
(
FastTrace(Other.Location)
&& Other != FireAgent
&& !Other.IsInState('Dying')
&&
(
!MonsterFriendly(ScriptedPawn(Other))
||
(
!Level.Game.bTeamGame
|| Other.PlayerReplicationInfo == None
|| FireAgent.PlayerReplicationInfo == None
|| Other.PlayerReplicationInfo.Team != FireAgent.PlayerReplicationInfo.Team
)
)
)
)
);
}
function BeginPlay()
{
if ( Owner == None )
return;
if ( Pawn(Owner) != None )
User = Pawn(Owner);
else
User = Pawn(Owner.Owner);
}
simulated function SetTarget(Pawn Other)
{
Seeking = Other;
}
simulated function WingedCrumb PathLocation()
{
if ( !bLayBreadcrumbs )
return None;
foreach RadiusActors(class'WingedCrumb', B, MaxPathDistance)
if ( FastTrace(Location, B.Location) )
return B;
return Spawn(class'WingedCrumb', self);
}
simulated function FindNavigationTarget()
{
while ( True )
{
if ( NavigationPath != None )
while ( VSize(Location - NavigationPath.Owner.Location) < 300 )
{
if ( WingedCrumb(NavigationPath.Next.Destination) == None )
break;
MyCrumb = WingedCrumb(NavigationPath.Next.Destination);
TempCrumb = NavigationPath;
NavigationPath = NavigationPath.Next;
TempCrumb.Destroy();
}
foreach RadiusActors(class'WingedCrumb', TargetWC, 768, Target.Location)
{
if ( TargetW == None || VSize(TargetWC.Location - TargetW.Location) < 256 )
TargetW = TargetWC;
}
if ( TargetW == None )
break;
NavigationPath = MyCrumb.FindPathToBreadcrumb(TargetW);
HomeTarget = NavigationPath.Next;
break;
}
}
simulated event Timer()
{
local Pawn P, Target;
local ut_spriteSmokePuff B;
local Actor A;
local AutoRocket AR;
local Vector WallNorm, WallLoc;
HomeToward(SpaceNormal(), 0.5, 0);
SetRotation(Rotator(Velocity));
A = WillHitWall(WallLoc, WallNorm);
if ( A != None && ( LevelInfo(A) != None || !CheckSeekable(Pawn(A), User) ) && ((VSize(WallLoc - Location) / VSize(Velocity * 0.1)) / 256) * MinHomeNormal() > (WallNorm dot Velocity) )
{
Velocity /= WallAvoidSlowdown;
Acceleration -= WallAvoidSpeed * 2 * (WallNorm dot Velocity) * WallNorm;
}
else if ( bFlock && Seeking == None )
{
foreach RadiusActors(class'AutoRocket', AR, FlockRadius)
{
HomeAt(AR, true);
}
}
if ( User != None )
bFoundUser = True;
MyCrumb = PathLocation();
if ( Seeking != None && !Seeking.IsInState('Dying') && CheckSeekable(Pawn(Seeking), User) )
{
HomeTarget = None;
if ( Navigation == NAV_Crumbs && ( FastTrace(Seeking.Location) && ( HomeTarget == None || !FastTrace(HomeTarget.Location) ) ) || ( HomeTarget != None && VSize(HomeTarget.Location - Location) < MinHomePathDistance && HomeTarget != Seeking ) )
FindNavigationTarget();
else if ( Navigation == NAV_Default && MyCrumb != None && ( !FastTrace(Seeking.Location) && ( HomeTarget == None || !FastTrace(HomeTarget.Location) ) ) || ( HomeTarget != None && VSize(HomeTarget.Location - Location) < MinHomePathDistance && HomeTarget != Seeking ) )
{
HomeTarget = Spawn(class'NavigationHelper');
NavigationHelper(HomeTarget).LoadPathToward(Seeking);
HomeTarget = NavigationHelper(HomeTarget).Helped(true);
}
else if ( FastTrace(Seeking.Location) )
HomeTarget = Seeking;
if ( HomeTarget != None )
{
HomeAt(HomeTarget);
if ( bShootAtTarget && PercentChance(ShootDensity) && ProjectileClass != None )
Spawn(ProjectileClass, Owner, '', Location + Vector(Rotation) * (CollisionRadius + ShootDistance + ProjectileClass.default.CollisionRadius) * ShootDistanceFactor);
}
}
else if ( PercentChance(TargetFindDensity) )
{
HomeTarget = None;
foreach RadiusActors(class'Pawn', P, TargetAcquiringRadius)
{
if ( Target == None || VSize(P.Location - Location) < VSize(Target.Location - Location) )
{
Target = P;
if ( CheckSeekable(Target, User) )
SetTarget(Target);
}
}
}
}
"Everyone is an idea man. Everybody thinks they have a revolutionary new game concept that no one else has ever thought of. Having cool ideas will rarely get you anywhere in the games industry. You have to be able to implement your ideas or provide some useful skill. Never join a project whose idea man or leader has no obvious development skills. Never join a project that only has a web designer. You have your own ideas. Focus on them carefully and in small chunks and you will be able to develop cool projects."
— Weapon of Destruction
— Weapon of Destruction
Re: Auto-Guiding Rockets -- [WIP]
Without understanding of complete intention of code I guess that self.Instigator would be a better choice than self.Owner.Gustavo6046 wrote:Code: Select all
class AutoRocket expands UT_SeekingRocket; ... function BeginPlay() { if ( Owner == None ) return; if ( Pawn(Owner) != None ) User = Pawn(Owner); else User = Pawn(Owner.Owner); }
"If Origin not in center it be not in center." --Buggie
- sektor2111
- Godlike
- Posts: 6423
- Joined: Sun May 09, 2010 6:15 pm
- Location: On the roof.
Re: [Auto-Guiding Rockets] -- Beta 1
You should look at PeaceRocket and use that thing as priority but preventing Instigator. If None Pawn is found do roam around.
Your old mod was based on a single concern, rocket avoiding walls and ignoring pawns being busy to track walls and nothing more.
Your old mod was based on a single concern, rocket avoiding walls and ignoring pawns being busy to track walls and nothing more.
Re: [Auto-Guiding Rockets] -- Beta 1
From the context user is used I guess that Gustavo wants to know who has emitted the projectile. AFAIK Projectiles have no owner, but Instigator is inherited automatically on spawning a Projectile.sektor2111 wrote:preventing Instigator
"If Origin not in center it be not in center." --Buggie
- sektor2111
- Godlike
- Posts: 6423
- Joined: Sun May 09, 2010 6:15 pm
- Location: On the roof.
Re: [Auto-Guiding Rockets] -- Beta 1
If he will quit blabbering with brain ideas about being programmer, and just using simple way, coding like a low level coder (it's not a shame - it's learning), probably will Never Fail. What is about ? USING STUPID LOW LEVEL LOGS, when you are using log("Owner ="@Owner) and log("Instigator ="@Instigator) might be helpful in figuring if that section is being ever executed and what content runs there. Else I see some "scientific" functions which I think have useless content just because they weren't checked if have been ever called. EPIC used LOGS - even forgetting to remove some of them. Logs are not painful, they do help a lot in clarifications about certain stuff if it's running or not - else the guess work is not the right way. There are a lot of simulated functions which I don't think are necessary like that. Client needs to know where is going rocket and not processing values from it. It needs information about spawning, direction changed, speed, and exploding. By checking a default good projectile eg. UT_SeekingRocket you'll see that not everything has to be a "simulated function". Again, LOGS are real tutorials if are not ignored.
I used Logs in 90% of things which I wrote and that's why they do work, because I've CHECKED them. To not forget for such a toy, if rocket has a job started function should not continue other dumb executions. If you have a target, go get it and forget stupid walls around.
I used Logs in 90% of things which I wrote and that's why they do work, because I've CHECKED them. To not forget for such a toy, if rocket has a job started function should not continue other dumb executions. If you have a target, go get it and forget stupid walls around.