Lego Mindstorms NXT Flugzeugspiel

Da ich für den Tag der offenen Tür meiner Schule, welcher bereits im Januar stattfand, eine etwas abwechslungsreichere und anspruchsvollere Projektidee gesucht habe, habe ich eine Abwandlung des 2D-Spiels “Helicopter” für den PC geschrieben, welche jedoch mit dem NXT gesteuert wird. Allerdings bin ich kein guter Grafiker, daher habe ich mein Spiel auf ein statisches Flugzeugbild beschränkt. Das gesamte Spiel wurde in C# programmiert, die Steuerung des NXTs in NXC.

Video:

Die NXT-Steuerung:
NXT-Steuerungsroboter

Quelltext C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace NXT_Helicopter
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        System.Drawing.Bitmap Bitmap;
        System.Drawing.Image plane;
        int planesize = 200;
        double planediagonal;
        bool started = false;
        Point screenmiddle;
        double rotation;
        int Byte;
        int oldByte=-1;
        Size Formsize;
        string path = "";
        long score = 0;
        long scoretoreach;

        ArrayList condensation;
        ArrayList highscorepoints;
        ArrayList highscorenames;
        TextBox nameBox;
        Button submitButton;

        ArrayList blocktypes;

        double leftfraction = (double)100 / 1000;

        double blockXfraction = (double)150 / (double)1000;
        double blockYfraction = (double)150 / (double)1000;

        double planefraction=(double)100 / (double)1000;

        ArrayList collisionZone;
        ArrayList originalZone;

        Color background = System.Drawing.Color.DeepSkyBlue;

        ArrayList blocks;
        

        Point planeposition;
        

        int maxData = 45;
        int maxDegrees = 45;

        double XSpeed = (double)10/(double)1000;
        double startspeed;

        double maxupfraction = (double)40/(double)1000;

        Point rotatePoint(Point middle, Point point, double degrees)
        {

            //return new Point((int)(middle.X + Math.Sin(degrees * Math.PI / 180) * Math.Sqrt(Math.Pow(point.X - middle.X, 2) + Math.Pow(point.Y - middle.Y, 2))), (int)(middle.Y + Math.Cos(degrees * Math.PI / 180) * Math.Sqrt(Math.Pow(point.X - middle.X, 2) + Math.Pow(point.Y - middle.Y, 2))));
            //return point;
            return new Point((int)(Math.Cos(degrees * Math.PI / 180) * (point.X - middle.X) - Math.Sin(degrees * Math.PI / 180)*(point.Y-middle.Y) + middle.X), (int)(Math.Sin(degrees * Math.PI / 180) * (point.X - middle.X) + Math.Cos(degrees * Math.PI / 180)*(point.Y-middle.Y) + middle.Y));
            //return new Point((int)(middle.X + Math.Cos(degrees * Math.PI / 180) * Math.Sqrt(Math.Pow(point.X - middle.X, 2) + Math.Pow(point.Y - middle.Y, 2))), (int)(middle.Y + Math.Sin(degrees * Math.PI / 180) * Math.Sqrt(Math.Pow(point.X - middle.X, 2) + Math.Pow(point.Y - middle.Y, 2))));
        }

        void nameBox_GotFocus(object sender, EventArgs e)
        {
            ((TextBox)sender).Text = "";
            ((TextBox)sender).ForeColor = Color.Black;
        }

        private void rotatePlane(double degrees)
        {
            double olddegrees=-degrees;
            degrees+=90;
            Point[] destinationPoints =
            {
                new Point((int)(planeposition.X+Math.Sin((degrees+135)*Math.PI/180)*(planediagonal)), (int)(planeposition.Y+Math.Cos((degrees+135)*Math.PI/180)*(planediagonal))),
                new Point((int)(planeposition.X+Math.Sin((degrees+45)*Math.PI/180)*(planediagonal)), (int)(planeposition.Y+Math.Cos((degrees+45)*Math.PI/180)*(planediagonal))),
                new Point((int)(planeposition.X+Math.Sin((degrees+225)*Math.PI/180)*(planediagonal)), (int)(planeposition.Y+Math.Cos((degrees+225)*Math.PI/180)*(planediagonal)))
            };
            Point middle = new Point((destinationPoints[0].X + destinationPoints[2].X) / 2, (destinationPoints[0].Y + destinationPoints[2].Y) / 2);
            middle = planeposition;
            for (int i = 0; i < originalZone.Count; i++)
            {
                Point pt = (Point)originalZone[i];

                collisionZone[i] = rotatePoint(middle, pt, olddegrees);
                
            }
            
            Graphics.FromImage(pictureBox1.Image).DrawImage(plane, destinationPoints);
            /*for (int i = 0; i < collisionZone.Count; i++)
            {
                Graphics.FromImage(pictureBox1.Image).FillRectangle(new SolidBrush(Color.Red), new Rectangle((Point)collisionZone[i], new Size(1, 1)));
            }*/
        }

        void updateScore()
        {
            tableLayoutPanel1.Controls.Clear();
            tableLayoutPanel1.RowCount = 0;
            tableLayoutPanel1.RowCount++;
            Label titlelabel = new Label();
            titlelabel.Name = "titlelabel";
            titlelabel.Text = "Highscore";
            titlelabel.Dock = DockStyle.Top;
            titlelabel.AutoSize = true;
            titlelabel.Font = new Font("Arial", 25, FontStyle.Bold);
            titlelabel.ForeColor = Color.Black;
            titlelabel.TextAlign = ContentAlignment.TopCenter;
            tableLayoutPanel1.Controls.Add(titlelabel, 0, 0);
            tableLayoutPanel1.SetColumnSpan(titlelabel, 2);
            tableLayoutPanel1.Visible = true;
            if (!System.IO.File.Exists(path + "highscore.txt"))
            {
                System.IO.File.WriteAllText(path + "highscore.txt", "");
            }
            string Highscore = System.IO.File.ReadAllText(path + "highscore.txt", Encoding.UTF8);
            string[] scores=Highscore.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < scores.Length; i++)
            {
                tableLayoutPanel1.RowCount++;
                for (int j = 0; j < 2; j++)
                {
                    Label label = new Label();
                    label.Text = scores[i].Split(new string[] { "\t" }, StringSplitOptions.None)[j];
                    label.AutoSize = true;
                    label.Dock = DockStyle.Top;
                    label.TextAlign = ContentAlignment.MiddleLeft;
                    label.Font = new Font("Arial", 20, FontStyle.Bold);
                    tableLayoutPanel1.Controls.Add(label, j, tableLayoutPanel1.RowCount-1);
                }
                highscorepoints.Add(Convert.ToInt64(scores[i].Split(new string[] { "\t" }, StringSplitOptions.None)[1]));
                highscorenames.Add(scores[i].Split(new string[] { "\t" }, StringSplitOptions.None)[0]);
            }
            nameBox = new TextBox();
            nameBox.Text = "Dein Name";
            nameBox.Dock = DockStyle.Bottom;
            nameBox.GotFocus += new EventHandler(nameBox_GotFocus);
            nameBox.ForeColor = Color.Gray;
            nameBox.Font = new Font("Arial", 20, FontStyle.Bold);
            Button replay = new Button();
            replay.Text = "Erneut spielen";
            replay.Dock = DockStyle.Bottom;
            replay.BackColor = SystemColors.ButtonFace;
            replay.AutoSize = true;
            replay.TextAlign = ContentAlignment.MiddleCenter;
            replay.Font = new Font("Arial", 20, FontStyle.Bold);
            replay.Click += new EventHandler(replay_Click);
            tableLayoutPanel1.RowCount++;
            tableLayoutPanel1.Controls.Add(nameBox, 0, tableLayoutPanel1.RowCount - 1);
            submitButton = new Button();
            submitButton.Text = "Eintragen";
            submitButton.AutoSize = true;
            submitButton.Font = new Font("Arial", 20, FontStyle.Bold); ;
            submitButton.Dock = DockStyle.Bottom;
            submitButton.TextAlign = ContentAlignment.MiddleCenter;
            submitButton.Click += new EventHandler(submitButton_Click);
            submitButton.BackColor = SystemColors.ButtonFace;
            tableLayoutPanel1.Controls.Add(submitButton, 1, tableLayoutPanel1.RowCount - 1);
            tableLayoutPanel1.RowCount++;
            tableLayoutPanel1.Controls.Add(replay, 0, tableLayoutPanel1.RowCount - 1);
            tableLayoutPanel1.SetColumnSpan(replay, 2);
        }

        void draw()
        {
            if (started)
            {
                bool collision = false;
                Image image = pictureBox1.Image;
                string debug = "Punktzahl: " + score.ToString();
                System.Random random = new Random();
                Graphics.FromImage(image).Clear(background);
                //Graphics.FromImage(pictureBox1.Image).DrawLine(new Pen(Color.Red), random.Next(pictureBox1.Width), random.Next(pictureBox1.Height), random.Next(pictureBox1.Width), random.Next(pictureBox1.Width));
                //Graphics.FromImage(pictureBox1.Image).DrawImage(plane, 10, 20, 150, 150);
                int Ychange=(int)(((double)Byte / (double)maxData) * (double)maxupfraction * (double)Formsize.Height);
                planeposition.Y -= Ychange;
                if (random.Next(30) == 5 && score >= scoretoreach)
                {
                    int top = random.Next(this.Height);
                    int width = random.Next(Formsize.Width / 100, Formsize.Width / 8);
                    int height = random.Next((int)((double)Formsize.Height * blockYfraction) + planesize + planesize / 3, this.Height - (int)((double)Formsize.Height * blockYfraction) - planesize - planesize / 3);
                    blocks.Add(new Rectangle(Formsize.Width, top, width, height));
                    blocktypes.Add((byte)1);
                    scoretoreach = score+ (long)((double)height / (double)25);
                }
                for (int i = 0; i < condensation.Count; i++)
                {
                    Point blockrect = (Point)condensation[i];
                    if (blockrect.X < -50)
                    {
                        condensation.RemoveAt(i);
                        i--;
                    }
                    else
                    {
                        blockrect.X -= (int)XSpeed;
                        condensation[i] = blockrect;
                    }
                }
                condensation.Add(new Point(planeposition.X, planeposition.Y));
                if (condensation.Count > 1)
                {
                    Graphics.FromImage(image).DrawCurve(new Pen(Color.FromArgb(150, Color.White), 10), (Point[])condensation.ToArray(typeof(Point)));
                }
                int left = 0;
                int downleft = 0;
                for (int i = 0; i < originalZone.Count; i++)
                {
                    Point pt = (Point)originalZone[i];
                    pt.Y -= Ychange;
                    originalZone[i] = pt;
                }
                for (int i = 0; i < blocks.Count; i++)
                {
                    Graphics.FromImage(image).FillRectangle(new SolidBrush(Color.LightGray), (Rectangle)blocks[i]);
                    Rectangle blockrect = (Rectangle)blocks[i];
                    if (blockrect.X + blockrect.Width < 0)
                    {
                        blocks.RemoveAt(i);
                        blocktypes.RemoveAt(i);
                        i--;
                    }
                    else
                    {
                        blockrect.X -= (int)XSpeed;
                        blocks[i] = blockrect;
                        if ((byte)blocktypes[i] == 0)
                        {
                            if (blockrect.X + blockrect.Width > left)
                            {
                                left = blockrect.X + blockrect.Width;
                            }
                        }
                        if ((byte)blocktypes[i] == 2)
                        {
                            if (blockrect.X + blockrect.Width > downleft)
                            {
                                downleft = blockrect.X + blockrect.Width;
                            }
                        }
                    }
                }
                while (left < Formsize.Width)
                {
                    int width = random.Next(20, (int)(blockXfraction * (double)Formsize.Width));
                    blocks.Add(new Rectangle(left, 0, width, random.Next((int)((double)Formsize.Height * blockYfraction) / 10, (int)((double)Formsize.Height * blockYfraction))));
                    blocktypes.Add((byte)0);
                    left += width;
                }
                while (downleft < Formsize.Width)
                {
                    int width = random.Next(20, (int)(blockXfraction * (double)Formsize.Width));
                    int height = random.Next((int)((double)Formsize.Height * blockYfraction) / 10, (int)((double)Formsize.Height * blockYfraction));
                    blocks.Add(new Rectangle(downleft, Formsize.Height-height, width, height));
                    blocktypes.Add((byte)2);
                    downleft += width;
                }
                rotatePlane(rotation);
                Graphics.FromImage(image).DrawString(debug, new System.Drawing.Font("Arial", 15), new SolidBrush(Color.Black), new Point(10, 10));
                pictureBox1.Refresh();
                for (int i = 0; i < blocks.Count; i++)
                {
                    Rectangle blockrect = (Rectangle)blocks[i];
                    for (int j = 0; j < collisionZone.Count; j++)
                    {
                        if (((Point)collisionZone[i]).X > blockrect.X && ((Point)collisionZone[i]).X < blockrect.X + blockrect.Width && ((Point)collisionZone[i]).Y > blockrect.Y && ((Point)collisionZone[i]).Y < blockrect.Y + blockrect.Height && !collision)
                        {
                            timer1.Stop();
                            collision = true;
                            System.Windows.Forms.Cursor.Show();
                            System.Windows.Forms.DialogResult result=MessageBox.Show("Du bist mit einem unbekannten Objekt kollidiert, dein Flugzeug ist nur noch Schrott.\n\nImmerhin hast du "+score.ToString()+" Punkte erreicht.\n\nMöchtest du dich in die Highscore eintragen?", "GAME OVER", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                            if (result == System.Windows.Forms.DialogResult.Yes)
                            {
                                
                                updateScore();
                                
                            }
                            else
                            {
                                load();
                            }
                        }
                    }
                }
                score++;
                if (score % 100 == 0)
                {
                    XSpeed = startspeed + score / 100;
                }
            }
        }

        void replay_Click(object sender, EventArgs e)
        {
            load();
        }

        void submitButton_Click(object sender, EventArgs e)
        {
            string highscorestring = "";
            bool inserted = false;
            for (int i = 0; i < highscorepoints.Count; i++)
            {
                if (score > (long)highscorepoints[i] && !inserted)
                {
                    highscorestring += nameBox.Text + "\t" + score.ToString() + "\r\n";
                    inserted = true;
                }
                highscorestring += (string)highscorenames[i] + "\t" + (long)highscorepoints[i] + "\r\n";
            }
            if (!inserted)
            {
                highscorestring += nameBox.Text + "\t" + score.ToString() + "\r\n";
                inserted = true;
            }
            System.IO.File.WriteAllText(path + "highscore.txt", highscorestring, Encoding.UTF8);
            updateScore();
            submitButton.Enabled=false;
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            draw();
           
        }

        private void drawThread()
        {
            while (true)
            {
                draw();
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
        }

        private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
        {
            while (serialPort1.BytesToRead >= 3)
            {
                serialPort1.ReadByte();
                serialPort1.ReadByte();
                oldByte=Byte+maxData;
                Byte=serialPort1.ReadByte();
                
                //MessageBox.Show(Byte.ToString());
                if (!started && Byte != oldByte)
                {
                    started = true;
                }
                Byte -= maxData;
                rotation = (double)(Byte * maxDegrees / (double)maxData);
                //rotation = Byte;
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            serialPort1.Dispose();
            serialPort1.Close();
        }

        void load()
        {
            highscorenames = new ArrayList();
            highscorepoints = new ArrayList();
            tableLayoutPanel1.Visible = false;
            score = 0;
            scoretoreach = 0;
            started = false;
            oldByte = -1;
            XSpeed = (double)10 / (double)1000;
            rotation = 0;
            this.BackColor = background;
            System.Windows.Forms.Cursor.Hide();
            blocktypes = new ArrayList();
            condensation = new ArrayList();
            blocks = new ArrayList();
            Formsize = this.Size;
            XSpeed *= Formsize.Width;
            screenmiddle = new Point((int)((double)Formsize.Width * leftfraction), Formsize.Height / 2);
            collisionZone = new ArrayList();
            originalZone = new ArrayList();
            planeposition = screenmiddle;
            plane = System.Drawing.Image.FromFile(path + "falcon.png");
            plane = plane.GetThumbnailImage((int)((double)Formsize.Width * planefraction), (int)((double)Formsize.Width * planefraction), null, IntPtr.Zero);
            planesize = plane.Width;
            planediagonal = Math.Sqrt((double)(planesize * planesize + planesize * planesize)) / (double)2;
            System.Drawing.Bitmap planeMap = new Bitmap(plane);
            Bitmap = new System.Drawing.Bitmap(pictureBox1.Width, pictureBox1.Height);
            pictureBox1.Image = Bitmap;
            for (int y = 0; y < plane.Height; y++)
            {
                for (int x = 0; x < plane.Width; x++)
                {
                    if (planeMap.GetPixel(x, y).A > 1 && planeMap.GetPixel(x, y).A < 255)
                    {
                        collisionZone.Add(new Point(screenmiddle.X - planesize / 2 + x, screenmiddle.Y - planesize / 2 + y));
                        originalZone.Add(new Point(screenmiddle.X - planesize / 2 + x, screenmiddle.Y - planesize / 2 + y));
                    }
                }
            }
            //originalZone = collisionZone;
            plane = planeMap;

            startspeed = XSpeed;
            timer1.Start();
            rotatePlane(0);
        }

        private void Form1_Shown(object sender, EventArgs e)
        {
            load();
            System.Windows.Forms.Cursor.Show();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            serialPort1.PortName = textBox1.Text;
            serialPort1.Open();
            System.Windows.Forms.Cursor.Hide();
            textBox1.Dispose();
            button1.Dispose();
        }
    }
}

Quelltext NXC

#define motor OUT_C
#define touch S4
#define BT 0

/*
Zuordnungen:
 45° -> 100%
  0° ->   0%
*/

byte buffer[1];
byte number;
int rotation;

int max=45;

task main()
{
   SetLongAbort(true);
   TextOut(0, LCD_LINE1, "Game Joystick");
   TextOut(0, LCD_LINE2, "(Motor C)");
   TextOut(0, LCD_LINE4, "Kalibrieren...");
   until(ButtonPressed(BTNCENTER, true));
   ResetRotationCount(motor);
   //PlayTone(440, 200);
   TextOut(0, LCD_LINE5, "OK");
   while(true)
   {
       rotation=MotorRotationCount(motor)%360;
       if(rotation > max)
       {
          rotation=max;
       }
       if(rotation < -max)
       {
          rotation=-max;
       }
       number=max+rotation;
       buffer[0]=number;
       BluetoothWrite(0, buffer);
       NumOut(0, LCD_LINE7, number);
       Wait(50);
   }
}

Downloads

Einfache, ausführbare Version oder Version mit Quelltext

Bookmark the permalink.

Leave a Reply

Your email address will not be published.