├── .gitignore
├── LICENSE
├── NuGet
└── Package.nuspec
├── README.md
└── Sources
├── Spritesheet.Sample.macOS
├── AppDelegate.cs
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ ├── AppIcon-128.png
│ │ ├── AppIcon-128@2x.png
│ │ ├── AppIcon-16.png
│ │ ├── AppIcon-16@2x.png
│ │ ├── AppIcon-256.png
│ │ ├── AppIcon-256@2x.png
│ │ ├── AppIcon-32.png
│ │ ├── AppIcon-32@2x.png
│ │ ├── AppIcon-512.png
│ │ ├── AppIcon-512@2x.png
│ │ └── Contents.json
│ └── Contents.json
├── Content
│ ├── README.txt
│ ├── characters.png
│ └── sheet.png
├── Entitlements.plist
├── Game.cs
├── Info.plist
├── Spritesheet.Sample.macOS.csproj
├── Utils
│ ├── PixelFont.cs
│ └── Primitive2D.cs
└── packages.config
├── Spritesheet.sln
└── Spritesheet
├── Animation.cs
├── AnimationDefinition.cs
├── Base
└── Repeat.cs
├── Extensions
└── SpriteBatchExtensions.cs
├── Frame.cs
├── Properties
└── AssemblyInfo.cs
├── Spritesheet.cs
├── Spritesheet.csproj
└── packages.config
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # .NET Core
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 | **/Properties/launchSettings.json
50 |
51 | *_i.c
52 | *_p.c
53 | *_i.h
54 | *.ilk
55 | *.meta
56 | *.obj
57 | *.pch
58 | *.pdb
59 | *.pgc
60 | *.pgd
61 | *.rsp
62 | *.sbr
63 | *.tlb
64 | *.tli
65 | *.tlh
66 | *.tmp
67 | *.tmp_proj
68 | *.log
69 | *.vspscc
70 | *.vssscc
71 | .builds
72 | *.pidb
73 | *.svclog
74 | *.scc
75 |
76 | # Chutzpah Test files
77 | _Chutzpah*
78 |
79 | # Visual C++ cache files
80 | ipch/
81 | *.aps
82 | *.ncb
83 | *.opendb
84 | *.opensdf
85 | *.sdf
86 | *.cachefile
87 | *.VC.db
88 | *.VC.VC.opendb
89 |
90 | # Visual Studio profiler
91 | *.psess
92 | *.vsp
93 | *.vspx
94 | *.sap
95 |
96 | # TFS 2012 Local Workspace
97 | $tf/
98 |
99 | # Guidance Automation Toolkit
100 | *.gpState
101 |
102 | # ReSharper is a .NET coding add-in
103 | _ReSharper*/
104 | *.[Rr]e[Ss]harper
105 | *.DotSettings.user
106 |
107 | # JustCode is a .NET coding add-in
108 | .JustCode
109 |
110 | # TeamCity is a build add-in
111 | _TeamCity*
112 |
113 | # DotCover is a Code Coverage Tool
114 | *.dotCover
115 |
116 | # Visual Studio code coverage results
117 | *.coverage
118 | *.coveragexml
119 |
120 | # NCrunch
121 | _NCrunch_*
122 | .*crunch*.local.xml
123 | nCrunchTemp_*
124 |
125 | # MightyMoose
126 | *.mm.*
127 | AutoTest.Net/
128 |
129 | # Web workbench (sass)
130 | .sass-cache/
131 |
132 | # Installshield output folder
133 | [Ee]xpress/
134 |
135 | # DocProject is a documentation generator add-in
136 | DocProject/buildhelp/
137 | DocProject/Help/*.HxT
138 | DocProject/Help/*.HxC
139 | DocProject/Help/*.hhc
140 | DocProject/Help/*.hhk
141 | DocProject/Help/*.hhp
142 | DocProject/Help/Html2
143 | DocProject/Help/html
144 |
145 | # Click-Once directory
146 | publish/
147 |
148 | # Publish Web Output
149 | *.[Pp]ublish.xml
150 | *.azurePubxml
151 | # TODO: Comment the next line if you want to checkin your web deploy settings
152 | # but database connection strings (with potential passwords) will be unencrypted
153 | *.pubxml
154 | *.publishproj
155 |
156 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
157 | # checkin your Azure Web App publish settings, but sensitive information contained
158 | # in these scripts will be unencrypted
159 | PublishScripts/
160 |
161 | # NuGet Packages
162 | *.nupkg
163 | # The packages folder can be ignored because of Package Restore
164 | **/packages/*
165 | # except build/, which is used as an MSBuild target.
166 | !**/packages/build/
167 | # Uncomment if necessary however generally it will be regenerated when needed
168 | #!**/packages/repositories.config
169 | # NuGet v3's project.json files produces more ignorable files
170 | *.nuget.props
171 | *.nuget.targets
172 |
173 | # Microsoft Azure Build Output
174 | csx/
175 | *.build.csdef
176 |
177 | # Microsoft Azure Emulator
178 | ecf/
179 | rcf/
180 |
181 | # Windows Store app package directories and files
182 | AppPackages/
183 | BundleArtifacts/
184 | Package.StoreAssociation.xml
185 | _pkginfo.txt
186 |
187 | # Visual Studio cache files
188 | # files ending in .cache can be ignored
189 | *.[Cc]ache
190 | # but keep track of directories ending in .cache
191 | !*.[Cc]ache/
192 |
193 | # Others
194 | ClientBin/
195 | ~$*
196 | *~
197 | *.dbmdl
198 | *.dbproj.schemaview
199 | *.jfm
200 | *.pfx
201 | *.publishsettings
202 | orleans.codegen.cs
203 |
204 | # Since there are multiple workflows, uncomment next line to ignore bower_components
205 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
206 | #bower_components/
207 |
208 | # RIA/Silverlight projects
209 | Generated_Code/
210 |
211 | # Backup & report files from converting an old project file
212 | # to a newer Visual Studio version. Backup files are not needed,
213 | # because we have git ;-)
214 | _UpgradeReport_Files/
215 | Backup*/
216 | UpgradeLog*.XML
217 | UpgradeLog*.htm
218 |
219 | # SQL Server files
220 | *.mdf
221 | *.ldf
222 | *.ndf
223 |
224 | # Business Intelligence projects
225 | *.rdl.data
226 | *.bim.layout
227 | *.bim_*.settings
228 |
229 | # Microsoft Fakes
230 | FakesAssemblies/
231 |
232 | # GhostDoc plugin setting file
233 | *.GhostDoc.xml
234 |
235 | # Node.js Tools for Visual Studio
236 | .ntvs_analysis.dat
237 | node_modules/
238 |
239 | # Typescript v1 declaration files
240 | typings/
241 |
242 | # Visual Studio 6 build log
243 | *.plg
244 |
245 | # Visual Studio 6 workspace options file
246 | *.opt
247 |
248 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
249 | *.vbw
250 |
251 | # Visual Studio LightSwitch build output
252 | **/*.HTMLClient/GeneratedArtifacts
253 | **/*.DesktopClient/GeneratedArtifacts
254 | **/*.DesktopClient/ModelManifest.xml
255 | **/*.Server/GeneratedArtifacts
256 | **/*.Server/ModelManifest.xml
257 | _Pvt_Extensions
258 |
259 | # Paket dependency manager
260 | .paket/paket.exe
261 | paket-files/
262 |
263 | # FAKE - F# Make
264 | .fake/
265 |
266 | # JetBrains Rider
267 | .idea/
268 | *.sln.iml
269 |
270 | # CodeRush
271 | .cr/
272 |
273 | # Python Tools for Visual Studio (PTVS)
274 | __pycache__/
275 | *.pyc
276 |
277 | # Cake - Uncomment if you are using it
278 | # tools/**
279 | # !tools/packages.config
280 |
281 | # Telerik's JustMock configuration file
282 | *.jmconfig
283 |
284 | # BizTalk build output
285 | *.btp.cs
286 | *.btm.cs
287 | *.odx.cs
288 | *.xsd.cs
289 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Aloïs Deniel
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/NuGet/Package.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Spritesheet
5 | $version$
6 | Spritesheet (for Monogame)
7 | Aloïs Deniel
8 | Aloïs Deniel
9 | https://github.com/aloisdeniel/Spritesheet/blob/master/LICENSE
10 | https://github.com/aloisdeniel/Spritesheet/
11 | https://raw.githubusercontent.com/aloisdeniel/Spritesheet/master/Documentation/Logo.png
12 | false
13 | Simple helper for creating sprite based animations for Monogame.
14 | Copyright 2017
15 | monogame animation sprite
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Spritesheet *for Monogame*
2 |
3 | Extremely basic APIs for creating sprite based animations.
4 |
5 | ## Install
6 |
7 | Available on NuGet
8 |
9 | [](https://www.nuget.org/packages/Spritesheet/)
10 |
11 | ## Quickstart
12 |
13 | **Create**
14 |
15 | ```csharp
16 | var sheet = new Spritesheet(texture2d).WithGrid((32, 32));
17 | var anim = sheet.CreateAnimation((0, 1), (1, 1), (2, 1)).FlipX();
18 | anim.Start(Repeat.Mode.Loop);
19 | ```
20 | **Update**
21 |
22 | ```csharp
23 | anim.Update(gameTime);
24 | ```
25 | **Draw**
26 |
27 | ```csharp
28 | spriteBatch.Draw(anim, new Vector2(64, 64));
29 | ```
30 |
31 | ## About
32 |
33 | This project was inspired by [kikito/anim8](https://github.com/kikito/anim8) great library for LÖVE2D.
34 |
35 | ## Contributions
36 |
37 | Contributions are welcome! If you find a bug please report it and if you want a feature please report it.
38 |
39 | If you want to contribute code please file an issue and create a branch off of the current dev branch and file a pull request.
40 |
41 | ## License
42 |
43 | MIT © [Aloïs Deniel](http://aloisdeniel.github.io)
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/AppDelegate.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet.Sample.macOS
2 | {
3 | using AppKit;
4 | using Foundation;
5 |
6 | [Register("AppDelegate")]
7 | class Program : NSApplicationDelegate
8 | {
9 | private static Game game;
10 |
11 | internal static void RunGame()
12 | {
13 | game = new Game();
14 | game.Window.AllowUserResizing = true;
15 | game.Run();
16 | }
17 |
18 | ///
19 | /// The main entry point for the application.
20 | ///
21 | static void Main(string[] args)
22 | {
23 | NSApplication.Init();
24 |
25 | using (var p = new NSAutoreleasePool())
26 | {
27 | NSApplication.SharedApplication.Delegate = new Program();
28 | NSApplication.Main(args);
29 | }
30 | }
31 |
32 | public override void DidFinishLaunching(NSNotification notification)
33 | {
34 | RunGame();
35 | }
36 |
37 | public override bool ApplicationShouldTerminateAfterLastWindowClosed(NSApplication sender)
38 | {
39 | return true;
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images": [
3 | {
4 | "filename": "AppIcon-16.png",
5 | "size": "16x16",
6 | "scale": "1x",
7 | "idiom": "mac"
8 | },
9 | {
10 | "filename": "AppIcon-16@2x.png",
11 | "size": "16x16",
12 | "scale": "2x",
13 | "idiom": "mac"
14 | },
15 | {
16 | "filename": "AppIcon-32.png",
17 | "size": "32x32",
18 | "scale": "1x",
19 | "idiom": "mac"
20 | },
21 | {
22 | "filename": "AppIcon-32@2x.png",
23 | "size": "32x32",
24 | "scale": "2x",
25 | "idiom": "mac"
26 | },
27 | {
28 | "filename": "AppIcon-128.png",
29 | "size": "128x128",
30 | "scale": "1x",
31 | "idiom": "mac"
32 | },
33 | {
34 | "filename": "AppIcon-128@2x.png",
35 | "size": "128x128",
36 | "scale": "2x",
37 | "idiom": "mac"
38 | },
39 | {
40 | "filename": "AppIcon-256.png",
41 | "size": "256x256",
42 | "scale": "1x",
43 | "idiom": "mac"
44 | },
45 | {
46 | "filename": "AppIcon-256@2x.png",
47 | "size": "256x256",
48 | "scale": "2x",
49 | "idiom": "mac"
50 | },
51 | {
52 | "filename": "AppIcon-512.png",
53 | "size": "512x512",
54 | "scale": "1x",
55 | "idiom": "mac"
56 | },
57 | {
58 | "filename": "AppIcon-512@2x.png",
59 | "size": "512x512",
60 | "scale": "2x",
61 | "idiom": "mac"
62 | }
63 | ],
64 | "info": {
65 | "version": 1,
66 | "author": "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Content/README.txt:
--------------------------------------------------------------------------------
1 | LICENCE CC0 - PUBLIC DOMAIN
2 |
3 | RESOURCES LINK : https://opengameart.org/content/a-platformer-in-the-forest
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Content/characters.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Content/characters.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Content/sheet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dotnet-ad/Spritesheet/bb2e89cebe4efc85a9513e0d58b1a893d6cbcbd7/Sources/Spritesheet.Sample.macOS/Content/sheet.png
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Entitlements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Game.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet.Sample.macOS
2 | {
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 | using System.IO;
6 | using Microsoft.Xna.Framework.Input;
7 |
8 | public class Game : Microsoft.Xna.Framework.Game
9 | {
10 | #region Fields
11 |
12 | private GraphicsDeviceManager graphics;
13 |
14 | private SpriteBatch spriteBatch;
15 |
16 | private Spritesheet sheet;
17 |
18 | private Animation[] animations;
19 |
20 | private Animation anim;
21 |
22 | private PixelFont font;
23 |
24 | private int animIndex = -1;
25 |
26 | #endregion
27 |
28 | public Game()
29 | {
30 | this.IsMouseVisible = true;
31 | graphics = new GraphicsDeviceManager(this);
32 | Content.RootDirectory = "Content";
33 | graphics.IsFullScreen = false;
34 | this.font = new PixelFont();
35 | }
36 |
37 | private Texture2D LoadTexture(string name)
38 | {
39 | using (var fileStream = new FileStream($"Content/{name}.png", FileMode.Open))
40 | {
41 | return Texture2D.FromStream(this.graphics.GraphicsDevice, fileStream);
42 | }
43 | }
44 |
45 | protected override void LoadContent()
46 | {
47 | // Create a new SpriteBatch, which can be used to draw textures.
48 | spriteBatch = new SpriteBatch(GraphicsDevice);
49 |
50 | this.font.LoadContent(this.GraphicsDevice);
51 |
52 | this.sheet = new Spritesheet(LoadTexture("characters"))
53 | .WithGrid((32, 32));
54 |
55 | this.animations = new[]
56 | {
57 | this.sheet.WithFrameEffect(SpriteEffects.FlipHorizontally).CreateAnimation((0, 1), (1, 1), (2, 1)),
58 | this.sheet.CreateAnimation((0, 1), (1, 1), (2, 1)),
59 | this.sheet.WithFrameEffect(SpriteEffects.FlipHorizontally).CreateAnimation((0, 0), (1, 0), (2, 0)),
60 | this.sheet.CreateAnimation((0, 0), (1, 0), (2, 0)),
61 | };
62 |
63 | this.NextAnimation();
64 |
65 | }
66 |
67 | private void NextAnimation()
68 | {
69 | this.animIndex = (this.animIndex + 1) % this.animations.Length;
70 | this.anim = this.animations[animIndex];
71 | this.anim.Start(Repeat.Mode.Loop);
72 | }
73 |
74 | private MouseState state;
75 |
76 | protected override void Update(GameTime gameTime)
77 | {
78 | this.anim.Update(gameTime);
79 |
80 | var newState = Mouse.GetState();
81 |
82 | if(state.LeftButton == ButtonState.Released && newState.LeftButton == ButtonState.Pressed)
83 | {
84 | this.NextAnimation();
85 | }
86 |
87 | state = newState;
88 |
89 | base.Update(gameTime);
90 | }
91 |
92 | protected override void Draw(GameTime gameTime)
93 | {
94 | GraphicsDevice.Clear(Color.Black);
95 |
96 | spriteBatch.Begin();
97 |
98 | var borders = new Color(1.0f, 1.0f, 1.0f, 0.2f);
99 |
100 | // Full texture
101 | spriteBatch.Draw(this.sheet.Texture, new Vector2(0, 0));
102 | spriteBatch.DrawRectangle(this.sheet.Texture.Bounds, borders);
103 |
104 | // Animation
105 | spriteBatch.Draw(this.anim, new Vector2(64, 64 + this.sheet.Texture.Height));
106 | this.font.Draw(spriteBatch, new Vector2(12, 12 + this.sheet.Texture.Height), $"{animIndex}", Color.White);
107 |
108 | // Frames in full texture
109 | for (int ia = 0; ia < anim.Frames.Length; ia++)
110 | {
111 | var a = anim.Frames[ia];
112 |
113 | spriteBatch.DrawRectangle(a.Area, borders);
114 | spriteBatch.DrawCross(a.Area.Location.ToVector2() + a.Origin.ToVector2(), borders);
115 | this.font.Draw(spriteBatch, a.Area.Location.ToVector2() + new Vector2(4, 4), $"{ia}", borders);
116 | }
117 |
118 | //Mouse
119 | const int mouseGrid = 16;
120 | var mx = (this.state.X / mouseGrid) * mouseGrid;
121 | var my = (this.state.Y / mouseGrid) * mouseGrid;
122 | spriteBatch.DrawLine(0, my, this.GraphicsDevice.Viewport.Width, my, Color.Green);
123 | spriteBatch.DrawLine(mx, 0, mx, this.GraphicsDevice.Viewport.Height, Color.Blue);
124 | this.font.Draw(spriteBatch, new Vector2(mx, my) + new Vector2(32,32), $"({mx},{my})", borders);
125 |
126 | spriteBatch.End();
127 |
128 | base.Draw(gameTime);
129 | }
130 |
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleName
6 | Spritesheet.Sample
7 | CFBundleIdentifier
8 | com.spritesheet-sample
9 | CFBundleShortVersionString
10 | 1.0
11 | CFBundleVersion
12 | 1
13 | LSMinimumSystemVersion
14 | 10.12
15 | CFBundleDevelopmentRegion
16 | en
17 | CFBundleInfoDictionaryVersion
18 | 6.0
19 | CFBundlePackageType
20 | APPL
21 | CFBundleSignature
22 | ????
23 | NSHumanReadableCopyright
24 | ${AuthorCopyright}
25 | NSPrincipalClass
26 | NSApplication
27 | XSAppIconAssets
28 | Assets.xcassets/AppIcon.appiconset
29 |
30 |
31 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Spritesheet.Sample.macOS.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | {399438CD-9CCD-410B-9491-B27746063359}
7 | {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
8 | Exe
9 | Spritesheet.Sample.macOS
10 | Spritesheet.Sample
11 | v2.0
12 | Xamarin.Mac
13 | Resources
14 |
15 |
16 | true
17 | full
18 | false
19 | bin\Debug
20 | DEBUG;
21 | prompt
22 | 4
23 | false
24 | Mac Developer
25 | false
26 | false
27 | false
28 | true
29 | true
30 | true
31 |
32 |
33 |
34 |
35 |
36 | pdbonly
37 | true
38 | bin\Release
39 |
40 | prompt
41 | 4
42 | false
43 | true
44 | false
45 | true
46 | true
47 | true
48 | SdkOnly
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | ..\packages\MonoGame.Framework.MacOS.3.6.0.1625\lib\XamarinMac\MonoGame.Framework.dll
58 |
59 |
60 | ..\packages\MonoGame.Framework.MacOS.3.6.0.1625\lib\XamarinMac\OpenTK.dll
61 |
62 |
63 | ..\packages\MonoGame.Framework.MacOS.3.6.0.1625\lib\XamarinMac\Tao.Sdl.dll
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | PreserveNewest
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | {C57AB359-8743-47D2-9731-9A1AEF32856E}
103 | Spritesheet
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Utils/PixelFont.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet.Sample.macOS
2 | {
3 | using System;
4 | using System.Collections.Generic;
5 | using Microsoft.Xna.Framework;
6 | using Microsoft.Xna.Framework.Graphics;
7 |
8 | public class PixelFont
9 | {
10 | private readonly Dictionary Pixels = new Dictionary()
11 | {
12 | { '0', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0 }},
13 | { '1', new short[] { 0, 1, 0, /**/ 1, 1, 0, /**/ 0, 1, 0, /**/ 0, 1, 0, /**/ 1, 1, 1 }},
14 | { '2', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 0, 0, 1, 0, /**/ 0, 1, 0, 0, /**/ 1, 1, 1, 1 }},
15 | { '3', new short[] { 1, 1, 1, 0, /**/ 0, 0, 0, 1, /**/ 0, 1, 1, 0, /**/ 0, 0, 0, 1, /**/ 1, 1, 1, 0 }},
16 | { '4', new short[] { 0, 0, 1, 1, /**/ 0, 1, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 1, /**/ 0, 0, 0, 1 }},
17 | { '5', new short[] { 1, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 1, 1, 1, /**/ 0, 0, 0, 1, /**/ 1, 1, 1, 0 }},
18 | { '6', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 0, /**/ 1, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0 }},
19 | { '7', new short[] { 1, 1, 1, 1, /**/ 0, 0, 0, 1, /**/ 0, 0, 1, 0, /**/ 0, 0, 1, 0, /**/ 0, 0, 1, 0 }},
20 | { '8', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0 }},
21 | { '9', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 1, /**/ 0, 0, 0, 1, /**/ 0, 1, 1, 0 }},
22 | { '-', new short[] { 0, 0, 0, /**/ 0, 0, 0, /**/ 1, 1, 1, /**/ 0, 0, 0, /**/ 0, 0, 0 }},
23 | { '+', new short[] { 0, 0, 0, /**/ 0, 1, 0, /**/ 1, 1, 1, /**/ 0, 1, 0, /**/ 0, 0, 0 }},
24 | { ':', new short[] { 0, 0, 0, /**/ 0, 1, 0, /**/ 0, 0, 0, /**/ 0, 1, 0, /**/ 0, 0, 0 }},
25 | { '(', new short[] { 0, 1, /**/ 1, 0, /**/ 1, 0, /**/ 1, 0, /**/ 0, 1 }},
26 | { ')', new short[] { 1, 0, /**/ 0, 1, /**/ 0, 1, /**/ 0, 1, /**/ 1, 0 }},
27 | { '.', new short[] { 0, 0, /**/ 0, 0, /**/ 0, 0, /**/ 0, 0, /**/ 1, 0 }},
28 | { ',', new short[] { 0, 0, /**/ 0, 0, /**/ 0, 0, /**/ 0, 1, /**/ 1, 0 }},
29 | { 'A', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1 }},
30 | { 'B', new short[] { 1, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 0 }},
31 | { 'C', new short[] { 0, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 0, 0, 0, /**/ 1, 0, 0, 0, /**/ 0, 1, 1, 1 }},
32 | { 'D', new short[] { 1, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 0 }},
33 | { 'E', new short[] { 1, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 1, 1, 1 }},
34 | { 'F', new short[] { 1, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 0, 0, 0 }},
35 | { 'G', new short[] { 1, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 1, 0, 1, 1, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 1 }},
36 | { 'H', new short[] { 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1 }},
37 | { 'I', new short[] { 1, /**/ 1, /**/ 1, /**/ 1, /**/ 1 }},
38 | { 'J', new short[] { 0, 0, 0, 1, /**/ 0, 0, 0, 1, /**/ 0, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0 }},
39 | { 'K', new short[] { 1, 0, 0, 1, /**/ 1, 0, 1, 0, /**/ 1, 1, 0, 0, /**/ 1, 0, 1, 0, /**/ 1, 0, 0, 1 }},
40 | { 'L', new short[] { 1, 0, 0, /**/ 1, 0, 0, /**/ 1, 0, 0, /**/ 1, 0, 0, /**/ 1, 1, 1 }},
41 | { 'M', new short[] { 1, 0, 0, 0, 1, /**/ 1, 1, 0, 1, 1, /**/ 1, 0, 1, 0, 1, /**/ 1, 0, 0, 0, 1, /**/ 1, 0, 0, 0, 1 }},
42 | { 'N', new short[] { 1, 0, 0, 1, /**/ 1, 1, 0, 1, /**/ 1, 0, 1, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1 }},
43 | { 'O', new short[] { 0, 1, 1, 1, 0, /**/ 1, 0, 0, 0, 1, /**/ 1, 0, 0, 0, 1, /**/ 1, 0, 0, 0, 1, /**/ 0, 1, 1, 1, 0 }},
44 | { 'P', new short[] { 1, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 0, /**/ 1, 0, 0, 0, /**/ 1, 0, 0, 0 }},
45 | { 'Q', new short[] { 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 1, 0, /**/ 0, 1, 0, 1 }},
46 | { 'R', new short[] { 1, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 0, /**/ 1, 0, 1, 0, /**/ 1, 0, 0, 1 }},
47 | { 'S', new short[] { 0, 1, 1, 1, /**/ 1, 0, 0, 0, /**/ 0, 1, 1, 0, /**/ 0, 0, 0, 1, /**/ 1, 1, 1, 0 }},
48 | { 'T', new short[] { 1, 1, 1, 1, 1, /**/ 0, 0, 1, 0, 0, /**/ 0, 0, 1, 0, 0, /**/ 0, 0, 1, 0, 0, /**/ 0, 0, 1, 0, 0 }},
49 | { 'U', new short[] { 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0 }},
50 | { 'V', new short[] { 1, 0, 0, 0, 1, /**/ 1, 0, 0, 0, 1, /**/ 0, 1, 0, 1, 0, /**/ 0, 1, 0, 1, 0, /**/ 0, 0, 1, 0, 0 }},
51 | { 'W', new short[] { 1, 0, 1, 0, 1, /**/ 1, 0, 1, 0, 1, /**/ 1, 0, 1, 0, 1, /**/ 0, 1, 0, 1, 0, /**/ 0, 1, 0, 1, 0 }},
52 | { 'X', new short[] { 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 0, 1, 1, 0, /**/ 1, 0, 0, 1, /**/ 1, 0, 0, 1 }},
53 | { 'Y', new short[] { 1, 0, 0, 1, /**/ 1, 0, 0, 1, /**/ 1, 1, 1, 1, /**/ 0, 0, 0, 1, /**/ 1, 1, 1, 0 }},
54 | { 'Z', new short[] { 1, 1, 1, 1, /**/ 0, 0, 0, 1, /**/ 0, 1, 1, 0, /**/ 1, 0, 0, 0, /**/ 1, 1, 1, 1 }},
55 | };
56 |
57 | private const int LetterSpace = 1;
58 | private const int LineSpace = 3;
59 | private const int Space = 4;
60 |
61 | private Dictionary Textures;
62 |
63 | public PixelFont()
64 | {
65 | }
66 |
67 | public void LoadContent(GraphicsDevice device)
68 | {
69 | if (this.Textures == null)
70 | {
71 | this.Textures = new Dictionary();
72 | foreach (var c in Pixels)
73 | {
74 | Textures[c.Key] = this.LoadCharacter(device, c.Key, c.Value);
75 | }
76 | }
77 | }
78 |
79 | private Texture2D LoadCharacter(GraphicsDevice device, char c, short[] pixels)
80 | {
81 | const int height = 5;
82 | var width = pixels.Length / height;
83 | var result = new Texture2D(device, width, height);
84 | var data = new Color[width * height];
85 | for (int pixel = 0; pixel < data.Length; pixel++)
86 | {
87 | data[pixel] = pixels[pixel] > 0 ? Color.White : Color.Transparent;
88 | }
89 | result.SetData(data);
90 | return result;
91 | }
92 |
93 | public Point Measure(string message, int fontSize = 10)
94 | {
95 | var scale = fontSize / 5.0f;
96 | var x = 0;
97 | var y = fontSize;
98 | var w = 0;
99 |
100 | foreach (var c in message)
101 | {
102 | if (c == ' ')
103 | {
104 | x += LetterSpace + Space;
105 | }
106 | else if (c == '\n')
107 | {
108 | y += LineSpace + fontSize;
109 | x = 0;
110 | }
111 | else
112 | {
113 | var texture = this.Textures[c];
114 | x += (int)((((x > 0) ? LetterSpace : 0) + texture.Width) * scale);
115 | }
116 |
117 | w = Math.Max(w, x);
118 | }
119 |
120 | return new Point((int)w, (int)y);
121 | }
122 |
123 |
124 | public void Draw(SpriteBatch spriteBatch, Vector2 position, string message, Color color, int fontSize = 10)
125 | {
126 | var scale = fontSize / 5.0f;
127 | var x = position.X;
128 | var y = position.Y;
129 |
130 | message = message.ToUpper();
131 |
132 | foreach (var c in message)
133 | {
134 | if (c == ' ')
135 | {
136 | x += LetterSpace + Space;
137 | }
138 | else if (c == '\n')
139 | {
140 | y += LineSpace + fontSize;
141 | x = position.X;
142 | }
143 | else if(this.Textures.ContainsKey(c))
144 | {
145 | var texture = this.Textures[c];
146 | spriteBatch.Draw(texture, new Vector2(x, y), color: color, scale: Vector2.One * scale);
147 | x += (int)((((x > 0) ? LetterSpace : 0) + texture.Width) * scale);
148 | }
149 | }
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/Utils/Primitive2D.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 |
6 | namespace Spritesheet.Sample.macOS
7 | {
8 | ///
9 | ///
10 | public static class Primitives2D
11 | {
12 |
13 |
14 | #region Private Members
15 |
16 | private static readonly Dictionary> circleCache = new Dictionary>();
17 | //private static readonly Dictionary> arcCache = new Dictionary>();
18 | private static Texture2D pixel;
19 |
20 | #endregion
21 |
22 | #region Cross
23 |
24 | public static void DrawCross(this SpriteBatch spriteBatch, Vector2 pos, Color color)
25 | {
26 | DrawLine(spriteBatch, pos.X - 4, pos.Y, pos.X - 1, pos.Y, color);
27 | DrawLine(spriteBatch, pos.X + 0, pos.Y, pos.X + 3, pos.Y, color);
28 | DrawLine(spriteBatch, pos.X, pos.Y - 3, pos.X, pos.Y - 0, color);
29 | DrawLine(spriteBatch, pos.X, pos.Y + 1, pos.X, pos.Y + 4, color);
30 | }
31 |
32 | #endregion
33 |
34 |
35 | #region Private Methods
36 |
37 | private static void CreateThePixel(SpriteBatch spriteBatch)
38 | {
39 | pixel = new Texture2D(spriteBatch.GraphicsDevice, 1, 1, false, SurfaceFormat.Color);
40 | pixel.SetData(new[] { Color.White });
41 | }
42 |
43 |
44 | ///
45 | /// Draws a list of connecting points
46 | ///
47 | /// The destination drawing surface
48 | /// /// Where to position the points
49 | /// The points to connect with lines
50 | /// The color to use
51 | /// The thickness of the lines
52 | private static void DrawPoints(SpriteBatch spriteBatch, Vector2 position, List points, Color color, float thickness)
53 | {
54 | if (points.Count < 2)
55 | return;
56 |
57 | for (int i = 1; i < points.Count; i++)
58 | {
59 | DrawLine(spriteBatch, points[i - 1] + position, points[i] + position, color, thickness);
60 | }
61 | }
62 |
63 |
64 | ///
65 | /// Creates a list of vectors that represents a circle
66 | ///
67 | /// The radius of the circle
68 | /// The number of sides to generate
69 | /// A list of vectors that, if connected, will create a circle
70 | private static List CreateCircle(double radius, int sides)
71 | {
72 | // Look for a cached version of this circle
73 | String circleKey = radius + "x" + sides;
74 | if (circleCache.ContainsKey(circleKey))
75 | {
76 | return circleCache[circleKey];
77 | }
78 |
79 | List vectors = new List();
80 |
81 | const double max = 2.0 * Math.PI;
82 | double step = max / sides;
83 |
84 | for (double theta = 0.0; theta < max; theta += step)
85 | {
86 | vectors.Add(new Vector2((float)(radius * Math.Cos(theta)), (float)(radius * Math.Sin(theta))));
87 | }
88 |
89 | // then add the first vector again so it's a complete loop
90 | vectors.Add(new Vector2((float)(radius * Math.Cos(0)), (float)(radius * Math.Sin(0))));
91 |
92 | // Cache this circle so that it can be quickly drawn next time
93 | circleCache.Add(circleKey, vectors);
94 |
95 | return vectors;
96 | }
97 |
98 |
99 | ///
100 | /// Creates a list of vectors that represents an arc
101 | ///
102 | /// The radius of the arc
103 | /// The number of sides to generate in the circle that this will cut out from
104 | /// The starting angle of arc, 0 being to the east, increasing as you go clockwise
105 | /// The radians to draw, clockwise from the starting angle
106 | /// A list of vectors that, if connected, will create an arc
107 | private static List CreateArc(float radius, int sides, float startingAngle, float radians)
108 | {
109 | List points = new List();
110 | points.AddRange(CreateCircle(radius, sides));
111 | points.RemoveAt(points.Count - 1); // remove the last point because it's a duplicate of the first
112 |
113 | // The circle starts at (radius, 0)
114 | double curAngle = 0.0;
115 | double anglePerSide = MathHelper.TwoPi / sides;
116 |
117 | // "Rotate" to the starting point
118 | while ((curAngle + (anglePerSide / 2.0)) < startingAngle)
119 | {
120 | curAngle += anglePerSide;
121 |
122 | // move the first point to the end
123 | points.Add(points[0]);
124 | points.RemoveAt(0);
125 | }
126 |
127 | // Add the first point, just in case we make a full circle
128 | points.Add(points[0]);
129 |
130 | // Now remove the points at the end of the circle to create the arc
131 | int sidesInArc = (int)((radians / anglePerSide) + 0.5);
132 | points.RemoveRange(sidesInArc + 1, points.Count - sidesInArc - 1);
133 |
134 | return points;
135 | }
136 |
137 | #endregion
138 |
139 |
140 | #region FillRectangle
141 |
142 | ///
143 | /// Draws a filled rectangle
144 | ///
145 | /// The destination drawing surface
146 | /// The rectangle to draw
147 | /// The color to draw the rectangle in
148 | public static void FillRectangle(this SpriteBatch spriteBatch, Rectangle rect, Color color)
149 | {
150 | if (pixel == null)
151 | {
152 | CreateThePixel(spriteBatch);
153 | }
154 |
155 | // Simply use the function already there
156 | spriteBatch.Draw(pixel, rect, color);
157 | }
158 |
159 |
160 | ///
161 | /// Draws a filled rectangle
162 | ///
163 | /// The destination drawing surface
164 | /// The rectangle to draw
165 | /// The color to draw the rectangle in
166 | /// The angle in radians to draw the rectangle at
167 | public static void FillRectangle(this SpriteBatch spriteBatch, Rectangle rect, Color color, float angle)
168 | {
169 | if (pixel == null)
170 | {
171 | CreateThePixel(spriteBatch);
172 | }
173 |
174 | spriteBatch.Draw(pixel, rect, null, color, angle, Vector2.Zero, SpriteEffects.None, 0);
175 | }
176 |
177 |
178 | ///
179 | /// Draws a filled rectangle
180 | ///
181 | /// The destination drawing surface
182 | /// Where to draw
183 | /// The size of the rectangle
184 | /// The color to draw the rectangle in
185 | public static void FillRectangle(this SpriteBatch spriteBatch, Vector2 location, Vector2 size, Color color)
186 | {
187 | FillRectangle(spriteBatch, location, size, color, 0.0f);
188 | }
189 |
190 |
191 | ///
192 | /// Draws a filled rectangle
193 | ///
194 | /// The destination drawing surface
195 | /// Where to draw
196 | /// The size of the rectangle
197 | /// The angle in radians to draw the rectangle at
198 | /// The color to draw the rectangle in
199 | public static void FillRectangle(this SpriteBatch spriteBatch, Vector2 location, Vector2 size, Color color, float angle)
200 | {
201 | if (pixel == null)
202 | {
203 | CreateThePixel(spriteBatch);
204 | }
205 |
206 | // stretch the pixel between the two vectors
207 | spriteBatch.Draw(pixel,
208 | location,
209 | null,
210 | color,
211 | angle,
212 | Vector2.Zero,
213 | size,
214 | SpriteEffects.None,
215 | 0);
216 | }
217 |
218 |
219 | ///
220 | /// Draws a filled rectangle
221 | ///
222 | /// The destination drawing surface
223 | /// The X coord of the left side
224 | /// The Y coord of the upper side
225 | /// Width
226 | /// Height
227 | /// The color to draw the rectangle in
228 | public static void FillRectangle(this SpriteBatch spriteBatch, float x, float y, float w, float h, Color color)
229 | {
230 | FillRectangle(spriteBatch, new Vector2(x, y), new Vector2(w, h), color, 0.0f);
231 | }
232 |
233 |
234 | ///
235 | /// Draws a filled rectangle
236 | ///
237 | /// The destination drawing surface
238 | /// The X coord of the left side
239 | /// The Y coord of the upper side
240 | /// Width
241 | /// Height
242 | /// The color to draw the rectangle in
243 | /// The angle of the rectangle in radians
244 | public static void FillRectangle(this SpriteBatch spriteBatch, float x, float y, float w, float h, Color color, float angle)
245 | {
246 | FillRectangle(spriteBatch, new Vector2(x, y), new Vector2(w, h), color, angle);
247 | }
248 |
249 | #endregion
250 |
251 |
252 | #region DrawRectangle
253 |
254 | ///
255 | /// Draws a rectangle with the thickness provided
256 | ///
257 | /// The destination drawing surface
258 | /// The rectangle to draw
259 | /// The color to draw the rectangle in
260 | public static void DrawRectangle(this SpriteBatch spriteBatch, Rectangle rect, Color color)
261 | {
262 | DrawRectangle(spriteBatch, rect, color, 1.0f);
263 | }
264 |
265 |
266 | ///
267 | /// Draws a rectangle with the thickness provided
268 | ///
269 | /// The destination drawing surface
270 | /// The rectangle to draw
271 | /// The color to draw the rectangle in
272 | /// The thickness of the lines
273 | public static void DrawRectangle(this SpriteBatch spriteBatch, Rectangle rect, Color color, float thickness)
274 | {
275 |
276 | // TODO: Handle rotations
277 | // TODO: Figure out the pattern for the offsets required and then handle it in the line instead of here
278 |
279 | DrawLine(spriteBatch, new Vector2(rect.X, rect.Y), new Vector2(rect.Right, rect.Y), color, thickness); // top
280 | DrawLine(spriteBatch, new Vector2(rect.X + 1f, rect.Y), new Vector2(rect.X + 1f, rect.Bottom + thickness), color, thickness); // left
281 | DrawLine(spriteBatch, new Vector2(rect.X, rect.Bottom), new Vector2(rect.Right, rect.Bottom), color, thickness); // bottom
282 | DrawLine(spriteBatch, new Vector2(rect.Right + 1f, rect.Y), new Vector2(rect.Right + 1f, rect.Bottom + thickness), color, thickness); // right
283 | }
284 |
285 |
286 | ///
287 | /// Draws a rectangle with the thickness provided
288 | ///
289 | /// The destination drawing surface
290 | /// Where to draw
291 | /// The size of the rectangle
292 | /// The color to draw the rectangle in
293 | public static void DrawRectangle(this SpriteBatch spriteBatch, Vector2 location, Vector2 size, Color color)
294 | {
295 | DrawRectangle(spriteBatch, new Rectangle((int)location.X, (int)location.Y, (int)size.X, (int)size.Y), color, 1.0f);
296 | }
297 |
298 |
299 | ///
300 | /// Draws a rectangle with the thickness provided
301 | ///
302 | /// The destination drawing surface
303 | /// Where to draw
304 | /// The size of the rectangle
305 | /// The color to draw the rectangle in
306 | /// The thickness of the line
307 | public static void DrawRectangle(this SpriteBatch spriteBatch, Vector2 location, Vector2 size, Color color, float thickness)
308 | {
309 | DrawRectangle(spriteBatch, new Rectangle((int)location.X, (int)location.Y, (int)size.X, (int)size.Y), color, thickness);
310 | }
311 |
312 | #endregion
313 |
314 |
315 | #region DrawLine
316 |
317 | ///
318 | /// Draws a line from point1 to point2 with an offset
319 | ///
320 | /// The destination drawing surface
321 | /// The X coord of the first point
322 | /// The Y coord of the first point
323 | /// The X coord of the second point
324 | /// The Y coord of the second point
325 | /// The color to use
326 | public static void DrawLine(this SpriteBatch spriteBatch, float x1, float y1, float x2, float y2, Color color)
327 | {
328 | DrawLine(spriteBatch, new Vector2(x1, y1), new Vector2(x2, y2), color, 1.0f);
329 | }
330 |
331 |
332 | ///
333 | /// Draws a line from point1 to point2 with an offset
334 | ///
335 | /// The destination drawing surface
336 | /// The X coord of the first point
337 | /// The Y coord of the first point
338 | /// The X coord of the second point
339 | /// The Y coord of the second point
340 | /// The color to use
341 | /// The thickness of the line
342 | public static void DrawLine(this SpriteBatch spriteBatch, float x1, float y1, float x2, float y2, Color color, float thickness)
343 | {
344 | DrawLine(spriteBatch, new Vector2(x1, y1), new Vector2(x2, y2), color, thickness);
345 | }
346 |
347 |
348 | ///
349 | /// Draws a line from point1 to point2 with an offset
350 | ///
351 | /// The destination drawing surface
352 | /// The first point
353 | /// The second point
354 | /// The color to use
355 | public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color)
356 | {
357 | DrawLine(spriteBatch, point1, point2, color, 1.0f);
358 | }
359 |
360 |
361 | ///
362 | /// Draws a line from point1 to point2 with an offset
363 | ///
364 | /// The destination drawing surface
365 | /// The first point
366 | /// The second point
367 | /// The color to use
368 | /// The thickness of the line
369 | public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point1, Vector2 point2, Color color, float thickness)
370 | {
371 | // calculate the distance between the two vectors
372 | float distance = Vector2.Distance(point1, point2);
373 |
374 | // calculate the angle between the two vectors
375 | float angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
376 |
377 | DrawLine(spriteBatch, point1, distance, angle, color, thickness);
378 | }
379 |
380 |
381 | ///
382 | /// Draws a line from point1 to point2 with an offset
383 | ///
384 | /// The destination drawing surface
385 | /// The starting point
386 | /// The length of the line
387 | /// The angle of this line from the starting point in radians
388 | /// The color to use
389 | public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point, float length, float angle, Color color)
390 | {
391 | DrawLine(spriteBatch, point, length, angle, color, 1.0f);
392 | }
393 |
394 |
395 | ///
396 | /// Draws a line from point1 to point2 with an offset
397 | ///
398 | /// The destination drawing surface
399 | /// The starting point
400 | /// The length of the line
401 | /// The angle of this line from the starting point
402 | /// The color to use
403 | /// The thickness of the line
404 | public static void DrawLine(this SpriteBatch spriteBatch, Vector2 point, float length, float angle, Color color, float thickness)
405 | {
406 | if (pixel == null)
407 | {
408 | CreateThePixel(spriteBatch);
409 | }
410 |
411 | // stretch the pixel between the two vectors
412 | spriteBatch.Draw(pixel,
413 | point,
414 | null,
415 | color,
416 | angle,
417 | Vector2.Zero,
418 | new Vector2(length, thickness),
419 | SpriteEffects.None,
420 | 0);
421 | }
422 |
423 | #endregion
424 |
425 |
426 | #region PutPixel
427 |
428 | public static void PutPixel(this SpriteBatch spriteBatch, float x, float y, Color color)
429 | {
430 | PutPixel(spriteBatch, new Vector2(x, y), color);
431 | }
432 |
433 |
434 | public static void PutPixel(this SpriteBatch spriteBatch, Vector2 position, Color color)
435 | {
436 | if (pixel == null)
437 | {
438 | CreateThePixel(spriteBatch);
439 | }
440 |
441 | spriteBatch.Draw(pixel, position, color);
442 | }
443 |
444 | #endregion
445 |
446 |
447 | #region DrawCircle
448 |
449 | ///
450 | /// Draw a circle
451 | ///
452 | /// The destination drawing surface
453 | /// The center of the circle
454 | /// The radius of the circle
455 | /// The number of sides to generate
456 | /// The color of the circle
457 | public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color)
458 | {
459 | DrawPoints(spriteBatch, center, CreateCircle(radius, sides), color, 1.0f);
460 | }
461 |
462 |
463 | ///
464 | /// Draw a circle
465 | ///
466 | /// The destination drawing surface
467 | /// The center of the circle
468 | /// The radius of the circle
469 | /// The number of sides to generate
470 | /// The color of the circle
471 | /// The thickness of the lines used
472 | public static void DrawCircle(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, Color color, float thickness)
473 | {
474 | DrawPoints(spriteBatch, center, CreateCircle(radius, sides), color, thickness);
475 | }
476 |
477 |
478 | ///
479 | /// Draw a circle
480 | ///
481 | /// The destination drawing surface
482 | /// The center X of the circle
483 | /// The center Y of the circle
484 | /// The radius of the circle
485 | /// The number of sides to generate
486 | /// The color of the circle
487 | public static void DrawCircle(this SpriteBatch spriteBatch, float x, float y, float radius, int sides, Color color)
488 | {
489 | DrawPoints(spriteBatch, new Vector2(x, y), CreateCircle(radius, sides), color, 1.0f);
490 | }
491 |
492 |
493 | ///
494 | /// Draw a circle
495 | ///
496 | /// The destination drawing surface
497 | /// The center X of the circle
498 | /// The center Y of the circle
499 | /// The radius of the circle
500 | /// The number of sides to generate
501 | /// The color of the circle
502 | /// The thickness of the lines used
503 | public static void DrawCircle(this SpriteBatch spriteBatch, float x, float y, float radius, int sides, Color color, float thickness)
504 | {
505 | DrawPoints(spriteBatch, new Vector2(x, y), CreateCircle(radius, sides), color, thickness);
506 | }
507 |
508 | #endregion
509 |
510 |
511 | #region DrawArc
512 |
513 | ///
514 | /// Draw a arc
515 | ///
516 | /// The destination drawing surface
517 | /// The center of the arc
518 | /// The radius of the arc
519 | /// The number of sides to generate
520 | /// The starting angle of arc, 0 being to the east, increasing as you go clockwise
521 | /// The number of radians to draw, clockwise from the starting angle
522 | /// The color of the arc
523 | public static void DrawArc(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, float startingAngle, float radians, Color color)
524 | {
525 | DrawArc(spriteBatch, center, radius, sides, startingAngle, radians, color, 1.0f);
526 | }
527 |
528 |
529 | ///
530 | /// Draw a arc
531 | ///
532 | /// The destination drawing surface
533 | /// The center of the arc
534 | /// The radius of the arc
535 | /// The number of sides to generate
536 | /// The starting angle of arc, 0 being to the east, increasing as you go clockwise
537 | /// The number of radians to draw, clockwise from the starting angle
538 | /// The color of the arc
539 | /// The thickness of the arc
540 | public static void DrawArc(this SpriteBatch spriteBatch, Vector2 center, float radius, int sides, float startingAngle, float radians, Color color, float thickness)
541 | {
542 | List arc = CreateArc(radius, sides, startingAngle, radians);
543 | //List arc = CreateArc2(radius, sides, startingAngle, degrees);
544 | DrawPoints(spriteBatch, center, arc, color, thickness);
545 | }
546 |
547 | #endregion
548 |
549 |
550 | }
551 | }
--------------------------------------------------------------------------------
/Sources/Spritesheet.Sample.macOS/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Sources/Spritesheet.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spritesheet", "Spritesheet\Spritesheet.csproj", "{C57AB359-8743-47D2-9731-9A1AEF32856E}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spritesheet.Sample.macOS", "Spritesheet.Sample.macOS\Spritesheet.Sample.macOS.csproj", "{399438CD-9CCD-410B-9491-B27746063359}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {C57AB359-8743-47D2-9731-9A1AEF32856E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {C57AB359-8743-47D2-9731-9A1AEF32856E}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {C57AB359-8743-47D2-9731-9A1AEF32856E}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {C57AB359-8743-47D2-9731-9A1AEF32856E}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {399438CD-9CCD-410B-9491-B27746063359}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {399438CD-9CCD-410B-9491-B27746063359}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {399438CD-9CCD-410B-9491-B27746063359}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | EndGlobalSection
22 | EndGlobal
23 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Animation.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet
2 | {
3 | using System;
4 | using Microsoft.Xna.Framework;
5 | using Microsoft.Xna.Framework.Graphics;
6 | using System.Linq;
7 |
8 | public class Animation
9 | {
10 | public Animation(Frame[] frames)
11 | {
12 | this.Frames = frames;
13 | this.TotalDuration = frames.Sum(x => x.Duration);
14 | this.CurrentFrame = this.Frames[0];
15 | }
16 |
17 | #region Cloning
18 |
19 | public Animation Clone() => new Animation(this.Frames);
20 |
21 | public Animation FlipX() => new Animation(this.Frames.Select(x => x.FlipX()).ToArray());
22 |
23 | public Animation FlipY() => new Animation(this.Frames.Select(x => x.FlipY()).ToArray());
24 |
25 | #endregion
26 |
27 | private Repeat.Mode repeat;
28 |
29 | public bool IsStarted { get; private set; }
30 |
31 | public Frame CurrentFrame { get; private set; }
32 |
33 | public double Time { get; private set; }
34 |
35 | public Frame[] Frames { get; }
36 |
37 | public double TotalDuration { get; }
38 |
39 | private Frame GetFrame(double amount)
40 | {
41 | var time = amount * this.TotalDuration;
42 | var current = 0.0;
43 |
44 | for (int i = 0; i < Frames.Length; i++)
45 | {
46 | var frame = Frames[i];
47 | current += frame.Duration;
48 | if (time <= current)
49 | {
50 | return frame;
51 | }
52 | }
53 |
54 | return null;
55 | }
56 |
57 | public void Start(Repeat.Mode repeat)
58 | {
59 | this.Time = 0;
60 | this.repeat = repeat;
61 | this.IsStarted = true;
62 | }
63 |
64 | public void Pause() => this.IsStarted = false;
65 |
66 | public void Resume() => this.IsStarted = true;
67 |
68 | public void Stop() => this.Pause();
69 |
70 | public bool Update(GameTime time)
71 | {
72 | if (this.IsStarted)
73 | {
74 | this.Time += time.ElapsedGameTime.TotalMilliseconds;
75 |
76 | var amount = this.UpdateCurrentFrame();
77 |
78 | if (Repeat.IsFinished(repeat, amount))
79 | {
80 | this.Stop();
81 | return true;
82 | }
83 | }
84 | return false;
85 | }
86 |
87 | private double UpdateCurrentFrame()
88 | {
89 | // Updating current frame
90 | var interval = this.CurrentFrame.Duration;
91 | var amount = (float)(this.Time / this.TotalDuration);
92 | var value = Repeat.Calculate(this.repeat, amount);
93 | var i = Math.Max(0, Math.Min(Frames.Length - 1, (int)(value * Frames.Length)));
94 | this.CurrentFrame = this.Frames[i];
95 | return amount;
96 | }
97 |
98 | public void Reset()
99 | {
100 | this.Time = 0;
101 | this.repeat = Repeat.Mode.Once;
102 | this.UpdateCurrentFrame();
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/AnimationDefinition.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet
2 | {
3 | using System.Linq;
4 |
5 | public class AnimationDefinition
6 | {
7 | public AnimationDefinition(string name, Frame[] frames)
8 | {
9 | this.Name = name;
10 | }
11 |
12 | public string Name { get; }
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Base/Repeat.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet
2 | {
3 | using System;
4 |
5 | public static class Repeat
6 | {
7 | ///
8 | /// A repeat mode for any kind of animation.
9 | ///
10 | public enum Mode
11 | {
12 | Once,
13 | OnceWithReverse,
14 | Loop,
15 | LoopWithReverse,
16 | Reverse,
17 | }
18 |
19 | ///
20 | /// Calculate the current value for a time between zero and one, and a curve mode.
21 | ///
22 | /// Curve mode.
23 | /// Current time (1.0f represents the one way total duration).
24 | public static double Calculate(Mode mode, double time)
25 | {
26 | if (mode == Mode.Once)
27 | time = Math.Min(Math.Max(time, 0.0f), 1.0f);
28 | else if (mode == Mode.Reverse)
29 | time = 1.0f - Math.Min(Math.Max(time, 0.0f), 1.0f);
30 | else if (mode == Mode.Loop)
31 | time %= 1.0f;
32 | else if (mode == Mode.LoopWithReverse)
33 | time %= 2.0f;
34 |
35 | if ((mode == Mode.OnceWithReverse || mode == Mode.LoopWithReverse) && time > 1.0f)
36 | {
37 | time = 2.0f - time;
38 | }
39 |
40 | return time;
41 | }
42 |
43 | ///
44 | /// Indicates whether the animation is finished.
45 | ///
46 | ///
47 | ///
48 | ///
49 | public static bool IsFinished(Mode mode, double time) => (((mode == Repeat.Mode.Once || mode == Repeat.Mode.Reverse) && time >= 1.0f) ||
50 | (mode == Repeat.Mode.OnceWithReverse && time >= 2.0f));
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Extensions/SpriteBatchExtensions.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet
2 | {
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 |
6 | public static class SpriteBatchExtensions
7 | {
8 | public static void Draw(this SpriteBatch batch, Frame frame, Vector2 position, Color? color = null, float rotation = 0, Vector2? scale = null, float layerDepth = 0)
9 | {
10 | batch.Draw(texture: frame.Texture,
11 | position: position,
12 | sourceRectangle: frame.Area,
13 | color: color ?? Color.White,
14 | rotation: rotation,
15 | origin: frame.Origin.ToVector2(),
16 | scale: scale ?? Vector2.One,
17 | effects: frame.Effects,
18 | layerDepth: layerDepth);
19 | }
20 |
21 | public static void Draw(this SpriteBatch batch, Animation animation, Vector2 position, Color? color = null, float rotation = 0, Vector2? scale = null, float layerDepth = 0)
22 | {
23 | batch.Draw(animation.CurrentFrame, position, color, rotation, scale, layerDepth);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Frame.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet
2 | {
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 |
6 | public class Frame
7 | {
8 | public Frame(Texture2D texture, Rectangle area, Point origin, double duration, SpriteEffects effects)
9 | {
10 | this.Texture = texture;
11 | this.Area = area;
12 | this.Origin = origin;
13 | this.Duration = duration;
14 | this.Effects = effects;
15 | }
16 |
17 | public Texture2D Texture { get; }
18 |
19 | public Rectangle Area { get; }
20 |
21 | public Point Origin { get; }
22 |
23 | public double Duration { get; }
24 |
25 | public SpriteEffects Effects { get; }
26 |
27 | #region Cloning
28 |
29 | public Frame FlipX()
30 | {
31 | return new Frame(this.Texture, this.Area, this.Origin, this.Duration, SpriteEffects.FlipHorizontally);
32 | }
33 |
34 | public Frame FlipY()
35 | {
36 | return new Frame(this.Texture, this.Area, this.Origin, this.Duration, SpriteEffects.FlipVertically);
37 | }
38 |
39 | public Frame WithDuration(double duration)
40 | {
41 | return new Frame(this.Texture, this.Area, this.Origin, duration, this.Effects);
42 | }
43 |
44 | public Frame WithOrigin(int x, int y)
45 | {
46 | return new Frame(this.Texture, this.Area, new Point(x, y), this.Duration, this.Effects);
47 | }
48 |
49 | public Frame WithArea(Rectangle area)
50 | {
51 | return new Frame(this.Texture, area, this.Origin, this.Duration, this.Effects);
52 | }
53 |
54 | #endregion
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 |
4 | // Information about this assembly is defined by the following attributes.
5 | // Change them to the values specific to your project.
6 |
7 | [assembly: AssemblyTitle("Spritesheet")]
8 | [assembly: AssemblyDescription("")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("")]
12 | [assembly: AssemblyCopyright("${AuthorCopyright}")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 |
20 | [assembly: AssemblyVersion("1.0.*")]
21 |
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 |
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Spritesheet.cs:
--------------------------------------------------------------------------------
1 | namespace Spritesheet
2 | {
3 | using Microsoft.Xna.Framework;
4 | using Microsoft.Xna.Framework.Graphics;
5 | using System.Linq;
6 |
7 | public class Spritesheet
8 | {
9 | public Spritesheet(Texture2D texture) : this(texture,null,null,null) {}
10 |
11 | private Spritesheet(Texture2D texture, Point? cellSize = null, Point? cellOffset = null, Point? cellOrigin = null, double frameDuration = 200.0f, SpriteEffects frameEffects = SpriteEffects.None)
12 | {
13 | this.Texture = texture;
14 | this.CellSize = cellSize ?? new Point(32,32);
15 | this.CellOffset = cellOffset ?? new Point(0,0);
16 | this.CellOrigin = cellOrigin ?? this.CellSize / new Point(2,2);
17 | this.FrameDefaultDuration = frameDuration;
18 | this.FrameDefaultEffects = frameEffects;
19 | }
20 |
21 | #region Properties
22 |
23 | public Texture2D Texture { get; }
24 |
25 | public Point CellSize { get; }
26 |
27 | public Point CellOffset { get; }
28 |
29 | public Point CellOrigin { get; }
30 |
31 | public double FrameDefaultDuration { get; }
32 |
33 | public SpriteEffects FrameDefaultEffects { get; }
34 |
35 | #endregion
36 |
37 | #region Grid
38 |
39 | public Spritesheet WithGrid((int w, int h) cell, (int x, int y) offset, (int x, int y) cellOrigin)
40 | {
41 | return new Spritesheet(this.Texture, new Point(cell.w, cell.h), new Point(offset.x, offset.y), new Point(cellOrigin.x, cellOrigin.y));
42 | }
43 |
44 | public Spritesheet WithGrid((int w, int h) cell, (int x, int y) offset)
45 | {
46 | return this.WithGrid(cell, offset, (cell.w / 2, cell.h / 2));
47 | }
48 |
49 | public Spritesheet WithGrid((int w, int h) cell)
50 | {
51 | return this.WithGrid(cell, (0,0), (cell.w / 2, cell.h / 2));
52 | }
53 |
54 | #endregion
55 |
56 | #region Frame default settings
57 |
58 | public Spritesheet WithFrameDuration(double durationInMs)
59 | {
60 | return new Spritesheet(this.Texture, this.CellSize, this.CellOffset, this.CellOrigin, durationInMs, this.FrameDefaultEffects);
61 | }
62 |
63 | public Spritesheet WithFrameEffect(SpriteEffects effects)
64 | {
65 | return new Spritesheet(this.Texture, this.CellSize, this.CellOffset, this.CellOrigin, this.FrameDefaultDuration, effects);
66 | }
67 |
68 | #endregion
69 |
70 | public Frame CreateFrame(int x, int y, double duration = 0.0, SpriteEffects effects = SpriteEffects.None)
71 | {
72 | x = x * this.CellSize.X + this.CellOffset.X;
73 | y = y * this.CellSize.Y + this.CellOffset.Y;
74 | var area = new Rectangle(x, y, this.CellSize.X, this.CellSize.Y);
75 | return new Frame(this.Texture, area, this.CellOrigin, duration, effects);
76 | }
77 |
78 | public Animation CreateAnimation(params (int x, int y, double duration, SpriteEffects effects)[] frames)
79 | {
80 | return new Animation(frames.Select(f => this.CreateFrame(f.x, f.y, f.duration, f.effects)).ToArray());
81 | }
82 |
83 | public Animation CreateAnimation(params (int x, int y, double duration)[] frames)
84 | {
85 | return this.CreateAnimation(frames.Select(x => (x.x, x.y, x.duration, this.FrameDefaultEffects)).ToArray());
86 | }
87 |
88 | public Animation CreateAnimation(params (int x, int y)[] frames)
89 | {
90 | return this.CreateAnimation(frames.Select(x => (x.x, x.y, this.FrameDefaultDuration, this.FrameDefaultEffects)).ToArray());
91 | }
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/Spritesheet.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | Debug
4 | AnyCPU
5 | {C57AB359-8743-47D2-9731-9A1AEF32856E}
6 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
7 | true
8 | Library
9 | Spritesheet
10 | Spritesheet
11 | v4.5
12 | Profile111
13 |
14 |
15 | true
16 | full
17 | false
18 | bin\Debug
19 | DEBUG;
20 | prompt
21 | 4
22 |
23 |
24 | true
25 | bin\Release
26 | prompt
27 | 4
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | ..\packages\MonoGame.Framework.Portable.3.6.0.1625\lib\portable-net45+win8+wpa81\MonoGame.Framework.dll
41 |
42 |
43 | ..\packages\System.ValueTuple.4.3.1\lib\netstandard1.0\System.ValueTuple.dll
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/Sources/Spritesheet/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------