Basic Tutorial 2: Spawn cubes dynamically and manipulate them using Skookum


#1

##Spawn cubes dynamically and manipulate them using Skookum


Remember that you can download the tutorial project here. This tutorial uses map Level2.


 

For this tutorial, we’re going to create the same cube but in a separate BP so we can use the Skookum Mind class to spawn it and manipulate it. This write-up assumes that you’ve already gone through the previous tutorial.

 

  1. Start a new project (or feel free to use any suitable test project you may have). Create a cube BP (just like we did in the previous tutorial) but name this one BP_Cube2. The reason for a new cube BP is that we want to have a different setup and scripts inside its Skookum class.

  2. Remember to turn off EnableGravity and apply some default material to its StaticMesh if you wish.

  3. That’s all for Unreal for the time being! Hit the :sk: button and let’s move on to the SkookumIDE.

  4. This time, we’re not going to add a constructor to our BP_Cube2 class as we’re going to spawn dynamic instances and manipulate them through the Mind class. We’re simply going to add a _rotate coroutine. Open the Add a Class/Member dialog and add _rotate. This will be our code inside:

() 
[
//create some random speeds for each axis
!yaw   : MathLib.random_float * 100.0
!pitch : MathLib.random_float * 100.0
!roll  : MathLib.random_float * 100.0

loop
  [
  !d : GameLib.world_delta_seconds
                      
  !r : RotationAngles!yaw_pitch_roll(yaw * d, pitch * d, roll * d)

  add_actor_world_rotation(r)

  _wait //always good to wait for at least a frame in loops otherwise our game might slow to a crawl
  ]
] 

 

  1. Save and compile. We’re done with BP_Cube2 scripts. Now we’re going to take a look at the Mind class. You can find it quickly by filtering for the term “Mind” in the filter in the Classes browser.

  2. You’ll notice that the Mind class has a Master subclass. The Master Mind is the 1st Skookum class to get constructed at launch. You can check that out by just running the current project that you’re creating and seeing the print call in its constructor:
    Member: Master.!() - Mind instance constructor called.
    So we could spawn and manipulate our cubes inside the Master, but we can do something even better. We can create our own Mind objects that we can add to different levels and have them manage our coroutines and updates depending on what level we’re currently in.

More info on the Mind class here.

  1. Since this is the 2nd tutorial, let’s create a Level2 subclass. Make sure Mind is highlighted and hit the + button and type in Level2. Highlight the newly created subclass and hit + again and create a constructor !.

  2. Let’s add a print call here:

()
[
  println("Level2 Mind has started!")
]

 

  1. Save and compile. Let’s move back to Unreal for a bit. We’re going to add our Level2 Mind into our current level. Go to your Modes tab and find Empty Actor inside Basic. Drag one out into the level anywhere (placement is not important here, this is a purely logical object; a container for our Mind class).

  2. Rename it to Level2 Mind so we never forget why we added this. Then under the object’s Details panel, hit +AddComponent, search for Skookum Script Mind, and add it. Highlight it in the component list and look for the Script Class Name under Script. This is where we need to provide the name of our Mind class; so type in Level2 and hit Enter. Save the project and run it and you’ll see your print call that we added in step 9.

  3. Now we have our custom Mind object running in the game. We can use this class to spawn some cubes and manipulate them! Let’s go back to the SkookumIDE, highlight the Level2 class, and open the Add a Class/Member dialog to add spawn_cube as a method. This will be our code for it:

(Real height : 0) 
[
!xform : player_pawn.transform
xform.@translation += [player_pawn.actor_forward_vector *= 500] //move xform forward relative to player
xform.@translation.@z += height //specify how high we want our cube to spawn
  
BP_Cube2.spawn_at_xform(xform)
]

 

  1. The main difference here being the parameter height that we’re setting to 0 by default. We can use that parameter to offset the cube on the z axis.

  2. One last thing we’re going to add to this class is a coroutine called _run_craziness. This will be our code for it (check the comments for an explanation on what it does):

() 
[
_wait //wait a frame to make sure the player has spawned

//spawn 3 cubes at varying heights (1st call uses the default parameter specified in the function)
spawn_cube
spawn_cube(2.0 * Real.@@meter)   
spawn_cube(4.0 * Real.@@meter)


4._do  //do the following block of code 4 times
  [       
  BP_Cube2.instances._do  //do the following block of code on all instances of BP_Cube2 objects in our level
    [
    race  //race the _rotate call with the _wait call; essentially rotating for 5 secs
      [
      item._rotate  //item refers to an instance of BP_Cube2
      _wait(5)
      ]    
    ]
  ]
]

More info on branch, sync, and race commands here.
 

  1. In short, the code above will spawn 3 cubes then rotate each one for 5 seconds and loop over all instances 4 times. All that’s left is to call our crazy coroutine from our Level2 constructor:
()
[
println("Level2 Mind has started!")
  
branch [_run_craziness]
]

 

  1. Save and compile then head on back to Unreal and run the game. You’ll see 3 cubes spawn on top of each other right in front of you with one rotating for 5 secs before the coroutine moves on to the next one! Make sure to go back to _run_craziness to experiment with the different values in there! :slight_smile:

Stay Skookum!

 
 

How would you modify the script(s) to have all 3 cubes rotating together in parallel?! :wink:


Basic SkookumScript UE4 Plugin Tutorials
#2

#3

Just worked through this and learned some things. So thanks for that, certainly helps to have little tuts like this.

So the answer to the last question was

branch[item._rotate]

instead of the whole race block? Seems to work at least. May I have finally understood branch :smiley:

One thing that had me scratch my head for a sec was the @translation bit. After checking Transform class I can see

&raw Vector3 !@translation

Maybe it’s just me but I find that naming a bit unfortunate. In UE4 this is called location which is a cleverer name IMO and also bears a smaller risk of confusion with transform. Just a small gripe obviously.


#4

Glad you’re finding them useful! :slight_smile:

So yeah, your solution works but you could also replace the entire block after spawning the cubes with this one line:
BP_Cube2.instances%_rotate

The % runs _rotate on all instances of BP_Cube2. Of course, this would run forever as opposed to the 4._do loop that we had previously! Make sure to experiment with that nifty little symbol!

As for your comment regarding @translation, it’s essentially the mathematical term for representing location in a transformation matrix. It’s more universally used across different engines and their code bases. But yes, I agree that the term location is a more designer friendly term!


#5

So what happens here exactly?

4._do [ BP_Cube2.instances%_rotate ]

When _rotate is called the first time, it starts rotating forever. What about the other 3 times? Skookum knows _rotate is already running and ignores it?


#6

It’s redundant. _rotate never returns so you can never run this block 4 times.


#7

Right. so what about this just for fun:

4._do [ branch[BP_Cube2.instances%_rotate] ]


#8
4._do
  [
  branch[BP_Cube2.instances%_rotate]
  ]

The above code would call _rotate() 4 times on every BP_Cube2 object in parallel and then return instantly.

So each cube would have 4 never ending _rotate() coroutine calls running on them. Since the simple _rotate() command above is based on the delta time they would stomp over the rotation redundantly. Though this simple _rotate() command does not if it retrieved the current rotation and increased it by an additive amount then each call would cause a cube to rotate a bit faster in a frame.


#9

Everything’s been a smooth ride until the line:
BP_Cube2.instances._do
When I enter it the SkookumIDE crashes with Fatal Error. It seems the editor doesn’t like me using the instances method.


#10

Hi @CryptoSeven and welcome to our forum! :slight_smile:

Sorry about that, we’ll take a look and get back to you as soon as we can.


#11

Thank you, much appreciated :slight_smile:


#12

We have tried to reproduce this here but couldn’t make it happen. What version of UE4 are you using and what version of the plugin/IDE?


#13

Unreal version 4.15.0 and SkookumIDE version 3.0.4135.

I have the same issue with instances method when trying to reproduce in other scripts or projects. Thanks for looking into it, but probably hard to track down why if it’s only on my end.


#14

Could you zip up your project and send it to us just to make sure we have the exact same project? I assume it happens consistently every time for you? If so, it should happen for is too with your project. When you zip it up, make sure to exclude temp folders such as Intermediate, DerivedDataCache and Saved.


#15

SkookumTut2.zip (750.9 KB)

Sure thing, let me know if this works.

Yeah it’s annoyingly consistent for me :wink: I commented out the line in _run_craziness that causes the editor to crash
//If I uncomment line below editor crashes as soon as I try to type something else.
//BP_Cube2.instances._do


#16

Ok so I was able to reproduce this with the Marketplace release of the IDE but not with latest. Please try the following: Download the latest IDE executable and place it in SkookumIDE\Engine\Binaries\Win64 of the plugin folder. Let me know if that fixes it!


#17

Hey that works, finally I can witness the glory of the cubes taking turn rotating :smiley: Thanks!


#18

#19

Thanks for the tutorial.

It seems I am unable to call the coroutine on the Cube class (I didn’t name is BP_Cube2). See the attached screenshot. Not sure what I am doing wrong.

image

Edit: I searched through the forums and found this post. Sadly, in my case, the compiler is throwing the following error when I try to compile:

image


#20

The first issue is that your outer loop is doing 4.do instead of 4._do. The do without the underscore is an immediate statement and can only contain immediate statements under it, the _do is a deferred statement that can take 1 or more frames.