Как я мог сделать картинную коробку, чтобы стать платформой, в которую может прыгнуть мой игрок? - PullRequest
0 голосов
/ 09 октября 2018

У меня уже есть движение игрока и прыжок с использованием таймера с интервалом 1 мс, и моя проблема в том, что я не могу сделать графический блок, чтобы стать платформой, вот мой код движения моего персонажа

public partial class Form1 : Form
{
    bool left, right;
    bool jump;
    int G = 20;
    int Force;


    public Form1()
    {
        InitializeComponent();

    }

    private void Form1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Right) { right = true; }
        if (e.KeyCode == Keys.Left) { left = true; }

        if (jump != true)
        {
            if (e.KeyCode == Keys.Space)
            {
                jump = true;
                Force = G;
            }
        }
    }

    private void Form1_KeyUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Right) { right = false; }
        if (e.KeyCode == Keys.Left) { left = false; }
    }

    private void timer1_Tick(object sender, EventArgs e)
    {

        if (right == true) { player.Left += 5; }
        if (left == true) { player.Left -= 5; }

        if (jump == true)
        {
            //Falling (if the player has jumped before)
            player.Top -= Force;
            Force -= 1;
        }

        if (player.Top + player.Height >= screen.Height)
        {
            player.Top = screen.Height - player.Height; //Stop falling at bottom
            jump = false;
        }
        else
        {
            player.Top += 5;//Falling 
        } 
    }
}

Я использую winforms для создания этой игры, потому что это то, что требуется.

Ответы [ 2 ]

0 голосов

Вы можете проверить код самостоятельно.Я добавил 3 pictureboxes в моей форме.Просто для упрощения дела форма не развернута.

enter image description here

Код:

bool left, right;
bool jump;
int G = 20;
int Force;
List<Rectangle> obstacles = new List<Rectangle>();

Добавить obstacles:

public Form1() {
    InitializeComponent();

    obstacles.Add( new Rectangle( pictureBox1.Left, pictureBox1.Top, pictureBox1.Width, pictureBox1.Height ) );
    obstacles.Add( new Rectangle( pictureBox2.Left, pictureBox2.Top, pictureBox2.Width, pictureBox2.Height ) );
    obstacles.Add( new Rectangle( pictureBox3.Left, pictureBox3.Top, pictureBox3.Width, pictureBox3.Height ) );
    obstacles.Add( new Rectangle( -1, 0, 1, this.ClientSize.Height ) ); //left border of form
    obstacles.Add( new Rectangle( this.ClientSize.Width, 0, 1, this.ClientSize.Height ) ); //right border of form
    obstacles.Add( new Rectangle( 0, this.ClientSize.Height, this.ClientSize.Width, 1 ) ); //down border of form
    obstacles.Add( new Rectangle( 0, -1, this.ClientSize.Height, 1 ) ); //up border of form

}

и в tick событие:

private void timer1_Tick( object sender, EventArgs e ) {
    Rectangle playerClone = player.Bounds; // new Rectangle( player.Left, player.Top, player.Width, player.Height );
    List<int> list = new List<int>();

    if( left == true ) {
        playerClone.X -= 5;

        //Check if we have left colision
        int pos = GetIntersectPosL( playerClone );

        if( pos >= 0 ) { //there is a colision
            playerClone.X = pos;
        }
    }
    else if( right == true ) {
        playerClone.X += 5;

        //Check if we have right colision
        int pos = GetIntersectPosR( playerClone );

        if( pos >= 0 ) { //there is a colision
            playerClone.X = pos - playerClone.Width;
        }
    }

    if( jump == true ) {
        playerClone.Y -= (Force - 5); //the 5 is from falling.

        if( Force - 5 >= 0 ) { //going up
            //Check if we have up colision, if the top of the player is colliding with anything
            int pos = GetIntersectPosU( playerClone );

            if( pos >= 0 ) { //there is a colision
                playerClone.Y = pos;
            }
        }
        else { //Falling down
            //Check if we have down colision, if the bottom of the player is colliding with anything
            int pos = GetIntersectPosD( playerClone );

            if( pos >= 0 ) { //there is a colision
                playerClone.Y = pos - playerClone.Height;

                jump = false;
            }
        }

        Force -= 1;
    }
    else { //Falling without previous jumping
        playerClone.Y += 5;

        //Check if we have down colision, if the bottom of the player is colliding with anything
        int pos = GetIntersectPosD( playerClone );

        if( pos >= 0 ) { //there is a colision
            playerClone.Y = pos - playerClone.Height;
        }

    }

    player.Bounds = playerClone;
}

private int GetIntersectPosL(Rectangle src) {
    List<int> list = new List<int>();

    //Get all intersect rectangles and add the right side to the list
    for( int i = 0; i < obstacles.Count; i++ ) {
        if( src.IntersectsWith( obstacles[ i ] ) == true ) {
            list.Add( obstacles[ i ].Right );
        }
    }

    if( list.Count == 0 ) { //no intersect
        return -1;
    }

    return list.Max();
}

private int GetIntersectPosR( Rectangle src ) {
    List<int> list = new List<int>();

    //Get all intersect rectangles and add the left side to the list
    for( int i = 0; i < obstacles.Count; i++ ) {
        if( src.IntersectsWith( obstacles[ i ] ) == true ) {
            list.Add( obstacles[ i ].Left );
        }
    }

    if( list.Count == 0 ) { //No intersect
        return -1;
    }

    return list.Min();
}

private int GetIntersectPosD( Rectangle src ) {
    List<int> list = new List<int>();

    //Get all intersect rectangles and add the top side to the list
    for( int i = 0; i < obstacles.Count; i++ ) {
        if( src.IntersectsWith( obstacles[ i ] ) == true ) {
            list.Add( obstacles[ i ].Top );
        }
    }

    if( list.Count == 0 ) { //No intersect
        return -1;
    }

    return list.Min();
}

private int GetIntersectPosU( Rectangle src ) {
    List<int> list = new List<int>();

    //Get all intersect rectangles and add the bottom side to the list
    for( int i = 0; i < obstacles.Count; i++ ) {
        if( src.IntersectsWith( obstacles[ i ] ) == true ) {
            list.Add( obstacles[ i ].Bottom );
        }
    }

    if( list.Count == 0 ) { //No intersect
        return -1;
    }

    return list.Max();
}
0 голосов
/ 09 октября 2018

Э-э, я полагаю, что это домашнее задание, поскольку вы делаете игру в winforms, поэтому я не буду писать вам код, но расскажу, как идет рабочий процесс.

Поскольку у вас есть часть движения, я не буду это объяснять.

То, что вы ищете, это Colliding.Что это означает, когда два объекта fictional borders сталкиваются, что делать (например, когда они касаются себя).

Fictional borders называются Colliders, и вам нужно создать collider дляваш player и для какого-то объекта.Collider может быть одним объектом (квадратом) или несколькими объектами (несколько квадратов, кружков ....).Для этого примера мы создадим colliders с простыми квадратами, так как ваша игра 2d.

Как вы видите, мы создали коллайдер для игрока (зеленый) и коллайдер для объекта (желтый).

Как видите, игроки сталкиваются с коллайдером объектов.В тот момент, когда эти два сталкиваются, мы поднимаем событие и что-то делаем.

У этого есть много решений, некоторые лучше, чем у других, но есть два простых решения, которые вы можете сделать, это следующее:

  • Применение силы противоположного направления
  • Перемещение в предыдущее местоположение

Применение силы противоположного направления - сложная вещь, и вам необходимо проверить, где сталкивался коллайдер, а затем переместить объект в этом направлении (так как вы не всегда будете стоять на объекте, но вы можете, например, удариться о стену), и для этого требуется некоторый код, который не подходит для начинающего, который делает это только для практики winforms.

простое решение для вас и будет сделано так:

  • Каждые 5 мс, которые вы помните текущую позицию игроков
  • Каждые 1 мс вы проверяете, сталкивается ли это с чем-то
  • Если этопри столкновении вы перемещаете его обратно на последнюю запомненную позицию.

Теперь вы спрашиваете, почему нужно помнить каждые 5 мс, но не 1 мs.Это потому, что если что-то случится и коллайдер не обнаружит столкновение, но столкнулось, игрок запомнит эту позицию, а когда произойдет столкновение, он вернется к последней сохраненной позиции, но она уже находится внутри стены.Таким образом, мы уменьшаем шансы на это.Конечно, вы тестируете и видите, что подходит вам больше всего.Также этот пример создаст замедленное движение, но, тем не менее, вы не сможете сделать настоящую игру там.

Это только простое решение для выполнения этой работы, но оно не рекомендуется.

Если вы хотитеБолее сложные и точные решения. В Интернете много статей, и я бы посоветовал вам посмотреть, как работает Unity 2d collision, и перевести это в ваш код.

Поскольку я заинтересовался делать это в winforms, у меня естьтакже сделал это.

Вот код, который я использовал:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;

namespace Game
{
    public partial class Form1 : Form
    {
        Player player;
        Obsticle obsticle;

        Thread UpdateThread;

        public const int Gravity = 1;

        public Form1()
        {
            InitializeComponent();
            InitializeObjects();

            UpdateThread = new Thread(() => {
                System.Timers.Timer UpdateTimer = new System.Timers.Timer();
                UpdateTimer.Elapsed += new System.Timers.ElapsedEventHandler(Update);
                UpdateTimer.Interval = 2;
                UpdateTimer.Enabled = true;                
            });
            UpdateThread.Start();
        }

        private void InitializeObjects()
        {
            PictureBox pb = new PictureBox();
            pb.BackgroundImage = global::Game.Properties.Resources.SuperMario;
            pb.BackgroundImageLayout = ImageLayout.Stretch;
            pb.Location = new Point(47, 59);
            pb.Name = "Player";
            pb.Size = new Size(76, 72);
            pb.TabIndex = 0;
            pb.TabStop = false;
            player = new Player(this, pb);

            PictureBox pb1 = new PictureBox();
            pb1.BackgroundImage = global::Game.Properties.Resources.Box;
            pb1.BackgroundImageLayout = ImageLayout.Stretch;
            pb1.Location = new Point(47, 226);
            pb1.Name = "Obsticle";
            pb1.Size = new Size(100, 95);
            pb1.TabIndex = 0;
            pb1.TabStop = false;
            obsticle = new Obsticle(this, pb1);
        }
        private void Update(object sender, ElapsedEventArgs e)
        {
            player.ApplyGravity(Gravity);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            player.Collider.DrawCollider(e.Graphics);
            obsticle.Collider.DrawCollider(e.Graphics);
        }
    }

    public class Object
    {
        public static List<Object> Objects = new List<Object>();

        public Form Handler;
        public PictureBox Picture { get; set; }
        public BoxCollider Collider { get; set; }

        public int x
        {
            get
            {
                return _x;
            }
            set
            {
                _x = value;
                Handler.Invoke(new Action(() => {
                    Picture.Location = new Point((int)_x, Picture.Location.Y);
                    Handler.Refresh();
                }));
            }
        }
        public int y
        {
            get
            {
                return _y;
            }
            set
            {
                _y = value;
                Handler.Invoke(new Action(() => {
                    Picture.Location = new Point(Picture.Location.X, _y);
                    Handler.Refresh();
                }));
            }
        }

        private int _x;
        private int _y;

        public Object(Form handler, PictureBox Picture)
        {
            this.Handler = handler;
            this.Picture = Picture;

            _x = Picture.Location.X;
            _y = Picture.Location.Y;

            handler.Controls.Add(Picture);

            Collider = new BoxCollider(this);

            Objects.Add(this);
        }

        public void ApplyGravity(int gravityForce)
        {
            if (Collider.CheckCollide())
                return;
            y += gravityForce;
        }
    }
    public class Player : Object
    {
        public int movementSpeed { get { return _movementSpeed; } }
        private int _movementSpeed = 10;

        public Player(Form handler, PictureBox Picture) : base(handler, Picture)
        {
        }

        public void MoveDown(int value)
        {
            y += value;
        }
    }
    public class Obsticle : Object
    {
        public Obsticle(Form handler, PictureBox Picture) : base(handler, Picture)
        {
        }
    }

    public class BoxCollider
    {
        private Pen Pen_Default = new Pen(Color.Red);
        private Object Object;
        private Rectangle rect;

        public BoxCollider(Object Object)
        {
            this.Object = Object;
        }

        public bool CheckCollide()
        {
            foreach(Object o in Object.Objects)
            {
                if (rect.IntersectsWith(o.Collider.rect) && o.Collider.rect != rect)
                    return true;
            }
            return false;
        }

        public void DrawCollider(Graphics g)
        {
            rect = new Rectangle(Object.Picture.Location.X, Object.Picture.Location.Y, Object.Picture.Width, Object.Picture.Height);
            Pen_Default.Width = 5;
            g.DrawRectangle(Pen_Default, rect);
        }
    }
}

У него нет механизма перемещения, так как я только хотел проверить столкновение.Вы получите ошибку для ресурсов, если скопируете / вставите их, просто добавьте 2 изображения и протестируйте их:)

Смысл в этом коде заключается в том, что перед изменением любой переменной позиции вам нужно вызвать if (Collider.CheckCollide)()) вернуть;поэтому, когда он сталкивается, он не будет перемещать объект.Также вы можете реализовать типы Collider, чтобы сообщить, что некоторые объекты сталкиваются с другими (например, бонусы)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...