source: 2014/30/MiskaK/The Reclaim/The Reclaim/The Reclaim/The Reclaim/The_Reclaim.cs @ 5602

Revision 5602, 20.5 KB checked in by anlakane, 6 years ago (diff)

Lisätty mm. ampuminen ja vihollisten tekoälyä.

Line 
1using System;
2using System.Collections.Generic;
3using Jypeli;
4using Jypeli.Assets;
5using Jypeli.Controls;
6using Jypeli.Effects;
7using Jypeli.Widgets;
8
9public class The_Reclaim : PhysicsGame
10{
11    public static The_Reclaim Peli;
12
13    /// <summary>
14    /// Verkko reitinhakua varten.
15    /// </summary>
16    public Map NavigationMesh { get; private set; }
17
18    public List<Soldier> HostileTroops = new List<Soldier>();
19    public List<Soldier> FriendlyTroops = new List<Soldier>();
20    public List<Soldier> SelectedTroops = new List<Soldier>();
21
22    public Timer AITick = new Timer();
23    private int CurrentTick = 1;
24
25    public List<LevelData> Levels = new List<LevelData>();
26    public LevelData CurrentLevel;
27
28    private Vector TroopSelectionCorner;
29    private bool SelectingTroops;
30    private ActionMenu actionMenu;
31    private Behaviour CurrentBehaviour = Behaviour.Idle;
32
33    private bool SelectingShootingTarget;
34    private Vector ShootingTargetCorner;
35
36#if !DEBUG
37    Label waterprint = new Label("The Reclaim (development version)\n by Miska Kananen");
38#endif
39
40    public override void Begin()
41    {
42        Peli = this;
43#if !DEBUG
44        waterprint.Position = new Vector(Screen.Left + waterprint.Width / 2, Screen.Bottom + 30);
45        waterprint.TextScale = new Vector(0.8, 0.8);
46        waterprint.TextColor = Color.White;
47        Add(waterprint);
48#endif
49        MainMenu();
50    }
51
52    void MainMenu()
53    {
54        StartGame("ruinedcity", 1);
55    }
56
57    void StartGame(string world, int levelCount)
58    {
59        LoadLevels(world, levelCount);
60        LoadLevel(1);
61        SetControls();
62        InitializeAI();
63    }
64
65    #region grafiikka
66
67    /// <summary>
68    /// Zoomataan kameraa hiiren rullan mukaan.
69    /// </summary>
70    void ZoomCamera()
71    {
72        double zoom = Camera.ZoomFactor + ((Mouse.WheelChange * 0.05) / Camera.ZoomFactor);
73        if (zoom > 0)
74            Camera.ZoomFactor += (Mouse.WheelChange * 0.05);
75        //if (Mouse.WheelChange > 0)
76        //Camera.Position = Mouse.PositionOnWorld;
77    }
78
79    protected override void Paint(Canvas canvas)
80    {
81        Vector mousePos = Mouse.PositionOnWorld;
82
83        if (SelectingTroops)
84        {
85            canvas.BrushColor = Color.Blue;
86            canvas.DrawLine(TroopSelectionCorner, new Vector(TroopSelectionCorner.X, mousePos.Y));
87            canvas.DrawLine(TroopSelectionCorner, new Vector(mousePos.X, TroopSelectionCorner.Y));
88            canvas.DrawLine(mousePos, new Vector(mousePos.X, TroopSelectionCorner.Y));
89            canvas.DrawLine(mousePos, new Vector(TroopSelectionCorner.X, mousePos.Y));
90        }
91
92        if (SelectingShootingTarget)
93        {
94            canvas.BrushColor = Color.Red;
95            canvas.DrawLine(ShootingTargetCorner, new Vector(ShootingTargetCorner.X, mousePos.Y));
96            canvas.DrawLine(ShootingTargetCorner, new Vector(mousePos.X, ShootingTargetCorner.Y));
97            canvas.DrawLine(mousePos, new Vector(mousePos.X, ShootingTargetCorner.Y));
98            canvas.DrawLine(mousePos, new Vector(ShootingTargetCorner.X, mousePos.Y));
99        }
100
101        /*for (int i = 0; i < SelectedTroops.Count; i++) // piirretään ampuvien sotilaiden kohdealueet
102        {
103            if (SelectedTroops[i].CurrentBehaviour == Behaviour.Shoot && SelectedTroops[i].ShootingTargetArea != null)
104            {
105                canvas.BrushColor = new Color(255, 0, 0, 32);
106                canvas.DrawLine(SelectedTroops[i].ShootingTargetArea.FirstCorner, new Vector(SelectedTroops[i].ShootingTargetArea.SecondCorner.X, SelectedTroops[i].ShootingTargetArea.FirstCorner.Y));
107                canvas.DrawLine(SelectedTroops[i].ShootingTargetArea.FirstCorner, new Vector(SelectedTroops[i].ShootingTargetArea.FirstCorner.X, SelectedTroops[i].ShootingTargetArea.SecondCorner.Y));
108                canvas.DrawLine(SelectedTroops[i].ShootingTargetArea.SecondCorner, new Vector(SelectedTroops[i].ShootingTargetArea.SecondCorner.X, SelectedTroops[i].ShootingTargetArea.FirstCorner.Y));
109                canvas.DrawLine(SelectedTroops[i].ShootingTargetArea.SecondCorner, new Vector(SelectedTroops[i].ShootingTargetArea.FirstCorner.X, SelectedTroops[i].ShootingTargetArea.SecondCorner.Y));
110            }
111        }*/
112        base.Paint(canvas);
113    }
114
115    /// <summary>
116    /// Piirretään valojuovia.
117    /// </summary>
118    /// <param name="position">Valojuovan tämänhetkinen sijainti.</param>
119    /// <param name="color">Valojuovan väri.</param>
120    /// <param name="lifetimeInSeconds">Kauanko valojuova pysyy kentällä.</param>
121    public void DrawTracers(Vector position, Color color, double lifetimeInSeconds, double brightnessFactor)
122    {
123        color.AlphaComponent = (byte)(32 * brightnessFactor); // 64 toimii
124        GameObject tracer = new GameObject(2, 2);
125        tracer.Shape = Shape.Circle;
126        tracer.Color = color;
127        tracer.Position = position;
128        tracer.MaximumLifetime = TimeSpan.FromSeconds(lifetimeInSeconds);
129        Add(tracer, -2);
130    }
131
132    /// <summary>
133    /// Piirretään valojuovia.
134    /// </summary>
135    /// <param name="tracingObject">Olio, josta valojuovat tulevat.</param>
136    /// <param name="color">Valojuovan väri.</param>
137    /// <param name="lifetimeInSeconds">Kauanko valojuova pysyy kentällä.</param>
138    /// <param name="brightnessFactor">Valojuovan kirkkaus.</param>
139    public void DrawTracers(GameObject tracingObject, Color color, double lifetimeInSeconds, double brightnessFactor)
140    {
141        color.AlphaComponent = (byte)(32 * brightnessFactor); // 64 toimii
142        GameObject tracer = new GameObject(60, 2);
143        tracer.Shape = Shape.Circle;
144        tracer.Color = color;
145        tracer.Position = tracingObject.Position;
146        tracer.Angle = tracingObject.Angle;
147        tracer.MaximumLifetime = TimeSpan.FromSeconds(lifetimeInSeconds);
148        Add(tracer, -2);
149    }
150
151    void UpdateFoW(GameObject fow)
152    {
153        SetTransparent(fow.Image, Vector.Zero, 0);
154    }
155
156    void SetTransparent(Image kuva, Vector position, double radius)
157    {
158        uint[,] bmp = kuva.GetDataUInt();
159        int ny = kuva.Height;
160        int nx = kuva.Width;
161
162        int minY = (int)(position.Y / 10 + ny / 2);
163        // ny / 2 olis y = o
164        // nx / 2 x = 0
165        // yks pikseli = 10 koordinaatistossa
166
167        for (int iy = 0; iy < ny; iy++)
168            for (int ix = 0; ix < nx; ix++)
169            {
170                uint c = bmp[iy, ix];
171                byte r = Color.GetRed(c);
172                byte g = Color.GetGreen(c);
173                byte b = Color.GetBlue(c);
174                byte a = Color.GetAlpha(c);
175
176                byte newAlpha = (byte)(a - 1);
177
178                bmp[iy, ix] = Color.PackRGB(r, g, b, newAlpha);
179            }
180        kuva.SetData(bmp);
181    }
182
183    #endregion
184
185    #region kentta
186
187    /// <summary>
188    /// Luodaan maailma ruutukarttojen pohjalta.
189    /// </summary>
190    /// <param name="data">Luomiseen tarvittavat tiedot.</param>
191    void CreateWorld(LevelData data)
192    {
193        SmoothTextures = false;
194        Level.BackgroundColor = Color.Black;
195        Camera.ZoomToAllObjects();
196        Mouse.IsCursorVisible = true;
197
198        GameObject backgroundImage = new GameObject(data.GroundTexture.Width * 2, data.GroundTexture.Height * 2); // *64
199        backgroundImage.Image = data.GroundTexture;
200        backgroundImage.Tag = "background";
201        Add(backgroundImage, -3);
202
203        NavigationMesh = new Map(data.Walls.Width, data.Walls.Height);
204
205        ColorTileMap walls = new ColorTileMap(data.Walls);
206        walls.SetTileMethod(Color.Black, CreateWall, Color.Transparent);
207        walls.SetTileMethod(Color.Gold, CreateWall, Color.Transparent);
208        walls.SetTileMethod(Color.BrightGreen, CreateEntrance, Entrance.Owner.Friendly);
209        walls.SetTileMethod(Color.Red, CreateEntrance, Entrance.Owner.Enemy);
210        walls.Execute(GameConstants.TILE_WIDTH, GameConstants.TILE_HEIGHT);
211
212
213
214        /*ColorTileMap roofs = new ColorTileMap(data.Roofs);
215        roofs.SetTileMethod(Color.DarkGray, CreateRoof, Color.DarkGray);
216        roofs.Execute(GameConstants.TILE_WIDTH, GameConstants.TILE_HEIGHT);*/
217
218        //GameObject fogOfWar = new GameObject(backgroundImage.Width, backgroundImage.Height);
219        //fogOfWar.Image = new Image(data.GroundTexture.Width, data.GroundTexture.Height, Color.Black);
220        //Add(fogOfWar, 2);
221
222        //Timer fowTimer = new Timer();
223        //fowTimer.Interval = 0.1;
224        //fowTimer.Timeout += delegate { UpdateFoW(fogOfWar); };
225        //fowTimer.Start();     
226    }
227
228    void CreateWall(Vector paikka, double leveys, double korkeus, IntPoint positionInLevelArray, Color vari) // vari DEBUG
229    {
230        PhysicsObject seina = PhysicsObject.CreateStaticObject(leveys, korkeus);
231        seina.Position = paikka;
232        seina.Color = vari;
233        seina.Tag = "seina";
234        Add(seina);
235
236        NavigationMesh.Nodes[positionInLevelArray.X, positionInLevelArray.Y].IsFull = true;
237    }
238
239    void CreateRoof(Vector paikka, double leveys, double korkeus, IntPoint positionInLevelArray, Color vari) // vari DEBUG
240    {
241        GameObject katto = new GameObject(leveys, korkeus);
242        katto.Position = paikka;
243        katto.Color = vari;
244        /*katto.NeedsUpdateCall = true;
245        katto.IsUpdated = true;
246        katto.NeedsUpdateCall = true;
247        katto.Updated += UpdateRoofTransparency;*/
248        Add(katto, 1);
249    }
250
251    void CreateEntrance(Vector paikka, double leveys, double korkeus, IntPoint posInLevel, Entrance.Owner owner)
252    {
253        Entrance e = new Entrance(paikka, GameConstants.ENTRANCE_RADIUS, owner, GameConstants.SECONDS_TO_CAPTURE);
254        //e.Spawn();
255        CurrentLevel.Entrances.Add(e);
256    }
257
258    /// <summary>
259    /// Ladataan kenttä ja luodaan se.
260    /// </summary>
261    /// <param name="level">Monesko kenttä.</param>
262    void LoadLevel(int level)
263    {
264        if (level < 0 || level > Levels.Count) return;
265        CurrentLevel = Levels[level - 1];
266        ClearGameObjects();
267        CreateWorld(CurrentLevel);
268    }
269
270    /// <summary>
271    /// Ladataan kaikki kentät.
272    /// </summary>
273    /// <param name="world">Maailmakansion nimi.</param>
274    /// <param name="levelCount">Ruutujen määrä maailmassa.</param>
275    void LoadLevels(String world, int levelCount)
276    {
277        Levels.Clear();
278        for (int i = 1; i < levelCount + 1; i++)
279        {
280            Image walls = LoadImage(world + "/" + "ruutu" + i.ToString() + "_seinat");
281            Image maatekstuuri = LoadImage(world + "/" + "ruutu" + i.ToString() + "_maatekstuuri");
282
283            LevelData data = new LevelData(maatekstuuri, walls, null);
284            Levels.Add(data);
285        }
286    }
287
288    /*void UpdateRoofTransparency(GameObject roof)
289    {
290        const double MIN_DISTANCE = 400.0;
291
292        if (Vector.Distance(roof.Position, Mouse.PositionOnWorld) < MIN_DISTANCE)
293        {
294
295        }
296        else roof.Color.AlphaComponent = 255;
297    }*/
298
299#endregion
300
301    #region hahmot
302
303    public Soldier CreateSoldier(Vector paikka, Image kuva, bool isPlayerControlled, double speed, Ase ase, Angle kulma)
304    {
305        Soldier s = new Soldier(kuva, 0.5, isPlayerControlled);
306        s.Position = paikka;
307        s.Shape = Shape.Circle;
308        s.Angle = kulma;
309        s.MovingSpeed = speed;
310        s.CollisionIgnoreGroup = 1;
311        s.SetWeapon(ase);
312        s.Weapon.UsesTracers = true;
313        s.LinearDamping = 0.95;
314        s.AngularDamping = 0.98;
315        s.Mass = 100;
316        EnemySpecialization[] specs = { EnemySpecialization.Attacker, EnemySpecialization.Defender, EnemySpecialization.Killer };
317
318        if (isPlayerControlled)
319        {
320            FriendlyTroops.Add(s);
321        }
322        else
323        {
324            HostileTroops.Add(s);
325            s.Specialization = RandomGen.SelectOneWithProbabilities<EnemySpecialization>(specs, 0.3, 0.5, 0.2); // eniten defendereitä, toiseksi eniten attackereita ja vähiten killereitä
326            s.Name.Text += " (" + s.Specialization.ToString() + ")";
327        }
328        Add(s);
329        return s;
330    }
331
332    #endregion
333
334    #region ohjaimet
335
336    void SetControls()
337    {
338        Mouse.ListenWheel(ZoomCamera, null);
339        Mouse.Listen(MouseButton.Left, ButtonState.Pressed, delegate {
340            TroopSelectionCorner = Mouse.PositionOnWorld;
341            SelectingTroops = true;
342        }, null);
343        Mouse.Listen(MouseButton.Left, ButtonState.Released, delegate {
344            SelectingTroops = false;
345            SelectTroops();
346        }, null);
347        Mouse.Listen(MouseButton.Middle, ButtonState.Pressed, delegate {
348            CreateActionMenu();
349        }, null);
350        Mouse.Listen(MouseButton.Middle, ButtonState.Released, delegate
351        {
352            actionMenu.ButtonClicked(actionMenu.GetButtonClosestToMouse());
353        }, null);
354        Mouse.Listen(MouseButton.Right, ButtonState.Pressed, delegate {
355            if (SelectedTroops.Count != 0)  ApplyBehaviour();
356        }, null);
357
358
359        Keyboard.Listen(Key.Space, ButtonState.Pressed, delegate { CreateSoldier(Mouse.PositionOnWorld, Images.OmaSotilasAKS74u, true, RandomGen.NextDouble(GameConstants.SOLDIER_MIN_SPEED, GameConstants.SOLDIER_MAX_SPEED), Aseet.GetRandomWeapon(), Angle.Zero); }, null);
360        Keyboard.Listen(Key.RightControl, ButtonState.Pressed, delegate { CreateSoldier(Mouse.PositionOnWorld, Images.VihollinenVSSVintorez, false, RandomGen.NextDouble(GameConstants.SOLDIER_MIN_SPEED, GameConstants.SOLDIER_MAX_SPEED), Aseet.GetRandomWeapon(), Angle.Zero); }, null);
361        //Keyboard.Listen(Key.Space, ButtonState.Pressed, delegate { MessageDisplay.Add(Mouse.PositionOnWorld.ToString()); MessageDisplay.Add(NavigationMesh.GetCorrespondingNode(Mouse.PositionOnWorld).ToString()); }, null);
362        Keyboard.Listen(Key.W, ButtonState.Down, LiikutaKameraa, null, new Vector(0.0, 1.0));
363        Keyboard.Listen(Key.S, ButtonState.Down, LiikutaKameraa, null, new Vector(0.0, -1.0));
364        Keyboard.Listen(Key.A, ButtonState.Down, LiikutaKameraa, null, new Vector(-1.0, 0.0));
365        Keyboard.Listen(Key.D, ButtonState.Down, LiikutaKameraa, null, new Vector(1.0, 0.0));
366
367    }
368
369    void LiikutaKameraa(Vector suunta)
370    {
371        if (Camera.ZoomFactor > 1)
372            Camera.Position += (suunta * GameConstants.CAMERA_MOVEMENT_SPEED / Camera.ZoomFactor);
373        else
374            Camera.Position += (suunta * GameConstants.CAMERA_MOVEMENT_SPEED);
375
376    }
377
378    void SelectTroops()
379    {
380        Vector corner = Mouse.PositionOnWorld;
381
382        SelectedTroops.ForEach(x => x.SelectionMarker.IsVisible = false); 
383        SelectedTroops.Clear();
384
385        for (int i = 0; i < HostileTroops.Count; i++)
386        {
387            HostileTroops[i].SelectionMarker.IsVisible = false;
388        }
389
390        List<GameObject> selected = GetObjects(x => x is Soldier && IsInside(x.Position, TroopSelectionCorner, corner));
391
392        for (int i = 0; i < selected.Count; i++)
393        {
394            Soldier s = (Soldier)selected[i];
395            if (s.IsPlayerControlled)
396            {
397                SelectedTroops.Add(s);
398                s.SelectionMarker.IsVisible = true;
399
400                if (s.TargetSoldiers != null)
401                {
402                    for (int j = 0; j < s.TargetSoldiers.Count; j++)
403                    {
404                        s.TargetSoldiers[j].SelectionMarker.IsVisible = true;
405                    }
406                }
407            }
408        }
409    }
410
411    /// <summary>
412    /// Onko piste kahden pisteen muodostaman suorakulmion sisällä.
413    /// </summary>
414    /// <param name="pos">Piste.</param>
415    /// <param name="firstCorner">Ensimmäinen nurkka.</param>
416    /// <param name="secondCorner">Toinen nurkka.</param>
417    /// <returns>Onko piste suorakulmion sisällä.</returns>
418    public bool IsInside(Vector pos, Vector firstCorner, Vector secondCorner)
419    {
420        if (pos.X < Math.Min(firstCorner.X, secondCorner.X) || pos.X > Math.Max(firstCorner.X, secondCorner.X)) return false;
421        if (pos.Y < Math.Min(firstCorner.Y, secondCorner.Y) || pos.Y > Math.Max(firstCorner.Y, secondCorner.Y)) return false;
422        return true;
423    }
424
425    void CreateActionMenu()
426    {
427        Vector mousePos = Mouse.PositionOnWorld;
428
429        actionMenu = new ActionMenu(300, 60, Behaviour.Idle, Behaviour.Move, Behaviour.Shoot);
430        actionMenu.Position = new Vector(Mouse.PositionOnScreen.X, Mouse.PositionOnScreen.Y);
431        actionMenu.Clicked += delegate(Behaviour action) { ActionButtonClicked(action, mousePos); actionMenu.Destroy(); };
432        Add(actionMenu);
433    }
434
435    void ActionButtonClicked(Behaviour action, Vector targetPosition)
436    {
437        CurrentBehaviour = action;
438        MessageDisplay.Add("Current action: " + action.ToString());
439    }
440   
441    #endregion
442
443    #region tekoaly
444
445    void ApplyBehaviour()
446    {
447        switch (CurrentBehaviour)
448        {
449            case Behaviour.Idle:
450                for (int i = 0; i < SelectedTroops.Count; i++)
451                {
452                    SelectedTroops[i].CurrentBehaviour = CurrentBehaviour;
453                    //SelectedTroops[i].ShootingTargetArea = null;
454                }
455                break;
456            case Behaviour.Move:
457                for (int i = 0; i < SelectedTroops.Count; i++)
458                {
459                    SelectedTroops[i].CurrentBehaviour = CurrentBehaviour;
460                    SelectedTroops[i].TargetLocation = Mouse.PositionOnWorld;
461                }
462                break;
463            case Behaviour.Shoot:
464                for (int i = 0; i < SelectedTroops.Count; i++)
465                {
466                    SelectedTroops[i].CurrentBehaviour = CurrentBehaviour;
467                }
468                if (!SelectingShootingTarget)
469                {
470                    ShootingTargetCorner = Mouse.PositionOnWorld; // tallennetaan ensimmäinen nurkka
471                    SelectingShootingTarget = true;
472
473                    Mouse.Listen(MouseButton.Right, ButtonState.Released, delegate
474                    {
475                        if (!SelectingShootingTarget) return;
476                        for (int i = 0; i < SelectedTroops.Count; i++)
477                        {
478                            SelectedTroops[i].TargetSoldiers.Clear();
479                            Area a = new Area(ShootingTargetCorner, Mouse.PositionOnWorld);
480                            List<GameObject> soldiersInArea = GetObjects(x => x is Soldier && a.IsInside(x.Position));
481                            for (int j = 0; j < soldiersInArea.Count; j++)
482                            {
483                                Soldier s = (Soldier)soldiersInArea[j];
484                                if (!s.IsPlayerControlled)
485                                    SelectedTroops[i].AddTargetSoldier(s);
486                            }
487                            for (int j = 0; j < SelectedTroops[i].TargetSoldiers.Count; j++)
488                            {
489                                // käydään läpi kaikki viholliset alueella
490                                SelectedTroops[i].TargetSoldiers[j].SelectionMarker.IsVisible = true;
491                            }
492                        }
493                        SelectingShootingTarget = false;
494                    }, null);
495                }
496                break;
497            default:
498                break;
499        }
500    }
501
502    void InitializeAI()
503    {
504        AITick.Interval = GameConstants.AI_REFRESH_RATE;
505        AITick.Timeout += DoAITick;
506        AITick.Start();
507    }
508
509    void DoAITick()
510    {
511        for (int i = 0; i < FriendlyTroops.Count; i++)
512        {
513            FriendlyTroops[i].UpdateAI();
514        }
515
516        for (int i = 0; i < HostileTroops.Count; i++)
517        {
518            HostileTroops[i].UpdateAI();
519            if (CurrentTick == 1)
520                HostileTroops[i].UpdateEnemyObjectives();
521            CurrentTick++;
522            if (CurrentTick > GameConstants.ENEMY_AI_OBJECTIVE_REFRESH_TICKS)
523                CurrentTick = 1;
524        }
525    }
526
527    #endregion
528
529    #region testit
530    /*void DrawRoute()
531    {
532        route = NavigationMesh.DijkstraSearch(NavigationMesh.GetCorrespondingNode(pos1), NavigationMesh.GetCorrespondingNode(pos2));
533
534        for (int i = 0; i < route.Length; i++)
535        {
536            GameObject g = new GameObject(25, 25, Shape.Rectangle);
537            g.Position = NavigationMesh.GetPositionOnWorld(route[i].Position);
538            g.Color = Color.Red;
539            Add(g, 3);
540            g.MaximumLifetime = TimeSpan.FromSeconds(5.0);
541        }
542    }*/
543
544    #endregion
545}
Note: See TracBrowser for help on using the repository browser.