Minecraft Modding: Spawning Custom Particles

Background


Particles are a mechanism in Minecraft that create effects like the hearts that float over a tamed animal, or even things like the rain. Basically they are simply a texture that can be drawn that keeps track of position and motion.

Although fully custom particles are useful sometimes you might just want to spawn vanilla particles. In that case check out Jabelar's Vanilla Particle Tutorial.

For other general tips on particles, you can see Jabelar's Particle Modding Tips.

The Recommended Approach


As mentioned in my page on general particle tips, you can't easily use the vanilla particle system because the texture map on the client is not accessible and the IDs used in the packets from the server are not easily extendable.

So my recommendation is to create a class that extends Particle and @Override the updateTick() and renderParticle() method to give yourself full control. The only difficult part is that the renderParticle() method needs to some graphics rendering methods (GLStateManager) so if you're not familiar with that you can copy my sample implementation below.

Important: The updateTick() method runs every game tick (20 times per second) and should be used for any logic that needs to be timed, such as the life of the particle, animation effects, changing the motion. The renderParticle() method runs every screen refresh (which can be typically 60 times per second, but depending on your computer could be anywhere from 30 to 120). You should basically leave that method to code that is specifically related to rendering.

You then have two options. You can create a custom class for every particle, or you can create a generic class that takes in parameters to help with further customization. In the rest of this tutorial, I give an example of a generic class that can be used to create all sorts of particles, including custom textures, animated textures, fade in or out, tint changes, etc.

Example Custom Particle System


Feel free to copy my code, but also please try to understand it! You can literally just copy my ParticleCustom class and then just spawn it as I explain below.

Important: The source code for my ParticleCustom class can be found on my example mod github repository.

Explanation Of The ParticleCustom Implementation


As mentioned, I'd like you to understand the code even if you copy it. So the class consists of the following major aspects:
  • Some fields to help keep track of the customizable settings as well as the progress of the animation.
  • Several alternate public constructors to give you different ways to control the creation. For example, if you don't want to animate it you can use a constructor that doesn't take any animation parameters and it will default to not being animated.
  • An @Override of the updateTick() method. Here I call other methods to help update counters, process gravity and so forth.
  • An @Override of the renderParticle() method. I won't explain it in detail, but the main idea is that it stitches a custom texture asset instead of using the vanilla texture map. It also contains code to process an animation "strip" -- basically a texture that contains a vertical series of images you want to either cycle through or "tween".
  • A private class called TextureDefinition that makes the code a bit more organized by collecting information about the texture (and texture animation) together.

Using The ParticleCustom Class


Warning: You cannot use the vanilla particle spawning methods with your custom particle. For example, you cannot use the WorldServer#spawnParticle() method on the server and you cannot use the ParticleManager#spawnEffectParticle() method on the client. Because these methods need particle IDs which can only be from the vanilla particle ID list.

Instead, with your custom particle:
  • Spawn client-side: If you want to spawn from the client you use ParticleManger#addEffect(). This method takes a Particle parameter directly and since ParticleCustom extends Particle it can be passed in directly too.
  • Spawn server-side: If you want to spawn from the server, you need to send a custom packet with enough information that the client can understand what type of custom particle and other parameters you want, and then again use ParticleManager#addEffect() on the client side.
Tip: If you want to be "lazy" and not worry about which side you're spawning from, I suggest creating a proxy method where your client and server implementations do each of the above respectively.

Features Of The ParticleCustom Class


So I tried to put in a fair amount of control, but keep it sort of simple as well. The basic idea is as follows:

  • Specify a texture: The texture of the particle will come from a PNG file in a /textures/particles/ folder in your assets and the name should match the string you pass into the constructor. Note the texture can be almost any size -- I recommend 64 pixels by 64 pixels as a good size as it has good resolution but won't take up too much memory.
  • Chain methods for other customization: I provide chainable methods to further customize the particle, such as setLifeSpan(), setAlpha(), setTintColor(), etc.
  • (Optionally) set up tween animations: I provide the opportunity to have three types of tweening animation (these can be enabled simultaneously):
    • Color tint. You can set the initial and final tint and it will automatically shift the color during the lifespan of the particle.
    • Alpha fade. You can set the initial and final alpha and it will automatically shift the amount of transparency during the lifespan of the particle.
    • Scale. You can set the inital and final scale and it will automatically shift the amount of size scaling during the lifespan of the particle.
  • (Optionally) set up strip animations: I provide a strip animation system where you can create a texture file that consists of multiple frames in the height (v) dimension of the image file. The animation will start at the top and cycle through the next in each tick. I provide a tween mode for the strip animation where instead of cycling every tick, it divides the lifespan by the number of frames so the animation will only go through once through the lifespan.

Example Spawning A Custom Particle


Let's say you have a simple smiley face texture. You could name it "emoji.png" and put it in your /textures/particles/ folder in your mod assets.

To create the particle so that it is emitted from the top of a block with some random motion and also fading out as it ages you could do the following in the block's randomDisplayTick() method:

    @SideOnly(Side.CLIENT)
    public void randomDisplayTick(IBlockState stateIn, World worldIn, BlockPos pos, Random rand)
    {
        double xPos = pos.getX() + 0.5D;
        double yPos = pos.getY() + 1.0D;
        double zPos = pos.getZ() + 0.5D;
        double xMotion = 0.1D*RANDOM.nextDouble() - 0.05D;
        double yMotion = 0.3D;
        double zMotion = 0.1D*RANDOM.nextDouble() - 0.05D;
        
        Particle theParticle = new ParticleCustom(
                "emoji",
                worldIn, 
                xPos, yPos, zPos, 
                xMotion, yMotion, zMotion)
                .setRotSpeed(((float)Math.random() - 0.5F) * 0.1F)
                .setLifeSpan(20 + rand.nextInt(20))
                .setGravity(0.2F)
                .setScale(2.0F)
                .setInitialAlpha(1.0F)
                .setFinalAlpha(0.0F)
                .setInitalTint(Color.WHITE)
                .setFinalTint(Color.RED);
        Minecraft.getMinecraft().effectRenderer.addEffect(theParticle);
    }

You can see that since this is a client-side method I'm using the ParticleManager#addEffect() method for the spawning. (The effectRenderer is of type ParticleManager.)

We pass a particle instance as a parameter. We construct that particle using our ParticleCustom class and giving it a string name (must match your texture file name!), the initial position and motion. Since this was to come out of the top of a block, I added 0.5D to the x and z and 1.0D to the y position of block itself to get the center of the top.

Then I "chain" a bunch of the setter methods to set things like the alpha fading, how much gravity affects the particle and so forth. Should be pretty self-explanatory.

Conclusion


Custom particles were always something I felt should be easier to mod, so I finally took the time to figure it out. Hopefully this gives you all the tools you need for custom particles. You can either use my example class directly or adapt it to your own needs. Happy modding!




1 comment:

  1. Thank you so much! It actually worked after hours of attempting lol

    ReplyDelete