[Auto-Guiding Rockets] -- Beta 1

Discussions about Coding and Scripting
Terraniux
Masterful
Posts: 717
Joined: Mon Jan 05, 2009 8:08 pm
Personal rank: Banished member

Re: Auto-Guiding Rockets -- [WIP]

Post by Terraniux »

any update on this?
This member can only post when permitted.
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: Auto-Guiding Rockets -- [WIP]

Post by sektor2111 »

Is in the same stage as Air Smashing mutator, Tag Games, weapon Jump Node, etc. more exactly a work in progress...
User avatar
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]

Post by Gustavo6046 »

Nope, this is actually a finished project. The auto-rocket is good enough. I forgot to post the last verion 'w'

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);
			}
		}
	}
}
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: 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
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: Auto-Guiding Rockets -- [WIP]

Post by Barbie »

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);
}
Without understanding of complete intention of code I guess that self.Instigator would be a better choice than self.Owner.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: [Auto-Guiding Rockets] -- Beta 1

Post by sektor2111 »

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.
User avatar
Barbie
Godlike
Posts: 2792
Joined: Fri Sep 25, 2015 9:01 pm
Location: moved without proper hashing

Re: [Auto-Guiding Rockets] -- Beta 1

Post by Barbie »

sektor2111 wrote:preventing Instigator
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.
"Multiple exclamation marks," he went on, shaking his head, "are a sure sign of a diseased mind." --Terry Pratchett
User avatar
sektor2111
Godlike
Posts: 6403
Joined: Sun May 09, 2010 6:15 pm
Location: On the roof.

Re: [Auto-Guiding Rockets] -- Beta 1

Post by sektor2111 »

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.
Post Reply