How to make an object "scalable" while rendered in a form
Asked Answered
S

2

8

I am rendering my game in a Winform in the same way as done in this sample: WinForms Series 1: Graphics Device

In my game I have some object, for example a rectangle that I can already put and move, in my game world, once created. My project here is a level-editor.

What I want to do is to make every object "sizable" or "scalable" (sorry if this isn't the correct word) in the same way as done in every software we commonly use, I mean: enter image description here

I have a class like:

public abstract class GameObject
{
    protected Vector2 position_ = Vector2.Zero;
    protected float rotation_ = 0.0f;
    protected Vector2 scale_ = Vector2.One;
    protected float depth_ = 0.0f;

    protected bool is_passable_ = true;

    protected GameObject(
        Vector2 starting_position)
    {
        this.position_ = starting_position;
    }

    [DisplayName("Position")]
    public virtual Vector2 Position
    {
        get { return position_; }
        set { position_ = value; }
    }

    [BrowsableAttribute(false)]
    public abstract Rectangle PositionRectangle
    {
        get;
    }

    [BrowsableAttribute(false)]
    public abstract Rectangle SelectionRectangle
    {
        get;
    }

    [DisplayName("Scale")]
    public abstract Vector2 Scale
    {
        get;
        set;
    }

    [BrowsableAttribute(false)]
    public virtual float Depth
    {
        get { return depth_; }
        set { depth_ = value; }
    }

    [DisplayName("IsPassable?")]
    public bool IsPassable
    {
        get { return is_passable_; }
        set { is_passable_ = value; }
    }

    [BrowsableAttribute(false)]
    public abstract Vector2 TextureSize
    {
        get;
    }

    public abstract void Update(GameTime gameTime);
    public abstract void Draw(SpriteBatch spriteBatch);
}

Once the class is instantiated, inside the form I thought to do something like: (gameWrapper is the control created with the sample to draw the game inside the form)

private void gameWrapper_MouseClick_1(object sender, MouseEventArgs e)
{
    Vector2 mouse_xy = new Vector2(e.Location.X, e.Location.Y);
    GameObject obj = gameWrapper.GetObjectByPosition(mouse_xy);
    propertyGrid1.SelectedObject = obj;
    if (obj != null)
        gameWrapper.SelectObject(obj);
    else gameWrapper.Unselect();

    propertyGrid1.Refresh();
 }

Inside gameWrapper:

public SelectObject(GameObject obj)
{
     List<Vector2> 4verticesList = new List();
     //
     // Code to add 4 vertices coordinates of the SelectionRectangle to 4verticesList
     //         

     foreach (Vector2 vertex_xy in 4VerticesList)
        DrawLittleRectangle(vertex_xy);
}

This is just what I thought to do. Draw little buttons/rectangles with a function and then handle clicks to them.

Is there already written some code to achieve this behaviour? Actually I'm not worried about how the object will resize, but just to the estetic buttons.

Specie answered 1/1, 2014 at 15:46 Comment(1)
I'll randomly guess that Graphics.ScaleTransform() is the answer. Post code instead of pictures.Caracalla
S
6

I've done it!

The main function:

private void DrawObjectSelection(SpriteBatch spriteBatch, Rectangle r)
{
    r = Telecamera.Transform(r);

    Vector2 v1 = new Vector2(r.X, r.Y);
    Vector2 v2 = new Vector2(r.X + r.Width, r.Y);
    Vector2 v3 = new Vector2(r.X, r.Y + r.Height);
    Vector2 v4 = new Vector2(r.X + r.Width, r.Y + r.Height);

    //The side rectangle
    DrawEmptyRectangle(spriteBatch, v1, v2, v3, v4);

    //4 squares at vertices
    DrawFilledSquare(spriteBatch, v1);
    DrawFilledSquare(spriteBatch, v2);
    DrawFilledSquare(spriteBatch, v3);
    DrawFilledSquare(spriteBatch, v4);

    //the other 4 in the middle of every side
    float height = v4.Y - v1.Y;
    float width = v2.X - v1.X;

    DrawFilledSquare(spriteBatch, new Vector2(v1.X, v1.Y + height / 2));
    DrawFilledSquare(spriteBatch, new Vector2(v2.X, v2.Y + height / 2));
    DrawFilledSquare(spriteBatch, new Vector2(v1.X + width / 2, v1.Y));
    DrawFilledSquare(spriteBatch, new Vector2(v1.X + width / 2, v4.Y));
}

With these functions:

private void DrawLine(
    SpriteBatch spriteBatch,
    float width,
    Vector2 point1, Vector2 point2)
{
    float angle = (float)Math.Atan2(point2.Y - point1.Y, point2.X - point1.X);
    float length = Vector2.Distance(point1, point2);

    spriteBatch.Draw(
        grid_texture,
        point1,
        null,
        selection_color,
        angle,
        Vector2.Zero,
        new Vector2(length, width),
        SpriteEffects.None,
        0);
}

private void DrawEmptyRectangle(
    SpriteBatch spriteBatch,
    Vector2 v1,
    Vector2 v2,
    Vector2 v3,
    Vector2 v4)
{
    /*
     * V1****V2
     * *      *
     * *      *
     * V3****V4
     */

    DrawLine(spriteBatch, 1.0f, v1, v2);
    DrawLine(spriteBatch, 1.0f, v1, v3);
    DrawLine(spriteBatch, 1.0f, v2, v4);
    DrawLine(spriteBatch, 1.0f, v3, v4);
}

private void DrawFilledSquare(
    SpriteBatch spriteBatch,
    Vector2 c_pos) //With center position
{
    int lato = 8;

    spriteBatch.Draw(
        grid_texture,
        new Rectangle(
            (int)c_pos.X - lato/2,
            (int)c_pos.Y - lato/2,
            lato,
            lato),
            selection_color);

}

When I want to draw it, I just need a rectangle, for example:

//...

DrawObjectSelection(spriteBatch, Camera.Transform(gameObject1.PositionRectangle));

//...

The only thing missing is Handling of clicks on every square. This is done by a simple "Contains" test with mouse position coor.

A screen of the result:

A screen of the result

Specie answered 6/1, 2014 at 10:59 Comment(0)
F
1

I think what you are looking for is something like CRectTracker (http://msdn.microsoft.com/en-us/library/41731bbw.aspx) in VC++. Unfortunately there is no C# equivalent still available. You could look into the below link for a starter.

http://www.codeproject.com/Articles/8765/C-Rect-Tracker

Fantasm answered 10/1, 2014 at 19:1 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.