Results 1 to 8 of 8
  1. #1
    MSgt. Shooter Person
    Join Date
    Dec 2009
    Posts
    149

    Default (RESOLVED) How To Spawn Carried Objects

    Thanks for your time.

    Previously I tried to handle placeable carried objects. This method failed for me, though it probably can be done seeing as how flags drop in place. Regardless, that's just a history.

    What I want to do is create a completely-from-scratch actor spawner for a carryable "bomb" class. This is what I have:

    Code:
    class UTBombSite extends UTGameObjective
    placeable;
    
    var UTBomb myBomb;
    var class<UTBomb> BombType;
    
    simulated event postBeginPlay() // simulated because the compiler told me to
    {
    	myBomb = Spawn(BombType, self);
    }
    
    defaultproperties
    {
    }
    This code does nothing. Can anyone help me?
    Last edited by AwesomeHighFive; 01-09-2010 at 03:13 AM.

  2. #2

    Default

    What I want to do is create a completely-from-scratch actor spawner for a carryable "bomb" class.
    This is a good idea. You will learn much more this way.

    As for your problem, logging will help you track this down...

    Code:
    simulated event postBeginPlay() // simulated because the compiler told me to
    {
            LogInternal("hi!");
    	myBomb = Spawn(BombType, self);
            LogInternal("bombspawn:"@myBomb@myBomb.location
    }
    If you don't see "hi!", this code isn't being called... if your bomb=None, the spawn is failing, and so on. These types of problems can be impossible to solve w/o a fair bit of logging and seeing what isn't as you expect it.

    As for why your code is not working, it appears your BombType is set to none since you never set it in DefaultProperties. That means you're trying to spawn an object of type 'none'. This, of course, fails.

    Code:
    defaultproperties
    {
        BombType=class'UTBomb'
    }
    Last edited by clb; 01-06-2010 at 04:52 PM.

  3. #3
    MSgt. Shooter Person
    Join Date
    Dec 2009
    Posts
    149

    Default

    Ok cool! It works partially (the object spawns after I set its homebase). The problem that remains is that this isn't much of a spawner if it can't respawn the object, and I'm not sure how to do this. I tried using Touch() and Tick() and in both cases I don't know how to get the object to test for being attached to the base without destroying it (which I can't do because it's on the player's back at the time).

    Code:
    class UTBombSite extends UTGameObjective
    placeable;
    
    var UTBomb myBomb;
    var class<UTBomb> BombType;
    
    simulated event postBeginPlay() // simulated because the compiler told me to
    {
    	`log("this is a test");
    	myBomb = Spawn(BombType, self);
    	myBomb.HomeBase = self; // or it spawns at static location (world origin?)
    }
    
    event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
    {
    	`log("touched");
    	if ( myBomb.HomeBase == None ) // always fails, doing myBomb == None also always fails
    	{
    		`log("no bomb exists, respawning it"); // never happens
    		myBomb = Spawn( BombType, self);
    		myBomb.HomeBase = self;
    	}
    }
    	
    
    defaultproperties
    {
    	BombType=class'UTBomb'
    
    	bCollideActors=true // or no touch
    
    	// handle collision hull
    	Begin Object Name=CollisionCylinder
    		CollideActors=true
    	End Object
    
    	// draw model
    	Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
    		StaticMesh=StaticMesh'Pickups.jump_pad.S_Pickups_Jump_Pad'
    		CollideActors=false
    		Scale3D=(X=1.0,Y=1.0,Z=1.0)
    		Translation=(X=0.0,Y=0.0,Z=-47.0)
    	End Object
    
     	Components.Add(StaticMeshComponent0)
    }
    I can't really use Touch() to set myBomb to none because the size of the base is larger than the size of the bomb (it would destroy the bomb before it was ever picked up). I don't know how else to do this test.

    I don't mind using Tick() instead of Touch() but I'm not sure how it works.

    Any ideas? Thanks again!

  4. #4

    Default

    First, it sounds like some of your problems are in your bomb class, not in the bombsite class. You should probably show the bomb class too. (I suspect the reason your code is acting strange is because of the bomb code, not the code you've shown).

    Second, we probably need to step back and have you explain what it is you are trying to do at a higher level. Here's my guess... the "bomb-site" is a static place in the world that spawns a single bomb... a player can pick up this bomb and presumably carry it somewhere and blow it up.. and once the player has blown up a bomb, you want the bomb to respawn at the site?

    If this is correct, most of the logic probably belongs in the bomb class, not the bombsite. In fact, your bombsite class is close to being done For example, it probably makes more sense for the player to "pick up" the bomb using the touch event on the bomb itself. The bomb site's only purpose would be to spawn bombs.

    In order to respawn bombs, I would make the bomb itself tell its base to spawn a new bomb -- not have the bomb-base decide. It looks like your bomb's get their "homebase" set and therefore inside your bombs blow-up() code, you should call mybase.spawn_new_bomb().

    Does this make sense? Something like this:

    Code:
    class UTBombSite extends UTGameObjective
    placeable;
    
    var UTBomb myBomb;
    var class<UTBomb> BombType;
    
    simulated event postBeginPlay() // simulated because the compiler told me to
    {
            SpawnBomb();
    }
    
    simulated function SpawnBomb()
    {
    	myBomb = Spawn(BombType, self);
    	myBomb.HomeBase = self; 
    }
    	
    defaultproperties
    {
    	BombType=class'UTBomb'
    
    	// draw model
    	Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
    		StaticMesh=StaticMesh'Pickups.jump_pad.S_Pickups_Jump_Pad'
    		CollideActors=false
    		Scale3D=(X=1.0,Y=1.0,Z=1.0)
    		Translation=(X=0.0,Y=0.0,Z=-47.0)
    	End Object
    
     	Components.Add(StaticMeshComponent0)
    }
    You probably don't need much more code then this to accomplish what you want. The last bit of the puzzle is to have the UTBomb call HomeBase.SpawnBomb() when appropriate (ie, when it blows up).

    I don't mind using Tick() instead of Touch() but I'm not sure how it works.
    If you need to go this route (depends on the exact mechanic you want), timer() is probably more appropriate than tick().
    Last edited by clb; 01-07-2010 at 05:01 PM.

  5. #5
    MSgt. Shooter Person
    Join Date
    Dec 2009
    Posts
    149

    Default

    Quote Originally Posted by clb View Post
    First, it sounds like some of your problems are in your bomb class, not in the bombsite class. You should probably show the bomb class too. (I suspect the reason your code is acting strange is because of the bomb code, not the code you've shown).
    Code:
    class UTBomb extends UTCarriedObject
    placeable;
    
    var PointLightComponent myLight;
    
    event PostBeginPlay()
    {
    	local Color white;
    	white.R = 255;
    	white.G = 255;
    	white.B = 255;
    	white.A = 255;
    
    	myLight = new(self)class'PointLightComponent';
    	AttachComponent(myLight);
    	myLight.SetLightProperties( 1, white );
    }
    
    function SetHolder( Controller C )
    {
    	local Vector v; // float above head for now
    	v = c.Pawn.location;
    	v.x += 0;
    	v.y += 15;
    	v.z += 60;
    
    	super.SetHolder(C);
    	if ( Holder != None )
    	{
    		HomeBase = None; // we cut all ties to where we spawned when someone picks us up
    		SetRelativeLocation(v);
    	}
    }
    
    
    defaultproperties
    {
    	// draw model
    	Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
    		StaticMesh=StaticMesh'Pickups.Health_Medium.Mesh.S_Pickups_Health_Medium'
    	End Object
    
     	Components.Add(StaticMeshComponent0)
    }
    Quote Originally Posted by clb View Post
    Second, we probably need to step back and have you explain what it is you are trying to do at a higher level.
    Ideally: "If a given delay has elapsed or the game is starting, spawn a bomb at this factory. The bomb can be carried by the player." (There is no need to detect when the bomb explodes, any number of bombs can be in play and do not need to be tracked separately.)

    Quote Originally Posted by clb View Post
    In order to respawn bombs, I would make the bomb itself tell its base to spawn a new bomb -- not have the bomb-base decide.
    I don't know if you still think this is the right way after the explanation above, but the only way this would work is to cause the bomb to have a timer() attached and to have the bomb tell the base to respawn at a given interval. It makes more sense to me to have the base track its own respawn rate.

    Thanks once again.

  6. #6

    Default

    Yes, you are absolutely right, my way above won't work with your mechanic. The mechanic you want should be done with timers. There are a couple of ways to do this depending on exactly how you want this to work.

    1. You could have the base have all the spawn logic (and state logic) and somehow visually change when a bomb present (e.g., spawn a particle system when a bomb is pick-up-able) then on the touch() event of the base, you could "give" the actor a bomb (spawn the bomb then, and give it to the pickup actor), and change states (disable particle system). This would be a textbook use of states.

    2. You could spawn bombs that have states... like "home", "carried", "dropped", "exploding" (this is similar to UTCarriedObject).. and have the bomb trigger various events in the base when appropriate.

    I'll give you an example of approach #2 (note i am at work so i'm just writing from the hip w/o testing/compiling):

    Code:
    class UTBombSite extends UTGameObjective
    placeable;
    
    var UTBomb myBomb;
    var class<UTBomb> BombType;
    
    var() float RespawnTime;     // how long from pickup to respawn 
                                           // (can be set in editor)
    
    simulated event postBeginPlay() 
    {
            super.PostBeginPlay();    // you probably want this
            SpawnBomb();
    }
    
    event Timer ()
    {
             SpawnBomb();
    }
    
    function SpawnBomb()
    {
        if (myBomb == None)
        {
    	myBomb = Spawn(BombType, self);
    	myBomb.HomeBase = self; 
         }
    }
    
    // a "fake" event called by the bomb when he is taken
    event BombTaken()
    {
            myBomb = None;
            setTimer(RespawnTime);
    }
    	
    defaultproperties
    {
    	BombType=class'UTBomb'
            RespawnTime=10.0
    
    	// draw model
    	Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
    		StaticMesh=StaticMesh'Pickups.jump_pad.S_Pickups_Jump_Pad'
    		CollideActors=false
    		Scale3D=(X=1.0,Y=1.0,Z=1.0)
    		Translation=(X=0.0,Y=0.0,Z=-47.0)
    	End Object
    
     	Components.Add(StaticMeshComponent0)
    }
    I've made a few changes above (you really don't need simulated (except postbeginplay()) on any of these functions -- if you are doing a multiplayer game, these functions should be server only)...

    Now, inside of setHolder, where appropriate, you will want to do:
    Code:
    if (homebase!=None)
    {
      homebase.BombTaken();
      homebase = None;
    }
    Last edited by clb; 01-08-2010 at 10:31 AM.

  7. #7
    MSgt. Shooter Person
    Join Date
    Dec 2009
    Posts
    149

    Default

    I tried that approach once and it said that HomeBase didn't include a member function BombTaken(), but this time I typecast it and it seems to work. Please look over this final code if you get a chance, as I don't like (or understand fully) typecasting, and I feel it may cause unforseen problems in the future.

    Only weird thing now is the setrelativelocation() info has stopped working for some reason. That's not the biggest deal in the world right now though.

    Thanks again!

    Code:
    class UTBomb extends UTCarriedObject
    placeable;
    
    var PointLightComponent myLight;
    
    event PostBeginPlay()
    {
    	local Color white;
    	white.R = 255;
    	white.G = 255;
    	white.B = 255;
    	white.A = 255;
    
    	myLight = new(self)class'PointLightComponent';
    	AttachComponent(myLight);
    	myLight.SetLightProperties( 1, white );
    }
    
    function SetHolder( Controller C )
    {
    	
    	local Vector v; // float above head for now
    
    	`log("Setting holder...");
    	if ( C.playerreplicationinfo.bHasFlag ) // dont set if we have a bomb
    		return;
    
    	v = c.Pawn.location;
    	v.x += 0;
    	v.y += 15;
    	v.z += 60;
    
    	super.SetHolder(C);
    	UTBombSite(HomeBase).BombTaken();
    	HomeBase = None; // we cut all ties to where we spawned when someone picks us up
    	SetRelativeLocation(v);
    }
    
    function Drop( optional Controller C )
    {
    	super.Drop( c );
    	Destroy();
    }
    
    defaultproperties
    {
    	// draw model
    	Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
    		StaticMesh=StaticMesh'Pickups.Health_Medium.Mesh.S_Pickups_Health_Medium'
    	End Object
    
     	Components.Add(StaticMeshComponent0)
    }
    Code:
    class UTBombSite extends UTGameObjective
    placeable;
    
    var UTBomb myBomb;
    var class<UTBomb> BombType;
    
    var() float RespawnTime;
    
    simulated event postBeginPlay() // simulated because the compiler told me to
    {
    	super.PostBeginPlay();
    	SpawnBomb();
    }
    
    function SpawnBomb()
    {
    	if (myBomb == None)
    	{
    		myBomb = Spawn(BombType, self);
    		myBomb.HomeBase = self; // or it spawns at static location (world origin?)
    	}
    }
    
    // fake event called by bomb when taken
    event BombTaken()
    {
    	myBomb = None;
    	setTimer(RespawnTime);
    }
    
    function Timer()
    {
    	SpawnBomb();
    }
    	
    
    defaultproperties
    {
    	BombType=class'UTBomb'
    	RespawnTime=2.0
    
    	bStatic = false
    	bCollideActors=true // or no touch
    
    	// draw model
    	Begin Object Class=StaticMeshComponent Name=StaticMeshComponent0
    		StaticMesh=StaticMesh'Pickups.jump_pad.S_Pickups_Jump_Pad'
    		CollideActors=false
    		Scale3D=(X=1.0,Y=1.0,Z=1.0)
    		Translation=(X=0.0,Y=0.0,Z=-47.0)
    	End Object
    
     	Components.Add(StaticMeshComponent0)
    }
    PS: Do I need to do anything to make this work in multiplayer? I've seen issues with carried objects and spawners where replication info was set, so I'm just curious if I should be doing any of that here.

  8. #8

    Default

    Looks good.

    Do I need to do anything to make this work in multiplayer? I've seen issues with carried objects and spawners where replication info was set, so I'm just curious if I should be doing any of that here.
    Maybe. The only way to find out is to fire up a server and a client (or two) and make sure everything looks right. If you plan on supporting multiplayer, you should be testing it like this frequently. Things will get complicated (as you'll have multiple copies running with different roles and replication). Most of the replication here is done for you, I believe, in the parent classes. The only logic we added has to do with spawning actors, and so that should be done purely on the server and let the actor (the bomb) replicate himself.

    For example, though, you might find the client doesn't enable the light properly on the bomb (not simulated).

    I tried that approach once and it said that HomeBase didn't include a member function BombTaken(), but this time I typecast it and it seems to work. Please look over this final code if you get a chance, as I don't like (or understand fully) typecasting, and I feel it may cause unforseen problems in the future.
    This is fairly straight forward. Any object can "act like" any object it descends from. That means your UTBombSite can 'act like' a UTGameObjective or even an Actor. Any function that takes an actor, for example, can take a UTBombSite.

    HomeBase is part of UTCarriedObject and is declared as UTGameObjective. That means homebase can be any UTGameObjective and it will "act like" a UTGameObjective . While HomeBase (a bomb site, in this case) is typed as UTGameObjective it will only have the functions of a UTGameObjective. UTGameObject doesn't have our "new" event, and so homebase doesn't, either.

    In your case, you want to treat the homebase as a UTBombSite, so you need to cast it. This cast works for UTGameObjectives that are also UTBombSites. This cast will fail if the object passed in isn't a UTBombSite but some other UTGameObjective (like a CTFFlagBase). If the cast succeeds, the object will now "act like" a UTBombSite, and have all the functions you've added to UTBombSite. This can be made safe with something like...

    Code:
    local UTBombSite site;
    site = UTBombSite(HomeBase);
    
    if (site != None)
    {
        //Homebase is a UTBombSite
    }
    else
    {
        //Homebase is some other UTGameObjective
    }
    Last edited by clb; 01-08-2010 at 11:31 PM.


 

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Copyright ©2009-2011 Epic Games, Inc. All Rights Reserved.
Digital Point modules: Sphinx-based search vBulletin skin by CompletevB.com.