Skip to content

Commit

Permalink
Merge PR #3001 by @skaldarnar - particle effect tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
Cervator committed Jul 18, 2017
2 parents fc59e47 + e913e7e commit 4cea875
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 33 deletions.
Expand Up @@ -18,6 +18,7 @@
import org.terasology.audio.AudioManager;
import org.terasology.audio.StaticSound;
import org.terasology.audio.events.PlaySoundEvent;
import org.terasology.entitySystem.entity.EntityBuilder;
import org.terasology.entitySystem.entity.EntityManager;
import org.terasology.entitySystem.entity.EntityRef;
import org.terasology.entitySystem.event.EventPriority;
Expand Down Expand Up @@ -155,6 +156,14 @@ private void commonDestroyed(DoDestroyEvent event, EntityRef entity, Block block
BlockDamageModifierComponent blockDamageModifierComponent = event.getDamageType().getComponent(BlockDamageModifierComponent.class);
// TODO: Configurable via block definition
if (blockDamageModifierComponent == null || !blockDamageModifierComponent.skipPerBlockEffects) {
// dust particle effect
if (entity.hasComponent(LocationComponent.class) && block.isDebrisOnDestroy()) {
EntityBuilder dustBuilder = entityManager.newBuilder("core:dustEffect");
dustBuilder.getComponent(LocationComponent.class).setWorldPosition(entity.getComponent(LocationComponent.class).getWorldPosition());
dustBuilder.build();
}

// sound to play for destroyed block
BlockSounds sounds = block.getSounds();
if (!sounds.getDestroySounds().isEmpty()) {
StaticSound sound = random.nextItem(sounds.getDestroySounds());
Expand Down
Expand Up @@ -12,7 +12,7 @@
"maxVelocity": [1.5, 4, 1.5]
},
"scaleRangeGenerator": {
"minScale": [0.2, 0.2, 0.2],
"minScale": [0.1, 0.1, 0.1],
"maxScale": [0.2, 0.2, 0.2]
},
"textureOffsetGenerator": {},
Expand Down
Expand Up @@ -27,6 +27,7 @@
import org.terasology.entitySystem.systems.RegisterSystem;
import org.terasology.logic.characters.events.AttackEvent;
import org.terasology.logic.location.LocationComponent;
import org.terasology.math.TeraMath;
import org.terasology.math.geom.Vector2f;
import org.terasology.math.geom.Vector3f;
import org.terasology.particles.components.ParticleDataSpriteComponent;
Expand All @@ -37,6 +38,7 @@
import org.terasology.utilities.random.FastRandom;
import org.terasology.utilities.random.Random;
import org.terasology.world.block.Block;
import org.terasology.world.block.BlockAppearance;
import org.terasology.world.block.BlockComponent;
import org.terasology.world.block.BlockManager;
import org.terasology.world.block.BlockPart;
Expand All @@ -46,7 +48,12 @@
import org.terasology.world.block.sounds.BlockSounds;
import org.terasology.world.block.tiles.WorldAtlas;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
* This system is responsible for giving blocks health when they are attacked and damaging them instead of destroying them.
Expand Down Expand Up @@ -101,10 +108,9 @@ public void onDamaged(OnDamagedEvent event, EntityRef entity, ActAsBlockComponen
if (blockComponent.block != null) {
onDamagedCommon(event, blockComponent.block, locComp.getWorldPosition(), entity);
}

}

public void onDamagedCommon(OnDamagedEvent event, BlockFamily blockFamily, Vector3f location, EntityRef entityRef) {
private void onDamagedCommon(OnDamagedEvent event, BlockFamily blockFamily, Vector3f location, EntityRef entityRef) {
BlockDamageModifierComponent blockDamageSettings = event.getType().getComponent(BlockDamageModifierComponent.class);
boolean skipDamageEffects = false;
if (blockDamageSettings != null) {
Expand All @@ -116,49 +122,71 @@ public void onDamagedCommon(OnDamagedEvent event, BlockFamily blockFamily, Vecto
}

private void onPlayBlockDamageCommon(BlockFamily family, Vector3f location, EntityRef entityRef) {
Optional<Texture> terrainTexture = Assets.getTexture("engine:terrain");
if (!terrainTexture.isPresent() || !terrainTexture.get().isLoaded()) {
return;
createBlockParticleEffect(family, location);

BlockSounds sounds = family.getArchetypeBlock().getSounds();
if (!sounds.getDigSounds().isEmpty()) {
StaticSound sound = random.nextItem(sounds.getDigSounds());
entityRef.send(new PlaySoundEvent(sound, 1f));
}
}

/**
* Creates a new entity for the block damage particle effect.
*
* If the terrain texture of the damaged block is available, the particles will have the block texture. Otherwise,
* the default sprite (smoke) is used.
*
* @param family the {@link BlockFamily} of the damaged block
* @param location the location of the damaged block
*/
private void createBlockParticleEffect(BlockFamily family, Vector3f location) {
EntityBuilder builder = entityManager.newBuilder("core:defaultBlockParticles");
builder.getComponent(LocationComponent.class).setWorldPosition(location);
ParticleDataSpriteComponent spriteComponent = builder.getComponent(ParticleDataSpriteComponent.class);
TextureOffsetGeneratorComponent textureOffsetGeneratorComponent = builder.getComponent(TextureOffsetGeneratorComponent.class);

spriteComponent.texture = terrainTexture.get();
Optional<Texture> terrainTexture = Assets.getTexture("engine:terrain");
if (terrainTexture.isPresent() && terrainTexture.get().isLoaded()) {
final BlockAppearance blockAppearance = family.getArchetypeBlock().getPrimaryAppearance();

final float tileSize = worldAtlas.getRelativeTileSize();
spriteComponent.textureSize.set(tileSize, tileSize);
final float relativeTileSize = worldAtlas.getRelativeTileSize();
final float particleScale = 0.25f;

Block b = blockManager.getBlock(family.getURI().toString()).getBlockFamily().getArchetypeBlock();
Vector2f offset = b.getPrimaryAppearance().getTextureAtlasPos(BlockPart.FRONT);
final float spriteSize = relativeTileSize * particleScale;

final float relTileSize = worldAtlas.getRelativeTileSize();
Vector2f particleTexSize = new Vector2f(
relTileSize * 0.25f,
relTileSize * 0.25f);
ParticleDataSpriteComponent spriteComponent = builder.getComponent(ParticleDataSpriteComponent.class);
spriteComponent.texture = terrainTexture.get();
spriteComponent.textureSize.set(spriteSize, spriteSize);

spriteComponent.textureSize.x *= 0.25f;
spriteComponent.textureSize.y *= 0.25f;
final List<Vector2f> offsets = computeOffsets(blockAppearance, particleScale);

textureOffsetGeneratorComponent.validOffsets.add(new Vector2f(
offset.x + random.nextFloat() * (tileSize - particleTexSize.x),
offset.y + random.nextFloat() * (tileSize - particleTexSize.y)));
TextureOffsetGeneratorComponent textureOffsetGeneratorComponent = builder.getComponent(TextureOffsetGeneratorComponent.class);
textureOffsetGeneratorComponent.validOffsets.addAll(offsets);
}

builder.build();
}

if (family.getArchetypeBlock().isDebrisOnDestroy()) {
EntityBuilder dustBuilder = entityManager.newBuilder("core:dustEffect");
dustBuilder.getComponent(LocationComponent.class).setWorldPosition(location);
dustBuilder.build();
}

BlockSounds sounds = family.getArchetypeBlock().getSounds();
if (!sounds.getDigSounds().isEmpty()) {
StaticSound sound = random.nextItem(sounds.getDigSounds());
entityRef.send(new PlaySoundEvent(sound, 1f));
}
/**
* Computes n random offset values for each block part texture.
*
* @param blockAppearance the block appearance information to generate offsets from
* @param scale the scale of the texture area (should be in 0 < scale <= 1.0)
*
* @return a list of random offsets sampled from all block parts
*/
private List<Vector2f> computeOffsets(BlockAppearance blockAppearance, float scale) {
final float relativeTileSize = worldAtlas.getRelativeTileSize();
final int absoluteTileSize = worldAtlas.getTileSize();
final float pixelSize = relativeTileSize / absoluteTileSize;
final int spriteWidth = TeraMath.ceilToInt(scale * absoluteTileSize);

final Stream<Vector2f> baseOffsets = Arrays.stream(BlockPart.sideValues()).map(blockAppearance::getTextureAtlasPos);

return baseOffsets.flatMap(baseOffset ->
IntStream.range(0, 8).boxed().map(i ->
new Vector2f(baseOffset).add(random.nextInt(absoluteTileSize - spriteWidth) * pixelSize, random.nextInt(absoluteTileSize - spriteWidth) * pixelSize)
)
).collect(Collectors.toList());
}

@ReceiveEvent(netFilter = RegisterMode.AUTHORITY)
Expand Down

0 comments on commit 4cea875

Please sign in to comment.