tag:blogger.com,1999:blog-69242189209451050612024-03-13T04:02:05.959-07:00Silicon Commander GamesVisit the <a href="http://www.siliconcommandergames.com">
Silicon Commander Games</a> web site!LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.comBlogger26125tag:blogger.com,1999:blog-6924218920945105061.post-68167788574952877532014-01-05T19:04:00.002-08:002014-01-05T19:04:19.554-08:00Solar Vengeance 8In development, this new release will once again target Windows. An early development screen shot!<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-kxK7QezSGts/UsodEhQQnNI/AAAAAAAAA_I/hCuwcFiPvCs/s1600/SV8ScreenShot1.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" src="http://2.bp.blogspot.com/-kxK7QezSGts/UsodEhQQnNI/AAAAAAAAA_I/hCuwcFiPvCs/s1600/SV8ScreenShot1.png" height="280" width="400" /></a></div>
<br />LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com2tag:blogger.com,1999:blog-6924218920945105061.post-34274253358000575142013-02-25T08:35:00.000-08:002013-02-25T08:35:04.468-08:00iWar II (WinWar II) Production<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-Cx1tBMbWCmU/USuQWQOeg-I/AAAAAAAAA64/OfMh0nz3tqE/s1600/iWarIIProduction.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="250" src="http://1.bp.blogspot.com/-Cx1tBMbWCmU/USuQWQOeg-I/AAAAAAAAA64/OfMh0nz3tqE/s400/iWarIIProduction.png" width="400" /></a></div>
Here's a sneak peek at iWar II, the successor to WinWar II, and also a sneak peek into my development environment on the Mac.<br />
<br />
Over the next few posts I intend to describe different aspects of iWarII game play, and how it's shaping up overall. In this post I'll focus on production.<br />
<br />
Like I envisioned a few weeks (or was it days?) ago, you no longer will simply select what units to produce, click a "build" button, and presto! Now, you more realistically divide your incoming resources into the different unit types available. See the list of units along right right, with sliders next to each one? You use the sliders to control how much of the incoming resources toward producing that unit type. The little dials next to the sliders show you what percentage of that unit is completed. If you distribute your resources among several units types, we start getting realistic build times for things like battleships, measured in a few years. Of course, you can pump all of your resources into a single unit type, in which case said battleship could probably be produced in six months or so, depending on your inflow.<br />
<br />
There's a pretty sophisticated resources production engine running under the hood here. All your zones have a value, which determines how many resources they produce. The resources are then automatically "shipped" to the closest factory zone. The farther away the factory zone is, the more resources lost due to shipping inefficiency. Shipping over sea zones if 5 times as costly as over land zones. The most beautiful part of all this is that it's completely under the hood, and the player won't need to manage any of it. However, the players who bother to learn the game will be able to benefit from their knowledge. For example, prudent players can build factories in other zones to increase their production efficiency. Of course, these factories themselves are items to produce, so they take some time to build.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com4tag:blogger.com,1999:blog-6924218920945105061.post-34272760368682390762013-02-15T06:02:00.000-08:002013-02-15T06:07:34.648-08:00Divide and Conquer!<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-M3A2pE1acJM/UR48dX0cyHI/AAAAAAAAA6o/_dbFP8p7Otk/s1600/iWarII.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="300" src="http://3.bp.blogspot.com/-M3A2pE1acJM/UR48dX0cyHI/AAAAAAAAA6o/_dbFP8p7Otk/s400/iWarII.png" width="400" /></a></div>
This morning sees the completion of some unit management features of the game. You can divide units by selecting your force counts with the sliders, or the "Half" button, and then tapping the "Divide" button. The selected Unit nicely divides into two, and the two new units slowly move a few pixels away from each other.<br />
<br />
To re-group, you can click the zone itself, and then tap the "Consolidate" button. All the like-type units will nicely move into one stack, and merge into single units.<br />
<br />
Another thing to notice here is how the Commander of the Army is being reported, just above the mini-map. Armies will fight at a substantial bonus when they are close to a Commander. Commanders will also help Armies rally and more quickly overcome fatigue.<br />
<br />
My thought have turned to how you will raise new forces in the game. In older versions you simply selected what you want to build and that was that. But what if it took a realistic amount of time to build units? It took 2 to 3 years to build a Battleship during World War II. For game purposes, maybe I could speed this up to 1 year. But imagine the tough choices that emerge when you have to plan that far ahead? Building major units is no longer a snap decision, but something you'd really agonize over.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-78232831066099382732013-02-12T05:25:00.004-08:002013-02-12T05:26:14.285-08:00iWarII Developments<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-VnOdi5kkCZw/URpABnP2BaI/AAAAAAAAA6Y/am0GM3_qH18/s1600/iOS+Simulator+Screen+shot+Feb+12,+2013+8.11.25+AM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="300" src="http://2.bp.blogspot.com/-VnOdi5kkCZw/URpABnP2BaI/AAAAAAAAA6Y/am0GM3_qH18/s400/iOS+Simulator+Screen+shot+Feb+12,+2013+8.11.25+AM.png" width="400" /></a></div>
Every day adding a few new zones to the world, tweaking the unit selection and movement, establishing the values of the land zones. iWarII development has some good momentum!<br />
<br />
From the screen shot here a few things about the new release are apparent:<br />
<br />
<br />
<ul>
<li>Each Major Power will begin the game with a number of Commanders, randomly generated. Commanders provide strong leadership bonuses to land forces. The closer a land unit is to a Commander, the greater the bonus.</li>
<li>Commanding your forces will be a simple matter of touching them on the map and dragging them to where you want them to go. More complicated things, like splitting and combining forces, will be handled via menu buttons.</li>
<li>We have a fog of war, and zones outside your visibility range are darkened.</li>
</ul>
<div>
I'm quite excited about the random Commanders aspect. Rather than Montgomery facing off against Rommel in Africa, the UK player might have his Field Marshall Jeans facing off against Gebaumann and his armored units in Algeria, and US General Pello might be tasked with protecting the Philippines against Japanese invasion. Each Commander will have a number of randomly generated stats that will determine their effectiveness, and capacity to improve. Commanders will also gain experience over time. Losing an experienced Commander will thus be a serious setback. A new Commander will eventually be spawned at your capital to replace the one lost, but they will begin with zero experience.</div>
LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-90990127362776067422013-02-09T05:22:00.004-08:002013-02-09T05:22:41.654-08:00Getting Apple's Linker to Cooperate<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-nsAgHhCeVS8/URZJx2XpO-I/AAAAAAAAA6A/vBTMcJKxQfI/s1600/crashlog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="http://3.bp.blogspot.com/-nsAgHhCeVS8/URZJx2XpO-I/AAAAAAAAA6A/vBTMcJKxQfI/s1600/crashlog.png" /></a></div>
<br />
If you came to this entry from a Google search for "cocos2d archive crash doesNotRecognizeSelector", you've come to the right place! I've just spent the past 2 hours figuring out why my iPad game ran fine for me, but was rejected by the app store due to a crash.<br />
<br />
Lesson one: Test your app in Release mode!<br />
<br />
Building in Release mode as opposed to Debug mode causes more compiler optimizations to occur, and can reveal unexpected and hard to track down bugs. You can save yourself alot of trouble by detecting these during your development, before you submit your freshly minted app for approval.<br />
<br />
At first I was puzzled by the rejection, since I could not duplicate the error when I clicked the Proceed button. After some research, I realized I had to <a href="http://developer.apple.com/library/ios/#qa/qa1764/_index.html" target="_blank">put an archived build onto my iPad using iTunes</a> to reproduce the issue. I did so, and sure enough, a crash after pressing the Proceed button! I've since learned that just running the app from within Xcode is good enough, as long as you target your Scheme to run in Release instead of Debug mode.<br />
<br />
Look at the crash log above. So, why is the code apparently calling a Selector that it doesn't recognize?<br />
<br />
I finally tracked this down to the Linker eliminating the CCGLView class from the build, because it incorrectly thought it wasn't being referenced. This caused any reference to methods called on CCGLView to throw an exception, doesNotRecognizeSelector. I'm not completely clear why the Linker came to this conclusion, but I was able to coerce the Linker to include the class by adding one line of code at the start of the CCTextureCache.m method:<br />
<br />
<span style="font-family: Menlo; font-size: 11px;">[</span><span style="color: #4f8187; font-family: Menlo; font-size: 11px;">CCGLView</span><span style="font-family: Menlo; font-size: 11px;"> </span><span style="color: #3d1d81; font-family: Menlo; font-size: 11px;">class</span><span style="font-family: Menlo; font-size: 11px;">];</span><br />
<br />
This line was enough to convince the Linker to include the class, and the crash no longer occurs in Release mode, and not even in an archived build that I copied to the iPad.<br />
<br />
Time to resubmit to the app store!<br />
<br />
<br />
<div style="color: #4f8187; font-family: Menlo; font-size: 11px;">
<br /></div>
LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-83428601105272185512013-02-02T04:52:00.003-08:002013-02-02T04:52:32.240-08:00World Taking Shape<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-JQNkRzbWYjk/UQ0KKa5GjLI/AAAAAAAAA5w/rZPO0Yv4-S8/s1600/MapSetEditor.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="220" src="http://4.bp.blogspot.com/-JQNkRzbWYjk/UQ0KKa5GjLI/AAAAAAAAA5w/rZPO0Yv4-S8/s400/MapSetEditor.png" width="400" /></a></div>
With Solar Vengeance wrapped up and submitted to the iTunes App Store, I've begun working on a version of WinWar II for the iPad. It only makes sense that I title the App "iWarII" since I've moved from Windows to iOS development.<br />
<br />
Treading familiar ground here again by developing my MapSet Editor tool in conjunction with the game itself. We start with a smattering of zones in Europe and a couple of sea zones, and will build out until the whole world is completed. This time I built in a nice feature into the MapSet Editor that lets me load reference images to correctly establish the shapes of the nations.<br />
<br />
Ideas for game play itself are also brewing. I want iWarII to be focused on managing your forces, and your commanders. Each nation will have a number of randomly generated commanders, complete with portrait images and randomly generated, but reasonable sounding, names. Each commander will be able to issue a number of orders to units in their vicinity, and units will fight more effectively when they are closer to a commander. Units will fight best when a commander is actually attached to them.<br />
<br />
The commanders will represent probably the most important resource in the game, with their limited capacity to issue orders. You'll have to move and manage them efficiently as you execute your battle plans.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com1tag:blogger.com,1999:blog-6924218920945105061.post-32736482728408839592013-01-21T03:41:00.002-08:002013-01-21T03:41:43.832-08:00A Tale of New Brains<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-qbIfHCtO9xY/UP0mR84NbsI/AAAAAAAAA5c/qQFcjZMUMdM/s1600/iOS+Simulator+Screen+shot+Jan+21,+2013+6.26.00+AM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="300" src="http://3.bp.blogspot.com/-qbIfHCtO9xY/UP0mR84NbsI/AAAAAAAAA5c/qQFcjZMUMdM/s400/iOS+Simulator+Screen+shot+Jan+21,+2013+6.26.00+AM.png" width="400" /></a></div>
In the latest incarnation of Solar Vengeance, this time written in Objective C and targeted at the iPad, I'm adding a few new computer Brain opponents to spice up the competition.<br />
<br />
The most recently completed Brain is called <i>Maximizar</i>, and tries to get an early jump in resource development by building an early Refinery StarShip. Refineries are one of three new StarShips types in this version, and they will double the value of any Resources deposited onto them by Freighters. Once the Resources are at a Refinery. But Refineries, like BattleStations, can build StarShips themselves. Also, like BattleStations, they have a fixed value of 6 Engines. However, Refineries don't have Hull to absorb damage, so they are relatively fragile platforms.<br />
<br />
In the new SV, you don't explicitly select which Brains you want to fight. Rather, you set a "Brain Calibration" level to control how tough you want your opponents to be. The setting ranges from "Training" (where you go up against instances of <i>Beginner</i> only) to "Easy", "Moderate", "Hard", and "Extreme", which introduces beat2k's masterpieces of <i>StrategoV</i> (converted by me from his <i>Stratego4</i> source code) and <i>Organism</i>. I rated <i>Maximizar</i> a challenge level of "Moderate" on this scale.<br />
<br />
Speaking of <i>StrategoV</i> - believe it or not I managed to finally convert the 8,000+ lines of C# code to Objective C after a few false starts, some sweat, and some numb fingers. Thank god for Search and Replace in Xcode!<br />
<br />
The next new Brain I created is named <i>Athenus</i>, and follows a more straightforward play style, using WarShips, Drones, and judicious use of InkSpots and Startillery. I rated Athenus a "Hard" on the above scale, although it has managed to hold its own even against Stratego5 and Organism. It's kind of a spiritual successor to <i>Argus</i> (who also appears here, unchanged), but is much tougher.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com2tag:blogger.com,1999:blog-6924218920945105061.post-617553636074045312012-12-13T16:28:00.004-08:002012-12-13T16:28:57.580-08:00Old Dog New TricksIt's been roughly 2 weeks steeping myself in Objective C, XCode, and iOS programming, and I've made a respectable amount of progress. Solar Vengeance for the iPad is coming closer to a reality. In this week I've ...<br />
<br />
<ul>
<li>Gotten a handle on UIKit/Appkit, and Apple's MVC application development architecture. In particular, I've figured out how to create UIViews that represent different screens in the application, and how to easily navigate between these screens. I've also developed a simple, custom color picker control, and gotten comfortable with the ubiquitous TableView component.</li>
<li>Port much of the game's "model" classes into Objective C, and wrapped my mind around the ARC programming concept. Coming from garbage-collected C# this was a bit of a leap, but Apple's recent ARC feature eases memory management substantially.</li>
<li>Successfully integrated the cocos2d OpenGL game engine into my app, and have some StarSystems, Shields, Scanners, a starfield background, and nebula rendering.</li>
<li>Build the foundation of my RealTimeEngine class, which will manage multiplayer games, and keep the impulses pumping in general. The RTE is kicking off an impulse every second, and my prototype game is chugging away, with Resources being generated! This also includes the beginning of the game order and state change architecture, with a Build Shield and Build Scanner order already operational.</li>
</ul>
<div>
A major challenge ahead will be working on the client/server layer to facilitate multiplayer matches. But I have a head start. My C# PrismServer is running on a dedicated machine at home, and I think I can write an Objective C PrismClient class to communicate with it.</div>
<div>
<br /></div>
<div>
I leave you now with a happy accident as I was testing out some tiled graphics to represent nebula. I had accidentally rendered the tiles twice as large as they needed to be for the nebula, but when I saw the result, I liked how the nebula now kind of looks concentrated and brighter where it is thickest, thanks to the translucent tiles blending on top of each other.</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-YwEagz51HRI/UMpyoY3TBNI/AAAAAAAAA40/sZosiYYRigU/s1600/SV_WIP2.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="497" src="http://4.bp.blogspot.com/-YwEagz51HRI/UMpyoY3TBNI/AAAAAAAAA40/sZosiYYRigU/s640/SV_WIP2.png" width="640" /></a></div>
<div>
<br /></div>
LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com1tag:blogger.com,1999:blog-6924218920945105061.post-519502720846691292012-12-03T20:24:00.003-08:002012-12-03T20:24:55.740-08:00Just a screen shot of some work in progress ...<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-8CbBiTalHNA/UL17BN-R42I/AAAAAAAAA4k/A-2mFueogec/s1600/Screen+Shot+2012-12-03+at+10.18.24+PM.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="499" src="http://3.bp.blogspot.com/-8CbBiTalHNA/UL17BN-R42I/AAAAAAAAA4k/A-2mFueogec/s640/Screen+Shot+2012-12-03+at+10.18.24+PM.png" width="640" /></a></div>
<br />LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com4tag:blogger.com,1999:blog-6924218920945105061.post-56661782901383990272009-09-04T05:39:00.000-07:002009-09-04T05:48:33.952-07:00Solar Vengeance 6 Released<a href="http://www.siliconcommandergames.com/SVSilverlight/SV6.htm">http://www.siliconcommandergames.com/SVSilverlight/SV6.htm</a><br /><br />It took a few months of part time effort to port <span id="SPELLING_ERROR_0" class="blsp-spelling-error">SV</span>5 to <span id="SPELLING_ERROR_1" class="blsp-spelling-error">Silverlight</span>, and now we have <span id="SPELLING_ERROR_2" class="blsp-spelling-error">SV</span>6. There are some decided advantages to the browser based version:<br /><br />1) You don't need to to download the latest build, that's taken care of automatically.<br />2) The graphics performance of the <span id="SPELLING_ERROR_3" class="blsp-spelling-error">Silverlight</span> sprites outperforms the <span id="SPELLING_ERROR_4" class="blsp-spelling-error">GDI</span>+ based graphics of <span id="SPELLING_ERROR_5" class="blsp-spelling-error">SV</span>5.<br /><br />A <span id="SPELLING_ERROR_6" class="blsp-spelling-error">Silverlight</span> version also poses some challenges that I still need to overcome. Biggest of these is providing a way for people to run a debug version of the app so they can develop and debug their Scenarios and Brains. Once I crack this I will publish the updated Scenario and Brain <span id="SPELLING_ERROR_7" class="blsp-spelling-error">API's</span> and promote these to developers.<br /><br />One of the hallmarks of Silicon Commander Games was the extensibility, and I think we've pushed the envelope by providing robust <span id="SPELLING_ERROR_8" class="blsp-spelling-error">API's</span> so developers can build their own Scenarios (levels) and Brains (computer <span id="SPELLING_ERROR_9" class="blsp-spelling-error">AI's</span>) that integrate seamlessly into the game. This will continue with <span id="SPELLING_ERROR_10" class="blsp-spelling-error">SV</span>6!<br /><br />Another challenge is to try and rebuild the <span id="SPELLING_ERROR_11" class="blsp-spelling-error">SCG</span> community and get some active players again. I'm hoping this will come naturally when I continue to build up the supporting documentation of the game with strategy guides, examples, etc. If you're reading this now you can help too by logging in and waiting a little bit in the lobby for other people to show up! I look at the logs and see someone like "Z" for example log in, and then 1 minute later log out. Then 5 minutes later someone else does the same thing. I'm guilty of this too some time, but I will try and hang out in the lobby more to catch other players and hopefully get some games logged!!<br /><br />I've also begun work on converting some of the class libraries for <span id="SPELLING_ERROR_12" class="blsp-spelling-error">WinWar</span> II over to <span id="SPELLING_ERROR_13" class="blsp-spelling-error">Silverlight</span>. This includes my tile-based map logical components, and a new <span id="SPELLING_ERROR_14" class="blsp-spelling-error">Silverlight</span> based <span id="SPELLING_ERROR_15" class="blsp-spelling-error">TileBasedGameBoard</span> component that can use my <span id="SPELLING_ERROR_16" class="blsp-spelling-error">MapSet</span> class to render tiles on the map. I'm hoping to port the <span id="SPELLING_ERROR_17" class="blsp-spelling-error">WinWarII</span> logic engine I created for V5 pretty easily to <span id="SPELLING_ERROR_18" class="blsp-spelling-error">Silverlight</span>, then build a new <span id="SPELLING_ERROR_19" class="blsp-spelling-error">UI</span>, much like I did for <span id="SPELLING_ERROR_20" class="blsp-spelling-error">SV</span>6.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com3tag:blogger.com,1999:blog-6924218920945105061.post-63919965500094075182009-07-13T11:33:00.000-07:002009-07-13T11:41:52.932-07:00Say no to Verbose XAML with EasyGrid!<p>EasyGrid is a simple enhancement to the basic Grid layout panel in WPF/Silverlight. The sole purpose of EasyGrid is to eliminate the verbose markup that clutters your XAML when you define Grids with many rows and columns.</p><p>EasyGrid provides a "mini-language" that lets you create all of the rows and columns of the grid by simply providing a value to the EasyGrid's Data property.</p><p>Before getting into the mini-language specifics, lets look at an example. Say we want to define a Grid that contains 4 columns, the first and last a fixed width, and the middle two variable, and 12 rows. You would wind up with markup something like this:<br /><br /><a href="http://3.bp.blogspot.com/_RVcCdy7G7j0/Slt-nBnZTFI/AAAAAAAAAb4/0ZDZk9yMZuM/s1600-h/Source1.png"><img style="WIDTH: 364px; HEIGHT: 362px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5358015390601006162" border="0" alt="" src="http://3.bp.blogspot.com/_RVcCdy7G7j0/Slt-nBnZTFI/AAAAAAAAAb4/0ZDZk9yMZuM/s400/Source1.png" /></a><br /><br />If you're anything like me, looking at markup like this gives you a headache! The EasyGrid version looks like this:<br /><br /><a href="http://2.bp.blogspot.com/_RVcCdy7G7j0/Slt_XWNH66I/AAAAAAAAAcA/SY0-u23pBRA/s1600-h/Source2.png"><img style="WIDTH: 400px; HEIGHT: 27px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5358016220761680802" border="0" alt="" src="http://2.bp.blogspot.com/_RVcCdy7G7j0/Slt_XWNH66I/AAAAAAAAAcA/SY0-u23pBRA/s400/Source2.png" /></a> </p><p><strong>The EasyGrid Mini-Language</strong><br /></p><p>The EasyGrid performs its magic via the Data property, which contains a string that represents all of the rows and columns of the grid. The Data property actually has two modes of operation, a simple mode and a verbose(?!?) mode.</p><p><strong>Simple Mode</strong><br /></p><p>In the simple mode, you can create a grid with a number of rows and columns that all have the "*" sizing specifier by using this syntax:</p><p>Data="CxR"</p><p>where C represents the number of desired columns and R represents the number of desired rows.</p><p>For example:</p><p>Data="12x30"</p><p><strong>Verbose Mode</strong><br /></p><p>In this mode, you use tokens to specify rows and columns. You can also use the "x" character to represent a number of rows or columns with the same sizing specification.</p><p>C - A "C" in the Data string means that the next token(s) will define grid columns.</p><p>R - A "R" in the Data string means that the next token(s) will define grid rows.</p><p># - A number token (for example "12" defines a row or column with a fixed size.</p><p>#* - A number followed by a * (for example 4*) defines a row or column with a proportional size.</p><p>Auto - The "Auto" token defines a row or column with an automatic size.</p><p>#x(token) - When there is a #x preceding a token, it means that the row or column will be repeated the specified number of times. For example, C 5x3* creates 5 columns with sizing of 3*.</p><p>That's all there is to the EasyGrid. Use it in your projects and "say no to verbose XAML!".</p><p><a href="http://www.siliconcommandergames.com/downloads/EasyGrid.zip">Download the EasyGrid component.</a></p>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-35249823295969391522009-07-06T05:56:00.001-07:002009-07-06T06:10:36.989-07:00Solar Vengeance 6 Lobby<a href="http://1.bp.blogspot.com/_RVcCdy7G7j0/SlH3cUZMC3I/AAAAAAAAAbw/Z_VLyEYuRYc/s1600-h/SV6Lobby.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 298px;" src="http://1.bp.blogspot.com/_RVcCdy7G7j0/SlH3cUZMC3I/AAAAAAAAAbw/Z_VLyEYuRYc/s400/SV6Lobby.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5355333497802984306" /></a><br />I completed the multiplayer lobby interface for Solar Vengeance 6 in Silverlight. Click the link below to log into the new lobby. You can set your profile, including a Glyph image, and chat with other users in the lobby.<br /><br />Implementing the lobby in the app was easy once my PrismServer components were ported to Silverlight. The PrismConnection component provides an easy way to connect a Silverlight app to a running PrismServer.<br /><br />In SV6 I create the PrismConnection component in code, but you could also create it in your XAML since it descends from DependencyObject. You'd just need to be sure to place it within a ContentControl, because Silverlight panels can't take DependencyObjects directly. When defined in XAML, you can set the properties like Host, Port, and SubjectName in your XAML, as well as hook up event handlers.<br /><br />In my custom application class I declare a private variable to hold the PrismConnection object, and a public property to provide access to it in other pages. In Application StartUp event, I create the instance:<br /><br />_prism = new PrismConnection("1.2.3.4", 4502, false);<br />_prism.SubjectName = "SV6";<br /><br />You'd replace "1.2.3.4" with the host name or IP address where your PrismServer is running.<br /><br />To connect, call the Connect method, which will eventually fire either the ConnectSuccessful or ConnectFailed events.<br /><br />In your ConnectSuccessful event handler you can call either Login (for existing users) or LoginNew (for new users). Login takes 2 parameters, a user name and a password. LoginNew takes 1 parameter, an instance of a PrismUser object that represents the user information for the new user.<br /><br />These methods will eventually fire either the LoginOK or the LoginFailed events, which you can handle accordingly.<br /><br />The PrismUser class has some helper methods that make it easy to store and retrieve Glyph images for users. The SV6 Lobby lets you select a local image file on your computer to represent you as your Glyph. PrismUser encodes this image into a Base64 string, and saves it in the PrismUser object, in one of the "Detail" fields. PrismUser GetDetail/SetDetail methods let you store arbitrary information with a PrismUser and have it saved on the server.<br /><br />When a user logs back in, its encoded Glyph string is decoded and converted back into an ImageSource which is then displayed next to them in the Lobby.<br /><br />I use the PrismUser GetDetail/SetDetail to store other game-specific information about a user, such as their rank and rating.<br /><br />Handling chat in the Lobby is virtually effortless thanks to PrismConnection doing all of the dirty work. To send a line of chat to other users, simply call the SendChat method. A ChatRecieved event is triggered when an incoming chat message is received. The EventArgs class provides you the PrismUser who sent the chat as well as the line of text itself.<br /><br />Now that the Lobby is completed I can move onto converting the actual game mechanics!<br /><br /><a href="http://www.siliconcommandergames.com/SVSilverlight/TestPage.html">Solar Vengeance 6 Development Build - with Lobby!</a>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com3tag:blogger.com,1999:blog-6924218920945105061.post-31039772714138140972009-06-29T07:31:00.000-07:002009-06-29T07:34:52.978-07:00ChatNDraw Silverlight DemoMy ChatNDraw Silverlight demo is completed. ChatNDraw is a Silverlight-based chat program that lets you create new chat rooms, chat with others who happen to be logged in, and draw in different colors using a shared blackboard.<br /><br />ChatNDraw was created using my PrismServer component suite that I just converted to WPF/Silverlight from WinForms (.NET 2.0). I plan to release the source for PrismServer as soon as I can complete the documentation.<br /><br /><a href="http://www.siliconcommandergames.com/ChatNDraw/TestPage.html">ChatNDraw Demo</a>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com2tag:blogger.com,1999:blog-6924218920945105061.post-90638230760002875972009-06-26T04:54:00.001-07:002009-06-26T04:56:23.318-07:00Rebirth of PrismServer - for Silverlight!I'm almost finished with the Silverlight/WPF port of PrismServer. I have a live Chat server running now on the following page. I'm still working on the "Draw" part of the "ChatNDraw" Silverlight app, but for now you can help me test the server by logging in and "Chatting"!<br /><br />Note - if you create an account here, it will become the eventual account you'll use for all SCG Silverlight games.<br /><br />I wanted to get this news out to allow for some early testing. I do plan on creating a post describing the new PrismServer in more detail, and possibly a revised CodeProject article. For now, my fingers are falling off of my hands so I need a break from coding ;)<br /><br /><a href="http://www.siliconcommandergames.com/ChatNDraw/TestPage.html">http://www.siliconcommandergames.com/ChatNDraw/TestPage.html</a>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com1tag:blogger.com,1999:blog-6924218920945105061.post-77004001343502642222009-06-23T06:46:00.001-07:002009-06-23T07:22:41.486-07:00Death of TurboSprite<a href="http://4.bp.blogspot.com/_RVcCdy7G7j0/SkDdA2UC-0I/AAAAAAAAAYw/BCxnSfeq91E/s1600-h/SVBuild7.png"><img style="WIDTH: 400px; HEIGHT: 251px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5350519363965483842" border="0" alt="" src="http://4.bp.blogspot.com/_RVcCdy7G7j0/SkDdA2UC-0I/AAAAAAAAAYw/BCxnSfeq91E/s400/SVBuild7.png" /></a><br />Earlier I began porting my object-oriented TurboSprite framework to WPF. This was relatively easy because WPF had the OnRender event and the DrawingContext that corresponds to WinForms Paint/Graphics combo.<br><br /><br />When I decided to target Silverlight as the next platform for Silicon Commander Games development, one of the first hurdles was the fact that it did not expose the OnRender/DrawingContext feature of WPF. This forced me to use the animation system(s) built into Silverlight/WPF and abandon further development of TurboSprite.<br />One of the benefits of encapsulating animation in TurboSprite was its clean, object-oriented design. I could create animatable sprite classes that were self-contained and re-usable.<br><br /><br />In Silverlight I am following the same philosphy of design, but using the animation model(s) provided by the framework. Note the plural!<br><br /><br /><strong>Model 1 - Property Based Animation<br /></strong><br><br />This model works by creating Storyboard objects, and then adding animations (like DoubleAnimation, ColorAnimation, etc.) to its Children. You call Begin() to start animating, and can handle the Complete event when the animation is finished. You provide a Duration that controls how long the animation lasts. The Storyboard can have multiple animations in its Children collection. Each animation targets a specific property of a specific object.<br><br /><br />I use this method when I need to move an object from one cell to another on the game grid. To simplify the model, I created a base class called SquareGridGameBoard that derives from UserControl. SquareGridGameBoard allows you to set the number of cells that compose the game board, as well as the width and height of each cell. It also provides a visual cell cursor, and a selection band that facilitates selecting a range of cells. SquareGridGameBoard also contains helper methods that make it easy to position, and move, an element on the game board.<br><br /><br />The MoveElement helper method encapsulates the plumbing of creating a Storyboard, the animations, and handling the completed event. Here's the code:<br><br /><br /><br /><span style="color:#009900;">//Move an element to another cell</span><br />public void MoveElement(UIElement element, int newX, int newY, Duration duration)<br />{<br />//Create Storyboard, and remember the element it references<br />Storyboard sb = new Storyboard();<br />sb.Completed += MoveCompleted;<br />_storyboardTargets[sb] = element;<br /><br><br /><span style="color:#009900;">//Animate X coordinate</span><br />DoubleAnimation animX = new DoubleAnimation();<br />animX.To = newX * CellWidth + _cellWidthHalf;<br />animX.Duration = duration;<br />sb.Children.Add(animX);<br />Storyboard.SetTarget(animX, element);<br />Storyboard.SetTargetProperty(animX, new PropertyPath("(Canvas.Left)"));<br /><br><br /><span style="color:#009900;">//Animate Y coordinate</span><br />DoubleAnimation animY = new DoubleAnimation();<br />animY.To = newY * CellHeight + _cellHeightHalf;<br />animY.Duration = duration;<br />sb.Children.Add(animY);<br />Storyboard.SetTarget(animY, element);<br />Storyboard.SetTargetProperty(animY, new PropertyPath("(Canvas.Top)"));<br />sb.Begin();<br />}<br /><br><br /><span style="color:#009900;">//Animation finished</span><br />private void MoveCompleted(object sender, EventArgs e)<br />{<br /><span style="color:#009900;">//what element was being moved?<br /></span>Storyboard sb = sender as Storyboard;<br />UIElement element = _storyboardTargets[sb];<br />_storyboardTargets.Remove(sb);<br /><br><br /><span style="color:#009900;">//push values into properties after animation changes them</span><br />double x = Canvas.GetLeft(element);<br />double y = Canvas.GetTop(element);<br />sb.Stop();<br />Canvas.SetLeft(element, x);<br />Canvas.SetTop(element, y);<br />}<br /><br><br />You can see this in action in the current demo as of Build 7. When you click on a cell of the game map, it creates a random StarShip, but also moves a StarSystem to that location, using the MoveElement method described above.<br /><br><br /><strong>Model 2 - Frame-Based Animation</strong><br /><br><br />Another animation option that Silverlight provides is enabled by creating an event handler for the static CompositionTarget.Rendering event. When you do this, Silverlight calls your handler on each frame of animation. The default frame rate is 60 FPS, but this is adjustable by adding the "maxFramerate" parameter in your HTML.<br /><br><br />I use this method to cycle the colors of an array of 10 SolidColorBrushes that draw the Shields around StarSystems. The Ellipse elements that compose the Shields have their Stroke properties set to one of the brushes in this static array. When the color of one of the brushes changes, it impacts all of the Shield Ellipses that used that brush in their Strokes.<br /><br><br />You can see the Shield color cycling in action in Build 7 of the demo.<br /><br><br /><a href="http://www.siliconcommandergames.com/SVSilverlight/TestPage.html">http://www.siliconcommandergames.com/SVSilverlight/TestPage.html</a><br /><br><br />Sometimes it makes sense to use property-based animations, but sometimes frame-rate animations are a more logical choice. There's no need to sacrifice, use both models, and select the one that makes the most sense for each particular animation task in your Silverlight app!LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com3tag:blogger.com,1999:blog-6924218920945105061.post-17885153434093885882009-06-22T12:35:00.000-07:002009-06-22T12:51:15.810-07:00Silverlight Nebula<a href="http://2.bp.blogspot.com/_RVcCdy7G7j0/Sj_gm1tl_0I/AAAAAAAAAYo/-n8gSIVKm-s/s1600-h/SVBuild6.png"><img style="WIDTH: 400px; HEIGHT: 249px; CURSOR: hand" id="BLOGGER_PHOTO_ID_5350241840197402434" border="0" alt="" src="http://2.bp.blogspot.com/_RVcCdy7G7j0/Sj_gm1tl_0I/AAAAAAAAAYo/-n8gSIVKm-s/s400/SVBuild6.png" /></a><br /><div>Today I cracked the problem of how to dynamically generate a bitmap that represents the background of the game map for Solar Vengeance Silverlight. Silverlight does not provide out of the box any class or method that allows you to simply create an offscreen bitmap and render its pixels using drawing methods. In Silverlight 3, this will be addressed by the inclusion of the WriteableBitmap class, but I wanted to move forward in Silverlight 2 and wait until 3 is released before switching to that version for my development.</div><br /><div></div><br /><div>Fortunately I was not the only one who was having this problem, and I came upon Ian Griffith's weblog posting here (<a href="http://www.interact-sw.co.uk/iangblog/2008/11/07/silverlight-writeable-bitmap">http://www.interact-sw.co.uk/iangblog/2008/11/07/silverlight-writeable-bitmap</a>) where he describes his PngGenerator class. This class suited my needs perfectly, and it looks like I will be able to easily swap in the WriteableBitmap when Silverlight 3 is released.</div><br /><div></div><br /><div>Now, here's the process flow of my nice new Nebula image in Solar Vengeance Silverlight,</div><br /><div></div><br /><ul><br /><li>I call the BuildScenario method of a Scenario-derived class (in this case Classic).</li><br /><li>Classic creates some random Nebula in the SVGame object.</li><br /><li>I create a PngGenerator of 100x100 pixels in size, representing the full number of cells in the map grid.</li><br /><li>For each cell that contains a Nebula, I set the pixel to a bluish color, otherwise set it to black.</li><br /><li>I make the image the source for an Image object and add this to the Canvas of the game board, sizing it to the full dimensions of the board (3,500 x 3,500) and setting its Stretch property to Stretch.</li></ul><br /><p>I was expecting to see sharp edges in the blown up image, but was surprised and happy to see the blended edges that Silverlight produced. Another hurlde overcome (this time thanks to Ian) in my quest to port Solar Vengeance to Silverlight.</p><br /><p>See the latest demo build here:</p><br /><p><a href="file:///C:/Silicon%20Commander/NET3.5/SV.Silverlight/SCG.SolarVengeance/Bin/Debug/TestPage.html">C:\Silicon Commander\NET3.5\SV.Silverlight\SCG.SolarVengeance\Bin\Debug\TestPage.html</a></p><br /><p></p><br /><p></p>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-23626704716493953122009-06-17T09:51:00.000-07:002009-06-17T09:59:24.290-07:00Markov Name Generator C# Class<p>A <a href="http://en.wikipedia.org/wiki/Markov_chain">Markov Chain</a> is a way of generating a result based on the statistical probabilities in a set of sample data. The MarkovNameGenerator class can generate random words (names) based on a set of sample words that it takes as input.</p><p>It works by building "chains" that count the number of occurrences of each letter in the alphabet after each group of "N" letters in the sample name. "N" is called the "Order" of the Markov Chain.</p><p>The class generates a new name by first selecting a random group of "N" letters to begin the name. It then goes forward letter by letter, examining the Chains and picking a new letter from the pool of letters that followed the previous "N" letter groups in the sample data.</p><p>For example, the words "Sally Sells Seashells" breaks down into the following 2-Order Chains:</p><p>SA-(L)<br />AL-(L)<br />LL-(Y)<br />LY-(End)<br /><span style="color:#ffff66;">SE-(L,A)<br />EL-(L,L)<br />LL-(S,S)<br />LS-(End,End)<br /></span>EA-(S)<br />AS-(H)<br />SH-(E)<br />HE-(L)</p><p>Note the Chains in yellow. These represent 2 letter pairs that occurred more than once in the sample words. The Chain contains all of the letters that follow the single pair of letters.</p><p>Now, when the generator makes a new random name it follows this sequence:</p><p>1 - Pick a starting pair of letters randomly:</p><p>AS</p><p>2 - Pick a random letter in the Chain following AS. In our example the only one is H.</p><p>AS->H</p><p>3 - Continue picking random letters in the chain until we get an end.</p><p>A(SH)->E<br />AS(HE)->L<br />ASH(EL)->L<br />ASHE(LL)->S</p><p>Result = Ashells</p><p>In this sample, we never encountered the SE pair, but if we had, we would have appended one of the two candidate letters in the chain randomly.</p><p>The fun comes when you feed the name generator with a large number of sample names. The generator, particularly when set to an Order of 3, can produce new names that bear a remarkable similarity in style to the sample names, while still being original.</p><p><strong>Using the Class</strong></p><p>The MarkovNameGenerator class constructor takes 3 arguments:</p><p>public MarkovNameGenerator(IEnumerable<string> sampleNames, int order, int minLength)</p><p>The first parameter is the collection of sample names. This can be an array or list of strings. Each string can contain one sample name, or a number of samples separated by commas.</p><p>The second parameter determines the Order of the Markov Chains, and the last parameter specifies the minimum length of a generated name.</p><p>Accessing the NextName property returns a new random name based on the sample data. The class ensures that the same random name is not returned twice.</p><p>Call the Reset method to clear out the internal list of previously generated names.</p><p><strong>Download</strong></p><p> <a href="http://www.siliconcommandergames.com/downloads/MarkovNameGenerator.zip">Click here</a> to download the MarkovNameGenerator.cs C# file.</p><p><strong>Silverlight Sample App</strong></p><p><a href="http://www.siliconcommandergames.com/markov/TestPage.html">http://www.siliconcommandergames.com/markov/TestPage.html</a></p>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-78779370447560015172009-06-15T18:55:00.001-07:002009-06-15T19:02:18.757-07:00Vector or Image?I'm learning that to take best advantage of the graphical model in WPF/Silverlight I need to shift much of the design work from bitmap based images to vector based graphics. This is especially true in Silverlight which has a much more limitted .NET class library, and no direct support for colorizing images.<br /><br />In Solar Vengeance, I have a set of grayscale images that represent each StarShip type. When a game begins, SV dynamically generates colorized versions of the images for display. This was easy to do in WinForms and System.Drawing. I haven't found a reasonable solution to this in Silverlight. The WriteableBitmap class that's coming in Silverlight 3 might be a solution, but along the way I have found a better way.<br /><br />The StarShip graphics for SV are very simple representations, and lend themselves well to vector based graphics. I can create custom classes in Silverlight that render the images using a combination of the simple graphics primitives that Silverlight offers, like Rectangle and Ellipse.<br /><br />By creating a common StarShip visual base class, I can provide a single "Color" property that gets inherited to the customized rendering classes.<br /><br />In the latest update of my demo app I render some StarShip types in a list box with a vector based version next to the image based. My work in progress is here ...<br /><br /><a href="http://www.siliconcommandergames.com/SVSilverlight/TestPage.html">http://www.siliconcommandergames.com/SVSilverlight/TestPage.html</a>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-63426293620505289572009-06-14T10:46:00.000-07:002009-06-14T10:55:04.308-07:00Foray into SilverlightI finally installed the Visual Studio 2008 Service Pack 1 and the Silverlight 2 development tools. I created my very first Silverlight test project today! Along the way I found something rather alarming. Visual editing of the design surface is not possible for Silverlight apps in Visual Studio 2008! You cannot drag and drop controls on the Window, nor can you edit the properties of controls using the Property Window in VS2008. My XAML chops are getting better every day, but this will really force me to exercise them. I understand the VS2010 might include design time support for Silverlight, which would be most welcome. On the other hand, this might finally push me to get off my behind and get Expression Blend.<br /><br />Another position was that my fledgling port of the Solar Vengeance logical engine class library ported to Silverlight without any errors or changes needed.<br /><br />When I develop a game, I always strive to cleanly separate the logical data model from the user interface. I create a .NET Class Library project that contains the logical model of the game, and a separate project for the user interface.<br /><br />By maintaining this strict seperation it is now much easier for me to port SV to another platform such as WPF and/or Silverlight. I'm also probably going to change how the multiplayer communication works. A beefed up custom PrismServer will use the same SV logical engine to create an instance of the game and serve as the "host" of the game. It will receive the orders from players, process the turn, and send the results back to each client on each Impluse.<br /><br />I have some challenges ahead if I want to create an SV front end in Silverlight. In particular, Silverlight does not support the DrawingContext and OnRender method which is the basis of my TurboSprite animation system. If I want a Silverlight SV, I will have to leverage its animation model, perhaps building my lightweight framework around Composition.Rendering which lets you get at the animation loop in a WPF/Silverlight app.<br /><br />For now, here's my first "Hello, World" Silverlight page ...<br /><br /><a href="http://www.siliconcommandergames.com/SVSilverlight/TestPage.html">http://www.siliconcommandergames.com/SVSilverlight/TestPage.html</a>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-3915927786481865452009-05-30T11:01:00.000-07:002009-05-30T11:59:31.135-07:00WPF Black Holes<a href="http://2.bp.blogspot.com/_RVcCdy7G7j0/SiF-ZrRA7JI/AAAAAAAAAYg/49pB846NMbQ/s1600-h/WPFBlackHoles.png"><img id="BLOGGER_PHOTO_ID_5341689612614036626" style="WIDTH: 400px; CURSOR: hand; HEIGHT: 310px" alt="" src="http://2.bp.blogspot.com/_RVcCdy7G7j0/SiF-ZrRA7JI/AAAAAAAAAYg/49pB846NMbQ/s400/WPFBlackHoles.png" border="0" /></a><br />My journey into WPF is still in its infancy, but I want to document some of the ups and downs I've discovered working with the framework, ending in a big UP!<br /><br />I've been googling like mad and absorbing knowledge as I ramp up the WPF learning curve. Some of my early research left me feeling pessimistic about the prospects of writing a game using WPF. First, there was the message group post (I cannot locate the link anymore, but I promise this was for real) where the poor programmer was experiencing poor render performance drawing lines in WPF (more on that later!) The suggestion he finally adopted was to run a WinForms Picture control hosted in his WPF application! Astonishingly, the GDI+ based WinForms outperformed WPF in the line drawing heavy application!<br /><br />Second was the promosing blog entitled "<a href="http://wpf4games.blogspot.com/">WPF for Games</a>". The author was literally gushing about WPF in his early blog entries. By the end of the blog, this grim topic appeared - "<a href="http://wpf4games.blogspot.com/2008/10/throwing-in-towel.html">Throwing in the Towel</a>", where the author is fed up fighting against the WPF framework and decides to write his game in XNA.<br /><br />I love a good challenge, and this just makes me want to try harder to get a decent game out of WPF ;)<br /><br />My first concrete project in WPF is a port of my TurboSprite sprite engine. I have debated internally about whether to port TurboSprite to WPF, or to try and use WPF's framework as the basis for my sprite animation. I concluded that porting TurboSprite would save me alot of headaches in the long run. My feeling is that my lightweight sprite engine will allow me to realize the graphics performance I want without pushing this burden onto the WPF framework. My sprites descend from Object - and there's nothing more lightweight than that! I will use the WPF framework to try and make a cool user interface surrounding the main SpriteSurface that contains the game's action.<br /><br />But how to translate TurboSprite to WPF? The main component of TurboSprite is the SpriteSurface, and for this I derive from FrameworkElement, and drawing in an overridden OnRender method, using the supplied DrawingContext. In my next blog post I plan to go into some of the early technical details of my implementation, but for now I can describe some of the early results.<br /><br />I've found that rendering images in the DrawingContext using DrawImage is blazingly fast, and perforing rotations using Transforms seems to not impact rendering performance. I was able to create many very large ImageSprites and add them to the SpriteSurface without and degredation in FPS. This is good news for Scenarios that like to use many large background graphics!<br /><br />Next I tried to tackle porting beat2k's SpiralSprite, which is the basis for black holes in the SV graphics. The code ported easily enough, but when I created a SpiralSprite in my new WPF TurboSprite, the animation rate went down the toilet! Adding 2 or 3 SpiralSprites caused a complete bottleneck and the FPS was down in the single digit range.<br /><br />But I was determined to find a better solution than hosting a WinForms control for my SpriteSurface!<br /><br />After some research I discovered that creating a Geometry was the way to go. Apparently, the Geometry can be rendered with graphics acceleration all in one shot, while rendering the individual lines was very time consuming. The problem with this approach is that it sacrificed the ability to color each segment of the spiral, an effect that beat2k implemented in his code. I solved the problem by rendering the SpiralSprite using a RadialGradientBrush, with the end color set to Transparent.<br /><br />The end result is a new SpiralSprite class that still has the customizability, the rotation (now leveraging the existing Sprite Spin and SpinSpeed properties), and that can be rendered extremely quickly on the SpriteSurface.<br /><br />The code for the modified SpiralSprite<br /><br /><pre><br />//SpiralSprite class by Jason Milliser<br /><br />using System;<br />using System.Collections.Generic;<br />using System.Windows;<br />using System.Windows.Media;<br /><br />namespace SCG.TurboSprite<br />{<br /> public class SpiralSprite : Sprite<br /> {<br /> //constructor<br /> public SpiralSprite(int arms, float radiusmin, int radiusmax, int armslope, int slopelength, bool isSpinningClockwise, Color CenterColor)<br /> {<br /> //arm slope is the number of lines drawn to the center of the spiral. Also controls the tightness of teh spiral. <br /> //slopelength is the length of each line segment of each spiral. longer lines can tighten spiral, but quality will go down.<br /> slength = slopelength;<br /> _centerColor = CenterColor; <br /> _direction = isSpinningClockwise; <br /> _radiusMax = radiusmax;<br /> _radiusMin = radiusmin;<br /> _armSlope = armslope;<br /> _arms = arms;<br /> Shape = new Rect(0-_radiusMax, 0-_radiusMax, _radiusMax * 2, _radiusMax * 2);<br /> }<br /><br /> //calculate points of spiral<br /> protected internal override void Process()<br /> {<br /> //we now need to create points only once, rotation performed by transformed<br /> if (_points != null)<br /> return;<br /><br /> int theta = 0;<br /> float sinvalue = 0;<br /> float cosvalue = 0;<br /> double altitude = 0;<br /> float faltitude = 0;<br /> double radiusscale = 0;<br /> double dradiusmin = 0;<br /> int rdegrees = 0; <br /><br /> //preliminary math calculations<br /> theta = 360 / _arms;<br /><br /> if (_points == null)<br /> _points = new Point[_arms * _armSlope + 1];<br /><br /> for (int arm = 0; arm < _arms; arm++)<br /> {<br /> for (int seg = 0; seg < _armSlope; seg++)<br /> {<br /> if (_direction == true)<br /> rdegrees = (seg * slength) + (arm * theta);<br /> else<br /> rdegrees = -(seg * slength) - (arm * theta);<br /> while (rdegrees < 0) rdegrees = rdegrees + 360;<br /> while (rdegrees >= 360) rdegrees = rdegrees - 360;<br /><br /> radiusscale = _radiusMax - _radiusMin;<br /> dradiusmin = _armSlope;<br /> altitude = (seg + 1) / dradiusmin;<br /> altitude = radiusscale * altitude;<br /> dradiusmin = _radiusMin;<br /> altitude = dradiusmin + altitude;<br /> faltitude = Convert.ToSingle(altitude);<br /><br /> sinvalue = LookupTables.Sin(rdegrees) * faltitude;<br /> cosvalue = LookupTables.Cos(rdegrees) * faltitude;<br /><br /> _points[(arm * _armSlope) + seg].X = sinvalue;<br /> _points[(arm * _armSlope) + seg].Y = cosvalue;<br /> }<br /> } <br /> }<br /><br /> //Render the sprite<br /> protected internal override void Render(DrawingContext dc)<br /> {<br /> if (_points != null)<br /> {<br /> //Create the Geometry if it doesn't yet exist<br /> //this needs to be done on the same thread, so it's done here and not in Process<br /> if (_geom == null)<br /> {<br /> _geom = new StreamGeometry();<br /> StreamGeometryContext sgc = _geom.Open();<br /> sgc.BeginFigure(_points[0], false, false);<br /> List<Point> points = new List<Point>();<br /> for (int i = 1; i < _points.Length; i++)<br /> points.Add(_points[i]);<br /> sgc.PolyLineTo(points, true, true);<br /> sgc.Close();<br /> }<br /><br /> //Transform the location to match the sprite's position<br /> Transform t = new TranslateTransform(X - Surface.OffsetX, Y - Surface.OffsetY);<br /> dc.PushTransform(t);<br /><br /> //Rotate sprite<br /> Transform rotate = new RotateTransform(FacingAngle);<br /> dc.PushTransform(rotate);<br /><br /> //Create gradient brush so spiral fades out<br /> RadialGradientBrush rgb = new RadialGradientBrush(_centerColor, Colors.Transparent); <br /><br /> //Draw the spiral geometry<br /> dc.DrawGeometry(null, new Pen(rgb, 2), _geom);<br /><br /> //Draw the central back hole<br /> dc.DrawEllipse(Brushes.Black, null, new Point(0, 0), 7, 7);<br /> dc.Pop();<br /> dc.Pop();<br /> }<br /> }<br /><br /> //private members<br /> private Point[] _points;<br /> private int _arms;<br /> private float _radiusMax;<br /> private float _radiusMin;<br /> private int _armSlope;<br /> private Color _centerColor; <br /> private bool _direction;<br /> private int slength;<br /> private StreamGeometry _geom = null;<br /> private Pen _pen = new Pen(Brushes.Yellow, 1);<br /> }<br />}<br /></pre>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-23707513562440730772009-05-29T01:36:00.000-07:002009-05-29T01:40:32.450-07:00Better Days ahead for WPFI see after reading <a href="http://windowsclient.net/wpfdesigner/articles/first-wpf-application.aspx">this article</a> that the deficiencies in the WPF development experience that I mentioned in the previous blog post are being addressed in Visual Studio 2010. For example, the Property window has an Events button that lets you see the events of a class and set event handlers. It was frustrating to see that missing in the VS 2008 WPF Designer. I know, you can get a list of events by typing a space in the XAML and using Intellisense, but this is a very poor substitute for having the events nicely laid out in the Property window. Also, there are RAD tools that help creating bindings and apply styles to controls. I also noted that VS 2010 will also include a Designer for Silverlight applications. Maybe 2010 will be the year for SV 2010 - WPF and Silverlight editions.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-14597061759144489432009-05-27T11:24:00.000-07:002009-05-27T11:48:49.801-07:00Feet wet with WPFI usually make a major shift in programming technologies when there's a very compelling reason. I remember when I decided to switch from Visual Basic to Delphi because Delphi offered a perfect object oriented framework and component model. Years later, when Delphi began to decline, I made a shift to the .NET Framework and C#. Mainly, I follwed Anders Hejlsberg from Borland to Microsoft - he was the primary architect of Delphi until Microsoft lured him away and he became the primary driver of C#.<br /><br />With .NET came a layer of abstraction away from Windows, meaning less fine-grained control and power, but a modern development environment with a clear future.<br /><br />Since the release of the .NET Framework 3.0 in late 2006, the WPF (Windows Presentation Foundation) framework was the cool new API in the Windows world. Windows Forms became old fashioned and quaint.<br /><br />I'm about 3 years late to the party, but I have finally begun to update myself in WPF. The compelling reason this time is fear that Windows Forms is becoming a dinosaur framework, and I need to keep current. I have mixed feelings about this move, unlike for example the shift from VB to Delphi which I felt had no negative aspects.<br /><br />First of all, my feeling is that WPF is currently half baked, without a full RAD development experience in Visual Studio. The idea of using two tools (Visual Studio and Expression Blend) to work on an application is not appealing to me. The direction of promoting XAML as a form markup language that a developer needs to code in leaves a very bad taste in my mouth. In my mind, the form markup language should remain in the background without having to be seen, much less edited. Also, much of the WPF API seems to have the flavor of the old Win32 APIs, with function calls with loads of obscure parameters in favor of a cleaner and more well thought out framework.<br /><br />On the positive side, preliminary conversion of TurboSprite to pure WPF is showing promising results, with an animation frame rate of 3000+ FPS in my basic testing with no sprites added yet to an animated surface. All of my research indicates that GDI+ suffered badly in terms of performance when rendering images. WPF makes better use of graphics accelerators, so in general rendering should be much faster, as my early tests support.<br /><br />Hopefully this will translate to an eventual SV6 and future games where graphics updates are no longer an issue! This transition also opens the door to create a companion SV6 client in Silverlight that will run in the web browser (in Windows or Macs) and allow multiplayer play through PrismServer. You may not remember, but once upon a time there was a Java applet version of SV that ran in the browser. Having a browser based, full fledged SV client is another compelling reason in favor of shifting development to WPF.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com2tag:blogger.com,1999:blog-6924218920945105061.post-12638368600430158862009-04-12T12:55:00.000-07:002009-04-12T13:06:03.452-07:00WinWarII 5.0 Research and Bombing<a href="http://2.bp.blogspot.com/_RVcCdy7G7j0/SeJJnMhBZOI/AAAAAAAAAYY/PXo7tvYL8YM/s1600-h/WWIIBombing.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 250px;" src="http://2.bp.blogspot.com/_RVcCdy7G7j0/SeJJnMhBZOI/AAAAAAAAAYY/PXo7tvYL8YM/s400/WWIIBombing.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323898647228802274" /></a><br />I completed two more features in WinWar II 5.0. Firstly, the Technological Research component is in place. To have your Nation conduct research, all you need to do is build Labs in one or more of your Zones. The Labs generate tech points behind the scenes, and you get periodical improvements during the game. If you place a Spy in another Nation's Zone that contains a Lab, you can also steal some of their tech points as they are generated.<br /><br />There are Conventional Technology Levels for Land, Air, and Sea. When you advance a Level, the units you build for the particular Unit Class (land/air/sea) are 10% stronger in their attack and defense (and bombing if applicable) levels.<br /><br />Special Technologies include:<br /><br />Radar<br />Allows you to build Radar installations in Zones that extend visibility.<br /><br />Encryption<br />Gives you a chance of eavesdropping on private communications between other Players.<br /><br />Rockets<br />Lets you build Rocket Launchers that can conduct Strategic Bombing in a target Zone in their range.<br /><br />Atomic<br />Lets you build "Atomic" units such as an Atomic Bomber. Atomic attacks will devastate a Zone, reducing its Value, and possibly destroying Bases, Factories, Labs, etc. in the Zone, in addition to taking a large chunk out of the Funds of the Nation attacked.<br /><br />I also completed the Strategic Bombing concept for the game. Certain Unit Types can be given the "Bombing" attribute which gives them Strategic Bombing capability. When these units are in an enemy Zone they will automatically conduct Strategic Bombing attacks periodically. The damage done is subtracted from the Funds of the Nation being attacked. Attacking high value Zones obviously does more damage.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com2tag:blogger.com,1999:blog-6924218920945105061.post-68580228502935750002009-03-30T06:07:00.000-07:002009-03-30T06:40:29.644-07:00WinWar II 5.0 Diplomacy<a href="http://3.bp.blogspot.com/_RVcCdy7G7j0/SdDLbA4UxvI/AAAAAAAAAX4/ovddQpjbU10/s1600-h/WWIIDiplomacy.png"><img style="cursor:pointer; cursor:hand;width: 400px; height: 244px;" src="http://3.bp.blogspot.com/_RVcCdy7G7j0/SdDLbA4UxvI/AAAAAAAAAX4/ovddQpjbU10/s400/WWIIDiplomacy.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5318974824877704946" /></a><br />I've completed the Diplomacy system for WinWar II 5.0. Each Nation in the game has a Stance against each other Nation in the game, even Minor Powers to Minor Powers. Actions that occur in the game can impact the Stances of Nations toward one another. Stances can more directly be affected by executing a Diplomatic Action.<br /><br />Each Major Power can take a Diplomatic Action when it's available. After an Action is taken, another Action isn't possible until an internal counter counts back down to zero. The length of time between Actions is determined by the last Action taken (some are more costly than others), the Political Strength of the Nation's Head of State, and a randomizer.<br /><br />Below are the Diploamtic Actions available in WinWar II 5.0:<br /><br />Conduct Summit - If successful the Stance of the target Nation is improved. There is a small chance that the Summit will backfire, reducing Stance. This chance is based roughly on the current Stance between the two Nations, the lower the Stance the greater that chance that the Summit will backfire. Note - if you raise the Stance of a Minor Power to 100, that Nation comes under your control!<br /><br />Denounce - Available only to Nations that are not flagged as "Imperial". This reduces the Stance between your Nation and the target Nation, and also impact the Stances of other Nations friendly to you toward the Target. A non-Imperial Major Power can only attack another Nation when they are At War (Stance = -100) so Denounce will be an important the Allied Powers.<br /><br />Declare War - Imperial Powers will have a Declare War Diplomatic Action instead of Denounce. An Imperial Power could Declare War automatically by just invading a Nation, but they might want to issue this Action if they want to attack an enemy navy without having to invade a Land Zone.<br /><br />Exert Pressure - If the target Nation succumbs to the pressure, it comes under your control immediately. If not, the Stance between the two Nations suffers. The Action has a greater chance of success if forces are massed along the target's border.<br /><br />Incite Coup - If successful, a new Government is formed in the target Nation, having a set of roughly opposing stances, with some randomization involved here.<br /><br />Another nuance of the Diplomatic System: taking hostile Diplomatic Actions has the effect of making the target Nation's neighbors nervous, and reducing your Stance with them. Also, Diplomatic Stances are dynamic, and can shift during the game spontaneously, sometimes with interesting results. For example, in one game, early on, Spain spontaneously allied with the UK. That would surely shake up the strategies in the early phases of play!<br /><br />A scolling ticker informs you of various events on the bottom of the screen, allowing you to keep up to date without providing too much of a distraction. Game event history is also available in a dedicated window if desired.LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0tag:blogger.com,1999:blog-6924218920945105061.post-4888549033629616932009-03-20T11:23:00.000-07:002009-03-21T02:30:30.526-07:00PrismServer UpdatePrismServer is the TCP/IP server I developed to handle communication between players in my MultiPlayer games. The newest version is written in C# and offered as open-source. It features a set of components that abstract the client/server communication protocol and exposes it through simple properties, events and methods.<br /><br />When I first switched from the Delphi programming language to C#, PrismServer was the first serious development effort I undertook. I always like to have a concrete project to work through when I learn a new language.<br /><br />Looking back at my original effort, I discovered some flaws in my work that experience with C# helped me recognize now. These flaws manifested themselves as sporadic crashes in the server piece of the PrismServer package.<br /><br />I have spent some time over the past few weeks nailing down and correcting these problems. The problems revolved mostly around multi-threading issues. I was not properly locking variables that could be access from different thread. The problems most frequently occurred when using a foreach loop, and then having the List<> that the loop was enumerating change by a call from another thread.<br /><br />For example, when PrismServer is trying to send information to all of the players in a specific room, it uses a foreach to enumerate the players in the room. If a player entered or exited a room during this loop, PrismServer.exe would crash hard.<br /><br />After identifying all of the appropriate places to put lock statements, another problem manifested. When a player would drop from the game, there would be noticable lag of about 30 seconds that stalled all traffic in the server. This sounded like a locking issue; i.e. one method waiting for a lock to be released that was set in another method.<br /><br />Sure enough, I discovered that the method that writes information to the players' sockets was locking the list of connected Guests in that subject. When one of the players dropped, this caused a delay as the socket timed out, and the lock was still set until the socket timeout completed. This caused a bad cascade that eventually brought the whole server to its knees until the socket timeout completed.<br /><br />I corrected this by creating a new thread to handle outgoing communication. When PrismServer wants to send something out on a socket, it now adds the string to a Queue<string>. The outgoing thread examines this Queue and sends the strings it finds there out the client socket. The Queue is locked only long enough to get the next piece of information to be sent. This design allows the server to run smoothly even when clients are timing out.<br /><br />After stress testing, I'm happy with the performance and stability of PrismServer, and look forward to seeing how long the new build can run before it needs to be restarted.<br /><br />Below is the relevant section of code that resulted in the most bang for the buck improvement (from PrismNetworkStream.cs)<br /><br /><!-- code formatted by http://manoli.net/csharpformat/ --><br /><pre class="csharpcode"><br /><span class="rem">//This thread keeps executing and writing information to the client</span><br /><span class="kwrd">private</span> <span class="kwrd">void</span> WriteThreadExecute()<br />{<br /> <span class="kwrd">while</span> (!_closed)<br /> {<br /> <span class="kwrd">bool</span> written = <span class="kwrd">true</span>;<br /> <span class="kwrd">while</span> (written)<br /> {<br /> written = <span class="kwrd">false</span>;<br /> <span class="kwrd">string</span> s = <span class="kwrd">null</span>;<br /> <span class="kwrd">lock</span> (_outgoing)<br /> {<br /> <span class="kwrd">if</span> (_outgoing.Count > 0)<br /> s = _outgoing.Dequeue();<br /> }<br /> <span class="kwrd">if</span> (s != <span class="kwrd">null</span>)<br /> {<br /> written = <span class="kwrd">true</span>;<br /> WriteString(s);<br /> }<br /> }<br /> Thread.Sleep(10);<br /> }<br />}<br /></pre>LucidDionhttp://www.blogger.com/profile/11691189006761497558noreply@blogger.com0