using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsForms_Game1
{
   
public partial class Form1 : Form
   
{
       
private Point player; //存放玩家x,y        
       
private Point[] vMonster; //存放怪物x,y 
       
private Bullet[] vBullet; //存放子彈x,y        
       
private Random random;
       
private Graphics wndGraphic; //視窗畫布
       
private Graphics backGraphic; //背景頁畫布
       
private Bitmap backBmp; //背景點陣圖
       
private const int VIEW_W = 1024;
       
private const int VIEW_H = 768;
       
private const float MAKE_MONSTER_TIME = 3;
       
private float makeMonsterTime; //生怪的時間
       
private const float MAKE_BULLET_TIME = 0.1f;
       
private float makeBulletTime; //再過多久生子彈的時間
       
private const float REQUIRE_FPS = 60; //預期的畫面更新率(每秒呼叫幾次onTimer)
       
private const int BALL_SIZE = 50; //球的直徑
       
private const int MAX_ENEMY = 30;
       
private const int MAX_BULLET = 10;
       
private Point mousePos;
       
private KeyState keySpace;//空白鍵
       
private KeyState keyUp;//上
       
private KeyState keyDown;//下
       
private KeyState keyLeft;//左
       
private KeyState keyRight;//右
       
public Form1()
       
{
            InitializeComponent();
            keySpace = new KeyState(Keys.Space);
            keyUp = new KeyState(Keys.Up);
            keyDown = new KeyState(Keys.Down);
            keyLeft = new KeyState(Keys.Left);
            keyRight = new KeyState(Keys.Right);
            makeBulletTime = 0;
            makeMonsterTime =
MAKE_MONSTER_TIME;
            wndGraphic = CreateGraphics(); //建立視窗畫布
            backBmp = new Bitmap(VIEW_W, VIEW_H);
            backGraphic = Graphics.FromImage(backBmp);
            mousePos = new Point();
            random = new Random();
            random = new Random();
            player = new Point();
       
    player.x = 100;
            player.y = 100;
            vMonster = new Point[MAX_ENEMY];
            vBullet = new Bullet[MAX_BULLET];
            for (int i = 0; i <
MAX_ENEMY; i++)
            {
                vMonster[i] = new Point();
                vMonster[i].x = random.Next(0, VIEW_W);
                vMonster[i].y = random.Next(0,
VIEW_H);
            }
            timer1.Interval = 1000 / (int)REQUIRE_FPS; // 1/30秒
            timer1.Start();
       
}
       
private void onPaint(object sender, PaintEventArgs e)
       
{
           drawGame();
       
}
       
private void moveMonster()
       
{
            for (int i = 0; i <
MAX_ENEMY; i++)
            {
                if (vMonster[i] != null)
                {
   
                vMonster[i].move(player);
                    /*碰到玩家球就消失
                    if
(vMonster[i].getDistance(player) < BALL_SIZE)
                    {
                        vMonster[i] = null;
                    }
                    */
                }
            }
       
}
       
private void moveBullet_KillMonster()
       
{
            for (int i = 0; i <
MAX_BULLET; i++)
            {
                if (vBullet[i] != null)
                {
                    vBullet[i].move();
                    //有沒有打到怪
                    for (int m = 0; m <
MAX_ENEMY; m++)
                    {
                        //子彈跟怪都是存在的
                        if (vMonster[m] != null)
                        {
                            if
(vMonster[m].getDistance(vBullet[i]) < BALL_SIZE)
                            {
                                vBullet[i] = null;
                                vMonster[m] = null;
                                break;
                            }
                        }
                    }
                    if (vBullet[i] != null)
                    {
                        if (vBullet[i].x > VIEW_W) //檢查出界                     
                            vBullet[i] = null;                      
                        else if (vBullet[i].y > VIEW_H) //檢查出界
                            vBullet[i] = null;
                        else if (vBullet[i].x < 0) //檢查出界
                            vBullet[i] = null;
                        else if(vBullet[i].y < 0) //檢查出界                        
                            vBullet[i] = null;                       
                    }
                }
            }
       
}
       
private void drawGame()
       
{
            backGraphic.FillRectangle(Brushes.White, 0, 0,
VIEW_W, VIEW_H);
            backGraphic.DrawEllipse(Pens.Red, player.x,
player.y, BALL_SIZE, BALL_SIZE); //畫出玩家
            int total = 0;
            //畫出怪物
            for (int i = 0; i <
MAX_ENEMY; i++)
            {
                if (vMonster[i] != null)
                {
                    total++;
                    backGraphic.DrawEllipse(Pens.Blue,
vMonster[i].x, vMonster[i].y, BALL_SIZE, BALL_SIZE);
                }
            }
            String str = "怪物數量:" + total;
            backGraphic.DrawString(str, SystemFonts.CaptionFont,
Brushes.Black, 0, 0);
            total = 0;
            //畫出子彈
            for (int i = 0; i <
MAX_BULLET; i++)
            {
                if (vBullet[i] != null)
                {
                    total++;
                    backGraphic.DrawEllipse(Pens.Black,
vBullet[i].x, vBullet[i].y, BALL_SIZE, BALL_SIZE);
                }                    
            }
            //顯示子彈的數量
            total = MAX_BULLET - total;
            str = "剩餘子彈:" + total;
            backGraphic.DrawString(str, SystemFonts.CaptionFont,
Brushes.Black, 0, 20);
            if (keySpace.isDown())
            {
                backGraphic.DrawString("space down", SystemFonts.CaptionFont, Brushes.Black, 0, 40);
            }
            else
            {
                backGraphic.DrawString("space up", SystemFonts.CaptionFont, Brushes.Black, 0, 40);
            }
            //將背景頁畫到視窗上面
           
wndGraphic.DrawImageUnscaled(backBmp, 0, 0);
            //Invalidate(); //通知重繪畫面
       
}
       
private void onTimer(object sender, EventArgs e)
       
{
            //就是主迴圈:main
            keySpace.onTimer();
            keyUp.onTimer();
            keyDown.onTimer();
            keyLeft.onTimer();
            keyRight.onTimer();
            if (keySpace.isPress()) //剛剛壓下去
            {
                //也要做發射
                fireBullet();
            }
            // 連發
            if (keySpace.isDown()) //壓著空白鍵
            {
                makeBulletTime -= 1.0f /
REQUIRE_FPS; // 1/30秒
                if(makeBulletTime <= 0)//發射子彈的時間到了
                {
                    fireBullet(); 
                }
            }
            if (keyUp.isDown()) player.y -= 5;
            if (keyDown.isDown()) player.y +=
5;
            if (keyLeft.isDown()) player.x -=
5;
            if (keyRight.isDown()) player.x +=
5;
            makeMonsterTime -= 1.0f / 30.0f;
            if(makeMonsterTime <= 0)
            {
                //生怪時間到了
                for (int i = 0; i <
MAX_ENEMY; i++)
                {
                    if (vMonster[i] == null)
                    {
                        vMonster[i] = new Point();
                        vMonster[i].x =
random.Next(0, VIEW_W);
                        vMonster[i].y =
random.Next(0, VIEW_H);
                        break;
                    }
                }
   
            makeMonsterTime =
MAKE_MONSTER_TIME;
            }
            moveMonster();
            moveBullet_KillMonster();
            drawGame();
       
}
       
void fireBullet()
       
{
            //原本放開,剛剛按下去
            for (int i = 0; i <
MAX_BULLET; i++)
            {
                if (vBullet[i] == null)
                {
                    vBullet[i] = new Bullet(player, mousePos);
                    vBullet[i].x = player.x;
                    vBullet[i].y = player.y;
                    break;
                }
            }
            makeBulletTime = MAKE_BULLET_TIME;
       
}
       
//滑鼠移動的通知
       
private void onMouseMove(object sender, MouseEventArgs e)
       
{
            mousePos.x = e.X;
            mousePos.y = e.Y;
       
}
       
//按鍵放開的通知
       
private void onKeyUp(object sender, KeyEventArgs e)
       
{
            keySpace.onKeyUp(e.KeyCode);
            keyUp.onKeyUp(e.KeyCode);
            keyDown.onKeyUp(e.KeyCode);
            keyLeft.onKeyUp(e.KeyCode);
            keyRight.onKeyUp(e.KeyCode);
       
}
       
//按下某個按鍵
       
private void onKeyDown(object sender, KeyEventArgs e)
       
{
            keySpace.onKeyDown(e.KeyCode);
            keyUp.onKeyDown(e.KeyCode);
            keyDown.onKeyDown(e.KeyCode);
            keyLeft.onKeyDown(e.KeyCode);
            keyRight.onKeyDown(e.KeyCode);
       
}
   
}
   
class Point
   
{
      
// public static float staticData =
1.7f; //共享
       
public float x, y;
       
public float getDistance(Point pnt)
       
{
            //x,y是指呼叫者的x,y
            //pnt是指傳入的物件
            float L = (float)Math.Sqrt((x - pnt.x) *
(x - pnt.x) + (y - pnt.y) * (y - pnt.y));
            return L;
       
}
       
public void move(Point target) //target > 玩家
       
{
            float L =
getDistance(target);
            float tx, ty;
            if (L > 1)
            {
                tx = x + (target.x - x) * 1 /
L;
                ty = y + (target.y - y) * 1 /
L;
                x = tx;
                y = ty;
            }
            else //距離很近
            {
                x = target.x;
                y = target.y;
            }
       
}
   
}
   
class Bullet : Point //Bullet繼承Point:加強或修改父類別
   
{
   
    private Point moveDir; //移動的向量
       
private const int BULLET_SPEED = 10;
       
//方法名稱與類別名稱相同:建構
       
//當new某個物件(實體)的時候會呼叫這個物件(實體)的建構
       
public Bullet(Point pos, Point mousePos) 
       
{
            x = pos.x;
            y = pos.y;
            float dist =
getDistance(mousePos);
            moveDir = new Point();
            moveDir.x = (mousePos.x - x) *
BULLET_SPEED / dist;
            moveDir.y = (mousePos.y - y) *
BULLET_SPEED / dist; 
       
}
       
public void move()
       
{
            //使用父類別的
            x += moveDir.x;
            y += moveDir.y;
       
}
   
}
   
//按鍵狀態(指定特定按鍵來做偵測)
   
class KeyState
   
{
       
//Keys不是一個類別,是一個列舉(enum)
       
private Keys theKey; //存放一個對應的按鍵編號 
       
//剛剛壓下去 / 目前這次是壓著的 / 上次onTimer是否壓著
       
bool bPress, bDown, bPreDown;
       
public KeyState(Keys k)
       
{
            theKey = k;
            bPress = false;
            bDown = false;
            bPreDown = false;
       
}
       
public void onKeyDown(Keys k)
       
{
            if(theKey == k)
            {                
                bDown = true; //剛剛按下去
            }
       
}
       
public void onKeyUp(Keys k)
       
{
            if (theKey == k)
            {
                bDown = false;
    
           bPress = false;
            }
       
}
       
public bool isPress() //是否剛剛按下去
       
{
            return bPress;
       
}
       
public bool isDown() //是否壓著
       
{
            return bDown;
       
}
       
public void onTimer() //timer通知時呼叫
       
{
            if(bDown == true)//此時是壓著
            {
                if (bPreDown == false) bPress = true;
                else bPress = false;
            }
            else
            {
                bPress = false;
            }
            bPreDown = bDown; //把這次的狀態記下來,下次就可以用這個狀態
       
}
   
}
}
