diff --git a/OpenRa.Game/Actor.cs b/OpenRa.Game/Actor.cs index 76dbd858af..9461c977d8 100755 --- a/OpenRa.Game/Actor.cs +++ b/OpenRa.Game/Actor.cs @@ -45,12 +45,12 @@ namespace OpenRa.Game case "1tnk": case "2tnk": case "3tnk": - case "4tnk": - traits.Add( new Traits.Mobile( this ) ); - traits.Add( new Traits.Turreted( this ) ); - traits.Add( new Traits.AttackTurreted( this ) ); - traits.Add( new Traits.RenderUnitTurreted( this ) ); - break; + case "4tnk": + traits.Add( new Traits.Mobile( this ) ); + traits.Add( new Traits.Turreted( this ) ); + traits.Add( new Traits.AttackTurreted( this ) ); + traits.Add( new Traits.RenderUnitTurreted( this ) ); + break; case "mrj": case "mgg": // TODO: these aren't actually turreted; they just have spinning-things diff --git a/OpenRa.Game/Game.cs b/OpenRa.Game/Game.cs index a9e6f4d2c0..508aaa73ec 100644 --- a/OpenRa.Game/Game.cs +++ b/OpenRa.Game/Game.cs @@ -1,20 +1,20 @@ using System.Collections.Generic; -using OpenRa.FileFormats; -using OpenRa.Game.Graphics; -using OpenRa.TechTree; -using System.Drawing; -using System.Linq; -using IrrKlang; +using OpenRa.FileFormats; +using OpenRa.Game.Graphics; +using OpenRa.TechTree; +using System.Drawing; +using System.Linq; +using IrrKlang; using IjwFramework.Collections; namespace OpenRa.Game { class Game - { + { public static readonly int CellSize = 24; public readonly World world; - public readonly Map map; + public readonly Map map; readonly TreeCache treeCache; public readonly TerrainRenderer terrain; public readonly Viewport viewport; @@ -27,9 +27,9 @@ namespace OpenRa.Game public readonly Dictionary players = new Dictionary(); - public Player LocalPlayer { get { return players[localPlayerIndex]; } } - public BuildingInfluenceMap LocalPlayerBuildings; - + public Player LocalPlayer { get { return players[localPlayerIndex]; } } + public BuildingInfluenceMap LocalPlayerBuildings; + ISoundEngine soundEngine; public Game(string mapName, Renderer renderer, int2 clientSize) @@ -49,8 +49,8 @@ namespace OpenRa.Game treeCache = new TreeCache(map); foreach( TreeReference treeReference in map.Trees ) - world.Add( new Actor( treeReference, treeCache, map.Offset ) ); - + world.Add( new Actor( treeReference, treeCache, map.Offset ) ); + LocalPlayerBuildings = new BuildingInfluenceMap(world, LocalPlayer); pathFinder = new PathFinder(map, terrain.tileSet, LocalPlayerBuildings); @@ -58,34 +58,34 @@ namespace OpenRa.Game network = new Network(); controller = new Controller(this); // CAREFUL THERES AN UGLY HIDDEN DEPENDENCY HERE STILL - worldRenderer = new WorldRenderer(renderer, this); - - soundEngine = new ISoundEngine(); - sounds = new Cache(LoadSound); - + worldRenderer = new WorldRenderer(renderer, this); + + soundEngine = new ISoundEngine(); + sounds = new Cache(LoadSound); + PlaySound("intro.aud", false); - } - - readonly Cache sounds; - - ISoundSource LoadSound(string filename) - { - var data = AudLoader.LoadSound(FileSystem.Open(filename)); - return soundEngine.AddSoundSourceFromPCMData(data, filename, - new AudioFormat() - { - ChannelCount = 1, - FrameCount = data.Length / 2, - Format = SampleFormat.Signed16Bit, - SampleRate = 22050 - }); - } - - public void PlaySound(string name, bool loop) - { - var sound = sounds[name]; - // todo: positioning - soundEngine.Play2D(sound, loop, false, false); + } + + readonly Cache sounds; + + ISoundSource LoadSound(string filename) + { + var data = AudLoader.LoadSound(FileSystem.Open(filename)); + return soundEngine.AddSoundSourceFromPCMData(data, filename, + new AudioFormat() + { + ChannelCount = 1, + FrameCount = data.Length / 2, + Format = SampleFormat.Signed16Bit, + SampleRate = 22050 + }); + } + + public void PlaySound(string name, bool loop) + { + var sound = sounds[name]; + // todo: positioning + soundEngine.Play2D(sound, loop, false, false); } public void Tick() @@ -94,28 +94,28 @@ namespace OpenRa.Game world.Update(); viewport.DrawRegions(); - } - - public bool IsCellBuildable(int2 a) - { - if (LocalPlayerBuildings[a] != null) return false; - - a += map.Offset; - - return map.IsInMap(a.X, a.Y) && - TerrainCosts.Cost(UnitMovementType.Wheel, - terrain.tileSet.GetWalkability(map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; - } - - public IEnumerable FindUnits(float2 a, float2 b) - { - var min = float2.Min(a, b); - var max = float2.Max(a, b); - - var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); - - return world.Actors - .Where(x => (x.Owner == LocalPlayer) && (x.Bounds.IntersectsWith(rect))); + } + + public bool IsCellBuildable(int2 a) + { + if (LocalPlayerBuildings[a] != null) return false; + + a += map.Offset; + + return map.IsInMap(a.X, a.Y) && + TerrainCosts.Cost(UnitMovementType.Wheel, + terrain.tileSet.GetWalkability(map.MapTiles[a.X, a.Y])) < double.PositiveInfinity; + } + + public IEnumerable FindUnits(float2 a, float2 b) + { + var min = float2.Min(a, b); + var max = float2.Max(a, b); + + var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y); + + return world.Actors + .Where(x => (x.Owner == LocalPlayer) && (x.Bounds.IntersectsWith(rect))); } } } diff --git a/OpenRa.Game/MainWindow.cs b/OpenRa.Game/MainWindow.cs index 2f41d8e37f..51a717543c 100644 --- a/OpenRa.Game/MainWindow.cs +++ b/OpenRa.Game/MainWindow.cs @@ -57,10 +57,10 @@ using System.Runtime.InteropServices; game.world.Add( new Actor( "mcv", new int2( 5, 5 ), game.players[ 3 ]) ); game.world.Add( new Actor( "mcv", new int2( 7, 5 ), game.players[ 2 ] ) ); - game.world.Add( new Actor( "mcv", new int2( 9, 5 ), game.players[ 0 ] ) ); + game.world.Add( new Actor( "mcv", new int2( 9, 5 ), game.players[ 0 ] ) ); var jeep = new Actor( "jeep", new int2( 9, 7 ), game.players[ 1 ] ); - game.world.Add( jeep ); - var tank = new Actor( "3tnk", new int2( 12, 7 ), game.players[ 1 ] ); + game.world.Add( jeep ); + var tank = new Actor( "3tnk", new int2( 12, 7 ), game.players[ 1 ] ); game.world.Add( tank ); tank.traits.Get().target = jeep; @@ -68,8 +68,8 @@ using System.Runtime.InteropServices; renderer.BuildPalette(game.map); - ShowCursor(false); - + ShowCursor(false); + game.world.ResetTimer(); } diff --git a/OpenRa.Game/MoveOrder.cs b/OpenRa.Game/MoveOrder.cs index 28162fd9c6..07643a3e64 100644 --- a/OpenRa.Game/MoveOrder.cs +++ b/OpenRa.Game/MoveOrder.cs @@ -21,27 +21,29 @@ namespace OpenRa.Game } public override void Apply( Game game, bool leftMouseButton ) - { - if (leftMouseButton) return; - if (game.LocalPlayer == Unit.Owner) + { + if (leftMouseButton) return; + if (game.LocalPlayer == Unit.Owner) game.PlaySound("ackno.r00", false); - Unit.traits.Get().destination = Destination; + var mobile = Unit.traits.Get(); + mobile.destination = Destination; + mobile.desiredFacing = null; } } class DeployMcvOrder : Order { - Actor Unit; + Actor Unit; int2 Location; public DeployMcvOrder( Actor unit, int2 location ) { - Unit = unit; + Unit = unit; Location = location; } public override void Apply( Game game, bool leftMouseButton ) - { + { if (leftMouseButton) return; Unit.traits.Get().DeployLocation = Location; var mobile = Unit.traits.Get(); diff --git a/OpenRa.Game/OpenRa.Game.csproj b/OpenRa.Game/OpenRa.Game.csproj index 640d0a9edd..57004ee3a0 100644 --- a/OpenRa.Game/OpenRa.Game.csproj +++ b/OpenRa.Game/OpenRa.Game.csproj @@ -140,6 +140,7 @@ + diff --git a/OpenRa.Game/Traits/AttackTurreted.cs b/OpenRa.Game/Traits/AttackTurreted.cs index 45ba26534b..18cda60801 100755 --- a/OpenRa.Game/Traits/AttackTurreted.cs +++ b/OpenRa.Game/Traits/AttackTurreted.cs @@ -30,7 +30,7 @@ namespace OpenRa.Game.Traits var mobile = self.traits.Get(); var turreted = self.traits.Get(); - turreted.desiredFacing = mobile.GetFacing( target.Location - self.Location ); + turreted.desiredFacing = Util.GetFacing( target.CenterLocation - self.CenterLocation, turreted.turretFacing ); if( turreted.desiredFacing != turreted.turretFacing ) return; diff --git a/OpenRa.Game/Traits/McvDeploy.cs b/OpenRa.Game/Traits/McvDeploy.cs index 50dce28d4c..4738a0c573 100644 --- a/OpenRa.Game/Traits/McvDeploy.cs +++ b/OpenRa.Game/Traits/McvDeploy.cs @@ -15,6 +15,7 @@ namespace OpenRa.Game.Traits public Order Order(Actor self, Game game, int2 xy) { + DeployLocation = null; // TODO: check that there's enough space at the destination. if( xy == self.Location ) return new DeployMcvOrder( self, xy ); @@ -24,24 +25,21 @@ namespace OpenRa.Game.Traits public void Tick(Actor self, Game game, int dt) { - var mobile = self.traits.Get(); + if( self.Location != DeployLocation ) + return; + var mobile = self.traits.Get(); + mobile.desiredFacing = 96; if( mobile.moveFraction < mobile.moveFractionTotal ) return; - if( self.Location != DeployLocation ) - { - DeployLocation = null; - return; - } - - if (mobile.Turn(12)) + if( mobile.facing != mobile.desiredFacing ) return; game.world.AddFrameEndTask(_ => { - game.world.Remove(self); - game.world.Add(new Actor("fact", self.Location - new int2(1, 1), self.Owner)); + game.world.Remove(self); + game.world.Add(new Actor("fact", self.Location - new int2(1, 1), self.Owner)); }); } } diff --git a/OpenRa.Game/Traits/Mobile.cs b/OpenRa.Game/Traits/Mobile.cs index 5ba35a57cd..0bf02fa5ee 100644 --- a/OpenRa.Game/Traits/Mobile.cs +++ b/OpenRa.Game/Traits/Mobile.cs @@ -15,6 +15,7 @@ namespace OpenRa.Game.Traits public int2 toCell { get { return self.Location; } } public int moveFraction, moveFractionTotal; public int facing; + public int? desiredFacing; public Mobile(Actor self) { @@ -22,41 +23,6 @@ namespace OpenRa.Game.Traits fromCell = destination = self.Location; } - public bool Turn(int desiredFacing) - { - if (facing == desiredFacing) - return false; - - int df = (desiredFacing - facing + 32) % 32; - facing = (facing + (df > 16 ? 31 : 1)) % 32; - return true; - } - - static float2[] fvecs = Util.MakeArray(32, - i => -float2.FromAngle(i / 16.0f * (float)Math.PI) * new float2(1f, 1.3f)); - - // TODO: move this somewhere more appropriate, now that AttackTurreted uses it. - public int GetFacing(float2 d) - { - if (float2.WithinEpsilon(d, float2.Zero, 0.001f)) - return facing; - - int highest = -1; - float highestDot = -1.0f; - - for (int i = 0; i < fvecs.Length; i++) - { - float dot = float2.Dot(fvecs[i], d); - if (dot > highestDot) - { - highestDot = dot; - highest = i; - } - } - - return highest; - } - void UpdateCenterLocation() { float fraction = (moveFraction > 0) ? (float)moveFraction / moveFractionTotal : 0f; @@ -71,13 +37,19 @@ namespace OpenRa.Game.Traits void Move(Actor self, Game game, int dt) { - if (fromCell != toCell) - { - if (Turn(GetFacing(toCell - fromCell))) - return; + if( fromCell != toCell ) + desiredFacing = Util.GetFacing( toCell - fromCell, facing ); - moveFraction += dt * ((UnitInfo.MobileInfo)self.unitInfo).Speed; + if( desiredFacing != null && desiredFacing != facing ) + { + Util.TickFacing( ref facing, desiredFacing.Value, self.unitInfo.ROT ); + return; } + desiredFacing = null; + + if( fromCell != toCell ) + moveFraction += dt * ((UnitInfo.MobileInfo)self.unitInfo).Speed; + if (moveFraction < moveFractionTotal) return; diff --git a/OpenRa.Game/Traits/RenderBuildingTurreted.cs b/OpenRa.Game/Traits/RenderBuildingTurreted.cs index 77a01e4095..373a71f7dc 100644 --- a/OpenRa.Game/Traits/RenderBuildingTurreted.cs +++ b/OpenRa.Game/Traits/RenderBuildingTurreted.cs @@ -10,8 +10,8 @@ namespace OpenRa.Game.Traits public RenderBuildingTurreted(Actor self) : base(self) { - anim.PlayThen("make", () => anim.PlayFetchIndex("idle", - () => self.traits.Get().turretFacing)); + anim.PlayThen( "make", () => anim.PlayFetchIndex( "idle", + () => self.traits.Get().turretFacing / 8 ) ); } } } diff --git a/OpenRa.Game/Traits/RenderUnit.cs b/OpenRa.Game/Traits/RenderUnit.cs index 91edff000a..93410781ff 100644 --- a/OpenRa.Game/Traits/RenderUnit.cs +++ b/OpenRa.Game/Traits/RenderUnit.cs @@ -12,7 +12,7 @@ namespace OpenRa.Game.Traits public RenderUnit(Actor self) : base(self) { - anim.PlayFetchIndex("idle", () => self.traits.Get().facing); + anim.PlayFetchIndex("idle", () => self.traits.Get().facing / 8); } protected static Pair Centered(Sprite s, float2 location) diff --git a/OpenRa.Game/Traits/RenderUnitTurreted.cs b/OpenRa.Game/Traits/RenderUnitTurreted.cs index 303467eae1..248c0aa60d 100644 --- a/OpenRa.Game/Traits/RenderUnitTurreted.cs +++ b/OpenRa.Game/Traits/RenderUnitTurreted.cs @@ -15,7 +15,7 @@ namespace OpenRa.Game.Traits : base(self) { turretAnim = new Animation(self.unitInfo.Name); - turretAnim.PlayFetchIndex("turret", () => self.traits.Get().turretFacing); + turretAnim.PlayFetchIndex("turret", () => self.traits.Get().turretFacing / 8); } public override IEnumerable> Render(Actor self) diff --git a/OpenRa.Game/Traits/Turreted.cs b/OpenRa.Game/Traits/Turreted.cs index 4e8e3fe667..dea6cb2b16 100644 --- a/OpenRa.Game/Traits/Turreted.cs +++ b/OpenRa.Game/Traits/Turreted.cs @@ -14,21 +14,13 @@ namespace OpenRa.Game.Traits { } - public void Tick(Actor self, Game game, int dt) + public void Tick( Actor self, Game game, int dt ) { // TODO: desiredFacing should follow the base unit's facing only when not in combat. // also, we want to be able to use this for GUN; avoid referencing Mobile. var df = desiredFacing ?? self.traits.Get().facing; - if( turretFacing != desiredFacing ) - { - var leftTurn = ( 32 + turretFacing - desiredFacing ) % 32; - var rightTurn = ( 32 + desiredFacing - turretFacing ) % 32; - if( leftTurn > rightTurn ) - turretFacing = ( turretFacing + 1 ) % 32; - else - turretFacing = ( turretFacing + 31 ) % 32; - } + Util.TickFacing( ref turretFacing, df, self.unitInfo.ROT ); } } } diff --git a/OpenRa.Game/Traits/Util.cs b/OpenRa.Game/Traits/Util.cs new file mode 100755 index 0000000000..9676226e4f --- /dev/null +++ b/OpenRa.Game/Traits/Util.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace OpenRa.Game.Traits +{ + static class Util + { + public static void TickFacing( ref int facing, int desiredFacing, int rot ) + { + var leftTurn = ( facing - desiredFacing ) & 0xFF; + var rightTurn = ( desiredFacing - facing ) & 0xFF; + if( Math.Min( leftTurn, rightTurn ) < rot ) + facing = desiredFacing; + else if( rightTurn < leftTurn ) + facing = ( facing + rot ) & 0xFF; + else + facing = ( facing - rot ) & 0xFF; + } + + static float2[] fvecs = Graphics.Util.MakeArray( 32, + i => -float2.FromAngle( i / 16.0f * (float)Math.PI ) * new float2( 1f, 1.3f ) ); + + public static int GetFacing( float2 d, int currentFacing ) + { + if( float2.WithinEpsilon( d, float2.Zero, 0.001f ) ) + return currentFacing; + + int highest = -1; + float highestDot = -1.0f; + + for( int i = 0 ; i < fvecs.Length ; i++ ) + { + float dot = float2.Dot( fvecs[ i ], d ); + if( dot > highestDot ) + { + highestDot = dot; + highest = i; + } + } + + return highest * 8; + } + + } +} diff --git a/OpenRa.Game/World.cs b/OpenRa.Game/World.cs index 928e19eb56..8e3295d2a1 100644 --- a/OpenRa.Game/World.cs +++ b/OpenRa.Game/World.cs @@ -25,11 +25,11 @@ namespace OpenRa.Game public void AddFrameEndTask( Action a ) { frameEndActions.Add( a ); } public event Action ActorAdded = _ => { }; - public event Action ActorRemoved = _ => { }; - - public void ResetTimer() - { - lastTime = Environment.TickCount; + public event Action ActorRemoved = _ => { }; + + public void ResetTimer() + { + lastTime = Environment.TickCount; } public void Update()