[EXAMPLE] 2D camera in mojo2

ddabrahim

Active Member
Joined
May 3, 2020
Location
Cyberspace
Hi.

Currently I am having a big fight trying to implement a 2D camera with mojo2 and I did come across this article explaining how to implement a camera in Monkey X and mojo: How to create a 2D Camera Effect in Monkey X

The author in the article also share links to third party sites where he was looking for ideas and answers, I think it is worth reading.
However the code in the article is not complete and missing few things. Since I did not see this or similar example included with Cerberus and did not find any reference to it on the forum either, I did go ahead and added missing bits and ported over to mojo2 and I thought it is worth sharing since it is working well.

The camera in this example is pretty basic, you can move up-down and left-right and make it follow the player and move the player to the position of the mouse click. No rotation and zoom but definitely a good starting point for most games. Hope someone may find it useful in the future.

Cerberus X:
'original code from: http://evolvingdeveloper.com/up-is-down-left-is-right-how-to-create-a-2d-camera-effect-in-monkey-x/

Import mojo2

Class AppName Extends App
    
    Field myCanvas:Canvas
    
    Field player:Player
    Field cam:Camera
    
    Field plants:List<PlantLife>
    Field max_plants:Int
    
    Field map_width:Float
    Field map_height:Float
    
    Method OnCreate()
        myCanvas = New Canvas()
        SetUpdateRate(60)
        
        map_width = 1000
        map_height = 1000
        
        max_plants = 100
        plants = New List<PlantLife>
        player = New Player("Me", 320, 240, 4.0)
        cam = New Camera( )
        GeneratePlants()
        ' Set the random seed for this instance of the game
        Seed = Millisecs()
    End
    
    Method OnUpdate()
        ' Get our target position to move the player
        If MouseDown(0)
            player.SetTarget(MouseX() - cam.position.x, MouseY() - cam.position.y)
        End
        ' Update the camera before we update the player
        ' Because we don’t want to move the camera before the player starts moving
        cam.Update(player.velocity)
        player.Update()
        ' Refill our eaten plants
        GeneratePlants()
        
        'collect plants
        For Local plant := Eachin plants
            If plant.visible
                If player.position.Distance(plant.position) <= player.size
                    plant.visible = False
                    If player.size <= 30
                        player.size += 1
                    End
                End
            End
        End
    End
    
    Method OnRender()
        myCanvas.Clear(1, 1, 1)
        ' Push the matrix so we can draw a HUD later
        myCanvas.PushMatrix()
        ' Move our world to the camera position
        myCanvas.Translate(cam.position.x, cam.position.y)
        ' Draw in our player and our plant life
        player.Draw(myCanvas)
        For Local plant:PlantLife = Eachin plants
            plant.Draw(myCanvas)
        End
        ' Pop the matrix back out
        myCanvas.PopMatrix()
        
        myCanvas.Flush()
    End
    
    Method GeneratePlants()
        ' draw some plants on the screen so we can see when we move
        Local plant_count:Int = plants.Count()
        If plant_count < max_plants
            For Local i:Int = plant_count Until max_plants
                Local xpos:Float = Rnd(25.0, map_width - 20)
                Local ypos:Float = Rnd(25.0, map_height - 20)
                
                plants.AddLast(New PlantLife(xpos, ypos))
            End
        End
    End
End

Class Camera
    ' Camera class alos shamelessly borrowed from Jim's Small Time Outlaws
    ' Youtube channel on creating basic games with Monkey X
    ' Great stuff you should seriously check it out
    Field original_pos:Vec2D
    Field position:Vec2D
    
    Method New(x:Float=0, y:Float=0)
        Self.position = New Vec2D(x, y)
        Self.original_pos = New Vec2D(x, y)
    End
    
    Method Reset()
        Self.position.Set(original_pos.x, original_pos.y)
    End
    
    ' My own take on the update method though
    ' This is what we use to follow the player around
    Method Update(velocity:Vec2D)
        Self.position.x -= velocity.x
        Self.position.y -= velocity.y
    End
End

Class PlantLife
    Field position:Vec2D
    Field visible:Bool = True
    
    Method New(x:Float, y:Float)
        Self.position = New Vec2D(x, y)
    End
    
    Method Draw(_canvas:Canvas)
        If visible
            _canvas.SetColor(0, 0, 1)
            _canvas.DrawRect(position.x, position.y, 5, 5)
            _canvas.SetColor(1, 1, 1)
        End
    End
    
End

Class Player

    Field position:Vec2D
    Field old_position:Vec2D
    Field velocity:Vec2D
    Field target:Vec2D
    Field distance:Float
    Field name:String
    Field exp:Float
    Field size:Float = 10
    Field box:Vec2D = New Vec2D()

    Field speed:Float
    
    Method New(name:String, x:Float, y:Float, speed:Float)
        Self.name = name
        Self.position = New Vec2D(x, y)
        Self.old_position = New Vec2D(x, y)
        Self.speed = speed
        
        Self.velocity = New Vec2D(0, 0)
        Self.distance = 0
    End
    
    Method Draw(_canvas:Canvas)
        _canvas.SetColor(0, 1, 0)
        _canvas.DrawRect(position.x, position.y, size, size)
        _canvas.SetColor(1, 1, 1)
    End
    
    Method Update()
        ' update position
        Self.old_position.Set(position.x, position.y)
        Self.position.Set(position.x + velocity.x, position.y + velocity.y)
        ' update velocity
        If (target <> Null)
            If (position.Distance(target)) < distance
                distance = position.Distance(target)
            Else
                ' we are not getting closer to the target anymore so stop moving
                velocity.Set(0, 0)
            End
        End
        
        ' update box
        Self.box.Set(position.x, position.y)
    End
    
    Method SetTarget(x:Float, y:Float)
        Self.target = New Vec2D(x - 5, y - 5)
        
        distance = position.Distance(target)
        
        Local deltax:Float = Abs(target.x - position.x)
        Local deltay:Float = Abs(target.y - position.y)
        Local sum_delta:Float = deltax + deltay
        
        If (target.x > position.x)
            velocity.x = speed * (deltax / sum_delta)
        Else If (target.x < position.x)
            velocity.x = -speed * (deltax / sum_delta)
        End
        
        If (target.y > position.y)
            velocity.y = speed * (deltay / sum_delta)
        Else If (target.y < position.y)
            velocity.y = -speed * (deltay / sum_delta)
        End
        
    End

End

Class Vec2D
    ' Vec2D class shamelessly borrowed from Jim's Small Time Outlaws
    ' Youtube channel on creating basic games with Monkey X
    
    Field x:Float
    Field y:Float
    
    Method New(x:Float, y:Float)
        Set(x, y)
    End
    
    Method Set(x:Float, y:Float)
        Self.x = x
        Self.y = y
    End
    
    ' My own personal touch to Jim's code
    ' Calculates Euclidean Distance
    Method Distance(point:Vec2D)
        Local xdelta:Float = point.x - Self.x
        Local ydelta:Float = point.y - Self.y
        
        Return Sqrt(xdelta * xdelta + ydelta * ydelta)       
    End
    
End

Function Main()
    New AppName()
End
 
Last edited:
Top Bottom