mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-10-02 11:10:50 +03:00
Add lifeRnd and extraLife for Weapons and more (#11477)
* lifeRnd and extraLife like velocityRnd and extraVelocity but with bullet lifetimes. random is applied before the scaling with scaleLife. * Update contributors * particle aspect ratio system * fix bug * seperate fin and color fin * Update ParticleEffect.java * New Triangle effect i'm trying my best bro * ok i found the bug and i fixed it * bug squashed 2 * addede extraLife and lifeRnd, and extraVelocity for turrets * Okay okay, one last change. --------- Co-authored-by: Anuken <arnukren@gmail.com>
This commit is contained in:
@@ -194,8 +194,9 @@ Jovinull
|
||||
Alon
|
||||
硫缺铅/PyratiteNoLead
|
||||
Space
|
||||
DeterMination
|
||||
rylid-umil
|
||||
NeilGreenFly
|
||||
DeterMination
|
||||
Sunky.MP3G
|
||||
jhonnata.andre
|
||||
Zaxerf1234
|
||||
Zaxerf1234
|
||||
|
||||
@@ -14,8 +14,11 @@ public class ParticleEffect extends Effect{
|
||||
private static final Rand rand = new Rand();
|
||||
private static final Vec2 rv = new Vec2();
|
||||
|
||||
/** Particle color. */
|
||||
public Color colorFrom = Color.white.cpy(), colorTo = Color.white.cpy();
|
||||
/** Number of particles created. */
|
||||
public int particles = 6;
|
||||
/** If true, the particle's length is set in a random range from 0 to length. */
|
||||
public boolean randLength = true;
|
||||
/** Gives the effect flipping compatability like casing effects. */
|
||||
public boolean casingFlip;
|
||||
@@ -24,8 +27,13 @@ public class ParticleEffect extends Effect{
|
||||
public Interp interp = Interp.linear;
|
||||
/** Particle size interpolation. Null to use interp. */
|
||||
public @Nullable Interp sizeInterp = null;
|
||||
/** Particle color interpolation. Null to use interp. */
|
||||
public @Nullable Interp colorInterp = null;
|
||||
/** Offset position of the particle. */
|
||||
public float offsetX, offsetY;
|
||||
/** Particle light properties. */
|
||||
public float lightScl = 2f, lightOpacity = 0.6f;
|
||||
/** Color of the light each particle emits. */
|
||||
public @Nullable Color lightColor;
|
||||
|
||||
//region only
|
||||
@@ -36,12 +44,22 @@ public class ParticleEffect extends Effect{
|
||||
public float sizeFrom = 2f, sizeTo = 0f;
|
||||
/** Controls the amount of ticks the effect waits before changing size. */
|
||||
public float sizeChangeStart = 0f;
|
||||
/** Controls the amount of ticks the effect waits before changing width. */
|
||||
public float widthChangeStart = 0f;
|
||||
/** Controls the amount of ticks the effect waits before changing height. */
|
||||
public float heightChangeStart = 0f;
|
||||
/** Whether the rotation adds with the parent */
|
||||
public boolean useRotation = true;
|
||||
/** Rotation offset. */
|
||||
public float offset = 0;
|
||||
/** Sprite to draw. */
|
||||
public String region = "circle";
|
||||
/** Particle width and height properties as a ratio of its radius. Does nothing to line particles. */
|
||||
public float widthFrom = 1f, widthTo = 1f, heightFrom = 1f, heightTo = 1f;
|
||||
/** Particle width interpolation. Null to use sizeInterp. */
|
||||
public @Nullable Interp widthInterp = null;
|
||||
/** Particle height interpolation. Null to use sizeInterp. */
|
||||
public @Nullable Interp heightInterp = null;
|
||||
|
||||
//line only
|
||||
public boolean line;
|
||||
@@ -55,6 +73,9 @@ public class ParticleEffect extends Effect{
|
||||
clip = Math.max(clip, length + Math.max(sizeFrom, sizeTo));
|
||||
sizeChangeStart = Mathf.clamp(sizeChangeStart, 0f, lifetime);
|
||||
if(sizeInterp == null) sizeInterp = interp;
|
||||
if(widthInterp == null) widthInterp = sizeInterp;
|
||||
if(heightInterp == null) heightInterp = sizeInterp;
|
||||
if(colorInterp == null) colorInterp = interp;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,10 +86,13 @@ public class ParticleEffect extends Effect{
|
||||
int flip = casingFlip ? -Mathf.sign(e.rotation) : 1;
|
||||
float rawfin = e.fin();
|
||||
float fin = e.fin(interp);
|
||||
float colFin = e.fin(colorInterp);
|
||||
float rad = sizeInterp.apply(sizeFrom, sizeTo, Mathf.curve(rawfin, sizeChangeStart / lifetime, 1f)) * 2;
|
||||
float width = rad * (widthInterp.apply(widthFrom, widthTo, Mathf.curve(rawfin, widthChangeStart / lifetime, 1f)) * 2);
|
||||
float height = rad * (heightInterp.apply(heightFrom, heightTo, Mathf.curve(rawfin, heightChangeStart / lifetime, 1f)) * 2);
|
||||
float ox = e.x + Angles.trnsx(realRotation, offsetX * flip, offsetY), oy = e.y + Angles.trnsy(realRotation, offsetX * flip, offsetY);
|
||||
|
||||
Draw.color(colorFrom, colorTo, fin);
|
||||
Draw.color(colorFrom, colorTo, colFin);
|
||||
Color lightColor = this.lightColor == null ? Draw.getColor() : this.lightColor;
|
||||
|
||||
if(line){
|
||||
@@ -91,7 +115,7 @@ public class ParticleEffect extends Effect{
|
||||
rv.trns(realRotation + rand.range(cone), !randLength ? l : rand.random(l));
|
||||
float x = rv.x, y = rv.y;
|
||||
|
||||
Draw.rect(tex, ox + x, oy + y, rad, rad / tex.ratio(), realRotation + offset + e.time * spin);
|
||||
Draw.rect(tex, ox + x, oy + y, width, height / tex.ratio(), realRotation + offset + e.time * spin);
|
||||
Drawf.light(ox + x, oy + y, rad * lightScl, lightColor, lightOpacity * Draw.getColorAlpha());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
package mindustry.entities.effect;
|
||||
|
||||
import arc.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.util.*;
|
||||
import mindustry.entities.*;
|
||||
import mindustry.graphics.*;
|
||||
|
||||
/** Creates a triangle with heavily customizable parameters. */
|
||||
public class TriangleEffect extends Effect{
|
||||
private static final Rand rand = new Rand();
|
||||
|
||||
/** Triangle color. */
|
||||
public Color colorFrom = Color.white.cpy(), colorTo = Color.white.cpy();
|
||||
/** Gives the effect flipping compatability like casing effects. */
|
||||
public boolean flippable;
|
||||
/** Triangle position interpolation. Also used as a fallback.*/
|
||||
public Interp interp = Interp.linear;
|
||||
/** Width interpolation. Null to use interp. */
|
||||
public @Nullable Interp widthInterp = null;
|
||||
/** Height interpolation. Null to use interp. */
|
||||
public @Nullable Interp heightInterp = null;
|
||||
/** Triangle color interpolation. Null to use interp. */
|
||||
public @Nullable Interp colorInterp = null;
|
||||
/** Controls the starting and ending positions of the triangle. */
|
||||
public float startX = 0, startY = 0, endX = 0, endY = 0;
|
||||
/** Triangle light properties. */
|
||||
public float lightScl = 8f, lightOpacityFrom = 0.6f, lightOpacityTo = 0f;
|
||||
/** Color of the light the triangle emits. */
|
||||
public @Nullable Color lightColor;
|
||||
|
||||
/** Controls the initial and final positions of each point on the triangle. */
|
||||
public float widthFrom = 4f, widthTo = 0f, heightFrom = 4f, heightTo = 4f;
|
||||
/** Whether the rotation adds with the parent */
|
||||
public boolean useRotation = true;
|
||||
/** Spin in degrees/tick. */
|
||||
public int spin = 0;
|
||||
/** Rotation offset. */
|
||||
public float offset = 0;
|
||||
|
||||
@Override
|
||||
public void init(){
|
||||
if(widthInterp == null) widthInterp = interp;
|
||||
if(heightInterp == null) heightInterp = interp;
|
||||
if(colorInterp == null) colorInterp = interp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(EffectContainer e){
|
||||
float realRotation = (useRotation ? (flippable ? Math.abs(e.rotation) : e.rotation) : baseRotation);
|
||||
int flip = flippable ? -Mathf.sign(e.rotation) : 1;
|
||||
float rawfin = e.fin();
|
||||
float colFin = e.fin(interp);
|
||||
float width = widthInterp.apply(widthFrom, widthTo, Mathf.curve(rawfin, 0, 1f));
|
||||
float height = heightInterp.apply(heightFrom, heightTo, Mathf.curve(rawfin, 0, 1f));
|
||||
float lightOpac = colorInterp.apply(lightOpacityFrom, lightOpacityTo, Mathf.curve(rawfin, 0, 1f));
|
||||
|
||||
float cx = interp.apply(startX, endX, Mathf.curve(rawfin, 0, 1f));
|
||||
float cy = interp.apply(startY, endY, Mathf.curve(rawfin, 0, 1f));
|
||||
Vec2 pos = new Vec2(cx, cy);
|
||||
pos.rotate(realRotation);
|
||||
|
||||
Draw.color(colorFrom, colorTo, colFin);
|
||||
Color lightColor = this.lightColor == null ? Draw.getColor() : this.lightColor;
|
||||
|
||||
Drawf.tri(pos.x + e.x, pos.y + e.y, width, height, realRotation + offset + e.time * spin);
|
||||
Drawf.light(pos.x + e.x, pos.y + e.y, lightScl, lightColor, lightOpac * Draw.getColorAlpha());
|
||||
}
|
||||
}
|
||||
@@ -101,6 +101,10 @@ public class Weapon implements Cloneable{
|
||||
public float velocityRnd = 0f;
|
||||
/** extra velocity that is added as a fraction */
|
||||
public float extraVelocity = 0f;
|
||||
/** fraction of lifetime that is random */
|
||||
public float lifeRnd = 0f;
|
||||
/** extra lifetime that is added as a fraction */
|
||||
public float extraLife = 0f;
|
||||
/** The half-radius of the cone in which shooting will start. */
|
||||
public float shootCone = 5f;
|
||||
/** Cone in which the weapon can rotate relative to its mount. */
|
||||
@@ -117,8 +121,10 @@ public class Weapon implements Cloneable{
|
||||
public boolean ignoreRotation = false;
|
||||
/** If true, this weapon cannot be used to attack targets. */
|
||||
public boolean noAttack = false;
|
||||
/** min velocity required for this weapon to shoot */
|
||||
/** min velocity required for this weapon to shoot. -1 to disable the limit. */
|
||||
public float minShootVelocity = -1f;
|
||||
/** max velocity at which this weapon to shoot. -1 to disable the limit. */
|
||||
public float maxShootVelocity = -1f;
|
||||
/** should the shoot effects follow the unit (effects need followParent set to true for this to work) */
|
||||
public boolean parentizeEffects;
|
||||
/** internal value used for alternation - do not change! */
|
||||
@@ -434,7 +440,7 @@ public class Weapon implements Cloneable{
|
||||
!(bullet.killShooter && mount.totalShots > 0) && //if the bullet kills the shooter, you should only ever be able to shoot once
|
||||
(!alternate || wasFlipped == flipSprite) &&
|
||||
mount.warmup >= minWarmup && //must be warmed up
|
||||
velLen >= minShootVelocity && //check velocity requirements
|
||||
velLen >= minShootVelocity && (maxShootVelocity == -1 || velLen <= maxShootVelocity) && //check velocity requirements
|
||||
(mount.reload <= 0.0001f || (alwaysContinuous && mount.bullet == null)) && //reload has to be 0, or it has to be an always-continuous weapon
|
||||
(alwaysShooting || Angles.within(rotate ? mount.rotation : unit.rotation + baseRotation, mount.targetRotation, shootCone)) //has to be within the cone
|
||||
){
|
||||
@@ -497,7 +503,8 @@ public class Weapon implements Cloneable{
|
||||
bulletX = mountX + Angles.trnsx(weaponRotation, this.shootX + xOffset + xSpread, this.shootY + yOffset + ySpread),
|
||||
bulletY = mountY + Angles.trnsy(weaponRotation, this.shootX + xOffset + xSpread, this.shootY + yOffset + ySpread),
|
||||
shootAngle = bulletRotation(unit, mount, bulletX, bulletY) + angleOffset,
|
||||
lifeScl = bullet.scaleLife ? Mathf.clamp(Mathf.dst(bulletX, bulletY, mount.aimX, mount.aimY) / bullet.range) : 1f,
|
||||
baseLife = (1f - lifeRnd) + Mathf.random(lifeRnd) + extraLife,
|
||||
lifeScl = bullet.scaleLife ? baseLife * Mathf.clamp(Mathf.dst(bulletX, bulletY, mount.aimX, mount.aimY) / bullet.range) : baseLife,
|
||||
angle = shootAngle + Mathf.range(inaccuracy + bullet.inaccuracy);
|
||||
|
||||
Entityc shooter = unit.controller() instanceof MissileAI ai ? ai.shooter : unit; //Pass the missile's shooter down to its bullets
|
||||
|
||||
@@ -58,6 +58,12 @@ public class Turret extends ReloadTurret{
|
||||
public float inaccuracy = 0f;
|
||||
/** Fraction of bullet velocity that is random. */
|
||||
public float velocityRnd = 0f;
|
||||
/** extra velocity that is added as a fraction */
|
||||
public float extraVelocity = 0f;
|
||||
/** fraction of lifetime that is random */
|
||||
public float lifeRnd = 0f;
|
||||
/** extra lifetime that is added as a fraction */
|
||||
public float extraLife = 0f;
|
||||
/** Fraction of lifetime that is added to bullets with lifeScale. */
|
||||
public float scaleLifetimeOffset = 0f;
|
||||
/** Maximum angle difference in degrees at which turret will still try to shoot. */
|
||||
@@ -785,11 +791,12 @@ public class Turret extends ReloadTurret{
|
||||
bulletX = x + Angles.trnsx(rotation - 90, shootX + xOffset + xSpread, shootY + yOffset),
|
||||
bulletY = y + Angles.trnsy(rotation - 90, shootX + xOffset + xSpread, shootY + yOffset),
|
||||
shootAngle = rotation + angleOffset + Mathf.range(inaccuracy + type.inaccuracy);
|
||||
|
||||
float lifeScl = type.scaleLife ? Mathf.clamp((1 + scaleLifetimeOffset) * Mathf.dst(bulletX, bulletY, targetPos.x, targetPos.y) / type.range, minRange() / type.range, range() / type.range) : 1f;
|
||||
|
||||
float baseLife = (1f - lifeRnd) + Mathf.random(lifeRnd) + extraLife,
|
||||
lifeScl = type.scaleLife ? Mathf.clamp((baseLife + scaleLifetimeOffset) * Mathf.dst(bulletX, bulletY, targetPos.x, targetPos.y) / type.range, minRange() / type.range, range() / type.range) : baseLife;
|
||||
|
||||
//TODO aimX / aimY for multi shot turrets?
|
||||
handleBullet(type.create(this, team, bulletX, bulletY, shootAngle, -1f, (1f - velocityRnd) + Mathf.random(velocityRnd), lifeScl, null, mover, targetPos.x, targetPos.y), xOffset, yOffset, shootAngle - rotation);
|
||||
handleBullet(type.create(this, team, bulletX, bulletY, shootAngle, -1f, (1f - velocityRnd) + Mathf.random(velocityRnd) + extraVelocity, lifeScl, null, mover, targetPos.x, targetPos.y), xOffset, yOffset, shootAngle - rotation);
|
||||
|
||||
(shootEffect == null ? type.shootEffect : shootEffect).at(bulletX, bulletY, rotation + angleOffset, type.hitColor);
|
||||
(smokeEffect == null ? type.smokeEffect : smokeEffect).at(bulletX, bulletY, rotation + angleOffset, type.hitColor);
|
||||
|
||||
Reference in New Issue
Block a user