• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Koobazaur

C# - reference to a variable?

12 posts in this topic

I am learning C# right now, coming from C++, and encountering a problem. I have a Form class that has a bitmap called DrawArea that it draws to the screen OnPaint. Further, I have a Renderer object that stores a reference to that DrawArea so it can draw to it. What I do is I pass the DrawArea to my Renderer, by reference, and set it to Renderer's private variable. Thus, the Renderer has a reference that points to the instance of DrawArea. This, however, is NOT what I want. You see, when my window resize, I delete my DrawArea and recreate it. Hence, when that happens, the Renderer's reference points to a, now obsolete, Bitmap*. Is there any way to have a reference point to an actual variable (other reference), rather than an instance in memory? Or do I need to use the "unsafe" pointers? Also can I return a reference via a function? how? (gah, I really dislike the C#'s referencing model ><) Btw, here's my code:
    /// <summary>
    /// This class takes care of rendering out TMEngine components to the screen
    /// </summary>
    class Renderer
    {
        //=========================================================================
        // Public
        //=========================================================================
        
        
        public Renderer(ref Bitmap DrawArea, ref cEntityManager EntityManager, ref cTimer Timer)
            {
            _DrawArea = DrawArea; //this doesn't do what I want
            _rEntityManager = EntityManager;
            _rTimer = Timer;
            
            }
            
            
        public void Update()
            {
                
                Graphics Graph = Graphics.FromImage(_DrawArea); // this throws exception if the DrawArea I passed in constructor gets deleted and re-created

                Pen MyPen = new Pen(Color.Blue); //yaya I know would be more efficient to story this as private member, but optimizations come later

                Graph.DrawEllipse(MyPen, 0, 0, 10, 10);

                MyPen.Dispose();            
            
            }

        //=========================================================================
        // Private 
        //=========================================================================
        private Bitmap _DrawArea;
        private cEntityManager _rEntityManager;
        private cTimer _rTimer;
        
    }


*as a sidenote, I get an exception when I try to modify that bitmap after reference - I thoguht C# did auto-garbage collection and would not delete the bitmap as long as I had some reference pointing to it...
0

Share this post


Link to post
Share on other sites
I asked this question recently (along with a hackish solution). Though one of the suggestions in there for a wrapper class will work here since the type isn't varying and you don't need closure sort of behavior.


public class KoobazaurBitmap{
public Bitmap Value;
}

public class Renderer{
private KoobazaurBitmap drawingArea;
}

public class Window{
private KoobazaurBitmap drawingArea;
private Renderer internalRenderer;
public Window(){
// create drawingArea;
internalRenderer = new Renderer(drawingArea,...);
}
public void Resize(Rectangle area){
drawingArea.Value = new Bitmap(...with new area...);
// drawingArea remains constant, but its data changes.
}
}



And C# won't collect something if there's a reference to it, so the exception is from something else. C# doesn't have **ptr sort of behavior unfortunately, but once you pickup the patterns and flow of the language that construct doesn't really ever come up.
0

Share this post


Link to post
Share on other sites
Hmmm "that construct doesn't ever come up." How then should I have avoided the problem? Is my approach of "The Renderer knows about the surface it draws to" inherently wrong and should be changed to something like "The Renderer queries for the draw surface every render" or even "The Renderer has the draw surface himself" ?
0

Share this post


Link to post
Share on other sites
Without knowing the particulars of your situation or the GDI stuff, I can't say. My renderer doesn't much care about the form beyond resizing (which it listens to via the form's events).

A quick look and it seems the renderer should have a reference to the form (which in turn has a reference to its drawing area) rather than directly to the drawing area.
0

Share this post


Link to post
Share on other sites
Quote:
really dislike the C#'s referencing model ><)


That's because you are doing it incorrectly. You do not need any of those "ref" keywords that you included.

http://forums.xna.com/thread/40480.aspx
http://msdn2.microsoft.com/en-us/library/14akc2c7(VS.80).aspx

In short: "ref" means to pass the VARIABLE by reference, not the object it points to. All reference types are, automatically, passed by reference. This means that returning a value is also automatically by reference!
0

Share this post


Link to post
Share on other sites
SnprBoB86, if you read my original post you will notice that passing the variable by reference is exactly what I wanted, hence I used ref correctly. It's just that I cannot set another variable to reference that variable, only the memory it points to.

And Telastyn, thanks for the feedback. I've changed my renderer to refer to the form as opposed to its drawing area.

Out of curiosity, how did you do the "listening to forms events" thing? In my case, does it simply mean the Form calling my Renderer in the OnResize event, or do you mean something else?

Blargh, maybe I just need to take the time to adjust to the new reference vs value variable model. Sure, maybe C++ is ladden with memory voulnerabilities and unsafe code but, damn, at least when I had ** ppSomething I knew exactly what was going on instead of having to wonder what is referencing what (not to mention extra flexibility). And wtf is up with the lack of template, errr, generic specialization? Seriously...
0

Share this post


Link to post
Share on other sites
Yeah, generic specialization (and template fu in general) is one of the things C++ does have going for it. And adjusting to the reference model does take a little bit of time. After that though it's nice to not have to worry about what level of indirection you're at or if you need to worry about who owns what.

I mean something like that. Conceptually, it's better to think of it as having the Renderer listen/hook onto the Form's Resize (or perhaps Begin or EndResize) event, since Resize will always be triggered and the OOP "who knows what" goes from the Renderer to the Form.


public class Renderer{

// We'll use the odd signature to match the event's
protected void FormResizeHandler( object Form, EventArgs Args ){
// reset Bitmap, handle other stuff
}

public Renderer( Form drawTarget ){
drawTarget.Resize += FormResizeHandler;
}
}




Renderer::FormResizeHandler will now get called whenever the form resizes.

(one thing to note, registering for an event like this provides a reference to a Renderer instance in Form so it won't be collected. You'll need to de-register or else Renderer will stick around as long as form does. Sometimes this is useful, sometimes it leads to a psuedo-memory leak)
0

Share this post


Link to post
Share on other sites
Hi guys,

Just had a quick read of your question and came up with this solution:

Instead of storing a Bitmap in the MainForm and a Renderer in the MainForm that references both the MainForm and the Bitmap, why not make some sort of visual renderer component that can sit within the form?

What I mean is, extend the MS PictureBox control (which has an image as a property) and then build your render around it. Then you can just drag this into the MainForm. Also, the PictureBox has an OnResize you can override which will fire when the MainForm is resized. Here's some code:


/// <summary>
/// This class takes care of rendering out TMEngine components to the screen.
/// </summary>
public class Renderer : PictureBox
{
#region Fields
// Entity manager.
private cEntityManager _entityManager = null;

// Timer.
private cTimer _timer = null;
#endregion


#region Properties
/// <summary>
/// This property is used to set / get the entity manager.
/// </summary>
public cEntityManager EntityManager
{
get { return _entityManager; }
set { _entityManager = value; }
}

/// <summary>
/// This property is used to set / get the timer.
/// </summary>
public cTimer Timer
{
get { return _timer; }
set { _timer = value; }
}

/// <summary>
/// This property is used to set / get the draw area.
/// </summary>
public System.Drawing.Bitmap DrawArea
{
get { return this.Image; }
set { this.Image = value; }
}
#endregion

#region Methods
/// <summary>
/// Default constructor.
/// </summary>
public Renderer()
{

}

/// <summary>
/// Constructor used to setup the renderer.
/// </summary>
/// <param name="entityManager">Entity manager.</param>
/// <param name="timer">Timer.</param>
public Renderer(cEntityManager entityManager, cTimer timer)
: this()
{
this.EntityManager = entityManager;
this.Timer = timer;
}

/// <summary>
/// This method is called when the picture box is resized.
/// </summary>
/// <param name="e">Default event arguments.</param>
protected override void OnResize(EventArgs e)
{
// Call the base method
base.OnResize(e);

// Update the renderer
this.Update();
}

/// <summary>
/// Update method.
/// </summary>
public void Update()
{
Graphics Graph = Graphics.FromImage(this.Image);
Pen MyPen = new Pen(Color.Blue);
Graph.DrawEllipse(MyPen, 0, 0, 10, 10);
MyPen.Dispose();
}
#endregion
}



If this isn't what you need then sorry, just thought it might help with the OO side of things!

James
0

Share this post


Link to post
Share on other sites

public Renderer(ref Bitmap DrawArea, ref cEntityManager EntityManager, ref cTimer Timer)
{
_DrawArea = DrawArea; //this doesn't do what I want
_rEntityManager = EntityManager;
_rTimer = Timer;

}



No, this is incorrect usage of "ref". You are not changing DrawArea, EntityManager, or Timer. Remove the ref keyword from all three and you will find that the code behaves 100% identically.

Examine this test code:



using System;
using System.Collections.Generic;

class UsingRef
{

static void AddTwo(int y)
{
y += 2;
}

static void AddTwo(ref int y)
{
y += 2;
}

static void AppendTwo(List<int> b)
{
b.Add(2);
b = null;
}

static void AppendTwo(ref List<int> b)
{
b.Add(2);
b = null;
}

public static void Main()
{

int x = 5;
List<int> a = new List<int>();


AddTwo(x);
Console.WriteLine(x);
AddTwo(ref x);
Console.WriteLine(x);


AppendTwo(a);
Console.WriteLine(a == null ? "null" : a.Count.ToString());
AppendTwo(ref a);
Console.WriteLine(a == null ? "null" : a.Count.ToString());


Console.ReadLine();

}

}



Additionally, a nitpicky comment: your capitalization and naming conventions do not match the standard guidelines. Google-up the .net guidelines.
0

Share this post


Link to post
Share on other sites
Quote:
Original post by Koobazaur
Sure, maybe C++ is ladden with memory voulnerabilities and unsafe code but, damn, at least when I had ** ppSomething I knew exactly what was going on instead of having to wonder what is referencing what (not to mention extra flexibility).
Keep in mind how long it took you to understand how that worked, though. C# is preposterously easy and very elegant once it clicks; I literally can't write C++ anymore.

0

Share this post


Link to post
Share on other sites
Quote:
Original post by Koobazaur
at least when I had ** ppSomething I knew exactly what was going on instead of having to wonder what is referencing what (not to mention extra flexibility). And wtf is up with the lack of template, errr, generic specialization? Seriously...


You have nearly the exact same flexibility in C# and you can know "exactly what is going on" with great certainty once you learn the .NET model just as you learned the C++ model.

C# can accomplish non-partial generics specialization through inheritance. For example:

class SpecializedForBar : Foo<Bar>
{
//override virtual members of Foo
}
0

Share this post


Link to post
Share on other sites
       
public void Update()
{

Graphics Graph = Graphics.FromImage(_DrawArea); // this throws exception if the DrawArea I passed in constructor gets deleted and re-created

Pen MyPen = new Pen(Color.Blue); //yaya I know would be more efficient to story this as private member, but optimizations come later

Graph.DrawEllipse(MyPen, 0, 0, 10, 10);

MyPen.Dispose();

}



Just thought I should make a point -- you're clearing up after your pen right here, but not your System.Drawing.Graphics object that you're drawing on -- this is going to be a potential problem later if you're not careful. Anytime you use a graphics object that you didn't get given (i.e., in a paint() method you get given the surface that GDI+ is looking after...) you ought to manually call dispose() so that things don't end up leaking later on :)

This is a fact of life of using GDI+ -- 'tis a C++ library wrapped up in .NET but still must use unmanaged memory for certain stuff (Bitmaps ought to be disposed too, btw).

Anyways, 'twas my two cents. I second the proposition of inheriting from an existing container, too -- save you lots of work. Drawing an Image (system.drawing.image)/Bitmap onto a panel is as easy as grabbing the paint code for said panel and squishing in something along the lines of

Given some PaintEventArgs e -- e.Graphics.DrawImage(Image i);

and voila. DrawImage is overloaded so you can specify things such as height/width/graphics unit etc.

~Shiny
0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0