Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • #16
    In this project I have three kinds (or classes) of object to track. First is the state of the game. These are things like ball coordinates, which change as the game progresses. Second are constants; unchanging settings determined before rather than as the game runs. Finally there are coordinates, which are self explanatory.

    Coordinate class definition:

    Code:
    version 15.1
    class coordinate{
        double x
        double y
    }
    Constant class definition:

    Code:
    version 15.1
    class constant{
        velocity = 1
        timestep = 1
        leftbound = 0
        rightbound = 100
        lowerbound = 0
        upperbound = 100
    }
    State class definition:

    Code:
    version 15.1
    class state{
        constant const
        coordinate ballstart
        coordinate ballcurrent
        coordinate paddlestart
        coordinate paddlecurrent
        double xballvelocity
        double yballvelocity
        double gameover = 0
    }
    
    program .checkgameover
        if `.ballcurrent.y' <= `.const.lowerbound'{
            .gameover = 1
        }
    end
    
    program .updateballposition
        .ballcurrent.x = `.ballcurrent.x'  + (`.xballvelocity' * `.const.timestep')
        .ballcurrent.y = `.ballcurrent.y' + (`.yballvelocity' * `.const.timestep')
    end
    
    program .checkwallcollision
        if `.ballcurrent.x' >= `.const.rightbound' {
            .reverseforce
        }
        if `.ballcurrent.x' <= `.const.leftbound' {
            .reverseforce
        }
        if `.ballcurrent.y' >= `.const.upperbound' {
            .reverseforce
        }
    end
    
    program .reverseforce
        if `.xballvelocity' < 0{
            .xballvelocity = abs(`.xballvelocity')
        }
        else{
            .xballvelocity = -`.xballvelocity'
        }
        if `.yballvelocity' < 0{
            .yballvelocity = abs(`.yballvelocity')
        }
        else{
            .yballvelocity = -`.yballvelocity'
        }
        local xtemp = `.xballvelocity'
        local ytemp = `.yballvelocity'
        .xballvelocity = `xtemp'
        .yballvelocity = `ytemp'
    end
    
    program .auto_update_paddle_position
        .paddlecurrent.x = .ballcurrent.x
    end
    
    program .update_paddle_position
    endversion 15.1
    class state{
        constant const
        coordinate ballstart
        coordinate ballcurrent
        coordinate paddlestart
        coordinate paddlecurrent
        double xballvelocity
        double yballvelocity
        double gameover = 0
    }
    
    program .checkgameover
        if `.ballcurrent.y' <= `.const.lowerbound'{
            .gameover = 1
        }
    end
    
    program .updateballposition
        .ballcurrent.x = `.ballcurrent.x'  + (`.xballvelocity' * `.const.timestep')
        .ballcurrent.y = `.ballcurrent.y' + (`.yballvelocity' * `.const.timestep')
    end
    
    program .checkwallcollision
        if `.ballcurrent.x' >= `.const.rightbound' {
            .reverseforce
        }
        if `.ballcurrent.x' <= `.const.leftbound' {
            .reverseforce
        }
        if `.ballcurrent.y' >= `.const.upperbound' {
            .reverseforce
        }
    end
    
    program .reverseforce
        if `.xballvelocity' < 0{
            .xballvelocity = abs(`.xballvelocity')
        }
        else{
            .xballvelocity = -`.xballvelocity'
        }
        if `.yballvelocity' < 0{
            .yballvelocity = abs(`.yballvelocity')
        }
        else{
            .yballvelocity = -`.yballvelocity'
        }
        local xtemp = `.xballvelocity'
        local ytemp = `.yballvelocity'
        .xballvelocity = `xtemp'
        .yballvelocity = `ytemp'
    end
    
    program .auto_update_paddle_position
        .paddlecurrent.x = .ballcurrent.x
    end
    
    program .update_paddle_position
    endversion 15.1
    class state{
        constant const
        coordinate ballstart
        coordinate ballcurrent
        coordinate paddlestart
        coordinate paddlecurrent
        double xballvelocity
        double yballvelocity
        double gameover = 0
    }
    
    program .checkgameover
        if `.ballcurrent.y' <= `.const.lowerbound'{
            .gameover = 1
        }
    end
    
    program .updateballposition
        .ballcurrent.x = `.ballcurrent.x'  + (`.xballvelocity' * `.const.timestep')
        .ballcurrent.y = `.ballcurrent.y' + (`.yballvelocity' * `.const.timestep')
    end
    
    program .checkwallcollision
        if `.ballcurrent.x' >= `.const.rightbound' {
            .reverseforce
        }
        if `.ballcurrent.x' <= `.const.leftbound' {
            .reverseforce
        }
        if `.ballcurrent.y' >= `.const.upperbound' {
            .reverseforce
        }
    end
    
    program .reverseforce
        if `.xballvelocity' < 0{
            .xballvelocity = abs(`.xballvelocity')
        }
        else{
            .xballvelocity = -`.xballvelocity'
        }
        if `.yballvelocity' < 0{
            .yballvelocity = abs(`.yballvelocity')
        }
        else{
            .yballvelocity = -`.yballvelocity'
        }
        local xtemp = `.xballvelocity'
        local ytemp = `.yballvelocity'
        .xballvelocity = `xtemp'
        .yballvelocity = `ytemp'
    end
    
    program .auto_update_paddle_position
        .paddlecurrent.x = .ballcurrent.x
    end
    
    program .update_paddle_position
    endversion 15.1
    class state{
        constant const
        coordinate ballstart
        coordinate ballcurrent
        coordinate paddlestart
        coordinate paddlecurrent
        double xballvelocity
        double yballvelocity
        double gameover = 0
    }
    
    program .checkgameover
        if `.ballcurrent.y' <= `.const.lowerbound'{
            .gameover = 1
        }
    end
    
    program .updateballposition
        .ballcurrent.x = `.ballcurrent.x'  + (`.xballvelocity' * `.const.timestep')
        .ballcurrent.y = `.ballcurrent.y' + (`.yballvelocity' * `.const.timestep')
    end
    
    program .checkwallcollision
        if `.ballcurrent.x' >= `.const.rightbound' {
            .reverseforce
        }
        if `.ballcurrent.x' <= `.const.leftbound' {
            .reverseforce
        }
        if `.ballcurrent.y' >= `.const.upperbound' {
            .reverseforce
        }
    end
    
    program .reverseforce
        if `.xballvelocity' < 0{
            .xballvelocity = abs(`.xballvelocity')
        }
        else{
            .xballvelocity = -`.xballvelocity'
        }
        if `.yballvelocity' < 0{
            .yballvelocity = abs(`.yballvelocity')
        }
        else{
            .yballvelocity = -`.yballvelocity'
        }
        local xtemp = `.xballvelocity'
        local ytemp = `.yballvelocity'
        .xballvelocity = `xtemp'
        .yballvelocity = `ytemp'
    end
    
    program .auto_update_paddle_position
        .paddlecurrent.x = .ballcurrent.x
    end
    
    program .update_paddle_position
    endversion 15.1
    class state{
        constant const
        coordinate ballstart
        coordinate ballcurrent
        coordinate paddlestart
        coordinate paddlecurrent
        double xballvelocity
        double yballvelocity
        double gameover = 0
    }
    
    program .checkgameover
        if `.ballcurrent.y' <= `.const.lowerbound'{
            .gameover = 1
        }
    end
    
    program .updateballposition
        .ballcurrent.x = `.ballcurrent.x'  + (`.xballvelocity' * `.const.timestep')
        .ballcurrent.y = `.ballcurrent.y' + (`.yballvelocity' * `.const.timestep')
    end
    
    program .checkwallcollision
        if `.ballcurrent.x' >= `.const.rightbound' {
            .reverseforce
        }
        if `.ballcurrent.x' <= `.const.leftbound' {
            .reverseforce
        }
        if `.ballcurrent.y' >= `.const.upperbound' {
            .reverseforce
        }
    end
    
    program .reverseforce
        if `.xballvelocity' < 0{
            .xballvelocity = abs(`.xballvelocity')
        }
        else{
            .xballvelocity = -`.xballvelocity'
        }
        if `.yballvelocity' < 0{
            .yballvelocity = abs(`.yballvelocity')
        }
        else{
            .yballvelocity = -`.yballvelocity'
        }
        local xtemp = `.xballvelocity'
        local ytemp = `.yballvelocity'
        .xballvelocity = `xtemp'
        .yballvelocity = `ytemp'
    end
    
    program .auto_update_paddle_position
        .paddlecurrent.x = .ballcurrent.x
    end
    
    program .update_paddle_position
    endversion 15.1
    class state{
        constant const
        coordinate ballstart
        coordinate ballcurrent
        coordinate paddlestart
        coordinate paddlecurrent
        double xballvelocity
        double yballvelocity
        double gameover = 0
    }
    
    program .checkgameover
        if `.ballcurrent.y' <= `.const.lowerbound'{
            .gameover = 1
        }
    end
    
    program .updateballposition
        .ballcurrent.x = `.ballcurrent.x'  + (`.xballvelocity' * `.const.timestep')
        .ballcurrent.y = `.ballcurrent.y' + (`.yballvelocity' * `.const.timestep')
    end
    
    program .checkwallcollision
        if `.ballcurrent.x' >= `.const.rightbound' {
            .reverseforce
        }
        if `.ballcurrent.x' <= `.const.leftbound' {
            .reverseforce
        }
        if `.ballcurrent.y' >= `.const.upperbound' {
            .reverseforce
        }
    end
    
    program .reverseforce
        if `.xballvelocity' < 0{
            .xballvelocity = abs(`.xballvelocity')
        }
        else{
            .xballvelocity = -`.xballvelocity'
        }
        if `.yballvelocity' < 0{
            .yballvelocity = abs(`.yballvelocity')
        }
        else{
            .yballvelocity = -`.yballvelocity'
        }
        local xtemp = `.xballvelocity'
        local ytemp = `.yballvelocity'
        .xballvelocity = `xtemp'
        .yballvelocity = `ytemp'
    end
    
    program .auto_update_paddle_position
        .paddlecurrent.x = .ballcurrent.x
    end
    
    program .update_paddle_position
    end
    Last edited by Daniel Schaefer; 11 Mar 2020, 14:35.

    Comment


    • #17
      How/where do you create instances of your classes? For `.Global.pongstate.const.rightbound' to exist in the namespace of draw_pong.ado, you would usually need something like

      Code:
      program draw_pong
          .Global.pongstate = .state.new
          code referring to `.Global.pongstate.const.rightbound'
      end
      I cannot remember all the details, but simplistic class names, such as state, coordinate, etc. might cause problems.

      Best
      Daniel

      Comment


      • #18
        daniel klein I create a global instance of the state object in my initialization routine. The .Global preface explicitly asks the global environment for the variable. As an aside, there doesn't seem to be a good way to pass class instances as a parameter between programs. Too bad because I prefer to globalize data as infrequently as I can.

        There are 5 routines at the moment, each in its own .ado file.

        pong - runs the full game by calling these sub-routines
        initialize_pong - sets everything up
        run_pong - run the game in a while loop
        draw_pong - draws each frame for plotting

        [edit] forgot the fifth!
        cleanup_pong - if I need to put globalized things back where they go before exiting. Right now basically just an alias for -discard-

        I cannot remember all the details, but simplistic class names, such as state, coordinate, etc. might cause problems.
        Is the worry that I'm using words that are already in stata's namespace? So some stata dev at some point long long ago already defined a class state, and I'm accidentally overwriting it?
        Last edited by Daniel Schaefer; 11 Mar 2020, 16:35.

        Comment


        • #19
          Originally posted by Daniel Schaefer View Post
          I create a global instance of the state object in my initialization routine. The .Global preface explicitly asks the global environment for the variable.
          Obviously, I cannot comment on code that you do not show. I am not sure how the .Global prefix works outside class-programs.

          Originally posted by Daniel Schaefer View Post
          As an aside, there doesn't seem to be a good way to pass class instances as a parameter between programs.
          I do not quite follow this concern. A class instance is just a name/argument. You can

          Code:
          program main
              tempname x
              .`x' = .my_class.new
              
              sub `x'
          end
          
          program sub
              agrs x
              
              code referring to .`x'
          end
          Originally posted by Daniel Schaefer View Post
          Is the worry that I'm using words that are already in stata's namespace? So some stata dev at some point long long ago already defined a class state, and I'm accidentally overwriting it?
          Basically, yes. I am not sure whether you could simply overwrite something (or something else might overwrite your stuff). Perhaps one of the routines using the same class-names would just not work/throw an error when initialized. As I have mentioned, I do not recall the details of name-spaces and scope for classes in Stata.

          Best
          Daniel

          Comment


          • #20
            daniel klein

            Obviously, I cannot comment on code that you do not show.
            Sure. The full source can be found here: https://github.com/CrazyWhatsIt/StataPong

            I do not quite follow this concern. A class instance is just a name/argument.
            That's the way it ought to work, but I spent a couple of days on this and never found a way to get stata to interpret the class as a valid argument or return type. I found some documentation - that I'm having trouble digging up again unfortunately - which led me to the conclusion that args accept a limited set of input types, and class instances weren't on the list. I'd be happy to be wrong about this though. After a decade or so of programming I've pretty much excepted that occasional roll-your-eyes-when-you-realize syntax errors are par for the course.

            As I have mentioned, I do not recall the details of name-spaces and scope for classes in Stata.
            Stata is fairly new to me, so I appreciate your help. I'm doing all of my debugging in an otherwise empty and unmodified instance of Stata, and I expect (though I may be wrong) that StataCorp is doing what they need to do to properly encapsulate their code, but being sensitive to namespace is probably just good practice regardless. I'll make those changes when I have some spare time again. Maybe this evening.

            Comment


            • #21
              daniel klein

              Looks like you're right about passing class instances as arguments!

              Code:
              version 15.01
              class my_class{
                  double var = 1
              }
              Code:
              . do "C:\Users\TEMPUN~1.004\AppData\Local\Temp\13\STDffe8_000000.tmp"
              
              . cd "H:\Users\Daniel Schaefer\proof of concept code"
              H:\Users\Daniel Schaefer\proof of concept code
              
              . capture program drop main sub
              
              .
              . program main
                1.     tempname x
                2.         di "create class"
                3.     .x = .my_class.new
                4.         di `.x.var'
                5.         di "enter sub"
                6.     sub `x'
                7. end
              
              .
              . program sub
                1.         di "sub start"
                2.     args x
                3.         di "display var"
                4.     di `.x.var'
                5. end
              
              .
              . main
              create class
              1
              enter sub
              sub start
              display var
              1
              
              .
              end of do-file

              Comment

              Working...
              X