tag:blogger.com,1999:blog-82210049881016819382024-03-05T15:02:52.418-05:002D Game MakingA Blog detailing the steps I take to make a 2D game. The hope is to share my knowledge with others who have the same passion.beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.comBlogger14125tag:blogger.com,1999:blog-8221004988101681938.post-23136730997320443742011-12-20T22:35:00.000-05:002011-12-20T22:35:19.706-05:00New Site Location...I've decided to move my blog to GameDev, and make it a developer;s Journal, which is exactly what this is. So, go on over, and see what I have planned.<br />
<br />
<a href="http://www.gamedev.net/blog/1385-2d-game-making-the-easy-way/">2d Game Making, the Easy Way</a><br />
<br />
Later!beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com2tag:blogger.com,1999:blog-8221004988101681938.post-41476004194827150642011-11-16T20:49:00.001-05:002011-11-16T21:17:06.177-05:00SmashPc: The PostmortemWhen I set out to make SmashPC, the main point was to try and share the ease of making a 2D game using SFML, chipmunk-physics, tinyxml, and Gleed2d.<br />
<br />
For this post, I'll go over the main points, and cover some of the improvements I could have done.<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>Overview of the Main Points</b></span><br />
<br />
To me, the biggest point I want to make is how a 2d physics engine makes writing games a snap. No longer do I have to handle moving every object within the world, checking all the collision possibilities, handling the odd collision detection issues we used to have, or any other number of things. Sure, there was a time when it was "fun" to handle all that stuff, but it seriously impeded making a cool game.<br />
<br />
Instead, we tell the physics engine what object are in the world; their mass, force, angle, rotational velocity, friction and all the other physical properties. We tell the physics engine to notify us when certain objects collide, so we can do fun stuff with them. Then, we basically say, "Go", and it goes. With little effort, I had 200 enemies all running towards me, pushing each other around, in a natural group. I think it's really cool stuff.<br />
<br />
I also really like the power SFML provides. It makes doing anything you want with sprites a snap (scaling, rotation, etc.). Input is handled easily, and sound is very well done. I didn't even bother with the spatial sound available, but it's another strong reason to use SFML.<br />
<br />
Throw in tinyxml, to handle parsing all the data, and gleed2d, for creating the levels, and saving them in XML, and you have the recipe for making games very easily.<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>What I could have done better</b></span><br />
<span class="Apple-style-span" style="font-size: large;"><b><br /></b></span><br />
The first thing I want to point out is the lack of a proper design before I began coding. I had an idea of what I wanted, but nothing concrete. I didn't always write code with the end result in mind, and that caused me to do some re-writes a few times (ie, adding the PhysicalObject parent class, and moving all objects to the SmashPcData class). This also added to my other issues.<br />
<br />
I should have used xml to detail enemies; instead, I just wrote the properties in the SmashPcEnemy class (Their speed, movement update time, etc.). This would also have been used to define what items are released by the "special" enemy; instead, I just hard-coded it in the SmashPcData class.<br />
<br />
<br />
I would re-do the GameLevel class. Initially, I included the option to add items to the map, but I didn't once use it. That caused me to waste some time and code.<br />
<div>
<br /></div>
<br />
I would like to re-do the weapons class. How I handled switching between bullets was poor.<br />
<br />
<span class="Apple-style-span" style="font-size: large;"><b>Final Word</b></span><br />
<span class="Apple-style-span" style="font-size: large;"><b><br /></b></span><br />
In the end, I just wanted to get it out, and I took some short-cuts to get there, but, I think the main point of this blog was fulfilled. I hope I showed how you can use the tools to make interesting 2D games.<br />
<br />
I may use this blog for other games I make. I'm thinking of a side-scroller type game, kinda like the Contra games. We'll just have to see.<br />
<br />
Until then!<br />
<br />beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com1tag:blogger.com,1999:blog-8221004988101681938.post-82152485263465179122011-11-15T20:12:00.001-05:002011-11-15T20:49:52.079-05:00Tying up loose SmashPc endsLast night I put my game as it sits on the blog. I wanted to tie up the last few steps I added.<br />
<br />
Here's the latest source code:<br />
<a href="http://dl.dropbox.com/u/27729730/SmashPC-11-15-11.zip">SmashPc 11-15-11</a><br />
<br />
First, the Rocket, I added Smoke trails. I added the <SmokeTrails> tag to the SmashPcWeapons.xml.<br />
I also added this Smoke element to the SmashPcItems.xml:<br />
<div id="iframeDiv95d62c6b-1afb-4506-9390-f9df2a59ce30" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe95d62c6b-1afb-4506-9390-f9df2a59ce30" src="http://www.blogtrog.com/code.aspx?id=95d62c6b-1afb-4506-9390-f9df2a59ce30" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 600px;"></iframe></div>
<div id="noIframeDiv95d62c6b-1afb-4506-9390-f9df2a59ce30" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: blue;"><</span><span style="color: maroon;">Smoke </span><span style="color: red;">Type</span><span style="color: blue;">="Fadeout"</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Image</span><span style="color: blue;">></span><span style="color: black;">smoke-small.png</span><span style="color: blue;"></</span><span style="color: maroon;">Image</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Interact</span><span style="color: blue;">></span><span style="color: black;">No</span><span style="color: blue;"></</span><span style="color: maroon;">Interact</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Value</span><span style="color: blue;">></span><span style="color: black;">0</span><span style="color: blue;"></</span><span style="color: maroon;">Value</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">TimeToLive</span><span style="color: blue;">></span><span style="color: black;">500</span><span style="color: blue;"></</span><span style="color: maroon;">TimeToLive</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Rotate</span><span style="color: blue;">></span><span style="color: black;">0</span><span style="color: blue;"></</span><span style="color: maroon;">Rotate</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"></</span><span style="color: maroon;">Smoke</span><span style="color: blue;">></span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('95d62c6b-1afb-4506-9390-f9df2a59ce30');
</script>
<br />
In SmashPcBullet::Draw(), I added this check at the end:<br />
<div id="iframeDiv4e3d8e28-1b22-4d1d-8876-b4a5f1bfdeff" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe4e3d8e28-1b22-4d1d-8876-b4a5f1bfdeff" src="http://www.blogtrog.com/code.aspx?id=4e3d8e28-1b22-4d1d-8876-b4a5f1bfdeff" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 600px;"></iframe></div>
<div id="noIframeDiv4e3d8e28-1b22-4d1d-8876-b4a5f1bfdeff" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: green;">//</span><span style="color: green;"> If we're drawing smoketrails, then lay one down, and set it to fade out</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (mbSmokeTrail)
{
cpVect Loc </span><span style="color: black;">=</span><span style="color: black;"> mpBody</span><span style="color: black;">-></span><span style="color: black;">p;
GameLevel::tLevelItem LevelItem;
LevelItem.ItemName </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: maroon;">"</span><span style="color: maroon;">Smoke</span><span style="color: maroon;">"</span><span style="color: black;">;
</span><span style="color: green;">//</span><span style="color: green;"> Set location at back of bullet</span><span style="color: green;">
</span><span style="color: black;"> Loc.x </span><span style="color: black;">-=</span><span style="color: black;"> cos(mpBody</span><span style="color: black;">-></span><span style="color: black;">a)</span><span style="color: black;">*</span><span style="color: black;">mpImage</span><span style="color: black;">-></span><span style="color: black;">GetWidth()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">;
Loc.y </span><span style="color: black;">-=</span><span style="color: black;"> sin(mpBody</span><span style="color: black;">-></span><span style="color: black;">a)</span><span style="color: black;">*</span><span style="color: black;">mpImage</span><span style="color: black;">-></span><span style="color: black;">GetHeight()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">;
LevelItem.Location </span><span style="color: black;">=</span><span style="color: black;"> Loc;
LevelItem.ImageName </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: maroon;">""</span><span style="color: black;">; </span><span style="color: green;">//</span><span style="color: green;"> get it from xml</span><span style="color: green;">
</span><span style="color: black;"> SmashPcItem </span><span style="color: black;">*</span><span style="color: black;">pSmokeItem </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">new</span><span style="color: black;"> SmashPcItem(mGameData,
mpApp, LevelItem, mpSpace);
mGameData.AddActiveItem(pSmokeItem);
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('4e3d8e28-1b22-4d1d-8876-b4a5f1bfdeff');
</script>
<br />
Basically, we add a "Smoke" item every time we update drawing the rocket. Since the TimeToLive is short, though, it won't be on the screen long. <br />
<br />
Now, if we check in SmashPcItem::Draw(), we do this:<br />
<div id="iframeDiv3b2db29c-c85c-4ff2-99e6-604220b6892a" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe3b2db29c-c85c-4ff2-99e6-604220b6892a" src="http://www.blogtrog.com/code.aspx?id=3b2db29c-c85c-4ff2-99e6-604220b6892a" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 600px;"></iframe></div>
<div id="noIframeDiv3b2db29c-c85c-4ff2-99e6-604220b6892a" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: green;">//</span><span style="color: green;"> if the type is FadeOut, then lessen tghe alpha</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (mpItemDetails</span><span style="color: black;">-></span><span style="color: black;">Type </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: maroon;">"</span><span style="color: maroon;">Fadeout</span><span style="color: maroon;">"</span><span style="color: black;">)
{
sf::Color AlphaColor(</span><span style="color: purple;">0</span><span style="color: black;">, </span><span style="color: purple;">0</span><span style="color: black;">, </span><span style="color: purple;">0</span><span style="color: black;">, </span><span style="color: purple;">255</span><span style="color: black;">);
U32 u32TimeDiff </span><span style="color: black;">=</span><span style="color: black;"> (timeGetTime() </span><span style="color: black;">-</span><span style="color: black;"> mu32StartTime)</span><span style="color: black;">+</span><span style="color: purple;">1</span><span style="color: black;">;
AlphaColor.a </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">255</span><span style="color: black;"> </span><span style="color: black;">-</span><span style="color: black;"> ((</span><span style="color: purple;">255</span><span style="color: black;">*</span><span style="color: black;">u32TimeDiff)</span><span style="color: black;">/</span><span style="color: black;">mu32TimeToLive);
PhysicalObject::Draw(PlayerLoc, AlphaColor);
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('3b2db29c-c85c-4ff2-99e6-604220b6892a');
</script>
<br />
This basically continually lowers the alpha on the image, based on the time to live, and the amount of time it has left to live. So, this give the "Smoke Trail" as seen in this screen shot:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw89_GkocqQ8L1WjjU-dA9Yh6zoYXMYgu9onaiD6A0hWXuw4HSV41ATW8LW54jKWnS6R_vmBH_FDoGDka48S_sQxkItstkIId1n2k7MJUXZ7KFO0ePBNbCvjdL_mJ4slqdGu-hg87K2Pc/s1600/SmokeTrails.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="246" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjw89_GkocqQ8L1WjjU-dA9Yh6zoYXMYgu9onaiD6A0hWXuw4HSV41ATW8LW54jKWnS6R_vmBH_FDoGDka48S_sQxkItstkIId1n2k7MJUXZ7KFO0ePBNbCvjdL_mJ4slqdGu-hg87K2Pc/s320/SmokeTrails.png" width="320" /></a></div>
<br />
The other stuff I did was handle changing levels, releasing an item when you kill a specific enemy, game over, and game won. This wasn't actually a big deal, but I took short cuts. I really should have created another configuration file that defines the levels, and modified the EnemySpawn items to detail what item to release.<br />
<br />
Here's the code, in the main loop before pOurPlayer->CheckInput(), that handles these pieces:<br />
<br />
<div id="iframeDiv79a9a937-7818-492e-a94b-a8f864bd8fba" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe79a9a937-7818-492e-a94b-a8f864bd8fba" src="http://www.blogtrog.com/code.aspx?id=79a9a937-7818-492e-a94b-a8f864bd8fba" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDiv79a9a937-7818-492e-a94b-a8f864bd8fba" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">mu32Health </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">)
{
</span><span style="color: green;">//</span><span style="color: green;"> Check for Lives?</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (u32Lives </span><span style="color: black;">></span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">)
{
Sleep(</span><span style="color: purple;">1000</span><span style="color: black;">);
u32Lives</span><span style="color: black;">--</span><span style="color: black;">;
delete pOurPlayer;
pOurPlayer </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">new</span><span style="color: black;"> SmashPcPlayer(GameData, </span><span style="color: black;">&</span><span style="color: black;">App, pMap</span><span style="color: black;">-></span><span style="color: black;">GetSpace(),
pMap</span><span style="color: black;">-></span><span style="color: black;">GetSpawnLocation(), </span><span style="color: black;">&</span><span style="color: black;">Weapon);
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
</span><span style="color: green;">//</span><span style="color: green;"> just quit I guess</span><span style="color: green;">
</span><span style="color: black;"> GameSound::Play(</span><span style="color: maroon;">"</span><span style="color: maroon;">GameOver</span><span style="color: maroon;">"</span><span style="color: black;">);
Sleep(</span><span style="color: purple;">4000</span><span style="color: black;">);
</span><span style="color: blue;">break</span><span style="color: black;">;
}
}
</span><span style="color: blue;">if</span><span style="color: black;"> (GameData.IsLevelOver())
{
U32 u32OldArmor </span><span style="color: black;">=</span><span style="color: black;"> pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">mu32Armor;
BOOL bGameOver </span><span style="color: black;">=</span><span style="color: black;"> FALSE;
</span><span style="color: green;">//</span><span style="color: green;"> Change Level</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (Level </span><span style="color: black;">==</span><span style="color: black;"> NumLevels)
{
bGameOver </span><span style="color: black;">=</span><span style="color: black;"> TRUE;
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
Level</span><span style="color: black;">++</span><span style="color: black;">;
}
</span><span style="color: green;">//</span><span style="color: green;"> Call the intermission function
</span><span style="color: green;">//</span><span style="color: green;"> also handles end-game</span><span style="color: green;">
</span><span style="color: black;"> Intermission(</span><span style="color: black;">&</span><span style="color: black;">App, pMap, pOurPlayer, </span><span style="color: black;">&</span><span style="color: black;">GameData, bGameOver,
u32ScreenX, u32ScreenY);
</span><span style="color: green;">//</span><span style="color: green;"> Reset GameData to make sure everything is cleared</span><span style="color: green;">
</span><span style="color: black;"> GameData.Reset();
delete pOurPlayer;
delete pMap;
</span><span style="color: green;">//</span><span style="color: green;"> Create new amp with new level data</span><span style="color: green;">
</span><span style="color: black;"> pMap </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">new</span><span style="color: black;"> SmashPcMap(Levelnames[Level</span><span style="color: black;">-</span><span style="color: purple;">1</span><span style="color: black;">].c_str(), GameData, </span><span style="color: black;">&</span><span style="color: black;">App);
Weapon.AssignSpace(pMap</span><span style="color: black;">-></span><span style="color: black;">GetSpace());
</span><span style="color: green;">//</span><span style="color: green;"> Start player at new spawn locations</span><span style="color: green;">
</span><span style="color: black;"> pOurPlayer </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">new</span><span style="color: black;"> SmashPcPlayer(GameData, </span><span style="color: black;">&</span><span style="color: black;">App, pMap</span><span style="color: black;">-></span><span style="color: black;">GetSpace(),
pMap</span><span style="color: black;">-></span><span style="color: black;">GetSpawnLocation(), </span><span style="color: black;">&</span><span style="color: black;">Weapon);
</span><span style="color: green;">//</span><span style="color: green;"> reset old armor</span><span style="color: green;">
</span><span style="color: black;"> pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">mu32Armor </span><span style="color: black;">=</span><span style="color: black;"> u32OldArmor;
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('79a9a937-7818-492e-a94b-a8f864bd8fba');
</script>
<br />
We check 1st if our guy is dead. if so, delay a second (the SmashPcPlayer->NotifyHit() handles playing the death sound), then restart the guy. If we're out of lives, play the Game Over sound and then quit.<br />
<br />
Then, I check if we've killed all the enemies in the level, and if so, Call the Intermission() function, which basically continues to draw the level, plays music, and puts up the "Level Complete" (or the "You've Won") status. Reset the GameData (which clears off all items and bullets from the active lists), deletes the player and map, and re-creates the map with the next level. <br />
<br />
We tell the Weapon class there's a new Physics Space, create a new player in the new map, and reset the armor.<br />
<br />
That's basically it! The next post will be a kind of postmortem, going of the specifics, and what I could've done better.beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-56162527633893616792011-11-15T00:38:00.001-05:002011-11-15T12:30:55.658-05:00SmashPC 1.0 Ready!I managed to cobble together enough code, and make a few levels to be able to release an actual game. It's late, so I'll wait to go over the specific's tomorrow. For now, download and extract the .zip (windows only), check the readme.txt, modify the SmashPcCfg.xml to configure your controls if you wish, and go!<br />
<br />
Let me know if there are any issues.<br />
<br />
<a href="http://dl.dropbox.com/u/27729730/SmashPc1.0.zip">SmashPc 1.0</a><br />
<br />
EDIT: The previous version didn't have all the .dll's required to play. If it failed to run previously, try this one.beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-89950567204382414472011-11-12T11:00:00.001-05:002011-11-12T11:19:46.158-05:00Some Flamethrowing goodness!I just wanted to post a video and picture of the enemies, and the flame-thrower I added in action.<br />
<br />
In the SmashPcWeapons.xml, I added this:<br />
<div id="iframeDiv411abe04-6d27-468f-899c-4396c398e1b6" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe411abe04-6d27-468f-899c-4396c398e1b6" src="http://www.blogtrog.com/code.aspx?id=411abe04-6d27-468f-899c-4396c398e1b6" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 600px;"></iframe></div>
<div id="noIframeDiv411abe04-6d27-468f-899c-4396c398e1b6" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: blue;"><</span><span style="color: maroon;">FlameThrower</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Image</span><span style="color: blue;">></span><span style="color: black;">flame.png</span><span style="color: blue;"></</span><span style="color: maroon;">Image</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Velocity</span><span style="color: blue;">></span><span style="color: black;">500</span><span style="color: blue;"></</span><span style="color: maroon;">Velocity</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Damage</span><span style="color: blue;">></span><span style="color: black;">6</span><span style="color: blue;"></</span><span style="color: maroon;">Damage</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Refire</span><span style="color: blue;">></span><span style="color: black;">10</span><span style="color: blue;"></</span><span style="color: maroon;">Refire</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">TimeToLive</span><span style="color: blue;">></span><span style="color: black;">700</span><span style="color: blue;"></</span><span style="color: maroon;">TimeToLive</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Fadeout</span><span style="color: blue;">></span><span style="color: black;">Yes</span><span style="color: blue;"></</span><span style="color: maroon;">Fadeout</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">DegreesOff</span><span style="color: blue;">></span><span style="color: black;">10</span><span style="color: blue;"></</span><span style="color: maroon;">DegreesOff</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">ContinuousSound</span><span style="color: blue;">></span><span style="color: black;">Yes</span><span style="color: blue;"></</span><span style="color: maroon;">ContinuousSound</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"></</span><span style="color: maroon;">FlameThrower</span><span style="color: blue;">></span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('411abe04-6d27-468f-899c-4396c398e1b6');
</script>
<br />
Fadeout means I want the bullet to fadeout during it's time to live. DegreesOff means I want it to fire at a random angle of 10 degrees off the straight angle.<br />
And, I had to modify SmashPcBullet.cpp to handle these changes:<br />
<br />
In SmashPcBullet Constructor, I added this:<br />
<div id="iframeDiv899b440e-708c-4fb4-a270-41da921749d2" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe899b440e-708c-4fb4-a270-41da921749d2" src="http://www.blogtrog.com/code.aspx?id=899b440e-708c-4fb4-a270-41da921749d2" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 700px;"></iframe></div>
<div id="noIframeDiv899b440e-708c-4fb4-a270-41da921749d2" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: green;">//</span><span style="color: green;"> If this gun shoots off a bit, modify the directions</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (BulletDetails.u32DegreesOff)
{
cpFloat RandomDegrees </span><span style="color: black;">=</span><span style="color: black;"> (cpFloat)(((S32)rand() </span><span style="color: black;">%</span><span style="color: black;"> (S32)BulletDetails.u32DegreesOff) </span><span style="color: black;">-</span><span style="color: black;">
(S32)BulletDetails.u32DegreesOff</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">);
mpBody</span><span style="color: black;">-></span><span style="color: black;">a </span><span style="color: black;">+=</span><span style="color: black;"> RandomDegrees</span><span style="color: black;">*</span><span style="color: black;">(PI</span><span style="color: black;">/</span><span style="color: purple;">180.0f</span><span style="color: black;">);
mpBody</span><span style="color: black;">-></span><span style="color: black;">v.x</span><span style="color: black;">=</span><span style="color: black;">cos( mpBody</span><span style="color: black;">-></span><span style="color: black;">a)</span><span style="color: black;">*</span><span style="color: black;">BulletDetails.Speed;
mpBody</span><span style="color: black;">-></span><span style="color: black;">v.y</span><span style="color: black;">=</span><span style="color: black;">sin( mpBody</span><span style="color: black;">-></span><span style="color: black;">a)</span><span style="color: black;">*</span><span style="color: black;">BulletDetails.Speed;
}
</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('899b440e-708c-4fb4-a270-41da921749d2');
</script>
<br />
And, in the SmashPcDraw(), I added this check:<br />
<div id="iframeDivfd031865-8294-4ff1-b09f-89dfc654f2ba" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframefd031865-8294-4ff1-b09f-89dfc654f2ba" src="http://www.blogtrog.com/code.aspx?id=fd031865-8294-4ff1-b09f-89dfc654f2ba" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 600px;"></iframe></div>
<div id="noIframeDivfd031865-8294-4ff1-b09f-89dfc654f2ba" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (mbFadeout)
{
U32 u32TimeDiff </span><span style="color: black;">=</span><span style="color: black;"> (timeGetTime() </span><span style="color: black;">-</span><span style="color: black;"> mu32StartTime)</span><span style="color: black;">+</span><span style="color: purple;">1</span><span style="color: black;">;
GlowColor.a </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">255</span><span style="color: black;"> </span><span style="color: black;">-</span><span style="color: black;"> ((</span><span style="color: purple;">255</span><span style="color: black;">*</span><span style="color: black;">u32TimeDiff)</span><span style="color: black;">/</span><span style="color: black;">mu32TimeToLive);
</span><span style="color: green;">//</span><span style="color: green;"> Change glow color to just alpha and make fade</span><span style="color: green;">
</span><span style="color: black;"> GlowColor.r </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">;
}
PhysicalObject::Draw(PlayerLoc, GlowColor);
</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('fd031865-8294-4ff1-b09f-89dfc654f2ba');
</script>
<br />
Anyway, here's the picture and video!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAr66PyyOZEpr49uxKdlsmv4hkeU8JgJIHB2QCUdRo6pOFla2HR7dhZGg79U-nvYVdfGhhiMBZiCOeh2d6kv5FUW5eGlhP1re_ij2tvBNs0b3r0fSaUsM3VUEH-2eaNg6rwqCki_SdY7I/s1600/Flamethrower.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAr66PyyOZEpr49uxKdlsmv4hkeU8JgJIHB2QCUdRo6pOFla2HR7dhZGg79U-nvYVdfGhhiMBZiCOeh2d6kv5FUW5eGlhP1re_ij2tvBNs0b3r0fSaUsM3VUEH-2eaNg6rwqCki_SdY7I/s320/Flamethrower.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dzcCw0yEBT879E-UAyzi0sIAu94v19xspDIgrus1p-QR5-OgnBH--5qfGSTLoDuVQsWOy1qzP4FYDqboAjbrQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe><br />
<br />beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com1tag:blogger.com,1999:blog-8221004988101681938.post-44458050240130022682011-11-11T23:41:00.001-05:002011-11-12T00:11:42.649-05:00I'm not dead! Enemies added!I apologize, it's been a while since I updated. I have been busy, but I finally am able to get back to this.<br />
<br />
And, the big news is, I've added our 1st enemies! OK, they're REALLY stupid, they just kind of move towards the player, shooting occasionally. Anyway, onto the code.<br />
<br />
Here's a link to the code:<br />
<a href="http://dl.dropbox.com/u/27729730/SmashPc-11-12-11.zip">SmashPc Code 11-12-11</a><br />
<br />
Before I get to the good stuff, I did a little more house cleaning.. I moved all the objects that live in the game (Items, Bullets, and Enemies) into the SmashPcData object, and let it keep the lists and call the update functions. So, now my main loop looks like this:<br />
<br />
<div id="iframeDiv387112c6-6888-4da0-9062-e8a720eefc80" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe387112c6-6888-4da0-9062-e8a720eefc80" src="http://www.blogtrog.com/code.aspx?id=387112c6-6888-4da0-9062-e8a720eefc80" style="border: 1px solid #e0e0e0; height: 350px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDiv387112c6-6888-4da0-9062-e8a720eefc80" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: green;">//</span><span style="color: green;"> main game loop</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">while</span><span style="color: black;"> (App.IsOpened())
{
pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">CheckInput();
cpSpaceStep(pMap</span><span style="color: black;">-></span><span style="color: black;">GetSpace(), </span><span style="color: purple;">1.0f</span><span style="color: black;">/</span><span style="color: purple;">60.0f</span><span style="color: black;">);
</span><span style="color: green;">/*</span><span style="color: green;"> clear screen and draw map </span><span style="color: green;">*/</span><span style="color: black;">
App.Clear(sf::Color(</span><span style="color: purple;">200</span><span style="color: black;">, </span><span style="color: purple;">200</span><span style="color: black;">, </span><span style="color: purple;">200</span><span style="color: black;">, </span><span style="color: purple;">255</span><span style="color: black;">));
pMap</span><span style="color: black;">-></span><span style="color: black;">Draw(pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">GetBody());
</span><span style="color: green;">//</span><span style="color: green;"> Update all the bullets in the world</span><span style="color: green;">
</span><span style="color: black;"> GameData.UpdateBullets(pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">GetBody());
</span><span style="color: green;">//</span><span style="color: green;"> check for items as well</span><span style="color: green;">
</span><span style="color: black;"> GameData.UpdateItems(pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">GetBody());
</span><span style="color: green;">//</span><span style="color: green;"> Finaly update all enemies</span><span style="color: green;">
</span><span style="color: black;"> GameData.UpdateEnemies(pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">GetBody());
pOurPlayer</span><span style="color: black;">-></span><span style="color: black;">Draw();
App.Display();
</span><span style="color: blue;">if</span><span style="color: black;"> (CheckGameEnd(</span><span style="color: black;">&</span><span style="color: black;">App))
{
App.Close();
</span><span style="color: blue;">break</span><span style="color: black;">;
}
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('387112c6-6888-4da0-9062-e8a720eefc80');
</script>
<br />
You can see it's pretty simple, and probably won't have much more to add. I suppose handling a dead player and changing levels. <br />
<br />
So, how do Enemies get added? In the level, I have "EnemySpawn" items, and they spawn enemies at a given rate. The plan is to give these spawn points levels, and the different enemy levels will make the enemies smarter, faster, tougher, etc.<br />
<br />
Here's the piece from SmashPcItem.xml for EnemySpawn1 (for level 1 enemies):<br />
<div id="iframeDivd0c4c4dc-2ada-420d-a948-7f532565b095" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframed0c4c4dc-2ada-420d-a948-7f532565b095" src="http://www.blogtrog.com/code.aspx?id=d0c4c4dc-2ada-420d-a948-7f532565b095" style="border: 1px solid #e0e0e0; height: 200px; margin: 0px; width: 600px;"></iframe></div>
<div id="noIframeDivd0c4c4dc-2ada-420d-a948-7f532565b095" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;"> </span><span style="color: blue;"><</span><span style="color: maroon;">EnemySpawn1 </span><span style="color: red;">Type</span><span style="color: blue;">="EnemySpawn"</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Interact</span><span style="color: blue;">></span><span style="color: black;">No</span><span style="color: blue;"></</span><span style="color: maroon;">Interact</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Value</span><span style="color: blue;">></span><span style="color: black;">50</span><span style="color: blue;"></</span><span style="color: maroon;">Value</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">ReleaseRate</span><span style="color: blue;">></span><span style="color: black;">5000</span><span style="color: blue;"></</span><span style="color: maroon;">ReleaseRate</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">EnemyLevel</span><span style="color: blue;">></span><span style="color: black;">1</span><span style="color: blue;"></</span><span style="color: maroon;">EnemyLevel</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"><</span><span style="color: maroon;">Rotate</span><span style="color: blue;">></span><span style="color: black;">0</span><span style="color: blue;"></</span><span style="color: maroon;">Rotate</span><span style="color: blue;">></span><span style="color: black;">
</span><span style="color: blue;"></</span><span style="color: maroon;">EnemySpawn1</span><span style="color: blue;">></span><span style="color: black;">
</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('d0c4c4dc-2ada-420d-a948-7f532565b095');
</script>
<br />
Which means we release a level 1 enemy every 5 seconds until 50 have been released.<br />
<br />
So, in SmashPcItem::Update(), we have this (Let me say, I really need to inherit from SmashPcItem, and make a SmashPcEnemySpawn class, but that'll be later):<br />
<br />
<div id="iframeDiv0368f7b5-8378-4c1a-ab7c-8692e8f2db3a" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe0368f7b5-8378-4c1a-ab7c-8692e8f2db3a" src="http://www.blogtrog.com/code.aspx?id=0368f7b5-8378-4c1a-ab7c-8692e8f2db3a" style="border: 1px solid #e0e0e0; height: 350px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDiv0368f7b5-8378-4c1a-ab7c-8692e8f2db3a" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;">BOOL SmashPcItem::Update(</span><span style="color: blue;">void</span><span style="color: black;">)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (mu32TimeToLive)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (timeGetTime() </span><span style="color: black;">></span><span style="color: black;"> mu32TimeToLive)
{
</span><span style="color: green;">//</span><span style="color: green;"> Mark Item for deletion</span><span style="color: green;">
</span><span style="color: black;"> mbActive </span><span style="color: black;">=</span><span style="color: black;"> FALSE;
GameSound::Play(</span><span style="color: maroon;">"</span><span style="color: maroon;">Despawn</span><span style="color: maroon;">"</span><span style="color: black;">);
</span><span style="color: blue;">return</span><span style="color: black;"> FALSE;
}
}
</span><span style="color: green;">//</span><span style="color: green;"> Release Enemies into the level</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (mpItemDetails</span><span style="color: black;">-></span><span style="color: black;">Type </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: maroon;">"</span><span style="color: maroon;">EnemySpawn</span><span style="color: maroon;">"</span><span style="color: black;">)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (mu32NumReleaseLeft </span><span style="color: black;">&&</span><span style="color: black;"> (mu32LastRelease </span><span style="color: black;">+</span><span style="color: black;"> mpItemDetails</span><span style="color: black;">-></span><span style="color: black;">u32ReleaseRate </span><span style="color: black;"><</span><span style="color: black;"> timeGetTime()))
{
SmashPcEnemy </span><span style="color: black;">*</span><span style="color: black;">pEnemy;
mu32LastRelease </span><span style="color: black;">=</span><span style="color: black;"> timeGetTime();
mu32NumReleaseLeft</span><span style="color: black;">--</span><span style="color: black;">;
</span><span style="color: green;">//</span><span style="color: green;"> Create an enemy</span><span style="color: green;">
</span><span style="color: black;"> pEnemy </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">new</span><span style="color: black;"> SmashPcEnemy(mGameData, mpApp, mpSpace,
mpBody</span><span style="color: black;">-></span><span style="color: black;">p, mpItemDetails</span><span style="color: black;">-></span><span style="color: black;">u32EnemyLevel);
</span><span style="color: green;">//</span><span style="color: green;"> Check if this enemy should release something</span><span style="color: green;">
</span><span style="color: black;"> mGameData.AddActiveEnemy(pEnemy);
}
}
</span><span style="color: blue;">return</span><span style="color: black;"> mbActive;
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('0368f7b5-8378-4c1a-ab7c-8692e8f2db3a');
</script>
<br />
And, our enemy class looks like this (I'm including it all here):
<br />
<div id="iframeDiv37fca73c-cf90-4e55-a85d-a00fe0859c42" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe37fca73c-cf90-4e55-a85d-a00fe0859c42" src="http://www.blogtrog.com/code.aspx?id=37fca73c-cf90-4e55-a85d-a00fe0859c42" style="border: 1px solid #e0e0e0; height: 500px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDiv37fca73c-cf90-4e55-a85d-a00fe0859c42" style="display: block; margin: 0px;">
<pre><div>
<span style="color: green;">/*</span><span style="color: green;">*****************************************************************************
*
* SmashPcEnemy() - Creates a player, and places him in the space
*
*****************************************************************************</span><span style="color: green;">*/</span><span style="color: black;">
SmashPcEnemy::SmashPcEnemy(SmashPcData </span><span style="color: black;">&</span><span style="color: black;">GameData,
sf::RenderWindow </span><span style="color: black;">*</span><span style="color: black;">pApp, cpSpace </span><span style="color: black;">*</span><span style="color: black;">pSpace,
cpVect Location, U32 u32Level) :
PhysicalObject(pApp, pSpace, </span><span style="color: maroon;">"</span><span style="color: maroon;">Gfx/blueenemy.bmp</span><span style="color: maroon;">"</span><span style="color: black;">, </span><span style="color: maroon;">""</span><span style="color: black;">,
Location, PI</span><span style="color: black;">/</span><span style="color: purple;">2.0f</span><span style="color: black;">, </span><span style="color: purple;">0.0f</span><span style="color: black;">, TRUE),
mu32Health(</span><span style="color: purple;">20</span><span style="color: black;">*</span><span style="color: black;">u32Level),
mu32LastFire(timeGetTime()),
mu32LastMoveUpdate(</span><span style="color: purple;">0</span><span style="color: black;">),
mGameData(GameData)
{
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Enemy created!\n</span><span style="color: maroon;">"</span><span style="color: black;">);
</span><span style="color: green;">//</span><span style="color: green;"> Set the Velocity limit to our fake movement</span><span style="color: green;">
</span><span style="color: black;"> mpBody</span><span style="color: black;">-></span><span style="color: black;">v_limit </span><span style="color: black;">=</span><span style="color: black;"> ENEMY_SPEED;
mpShape</span><span style="color: black;">-></span><span style="color: black;">collision_type </span><span style="color: black;">=</span><span style="color: black;"> ENEMY_COL_TYPE;
mpShape</span><span style="color: black;">-></span><span style="color: black;">layers </span><span style="color: black;">=</span><span style="color: black;"> ENEMY_PLAYER_LAYER;
mpShape</span><span style="color: black;">-></span><span style="color: black;">data </span><span style="color: black;">=</span><span style="color: black;"> (</span><span style="color: blue;">void</span><span style="color: black;"> </span><span style="color: black;">*</span><span style="color: black;">)</span><span style="color: blue;">this</span><span style="color: black;">;
</span><span style="color: green;">//</span><span style="color: green;"> Create Collision handler here</span><span style="color: green;">
</span><span style="color: black;"> cpSpaceAddCollisionHandler(mpSpace, ENEMY_COL_TYPE, BULLET_COL_TYPE, SmashPcEnemy::BulletCollision, NULL, NULL, NULL, NULL);
</span><span style="color: green;">//</span><span style="color: green;"> Sound notifying a player has spawned</span><span style="color: green;">
</span><span style="color: black;"> GameSound::Play(</span><span style="color: maroon;">"</span><span style="color: maroon;">EnemySpawn</span><span style="color: maroon;">"</span><span style="color: black;">);
}
</span><span style="color: green;">/*</span><span style="color: green;">*****************************************************************************
*
* ~SmashPcEnemy() - Removes a player
*
*****************************************************************************</span><span style="color: green;">*/</span><span style="color: black;">
SmashPcEnemy::</span><span style="color: black;">~</span><span style="color: black;">SmashPcEnemy()
{
}
</span><span style="color: green;">/*</span><span style="color: green;">*****************************************************************************
*
* Update() - Do enemy things
*
*****************************************************************************</span><span style="color: green;">*/</span><span style="color: black;">
</span><span style="color: blue;">void</span><span style="color: black;"> SmashPcEnemy::Update(cpBody </span><span style="color: black;">*</span><span style="color: black;">pPlayerBody)
{
U32 u32Time </span><span style="color: black;">=</span><span style="color: black;"> timeGetTime();
</span><span style="color: green;">//</span><span style="color: green;"> check if we need to update the movement</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (mu32LastMoveUpdate </span><span style="color: black;">+</span><span style="color: black;"> ENEMY_UPDATE_MOVE </span><span style="color: black;"><</span><span style="color: black;"> u32Time)
{
cpFloat Angle </span><span style="color: black;">=</span><span style="color: black;"> atan2(pPlayerBody</span><span style="color: black;">-></span><span style="color: black;">p.y </span><span style="color: black;">-</span><span style="color: black;"> mpBody</span><span style="color: black;">-></span><span style="color: black;">p.y,
pPlayerBody</span><span style="color: black;">-></span><span style="color: black;">p.x </span><span style="color: black;">-</span><span style="color: black;"> mpBody</span><span style="color: black;">-></span><span style="color: black;">p.x);
</span><span style="color: green;">//</span><span style="color: green;"> add randomization to angle</span><span style="color: green;">
</span><span style="color: black;"> cpFloat RandomDegrees </span><span style="color: black;">=</span><span style="color: black;"> (cpFloat)(((S32)rand() </span><span style="color: black;">%</span><span style="color: black;"> </span><span style="color: purple;">20</span><span style="color: black;">) </span><span style="color: black;">-</span><span style="color: black;"> </span><span style="color: purple;">10</span><span style="color: black;">);
Angle </span><span style="color: black;">+=</span><span style="color: black;"> (RandomDegrees</span><span style="color: black;">*</span><span style="color: black;">PI)</span><span style="color: black;">/</span><span style="color: purple;">180.0f</span><span style="color: black;">;
cpBodySetAngle(mpBody, Angle);
</span><span style="color: green;">//</span><span style="color: green;"> Change force towards player</span><span style="color: green;">
</span><span style="color: black;"> mForce </span><span style="color: black;">=</span><span style="color: black;"> cpv(ENEMY_FORCE</span><span style="color: black;">*</span><span style="color: black;">cos(Angle), ENEMY_FORCE</span><span style="color: black;">*</span><span style="color: black;">sin(Angle));
</span><span style="color: green;">//</span><span style="color: green;">mpBody->f = cpv(ENEMY_FORCE*cos(Angle), ENEMY_FORCE*sin(Angle));</span><span style="color: green;">
</span><span style="color: black;">
mu32LastMoveUpdate </span><span style="color: black;">=</span><span style="color: black;"> u32Time;
}
mpBody</span><span style="color: black;">-></span><span style="color: black;">f </span><span style="color: black;">=</span><span style="color: black;"> mForce;
</span><span style="color: blue;">if</span><span style="color: black;"> (mu32LastFire </span><span style="color: black;">+</span><span style="color: black;"> ENEMY_REFIRE_TIME </span><span style="color: black;"><</span><span style="color: black;"> u32Time)
{
SmashPcData::tBulletList BulletList;
mGameData.GetBulletList(BulletList);
SmashPcBullet </span><span style="color: black;">*</span><span style="color: black;">pBullet </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">new</span><span style="color: black;"> SmashPcBullet(mpApp, BulletList[</span><span style="color: purple;">0</span><span style="color: black;">],
mpBody, mpSpace, FALSE);
mGameData.AddActiveBullet(pBullet);
mu32LastFire </span><span style="color: black;">=</span><span style="color: black;"> u32Time;
}
}
</span><span style="color: green;">/*</span><span style="color: green;">*****************************************************************************
*
* NotifyHit() - Notify the enemy it has been hit by a bullet
*
*****************************************************************************</span><span style="color: green;">*/</span><span style="color: black;">
</span><span style="color: blue;">void</span><span style="color: black;"> SmashPcEnemy::NotifyHit(SmashPcBullet </span><span style="color: black;">*</span><span style="color: black;">pBullet)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (mu32Health </span><span style="color: black;"><</span><span style="color: black;"> pBullet</span><span style="color: black;">-></span><span style="color: black;">GetDamage())
{
</span><span style="color: green;">//</span><span style="color: green;"> Enemy Dead</span><span style="color: green;">
</span><span style="color: black;"> mu32Health </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">;
</span><span style="color: green;">//</span><span style="color: green;"> Play dead sound</span><span style="color: green;">
</span><span style="color: black;"> }
</span><span style="color: blue;">else</span><span style="color: black;">
{
GameSound::Play(</span><span style="color: maroon;">"</span><span style="color: maroon;">PlayerHit</span><span style="color: maroon;">"</span><span style="color: black;">);
mu32Health </span><span style="color: black;">-=</span><span style="color: black;"> pBullet</span><span style="color: black;">-></span><span style="color: black;">GetDamage();
}
pBullet</span><span style="color: black;">-></span><span style="color: black;">SetDead();
}
</span><span style="color: green;">/*</span><span style="color: green;">*****************************************************************************
*
* BulletCollision() - Callback for when Enemy hits a bullet
*
*****************************************************************************</span><span style="color: green;">*/</span><span style="color: black;">
</span><span style="color: blue;">int</span><span style="color: black;"> SmashPcEnemy::BulletCollision(cpArbiter </span><span style="color: black;">*</span><span style="color: black;">arb, </span><span style="color: blue;">struct</span><span style="color: black;"> cpSpace </span><span style="color: black;">*</span><span style="color: black;">space, </span><span style="color: blue;">void</span><span style="color: black;"> </span><span style="color: black;">*</span><span style="color: black;">data)
{
SmashPcBullet </span><span style="color: black;">*</span><span style="color: black;">pBullet;
SmashPcEnemy </span><span style="color: black;">*</span><span style="color: black;">pEnemy;
cpShape </span><span style="color: black;">*</span><span style="color: black;">pBulletShape, </span><span style="color: black;">*</span><span style="color: black;">pEnemyShape;
cpArbiterGetShapes(arb, </span><span style="color: black;">&</span><span style="color: black;">pEnemyShape, </span><span style="color: black;">&</span><span style="color: black;">pBulletShape);
pEnemy </span><span style="color: black;">=</span><span style="color: black;"> reinterpret_cast</span><span style="color: black;"><</span><span style="color: black;">SmashPcEnemy</span><span style="color: black;">*></span><span style="color: black;">(pEnemyShape</span><span style="color: black;">-></span><span style="color: black;">data);
pBullet </span><span style="color: black;">=</span><span style="color: black;"> reinterpret_cast</span><span style="color: black;"><</span><span style="color: black;">SmashPcBullet</span><span style="color: black;">*></span><span style="color: black;">(pBulletShape</span><span style="color: black;">-></span><span style="color: black;">data);
</span><span style="color: green;">//</span><span style="color: green;"> We have the enemy that hit, and the bullet he hit</span><span style="color: green;">
</span><span style="color: black;"> pEnemy</span><span style="color: black;">-></span><span style="color: black;">NotifyHit(pBullet);
</span><span style="color: blue;">return</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">;
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('37fca73c-cf90-4e55-a85d-a00fe0859c42');
</script>
<br />
OK, some explanation. In the constructor, we setup the specific physics attributes, including the collision handler. We're basically saying we want the enemy to get a callback when it's hit by the player's bullet. The Layer is set so it will be in the same collision layer as the player and the player bullets, even though we only want to get notified of hitting bullets (see chipmunk-physics for more on collision layers).<br />
<br />
In SmashPcEnemy::Update(), we move the enemy towards the player every so often. Notice we don't reset the velocity when we change the force, so the enemy will somewhat slowly change direction, continuing on it's previous path until the force can change it's direction fully. This will change for different "levels" of enemies, but this is it for now.<br />
<br />
The BulletCollision() simply calls the enemies NotifyHit(), with the bullet it hit, and in NotifyHit(), we reduce the health of the enemy.<br />
<br />
Finally, there is no specific enemy Draw, it uses the PhysicsObject::Draw() by default (the inherited class).<br />
<br />
The other thing I did was add a Collision Handler to the SmashPcPlayer class, which I didn't have before. It's basically identical to the Enemy's, except we subtract the damage from the armor 1st if the player has armor.<br />
<br />
Well, this results in some bad enemies. I'll have to adjust the AI some, but here's some pics. The first one, I just let the enemies pile up, and watched em run around. It's def a group mentality.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Q0__eT-TDPP3hZcPAcd4Ut3sODfgHkRB8NH_2yqwG9ge8V-5fsY7TfYD_w7NKdoFvmAMUJ5-pRF9KAkVU4MCPjCbUIc7k0GEOSF0l9wtiC3KbEdmbn94bgNJ7CNw8BLTvJRx07xBC_s/s1600/enemies2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4Q0__eT-TDPP3hZcPAcd4Ut3sODfgHkRB8NH_2yqwG9ge8V-5fsY7TfYD_w7NKdoFvmAMUJ5-pRF9KAkVU4MCPjCbUIc7k0GEOSF0l9wtiC3KbEdmbn94bgNJ7CNw8BLTvJRx07xBC_s/s320/enemies2.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlC-wDvF_vAMMboYPLup-iv_dUxnG7Vvd-j3quaS9vyPZDbpOvgNnPaLDJ__dyBTjXrAEf5Y63k3t8z8A9zNFaKt_y9BxVFufBwflEANJkVs6w4bMzYEV2SGNG7r6-mo91bBTpwVWKjuc/s1600/enemies1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlC-wDvF_vAMMboYPLup-iv_dUxnG7Vvd-j3quaS9vyPZDbpOvgNnPaLDJ__dyBTjXrAEf5Y63k3t8z8A9zNFaKt_y9BxVFufBwflEANJkVs6w4bMzYEV2SGNG7r6-mo91bBTpwVWKjuc/s320/enemies1.png" width="320" /></a></div>
<br />
OK, until next time!<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-11267230451751483562011-10-29T00:53:00.000-04:002011-10-29T00:53:10.240-04:00Quick Update...I haven't done anything real major lately, just tying some loose ends up, doing some under-the-cover work to get ready to integrate Enemies...the real hard part.
Anyway, here's a screenshot and a crappy video of what I have so far, with some ground tiles added:
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOxcyxi8Z_n6uesbGjelevFpF65XFc67J0U7Fhug7zpJOTycjHA5jSL-FQh2izKy-wI-ju4pZM9yXIhTmz2aR7aiUULbyNyYmWoz-cYlflHd169pN9Z_nAhKsoux6v4hJ5lAQ7u7Z76qA/s1600/Screenshot-11-29.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOxcyxi8Z_n6uesbGjelevFpF65XFc67J0U7Fhug7zpJOTycjHA5jSL-FQh2izKy-wI-ju4pZM9yXIhTmz2aR7aiUULbyNyYmWoz-cYlflHd169pN9Z_nAhKsoux6v4hJ5lAQ7u7Z76qA/s320/Screenshot-11-29.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
And the video:</div>
<div class="separator" style="clear: both; text-align: left;">
</div>
<div style="text-align: left;">
<br /></div>
<div style="text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='320' height='266' src='https://www.blogger.com/video.g?token=AD6v5dxVFT7MdeBx655gz__mGu16ehYxK78MbPj_S8GAqTRzqPFwNQIpPpwN2XrcX-f1dxtSJyEZQFLQUOoIe_rwHw' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-11697472101911920512011-10-27T00:02:00.001-04:002011-10-28T00:19:53.873-04:00Inheriting From Physical ObjectAs I mentioned in the last post, I realized I should be inheriting from a Super Class for classes that represent a physical object. So, I made the PhysicalObject class:<br />
<div id='iframeDivfea771e5-c58e-405f-a67a-2f4dd1643032' style='display:none;margin:0px;'><iframe id='iframefea771e5-c58e-405f-a67a-2f4dd1643032' src='http://www.blogtrog.com/code.aspx?id=fea771e5-c58e-405f-a67a-2f4dd1643032' style='width: 800px; height: 400px; border: 1px solid #e0e0e0;margin:0px;' frameborder='0'></iframe></div><div id='noIframeDivfea771e5-c58e-405f-a67a-2f4dd1643032' style='display:block;margin:0px;'><pre><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #000000;">PhysicalObject::PhysicalObject(sf::RenderWindow </span><span style="color: #000000;">*</span><span style="color: #000000;">pApp, cpSpace </span><span style="color: #000000;">*</span><span style="color: #000000;">pSpace,
std::</span><span style="color: #0000FF;">string</span><span style="color: #000000;"> ImageName, std::</span><span style="color: #0000FF;">string</span><span style="color: #000000;"> GlowImageName,
cpVect Location, cpFloat Angle, cpFloat Speed,
cpFloat Depth, cpFloat RotSpeed) :
mpApp(pApp),
mpSpace(pSpace),
mpImage(NULL),
mpGlowImage(NULL),
mpSprite(NULL),
mpGlowSprite(NULL),
mDepth(Depth)
{
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Load the image</span><span style="color: #008000;">
</span><span style="color: #000000;"> mpImage </span><span style="color: #000000;">=</span><span style="color: #000000;"> Utilities::ImageGet(ImageName.c_str());
mpSprite </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> sf::Sprite();
mpSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetImage(</span><span style="color: #000000;">*</span><span style="color: #000000;">mpImage);
mpSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetOrigin(mpImage</span><span style="color: #000000;">-></span><span style="color: #000000;">GetWidth()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">, mpImage</span><span style="color: #000000;">-></span><span style="color: #000000;">GetHeight()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Set to middle of screen</span><span style="color: #008000;">
</span><span style="color: #000000;"> mpSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetPosition(pApp</span><span style="color: #000000;">-></span><span style="color: #000000;">GetWidth()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">, pApp</span><span style="color: #000000;">-></span><span style="color: #000000;">GetHeight()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">);
</span><span style="color: #0000FF;">if</span><span style="color: #000000;"> (GlowImageName.size() </span><span style="color: #000000;">></span><span style="color: #000000;"> </span><span style="color: #800080;">0</span><span style="color: #000000;">)
{
mpGlowImage </span><span style="color: #000000;">=</span><span style="color: #000000;"> Utilities::ImageGet(GlowImageName.c_str());
mpGlowSprite </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> sf::Sprite();
mpGlowSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetImage(</span><span style="color: #000000;">*</span><span style="color: #000000;">mpGlowImage);
mpGlowSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetOrigin(mpGlowImage</span><span style="color: #000000;">-></span><span style="color: #000000;">GetWidth()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">, mpGlowImage</span><span style="color: #000000;">-></span><span style="color: #000000;">GetHeight()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Set to middle of screen</span><span style="color: #008000;">
</span><span style="color: #000000;"> mpGlowSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetPosition(pApp</span><span style="color: #000000;">-></span><span style="color: #000000;">GetWidth()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">, pApp</span><span style="color: #000000;">-></span><span style="color: #000000;">GetHeight()</span><span style="color: #000000;">/</span><span style="color: #800080;">2</span><span style="color: #000000;">);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> for glow, set to additive blend</span><span style="color: #008000;">
</span><span style="color: #000000;"> mpGlowSprite</span><span style="color: #000000;">-></span><span style="color: #000000;">SetBlendMode(sf::Blend::Add);
}
mpBody </span><span style="color: #000000;">=</span><span style="color: #000000;"> cpBodyNew(</span><span style="color: #800080;">1.0f</span><span style="color: #000000;">, </span><span style="color: #800080;">1.0f</span><span style="color: #000000;">);
cpBodySetPos(mpBody, Location);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> Set the Velocity</span><span style="color: #008000;">
</span><span style="color: #000000;"> mpBody</span><span style="color: #000000;">-></span><span style="color: #000000;">v.x</span><span style="color: #000000;">=</span><span style="color: #000000;">cos( Angle)</span><span style="color: #000000;">*</span><span style="color: #000000;">Speed;
mpBody</span><span style="color: #000000;">-></span><span style="color: #000000;">v.y</span><span style="color: #000000;">=</span><span style="color: #000000;">sin( Angle)</span><span style="color: #000000;">*</span><span style="color: #000000;">Speed;
cpBodySetAngle(mpBody, Angle);
mpBody</span><span style="color: #000000;">-></span><span style="color: #000000;">w </span><span style="color: #000000;">=</span><span style="color: #000000;"> RotSpeed;
mpShape </span><span style="color: #000000;">=</span><span style="color: #000000;"> cpCircleShapeNew(mpBody, (mpImage</span><span style="color: #000000;">-></span><span style="color: #000000;">GetWidth() </span><span style="color: #000000;">+</span><span style="color: #000000;"> mpImage</span><span style="color: #000000;">-></span><span style="color: #000000;">GetHeight())</span><span style="color: #000000;">/</span><span style="color: #800080;">4</span><span style="color: #000000;">, cpvzero);
mpShape</span><span style="color: #000000;">-></span><span style="color: #000000;">e </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0.0f</span><span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;"> not elatics, no bouncing</span><span style="color: #008000;">
</span><span style="color: #000000;"> mpShape</span><span style="color: #000000;">-></span><span style="color: #000000;">u </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #800080;">0.0f</span><span style="color: #000000;">; </span><span style="color: #008000;">//</span><span style="color: #008000;"> 0.0 is frictionless</span><span style="color: #008000;">
</span><span style="color: #000000;">
cpSpaceAddBody(mpSpace, mpBody);
cpSpaceAddShape(mpSpace, mpShape);
}</span></div></pre></div><script language='javascript' src='http://www.blogtrog.com/scripts/bt_code.js' type='text/javascript'></script><script language='javascript' type='text/javascript'>bt_code_init('fea771e5-c58e-405f-a67a-2f4dd1643032');</script>
<br />
The constructor handles all the physics stuff (except defining collision types and callbacks) and the image stuff.<br />
<br />
I also made a Draw in the PhysicalObject class:
<br />
<div id="iframeDivbf76a850-8a7a-497d-a360-723746e928cd" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframebf76a850-8a7a-497d-a360-723746e928cd" src="http://www.blogtrog.com/code.aspx?id=bf76a850-8a7a-497d-a360-723746e928cd" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 700px;"></iframe></div>
<div id="noIframeDivbf76a850-8a7a-497d-a360-723746e928cd" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;">BOOL PhysicalObject::Draw(cpVect PlayerLoc, sf::Color GlowColor)
{
cpFloat Angle </span><span style="color: black;">=</span><span style="color: black;"> cpBodyGetAngle(mpBody);
cpFloat Itemx </span><span style="color: black;">=</span><span style="color: black;"> (cpFloat)mpApp</span><span style="color: black;">-></span><span style="color: black;">GetWidth()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">;
cpFloat Itemy </span><span style="color: black;">=</span><span style="color: black;"> (cpFloat)mpApp</span><span style="color: black;">-></span><span style="color: black;">GetHeight()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">;
BOOL bDraw </span><span style="color: black;">=</span><span style="color: black;"> TRUE;
mpSprite</span><span style="color: black;">-></span><span style="color: black;">SetRotation(Angle</span><span style="color: black;">*</span><span style="color: black;">(</span><span style="color: purple;">180.0f</span><span style="color: black;">/</span><span style="color: black;">PI));
</span><span style="color: blue;">if</span><span style="color: black;"> (</span><span style="color: black;">!</span><span style="color: black;">cpveql(PlayerLoc, cpvzero))
{
</span><span style="color: green;">//</span><span style="color: green;"> Locate the sprite based off player's location</span><span style="color: green;">
</span><span style="color: black;"> Itemx </span><span style="color: black;">=</span><span style="color: black;"> (cpFloat)(mpApp</span><span style="color: black;">-></span><span style="color: black;">GetWidth()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">) </span><span style="color: black;">+</span><span style="color: black;"> (mpBody</span><span style="color: black;">-></span><span style="color: black;">p.x </span><span style="color: black;">-</span><span style="color: black;"> PlayerLoc.x);
Itemy </span><span style="color: black;">=</span><span style="color: black;"> (cpFloat)(mpApp</span><span style="color: black;">-></span><span style="color: black;">GetHeight()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">) </span><span style="color: black;">+</span><span style="color: black;"> (mpBody</span><span style="color: black;">-></span><span style="color: black;">p.y </span><span style="color: black;">-</span><span style="color: black;"> PlayerLoc.y);
</span><span style="color: blue;">if</span><span style="color: black;"> (</span><span style="color: black;">!</span><span style="color: black;">((Itemx </span><span style="color: black;">></span><span style="color: black;"> </span><span style="color: black;">-</span><span style="color: black;">(cpFloat)mpImage</span><span style="color: black;">-></span><span style="color: black;">GetWidth()) </span><span style="color: black;">&&</span><span style="color: black;">
(Itemx </span><span style="color: black;"><</span><span style="color: black;"> (cpFloat)mpApp</span><span style="color: black;">-></span><span style="color: black;">GetWidth() </span><span style="color: black;">+</span><span style="color: black;"> (cpFloat)mpImage</span><span style="color: black;">-></span><span style="color: black;">GetWidth()) </span><span style="color: black;">&&</span><span style="color: black;">
(Itemy </span><span style="color: black;">></span><span style="color: black;"> </span><span style="color: black;">-</span><span style="color: black;">(cpFloat)mpImage</span><span style="color: black;">-></span><span style="color: black;">GetHeight()) </span><span style="color: black;">&&</span><span style="color: black;">
(Itemy </span><span style="color: black;"><</span><span style="color: black;"> (cpFloat)mpApp</span><span style="color: black;">-></span><span style="color: black;">GetHeight() </span><span style="color: black;">+</span><span style="color: black;"> (cpFloat)mpImage</span><span style="color: black;">-></span><span style="color: black;">GetHeight())))
{
bDraw </span><span style="color: black;">=</span><span style="color: black;"> FALSE;
}
}
</span><span style="color: blue;">if</span><span style="color: black;"> (bDraw)
{
mpSprite</span><span style="color: black;">-></span><span style="color: black;">SetPosition(Itemx, Itemy);
</span><span style="color: green;">//</span><span style="color: green;"> Draw shadow 1st if depth</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (mDepth </span><span style="color: black;">></span><span style="color: black;"> </span><span style="color: purple;">0.001f</span><span style="color: black;">)
{
cpFloat Radius </span><span style="color: black;">=</span><span style="color: black;"> cpCircleShapeGetRadius(mpShape);
sf::Shape oCircle </span><span style="color: black;">=</span><span style="color: black;"> sf::Shape::Circle(Itemx</span><span style="color: black;">+</span><span style="color: purple;">5.0</span><span style="color: black;">, Itemy</span><span style="color: black;">+</span><span style="color: purple;">5.0</span><span style="color: black;">, mDepth</span><span style="color: black;">*</span><span style="color: black;">Radius</span><span style="color: black;">*</span><span style="color: purple;">0.80f</span><span style="color: black;">,
sf::Color(</span><span style="color: purple;">0</span><span style="color: black;">, </span><span style="color: purple;">0</span><span style="color: black;">, </span><span style="color: purple;">0</span><span style="color: black;">, </span><span style="color: purple;">150</span><span style="color: black;">));
mpApp</span><span style="color: black;">-></span><span style="color: black;">Draw(oCircle);
}
mpApp</span><span style="color: black;">-></span><span style="color: black;">Draw(</span><span style="color: black;">*</span><span style="color: black;">mpSprite);
</span><span style="color: green;">//</span><span style="color: green;"> If we get glow alpha and we have glow image</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (GlowColor.a </span><span style="color: black;">&&</span><span style="color: black;"> mpGlowSprite)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (</span><span style="color: black;">!</span><span style="color: black;">cpveql(PlayerLoc, cpvzero))
{
mpGlowSprite</span><span style="color: black;">-></span><span style="color: black;">SetPosition(Itemx, Itemy);
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
mpGlowSprite</span><span style="color: black;">-></span><span style="color: black;">SetPosition(mpApp</span><span style="color: black;">-></span><span style="color: black;">GetWidth()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">, mpApp</span><span style="color: black;">-></span><span style="color: black;">GetHeight()</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">);
}
mpGlowSprite</span><span style="color: black;">-></span><span style="color: black;">SetRotation(Angle</span><span style="color: black;">*</span><span style="color: black;">(</span><span style="color: purple;">180.0f</span><span style="color: black;">/</span><span style="color: black;">PI));
mpGlowSprite</span><span style="color: black;">-></span><span style="color: black;">SetColor(GlowColor);
mpApp</span><span style="color: black;">-></span><span style="color: black;">Draw(</span><span style="color: black;">*</span><span style="color: black;">mpGlowSprite);
}
}
</span><span style="color: blue;">return</span><span style="color: black;"> TRUE;
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('bf76a850-8a7a-497d-a360-723746e928cd');
</script>
<br />
As you can see, we handle the images and the glow images here. We also added a Depth member to draw shadows under objects.<br />
<br />
Here's the latest screenshot:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh25KA9SaX5fOtBryz6W68D7ysRgPlhNsG7FsF5o6dLKj5-gAjAPlVxD0exjbMcC5bOHGES4er4qken39EE5ssKHzJNTElUFVIyeii5mWnMPzoq93-Cexrnc3jevJLzOdP6WyyatWA4210/s1600/LevelAndItems.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh25KA9SaX5fOtBryz6W68D7ysRgPlhNsG7FsF5o6dLKj5-gAjAPlVxD0exjbMcC5bOHGES4er4qken39EE5ssKHzJNTElUFVIyeii5mWnMPzoq93-Cexrnc3jevJLzOdP6WyyatWA4210/s320/LevelAndItems.png" width="320" /></a></div>
<br />beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-19990854589619770352011-10-26T21:46:00.000-04:002011-10-28T00:25:47.268-04:00Added Level and Item introductionSo far, we've been using a hard-coded map, with 4 walls. Well, we need some way to create a real map, with multiple walls, items, etc. To accomplish this, I decided to use the tool Gleed2d (<a href="http://gleed2d.codeplex.com/">Gleed2d Site</a>). The tool allows me to lay out a map and it outputs it as an xml file. using tinyxml, we can parse this and use SmashPcMap to render it.<br />
<br />
Here's the source code:<br />
<a href="http://dl.dropbox.com/u/27729730/SmashPC-10-26-11.zip">SmashPc 10-26-11 Code</a><br />
<div>
<br /></div>
<div>
First, a picture of the level from gleed2d:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5_2Hi6A3PmqbO5rrvOPoeruqxAFymnOHnDeQThaR2DZiFxS_c52hzNp-3Cvgg-x6r4zOg3IC-kIQHMTO4OPIAH2IOV4QY5sxSOGNMKSYJ_GK7o0caYXbYaD62MkD_hfja1fp8OiRJdNI/s1600/Gleed2dLevel.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="197" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5_2Hi6A3PmqbO5rrvOPoeruqxAFymnOHnDeQThaR2DZiFxS_c52hzNp-3Cvgg-x6r4zOg3IC-kIQHMTO4OPIAH2IOV4QY5sxSOGNMKSYJ_GK7o0caYXbYaD62MkD_hfja1fp8OiRJdNI/s320/Gleed2dLevel.png" width="320" /></a></div>
<div>
As you can see, it's not much more than 4 walls. I added a block in the middle. a little circular wall with armor inside, some Enemy Generator Platforms (the things in the corner, will spawn enemies), and the little circles are the players spawn points.</div>
<div>
<br /></div>
<div>
As I said, this creates a xml file. So, I created the GameLevel.h and .cpp to parse that xml file and generate data we can understand.<br />
<br />
The code is below, you can expand them to see it if you want. It's got a lot of xml parsing. I'll explain a little below.<br />
GamLevel::GameLevel():</div>
<div id="iframeDivdf258c10-cce8-412f-b91d-6155169415a3" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframedf258c10-cce8-412f-b91d-6155169415a3" src="http://www.blogtrog.com/code.aspx?id=df258c10-cce8-412f-b91d-6155169415a3" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDivdf258c10-cce8-412f-b91d-6155169415a3" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;">GameLevel::GameLevel(</span><span style="color: blue;">char</span><span style="color: black;"> </span><span style="color: black;">*</span><span style="color: black;">pcFileToLoad) :
mbValid(FALSE)
{
TiXmlDocument doc(pcFileToLoad);
</span><span style="color: green;">//</span><span style="color: green;"> load and check if it was successful</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (doc.LoadFile())
{
TiXmlElement </span><span style="color: black;">*</span><span style="color: black;">root </span><span style="color: black;">=</span><span style="color: black;"> doc.RootElement();
</span><span style="color: green;">//</span><span style="color: green;"> extract level name, can check at some point</span><span style="color: green;">
</span><span style="color: black;"> printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Level name %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, root</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">Name</span><span style="color: maroon;">"</span><span style="color: black;">));
</span><span style="color: blue;">for</span><span style="color: black;">(TiXmlElement</span><span style="color: black;">*</span><span style="color: black;"> LayersElem </span><span style="color: black;">=</span><span style="color: black;"> root</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(); LayersElem;
LayersElem </span><span style="color: black;">=</span><span style="color: black;"> LayersElem</span><span style="color: black;">-></span><span style="color: black;">NextSiblingElement())
{
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">LayersElem %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, LayersElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr().c_str());
</span><span style="color: green;">//</span><span style="color: green;"> this should be Layers</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (LayersElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr() </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: blue;">string</span><span style="color: black;">(</span><span style="color: maroon;">"</span><span style="color: maroon;">Layers</span><span style="color: maroon;">"</span><span style="color: black;">))
{
</span><span style="color: blue;">for</span><span style="color: black;">(TiXmlElement</span><span style="color: black;">*</span><span style="color: black;"> LayerElem </span><span style="color: black;">=</span><span style="color: black;"> LayersElem</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(); LayerElem;
LayerElem </span><span style="color: black;">=</span><span style="color: black;"> LayerElem</span><span style="color: black;">-></span><span style="color: black;">NextSiblingElement())
{
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">LayerElem %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, LayerElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr().c_str());
</span><span style="color: green;">//</span><span style="color: green;"> This should be Layer</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (LayerElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr() </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: blue;">string</span><span style="color: black;">(</span><span style="color: maroon;">"</span><span style="color: maroon;">Layer</span><span style="color: maroon;">"</span><span style="color: black;">))
{
</span><span style="color: blue;">for</span><span style="color: black;">(TiXmlElement</span><span style="color: black;">*</span><span style="color: black;"> ItemsElem </span><span style="color: black;">=</span><span style="color: black;"> LayerElem</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(); ItemsElem;
ItemsElem </span><span style="color: black;">=</span><span style="color: black;"> ItemsElem</span><span style="color: black;">-></span><span style="color: black;">NextSiblingElement())
{
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">ItemsElem %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, ItemsElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr().c_str());
</span><span style="color: green;">//</span><span style="color: green;"> This should be Items</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (ItemsElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr() </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: blue;">string</span><span style="color: black;">(</span><span style="color: maroon;">"</span><span style="color: maroon;">Items</span><span style="color: maroon;">"</span><span style="color: black;">))
{
</span><span style="color: blue;">for</span><span style="color: black;">(TiXmlElement</span><span style="color: black;">*</span><span style="color: black;"> ItemElem </span><span style="color: black;">=</span><span style="color: black;"> ItemsElem</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(); ItemElem;
ItemElem </span><span style="color: black;">=</span><span style="color: black;"> ItemElem</span><span style="color: black;">-></span><span style="color: black;">NextSiblingElement())
{
</span><span style="color: green;">//</span><span style="color: green;"> This should be Item</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (ItemElem</span><span style="color: black;">-></span><span style="color: black;">ValueStr() </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: blue;">string</span><span style="color: black;">(</span><span style="color: maroon;">"</span><span style="color: maroon;">Item</span><span style="color: maroon;">"</span><span style="color: black;">))
{
ParseItem(ItemElem);
}
}
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
</span><span style="color: green;">//</span><span style="color: green;"> it's scoll speed, we can ignore</span><span style="color: green;">
</span><span style="color: black;"> printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Skip Scroll\n</span><span style="color: maroon;">"</span><span style="color: black;">);
}
}
}
}
}
}
mbValid </span><span style="color: black;">=</span><span style="color: black;"> TRUE;
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Failed opening %s, reason: %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, pcFileToLoad, doc.ErrorDesc());
}
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('df258c10-cce8-412f-b91d-6155169415a3');
</script>
<br />
GameLevel::ParseItem()
<br />
<div id="iframeDiv24a937ad-2858-40f5-910f-29f3b78e5a53" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframe24a937ad-2858-40f5-910f-29f3b78e5a53" src="http://www.blogtrog.com/code.aspx?id=24a937ad-2858-40f5-910f-29f3b78e5a53" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDiv24a937ad-2858-40f5-910f-29f3b78e5a53" style="display: block; margin: 0px;">
<pre><div>
<span style="color: blue;">void</span><span style="color: black;"> GameLevel::ParseItem(TiXmlElement</span><span style="color: black;">*</span><span style="color: black;"> ItemElem)
{
tLevelWall LevelWall;
tLevelItem LevelItem;
map SpecValues;
</span><span style="color: green;">//</span><span style="color: green;"> store off position</span><span style="color: green;">
</span><span style="color: black;"> cpVect Position;
Position.x </span><span style="color: black;">=</span><span style="color: black;"> atof(ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Position</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">X</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
Position.y </span><span style="color: black;">=</span><span style="color: black;"> atof(ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Position</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Y</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
</span><span style="color: green;">//</span><span style="color: green;"> check for custom properties and handle if found</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(</span><span style="color: maroon;">"</span><span style="color: maroon;">CustomProperties</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild() </span><span style="color: black;">!=</span><span style="color: black;"> NULL)
{
</span><span style="color: blue;">string</span><span style="color: black;"> Key, Value;
</span><span style="color: blue;">for</span><span style="color: black;">(TiXmlElement</span><span style="color: black;">*</span><span style="color: black;"> PropElem </span><span style="color: black;">=</span><span style="color: black;"> ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(</span><span style="color: maroon;">"</span><span style="color: maroon;">CustomProperties</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChildElement(); PropElem;
PropElem </span><span style="color: black;">=</span><span style="color: black;"> PropElem</span><span style="color: black;">-></span><span style="color: black;">NextSiblingElement())
{
Key </span><span style="color: black;">=</span><span style="color: black;"> PropElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">Name</span><span style="color: maroon;">"</span><span style="color: black;">);
Value </span><span style="color: black;">=</span><span style="color: black;"> PropElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">ValueStr();
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">SpecField Key %s Val %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, Key.c_str(), Value.c_str());
SpecValues[Key] </span><span style="color: black;">=</span><span style="color: black;"> Value;
}
}
</span><span style="color: green;">//</span><span style="color: green;"> check for spawn 1st</span><span style="color: green;">
</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (strncmp(ItemElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">Name</span><span style="color: maroon;">"</span><span style="color: black;">), </span><span style="color: maroon;">"</span><span style="color: maroon;">Spawn</span><span style="color: maroon;">"</span><span style="color: black;">, </span><span style="color: purple;">5</span><span style="color: black;">) </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">)
{
mSpawns.push_back(Position);
}
</span><span style="color: green;">/*</span><span style="color: green;"> If it's a rectangle, it's made as a wall or spawn point </span><span style="color: green;">*/</span><span style="color: black;">
</span><span style="color: blue;">else</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (strcmp(ItemElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">xsi:type</span><span style="color: maroon;">"</span><span style="color: black;">), </span><span style="color: maroon;">"</span><span style="color: maroon;">RectangleItem</span><span style="color: maroon;">"</span><span style="color: black;">) </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">)
{
LevelWall.StartingPoint </span><span style="color: black;">=</span><span style="color: black;"> Position;
LevelWall.EndingPoint.x </span><span style="color: black;">=</span><span style="color: black;"> atof(ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Width</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value()) </span><span style="color: black;">+</span><span style="color: black;">
Position.x;
LevelWall.EndingPoint.y </span><span style="color: black;">=</span><span style="color: black;"> atof(ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Height</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value()) </span><span style="color: black;">+</span><span style="color: black;">
Position.y;
LevelWall.bIsRect </span><span style="color: black;">=</span><span style="color: black;"> TRUE;
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Rect Start x %f end %f\n</span><span style="color: maroon;">"</span><span style="color: black;">, LevelWall.StartingPoint.x, LevelWall.EndingPoint.x);
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Rect Start y %f end %f\n</span><span style="color: maroon;">"</span><span style="color: black;">, LevelWall.StartingPoint.y, LevelWall.EndingPoint.y);
</span><span style="color: green;">//</span><span style="color: green;"> add to vector</span><span style="color: green;">
</span><span style="color: black;"> mWalls.push_back(LevelWall);
}
</span><span style="color: blue;">else</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (strcmp(ItemElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">xsi:type</span><span style="color: maroon;">"</span><span style="color: black;">), </span><span style="color: maroon;">"</span><span style="color: maroon;">TextureItem</span><span style="color: maroon;">"</span><span style="color: black;">) </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">)
{
</span><span style="color: blue;">string</span><span style="color: black;"> TempString;
cpVect SecondLoc </span><span style="color: black;">=</span><span style="color: black;"> cpvzero;
LevelItem.Location </span><span style="color: black;">=</span><span style="color: black;"> Position;
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">SpriteName %s\n</span><span style="color: maroon;">"</span><span style="color: black;">, ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">texture_filename</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
</span><span style="color: green;">//</span><span style="color: green;"> get name up to _</span><span style="color: green;">
</span><span style="color: black;"> TempString </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">string</span><span style="color: black;">(ItemElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">Name</span><span style="color: maroon;">"</span><span style="color: black;">));
LevelItem.ItemName </span><span style="color: black;">=</span><span style="color: black;"> TempString.substr(</span><span style="color: purple;">0</span><span style="color: black;">, TempString.find(</span><span style="color: maroon;">"</span><span style="color: maroon;">_</span><span style="color: maroon;">"</span><span style="color: black;">));
cout </span><span style="color: black;"><<</span><span style="color: black;"> </span><span style="color: maroon;">"</span><span style="color: maroon;">LevelItem name </span><span style="color: maroon;">"</span><span style="color: black;"> </span><span style="color: black;"><<</span><span style="color: black;"> LevelItem.ItemName </span><span style="color: black;"><<</span><span style="color: black;"> endl;
</span><span style="color: green;">//</span><span style="color: green;"> load the texture here</span><span style="color: green;">
</span><span style="color: black;"> LevelItem.pImage </span><span style="color: black;">=</span><span style="color: black;"> Utilities::ImageGet(ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">texture_filename</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
mItems.push_back(LevelItem);
}
</span><span style="color: blue;">else</span><span style="color: black;"> </span><span style="color: blue;">if</span><span style="color: black;"> (strcmp(ItemElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">xsi:type</span><span style="color: maroon;">"</span><span style="color: black;">), </span><span style="color: maroon;">"</span><span style="color: maroon;">PathItem</span><span style="color: maroon;">"</span><span style="color: black;">) </span><span style="color: black;">==</span><span style="color: black;"> </span><span style="color: purple;">0</span><span style="color: black;">)
{
</span><span style="color: green;">//</span><span style="color: green;"> Parse the Path starting at WorldPoints</span><span style="color: green;">
</span><span style="color: black;"> ParsePath(ItemElem</span><span style="color: black;">-></span><span style="color: black;">Attribute(</span><span style="color: maroon;">"</span><span style="color: maroon;">Name</span><span style="color: maroon;">"</span><span style="color: black;">),
ItemElem</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">WorldPoints</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Vector2</span><span style="color: maroon;">"</span><span style="color: black;">));
}
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('24a937ad-2858-40f5-910f-29f3b78e5a53');
</script>
<br />
GameLevel::ParsePath()
<br />
<div id="iframeDiva42137dd-42c6-4d58-bc9b-342732946cd0" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframea42137dd-42c6-4d58-bc9b-342732946cd0" src="http://www.blogtrog.com/code.aspx?id=a42137dd-42c6-4d58-bc9b-342732946cd0" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDiva42137dd-42c6-4d58-bc9b-342732946cd0" style="display: block; margin: 0px;">
<pre><div>
<span style="color: blue;">void</span><span style="color: black;"> GameLevel::ParsePath(</span><span style="color: blue;">const</span><span style="color: black;"> </span><span style="color: blue;">char</span><span style="color: black;"> </span><span style="color: black;">*</span><span style="color: green;">/*</span><span style="color: green;">pName</span><span style="color: green;">*/</span><span style="color: black;">, </span><span style="color: blue;">const</span><span style="color: black;"> TiXmlNode </span><span style="color: black;">*</span><span style="color: black;">WorldCoordNode)
{
tLevelWall LevelWall;
BOOL bFirst </span><span style="color: black;">=</span><span style="color: black;"> TRUE;
</span><span style="color: green;">//</span><span style="color: green;"> Might use name if we use paths for more than walls in the future</span><span style="color: green;">
</span><span style="color: black;">
</span><span style="color: blue;">for</span><span style="color: black;">(</span><span style="color: blue;">const</span><span style="color: black;"> TiXmlNode</span><span style="color: black;">*</span><span style="color: black;"> CoordNode </span><span style="color: black;">=</span><span style="color: black;"> WorldCoordNode; CoordNode;
CoordNode </span><span style="color: black;">=</span><span style="color: black;"> CoordNode</span><span style="color: black;">-></span><span style="color: black;">NextSibling())
{
</span><span style="color: blue;">if</span><span style="color: black;"> (bFirst)
{
LevelWall.StartingPoint.x </span><span style="color: black;">=</span><span style="color: black;"> atof(CoordNode</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">X</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
LevelWall.StartingPoint.y </span><span style="color: black;">=</span><span style="color: black;"> atof(CoordNode</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Y</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
bFirst </span><span style="color: black;">=</span><span style="color: black;"> FALSE;
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
cpFloat SwapVal;
LevelWall.EndingPoint.x </span><span style="color: black;">=</span><span style="color: black;"> atof(CoordNode</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">X</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
LevelWall.EndingPoint.y </span><span style="color: black;">=</span><span style="color: black;"> atof(CoordNode</span><span style="color: black;">-></span><span style="color: black;">FirstChild(</span><span style="color: maroon;">"</span><span style="color: maroon;">Y</span><span style="color: maroon;">"</span><span style="color: black;">)</span><span style="color: black;">-></span><span style="color: black;">FirstChild()</span><span style="color: black;">-></span><span style="color: black;">Value());
LevelWall.bIsRect </span><span style="color: black;">=</span><span style="color: black;"> FALSE;
mWalls.push_back(LevelWall);
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Path Start x %f end %f\n</span><span style="color: maroon;">"</span><span style="color: black;">, LevelWall.StartingPoint.x, LevelWall.EndingPoint.x);
printf(</span><span style="color: maroon;">"</span><span style="color: maroon;">Path Start y %f end %f\n</span><span style="color: maroon;">"</span><span style="color: black;">, LevelWall.StartingPoint.y, LevelWall.EndingPoint.y);
LevelWall.StartingPoint </span><span style="color: black;">=</span><span style="color: black;"> LevelWall.EndingPoint;
}
}
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('a42137dd-42c6-4d58-bc9b-342732946cd0');
</script>
Basically, we open the xml, and read each "Item." In gleed2d speak, anything in the map is an item. For us, an Item is Either a "RectangleItem", which is just a Wall, a "TextureItem", which is an item in the game, a "PathItem", which is a connected wall, or a Spawn (our name). We read each of these out into a WallList, ItemList, or SpawnList.<br />
<br />
In order to use these, we modify SmashPcMap to load the Level, and it reads the lists out and draws the walls and items.<br />
<br />
Here's the new CreateSpace, which puts the walls into the physics space:<br />
<div id="iframeDivc03e19ba-2e62-4d6e-8bf3-c50668c55343" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframec03e19ba-2e62-4d6e-8bf3-c50668c55343" src="http://www.blogtrog.com/code.aspx?id=c03e19ba-2e62-4d6e-8bf3-c50668c55343" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDivc03e19ba-2e62-4d6e-8bf3-c50668c55343" style="display: block; margin: 0px;">
<pre><div>
<span style="color: blue;">void</span><span style="color: black;"> SmashPcMap::CreateSpace(</span><span style="color: blue;">void</span><span style="color: black;">)
{
GameLevel::tLevelItem LevelItem;
GameLevel::tLevelWall LevelWall;
cpShape </span><span style="color: black;">*</span><span style="color: black;">pShape;
std::vector::iterator it;
</span><span style="color: green;">/*</span><span style="color: green;"> loop through all the walls 1st and draw them </span><span style="color: green;">*/</span><span style="color: black;">
</span><span style="color: blue;">for</span><span style="color: black;"> (it </span><span style="color: black;">=</span><span style="color: black;"> mpLevel</span><span style="color: black;">-></span><span style="color: black;">mWalls.begin();
it </span><span style="color: black;">!=</span><span style="color: black;"> mpLevel</span><span style="color: black;">-></span><span style="color: black;">mWalls.end(); it</span><span style="color: black;">++</span><span style="color: black;">)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (it</span><span style="color: black;">-></span><span style="color: black;">bIsRect)
{
cpVect Verts[</span><span style="color: purple;">4</span><span style="color: black;">] </span><span style="color: black;">=</span><span style="color: black;"> {{it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.x, it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.y},
{it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.x, it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.y},
{it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.x, it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.y},
{it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.x, it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.y} };
pShape </span><span style="color: black;">=</span><span style="color: black;"> cpSpaceAddShape(mpSpace, cpPolyShapeNew(</span><span style="color: black;">&</span><span style="color: black;">mpSpace</span><span style="color: black;">-></span><span style="color: black;">staticBody, </span><span style="color: purple;">4</span><span style="color: black;">, Verts, cpvzero));
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
pShape </span><span style="color: black;">=</span><span style="color: black;"> cpSpaceAddShape(mpSpace, cpSegmentShapeNew(</span><span style="color: black;">&</span><span style="color: black;">mpSpace</span><span style="color: black;">-></span><span style="color: black;">staticBody, it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint, it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint, </span><span style="color: purple;">10.0f</span><span style="color: black;">));
}
pShape</span><span style="color: black;">-></span><span style="color: black;">e </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">0.0f</span><span style="color: black;">;</span><span style="color: green;">//</span><span style="color: green;">9f;</span><span style="color: green;">
</span><span style="color: black;"> pShape</span><span style="color: black;">-></span><span style="color: black;">u </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">0.0f</span><span style="color: black;">;</span><span style="color: green;">//</span><span style="color: green;">3f;</span><span style="color: green;">
</span><span style="color: black;"> pShape</span><span style="color: black;">-></span><span style="color: black;">collision_type </span><span style="color: black;">=</span><span style="color: black;"> WALL_COL_TYPE;
pShape</span><span style="color: black;">-></span><span style="color: black;">data </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: blue;">this</span><span style="color: black;">;
</span><span style="color: green;">//</span><span style="color: green;"> Walls occupy all layers</span><span style="color: green;">
</span><span style="color: black;"> }
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('c03e19ba-2e62-4d6e-8bf3-c50668c55343');
</script>
<br />
And here's the SmashPcMap::Draw that draws the walls and items:<br />
<div id="iframeDivc0dfee52-8b5b-4571-b11a-95858c59ba6e" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframec0dfee52-8b5b-4571-b11a-95858c59ba6e" src="http://www.blogtrog.com/code.aspx?id=c0dfee52-8b5b-4571-b11a-95858c59ba6e" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDivc0dfee52-8b5b-4571-b11a-95858c59ba6e" style="display: block; margin: 0px;">
<pre><div>
<span style="color: black;">BOOL SmashPcMap::Draw(cpBody </span><span style="color: black;">*</span><span style="color: black;">PlayerBody)
{
cpFloat LeftX </span><span style="color: black;">=</span><span style="color: black;"> PlayerBody</span><span style="color: black;">-></span><span style="color: black;">p.x </span><span style="color: black;">-</span><span style="color: black;"> mu32ScreenWidth</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">;
cpFloat TopY </span><span style="color: black;">=</span><span style="color: black;"> PlayerBody</span><span style="color: black;">-></span><span style="color: black;">p.y </span><span style="color: black;">-</span><span style="color: black;"> mu32ScreenHeight</span><span style="color: black;">/</span><span style="color: purple;">2</span><span style="color: black;">;
std::vector::iterator it;
</span><span style="color: green;">/*</span><span style="color: green;"> loop through all the walls 1st and draw them </span><span style="color: green;">*/</span><span style="color: black;">
</span><span style="color: blue;">for</span><span style="color: black;"> (it </span><span style="color: black;">=</span><span style="color: black;"> mpLevel</span><span style="color: black;">-></span><span style="color: black;">mWalls.begin();
it </span><span style="color: black;">!=</span><span style="color: black;"> mpLevel</span><span style="color: black;">-></span><span style="color: black;">mWalls.end(); it</span><span style="color: black;">++</span><span style="color: black;">)
{
sf::Shape oShape;
</span><span style="color: blue;">if</span><span style="color: black;"> (it</span><span style="color: black;">-></span><span style="color: black;">bIsRect)
{
oShape </span><span style="color: black;">=</span><span style="color: black;"> sf::Shape::Rectangle (it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.x </span><span style="color: black;">-</span><span style="color: black;"> LeftX, it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.y </span><span style="color: black;">-</span><span style="color: black;"> TopY,
it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.x </span><span style="color: black;">-</span><span style="color: black;"> it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.x,
it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.y </span><span style="color: black;">-</span><span style="color: black;"> it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.y,
sf::Color(</span><span style="color: purple;">128</span><span style="color: black;">, </span><span style="color: purple;">128</span><span style="color: black;">, </span><span style="color: purple;">128</span><span style="color: black;">, </span><span style="color: purple;">255</span><span style="color: black;">));
}
</span><span style="color: blue;">else</span><span style="color: black;">
{
oShape </span><span style="color: black;">=</span><span style="color: black;"> sf::Shape::Line(it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.x </span><span style="color: black;">-</span><span style="color: black;"> LeftX, it</span><span style="color: black;">-></span><span style="color: black;">StartingPoint.y </span><span style="color: black;">-</span><span style="color: black;"> TopY,
it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.x </span><span style="color: black;">-</span><span style="color: black;"> LeftX, it</span><span style="color: black;">-></span><span style="color: black;">EndingPoint.y </span><span style="color: black;">-</span><span style="color: black;"> TopY,
</span><span style="color: purple;">10</span><span style="color: black;">, sf::Color(</span><span style="color: purple;">128</span><span style="color: black;">, </span><span style="color: purple;">128</span><span style="color: black;">, </span><span style="color: purple;">128</span><span style="color: black;">, </span><span style="color: purple;">255</span><span style="color: black;">));
}
mpApp</span><span style="color: black;">-></span><span style="color: black;">Draw(oShape);
}
</span><span style="color: green;">//</span><span style="color: green;"> draw all the items</span><span style="color: green;">
</span><span style="color: black;"> std::vector::iterator ItemIt;
</span><span style="color: blue;">for</span><span style="color: black;"> (ItemIt </span><span style="color: black;">=</span><span style="color: black;"> ItemList.begin(); ItemIt </span><span style="color: black;">!=</span><span style="color: black;"> ItemList.end(); ItemIt</span><span style="color: black;">++</span><span style="color: black;">)
{
(</span><span style="color: black;">*</span><span style="color: black;">ItemIt)</span><span style="color: black;">-></span><span style="color: black;">Draw(PlayerBody</span><span style="color: black;">-></span><span style="color: black;">p);
}
</span><span style="color: blue;">return</span><span style="color: black;"> TRUE;
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('c0dfee52-8b5b-4571-b11a-95858c59ba6e');
</script>
You can see we created a new class, "SmashPcItem" which doesn't do alot yet, but it will Draw().
I have implemented the beginnings of collision between Player an Items. Here's how I have the SmashPcItem::CreatePhysicsObject():<br />
<div id="iframeDivacb04d3a-3270-4654-82ce-567012b7cac5" style="display: none; margin: 0px;">
<iframe frameborder="0" id="iframeacb04d3a-3270-4654-82ce-567012b7cac5" src="http://www.blogtrog.com/code.aspx?id=acb04d3a-3270-4654-82ce-567012b7cac5" style="border: 1px solid #e0e0e0; height: 400px; margin: 0px; width: 800px;"></iframe></div>
<div id="noIframeDivacb04d3a-3270-4654-82ce-567012b7cac5" style="display: block; margin: 0px;">
<pre><div>
<span style="color: blue;">void</span><span style="color: black;"> SmashPcItem::CreatePhysicsObjects(</span><span style="color: blue;">void</span><span style="color: black;">)
{
</span><span style="color: blue;">if</span><span style="color: black;"> (mbPhysical)
{
cpFloat Inertia;
mpBody </span><span style="color: black;">=</span><span style="color: black;"> cpBodyNew(</span><span style="color: purple;">500.0f</span><span style="color: black;">, </span><span style="color: purple;">500.0f</span><span style="color: black;">);
cpBodySetPos(mpBody, mItemInfo.Location);
mpBody</span><span style="color: black;">-></span><span style="color: black;">v </span><span style="color: black;">=</span><span style="color: black;"> cpvzero;
</span><span style="color: green;">/*</span><span style="color: green;"> teleporter doesn't spin </span><span style="color: green;">*/</span><span style="color: black;">
mpBody</span><span style="color: black;">-></span><span style="color: black;">w </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">2.0f</span><span style="color: black;">;
mpShape </span><span style="color: black;">=</span><span style="color: black;"> cpCircleShapeNew(mpBody,
(cpFloat)((mItemInfo.pImage</span><span style="color: black;">-></span><span style="color: black;">GetWidth() </span><span style="color: black;">+</span><span style="color: black;"> mItemInfo.pImage</span><span style="color: black;">-></span><span style="color: black;">GetHeight())</span><span style="color: black;">/</span><span style="color: purple;">4</span><span style="color: black;">),
cpvzero);
Inertia </span><span style="color: black;">=</span><span style="color: black;"> cpMomentForCircle(</span><span style="color: purple;">5.0f</span><span style="color: black;">, </span><span style="color: purple;">0.0f</span><span style="color: black;">,
(cpFloat)((mItemInfo.pImage</span><span style="color: black;">-></span><span style="color: black;">GetWidth() </span><span style="color: black;">+</span><span style="color: black;"> mItemInfo.pImage</span><span style="color: black;">-></span><span style="color: black;">GetHeight())</span><span style="color: black;">/</span><span style="color: purple;">4</span><span style="color: black;">),
cpvzero);
cpBodySetMoment(mpBody, Inertia);
mpShape</span><span style="color: black;">-></span><span style="color: black;">e </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">0.0f</span><span style="color: black;">; </span><span style="color: green;">//</span><span style="color: green;"> not elatics, no bouncing</span><span style="color: green;">
</span><span style="color: black;"> mpShape</span><span style="color: black;">-></span><span style="color: black;">u </span><span style="color: black;">=</span><span style="color: black;"> </span><span style="color: purple;">1.0f</span><span style="color: black;">; </span><span style="color: green;">//</span><span style="color: green;"> 0.0 is frictionless</span><span style="color: green;">
</span><span style="color: black;"> mpShape</span><span style="color: black;">-></span><span style="color: black;">collision_type </span><span style="color: black;">=</span><span style="color: black;"> ITEM_COL_TYPE;
mpShape</span><span style="color: black;">-></span><span style="color: black;">layers </span><span style="color: black;">=</span><span style="color: black;"> MAP_ITEM_LAYER;
mpShape</span><span style="color: black;">-></span><span style="color: black;">data </span><span style="color: black;">=</span><span style="color: black;"> static_cast</span><span style="color: black;"><</span><span style="color: blue;">void</span><span style="color: black;"> </span><span style="color: black;">*></span><span style="color: black;">(</span><span style="color: blue;">this</span><span style="color: black;">);
cpSpaceAddBody(mpSpace, mpBody);
cpSpaceAddShape(mpSpace, mpShape);
</span><span style="color: green;">//</span><span style="color: green;"> Create Collision handler here, only player notifies the item
</span><span style="color: green;">//</span><span style="color: green;"> data can be NULL since we have class stored in Shape</span><span style="color: green;">
</span><span style="color: black;"> cpSpaceAddCollisionHandler(mpSpace, ITEM_COL_TYPE, PLAYER_COL_TYPE, SmashPcItem::PlayerCollision, NULL, NULL, NULL, NULL);
}
}</span></div>
</pre>
</div>
<script language="javascript" src="http://www.blogtrog.com/scripts/bt_code.js" type="text/javascript">
</script><script language="javascript" type="text/javascript">
bt_code_init('acb04d3a-3270-4654-82ce-567012b7cac5');
</script>
You see at the end, I create a callback to SmashPcItem::PlayerCollision() when an item of collision type PLAYER_COL_TYPE and ITEM_COL_TYPE collide. That callback does this:<br />
<div id='iframeDive81b7ab4-ffff-4cd8-a80c-3ac2a6abe7cb' style='display:none;margin:0px;'><iframe id='iframee81b7ab4-ffff-4cd8-a80c-3ac2a6abe7cb' src='http://www.blogtrog.com/code.aspx?id=e81b7ab4-ffff-4cd8-a80c-3ac2a6abe7cb' style='width: 800px; height: 200px; border: 1px solid #e0e0e0;margin:0px;' frameborder='0'></iframe></div><div id='noIframeDive81b7ab4-ffff-4cd8-a80c-3ac2a6abe7cb' style='display:block;margin:0px;'><pre><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #0000FF;">int</span><span style="color: #000000;"> SmashPcItem::PlayerCollision(cpArbiter </span><span style="color: #000000;">*</span><span style="color: #000000;">arb, </span><span style="color: #0000FF;">struct</span><span style="color: #000000;"> cpSpace </span><span style="color: #000000;">*</span><span style="color: #000000;">space, </span><span style="color: #0000FF;">void</span><span style="color: #000000;"> </span><span style="color: #000000;">*</span><span style="color: #000000;">data)
{
SmashPcItem </span><span style="color: #000000;">*</span><span style="color: #000000;">pItem;
SmashPcPlayer </span><span style="color: #000000;">*</span><span style="color: #000000;">pPlayer;
cpShape </span><span style="color: #000000;">*</span><span style="color: #000000;">pItemShape, </span><span style="color: #000000;">*</span><span style="color: #000000;">pPlayerShape;
cpArbiterGetShapes(arb, </span><span style="color: #000000;">&</span><span style="color: #000000;">pItemShape, </span><span style="color: #000000;">&</span><span style="color: #000000;">pPlayerShape);
pPlayer </span><span style="color: #000000;">=</span><span style="color: #000000;"> reinterpret_cast(pPlayerShape</span><span style="color: #000000;">-></span><span style="color: #000000;">data);
pItem </span><span style="color: #000000;">=</span><span style="color: #000000;"> reinterpret_cast(pItemShape</span><span style="color: #000000;">-></span><span style="color: #000000;">data);
</span><span style="color: #008000;">//</span><span style="color: #008000;"> We have the player that hit, and the item he hit</span><span style="color: #008000;">
</span><span style="color: #000000;"> pItem</span><span style="color: #000000;">-></span><span style="color: #000000;">NotifyHit(pPlayer);
}</span></div></pre></div><script language='javascript' src='http://www.blogtrog.com/scripts/bt_code.js' type='text/javascript'></script><script language='javascript' type='text/javascript'>bt_code_init('e81b7ab4-ffff-4cd8-a80c-3ac2a6abe7cb');</script>
<br />
Basically, it get the player and item objects that collided and notifies that item of being hit. Currently NotifyHit() doesn't do anything.<br />
<br />
Next time, I'm going to do a little re-design. I notice the classes SmashPcPlayer, SmashPcItem, and SmashPcBullet all have physicsal properties and can eb Drawn, which I should inherit from one class to stop from using the same code over and over.beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-4385613813476389732011-10-25T12:34:00.000-04:002011-10-25T12:34:48.806-04:00Added Bullet/Wall Collision...OK, I found a major no-no I was doing in my SmashPcBullet deconstructor; I wasn't removing and freeing the physics body/shape from the world. And, that was bad. So, I've fixed that.<br />
<br />
Get the code here:<br />
<a href="http://webpages.charter.net/wwjennings/SmashPC-10-25-11_2.zip">SmashPC 11-25-11_2 Collision</a><br />
<br />
Here's the fixed deconstructor:<br />
<pre class="brush: cpp">SmashPcBullet::~SmashPcBullet()
{
delete mpSprite;
if (mBulletDetails.pGlowImage)
{
delete mpGlowSprite;
}
cpSpaceRemoveBody(mpSpace, mpBody);
cpSpaceRemoveShape(mpSpace, mpShape);
cpBodyFree(mpBody);
cpShapeFree(mpShape);
}
</pre>
<br />
And, I added this line in the constructor to add a collision handler:<br />
<pre class="brush: cpp"> // Create Collision handler here, only wall notifies the bullet
// other handlers get notifed of hit by bullet
// data can be NULL since we have class stored in Shape
cpSpaceAddCollisionHandler(mpSpace, BULLET_COL_TYPE, WALL_COL_TYPE, SmashPcBullet::WallCollision, NULL, NULL, NULL, NULL);
</pre>
<br />
This call sets the function SmashPcBullet::WallCollision as the callback for collisions between type BULLET_COL_TYPE (which is all bullets) and WALL_COL_TYPE (all walls).
<br />
And, here's WallCollision (defined static in header file):
<br />
<pre class="brush: cpp">int SmashPcBullet::WallCollision(cpArbiter *arb, struct cpSpace *space, void *data)
{
SmashPcBullet *pBullet;
cpShape *pBulletShape, *pWallShape;
cpArbiterGetShapes(arb, &pBulletShape, &pWallShape);
printf("Callback!\n");
pBullet = reinterpret_cast<smashpcbullet*>(pBulletShape->data);
// Mark bullet for removal
pBullet->SetDead();
}
</smashpcbullet*></pre>
If you recall, in the SmashPcBullet constructor, we assign mpShape->data = this. So, in the callback, we can extract the Bullet class and set it to Dead, so it will be removed.<br />
<br />
Here's a in-game picture shooting bullets against the wall:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXFeTqV4EwaxuqW_zNajf6y2v7yqfxa-Vx-8JHXCXmHAcPqZsLGDqkhdo7Nia92tNudI57Zi14BovLlmaCGQbdOAEFMnk_AkUSb1GJMC5NVGoxCDUJu2RJGLfqUVkyKGE3P72jccxyIaI/s1600/WallCollision.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="248" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXFeTqV4EwaxuqW_zNajf6y2v7yqfxa-Vx-8JHXCXmHAcPqZsLGDqkhdo7Nia92tNudI57Zi14BovLlmaCGQbdOAEFMnk_AkUSb1GJMC5NVGoxCDUJu2RJGLfqUVkyKGE3P72jccxyIaI/s320/WallCollision.png" width="320" /></a></div>
<br />beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-46652650138924357332011-10-25T08:06:00.000-04:002011-10-28T00:28:16.373-04:00Bullets Added!Last time I promised Bullets and collision detection. Well, I'm providing 1/2 of that. I haven't put in the chipmunk-physics driven collision detection callbacks yet, but I did provide bullets. In doing so, I also now point the player towards the mouse, and fire the bullets in that direction. <br />
<br />
Download this version of code here:<br />
<a href="http://webpages.charter.net/wwjennings/SmashPC-10-25-11.zip">SmashPC 10-25-11 Code</a><br />
<br />
Right now the bullets pool in a corner until the TimeToLive expires, but you can see the Pysics engine doing it's work. Since the Bullets and Walls are in the same collision layer, they get stopped by the walls. Let's get to the code.<br />
<br />
First, here's my SmashPcWeapons.xml file which defines the weapons:<br />
<div id='iframeDiv36ddeaf0-b19d-46cf-a1b9-2a56fd063ba9' style='display:none;margin:0px;'><iframe id='iframe36ddeaf0-b19d-46cf-a1b9-2a56fd063ba9' src='http://www.blogtrog.com/code.aspx?id=36ddeaf0-b19d-46cf-a1b9-2a56fd063ba9' style='width: 500px; height: 200px; border: 1px solid #e0e0e0;margin:0px;' frameborder='0'></iframe></div><div id='noIframeDiv36ddeaf0-b19d-46cf-a1b9-2a56fd063ba9' style='display:block;margin:0px;'><pre><div><!--
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
--><span style="color: #0000FF;"><</span><span style="color: #800000;">smashpcweapons</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">peashooter</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">image</span><span style="color: #0000FF;">></span><span style="color: #000000;">Bullet.bmp</span><span style="color: #0000FF;"></</span><span style="color: #800000;">image</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">glowimage</span><span style="color: #0000FF;">></span><span style="color: #000000;">Bullet_glow.bmp</span><span style="color: #0000FF;"></</span><span style="color: #800000;">glowimage</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">velocity</span><span style="color: #0000FF;">></span><span style="color: #000000;">1000</span><span style="color: #0000FF;"></</span><span style="color: #800000;">velocity</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">damage</span><span style="color: #0000FF;">></span><span style="color: #000000;">10</span><span style="color: #0000FF;"></</span><span style="color: #800000;">damage</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">refire</span><span style="color: #0000FF;">></span><span style="color: #000000;">290</span><span style="color: #0000FF;"></</span><span style="color: #800000;">refire</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"><</span><span style="color: #800000;">timetolive</span><span style="color: #0000FF;">></span><span style="color: #000000;">3000</span><span style="color: #0000FF;"></</span><span style="color: #800000;">timetolive</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"></</span><span style="color: #800000;">peashooter</span><span style="color: #0000FF;">></span><span style="color: #000000;">
</span><span style="color: #0000FF;"></</span><span style="color: #800000;">smashpcweapons</span><span style="color: #0000FF;">></span></div></pre></div><script language='javascript' src='http://www.blogtrog.com/scripts/bt_code.js' type='text/javascript'></script><script language='javascript' type='text/javascript'>bt_code_init('36ddeaf0-b19d-46cf-a1b9-2a56fd063ba9');</script>
<br />
<br />
This only defines one weapon for now, the PeaShooter. The SmashPcWeapon class will read through that file and load all the available weapons and their attributes. We will be adding attributes as the weapons get mroe complex.<br />
<br />
Now, Let's look at SmashPcWeapon. This is designed to only be instanced once as we don't want to continually be reading off disk for the xml file. The constructor opens the xml and stores the details in a map:<br />
<pre class="brush: cpp">SmashPcWeapon::SmashPcWeapon(char *pcFilename, sf::RenderWindow *pApp,
cpSpace *pSpace) :
mu32LastFireTime(0),
mpApp(pApp),
mpSpace(pSpace)
{
SmashPcBullet::tBulletDetails Bullet;
TiXmlDocument doc(pcFilename);
// load and check if it was successful
if (doc.LoadFile())
{
// root is GravithonWeapons
TiXmlElement *root = doc.RootElement();
for(TiXmlElement* WeapElem = root->FirstChildElement(); WeapElem;
WeapElem = WeapElem->NextSiblingElement())
{
char cFile[64];
Bullet.u32TimeToLive = 0;
Bullet.pGlowImage = NULL;
// Assign the other pieces
Bullet.Speed =
atof(WeapElem->FirstChild("Velocity")->FirstChild()->Value());
Bullet.u32Damage =
atoi(WeapElem->FirstChild("Damage")->FirstChild()->Value());
Bullet.u32Refire =
atoi(WeapElem->FirstChild("Refire")->FirstChild()->Value());
// load the image
sprintf(cFile, "Gfx/%s",
WeapElem->FirstChild("Image")->FirstChild()->Value());
Bullet.pImage = Utilities::ImageGet(cFile);
// Check for optional values
if (WeapElem->FirstChild("TimeToLive"))
{
Bullet.u32TimeToLive =
atoi(WeapElem->FirstChild("TimeToLive")->FirstChild()->Value());
}
if (WeapElem->FirstChild("GlowImage"))
{
sprintf(cFile, "Gfx/%s",
WeapElem->FirstChild("GlowImage")->FirstChild()->Value());
Bullet.pGlowImage = Utilities::ImageGet(cFile);
}
// Store off in map
mBulletHash[WeapElem->ValueStr()] = Bullet;
}
}
else
{
printf("Failed to open %s\n", pcFilename);
}
// Set the 1st weapon as the default
mSelectedBullet = mBulletHash.begin()->first;
}
</pre>
<br />
The function SelectBullet simply sets which type of bullet the weapon will fire.<br />
<br />
The last function, FireBullet:<br />
<pre class="brush: cpp">SmashPcBullet *SmashPcWeapon::FireBullet(cpBody *pPlayerBody, BOOL bOurBullet)
{
SmashPcBullet *pBullet = NULL;
U32 u32Time = timeGetTime();
// Check if it's time to fire
if (mu32LastFireTime + mBulletHash[mSelectedBullet].u32Refire <= u32Time )
{
pBullet = new SmashPcBullet(mpApp, mBulletHash[mSelectedBullet],
pPlayerBody, mpSpace, bOurBullet);
// Play Sound (use name of bullet for sound)
GameSound::Play(mSelectedBullet, TRUE);
mu32LastFireTime = u32Time;
}
return pBullet;
}
</pre>
<br />
You can see we only fire when the refire rate is past, and we return a bullet. You'll see why we return a bullet in a sec.<br />
<br />
Next we'll take a look at SmashPcBullet class. Here's the constructor:<br />
<pre class="brush: cpp" name="code">SmashPcBullet::SmashPcBullet(sf::RenderWindow *pApp,
tBulletDetails &BulletDetails,
cpBody *pPlayerBody, cpSpace *pSpace,
BOOL bOurBullet) :
mpApp(pApp),
mBulletDetails(BulletDetails),
mpSpace(pSpace),
mbDead(FALSE)
{
// Set Time to Live to when it should die
if (mBulletDetails.u32TimeToLive)
{
mBulletDetails.u32TimeToLive = timeGetTime() + mBulletDetails.u32TimeToLive;
}
mpSprite = new sf::Sprite();
mpSprite->SetImage(*mBulletDetails.pImage);
mpSprite->SetOrigin(mBulletDetails.pImage->GetWidth()/2,
mBulletDetails.pImage->GetHeight()/2);
// Rotate sprite
mpSprite->SetRotation(pPlayerBody->a*(180.0f/PI));
if (mBulletDetails.pGlowImage)
{
mpGlowSprite = new sf::Sprite();
mpGlowSprite->SetImage(*mBulletDetails.pGlowImage);
mpGlowSprite->SetOrigin(mBulletDetails.pGlowImage->GetWidth()/2,
mBulletDetails.pGlowImage->GetHeight()/2);
// for glow, set to additive blend
mpGlowSprite->SetBlendMode(sf::Blend::Add);
// Rotate sprite
mpGlowSprite->SetRotation(pPlayerBody->a*(180.0f/PI));
}
mpBody = cpBodyNew(0.1f, 0.1f);
cpFloat Angle = pPlayerBody->a;
mpBody->p = pPlayerBody->p;
mpBody->v.x=cos( Angle)*mBulletDetails.Speed;
mpBody->v.y=sin( Angle)*mBulletDetails.Speed;
cpBodySetAngle(mpBody, Angle);
mpBody->w = 0.0f;
mpShape = cpCircleShapeNew(mpBody,
(mBulletDetails.pImage->GetWidth() + mBulletDetails.pImage->GetHeight())/4,
cpvzero);
mpShape->e = 0.0f; // not elatics, no bouncing
mpShape->u = 1.0f; // 0.0 is frictionless
mpShape->collision_type = BULLET_COL_TYPE;
mpShape->data = (void *)this;
if (bOurBullet)
{
mpShape->layers = BULLET_LAYER;
}
else
{
mpShape->layers = ENEMY_BULLET_LAYER;
}
cpSpaceAddBody(mpSpace, mpBody);
cpSpaceAddShape(mpSpace, mpShape);
// Create Collision handler here
}
</pre>
<br />
<br />
Here, we create the sprite based on the image, but we also create the "glow" sprite if a glow image is passed in. This will put a glow around the bullet image, which is a nice effect.<br />
<br />
Then, we create the physics body and shape. We assign the location the same as the player's body, and the same thing with the angle. We do a little trig to set the X and Y velocities based on the given Speed and Angle the player's facing.<br />
<br />
The layers is the collision layer. Only objects whos collision layer mask's overlapp will collide. So, we don't want our player to collide with is own bullets, so we want to make sure the player's layer doesn't over lap his own bullets.<br />
<br />
The other major function in SmashPcBullet is Draw:<br />
<pre class="brush: cpp">BOOL SmashPcBullet::Draw(cpVect PlayerLoc)
{
// Compute where on the screen the bullet should be drawn
cpFloat Bullx = (cpFloat)(mpApp->GetWidth()/2) + (mpBody->p.x - PlayerLoc.x);
cpFloat Bully = (cpFloat)(mpApp->GetHeight()/2) + (mpBody->p.y - PlayerLoc.y);
if (((Bullx > 0) && (Bullx < (cpFloat)mpApp->GetWidth())) &&
((Bully > 0) && (Bully < (cpFloat)mpApp->GetHeight())))
{
mpSprite->SetPosition(Bullx, Bully);
mpSprite->SetRotation(mpBody->a*(180.0f/PI));
if (mBulletDetails.u32TimeToLive)
{
if (timeGetTime() > mBulletDetails.u32TimeToLive)
{
// Mark bullet for deletion
mbDead = TRUE;
return TRUE;
}
}
mpApp->Draw(*mpSprite);
if (mBulletDetails.pGlowImage)
{
mpGlowSprite->SetPosition(Bullx, Bully);
mpGlowSprite->SetRotation(mpBody->a*(180.0f/PI));
mpGlowSprite->SetColor(sf::Color(255, 0, 0, 180));
mpApp->Draw(*mpGlowSprite);
}
}
return TRUE;
}
</pre>
<br />
We check the bullet's world location against the player location and we only draw the bullet if it's on the visible screen. And, if there's a glow image, we draw it, but with a Red tint, and partial alpha value.<br />
<br />
Now, in SmashPcPlayer::CheckInput(), when the Fire key is pressed, we just tell the weapon to fire. I've also added the code to position the player towards the mouse:<br />
<pre class="brush: cpp"> // Check for fire
if (Utilities::KeyIsDown(Input, GAME_KEY_FIRE))
{
pBullet = mpWeapon->FireBullet(mpBody, TRUE);
}
else if (Utilities::KeyIsDown(Input, GAME_KEY_SPECIAL_FIRE))
{
// Handle later
}
// Finally, find location of Mouse and point player towards it
cpFloat MouseX = (cpFloat)Input.GetMouseX();
cpFloat MouseY = (cpFloat)Input.GetMouseY();
cpFloat Angle = atan2(MouseY - (cpFloat)(mpApp->GetHeight()/2),
MouseX - (cpFloat)(mpApp->GetWidth()/2));
cpBodySetAngle(mpBody, Angle);
</pre>
<br />
<br />
Finally in the main loop, we have to keep track of the bullets, so we add them to a vector. We then draw every bullet in the vector. If a Bullet needs to be removed, we do that before drawing. Here's the added code:<br />
<pre class="brush: cpp"> SmashPcBullet *pBullet;
std::vector<smashpcbullet*> BulletList;
.
.
.
pBullet = pOurPlayer->CheckInput();
if (pBullet)
{
BulletList.push_back(pBullet);
}
.
.
.
// Check for bullet removal, else Draw all the Bullets
for (std::vector<smashpcbullet*>::iterator it = BulletList.begin();
it != BulletList.end(); )
{
if ((*it)->IsDead())
{
delete *it;
it = BulletList.erase(it);
if (it == BulletList.end())
{
break;
}
continue;
}
else
{
(*it)->Draw(pOurPlayer->GetBody()->p);
}
it++;
}
</smashpcbullet*></smashpcbullet*></pre>
<br />
Next time I'll add Collisions, I (almost) promise!beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-51623862294362851852011-10-23T23:12:00.001-04:002011-10-24T13:32:04.275-04:00Adding 2d Physics EngineFor this update, I started adding the 2d physics engine, Chipmunk Physics. As mentioned earlier, the 2d physics engine does so much work for a 2d programmer. It performs all the movement and collision detection for every object in the game. This update just adds some walls, and handles moving the player through the 2d physics world.<br />
I also added a new class, SmashPcMap, which handles the loading and drawing the level.<br />
<br />
You can get the source code here:<br />
<a href="http://webpages.charter.net/wwjennings/SmashPc-10-23-11.zip">SmashPc 11-23 code</a><br />
<br />
First, in SmashPc.cpp, main(), here's the new function:<br />
<br />
<pre class="brush: cpp">int main(int argc, char *argv[])
{
sf::Event Event;
BOOL bFullScreen;
GameSound::Init("SmashPcSounds.xml");
Utilities::LoadConfig("SmashPcCfg.xml");
Utilities::ScreenResolutionGet(gu32ScreenX, gu32ScreenY, bFullScreen);
sf::RenderWindow App(sf::VideoMode(gu32ScreenX, gu32ScreenY, 32), "SmashPC", (bFullScreen ? sf::Style::Fullscreen : sf::Style::Default));
cpInitChipmunk();
gpMap = new SmashPcMap("", gu32ScreenX, gu32ScreenY, &App);
// Create location; Typically, use location from level, but fake for now
gpOurPlayer = new SmashPcPlayer(&App, gpMap->GetSpace(), cpv(200, 200));
srand(time(NULL));
App.ShowMouseCursor(true);
App.SetCursorPosition(gu32ScreenX/2, gu32ScreenX/2);
App.SetFramerateLimit(60);
// main game loop
while (App.IsOpened())
{
while (App.PollEvent(Event))
{
// Window closed
if (Event.Type == sf::Event::Closed)
{
App.Close();
GameSound::Shutdown();
}
// Escape key pressed
if (Event.Type == sf::Event::KeyPressed)
{
if (Event.Key.Code == sf::Key::Escape)
{
App.Close();
GameSound::Shutdown();
}
}
}
gpOurPlayer->CheckInput();
cpSpaceStep(gpMap->GetSpace(), 1.0f/60.0f);
/* clear screen and draw map */
App.Clear();
gpMap->Draw(gpOurPlayer->GetBody());
gpOurPlayer->Draw();
App.Display();
}
return 0;
}</pre>
You see we added the call to cpInitChipmunk(), which kicks off the physics engine.<br />
Later we call cpSpaceStep(). This function simulates all the objects defined in the space at a speed of 60 frames per second.<br />
We also call create an instance of SmashPcMap(), which will create the physics space, loads the level, and draws it. Currently, we're not loading levels yet, so we just pass it an empty level.<br />
<br />
In SmashPcMap, we create and init the space:<br />
<pre class="brush: cpp"> mpSpace = cpSpaceNew();
cpSpaceInit(mpSpace);
mpSpace->iterations = 10;</pre>
<br />
And, In CreateSpace() we create fake walls that just surrounds the world:<br />
<pre class="brush: cpp"> // use static body and add this wall shape
pShape = cpSpaceAddShape(mpSpace, cpPolyShapeNew(&mpSpace->staticBody, 4, Verts, cpvzero));
pShape->e = 0.9f;
pShape->u = 0.3f;
pShape->collision_type = WALL_COL_TYPE;
pShape->data = this;</pre>
<br />
Looking in SmashPcPlayer, We added the starting world location of the player and the physics space to the constructor. Here is is:<br />
<br />
<pre class="brush: cpp">SmashPcPlayer::SmashPcPlayer(sf::RenderWindow *pApp, cpSpace *pSpace,
cpVect Location) :
mpApp(pApp),
mpSpace(pSpace),
mu32Health(100),
mu32Armor(0),
mu32LastFire(0),
mu32LastSpecialFire(0)
{
// Load the temp image for this player
mpImage = Utilities::ImageGet("Gfx/Player.bmp");
mpSprite = new sf::Sprite();
mpSprite->SetImage(*mpImage);
mpSprite->SetOrigin(mpImage->GetWidth()/2, mpImage->GetHeight()/2);
// Set to middle of screen
mpSprite->SetPosition(pApp->GetWidth()/2, pApp->GetHeight()/2);
mpBody = cpBodyNew(1.0f, 1.0f);
cpBodySetPos(mpBody, Location);
mpBody->v = cpvzero;
mpBody->v_limit = PLAYER_SPEED;
cpBodySetAngle(mpBody, PI/2.0f);
mpBody->w = 0.0f;
mpShape = cpCircleShapeNew(mpBody, mpImage->GetWidth()/2, cpvzero);
mpShape->e = 0.0f; // not elatics, no bouncing
mpShape->u = 1.0f; // 0.0 is frictionless
mpShape->collision_type = PLAYER_COL_TYPE;
mpShape->data = (void *)this;
mpShape->layers = PLAYER_LAYER;
cpSpaceAddBody(mpSpace, mpBody);
cpSpaceAddShape(mpSpace, mpShape);
// Create Collision handler here
// Sound notifying a player has spawned
GameSound::Play("PlayerSpawn");
}</pre>
<br />
You can see the code that creates the player's body and shape in the physics space (world). The body is basically for collisions and holds the velocity, force, and position, and it's connected to the shape which defines the bodies we...shape. We use circle for player.<br />
<br />
For Draw(), we're just drawing the player in the middle of the screen, and moving the world around him.<br />
<br />
CheckInput() has been modified and it probably needs some explanation. Here it is:<br />
<pre class="brush: cpp">void SmashPcPlayer::CheckInput(void)
{
const sf::Input& Input = mpApp->GetInput();
cpFloat xForce = 0, yForce = 0;
cpVect Vel;
U32 u32Time = timeGetTime();
// Set all forces to 0
mpBody->f = cpvzero;
Vel = cpBodyGetVel(mpBody);
// We'll just assign velocities to a hardcoded value for now
if (Utilities::KeyIsDown(Input, GAME_KEY_LEFT))
{
xForce -= PLAYER_FORCE;
}
else if (Vel.x < 0.01f)
{
mpBody->v.x = 0;
}
if (Utilities::KeyIsDown(Input, GAME_KEY_RIGHT))
{
xForce += PLAYER_FORCE;
}
else if (Vel.x > 0.01f)
{
mpBody->v.x = 0;
}
if (Utilities::KeyIsDown(Input, GAME_KEY_DOWN))
{
yForce += PLAYER_FORCE;
}
else if (Vel.y > 0.01f)
{
mpBody->v.y = 0;
}
if (Utilities::KeyIsDown(Input, GAME_KEY_UP))
{
yForce -= PLAYER_FORCE;
}
else if (Vel.y < 0.01f)
{
mpBody->v.y = 0;
}
mpBody->f = cpv(xForce, yForce);
// Check for fire
if (Utilities::KeyIsDown(Input, GAME_KEY_FIRE))
{
// we'll fake a re-fire speed check, 400 mS
if (mu32LastFire + 400 <= u32Time )
{
// Play Fake Sound, repeat
GameSound::Play("PeaShooter", TRUE);
mu32LastFire = u32Time;
}
}
}</pre>
<br />
First, a mention about moving things around in a physics engine. Typically, in games, you just give something a velocity, and say go. Well, that kind of work in physics engines, but problems occur when you have collisions. If you constantly give an object a velocity, and it's colliding with an object, the physics engine will keep moving it that way, whether it's collided with something or not.<br />
<br />
So, to "fake" it, we 1st give a v_limit to the body, (see the Constructor). This is the maximum velocity the body can have. Then when we want the player to move a direction, we just give it a massive force in the direction it's moving. If it's too low, the body will accelerate to the velocity we want, but for this game, we want full speed or no speed.<br />
<br />
Also, we have to add some code where we actually set the velocity to 0; otherwise, if we're moving right, and let up on the left key, the player will continue to move right until friction stops it.<br />
<br />
Next time we'll add bullets to the system, and how to handle collisions.<br />
<br />
Till then!<br />
<br />
Edit 11-24-11:<br />
I forgot to mention the other change in SmashPcMap, how it draws. Here is thespecific code:<br />
<pre class="brush: cpp">BOOL SmashPcMap::Draw(cpBody *PlayerBody)
{
cpFloat LeftX = PlayerBody->p.x - mu32ScreenWidth/2;
cpFloat TopY = PlayerBody->p.y - mu32ScreenHeight/2;
// Soon we will draw all items loaded from the level
// but, now it's only the fake walls, so draw them
// fake corners removed...
for (int i = 0; i < 4; i++)
{
cpVect Verts[4] = // ... removed from snippet
sf::Shape oShape;
oShape = sf::Shape::Rectangle (Verts[0].x - LeftX, Verts[0].y - TopY,
Verts[2].x - Verts[0].x, Verts[2].y - Verts[0].y,
sf::Color(128, 128, 128, 255));
mpApp->Draw(oShape);
}
return TRUE;
}
</pre>
<br />
We now pass in the player's body so we can get the location of him within the physics world. We then draw the rest of the world around the player (since we want to keep the player in the middle of the screen and scroll the rest of the world around him). That's why it is all based on LeftX and Top Y of the player (again, in world coordinates).beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-45467149606926075862011-10-23T10:02:00.000-04:002011-10-26T21:19:21.503-04:00SmashPC is Started!So, I've decided specifically what type of game I'll be making. It'll be a top-down Alien Swarm type game (for those old guys, think SmashTV). In fact, I've named it SmashPC.<br />
<br />
What I've done for this initial code drop is implement the basics as far as SFML window, simple sprite drawing, playing Sounds, and Input and input configuration. <br />
<br />
You can get the full source code and project here:<br />
(Link Removed, get newer version)<br />
<br />
First, we need to create a project. So, using Code::Blocks, I made a project, and pointed at all the libraries I would need.<br />
<br />
Here's my settings for the Compiler and Linker:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAH7-02fSn192f3iFXPgLlUmgi1q0NBI-v1vx9zMFqZe_LHjg9D_384NcYDscwM7jcnF4EY0-HM0jcCuirwmvJ_jyULGJq16tLvzDIjWMXU0bl8DcGLHj5yW-W58s2xXfjju3I23RUODA/s1600/SearchDirCompiler.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAH7-02fSn192f3iFXPgLlUmgi1q0NBI-v1vx9zMFqZe_LHjg9D_384NcYDscwM7jcnF4EY0-HM0jcCuirwmvJ_jyULGJq16tLvzDIjWMXU0bl8DcGLHj5yW-W58s2xXfjju3I23RUODA/s320/SearchDirCompiler.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe9TC9YXaG4oTmTc3s_JJIM-hlyVllokmahuclEW2kMAyvpkZXhtKti5wN_8CDZ_jCUAYWBHIgdCcweg6FYxLo78UyochplCtYkSG78AnAGyWKoWNJES-gxtKED2OczHjZQmLKXAAOv5E/s1600/SearchDirLinker.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhe9TC9YXaG4oTmTc3s_JJIM-hlyVllokmahuclEW2kMAyvpkZXhtKti5wN_8CDZ_jCUAYWBHIgdCcweg6FYxLo78UyochplCtYkSG78AnAGyWKoWNJES-gxtKED2OczHjZQmLKXAAOv5E/s320/SearchDirLinker.png" width="320" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLeJ9uSxZ7Hd4XtiHeZXrGBOQ8yycoghyphenhyphen7_n18YCQXthc43JA2tHzL8haiNpIzo_1wl9yhO-ZBTCJKTGcSVik-z9A96IUcUIX7xjPuso9vuc8WPNAzLuHl_LDy_WATaB_1bOL95AG2DD0/s1600/LinkerSetting.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="236" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLeJ9uSxZ7Hd4XtiHeZXrGBOQ8yycoghyphenhyphen7_n18YCQXthc43JA2tHzL8haiNpIzo_1wl9yhO-ZBTCJKTGcSVik-z9A96IUcUIX7xjPuso9vuc8WPNAzLuHl_LDy_WATaB_1bOL95AG2DD0/s320/LinkerSetting.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
(Check out the links for sfml, tinyxml, and chipmunk-physics in the 1st blog entry to get those libraries. I use sfml2.0, but 1.6 should work fine).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next, I add the main source code (in SmashPc.cpp), and a simple main loop. Here's what I have so far:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: cpp">int main(int argc, char *argv[])
{
sf::Event Event;
BOOL bFullScreen;
GameSound::Init("SmashPcSounds.xml");
Utilities::LoadConfig("SmashPcCfg.xml");
Utilities::ScreenResolutionGet(gu32GravScreenX, gu32GravScreenY, bFullScreen);
sf::RenderWindow App(sf::VideoMode(gu32GravScreenX, gu32GravScreenY, 32), "SmashPC", (bFullScreen ? sf::Style::Fullscreen : sf::Style::Default));
gpOurPlayer = new SmashPcPlayer(&App);
srand(time(NULL));
App.ShowMouseCursor(true);
App.SetCursorPosition(gu32GravScreenX/2, gu32GravScreenX/2);
// main game loop
while (App.IsOpened())
{
float FrameTime;
const sf::Input& Input = App.GetInput();
while (App.PollEvent(Event))
{
// Window closed
if (Event.Type == sf::Event::Closed)
{
App.Close();
GameSound::Shutdown();
}
// Escape key pressed
if (Event.Type == sf::Event::KeyPressed)
{
if (Event.Key.Code == sf::Key::Escape)
{
App.Close();
GameSound::Shutdown();
}
}
}
gpOurPlayer->CheckInput();
FrameTime = App.GetFrameTime();
if (FrameTime > 1/60.0f)
{
//printf("Frametime %f expected %f\n", FrameTime, 1/60.0f);
}
else
{
Sleep((U32)((1/60.0f - FrameTime)*1000.0f));
FrameTime = 1/60.0f;
}
/* clear screen and draw map */
App.Clear();
gpOurPlayer->Draw();
App.Display();
}
return 0;
}
</pre>
<br />
<div class="separator" style="clear: both; text-align: left;">
You see some simple SFML setup, but we're also calling the functions <span class="Apple-style-span" style="font-family: monospace; white-space: pre;">GameSound::Init() and </span><span class="Apple-style-span" style="font-family: monospace; white-space: pre;">Utilities::LoadConfig(). </span> </div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Gamesound::Init loads the sounds stored in SmashPcSounds.xml. Here's that function:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: cpp">void GameSound::Init(char *pcFilename)
{
if (bNeedsInit)
{
TiXmlDocument doc(pcFilename);
// load and check if it was successful
if (doc.LoadFile())
{
TiXmlElement *root = doc.RootElement();
for(TiXmlElement* example = root->FirstChildElement(); example;
example = example->NextSiblingElement())
{
char cFile[32];
std::string SoundStr = example->ValueStr();
printf("Found SoundName %s .. ", SoundStr.c_str());
SoundMap[SoundStr] = new sf::SoundBuffer();
sprintf(cFile, "Sfx/%s", example->GetText());
if (!SoundMap[SoundStr]->LoadFromFile(cFile))
{
printf("Failed loading sound %s!\n", cFile);
}
}
}
else
{
printf("Failed opening GravithonSounds.xml\n");
}
bNeedsInit = FALSE;
}
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
This is using tinyxml to parse the xml file, and it uses std::map to associated a string to a sfml sound buffer. This way, you play a sound you'd just pass in the string to play, like GameSound::Play("PeaShooter");</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The next piece you saw was the call to Utilities::LoadConfig(). This function loads the SmashPcCfg.xml file and setups the users prefrences with respect to controls, mouse sensitivty, and screen resolution. Take a look at the Utilities.cpp and.h for more info on how it does that.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Finally, there's SmashPcPlayer class. Here's the constructor:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="brush: cpp">SmashPcPlayer::SmashPcPlayer(sf::RenderWindow *pApp) :
mpApp(pApp),
mu32Health(100),
mu32Armor(0),
mu32LastFire(0),
mu32LastSpecialFire(0)
{
// Load the temp image for this player
mpImage = Utilities::ImageGet("Gfx/Player.bmp");
mpSprite = new sf::Sprite();
mpSprite->SetImage(*mpImage);
mpSprite->SetOrigin(mpImage->GetWidth()/2, mpImage->GetHeight()/2);
// Set to middle of screen
mpSprite->SetPosition(pApp->GetWidth()/2, pApp->GetHeight()/2);
// Sound notifying a player has spawned
GameSound::Play("PlayerSpawn");
}
</pre>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
We make a call to load the image (we use the Utilities function since we want to make sure we won't load the image more than once), and create a sprite from the image, set the sprite to the middle of the screen, and play a sound, noting the player has spawned in the world.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
The SmashPcPlayer->Draw () currently just draws the sprite where the payer is.</div>
<div class="separator" style="clear: both; text-align: left;">
And, SmashPcPlayer->CheckInput() simply moves the player around and plays a gunshot sound when you press the Fire button (configured as left mouse button).</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Next time we'll add in chipmunk-physics 2d engine to handle all the big work for us as far as movement and collision detection.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0tag:blogger.com,1999:blog-8221004988101681938.post-88486813133369210192011-10-18T22:45:00.000-04:002011-10-18T22:45:49.152-04:00Welcome!Hi whomever is reading this. So, I've been thinking of sharing the knowledge I've gain over the years, and some of the recently knowledge I've recently gained that has made making 2d games SO EASY. My plan is to make a top-down 2d game, and post updates to this blog as I go.<br />
<br />
I would add the critical elements that go into making the game, as well as a running copy of the source code.<br />
<br />
Yes, I typically have big ideas, and they fizzle out, but I hope that's not the case here as I feel I can add alot.<br />
<br />
The plan is to use C++ (using Code::Blocks IDE) and use these API's/SDK's to help me get there:<br />
<a href="http://www.sfml-dev.org/">SFML</a> : This is the multimedia API, and I really love it. Easy to use, powerful (Graphics sits on top of OpenGL, for great HW accelration, Audio is on OpenAL, to provide lots of utililty)<br />
<a href="http://chipmunk-physics.net/">chipmunk-physics</a> : This is the 2d physics engine I will use. It makes representing objects in a 2d world very easy, and does most of the hard work for me.<br />
<a href="http://www.grinninglizard.com/tinyxml/">tinyxml</a> : TinyXML will do the XML parsing for me. I use xml for real-time modification of different components of the game, including the levels.<br />
<a href="http://gleed2d.codeplex.com/">gleed2d</a> : Gleed2d is a free-form level -editor (ie, not tied to tiles), and stores levels in XML. I have found it's very flexible and provides the level editor for me.<br />
<br />
So, follow along, and let's see where we go!beernuttshttp://www.blogger.com/profile/16086971442417391063noreply@blogger.com0