fork download
  1. using System;
  2. using System.Collections.Generic;
  3. using Microsoft.Xna.Framework;
  4. using Microsoft.Xna.Framework.Audio;
  5. using Microsoft.Xna.Framework.Content;
  6. using Microsoft.Xna.Framework.GamerServices;
  7. using Microsoft.Xna.Framework.Graphics;
  8. using Microsoft.Xna.Framework.Input;
  9. using Microsoft.Xna.Framework.Media;
  10. using System.Runtime.InteropServices;
  11.  
  12. public class User32
  13. {
  14. [DllImport("user32.dll")]
  15. public static extern void SetWindowPos(uint hwnd, uint level, int x, int y, int w, int h, uint flags);
  16. }
  17. namespace trial2
  18. {
  19. class Entity
  20. {
  21. public static Texture2D tex;
  22. public float x, y;
  23. public float w, h;
  24. public Color color = Color.White;
  25.  
  26. public static Color baseColor = new Color( 1, 0, 0, 0.2f );
  27.  
  28. public static void init( GraphicsDevice gpu, int width, int height )
  29. {
  30. Color[] blockColors = new Color[ width * height ];
  31.  
  32. for( int i = 0 ; i < width * height ; i++ ) blockColors[ i ] = Color.AliceBlue;
  33.  
  34. tex = new Texture2D( gpu, width, height );
  35. tex.SetData<Color>( blockColors );
  36. }
  37.  
  38. public float Left
  39. {
  40. get { return x; }
  41. set { x = value; }
  42. }
  43. public float Right
  44. {
  45. get { return x+w; }
  46. set { x = value - w ; }
  47. }
  48. public float Top
  49. {
  50. get { return y ; }
  51. set { y = value ; }
  52. }
  53. public float Bottom
  54. {
  55. get { return y + h; }
  56. set { y = value - h ; }
  57. }
  58.  
  59. public Rectangle getRect()
  60. {
  61. return new Rectangle((int)x,(int)y,(int)w,(int)h);
  62. }
  63.  
  64. /// <summary>Its only intersecting if there is overlap in BOTH x and y.</summary>
  65. public bool intersects( Entity o )
  66. {
  67. return ( ( this.hitsBottomOf(o) || this.hitsTopOf(o) ) && ( this.hitsLeftOf(o) || this.hitsRightOf(o) ) );
  68. }
  69.  
  70. // get overlap.
  71. // -y = this ON o's TOP edge (needs to move -y: down)
  72. // +y = this ON o's BOTTOM edge (needs to move +y: up)
  73. // -x = this ON o's RIGHT (needs to move -x: to the left)
  74. // +x = this ON o's LEFT (needs to move +x: to the right)
  75.  
  76. public bool hitsTopOf( Entity o )
  77. {
  78. // +----------> +x
  79. // | ______
  80. // | |this|
  81. // | |____|_
  82. // | || o |
  83. // | | |
  84. // | |____|
  85. // v
  86. // +y
  87. // 1. this hits o from the top
  88. return ( this.Bottom <= o.Bottom && // this is above o and
  89. this.Bottom > o.Top ) ; // this's Bottom below o's Top
  90. }
  91.  
  92. public bool hitsBottomOf( Entity o )
  93. {
  94. // 2. this's head hit a ceiling tile o
  95. // ______
  96. // | o |
  97. // |____|_
  98. // ||this|
  99. // | |
  100. // |____|
  101. return ( this.Top >= o.Top && // this is below o and
  102. this.Top < o.Bottom ) ;// this's top has entered bottom of o
  103. }
  104.  
  105. public bool hitsLeftOf( Entity o )
  106. {
  107. // x
  108. // 3.
  109. // ______
  110. // __|_o_ |
  111. // |this| |
  112. // | |_|
  113. // |____|
  114. return ( this.Left <= o.Left && // this approaches from left and
  115. this.Right > o.Left ) ; // this's right is stepping on o's left OR
  116. }
  117.  
  118. public bool hitsRightOf( Entity o )
  119. {
  120. // 4.
  121. // ______
  122. // __|this|
  123. // | o | |
  124. // | |_|
  125. // |____|
  126. return ( this.Right >= o.Right && // this approaches from right and
  127. this.Left < o.Right ) ; // this's left is stepping into o's right
  128. }
  129.  
  130. public void pushOffX( Entity o )
  131. {
  132. // 3.
  133. // ______
  134. // __|_o_ |
  135. // |this| |
  136. // | |_|
  137. // |____|
  138. if( this.hitsLeftOf( o ) )
  139. this.x -= ( this.Right - o.Left ) ;
  140.  
  141. // 4.
  142. // ______
  143. // __|this|
  144. // | o | |
  145. // | |_|
  146. // |____|
  147. else if( this.hitsRightOf( o ) )
  148. this.x += o.Right - this.Left ;
  149. }
  150. public void pushOffY( Entity o )
  151. {
  152. // +----------> +x
  153. // | ______
  154. // | |this|
  155. // | |____|_
  156. // | || o |
  157. // | | |
  158. // | |____|
  159. // v
  160. // +y
  161. // 1. this hits o from the top
  162. if( this.hitsTopOf( o ) ) // 1. this hit floor o with his feet
  163. this.y -= this.Bottom - o.Top ; // -y value
  164.  
  165. // 2. this's head hit a ceiling tile o
  166. // ______
  167. // | o |
  168. // |____|_
  169. // ||this|
  170. // | |
  171. // |____|
  172. if( this.hitsBottomOf( o ) )
  173. this.y += o.Bottom - this.Top ;
  174. }
  175.  
  176.  
  177. /// <summary>Mag px overlap, x</summary>
  178. /// <param name="o"></param>
  179. /// <returns></returns>
  180. public float XOverlap( Entity o )
  181. {
  182. // for this to "count",
  183. // you must overlap in Y
  184. if( this.hitsTopOf( o ) || this.hitsBottomOf( o ) )
  185. {
  186. // 3.
  187. // ______
  188. // __|_o_ |
  189. // |this| |
  190. // | |_|
  191. // |____|
  192. if( this.hitsLeftOf( o ) ) // 3. t1 is bumping into t2 to the right
  193. //return o.Left - this.Right; // -x, b/c this needs move left
  194. return this.Right - o.Left ; // abs(x)
  195.  
  196. // 4.
  197. // ______
  198. // __|this|
  199. // | o | |
  200. // | |_|
  201. // |____|
  202. else if( this.hitsRightOf( o ) ) // 4. t1 hitting t2 to the left
  203. return o.Right - this.Left; // +x
  204. else
  205. return 0 ;
  206. }
  207. else
  208. return 0;
  209. }
  210.  
  211.  
  212. /// <summary>Magnitude of pixel overlap in y</summary>
  213. public float YOverlap( Entity o )
  214. {
  215. if( this.hitsLeftOf( o ) || this.hitsRightOf( o ) )
  216. {
  217. // +----------> +x
  218. // | ______
  219. // | |this|
  220. // | |____|_
  221. // | || o |
  222. // | | |
  223. // | |____|
  224. // v
  225. // +y
  226. // 1. this hits o from the top
  227. if( this.hitsTopOf( o ) ) // 1. this hit floor o with his feet
  228. //return o.Top - this.Bottom ; // -y value
  229. return this.Bottom - o.Top ; // abs(y)
  230.  
  231. // 2. this's head hit a ceiling tile o
  232. // ______
  233. // | o |
  234. // |____|_
  235. // ||this|
  236. // | |
  237. // |____|
  238. else if( this.hitsBottomOf( o ) ) // 2. this's head hit a ceiling tile o
  239. return o.Bottom - this.Top ; // player move down +y
  240.  
  241. else
  242. return 0 ;
  243. }
  244. else
  245. return 0 ;
  246. }
  247.  
  248. }
  249.  
  250.  
  251. class Player : Entity
  252. {
  253. public float sp = 5 ;
  254. public float vx,vy;
  255. public bool groundContact;
  256.  
  257. public static double JUMP_JUICE = .3;
  258. public double jumpJuiceRem = 0;
  259.  
  260. double expFactor = 1.0; /// how strong gravity is. make large for stronger gravity
  261.  
  262. public Player( int width, int height )
  263. {
  264. w=width; h=height;
  265. x = y = w;
  266. vx=vy=0;
  267. color = new Color( 0, 1, 0, 0.2f );
  268. }
  269.  
  270. public void doJump()
  271. {
  272. if( groundContact ) // if on ground
  273. {
  274. jumpJuiceRem = Player.JUMP_JUICE;
  275. groundContact = false;
  276. }
  277. }
  278.  
  279. public void computeVel( GameTime gt )
  280. {
  281. vx=vy=0;
  282.  
  283. // Set his velocity
  284. if( jumpJuiceRem > 0 ) // jump juice left
  285. {
  286. // he's jumping
  287. // 5 - 5 = 0 (at start)
  288. // 5 - 0 = 5 (at end)
  289. double jumpDist = 22.5 * Math.Exp( -expFactor * ( JUMP_JUICE - jumpJuiceRem ) );
  290. vy -= ( float )jumpDist;
  291.  
  292. // spend his jump juice by time
  293. jumpJuiceRem -= gt.ElapsedGameTime.TotalSeconds;
  294. }
  295.  
  296. vy += sp ; // everything falls at a constant rate
  297. }
  298.  
  299.  
  300. public void move()
  301. {
  302. x+=vx; y+=vy;
  303. }
  304.  
  305. }
  306.  
  307. class Tile : Entity
  308. {
  309. public Tile( int width, int height )
  310. {
  311. w=width; h=height;
  312. color = baseColor;
  313. }
  314. }
  315.  
  316. public class CollisionDemo2 : Microsoft.Xna.Framework.Game
  317. {
  318. GraphicsDevice gpu;
  319. GraphicsDeviceManager graphics;
  320. SpriteBatch sb;
  321. //SpriteFont sf;
  322.  
  323. Player p;
  324. Tile movingTile;
  325. List<Tile> tiles;
  326.  
  327. public CollisionDemo2()
  328. {
  329. graphics = new GraphicsDeviceManager( this );
  330. Content.RootDirectory = "Content";
  331. }
  332.  
  333. protected override void Initialize()
  334. {
  335. base.Initialize();
  336. }
  337.  
  338. private void wallTest()
  339. {
  340. //Console.WriteLine( "move" ) ;
  341. p.move() ;
  342.  
  343. p.groundContact = false ;
  344.  
  345. List<Tile> intns = new List<Tile>();
  346.  
  347. foreach( Tile t in tiles )
  348. {
  349. t.color = Entity.baseColor; // reset
  350.  
  351. if( p.intersects( t ) )
  352. {
  353. t.color = Color.Red ;
  354. intns.Add( t ) ;
  355. }
  356. }
  357.  
  358. // categorize intersections:
  359. List<Tile> groundTiles = new List<Tile>() ;
  360. List<Tile> ceilingTiles = new List<Tile>() ;
  361. foreach( Tile t in intns )
  362. {
  363. if( p.hitsTopOf( t ) )
  364. {
  365. // does this count as grounding?
  366. // define grounding as 1/4 tile width
  367. if( p.XOverlap( t ) > t.w / 4 )
  368. {
  369. //Console.WriteLine( "p grounded" ) ;
  370. p.groundContact =true ;
  371. t.color = Color.Black ;
  372. groundTiles.Add( t ) ;
  373. }
  374. }
  375.  
  376. // Do the same thing for ceiling tiles
  377. if( p.hitsBottomOf( t ) )
  378. {
  379. if( p.XOverlap( t ) > t.w / 4 )
  380. {
  381. //Console.WriteLine( "OW MY HEAD!" ) ;
  382. t.color = Color.Plum ;
  383. ceilingTiles.Add( t ) ;
  384. p.jumpJuiceRem = 0 ; // kill jump
  385. }
  386. }
  387. }
  388.  
  389. // push off the ceiling and remove those tiles
  390. // from the main collection
  391. // 1 RESOLVE CEILING BUMPS (and remove these tiles from further consideration)
  392. foreach( Tile t in ceilingTiles )
  393. {
  394. if( p.intersects( t ) ) // check this again since player will be moving between iterations
  395. p.pushOffY( t ) ;
  396.  
  397. intns.Remove( t ) ; // remove it from the main collection once we push off it
  398. }
  399.  
  400. // 2 RESOLVE MID-AIR WALL COLLISIONS
  401. if( !p.groundContact ) // then push x off first
  402. {
  403. //sb.DrawString( sf, "Flying", new Vector2( 0, 20 ), Color.Red ) ;
  404.  
  405. // now that's done, we can push off x
  406. foreach( Tile t in intns )
  407. {
  408. if( p.intersects( t ) )
  409. if( p.hitsLeftOf( t ) || p.hitsRightOf( t ) )
  410. {
  411. //Console.WriteLine( "Push t side " + p.XOverlap( t ) );
  412. t.color = Color.Olive;
  413. p.pushOffX( t );
  414. }
  415. }
  416. }
  417.  
  418. // 3 RESOLVE SINK-INTO-GROUND COLLISIONS
  419. else
  420. {
  421. // push off y
  422. foreach( Tile t in groundTiles )
  423. {
  424. if( p.intersects( t ) )
  425. {
  426. if( p.hitsTopOf( t ) )
  427. {
  428. //Console.WriteLine( "Push t bottom " + p.YOverlap( t ) );
  429. p.pushOffY( t ) ;
  430. intns.Remove( t ) ;
  431. }
  432. }
  433. }
  434. }
  435.  
  436. // now for the rest of the tiles we intersected with
  437. // that were neither ground nor ceiling tiles
  438. // 4 RESOLVE ALL OTHER COLLISIONS (GROUNDED-WALL COLLISIONS)
  439. foreach( Tile t in intns )
  440. {
  441. if( p.intersects( t ) )
  442. if( p.hitsRightOf( t ) || p.hitsLeftOf( t ) )
  443. {
  444. //Console.WriteLine( "Push t side#2: " + p.XOverlap( t ) );
  445. t.color = Color.Aqua ;
  446. p.pushOffX( t ) ;
  447. }
  448. }
  449. }
  450.  
  451. protected override void LoadContent()
  452. {
  453. gpu = GraphicsDevice;
  454. sb = new SpriteBatch( GraphicsDevice );
  455. //sf = Content.Load<SpriteFont>( "SpriteFont1" ) ;
  456.  
  457. //User32.SetWindowPos( (uint)Window.Handle, 0, 0, 0, 800, 600, 1 ) ;
  458.  
  459. int s = 40;
  460. Entity.init( gpu, s, s );
  461.  
  462. p = new Player( s, s );
  463.  
  464. // the world is an array of Tiles
  465. int w = gpu.Viewport.Width;
  466. int h = gpu.Viewport.Height;
  467.  
  468. int tw = w / s;
  469. int th = h / 2 / s;
  470. tiles = new List<Tile>();
  471. Tile t;
  472. for( int row = 0 ; row < h / 2 ; row += s )
  473. {
  474. for( int col = 0 ; col < w ; col += s )
  475. {
  476. t = new Tile( s, s );
  477.  
  478. t.Top = gpu.Viewport.Height - row;
  479. t.Left = col;
  480.  
  481. tiles.Add( t );
  482. }
  483. }
  484.  
  485. // make a wall
  486. for( int row = h / 2 ; row < gpu.Viewport.Height ; row += s )
  487. {
  488. t = new Tile( s, s );
  489.  
  490. t.Top = gpu.Viewport.Height - row;
  491. t.Left = 6 * s;
  492.  
  493. tiles.Add( t );
  494. }
  495.  
  496. Random r = new Random();
  497. // some random tiles
  498. for( int i = 0 ; i < 10 ; i++ )
  499. {
  500. t = new Tile( s, s );
  501.  
  502. t.Top = ( float )( s * th * r.NextDouble() );
  503. t.Left = ( float )( s * tw * r.NextDouble() );
  504.  
  505. tiles.Add( t );
  506. }
  507.  
  508. movingTile = new Tile( s, s );
  509. movingTile.Left = 4 * s;
  510. movingTile.Top = h / 2 - s;
  511.  
  512. tiles.Add( movingTile );
  513. }
  514.  
  515. double a = 0.0f;
  516. protected override void Update( GameTime gameTime )
  517. {
  518.  
  519. base.Update( gameTime );
  520. }
  521.  
  522. protected override void Draw( GameTime gameTime )
  523. {
  524. gpu.Clear( Color.Gray );
  525.  
  526. sb.Begin( SpriteSortMode.BackToFront, BlendState.AlphaBlend );
  527.  
  528.  
  529.  
  530.  
  531. #region computation: needs move update
  532. KeyboardState ks = Keyboard.GetState();
  533. if( ks.IsKeyDown( Keys.Escape ) )
  534. this.Exit();
  535.  
  536.  
  537.  
  538. a += 0.01f;
  539. if( a >= 2 * Math.PI )
  540. a -= 2 * Math.PI;
  541.  
  542. // Before moving the tile.. should see if the move's allowed
  543. movingTile.y += ( float )Math.Sin( a );
  544.  
  545. p.computeVel( gameTime );
  546.  
  547.  
  548.  
  549. if( ks.IsKeyDown( Keys.Up ) )
  550. p.doJump();
  551.  
  552. if( ks.IsKeyDown( Keys.Left ) )
  553. p.vx = -p.sp;
  554. if( ks.IsKeyDown( Keys.Right ) )
  555. p.vx = p.sp;
  556.  
  557. if( !ks.IsKeyDown( Keys.Space ) )
  558. wallTest();
  559. #endregion
  560.  
  561.  
  562.  
  563.  
  564. sb.Draw( Entity.tex, p.getRect(), Color.Blue );
  565. foreach( Tile t in tiles )
  566. sb.Draw( Entity.tex, t.getRect(), t.color );
  567. sb.End();
  568.  
  569. base.Draw( gameTime );
  570. }
  571. }
  572.  
  573.  
  574. //launcher
  575. static class Program
  576. {
  577. static void Main( string[] args )
  578. {
  579. using( CollisionDemo2 game = new CollisionDemo2() )
  580. {
  581. game.Run();
  582. }
  583. }
  584. }
  585. }
Not running #stdin #stdout 0s 0KB
stdin
Standard input is empty
stdout
Standard output is empty