z offsets

This commit is contained in:
Chris Forbes
2009-12-22 19:13:30 +13:00
parent 3c1ead59fd
commit 3bc97ac0b9
21 changed files with 134 additions and 83 deletions

View File

@@ -65,13 +65,13 @@ namespace OpenRa.Game
get
{
var firstSprite = Render().FirstOrDefault();
if( firstSprite == null )
if( firstSprite.Sprite == null )
return new float2( 0, 0 );
return firstSprite.a.size;
return firstSprite.Sprite.size;
}
}
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
var mods = traits.WithInterface<IRenderModifier>();
var sprites = traits.WithInterface<IRender>().SelectMany(x => x.Render(this));

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using OpenRa.Game.GameRules;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
@@ -60,7 +61,7 @@ namespace OpenRa.Game.Effects
const float height = .1f;
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
if (anim != null)
{
@@ -72,15 +73,15 @@ namespace OpenRa.Game.Effects
if (Projectile.High || Projectile.Arcing)
{
if (Projectile.Shadow)
yield return Tuple.New(anim.Image, pos, 8);
yield return new Renderable(anim.Image, pos, 8);
var at = (float)t / TotalTime();
var highPos = pos - new float2(0, (VisualDest - Src).Length * height * 4 * at * (1 - at));
yield return Tuple.New(anim.Image, highPos, Owner.Palette);
yield return new Renderable(anim.Image, highPos, Owner.Palette);
}
else
yield return Tuple.New(anim.Image, pos, Projectile.UnderWater ? 8 : Owner.Palette);
yield return new Renderable(anim.Image, pos, Projectile.UnderWater ? 8 : Owner.Palette);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
@@ -24,9 +25,9 @@ namespace OpenRa.Game.Effects
public void Tick() { anim.Tick(); }
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
yield return Tuple.New(anim.Image, pos - .5f * anim.Image.size, owner.Palette);
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, owner.Palette);
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
@@ -19,9 +20,9 @@ namespace OpenRa.Game.Effects
public void Tick() { anim.Tick(); }
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
yield return Tuple.New(anim.Image, pos.ToFloat2() - 0.5f * anim.Image.size, 0);
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, 0);
}
public Player Owner { get { return null; } }

View File

@@ -1,11 +1,12 @@
using System.Collections.Generic;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
interface IEffect
{
void Tick();
IEnumerable<Tuple<Sprite, float2, int>> Render();
IEnumerable<Renderable> Render();
}
}

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using OpenRa.Game.GameRules;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
@@ -75,9 +76,9 @@ namespace OpenRa.Game.Effects
// todo: turbo boost vs aircraft
}
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
yield return Tuple.New(anim.Image, Pos - 0.5f * anim.Image.size, 0);
yield return new Renderable(anim.Image, Pos - 0.5f * anim.Image.size, 0);
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
@@ -20,9 +21,9 @@ namespace OpenRa.Game.Effects
anim.Tick();
}
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
yield return Tuple.New(anim.Image, pos.ToFloat2() - .5f * anim.Image.size, 0);
yield return new Renderable(anim.Image, pos - .5f * anim.Image.size, 0);
}
}
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenRa.Game.Graphics;
using OpenRa.Game.Traits;
namespace OpenRa.Game.Effects
{
@@ -26,7 +27,7 @@ namespace OpenRa.Game.Effects
--timeUntilRemove;
}
public IEnumerable<Tuple<Sprite, float2, int>> Render()
public IEnumerable<Renderable> Render()
{
if( from.X < to.X )
return DrawZap( from, to, tesla );
@@ -36,7 +37,7 @@ namespace OpenRa.Game.Effects
return DrawZap( from, to, tesla );
}
static IEnumerable<Tuple<Sprite, float2, int>> DrawZap( int2 from, int2 to, Sequence tesla )
static IEnumerable<Renderable> DrawZap( int2 from, int2 to, Sequence tesla )
{
int2 d = to - from;
if( d.X < 8 )
@@ -45,7 +46,7 @@ namespace OpenRa.Game.Effects
var y = d.Y;
while( y >= prev.Y + 8 )
{
yield return Tuple.New( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), 0 );
yield return new Renderable( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), 0 );
prev.Y += 8;
}
}
@@ -57,26 +58,26 @@ namespace OpenRa.Game.Effects
var y = i * d.Y / d.X;
if( y <= prev.Y - 8 )
{
yield return Tuple.New( tesla.GetSprite( 3 ), (float2)( from + prev - new int2( 8, 16 ) ), 0 );
yield return new Renderable(tesla.GetSprite(3), (float2)(from + prev - new int2(8, 16)), 0);
prev.Y -= 8;
while( y <= prev.Y - 8 )
{
yield return Tuple.New( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 16 ) ), 0 );
yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 16)), 0);
prev.Y -= 8;
}
}
else if( y >= prev.Y + 8 )
{
yield return Tuple.New( tesla.GetSprite( 0 ), (float2)( from + prev - new int2( 8, 8 ) ), 0 );
yield return new Renderable(tesla.GetSprite(0), (float2)(from + prev - new int2(8, 8)), 0);
prev.Y += 8;
while( y >= prev.Y + 8 )
{
yield return Tuple.New( tesla.GetSprite( 2 ), (float2)( from + prev - new int2( 0, 8 ) ), 0 );
yield return new Renderable(tesla.GetSprite(2), (float2)(from + prev - new int2(0, 8)), 0);
prev.Y += 8;
}
}
else
yield return Tuple.New( tesla.GetSprite( 1 ), (float2)( from + prev - new int2( 8, 8 ) ), 0 );
yield return new Renderable(tesla.GetSprite(1), (float2)(from + prev - new int2(8, 8)), 0);
prev.X += 8;
}

View File

@@ -31,18 +31,30 @@ namespace OpenRa.Game.Graphics
}
void DrawSpriteList(RectangleF rect,
IEnumerable<Tuple<Sprite, float2, int>> images)
IEnumerable<Renderable> images)
{
foreach (var image in images)
{
var loc = image.b;
var loc = image.Pos;
if (loc.X > rect.Right || loc.X < rect.Left - image.a.bounds.Width)
if (loc.X > rect.Right || loc.X < rect.Left - image.Sprite.bounds.Width)
continue;
if (loc.Y > rect.Bottom || loc.Y < rect.Top - image.a.bounds.Height)
if (loc.Y > rect.Bottom || loc.Y < rect.Top - image.Sprite.bounds.Height)
continue;
spriteRenderer.DrawSprite(image.a, loc, image.c);
spriteRenderer.DrawSprite(image.Sprite, loc, image.Palette);
}
}
class SpriteComparer : IComparer<Renderable>
{
public int Compare(Renderable x, Renderable y)
{
var result = x.ZOffset.CompareTo(y.ZOffset);
if (result == 0)
result = x.Pos.Y.CompareTo(y.Pos.Y);
return result;
}
}
@@ -50,17 +62,18 @@ namespace OpenRa.Game.Graphics
{
terrainRenderer.Draw(Game.viewport);
var comparer = new SpriteComparer();
var rect = new RectangleF(
Game.viewport.Location.ToPointF(),
new SizeF( Game.viewport.Width, Game.viewport.Height ));
foreach (Actor a in Game.world.Actors.OrderBy(u => u.CenterLocation.Y))
DrawSpriteList(rect, a.Render());
/* todo: cull to screen again */
var renderables = Game.world.Actors.SelectMany(a => a.Render())
.OrderBy(r => r, comparer);
foreach (var a in Game.world.Actors
.Where(u => u.traits.Contains<Traits.RenderWarFactory>())
.Select(u => u.traits.Get<Traits.RenderWarFactory>()))
DrawSpriteList(rect, a.RenderRoof(a.self));
foreach (var r in renderables)
spriteRenderer.DrawSprite(r.Sprite, r.Pos, r.Palette);
foreach (var e in Game.world.Effects)
DrawSpriteList(rect, e.Render());

View File

@@ -164,6 +164,7 @@
<Compile Include="Traits\AttackInfo.cs" />
<Compile Include="Traits\AttackTurreted.cs" />
<Compile Include="Traits\AutoTarget.cs" />
<Compile Include="Traits\BelowUnits.cs" />
<Compile Include="Traits\Building.cs" />
<Compile Include="Traits\Explodes.cs" />
<Compile Include="Traits\ChronoshiftDeploy.cs" />

View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace OpenRa.Game.Traits
{
class BelowUnits : IRenderModifier
{
public BelowUnits(Actor self) { }
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
{
return r.Select(a => a.WithZOffset(-1));
}
}
}

View File

@@ -18,16 +18,16 @@ namespace OpenRa.Game.Traits
remainingUncloakTime = (int)(Rules.General.SubmergeDelay * 60 * 25);
}
public IEnumerable<Tuple<Sprite, float2, int>>
ModifyRender(Actor self, IEnumerable<Tuple<Sprite, float2, int>> rs)
public IEnumerable<Renderable>
ModifyRender(Actor self, IEnumerable<Renderable> rs)
{
if (remainingUncloakTime > 0)
return rs;
if (self.Owner == Game.LocalPlayer)
return rs.Select(a => Tuple.New(a.a, a.b, 8));
return rs.Select(a => a.WithPalette(8));
else
return new Tuple<Sprite, float2, int>[] { };
return new Renderable[] { };
}
public void Tick(Actor self)

View File

@@ -16,7 +16,7 @@ namespace OpenRa.Game.Traits
anim.PlayRepeating("idle");
}
public IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self)
public IEnumerable<Renderable> Render(Actor self)
{
var uog = Game.controller.orderGenerator as UnitOrderGenerator;
if (uog != null && self.Owner == Game.LocalPlayer && uog.selection.Contains(self))

View File

@@ -3,7 +3,7 @@ using OpenRa.Game.Graphics;
namespace OpenRa.Game.Traits
{
class RenderWarFactory : RenderBuilding, INotifyBuildComplete
class RenderWarFactory : IRender, INotifyBuildComplete, INotifyDamage, ITick
{
public Animation roof;
bool doneBuilding;
@@ -12,7 +12,6 @@ namespace OpenRa.Game.Traits
string prefix = "";
public RenderWarFactory(Actor self)
: base(self)
{
this.self = self;
roof = new Animation(self.Info.Image ?? self.Info.Name);
@@ -21,22 +20,19 @@ namespace OpenRa.Game.Traits
public void BuildingComplete( Actor self )
{
doneBuilding = true;
anim.Play( "idle" );
roof.Play( prefix + "idle-top" );
}
public IEnumerable<Tuple<Sprite, float2, int>> RenderRoof(Actor self)
public IEnumerable<Renderable> Render(Actor self)
{
if (doneBuilding)
yield return Tuple.New(roof.Image,
24f * (float2)self.Location, self.Owner.Palette);
yield return new Renderable(roof.Image,
24f * (float2)self.Location, self.Owner.Palette, 2);
}
public override void Tick(Actor self)
public void Tick(Actor self)
{
base.Tick(self);
if (doneBuilding)
roof.Tick();
if (doneBuilding) roof.Tick();
var b = self.Bounds;
if (isOpen && null == Game.UnitInfluence.GetUnitAt(((1/24f) * self.CenterLocation).ToInt2()))
@@ -51,10 +47,8 @@ namespace OpenRa.Game.Traits
roof.PlayThen(prefix + "build-top", () => isOpen = true);
}
public override void Damaged(Actor self, AttackInfo e)
public void Damaged(Actor self, AttackInfo e)
{
base.Damaged(self, e);
if (!e.DamageStateChanged) return;
switch (e.DamageState)
{

View File

@@ -15,7 +15,7 @@ namespace OpenRa.Game.Traits
anims.Add( "", new Animation( self.Info.Image ?? self.Info.Name ) );
}
public virtual IEnumerable<Tuple<Sprite, float2, int>> Render( Actor self )
public virtual IEnumerable<Renderable> Render( Actor self )
{
foreach( var a in anims.Values )
if( a.DisableFunc == null || !a.DisableFunc() )
@@ -46,7 +46,7 @@ namespace OpenRa.Game.Traits
this.DisableFunc = d;
}
public Tuple<Sprite, float2, int> Image( Actor self )
public Renderable Image( Actor self )
{
if( OffsetFunc != null )
return Util.Centered( self, Animation.Image, self.CenterLocation + OffsetFunc() );

View File

@@ -21,16 +21,16 @@ namespace OpenRa.Game.Traits
public void Attacking(Actor self) { DoSurface(); }
public void Damaged(Actor self, AttackInfo e) { DoSurface(); }
public IEnumerable<Tuple<Sprite, float2, int>>
ModifyRender(Actor self, IEnumerable<Tuple<Sprite, float2, int>> rs)
public IEnumerable<Renderable>
ModifyRender(Actor self, IEnumerable<Renderable> rs)
{
if (remainingSurfaceTime > 0)
return rs;
if (self.Owner == Game.LocalPlayer)
return rs.Select(a => Tuple.New(a.a, a.b, 8));
else
return new Tuple<Sprite, float2, int>[] { };
if (self.Owner == Game.LocalPlayer)
return rs.Select(a => a.WithPalette(8));
else
return new Renderable[] { };
}
public void Tick(Actor self)

View File

@@ -10,9 +10,32 @@ namespace OpenRa.Game.Traits
// depends on the order of pips in WorldRenderer.cs!
enum PipType { Transparent, Green, Yellow, Red, Gray };
enum TagType { None, Fake, Primary };
struct Renderable
{
public readonly Sprite Sprite;
public readonly float2 Pos;
public readonly int Palette;
public readonly int ZOffset;
public Renderable(Sprite sprite, float2 pos, int palette, int zOffset)
{
Sprite = sprite;
Pos = pos;
Palette = palette;
ZOffset = zOffset;
}
public Renderable(Sprite sprite, float2 pos, int palette)
: this(sprite, pos, palette, 0) { }
public Renderable WithPalette(int newPalette) { return new Renderable(Sprite, Pos, newPalette, ZOffset); }
public Renderable WithZOffset(int newOffset) { return new Renderable(Sprite, Pos, Palette, newOffset); }
public Renderable WithPos(float2 newPos) { return new Renderable(Sprite, newPos, Palette, ZOffset); }
}
interface ITick { void Tick(Actor self); }
interface IRender { IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self); }
interface IRender { IEnumerable<Renderable> Render(Actor self); }
interface INotifyDamage { void Damaged(Actor self, AttackInfo e); }
interface INotifyBuildComplete { void BuildingComplete (Actor self); }
interface IOrder
@@ -23,8 +46,7 @@ namespace OpenRa.Game.Traits
interface IProducer { bool Produce( Actor self, UnitInfo producee ); }
interface IOccupySpace { IEnumerable<int2> OccupiedCells(); }
interface INotifyAttack { void Attacking(Actor self); }
interface IRenderModifier { IEnumerable<Tuple<Sprite, float2, int>>
ModifyRender( Actor self, IEnumerable<Tuple<Sprite, float2, int>> r ); }
interface IRenderModifier { IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r); }
interface IDamageModifier { float GetDamageModifier(); }
interface ISpeedModifier { float GetSpeedModifier(); }
interface IPips { IEnumerable<PipType> GetPips(); }

View File

@@ -12,9 +12,9 @@ namespace OpenRa.Game.Traits
Image = treeImage;
}
public IEnumerable<Tuple<Sprite, float2, int>> Render(Actor self)
public IEnumerable<Renderable> Render(Actor self)
{
yield return Tuple.New(Image, Game.CellSize * (float2)self.Location, 0);
yield return new Renderable(Image, Game.CellSize * (float2)self.Location, 0);
}
}
}

View File

@@ -117,17 +117,11 @@ namespace OpenRa.Game.Traits
public static float2 RelOffset(this int[] offset) { return new float2(offset[0], offset[1]); }
public static float2 AbsOffset(this int[] offset) { return new float2(offset.ElementAtOrDefault(2), offset.ElementAtOrDefault(3)); }
public static Tuple<Sprite, float2, int> Centered(Actor self, Sprite s, float2 location)
public static Renderable Centered(Actor self, Sprite s, float2 location)
{
var pal = self.Owner == null ? 0 : self.Owner.Palette;
var loc = location - 0.5f * s.size;
return Tuple.New(s, loc.Round(), pal);
}
public static Tuple<Sprite, float2, int> CenteredShadow(Actor self, Sprite s, float2 location)
{
var loc = location - 0.5f * s.size;
return Tuple.New(s, loc.Round(), 8);
return new Renderable(s, loc.Round(), pal);
}
public static float GetEffectiveSpeed(Actor self)

View File

@@ -10,11 +10,14 @@ namespace OpenRa.Game.Traits
{
public WithShadow(Actor self) {}
public IEnumerable<Tuple<Sprite, float2, int>> ModifyRender(Actor self, IEnumerable<Tuple<Sprite, float2, int>> r)
public IEnumerable<Renderable> ModifyRender(Actor self, IEnumerable<Renderable> r)
{
var unit = self.traits.Get<Unit>();
var shadowSprites = r.Select( a => Tuple.New( a.a, a.b, 8 ));
var flyingSprites = r.Select( a => Tuple.New( a.a, a.b - new float2( 0, unit.Altitude ), a.c ));
var shadowSprites = r.Select(a => a.WithPalette(8));
var flyingSprites = (unit.Altitude <= 0) ? r
: r.Select(a => a.WithPos(a.Pos - new float2(0, unit.Altitude)).WithZOffset(3));
return shadowSprites.Concat(flyingSprites);
}
}

View File

@@ -331,7 +331,7 @@ SelectionPriority=3
LongDesc=Provides Allied advanced technologies.\n Special Ability: GPS Satellite
[WEAP]
Description=War Factory
Traits=Building, RenderWarFactory, RallyPoint, Production
Traits=Building, RenderBuilding, RenderWarFactory, RallyPoint, Production
Dimensions=3,2
Footprint=xxx xxx
Produces=Vehicle
@@ -381,12 +381,12 @@ LongDesc=Stores excess harvested Ore
[HPAD]
Description=Helipad
Traits=Building, RenderBuilding, Production
Traits=Building, RenderBuilding, Production, BelowUnits
Dimensions=2,2
Footprint=xx xx
Produces=Plane
SelectionPriority=3
SpawnOffset=0,0 ; todo: push this up a bit, but we've got a z-order issue first.
SpawnOffset=0,-4 ; todo: push this up a bit, but we've got a z-order issue first.
LongDesc=Produces and reloads helicopters
[DOME]
Description=Radar Dome
@@ -397,7 +397,7 @@ SelectionPriority=3
LongDesc=Provides an overview of the battlefield.\n Requires power to operate.
[AFLD]
Description=Airstrip
Traits=Building, RenderBuilding, Production
Traits=Building, RenderBuilding, Production, BelowUnits
Dimensions=3,2
Footprint=xxx xxx
Produces=Plane
@@ -452,7 +452,7 @@ SelectionPriority=3
LongDesc=Produces attack dogs
[FIX]
Description=Service Depot
Traits=Building, RenderBuilding
Traits=Building, RenderBuilding, BelowUnits
Dimensions=3,3
Footprint=_x_ xxx _x_
SelectionPriority=3
@@ -466,7 +466,7 @@ SelectionPriority=3
LongDesc=Looks like a Construction Yard.
[WEAF]
Description=Fake War Factory
Traits=Building, RenderWarFactory, Fake
Traits=Building, RenderBuilding, RenderWarFactory, Fake
Dimensions=3,2
Footprint=xxx xxx
SelectionPriority=3