Jump to content

[Fixed] Foliage Collision Volume


Ruud033

Recommended Posts

Code is bugging, dont know why

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
//=============================================================================

class FoliageCollisionVolume extends Volume 
   placeable; 

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

simulated function UpdateCollisionBasedOnDistanceTimer() //simulated functions are MAYBE client side only, have to try this!
{	
local float CollisionDistance;
local playercontroller PC;

if(PC.Pawn == None)
	return;	

CollisionDistance = VSize(PC.Pawn.location - location); //The distance between the two actors

if(CollisionDistance<=400) //Checks when ever to create collision or what ever number if you have that
   {
       SetTimer(0.6f,false,'CreateCollision');
       CollisionDistance =400;
   }	

function CreateCollision() 
{ 
local InstancedFoliageActor ac; 
local InstancedStaticMeshComponent comp; 
local vector loc, scale; 
local Rotator rot; 
local BlockingMesh CreatedBlockingMesh; 
local int i, j; 

super.CreateCollision(); 
//look for the InstancedFoliageActor 
foreach AllActors(class'InstancedFoliageActor',ac) 
{ 
	//iterate through the various foliage components 
	for(i=0; i		{ 
		comp = ac.InstancedStaticMeshComponents[i]; 
		if (comp.StaticMesh.BodySetup != none) 
		{ 
			//iterate through the various meshes in this component, if it has a collision model 
			for (j=0; j				{ 
				//decompose the instance's transform matrix 
				loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 
				if (ContainsPoint(loc)) //check if this instance is within the volume 
				{ 
					rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
					scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
					CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
					CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
					CreatedBlockingMesh.SetDrawScale3D(scale); 
				} 
			} 
		} 
	} 
} 
}  	
} 

---------------------

F:\Program Files\Renegade X Beta4\SDK\Development\Src\FoliageCollisionVolume\Classes\FoliageCollisionVolume.uc(36) : Error, 'Function' is not allowed here

Failure - 1 error(s), 0 warning(s)

Execution of commandlet took: 4.37 seconds

[jun 16, 10:46 ] COMMANDLET 'UDK.exe make' FAILED

Edited by Guest
Link to comment
Share on other sites

Nope, sorry but it's there already. Is a function within a function allowed?? I've also read somewhere that timers are not supposed to fire a function or something?? (Silo uses the same though)

If function in function can't work, then make the second function outside the bracket. As long as the timer calls it by name, it should work...

 if(CollisionDistance<=400) //Checks when ever to create collision or what ever number if you have that
   {
       SetTimer(0.6f,false,'CreateCollision');
       CollisionDistance =400;
   }   
} //<--Add a bracket here... 
{ //<---and also below. That pretty much sums up making them separate.
function CreateCollision()
{
  local InstancedFoliageActor ac;
  local InstancedStaticMeshComponent comp;
  local vector loc, scale;
  local Rotator rot;
  local BlockingMesh CreatedBlockingMesh;
  local int i, j; 

Link to comment
Share on other sites

  • Totem Arts Staff

Supposedly a function can be fired with Timer ever since Unreal Engine 3 came (can't do so in the previous iteration) So a function within a function isn't necessary.... not that it will work anyways

Also Bro, that's kinda confusing. You can't make a function inside a bracket... unless it was a bracket for State, which should not be necessary

Link to comment
Share on other sites

Nope, sorry but it's there already. Is a function within a function allowed?? I've also read somewhere that timers are not supposed to fire a function or something?? (Silo uses the same though)

If function in function can't work, then make the second function outside the bracket. As long as the timer calls it by name, it should work...

 if(CollisionDistance<=400) //Checks when ever to create collision or what ever number if you have that
   {
       SetTimer(0.6f,false,'CreateCollision');
       CollisionDistance =400;
   }   
} //<--Add a bracket here... 
{ //<---and also below. That pretty much sums up making them separate.
function CreateCollision()
{
  local InstancedFoliageActor ac;
  local InstancedStaticMeshComponent comp;
  local vector loc, scale;
  local Rotator rot;
  local BlockingMesh CreatedBlockingMesh;
  local int i, j; 

This worked! Below is the code. I still have my doubts about this code, I think it still spawns EVERYTHING once the client is in range of it.. I need to change the code to look for foliage instances, any idea on how to do that?

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
//=============================================================================

class FoliageCollisionVolume extends Volume 
   placeable; 

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

simulated function UpdateCollisionBasedOnDistanceTimer() //simulated functions are MAYBE client side only, have to try this!
{	
local float CollisionDistance;
local playercontroller PC;

if(PC.Pawn == None)
	return;	

CollisionDistance = VSize(PC.Pawn.location - location); //The distance between the two actors

if(CollisionDistance<=400) //Checks when ever to create collision or what ever number if you have that
   {
CollisionDistance =400;
SetTimer(0.6f,false,'CreateCollision');
}
}

simulated function CreateCollision() 
{ 
local InstancedFoliageActor ac; 
local InstancedStaticMeshComponent comp; 
local vector loc, scale; 
local Rotator rot; 
local BlockingMesh CreatedBlockingMesh; 
local int i, j; 

//look for the InstancedFoliageActor 
foreach AllActors(class'InstancedFoliageActor',ac) 
{ 
	//iterate through the various foliage components 
	for(i=0; i		{ 
		comp = ac.InstancedStaticMeshComponents[i]; 
		if (comp.StaticMesh.BodySetup != none) 
		{ 
			//iterate through the various meshes in this component, if it has a collision model 
			for (j=0; j				{ 
				//decompose the instance's transform matrix 
				loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 
				if (ContainsPoint(loc)) //check if this instance is within the volume 
				{ 
					rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
					scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
					CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
					CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
					CreatedBlockingMesh.SetDrawScale3D(scale); 
				} 
			} 
		} 
	} 
} 
} 

Link to comment
Share on other sites

That is a shame, idk why it does that. Since we borrowed SBH code, that would be like being able to see all SBH on the map if a single SBH was in range of you.

Anyone else have any clue?

After some hours of thinking and trial and error I've got this code, it compiles well but I think it can't find the correct distance between actor and foliage.

I think this is due to PC.Pawn.location, this node is not saying anything to me, its meaningless as far as I know. I had to make a local variable called "PC" (check the code) to get it to work and I still don't know what it does.

###So what I did now is I made a radical change. Now I am determining the locations of the foliage first, THEN check if the player is in range (because I already have the exact location's) THEN check whether the foliage is in a volume or not and THEN spawn the collision.

It compiles correctly but still, does not work, it does not spawn in the collision. I think this is due to the playerlocation / actor location.

I am thinking about putting a check around the foliage, a trigger zone.. so for instance, if an Rx_Actor is closer than 400 units, the script checks whether it's in a volume and THEN spawns the stuff.. rather than monitoring each player realtime.

I don't know how to do that (yet). Have to analyse the trigger volume scripting.

This is my code for now (as described in ###)

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Edited by Ruud033
//=============================================================================

class FoliageCollisionVolume extends Volume 
   placeable; 

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

simulated function CreateCollision() 
{ 
local InstancedFoliageActor ac; 
local InstancedStaticMeshComponent comp; 
local vector loc, scale; 
local Rotator rot; 
local BlockingMesh CreatedBlockingMesh; 
local int i, j; 
local float CollisionDistance;
local playercontroller PC;

//look for the InstancedFoliageActor 
foreach AllActors(class'InstancedFoliageActor',ac) 
{ 
	//iterate through the various foliage components 
	for(i=0; i		{ 
		comp = ac.InstancedStaticMeshComponents[i]; 
		if (comp.StaticMesh.BodySetup != none) 
		{ 
			//iterate through the various meshes in this component, if it has a collision model 
			for (j=0; j				{ 
				//decompose the instance's transform matrix 
				loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 
				CollisionDistance = VSize(PC.Pawn.location - loc); //The distance between the two actors

				if(CollisionDistance<=400) //Checks when ever to create collision or what ever number if you have that 
				{
					if (ContainsPoint(loc)) //check if this instance is within the volume
					{ 
						rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
						scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
						CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
						CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
						CreatedBlockingMesh.SetDrawScale3D(scale); 
					} 
				}
			} 
		} 
	} 
} 
} 

After compiling it only says this;

Warning/Error Summary

---------------------

F:\Program Files\Renegade X Beta4\SDK\Development\Src\FoliageCollisionVolume\Classes\FoliageCollisionVolume.uc(46) : Warning, 'PC' : local variable used before assigned a value

Interesting stuff for player log:

https://forums.epicgames.com/threads/89 ... d-Material

http://www.polycount.com/forum/showthread.php?t=97548

https://forums.epicgames.com/threads/74 ... r-location

Link to comment
Share on other sites

  • Totem Arts Staff

It's quite a big issue. You did not define what PC is. You only tell the function that it's of a PlayerController type, but did not determine which PlayerController in the current world PC is referring to.

Unfortunately I don't know how to get all PlayerControllers, except maybe with ForEach.

Link to comment
Share on other sites

It's quite a big issue. You did not define what PC is. You only tell the function that it's of a PlayerController type, but did not determine which PlayerController in the current world PC is referring to.

Unfortunately I don't know how to get all PlayerControllers, except maybe with ForEach.

The SBH had an if statement like: if [LocalPC.PlayerPawn == None]

But that kept erroring in this code. Is that something that would help stifle this, and why couldn't it find LocalPC if so...

Link to comment
Share on other sites

  • Totem Arts Staff

LocalPC isn't a magic word, it's a variable that's set in the Pawn class iirc. You actually need to find and set the localpc if you're outside of a class that already has a variable for it or a function that points to it.

As Hande said, you would probably need to look through Player controllers with a foreach statement. The exact syntax from this object I can't tell you without being at my computer.

Link to comment
Share on other sites

Yeah that would make sense, I thought it was a variable in another location (like Stankmod.rx_vehicle_stealth_tank) so it could be referenced externally, but it makes sense. So, could he just add a default properties field at the bottom and then a localpc? Or does he also need a foreach statement?

Rudd, I suggest you search the pawnsbh for both those and see if you can figure out how to do one or both of those from looking at the code in context of the sbh.

Link to comment
Share on other sites

I don't need to use the localpc.pawn.location variable persé.. I could also use some other variable that outputs a location that's relevant to a player. CameraWorldPosition for example.

Any other clues on this?

Edit: So I've been looking into possibilities on how to do this.

- Enable rigidbody blocking (failed because I was not allowed to add this value to the foliage, said the compiler)

- Spawn collision by checking the distance between actors (failed because I can't get the correct distance calculation right! Don't know how to fix this.

- Spawn collision by touching the volume (still looking into this right now)

Link to comment
Share on other sites

So I've gotten quite far in this already. It spawns the new dynamic actors when I walk in the zone BUT, it only destroys 1 actor (read: blocking mesh) when I leave the zone.. How can I make sure it destroys ALL created actors? Yosh spoke of a dynamic array of some sort.. Can anyone advise me on this? Every input is welcome.

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Heavily modified by Ruud033
//=============================================================================

class FoliageCollisionVolume extends Volume 
   placeable; 
var BlockingMesh CreatedBlockingMesh; //need dynamic array

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local InstancedFoliageActor ac; 
   local InstancedStaticMeshComponent comp; 
   local vector loc, scale; 
   local Rotator rot; 
   local int i, j; 

   super.Touch(Other, OtherComp, HitLocation, HitNormal);

//look for the InstancedFoliageActor 
foreach AllActors(class'InstancedFoliageActor',ac) 
{ 
	//iterate through the various foliage components 
	for(i=0; i		{ 
		comp = ac.InstancedStaticMeshComponents[i]; 
		if (comp.StaticMesh.BodySetup != none) 
		{ 
			//iterate through the various meshes in this component, if it has a collision model 
			for (j=0; j				{ 
				//decompose the instance's transform matrix 
				loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 

				if (ContainsPoint(loc)) //check if this instance is within the volume 
				{ 
					rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
					scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
					CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
					CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
					CreatedBlockingMesh.SetDrawScale3D(scale); 
				} 
			} 
		} 
	} 
} 
}  	

event Untouch( Actor Other )
{
CreatedBlockingMesh.Destroy(); 
} 

defaultproperties
{
bColored=true
BrushColor=(R=0,G=255,B=255,A=255)

bCollideActors=true
bProjTarget=true
SupportedEvents.Empty
SupportedEvents(0)=class'SeqEvent_Touch'
}

Link to comment
Share on other sites

Not sure why code doesn't remove all spawned actors. Maybe Super.Untouch(Other) does something important behind the scenes? If so you should add it within event Untouch

You could also try manually destroying all other meshes within "distance" radius of that one mesh which successfully gets destroyed upon Untouch.

var int distance;

event Untouch ( Actor Other)
{
  ForEach WorldInfo.AllActors(Actor mesh)
  {
     if (mesh.IsA('BlockingMesh') && (vSizeSq(mesh.pos - CreatedBlockingMesh.pos) <= (distance**2)))
     {
        mesh.Destroy();
     }
  }
}

Edited by Guest
Link to comment
Share on other sites

Here is version using DynamicArrays, it is probably faster.

Search for "NEW CODE" to easily locate what I've added.

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Heavily modified by Ruud033
//=============================================================================

class FoliageCollisionVolume extends Volume 
   placeable; 
var BlockingMesh CreatedBlockingMesh; //need dynamic array
       var Array SpawnedBlockingMeshes; // NEW CODE

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local InstancedFoliageActor ac; 
   local InstancedStaticMeshComponent comp; 
   local vector loc, scale; 
   local Rotator rot; 
   local int i, j; 

   super.Touch(Other, OtherComp, HitLocation, HitNormal);

//look for the InstancedFoliageActor 
foreach AllActors(class'InstancedFoliageActor',ac) 
{ 
	//iterate through the various foliage components 
	for(i=0; i		{ 
		comp = ac.InstancedStaticMeshComponents[i]; 
		if (comp.StaticMesh.BodySetup != none) 
		{ 
			//iterate through the various meshes in this component, if it has a collision model 
			for (j=0; j				{ 
				//decompose the instance's transform matrix 
				loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 

				if (ContainsPoint(loc)) //check if this instance is within the volume 
				{ 
					rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
					scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
					CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
					CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
					CreatedBlockingMesh.SetDrawScale3D(scale);
                                               SpawnedBlockingMeshes.AddItem(CreatedBlockingMesh); // NEW CODE
				} 
			} 
		} 
	} 
} 
}  	

// NEW CODE STARTS
event Untouch( Actor Other )
{
    Super.Untouch(Other);
    ForEach SpawnedBlockingMeshes(BlockingMesh mesh)
                  mesh.Destroy();
    SpawnedBlockingMeshes.Length = 0;
} 
// NEW CODE ENDS	
defaultproperties
{
bColored=true
BrushColor=(R=0,G=255,B=255,A=255)

bCollideActors=true
bProjTarget=true
SupportedEvents.Empty
SupportedEvents(0)=class'SeqEvent_Touch'
}

Link to comment
Share on other sites

I think I know why your code only deletes one blocking mesh.

Spawn(x) is a function which tell engine to spawn object of class x and returns memory address of that object.

When you say Y = Spawn(x); then you are giving two instructions:

1)Spawn object of class X

2)Give that address of object to Y

Take a look at this:

for (i=0; i < 3; i++)
{
   SpawnedBlockingMesh = Spawn(BlockingMesh);
}

i=0: Engine spawns blockingmesh1 on the map and makes your SpawnedBlockingMesh point to blockingmesh1

i=1: Engine spawns blockingmesh2 and your SpawnedBlockingMesh now points to blockingmesh2

i=2: Engine spawns blockingmesh3 and SpawnedBlockingMesh now points to blockingmesh3

When you use

SpawnedBlockingMesh.Delete();

Only object deleted will be the one SpawnedBlockingMesh is pointing at and that is mesh 3.

You have lost your references to mesh 1 and mesh 2 because you keep overwriting SpawnedBlockingMesh with addresses of new objects.

That is why you need to use dynamic arrays.

Instead of

SpawnedBlockingMesh = Spawn(BlockingMesh)

use

var Array SpawnedBlockingMeshArray;
...
for (i=0; i<3; i++)
{
SpawnedBlockingMeshArray.AddItem(Spawn(BlockingMesh));
}

Link to comment
Share on other sites

Your current code does not work sadly :( I'm trying to figure out what's happening. The issue seems to be in line 69.

F:\Program Files\Renegade X Beta4\SDK\Development\Src\FoliageCollisionVolume\Classes\FoliageCollisionVolume.uc(69) : Error, Bad or missing expression for token: BlockingMesh, in 'foreach array'

Failure - 1 error(s), 0 warning(s)

Execution of commandlet took: 4.63 seconds

[jun 22, 7:19 ] COMMANDLET 'UDK.exe make' FAILED

Maybe you've done it wrong there? check out this:

https://udn.epicgames.com/Three/UnrealS ... ators.html

https://udn.epicgames.com/Three/UnrealS ... ayIterator

http://wiki.beyondunreal.com/Dynamic_arrays

Not sure what is going on there.

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Heavily modified by Ruud033
//=============================================================================

class FoliageCollisionVolume extends Volume 
placeable; 
var BlockingMesh CreatedBlockingMesh; 
var Array SpawnedBlockingMeshes; 

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

//Search for each tree apart, the code goes trough the volume and searches each tree.
event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local InstancedFoliageActor ac; 
local InstancedStaticMeshComponent comp; 
local vector loc, scale; 
local Rotator rot; 
local int i, j; 

super.Touch(Other, OtherComp, HitLocation, HitNormal);

  //look for the InstancedFoliageActor 
  foreach AllActors(class'InstancedFoliageActor',ac) 
  { 
     //iterate through the various foliage components 
     for(i=0; i      { 
        comp = ac.InstancedStaticMeshComponents[i]; 
        if (comp.StaticMesh.BodySetup != none) 
        { 
           //iterate through the various meshes in this component, if it has a collision model 
           for (j=0; j            { 
              //decompose the instance's transform matrix 
              loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 

              if (ContainsPoint(loc)) //check if this instance is within the volume 
              { 
                 rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
                 scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
                 CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
                 CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
                 CreatedBlockingMesh.SetDrawScale3D(scale);
                 SpawnedBlockingMeshes.AddItem(CreatedBlockingMesh); 
              } 
           } 
        } 
     } 
  } 
}     

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{
   Super.Untouch(Other);

   ForEach SpawnedBlockingMeshes(BlockingMesh, mesh)
{
	mesh.Destroy();
	SpawnedBlockingMeshes.Length = 0;
}
} 

defaultproperties
{
  bColored=true
  BrushColor=(R=0,G=255,B=255,A=255)

  bCollideActors=true
  bProjTarget=true
  SupportedEvents.Empty
  SupportedEvents(0)=class'SeqEvent_Touch'
}

Edit: also posted on UDK forums https://forums.epicgames.com/threads/99 ... st31929327

Link to comment
Share on other sites

when doing this:

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{

   Super.Untouch(Other);

ForEach SpawnedBlockingMeshes(class'BlockingMesh', mesh)
{
	mesh.Destroy();
	SpawnedBlockingMeshes.Length = 0;
}
} 

I get:

---------------------

F:\Program Files\Renegade X Beta4\SDK\Development\Src\FoliageCollisionVolume\Classes\FoliageCollisionVolume.uc(70) : Error, 'foreach array': Expecting a variable, not a constant

Failure - 1 error(s), 0 warning(s)

Execution of commandlet took: 4.98 seconds

[jun 22, 10:24 ] COMMANDLET 'UDK.exe make' FAILED

Link to comment
Share on other sites

  • Totem Arts Staff
when doing this:

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{

   Super.Untouch(Other);

ForEach SpawnedBlockingMeshes(class'BlockingMesh', mesh)
{
	mesh.Destroy();
	SpawnedBlockingMeshes.Length = 0;
}
} 

I get:

---------------------

F:\Program Files\Renegade X Beta4\SDK\Development\Src\FoliageCollisionVolume\Classes\FoliageCollisionVolume.uc(70) : Error, 'foreach array': Expecting a variable, not a constant

Failure - 1 error(s), 0 warning(s)

Execution of commandlet took: 4.98 seconds

[jun 22, 10:24 ] COMMANDLET 'UDK.exe make' FAILED

Basically what Hande said, as he beat me to it. When you iterate through a dynamic array with foreach, it only needs an out variable to set something to. The dynamic array can only be ONE type of thing, so it doesn't need you to tell it what kind of thing to look for.

Link to comment
Share on other sites

Tried your script, also added a vehicle check. Thanks for this idea Handepsilon, I only need to spawn collision when ever a VEHICLE hits the volume, infantry does not matter since they already collide... all the sudden we have a LOT of performance gain over time :D:D:D since the server does not have to spawn collision for infantry.

Sadly, the collision does not remove itself... I have bNoDelete=false in the BlockingMesh.uc set, so that should not be an issue for Destroy()

FoliageCollisionVolume.uc

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Heavily modified by Ruud033
//=============================================================================

class FoliageCollisionVolume extends Volume 
placeable; 
var BlockingMesh CreatedBlockingMesh; 
var Array SpawnedBlockingMeshes; 

static final function vector MatrixGetScale(Matrix TM) 
{ 
   local Vector s; 
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2); 
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2); 
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2); 
   return s; 
} 

//Search for each tree apart, the code goes trough the volume and searches each tree.
event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local InstancedFoliageActor ac; 
local InstancedStaticMeshComponent comp; 
local vector loc, scale; 
local Rotator rot; 
local int i, j; 

super.Touch(Other, OtherComp, HitLocation, HitNormal);

If(Other.IsA('Vehicle'))
{

  //look for the InstancedFoliageActor 
  foreach AllActors(class'InstancedFoliageActor',ac) 
  { 
     //iterate through the various foliage components 
     for(i=0; i      { 
        comp = ac.InstancedStaticMeshComponents[i]; 
        if (comp.StaticMesh.BodySetup != none) 
        { 
           //iterate through the various meshes in this component, if it has a collision model 
           for (j=0; j            { 
              //decompose the instance's transform matrix 
              loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform); 

              if (ContainsPoint(loc)) //check if this instance is within the volume 
              { 
                 rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform); 
                 scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform); 
                 CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot); 
                 CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh); 
                 CreatedBlockingMesh.SetDrawScale3D(scale);
                 SpawnedBlockingMeshes.AddItem(Spawn(class'BlockingMesh')); 
              } 
           } 
        } 
     } 
  } 
}
}

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{
local int i;
Super.Untouch(Other);

  for(i=0; i > SpawnedBlockingMeshes.Length; i++) 
	{
	SpawnedBlockingMeshes[i].Destroy();//if bNoDelete is set to false in defaultproperties; this deletes it
	SpawnedBlockingMeshes.Remove(i--,1);
	}
	SpawnedBlockingMeshes.Length = 0;
} 

defaultproperties
{
  bColored=true
  BrushColor=(R=0,G=255,B=255,A=255)

  bCollideActors=true
  SupportedEvents.Empty
  SupportedEvents(0)=class'SeqEvent_Touch'
}

BlockingMesh.uc

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Modified by Ruud033
//=============================================================================

class BlockingMesh extends DynamicSMActor_Spawnable; 

defaultproperties 
{ 
   Begin Object Name=StaticMeshComponent0 
       HiddenGame = true //we don't wanna draw this, it's just used to test collision 
       BlockRigidBody=true //DynamicSMActors have collision disabled by default 
	CastShadow=false
	MaxDrawDistance = 500
	bAllowCullDistanceVolume=true
	AlwaysLoadOnServer=false
   End object 
   bCollideActors=true //same here 
   bTickIsDisabled = true //greatly improves performance on the game thread 
bStatic=false
bNoDelete=false
}

Link to comment
Share on other sites

  • Totem Arts Staff

Ok, let's revamp your script. All modifications are in bold

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Heavily modified by Ruud033
//=============================================================================

class FoliageCollisionVolume extends Volume
  placeable;
  var BlockingMesh CreatedBlockingMesh;
  var Array SpawnedBlockingMeshes;
 [b]var bool bBlockersHaveSpawned //Check if blockers have already spawned. If it has, no need to spawn more[/b]
 [b]var Array VehiclesInVolume;[/b]

static final function vector MatrixGetScale(Matrix TM)
{
   local Vector s;
   s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2);
   s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2);
   s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2);
   return s;
}

//Search for each tree apart, the code goes trough the volume and searches each tree.
event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
  local InstancedFoliageActor ac;
  local InstancedStaticMeshComponent comp;
  local vector loc, scale;
  local Rotator rot;
  local int i, j;

  super.Touch(Other, OtherComp, HitLocation, HitNormal);

  If(Other.IsA('Vehicle'))
  {
    [b]VehiclesInVolume.AddItem(Vehicle(Other));
  if(!bBlockersHaveSpawned)
  {
    bBlockersHaveSpawned = true;[/b]

  //look for the InstancedFoliageActor
  foreach AllActors(class'InstancedFoliageActor',ac)
  {
     //iterate through the various foliage components
     for(i=0; i      {
        comp = ac.InstancedStaticMeshComponents[i];
        if (comp.StaticMesh.BodySetup != none)
        {
           //iterate through the various meshes in this component, if it has a collision model
           for (j=0; j            {
              //decompose the instance's transform matrix
              loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform);

              if (ContainsPoint(loc)) //check if this instance is within the volume
              {
                 rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform);
                 scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform);
                 CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot);
                 CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh);
                 CreatedBlockingMesh.SetDrawScale3D(scale);
                 SpawnedBlockingMeshes.AddItem(Spawn(class'BlockingMesh'));
              }
           }
        }
     }
  }
}
}
}

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{
  local int i;
  Super.Untouch(Other);

 [b]for(i=0; i < VehiclesInVolume.Length; i++)
 {
   if(Vehicle(Other) == VehiclesInVolume[i])
   VehiclesInVolume.RemoveItem(i--, 1);
 }[/b]
[b]  if(VehiclesInVolume.Length <= 0)
 {[/b]
    for(i=0; i [b]<[/b] SpawnedBlockingMeshes.Length; i++)
     {
     SpawnedBlockingMeshes[i].Destroy();//if bNoDelete is set to false in defaultproperties; this deletes it
     SpawnedBlockingMeshes.Remove(i--,1); [b]// Hande's note : This is not necessary as the below function will automatically empty the array[/b]
     }
     SpawnedBlockingMeshes.Length = 0;
     [b]bBlockersHaveSpawned = false;[/b]
 [b]}[/b]
}

defaultproperties
{
  bColored=true
  BrushColor=(R=0,G=255,B=255,A=255)

  bCollideActors=true
  SupportedEvents.Empty
  SupportedEvents(0)=class'SeqEvent_Touch'
}

Something like this. Just fix things that needs to be fixed

EDIT : Replace :

 for(i=0; i < VehiclesInVolume.Length; i++)
 {
   if(Vehicle(Other) == VehiclesInVolume[i])
   VehiclesInVolume.RemoveItem(i--, 1);
 }

To :

 VehiclesInVolume.RemoveItem(Vehicle(Other));

Link to comment
Share on other sites

New script update:

Delete issue still persists.. It won't delete the actors once Untouch()

FoliageCollisionVolume.uc

//=============================================================================
// FoliageCollisionVolume: a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/91 ... on-foliage 
// Heavily modified by Ruud033 & Handepsilon
//=============================================================================

class FoliageCollisionVolume extends Volume
placeable;
var BlockingMesh CreatedBlockingMesh;
var Array SpawnedBlockingMeshes;
var bool bBlockersHaveSpawned; //Check if blockers have already spawned. If it has, no need to spawn more
var Array VehiclesInVolume;

static final function vector MatrixGetScale(Matrix TM)
{
local Vector s;
s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2);
s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2);
s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2);
return s;
}

//Search for each tree apart, the code goes trough the volume and searches each tree.
event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local InstancedFoliageActor ac;
local InstancedStaticMeshComponent comp;
local vector loc, scale;
local Rotator rot;
local int i, j;

super.Touch(Other, OtherComp, HitLocation, HitNormal);

If(Other.IsA('Vehicle'))
{
VehiclesInVolume.AddItem(Vehicle(Other));

	if(!bBlockersHaveSpawned)
	{
	bBlockersHaveSpawned = true;

		//look for the InstancedFoliageActor
		foreach AllActors(class'InstancedFoliageActor',ac)
		{
			//iterate through the various foliage components
			for(i=0; i				{
				comp = ac.InstancedStaticMeshComponents[i];

				if (comp.StaticMesh.BodySetup != none)
				{
					//iterate through the various meshes in this component, if it has a collision model
					for (j=0; j						{
						//decompose the instance's transform matrix
						loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform);
						if (ContainsPoint(loc)) //check if this instance is within the volume
						{
						rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform);
						scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform);
						CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot);
						CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh);
						CreatedBlockingMesh.SetDrawScale3D(scale);
						SpawnedBlockingMeshes.AddItem(Spawn(class'BlockingMesh'));
						}
					}
				}
			}
		}
	}
}
}

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{
local int i;
Super.Untouch(Other);

VehiclesInVolume.RemoveItem(Vehicle(Other));
if(VehiclesInVolume.Length <= 0)
{
	for(i=0; i < SpawnedBlockingMeshes.Length; i++)
	{
	SpawnedBlockingMeshes[i].Destroy();//if bNoDelete is set to false in defaultproperties; this deletes it
	// Ok removed SpawnedBlockingMeshes.Remove(i--,1); // Hande's note : This is not necessary as the below function will automatically empty the array
	}
SpawnedBlockingMeshes.Length = 0;
bBlockersHaveSpawned = false;
}
}

defaultproperties
{
bColored=true
BrushColor=(R=0,G=255,B=255,A=255)

bCollideActors=true
SupportedEvents.Empty
SupportedEvents(0)=class'SeqEvent_Touch'
}

Link to comment
Share on other sites

It works perfectly.

BlockingMesh.uc

//=============================================================================
// FoliageCollisionVolume:  a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/913559-How-to-enable-collision-on-foliage
// Modified by Ruud033
//=============================================================================

class BlockingMesh extends DynamicSMActor_Spawnable; 

defaultproperties 
{ 
   Begin Object Name=StaticMeshComponent0 
       HiddenGame = true //we don't wanna draw this, it's just used to test collision 
       BlockRigidBody=true //DynamicSMActors have collision disabled by default 
	CastShadow=false
	MaxDrawDistance = 500
	bAllowCullDistanceVolume=true
	AlwaysLoadOnServer=false
   End object 
   bCollideActors=true //same here 
   bTickIsDisabled = true //greatly improves performance on the game thread 
bStatic=false
bNoDelete=false
}

FoliageCollisionVolume.uc

//=============================================================================
// FoliageCollisionVolume: a vehicle collision solution
// used to collide certain classes of actors
// primary use is to provide collision for non-zero extent traces around static meshes
// Created by Pinheiro, https://forums.epicgames.com/threads/91 ... on-foliage 
// Heavily modified by Ruud033 & Handepsilon
// Thanks Crnyo and nameloc for the additional help
//=============================================================================

class FoliageCollisionVolume extends Volume
placeable;
var BlockingMesh CreatedBlockingMesh;
var Array SpawnedBlockingMeshes;
var bool bBlockersHaveSpawned; //Check if blockers have already spawned. If it has, no need to spawn more
var Array VehiclesInVolume;

static final function vector MatrixGetScale(Matrix TM)
{
local Vector s;
s.x = sqrt(TM.XPlane.X**2 + TM.XPlane.Y**2 + TM.XPlane.Z**2);
s.y = sqrt(TM.YPlane.X**2 + TM.YPlane.Y**2 + TM.YPlane.Z**2);
s.z = sqrt(TM.ZPlane.X**2 + TM.ZPlane.Y**2 + TM.ZPlane.Z**2);
return s;
}

//Search for each tree apart, the code goes trough the volume and searches each tree.
event Touch( Actor Other, PrimitiveComponent OtherComp, vector HitLocation, vector HitNormal )
{
local InstancedFoliageActor ac;
local InstancedStaticMeshComponent comp;
local vector loc, scale;
local Rotator rot;
local int i, j;

super.Touch(Other, OtherComp, HitLocation, HitNormal);

If(Other.IsA('Vehicle'))
{
VehiclesInVolume.AddItem(Vehicle(Other));

	if(!bBlockersHaveSpawned)
	{
	bBlockersHaveSpawned = true;

		//look for the InstancedFoliageActor
		foreach AllActors(class'InstancedFoliageActor',ac)
		{
			//iterate through the various foliage components
			for(i=0; i				{
				comp = ac.InstancedStaticMeshComponents[i];

				if (comp.StaticMesh.BodySetup != none)
				{
					//iterate through the various meshes in this component, if it has a collision model
					for (j=0; j						{
						//decompose the instance's transform matrix
						loc = MatrixGetOrigin(comp.PerInstanceSMData[j].Transform);
						if (ContainsPoint(loc)) //check if this instance is within the volume
						{
						rot = MatrixGetRotator(comp.PerInstanceSMData[j].Transform);
						scale = MatrixGetScale(comp.PerInstanceSMData[j].Transform);
						CreatedBlockingMesh = Spawn(class'BlockingMesh',ac,,loc,rot);
						CreatedBlockingMesh.StaticMeshComponent.SetStaticMesh(comp.StaticMesh);
						CreatedBlockingMesh.SetDrawScale3D(scale);
						SpawnedBlockingMeshes.AddItem(CreatedBlockingMesh);
						}
					}
				}
			}
		}
	}
}
}

//Destroy the spawned meshes once untouched
event Untouch( Actor Other )
{
local int i;
Super.Untouch(Other);

VehiclesInVolume.RemoveItem(Vehicle(Other));
if(VehiclesInVolume.Length <= 0)
{
	for(i=0; i < SpawnedBlockingMeshes.Length; i++)
	{
	SpawnedBlockingMeshes[i].Destroy();//if bNoDelete is set to false in defaultproperties; this deletes it
	// Ok removed SpawnedBlockingMeshes.Remove(i--,1); // Hande's note : This is not necessary as the below function will automatically empty the array
	}
SpawnedBlockingMeshes.Length = 0;
bBlockersHaveSpawned = false;
}
}

defaultproperties
{
bColored=true
BrushColor=(R=0,G=255,B=255,A=255)

bCollideActors=true
SupportedEvents.Empty
SupportedEvents(0)=class'SeqEvent_Touch'
}

Link to comment
Share on other sites

  • 3 weeks later...

In my map? If it was in my map that could be! I have not uploaded the optimised version yet as I have to add stuff to it and what not before I bring it out again.. Oh well, I'll build all and re-upload what I have now. Lots of changes already so..

If it was in your map you might want to ask yourself if you have set the size of the volumes correctly

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...