Hi, @happygrass_cn first of all welcome in the plugincafe community.
While you have deleted your topic (probably because you solved it). I had a solution that explores a few areas in Cinema 4D that are not so well documented so I restored it.
So my solution uses a cloner with 2 clones (one animated and the other one similar but without animation).
I also define a thinking particle channel data( a boolean "isMoving").
A python effector will read this attribute and according to this attribute will affect the displayed cloned object to be either the animated one or not.
Of course, this does not provide interpolation between animation so it can look a bit odd.
Finally in Python SetPData does not support boolean, so "IsMoving" is not a boolean (DTYPE_BOOL) but an integer(DTYPE_LONG) that I thread as a boolean.
The Python generator does the next things:
Thinking Particles Creation. Custom Data Channel Creation/Assignation. Movement of particles. import c4d def GetParticleSystemAndRootGroup(): # Retrieves the Particles System of the current document pSys = doc.GetParticleSystem() if pSys is None: raise RuntimeError("op is none, please select one object.") # Retrieves the Root group (where all particles belongs as default) rootGrp = pSys.GetRootGroup() if rootGrp is None: raise RuntimeError("Failed to retrieve root group of tp master system.") return pSys, rootGrp def GetIsMovingChannelId(): # Retrieves the Particles System and the root group of the current document pSys, rootGrp = GetParticleSystemAndRootGroup() for x in xrange(pSys.NumDataChannels()): if pSys.DataChannelName(x) == "isMoving(Integer)": return x return False def CreateParticle(count): # Retrieves the Particles System and the root group of the current document pSys, rootGrp = GetParticleSystemAndRootGroup() if pSys.NumParticles() >= count: return # Allows each particles to get a custom colors rootGrp[c4d.PGROUP_USE_COLOR] = False # Creates 90 Particles particlesIds = pSys.AllocParticles(count) if not particlesIds: raise RuntimeError("Failed to create X TP particles.") # Check if the "isMoving"" Channel data already exist and if not create it # This Boolean "isMoving" will store the moving state of a particle if GetIsMovingChannelId() is False: pSys.AddDataChannel(c4d.DTYPE_LONG, "isMoving") isMovingId = GetIsMovingChannelId() if isMovingId is False: raise RuntimeError("Failed to retrieve IsMoving particle Data") # Assigns position and colors for each particles for particleId in particlesIds: # Checks if particles ID is ok if particleId == c4d.NOTOK: continue # Defines a lifetime of 1000 frame for each particles pSys.SetLife(particleId, c4d.BaseTime(1000)) # Calculates a position sin, cos = c4d.utils.SinCos(particleId) pos = c4d.Vector(sin * 300.0, cos * 300.0, particleId * 30.0) # Assigns position pSys.SetPosition(particleId, pos) # Calculates a color hsv = c4d.Vector(float(particleId) * 1.0 / count, 1.0, 1.0) rgb = c4d.utils.HSVToRGB(hsv) # Assigns color pSys.SetColor(particleId, rgb) # Assigns a "freeze" data to indicate either the particle is stoped or not pSys.SetPData(particleId, isMovingId, False) return particlesIds def MoveParticle(frame): # Retrieves the Particles System and the root group of the current document pSys, rootGrp = GetParticleSystemAndRootGroup() isMovingId = GetIsMovingChannelId() if isMovingId is False: raise RuntimeError("Failed to retrieve IsMoving particle Data") for particleId in xrange(pSys.NumParticles()): # If particle don't belong to the root group if pSys.Group(particleId) != rootGrp: continue sin, cos = c4d.utils.SinCos(particleId + (frame/40.00)) pos = c4d.Vector(sin * 300.0, cos * 300.0, particleId * 30.0) # Assigns position pSys.SetPosition(particleId, pos) # Assigns a "freeze" data to indicate either the particle is stoped or not pSys.SetPData(particleId, isMovingId, True) def FreezeParticle(): # Retrieves the Particles System and the root group of the current document pSys, rootGrp = GetParticleSystemAndRootGroup() isMovingId = GetIsMovingChannelId() if isMovingId is False: raise RuntimeError("Failed to retrieve IsMoving particle Data") for particleId in xrange(pSys.NumParticles()): # If particle don't belong to the root group if pSys.Group(particleId) != rootGrp: continue # Assigns a "freeze" data to indicate either the particle is stoped or not pSys.SetPData(particleId, isMovingId, 0) def main(): currentFrame = doc.GetTime().GetFrame(doc.GetFps()) if currentFrame == 0: CreateParticle(20) # Don't move particles from frame 150 to 250 elif 150 <= currentFrame <= 250: if currentFrame == 150: FreezeParticle() else: MoveParticle(currentFrame)The Python Effector set in Full Control does the next things:
Read the data for each particle of the Custom Data Channel Defines the cloned used according to this value import c4d def GetParticleSystemAndRootGroup(): # Retrieves the Particles System of the current document pSys = doc.GetParticleSystem() if pSys is None: raise RuntimeError("op is none, please select one object.") # Retrieves the Root group (where all particles belongs as default) rootGrp = pSys.GetRootGroup() if rootGrp is None: raise RuntimeError("Failed to retrieve root group of tp master system.") return pSys, rootGrp def GetIsMovingChannelId(): # Retrieves the Particles System and the root group of the current document pSys, rootGrp = GetParticleSystemAndRootGroup() for x in xrange(pSys.NumDataChannels()): if pSys.DataChannelName(x) == "isMoving(Integer)": return x return False def main() : moData = c4d.modules.mograph.GeGetMoData(op) if moData is None: return False cnt = moData.GetCount() mdClone = moData.GetArray(c4d.MODATA_CLONE) hasField = op[c4d.FIELDS].HasContent() # Retrieves the Particles System and the root group of the current document pSys, rootGrp = GetParticleSystemAndRootGroup() # Retrieve the isMovingData channel ID isMovingId = GetIsMovingChannelId() if isMovingId is False: raise RuntimeError("Failed to retrieve IsMoving particle Data") # Maybe there is more particles allocated than what's is used in the cloner (aka mutlipe particle group) # So we loop over them cloneId = 0 for particleId in xrange(pSys.NumParticles()): # If particle don't belong to the root group if pSys.Group(particleId) != rootGrp: continue if cloneId > cnt: raise RuntimeError("There is more cloneID than allowed") # Retrieve the internal IsMoving Data and check if the particle is moving, isMoving = pSys.GetPData(particleId, isMovingId) if isMoving == 1: # Defines the float value representing the cloned 0 = First child, 1 = last child mdClone[cloneId] = 0.0 else: mdClone[cloneId] = 1.0 cloneId +=1 moData.SetArray(c4d.MODATA_CLONE, mdClone, hasField) return TrueAnd the attached scene with everything together.
generatorTp.c4d
Cheers,
Maxime.