• Dear Cerberus X User!

    As we prepare to transition the forum ownership from Mike to Phil (TripleHead GmbH), we need your explicit consent to transfer your user data in accordance with our amended Terms and Rules in order to be compliant with data protection laws.

    Important: If you accept the amended Terms and Rules, you agree to the transfer of your user data to the future forum owner!

    Please read the new Terms and Rules below, check the box to agree, and click "Accept" to continue enjoying your Cerberus X Forum experience. The deadline for consent is April 5, 2024.

    Do not accept the amended Terms and Rules if you do not wish your personal data to be transferred to the future forum owner!

    Accepting ensures:

    - Continued access to your account with a short break for the actual transfer.

    - Retention of your data under the same terms.

    Without consent:

    - You don't have further access to your forum user account.

    - Your account and personal data will be deleted after April 5, 2024.

    - Public posts remain, but usernames indicating real identity will be anonymized. If you disagree with a fictitious name you have the option to contact us so we can find a name that is acceptable to you.

    We hope to keep you in our community and see you on the forum soon!

    All the best

    Your Cerberus X Team

Functions and multiple outputs

Wingnut

Well-known member
3rd Party Module Dev
Tutorial Author
Joined
Jan 2, 2020
Messages
1,414
What's the preferable way to multiple outputs in Cerberus functions?

A simple example would be if you have a pair of x and y coordinates that a function changes and now you want to output the new pair.

PSEUDOCODE
Code:
Function TransformXandY(float wX,float wY,int &SX,int &SY)
    SX = (wX - 10)
    SY = (wY - 10) 
End
 
The answer given there is just a relative change that it encodes and gives back, what if you really want two or more absolute variables back?
 
I know that I could simply use OO and have a refined chunk of information thrown back and forth that way, but is there any other way that is more direct in Cerberus?
 
I made an absolute encoding last week, which allows me to put x & y coordinates in the range of 0-65535 together into one INT, but this is a nasty as it cannot do anything else. I use it only for extreme speed and memory conservation.

I'm looking for something more flexible, something that would fit in-between this idea and OO. Not sure it exist.
 
The answer given there is just a relative change that it encodes and gives back, what if you really want two or more absolute variables back?
Guess you didn't see the bit in the middle that tells you why you can not pass the SX and SY, and expect that it will change.
The parameter direction will be treated as a local variable and have absolutely no affect out side the AI_left method. This is down to only a copy being made of the value passed as the parameter and not the memory location of the variable, so it will not affect the original variable. With class objects, only the reference (aka it's address in memory) is being copied, so any change to that object affects that object directly.
 
But arrays will right? Except arrays, in a way arrays is in the middle but it's still limited.

This is the OO solution I use now to test

Code:
Import mojo2

Class xy
    Global x:Int ' Field x:Int
    Global y:Int ' Field y:Int
End

Function Main()
    New Game
    Return 0
End

Class Game Extends App

    Field a:xy

    Method OnCreate()
    
        ' Create
        a = New xy()
        
        ' Set
        a.x = 10
        a.y = 10
        
        ' Change
        a = changexy(a)
        
        ' Print
        Print a.x
        Print a.y
        
        Return 0
    End
End

Function changexy:xy(parameter:xy)
    parameter.x = parameter.x + 1
    parameter.y = parameter.y + 10
    Return parameter
End
 
A bit more cleaned up, I'm not sure about the speed yet but it looks okay. It does not create anything new all the time.

Code:
Import mojo2

Function Main()
    New Game
    Return 0
End

Class Game Extends App
   
    Field a:xy = New xy() ' Create variable a of class xy
   
    Method OnCreate()
   
        ' Set
        a.x = 10
        a.y = 10
       
        ' Change
        a = changexy(a)
       
        ' Print
        Print a.x
        Print a.y
       
        Return 0
    End
End

Class xy
    Global x:Int ' Field x:Int
    Global y:Int ' Field y.Int
End

Function changexy:xy(parameter:xy)
    parameter.x = parameter.x + 1
    parameter.y = parameter.y + 10
    Return parameter
End
 
Good to know. That is true with most languages.
 
I can't get the array of xy's to work correctly sadly. Not sure I use the correct syntax.

Code:
Strict
Import mojo2

Function Main:Int()
    New Game()
    Return 0
End

Class Game Extends App

    Field a:xy = New xy ' Create variable of type xy
    Field indices:xy[100] ' Create array of type xy
    
    Method OnCreate:Int()
    
        ' Set
        a.x = 10
        a.y = 10
        
        ' Change
        a = changexy(a)
        
        ' Print
        Print a.x
        Print a.y
        
        ' Test array
        ' indices[0].x = 10
        ' Print indices[0].x
        
        Return 0
    End
End

Class xy
    Field x:Int
    Field y:Int
End

Function changexy:xy(parameter:xy)
    parameter.x = parameter.x + 1
    parameter.y = parameter.y + 10
    Return parameter
End
 
Cerberus:
Class Game Extends App

    Field a:xy = New xy ' Create variable of type xy
    Field indices:xy[100] ' Create array of type xy
    
    Method OnCreate:Int()
        ' You forgot to initialize the array'
        For Local i:= 0 To 99
            indices[i] = New xy
        Next
 
Thanks! Got it working and it looks good too!
 
Put alien logic into it to try everything
Code:
Strict
Import mojo2

Function Main:Int()
    New Game()
    Return 0
End

Class Game Extends App

    Field canvas:Canvas
   
'    Field a:xy = New xy    ' Create simple variable of type xy
    Field indices:xy[100]    ' Create array of type xy
   
    Method OnCreate:Int()
       
        ' Inits
        For Local i := 0 To 99 ; indices[i] = New xy ; Next    ' Init Array
        canvas = New Canvas()                        ' Init canvas
        SetSwapInterval 1
        SetUpdateRate 0
       
        ' Continue init array
        For Local i := 0 To 99
            indices[i] = initxy(indices[i])
        Next  
           
        Return 0
    End
   
    Method Update:Int()  
        Return 0
    End
   
    Method OnRender:Int()
        canvas.Clear

        ' Loop all objects
        For Local i := Eachin indices
            canvas.DrawRect i.x,i.y,16,16                    ' Draw
            i = movexy(i)                                ' Update
        Next

        ' For Local i := 0 To 99
        '     canvas.DrawRect indices[i].x,indices[i].y,16,16    ' Draw
        '     indices[i] = movexy(indices[i])                ' Update
        ' Next

        canvas.Flush
        Return 0      
    End

End

Class xy
    Field x:Int
    Field y:Int
    Field vx:Int
    Field vy:Int
End

Function initxy:xy(p:xy)
    p.x = Rnd(640)
    p.y = Rnd(480)
    p.vx = Rnd(1,2)
    If Rnd(1) >= 0.5 Then p.vx = -p.vx
    p.vy = Rnd(1,2)
    Return p
End

Function movexy:xy(p:xy)
    p.x = p.x + p.vx
    If p.x < 0 Or p.x >= 640 Then p.vx = -p.vx
    p.y = p.y + p.vy
    If p.y < 0 Or p.y >= 480 Then p.vy = -p.vy
    Return p
End
 
Standard: create a class e.g. a Point class with fields x and y.

Quick and dirty: use an array. You can pass an array or just create one in your function and return it. (Or another collection type such as a stack.)
 
Here I use the standard way and I enjoy having data and code separate.
 
The only thing I miss is to be able to express one as a constant like you can in JavaScript and JSON.

For example Return an xy that you create witthout object. It's an object of course. But you create it on the spot. Just one of those small things. There's workarounds of course.
 
When I want to output a value on the fly and create a test variable of xy, it does not work.


Code:
Strict
Import mojo2

Function Main:Int()
    New Game()
    Return 0
End

Class Game Extends App

    Const n:Int = 100

    Field canvas:Canvas
'    Field a:xy = New xy    ' Create simple variable of type xy
    Field indices:xy[n]        ' Create array of type xy
    
    Method OnCreate:Int()
        
        ' Inits
        canvas = New Canvas()                        ' Init canvas
        SetSwapInterval 1
        SetUpdateRate 0
        For Local i := 0 Until n ; indices[i] = New xy ; Next    ' Init Array
        For Local i := Eachin indices ; i = initxy(i) ; Next
        
        Return 0
    End
    
    Method OnRender:Int()
        canvas.Clear

        ' Loop all objects
        For Local i := Eachin indices
            canvas.DrawRect i.x,i.y,16,16                    ' Draw
            i = movexy(i)                                ' Update
        Next

        ' For Local i := 0 Until n
        '     canvas.DrawRect indices[i].x,indices[i].y,16,16    ' Draw
        '     indices[i] = movexy(indices[i])                ' Update
        ' Next
        
        canvas.Flush
        Return 0       
    End

End

Class xy
    Field x:Int
    Field y:Int
    Field vx:Int
    Field vy:Int
End

Function initxy:xy(p:xy)
    p.x = Rnd(640)
    p.y = Rnd(480)
    p.vx = Rnd(1,2)
    If Rnd(1) >= 0.5 Then p.vx = -p.vx
    p.vy = Rnd(1,2)
    Return p
End

Function movexy:xy(p:xy)
    p.x = p.x + p.vx
    If p.x < 0 Or p.x >= 640 Then p.vx = -p.vx
    p.y = p.y + p.vy
    If p.y < 0 Or p.y >= 480 Then p.vy = -p.vy

    ' Create output of only zeros (does not work)
    Local test:xy = New xy
    test.x = 0
    test.y = 0
    test.vx = 0
    test.vy = 0   
    Return test

    ' Return p
End
 
It does work if you exclude the Each loop and index manually.

Code:
Strict
Import mojo2

Function Main:Int()
    New Game()
    Return 0
End

Class Game Extends App

    Const n:Int = 100

    Field canvas:Canvas
'    Field a:xy = New xy    ' Create simple variable of type xy
    Field indices:xy[n]        ' Create array of type xy
   
    Method OnCreate:Int()

        ' Inits
        canvas = New Canvas()                        ' Init canvas
        SetSwapInterval 1
        SetUpdateRate 0
        For Local i := 0 Until n ; indices[i] = New xy ; Next    ' Init Array
        For Local i := Eachin indices ; i = initxy(i) ; Next
       
        Return 0
    End
   
    Method OnRender:Int()
        canvas.Clear

        ' Loop all objects
        'For Local i := Eachin indices
        '    canvas.DrawRect i.x,i.y,16,16                    ' Draw
        '    i = movexy(i)                                ' Update
        'Next

         For Local i := 0 Until n
             canvas.DrawRect indices[i].x,indices[i].y,16,16    ' Draw
             indices[i] = movexy(indices[i])                ' Update
         Next
       
        canvas.Flush
        Return 0      
    End

End

Class xy
    Field x:Int
    Field y:Int
    Field vx:Int
    Field vy:Int
End

Function initxy:xy(p:xy)
    p.x = Rnd(640)
    p.y = Rnd(480)
    p.vx = Rnd(1,2)
    If Rnd(1) >= 0.5 Then p.vx = -p.vx
    p.vy = Rnd(1,2)
    Return p
End

Function movexy:xy(p:xy)
    p.x = p.x + p.vx
    If p.x < 0 Or p.x >= 640 Then p.vx = -p.vx
    p.y = p.y + p.vy
    If p.y < 0 Or p.y >= 480 Then p.vy = -p.vy

    ' Create output of only zeros (does not work)
    Local test:xy = New xy
    test.x = 0
    test.y = 0
    test.vx = 0
    test.vy = 0
    Return test

    Return p
End
 
Though am a bit worried about this part, wondering if it's creating objects, there gonna be millions of calls.

Code:
Local test:xy = New xy

EDIT which brought me here:

It's a bit silver tape to use a global as a forever constant. But for now it's okay. I might actually keep this solution.

Code:
Strict
Import mojo2

Global test:xy = New xy ' To be re-used as constant forever

Function Main:Int()
    New Game()
    Return 0
End

Class Game Extends App

    Const n:Int = 100

    Field canvas:Canvas
'    Field a:xy = New xy    ' Create simple variable of type xy
    Field indices:xy[n]        ' Create array of type xy
    
    Method OnCreate:Int()

        ' Inits
        canvas = New Canvas()
        SetSwapInterval 1
        SetUpdateRate 0
        For Local i := 0 Until n ; indices[i] = New xy ; Next
        For Local i := 0 Until n ; indices[i] = initxy( indices[i]) ; Next
        Return 0
    End
    
    Method OnRender:Int()
        canvas.Clear

         For Local i := 0 Until n
             canvas.DrawRect indices[i].x,indices[i].y,16,16    ' Draw
             indices[i] = movexy(indices[i])                ' Update
         Next
        
        canvas.Flush
        Return 0       
    End

End

Class xy
    Field x:Int
    Field y:Int
    Field vx:Int
    Field vy:Int
End

Function initxy:xy(p:xy)
    p.x = Rnd(640)
    p.y = Rnd(480)
    p.vx = Rnd(1,2)
    If Rnd(1) >= 0.5 Then p.vx = -p.vx
    p.vy = Rnd(1,2)
    Return p
End

Function movexy:xy(p:xy)
    p.x = p.x + p.vx
    If p.x < 0 Or p.x >= 640 Then p.vx = -p.vx
    p.y = p.y + p.vy
    If p.y < 0 Or p.y >= 480 Then p.vy = -p.vy

    ' Create a xy constant and output
    ' Local test:xy = New xy ; test.x = 0 ; test.y = 0 ; test.vx = 0 ; test.vy = 0
    ' Return test
    
    ' TEST OF OUTPUTTING A CONSTANT XY (should put everything in the corner still)
     test.x = 0
    test.y = 0
    test.vx = 0
    test.vy = 0
     Return test ' Comment this line to get back to normal
 
    Return p
End
 
Last edited:
Back
Top Bottom