290 likes | 400 Views
Hoorcollege 12. Afronding Penguin Pairs & overzicht Tick Tick. Penguin selecteren. class Arrow : GameObjectList { protected SpriteGameObject arrowNormal, arrowHover; protected bool pressed; public Arrow( string normal, string hover, int layer = 0,
E N D
Hoorcollege 12 Afronding Penguin Pairs & overzicht Tick Tick
Penguin selecteren class Arrow : GameObjectList { protected SpriteGameObject arrowNormal, arrowHover; protectedbool pressed; public Arrow(string normal, string hover, int layer = 0, string id = "", int sheetIndex = 0) : base(layer, id) { arrowNormal = new SpriteGameObject(normal, 0, id, sheetIndex); arrowHover = new SpriteGameObject(hover, 1, id, sheetIndex); this.Add(arrowNormal); this.Add(arrowHover); arrowHover.Visible = false; pressed = false; } … Subklasse van GameObjectList
Penguin selecteren publicoverridevoidHandleInput(InputHelperinputHelper) { base.HandleInput(inputHelper); Vector2 mousePos = inputHelper.MousePosition; arrowHover.Visible = arrowNormal.BoundingBox.Contains( (int)mousePos.X,(int)mousePos.Y); pressed = inputHelper.MouseLeftButtonPressed() && arrowHover.Visible; } public boolPressed { get { returnpressed; } }
Penguin selecteren class AnimalSelector : GameObjectList { protected Arrow arrowright, arrowup, arrowleft, arrowdown; protected Animal selectedAnimal; public AnimalSelector(int layer = 0, string id = "") : base(layer, id) { // add the four arrows for both states … } ... }
Penguin selecteren public overridevoidHandleInput(InputHelperinputHelper) { if (!visible) return; base.HandleInput(inputHelper); Vector2 animalVelocity = Vector2.Zero; if (arrowdown.Pressed) animalVelocity.Y = 1; elseif (arrowup.Pressed) animalVelocity.Y = -1; elseif(arrowleft.Pressed) animalVelocity.X = -1; elseif(arrowright.Pressed) animalVelocity.X = 1; animalVelocity *= 300; if (inputHelper.MouseLeftButtonPressed()) this.Visible = false; if (selectedAnimal != null && animalVelocity != Vector2.Zero) selectedAnimal.Velocity = animalVelocity; }
Interactie tussen penguins • Gebeurt (zoals te verwachten) in de Animal klasse. public Point GetCurrentBlock() { GameObjectGridtilefield = GameWorld.Find("tilefield") asGameObjectGrid; Point p = new Point((int)Math.Floor(position.X / tilefield.CellWidth), (int)Math.Floor(position.Y/tilefield.CellHeight)); if(velocity.X > 0) p.X++; if(velocity.Y > 0) p.Y++; return p; }
Penguin interactie Point target = GetCurrentBlock(); if (this.GetTileType(target) == TileType.Background) { this.Visible = false; velocity = Vector2.Zero; PenguinPairs.AssetManager.playSound("snd_lost"); return; } else if ... publicTileTypeGetTileType(Point p) { GameObjectGrid t= GameWorld.Find("tilefield") asGameObjectGrid; if (IsOutsideField(p)) return TileType.Background; Tile tile = tilefield.Objects[p.X, p.Y] as Tile; return tile.TileType; }
Penguin interactie if (this.GetTileType(target) == TileType.Background) { ... } else if (this.GetTileType(target) == TileType.Wall) { this.StopMoving(); return; } public voidStopMoving() { GameObjectGridtilefield = GameWorld.Find("tilefield") asGameObjectGrid; velocity.Normalize(); Vector2 oldBlock = new Vector2(GetCurrentBlock().X, GetCurrentBlock().Y) - velocity; position = oldBlock * new Vector2(tilefield.CellWidth, tilefield.CellHeight); velocity = Vector2.Zero; }
Penguin interactie publicAnimalFindAnimalAtPosition(Vector2 pos) { foreach (Animal j in animals) if (j.Position == pos && j.Velocity == Vector2.Zero) return j; returnnull; } Methode in de Level klasse. Level level = Root as Level; Animal j = level.FindAnimalAtPosition(target); if (j == null || !j.Visible) return; // in dit geval hoeven we niks te doen
Verschillende game objecten… if (j.IsEmptyBox()) { this.Visible = false; j.sprite.SheetIndex = this.sprite.SheetIndex; } elseif((j.sprite.SheetIndex == sprite.SheetIndex || this.IsMultiColoredPenguin() || j.IsMultiColoredPenguin()) && !j.IsSeal()) { j.Visible = false; this.Visible = false; PairListpairlist = GameWorld.Find("pairList") as PairList; pairlist.AddPair(sprite.SheetIndex); PenguinPairs.AssetManager.PlaySound("Sounds/snd_pair"); } else this.StopMoving();
Libraries • We hergebruiken best veel klassen steeds opnieuw • GameObject • SpriteGameObject • GameObjectList • TextGameObject • GameStateManager • ... • Gebruik libraries om niet steeds de bestanden te hoeven kopieren!
GameEnvironment library • Basis: klasse GameEnvironment • bevat alle belangrijke elementen van een game public class GameEnvironment : Game { protected GraphicsDeviceManager graphics; protected SpriteBatch spriteBatch; protected InputHelper inputHelper; protected Matrix spriteScale; protected static Point screen; protected static GameStateManager gameStateManager; protected static Random random; protected staticAssetManagerassetManager; protected static GameSettingsManager gameSettingsManager; ... }
Library in Visual Studio • Elke library is een apart project • Voeg library projecten toe om ze te kunnen gebruiken
Nieuwe PenguinPairs klasse class PenguinPairs : GameEnvironment { static void Main() { PenguinPairs game = new PenguinPairs(); game.Run(); } public PenguinPairs() { Content.RootDirectory = "Content"; this.IsMouseVisible = true; GameSettingsManager.SetValue("hints", "on"); } protected override void LoadContent() { ... } }
Nieuwe PenguinPairs klasse protected override void LoadContent() { base.LoadContent(); screen = new Point(1200, 900); this.SetFullScreen(false); // add the game states gameStateManager.AddGameState("playingState", new PlayingState(Content)); gameStateManager.AddGameState("titleMenu", new TitleMenuState()); gameStateManager.AddGameState("optionsMenu", new OptionsMenuState()); gameStateManager.AddGameState("levelMenu", new LevelMenuState()); gameStateManager.AddGameState("helpState", new HelpState()); gameStateManager.AddGameState("levelFinishedState",newLevelFinishedState()); gameStateManager.SwitchTo("titleMenu"); AssetManager.PlayMusic("Sounds/snd_music"); }
Platform games • Genre kwam begin jaren ‘80 opzetten • ‘jumping puzzles’ • Springen van ene naar andere platform • Obstakels ontwijken • Regelmatig gekoppeld met andere game genres, zoals adventure, RPG, shooters…
Typen platform games • Eerste games waren 1 scherm per level • Latere games introduceerden sidescrolling • Nog later: 3D platform games
Veelgebruikte elementen • Levels bestaan uit ‘tiles’ • Makkelijk grote levels maken zonder dat het veel geheugen kost • Verschillende typen tiles • Achtergrondtiles (doorzichtig) • Bloktiles • Platformtiles (kun je van onderen doorheen springen) • Tiles voor begin & einde van het level • Enz.
Veelgebruikte elementen • Spelerkanpunten/levensvergaren • Vijanden of anderebewegendeobstakelsmoetenvermedenworden • Puzzelelementen • Switch of combinatie van switches vinden, omverdertekunnenspelen
Tick tick Wall tile Background tile Exit Resterendetijd Waterdruppel Speler Achtergrondlagen
Opbouw van de game • Levels wordengeladenuiteentekstbestand • We hebbenverschillendesoorten game objecten • De speler • Vijanden • Waterdruppels • Tiles • Overlays
Levels en tiles Waterdruppel Eind van het level Achtergrondtile • .................... • .................X.. • ..........########## • .................... • WWW....WWWW......... • ---....####......... • .................... • WWW................. • ###.........WWWWW... • ............#####... • ....WWW............. • ....###............. • .................... • .1........W.W.W.W.W. • #################### Walltile Startpositie van de speler
Levels uit files lezen • Voordelen: • Levels wordenonafhankelijk van de game code geproduceerd • Makkelijknieuwe levels toe tevoegen • Makkelijkeromtetesten • Nadelen: • Levels kunnen door iedereenge-edit worden (makkelijkeromvalstespelen) • Extra code nodigom levels uit files telezen • Misschienzelfseenspecialeleveleditornodig
Levels uit een file lezen private void LoadTiles(string path) { // lees het level in List<string> tekstlines = new List<string>(); StreamReader fileReader = new StreamReader(path); string line = fileReader.ReadLine(); int width = line.Length; while (line != null) { tekstlines.Add(line); line = fileReader.ReadLine(); } // maak alle tiles … } Een List omallegelezen regels in tebewaren. Lees 1 regel. We gebruiken de StreamReaderklasse. Blijflezentotdatergeen regels meerzijn.
Levels uit een file lezen private void LoadTiles(string path) { // lees het level in … // maak alle tiles TileField tiles = new TileField(textlines.Count - 1, width, 1, "tiles"); this.Add(tiles); tiles.CellWidth = 72; tiles.CellHeight = 55; for (int x = 0; x < width; ++x) for (int y = 0; y < textlines.Count - 1; ++y) { Tile t = LoadTile(textlines[y][x], x, y); tiles.Add(t, x, y); } } Subklasse van GameObjectGrid Methode die gegeven een karakter een Tile oplevert.
private Tile LoadTile(char tileType, int x, int y) { switch (tileType) { case'.': return new Tile(); case'-': returnLoadBasicTile("spr_platform", TileType.Platform); case'X': returnLoadEndTile(x, y); case'W': returnLoadWaterTile(x, y); case'1': returnLoadStartTile(x, y); case'#': returnLoadBasicTile("spr_wall", TileType.Normal); default: return new Tile(); } }
Laden van een waterdruppel tile privateTileLoadWaterTile(int x, int y) { GameObjectListwd = this.Find("waterdrops") asGameObjectList; GameObjectGrid tiles = this.Find("tiles") asGameObjectGrid; WaterDrop w = newWaterDrop(); w.Origin = w.Center; w.Position = new Vector2(x*tiles.CellWidth, y*tiles.CellHeight - 10); w.Position += new Vector2(tiles.CellWidth, tiles.CellHeight) / 2; wd.Add(w); return new Tile(); }
De volgende keer • Animatie • Botsingen / game physics