Results 1 to 10 of 10

Thread: [Solved] Overriding a procedure

  1. #1

    [Solved] Overriding a procedure

    System: Ubuntu 9.04
    Compiler/IDE: FPC/Lazarus 9.26-4
    Libraries/API: None

    Basically, in unit2 I have this object:
    Code:
    Sprite = Object
         public
            x,y,xspeed,yspeed,gravity,lastx,lasty,collision: integer;
            solid: boolean;
            img: TBitmap;
            procedure Create();
            procedure Destroy();
            procedure Collide(); // Empty by default. I want to override it.
      end;
    That has the empty procedure "Collide". Now, my unit1 uses unit2 and I create a sprite object like so:
    Code:
    Player: Sprite;
    Player := Sprite.Create;
    Player.Collide := PlayerCollide; // Yells at me here
    Where PlayerCollide is a procedure in unit1
    Code:
    procedure TForm1.PlayerCollide();
    begin
       Player.y := 32;
    end;
    It's a bit messy, and I've never done any overrides before, much less of my own procedures..

    [Random]
    Quite ambitious for me, and quite poorly coded, but I'm working on a simple 2d, software-rendered game engine. The idea behind what was mentioned above is so the person making their game could override the collision code to handle them how they want: Ex: Delete objects, Teleport places ETC.

  2. #2

    Re: Overriding a procedure

    Hi dazappa

    hmm...I think the sprite should be of type Class instead of Object?

    [pascal]Sprite = Class
    public
    x,y,xspeed,yspeed,gravity,lastx,lasty,collision: integer;
    solid: boolean;
    img: TBitmap;
    procedure Create();
    procedure Destroy();
    procedure Collide(); // Empty by default. I want to override it.
    end;[/pascal]

    Also if you want to override a method you need to use "virtual" against the method like so:

    [pascal]Sprite = Class
    public
    ...
    procedure Collide(); Virtual; // Empty by default. I want to override it.
    end;[/pascal]

    class overriding Collide method:
    [pascal]MySprite = Class(TSprite)
    procedure Collide(); Override; // override empty method
    end;[/pascal]

    [pascal]Procedure TMySprite.Collide;
    Begin
    // do something new here
    End;[/pascal]

    I hope this helps

    cheers,
    Paul

  3. #3

    Re: Overriding a procedure

    You could also just make it a procedure variable
    [pascal]
    Sprite = Object
    public
    x,y,xspeed,yspeed,gravity,lastx,lasty,collision: integer;
    solid: boolean;
    img: TBitmap;
    procedure Create();
    procedure Destroy();
    Collide: procedure of object; // Empty by default. I want to override it.
    end;
    [/pascal]

    And then do:
    [pascal]
    Player: Sprite;
    Player := Sprite.Create;
    Player.Collide := @PlayerCollide; // Yells at me here
    [/pascal]

    You can't do it the other way around unless you hack the vmt. And that's not bound to work the same way on all platforms
    Peregrinus, expectavi pedes meos in cymbalis
    Nullus norvegicorum sole urinat

  4. #4

    Re: Overriding a procedure

    Quote Originally Posted by JSoftware
    You could also just make it a procedure variable
    [pascal]
    Sprite = Object
    public
    x,y,xspeed,yspeed,gravity,lastx,lasty,collision: integer;
    solid: boolean;
    img: TBitmap;
    procedure Create();
    procedure Destroy();
    Collide: procedure of object; // Empty by default. I want to override it.
    end;
    [/pascal]

    And then do:
    [pascal]
    Player: Sprite;
    Player := Sprite.Create;
    Player.Collide := @PlayerCollide; // Yells at me here
    [/pascal]

    You can't do it the other way around unless you hack the vmt. And that's not bound to work the same way on all platforms
    This works exactly as I want. How would I define the default procedure for Sprite.Collide though? (Is it possible?) Obviously "procedure Sprite.Collide begin end;" no longer worked

    This seems like it could be a solution: http://www.swissdelphicenter.ch/torr...ode.php?id=799 , but is there a better solution?

  5. #5
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2

    Re: Overriding a procedure

    In terms of object orientated programming, the most widely used way is to do what Paul has suggested. Declare the method in the base class as 'virtual' and then override it in the child classes.

    By doing it that way, if your base class has functionality in it that will also be needed for the children, you can use the 'inherited' keyword to call the common functionality.

    To use the procedure variable method (which is the standard eventing mechanism), you should really handle the situation where the variable is not initialised, which would result in an additional 'if assigned()' or 'if collide<>nil' style check to avoid attempting to call a routine at address 0x00000000 (which I'm guessing is why your code isn't working using that method). If the routine is being called alot, then those checks create an overhead that can be avoided by using real overrides.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  6. #6
    PGDCE Developer de_jean_7777's Avatar
    Join Date
    Nov 2006
    Location
    Bosnia and Herzegovina (Herzegovina)
    Posts
    287

    Re: Overriding a procedure

    You could assign some procedure to the procedure variable in your unit in the
    Code:
    INITIALIZATION
    part. This way you can assign your procedure variable a default procedure, and you won't have to check if it is nil. This is what I do in my projects, though you do have to be careful that your procedure variables are always initialized if you do not want to do checking.

    I usually assign procedure variables some dummy procedures in the INITIALIZATION part. These dummy routines do nothing, but they prevent crashes in case of a call to a nil procedure variable. Then later on I assign them some other procedure.
    Existence is pain

  7. #7

    Re: Overriding a procedure

    Quote Originally Posted by AthenaOfDelphi
    In terms of object orientated programming, the most widely used way is to do what Paul has suggested. Declare the method in the base class as 'virtual' and then override it in the child classes.

    By doing it that way, if your base class has functionality in it that will also be needed for the children, you can use the 'inherited' keyword to call the common functionality.

    To use the procedure variable method (which is the standard eventing mechanism), you should really handle the situation where the variable is not initialised, which would result in an additional 'if assigned()' or 'if collide<>nil' style check to avoid attempting to call a routine at address 0x00000000 (which I'm guessing is why your code isn't working using that method). If the routine is being called alot, then those checks create an overhead that can be avoided by using real overrides.
    Well I have 2 main problems with this.
    1. (I believe) I'd have to create a separate class each time I want different collision code
    2. The way I'm writing this is engine is so the engine manages all of the objects

    Quote Originally Posted by de_jean_7777
    You could assign some procedure to the procedure variable in your unit in the
    Code:
    INITIALIZATION
    part. This way you can assign your procedure variable a default procedure, and you won't have to check if it is nil. This is what I do in my projects, though you do have to be careful that your procedure variables are always initialized if you do not want to do checking.

    I usually assign procedure variables some dummy procedures in the INITIALIZATION part. These dummy routines do nothing, but they prevent crashes in case of a call to a nil procedure variable. Then later on I assign them some other procedure.
    I never think of the simple things...

    Ok, so now for the sake of organization and (somewhat) cleaner code, how can I pass variables into the collide procedure? (Because assigning procedures without using the way Paul showed means the procedure does not have access to the object's variables).

    So I was thinking:
    Code:
     Sprite = Object 
         public 
            x,y,xspeed,yspeed,gravity,lastx,lasty,collision: integer; 
            solid: boolean; 
            img: TBitmap; 
            procedure Create(); 
            procedure Destroy(); 
            Collide: procedure(index: integer) of object; // Empty by default. I want to override it. 
      end;
    
    ...
    
    Player: Sprite; 
    Player := Sprite.Create; 
    Player.Collide := @PlayerCollide; // Yells at me here
    
    ...
    
    procedure PlayerCollide(index: Integer);
    begin
    
    end;
    But it yells at the same line as before when I try that.

    (PS: Might want to post somewhere how to use code highlighting on these forums)

  8. #8
    PGD Community Manager AthenaOfDelphi's Avatar
    Join Date
    Dec 2004
    Location
    South Wales, UK
    Posts
    1,245
    Blog Entries
    2

    Re: Overriding a procedure

    To use code highlight, you enclose your code in PASCAL tags... like this, without the spaces (depending on which theme you are using, I believe Traveler has integrated the code highlighting into the message editor).

    [ pascal ]
    Your code here
    [ /pascal ]

    With regards to using the more correct OOP approach to overrides.... if the user of your engine has the code, they can override it (or modify it to suit their needs).

    With regards to the compiler crying at the @ symbol... if FreePascal's eventing mechanisms are the same as those in Delphi, then you shouldn't need the @ but, the method you try and call must be a method of a class because you've defined the holding variable as 'procedure of object'.
    :: AthenaOfDelphi :: My Blog :: My Software ::

  9. #9

    Re: Overriding a procedure

    The @ is used for a pointer reference. Looking at your code, Player.Collide is not a pointer, so you should remove the @ sign.

    [pascal]
    Player.Collide := PlayerCollide; //@ is removed
    [/pascal]

    I rarely make use of pointers, so I hope this helps.

  10. #10

    Re: Overriding a procedure

    After some toying, I've got it working perfectly as I imagined

    [pascal]
    Sprite = object
    public
    x,y,xspeed,yspeed,gravity,lastx,lasty,collision: integer;
    solid: boolean;
    img: TBitmap;
    procedure Create();
    procedure Destroy();
    Collide: procedure of object;
    Draw: procedure of object;
    procedure DefaultDraw();
    procedure DefaultCollision();
    procedure LoadFromFile(F: String);
    end;

    ...

    procedure Sprite.Create();
    begin
    img := TBitmap.Create;
    lastx := x;
    lasty := y;
    solid := false;
    Collide := DefaultCollision;
    Draw := DefaultDraw;
    end;
    [/pascal]
    Then I can just change Sprite.Collide to something else from the main game unit (oddly enough, this was giving me errors from within the engine unit, but as Sprite.Create is always called, this works wonderfull).

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •