Home Unreal Engine

Magnetism in UDK

Hi guys
Im using a sample script by Ryan Medeiros his site can be found here
I modified it and it compiled fine. Now my question is how do i use this
script to influence objects?
My level has two cylinders and i need the to attract and repel based on the
script. However i do not know how to attach the script to the objects. Any
pointers would be great. Thanks

here is the source
/**
 * MagneticComponent
 * 
 * This component provides the mechanism to have magnetism physics 
 * within unreal.  It can be attached to any actor and then configured 
 * to have the desired magnetic properties.
 * 
 * Used currently with Pawns, KActors, InterpActors and Projectiles.
 * Magnetic "Fields" (directional rather than radial effect) are
 * handled seperately.
 * 
 * The force uses a linear model (rather than a more "real" quadratic
 * model), because we found linear to feel better than quadratic fall-
 * off.
 * 
 * Major properties are: 
 *      magnetState - red, blue or neutral
 *      radius      - max distance this magnet affects others
 *      power       - how "strong" the magnet is
 */
class PFG_MagneticComponent extends ActorComponent
    hidecategories(Object);


enum EMagnetType
{
    MT_Player,
    MT_Static,  // InterpActors or placed magnets
    MT_Movable, // Standard KActor Magnet
    MT_Magba,   // Enemy type
    MT_Projectile
};
enum EMagnetState
{
    MS_Neutral,
    MS_Red,
    MS_Blue
};

var(Magnet) EMagnetState magnetState;
var(Magnet) interp float radius;
var(Magnet) interp float power;
var(Magnet) interp float damping <UIMin=0.0 | UIMax=1.0>;

var(Affects)    bool  bMovables;
var(Affects)    bool  bMagbas;
var(Affects)    bool  bPlayer;
var(Affects)    bool  bProjectiles;

var(AffectedBy) bool  bByPlayer;
var(AffectedBy) bool  bByStatics;
var(AffectedBy) bool  bByFields;
var(AffectedBy) bool  bByMovables;
var(AffectedBy) bool  bByMagbas;
var(AffectedBy) bool  bByProjectiles;

var float deltaSpeed;

var const float maxViscousDamping;
var bool        hasViscDampingApplied;
var bool        bAffectsOthersOnly;
var bool        bEnabled;
var bool        bAffectPlayer;
var EMagnetType mType;


/** 
 *  This function should be called within Tick of 
 *  every magnet which affects the physics of others
 *  @param dt DeltaTime from calling function
 */
simulated function AffectOthers(float dt)
{
    local Actor    other;
    local GamePawn otherPawn;
    local KActor   otherMagnet;
    local UDKProjectile otherProjectile;
    local Vector   direction, velProj;
    local float    magnitude, dist, viscDamp, normDist;
    local PFG_MagneticComponent otherComponent, tmp;

    if(!bEnabled || MagnetState==MS_Neutral || Owner == none || (Pawn(Owner) != none && Pawn(Owner).Health <= 0) )
        return;

    foreach Owner.CollidingActors( class'Actor', other, Radius)
    {        
        // Three classes of objects can be magnets.  And for some reason Unreal gives the Owner back as well.
        if( Owner != other && (GamePawn(other) != none || KActor(other) != none || UDKProjectile(other) != none) )
        {
            otherComponent = none;
            foreach other.ComponentList( class'PFG_MagneticComponent', tmp )
                otherComponent = tmp; 

            otherPawn = GamePawn(other);
            otherMagnet = KActor(other);
            otherProjectile = UDKProjectile(other);

            /** 
             *  This is basically a big matrix that allows Level Designers to choose
             *  what each magnet affects and disable other magnets affecting it.  I'm
             *  a little disappointed by how ugly/large of an if block it is, but 
             *  offers our designers explicit control.
             */
            if(  ( otherComponent == none || otherComponent.MagnetState == MS_Neutral ) || 
                 ( otherComponent.bAffectsOthersOnly ) ||
                 ( !otherComponent.bEnabled ) ||
                 ( otherComponent.mType == MT_Player     && !bPlayer ) ||
                 ( otherComponent.mType == MT_Magba      && !bMagbas ) ||
                 ( otherComponent.mType == MT_Movable    && !bMovables) ||
                 ( otherComponent.mType == MT_Projectile && !bProjectiles ) ||
                 ( mType == MT_Player  && !otherComponent.bByPlayer ) ||
                 ( mType == MT_Static  && !otherComponent.bByStatics ) ||
                 ( mType == MT_Movable && !otherComponent.bByMovables ) ||
                 ( mType == MT_Magba   && !otherComponent.bByMagbas ) ||
                 ( mType == MT_Projectile && !otherComponent.bByProjectiles )   )
                continue;


            dist = VSize(other.Location - Owner.Location);

            if(dist < 1.6f)
            {
                // Too close together, simply attach.  For U shaped magnets.
                // Co-op direction and velProj to prevent extra variables.
                direction = (Owner.Location - other.Location)*0.5f + other.Location;
                velProj = (other.Velocity + Owner.Velocity)*0.5f;

                otherComponent.hasViscDampingApplied = true;
                other.SetLocation( direction );
                Owner.SetLocation( direction );
                other.Velocity = velProj;
                Owner.Velocity = velProj;
                continue;
            }
                
            magnitude = (power * otherComponent.power) / dist;

            /**
             *    Viscous damping
             *  Use viscous damping in order to prevent physics craziness when
             *  two magnets are consistently colliding between frames.  Without
             *  this system, magnets tend to become unstable when attracted and
             *  next to each other.
             */
            if( otherProjectile == none && (dist < 80 || otherComponent.hasViscDampingApplied) )
            {
                // Quadratic falloff
                viscDamp = maxViscousDamping * ( 1 - (dist*dist/6400) );

                // Pawns and KActors must be handled seperately, as below.
                if( otherPawn != none && !otherComponent.hasViscDampingApplied)
                    otherPawn.AddVelocity( -viscDamp*otherPawn.Velocity, otherPawn.Location, None );
                else if( otherMagnet != none && !otherComponent.hasViscDampingApplied)
                    otherMagnet.ApplyImpulse(otherMagnet.Velocity, 
                        -viscDamp * VSize(otherMagnet.Velocity), otherMagnet.Location );

                // Scale magnitude by the amount of viscous damping applied
                magnitude *= 1-viscDamp-(0.1);
                otherComponent.hasViscDampingApplied = true;
            }

            if(otherComponent.MagnetState != MagnetState)
                direction = (Owner.Location - other.Location); // Pull
            else
                direction = (other.Location - Owner.Location); // Push
            
            if( dist < 100 )
            {
                // A quick-fix to prevent flying characters.
                direction.Z = 0;
                normDist = VSize(direction);
                magnitude *= normDist/dist;
                if(normDist != 0)
                    direction /= normDist;
            }
            else
                direction = Normal(direction);

            /**
             *  Note:
             *  The 30 and 50 are used as scaling factors below.  Pawns react
             *  differently through AddVelocity() than KActors do through
             *  ApplyImpluse().  These are left high (ie not 3 & 5) so that
             *  level designers can work with smaller numbers and to balance
             *  with projectiles.
             */
            if( otherPawn != none )
            {
                otherPawn.SetPhysics(PHYS_Falling); // Allows upward physics
                otherPawn.AddVelocity( direction*(magnitude*dt*30), otherPawn.Location, None );
            }
            else if( otherMagnet != none )
            {
                otherMagnet.ApplyImpulse( direction, magnitude*dt*50, otherMagnet.Location );
            }
            /*else if ( otherProjectile != none )
            //{
            //   if (otherProjectile.Owner != none && !ML_ENMY_MagRay(otherProjectile.Owner).bAimsInZ) direction.Z = 0;
            //  otherProjectile.Velocity += direction * magnitude * dt * otherProjectile.Speed * deltaSpeed;
                }
                */

            /**
             *    Regular damping
             *  Applied along the line of effect between
             *  two magnets.
             */
            if( dist >= 60 )
            {
                velProj = ProjectOnTo( other.Velocity , direction);
                velProj *= -damping;
                magnitude = VSize(velProj);
                if( magnitude != 0 )
                {
                    if( otherPawn != none )
                        otherPawn.AddVelocity( -direction*magnitude*dt, otherPawn.Location, None );
                    else if( otherMagnet != none)
                        otherMagnet.ApplyImpulse( velProj, magnitude*dt, otherMagnet.Location);
                }
            }
        }
    }

}

function bool IsOpposite(EMagnetState Other)
{
    return (Other == MS_Blue && MagnetState == MS_Red) || (Other == MS_Red && MagnetState == MS_Blue);
}


DefaultProperties
{
    TickGroup=TG_PreAsyncWork

    damping = 0.04
    magnetState=MS_Neutral
    bAffectsOthersOnly=false
    bEnabled=true
    Radius=512.0
    power=50.0

    deltaSpeed=0.15f

    maxViscousDamping = 0.8
    hasViscDampingApplied = false

    bMovables = true
    bMagbas = true
    bPlayer = true
    bProjectiles = true

    bByPlayer = true
    bByStatics = true
    bByFields = true
    bByMovables = true
    bByMagbas = true
    bByProjectiles = true
}

Sign In or Register to comment.