Yet Another Platformer

Game development specific discussions.
sero
Posts: 25
Joined: Mar 06, 2018 13:26
Location: USA

Yet Another Platformer

Postby sero » Nov 03, 2019 16:43

Greetings, I've been chipping away at a bare bones 2d platformer engine. The aim of this engine is to use horizontal tiled polygons instead of the more traditional tiled grid approach. I want to build this engine around responsive and enjoyable player movement using WASD + mouse control. Combat would primarily be ranged like in Metroid and Abuse with mouse aiming and camera focus being an engine feature.

I want the engine code to be open without restrictions. I have set up a GitHub account to enable collaboration. I am unfamiliar with GitHub and will post my efforts here first. I am a full time student and my experience in computer programming is limited. If you may be interested in collaborating please send me a message. Included is a prototype demonstrating simple horizontal movement and mouse directed camera focus.

GitHub repository => https://github.com/Serogue72/var-engine

Image

Code: Select all

const fps_cap = 30

#macro CONSOLE( _VALUE )
   shell "echo " + str( _VALUE )
#endmacro

type udt_RGB
   R as ubyte
   G as ubyte
   B as ubyte
end type

type udt_IMAGE_OLD_HEADER field = 1
   BPP : 3 as ushort
   W : 13 as ushort
   H as ushort
end type

type udt_IMAGE field = 1
   union
      OLD as udt_IMAGE_OLD_HEADER
      OLD_TYPE as ulong
   end union
   BPP as long
   W as ulong
   H as ulong
   PITCH as ulong
   RESERVED( 1 to 12 ) as ubyte
end type

type udt_MOUSE
   X as integer
   Y as integer
   W as integer
   B as integer
   PREVIOUS_B as integer
   CLIP as integer
   RESULT as long
   
   REGISTER as boolean
end type

type udt_CAMERA
  DIVIDER as single
  WIDTH_HALF as integer
  HEIGHT_HALF as integer
  X as integer
  Y as integer
end type

type udt_CELL
  WALL_Y_TOP( 0 to 1 ) as integer
  WALL_SLOPE_TOP as single
  WALL_Y_BOTTOM( 0 to 1 ) as integer
  WALL_SLOPE_BOTTOM as single
end type

type udt_CHUNK
  CELL( 0 to 19 ) as udt_CELL
end type

type udt_CHARACTER
  CELL_ID as byte
  X as integer
  Y as integer
end type

type udt_FRC
  as double fps_resolution
  as double fps_sleep_resolution
 
  as double previous_frame_timer
  as double previous_cycle_timer
  as double cycle_timer
 
  as double cycle_timer_difference
  as double cycle_timer_overlap
 
  as integer previous_frame_counter
  as integer frame_counter
 
  as double previous_sleep_time
  as double sleep_time
 
  declare constructor()
  declare sub START()
  declare sub REGULATE()
end type

dim shared as udt_CAMERA CAMERA
dim shared as udt_CHUNK CHUNK( 0 to 9 )
dim shared as udt_CHARACTER CHARACTER

dim shared as udt_IMAGE ptr FONT_SMALL
dim shared as udt_IMAGE ptr FONT_LARGE
dim shared as integer DRAW_CHARACTER_W( 0 to 1 )
dim shared as integer DRAW_CHARACTER_H( 0 to 1 )

dim shared as udt_MOUSE MOUSE
dim shared as integer SCREEN_SIZE

dim shared as udt_FRC FRC

declare sub INIT_SCREEN()
declare sub DESTROY_SCREEN()

declare sub INIT_CHUNK()
declare sub SWAP_CHUNKS( _direction as integer )

declare sub INIT_MOUSE()
declare sub UPDATE_MOUSE()

declare sub INIT_CHARACTER()
declare sub UPDATE_CHARACTER()

declare sub INIT_CAMERA()
declare sub UPDATE_CAMERA()

INIT_SCREEN()
INIT_CHUNK()
INIT_MOUSE()
INIT_CHARACTER()
INIT_CAMERA()

dim as integer I, J, K
dim as ubyte L, M
dim as string KEY

randomize, 3
FRC.START()
do
  KEY = inkey
  select case KEY
  case chr( 255 ) & "K" 'left
    CHARACTER.X = CHARACTER.X - 11
    if CHARACTER.X < 0 then
      CHARACTER.CELL_ID = CHARACTER.CELL_ID - 1
      CHARACTER.X = CHARACTER.X + 16
      if CHARACTER.CELL_ID = -1 then
        CHARACTER.CELL_ID = 19
        SWAP_CHUNKS( 4 )
      end if
    end if
  case chr( 255 ) & "M" 'right
    CHARACTER.X = CHARACTER.X + 11
    if CHARACTER.X > 15 then
      CHARACTER.CELL_ID = CHARACTER.CELL_ID + 1
      CHARACTER.X = CHARACTER.X - 16
      if CHARACTER.CELL_ID = 20 then
        CHARACTER.CELL_ID = 0
        SWAP_CHUNKS( 6 )
      end if
    end if
  end select
  if MOUSE.REGISTER then
    CHARACTER.CELL_ID = CHARACTER.CELL_ID + 1
    if CHARACTER.CELL_ID = 20 then
      CHARACTER.CELL_ID = 0
    end if
  end if
   UPDATE_MOUSE()
  UPDATE_CHARACTER()
  UPDATE_CAMERA()
  screenlock
    cls
   
      for I = 0 to 19
         K = I * 12
         M = L + K
         for J = 0 to 15
            line ( ( I * 16 ) - CAMERA.X + J - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y + ( J * CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP ) )-( ( I * 16 ) - CAMERA.X + J - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y + ( J * CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM ) ), rgb( 0, M, 0 )
         next J
         line ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line ( ( ( I + 1 ) * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
      for I = 0 to 19
         K = I * 12
         M = L + K
         for J = 0 to 15
            line ( ( I * 16 ) - CAMERA.X + J, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y + ( J * CHUNK( 5 ).CELL( I ).WALL_SLOPE_TOP ) )-( ( I * 16 ) - CAMERA.X + J, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y + ( J * CHUNK( 5 ).CELL( I ).WALL_SLOPE_BOTTOM ) ), rgb( M, 0, 0 )
         next J
         line ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line ( ( ( I + 1 ) * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
      for I = 0 to 19
         K = I * 12
         M = L + K
         for J = 0 to 15
            line ( ( I * 16 ) - CAMERA.X + J + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y + ( J * CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP ) )-( ( I * 16 ) - CAMERA.X + J + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y + ( J * CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM ) ), rgb( 0, 0, M )
         next J
         line ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line ( ( ( I + 1 ) * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
   
    ' dummy character
      'console( CHARACTER.CELL_ID )
    line ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X - 5, CHARACTER.Y - CAMERA.Y - 7 )-( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X + 5, CHARACTER.Y - CAMERA.Y + 16 ), rgb( 255, 255, 255 ), bf
    circle ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X, CHARACTER.Y - CAMERA.Y ), 3, rgb( 127, 0, 0 ), , , , F
   
    ' report framerate
    line ( 4, 3 )-( 99, 35 ), rgb( 0, 0, 0 ), bf
    draw string ( 4, 4 ), "fps cap (" & fps_cap & ")", rgb( 255, 127, 0 )
    draw string ( 4, 16 ), "fps old (" & frc.previous_frame_counter & ")", rgb( 255, 127, 0 )
    draw string ( 4, 28 ), "fps new (" & frc.frame_counter & ")", rgb( 255, 127, 0 )
  screenunlock
  L = L + 3
  FRC.REGULATE()
loop until( KEY = chr( 27 ) )

DESTROY_SCREEN()
END








constructor udt_FRC()
  fps_resolution = 1 / fps_cap
  fps_sleep_resolution = 1000 / fps_cap
  cycle_timer_overlap = 1
  previous_sleep_time = fps_resolution * 1000
end constructor

sub udt_FRC.START()
  previous_cycle_timer = timer
end sub

sub udt_FRC.REGULATE()
  frame_counter += 1
  cycle_timer = timer
  cycle_timer_difference = cycle_timer - previous_cycle_timer
  if cycle_timer_difference > cycle_timer_overlap then
    cycle_timer_overlap = 1 - ( cycle_timer_difference - cycle_timer_overlap )
    previous_cycle_timer = cycle_timer
    previous_frame_counter = frame_counter
    frame_counter = 0
  end if
  sleep_time = previous_sleep_time + ( ( fps_resolution - cycle_timer + previous_frame_timer ) * 1000 )
  if sleep_time < 1 then sleep_time = 1
  previous_sleep_time = sleep_time
 
  sleep sleep_time, 1
  previous_frame_timer = cycle_timer
end sub

sub INIT_SCREEN()
   screencontrol 103, "GDI"
   screenres 320, _
            180, _
            32,, _
            &h04
end sub

sub DESTROY_SCREEN()
   screen 0
end sub

sub INIT_CHUNK()
  dim as integer I, J
 
   CHUNK( 4 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 4 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 4 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 4 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 4 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 4 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 8
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) + 2
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - 4
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 9 to 10
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 11 to 18
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - 2
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) + 4
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   
   CHUNK( 4 ).CELL( 19 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 4 ).CELL( 19 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 4 ).CELL( 19 ).WALL_SLOPE_TOP = 0
   CHUNK( 4 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 4 ).CELL( 19 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 4 ).CELL( 19 ).WALL_SLOPE_BOTTOM = 0
 
   CHUNK( 5 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 5 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 5 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 5 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 5 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 5 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 19
      CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 5 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 5 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 5 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 5 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I

   CHUNK( 6 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 6 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 6 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 6 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 6 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 6 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 8
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - 1
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) + 6
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 9 to 10
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 11 to 18
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) + 1
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - 6
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   
   CHUNK( 6 ).CELL( 19 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 6 ).CELL( 19 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 6 ).CELL( 19 ).WALL_SLOPE_TOP = 0
   CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 6 ).CELL( 19 ).WALL_SLOPE_BOTTOM = 0
end sub

sub SWAP_CHUNKS( _direction as integer )
  dim as udt_CHUNK buffer
  select case _direction
  case 4
    buffer = CHUNK( 6 )
    CHUNK( 6 ) = CHUNK( 5 )
    CHUNK( 5 ) = CHUNK( 4 )
    CHUNK( 4 ) = buffer
  case 6
    buffer = CHUNK( 4 )
    CHUNK( 4 ) = CHUNK( 5 )
    CHUNK( 5 ) = CHUNK( 6 )
    CHUNK( 6 ) = buffer
  end select
end sub

sub INIT_MOUSE()
   MOUSE.RESULT = getmouse( MOUSE.X, MOUSE.Y, MOUSE.W, MOUSE.B, MOUSE.CLIP )
   MOUSE.PREVIOUS_B = MOUSE.B
end sub

sub UPDATE_MOUSE()
   MOUSE.PREVIOUS_B = MOUSE.B
   MOUSE.RESULT = getmouse( MOUSE.X, MOUSE.Y, MOUSE.W, MOUSE.B, MOUSE.CLIP )
   
   if MOUSE.RESULT = 0 then
      if ( ( MOUSE.B and 1 ) or ( MOUSE.B and 2 ) ) and _
          ( MOUSE.PREVIOUS_B = 0 ) then
         MOUSE.REGISTER = true
      else
         MOUSE.REGISTER = false
      end if
   end if
end sub

sub INIT_CHARACTER()
  CHARACTER.CELL_ID = 10
  CHARACTER.X = 0
  CHARACTER.Y = CAMERA.HEIGHT_HALF
end sub

sub UPDATE_CHARACTER()
  CHARACTER.Y = CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17
end sub

sub INIT_CAMERA()
  CAMERA.WIDTH_HALF = 160
  CAMERA.HEIGHT_HALF = 90
 
  CAMERA.DIVIDER = 1.15
end sub


sub UPDATE_CAMERA()
  CAMERA.X = ( ( MOUSE.X - CAMERA.WIDTH_HALF ) / CAMERA.DIVIDER ) + CHARACTER.X + ( ( CHARACTER.CELL_ID - 10 ) * 16 )
  CAMERA.Y = ( ( MOUSE.Y - CAMERA.HEIGHT_HALF ) / CAMERA.DIVIDER ) + ( CHARACTER.Y - CAMERA.HEIGHT_HALF )
end sub
Last edited by sero on Nov 04, 2019 19:39, edited 1 time in total.
badidea
Posts: 1570
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Yet Another Platformer

Postby badidea » Nov 03, 2019 19:59

Hi, platform games are not my favorite type of games. Maybe I played too much of them in the past.
But I am interested in your progress updates. Also on GitHub experience, which is also on my list to learn more.

On which OS do you develop? I can report the the code seems to run fine on linux here.
Some comments:
- You write WASD, but the control are still the left/right keys. No jumping yet :-(
- If you include mouse out-of-window detection, then you can keep the view on the last valid mouse position.
- I see a lot off nearly identical lines of code and 'magic numbers' e.g: "CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175". I amuse that this is only for this demo and later 'optimized away'.
sero
Posts: 25
Joined: Mar 06, 2018 13:26
Location: USA

Re: Yet Another Platformer

Postby sero » Nov 03, 2019 21:49

badidea wrote:- You write WASD, but the control are still the left/right keys. No jumping yet :-(

Haha, yeah this demo is lacking a few important things like proper keyboard handling and character movement. Those are next on the list. Jumping will most definitely be an important part of that. I want to make an enjoyable character movement and control experience that the world is built around instead of adapting movement and control to fit a certain world structure.

I use a Windows 10 machine for coding. I don't intend to make this an OS specific engine. I'm glad to hear this buggy and unoptimized prototype works on Linux :)
badidea
Posts: 1570
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: Yet Another Platformer

Postby badidea » Nov 04, 2019 20:22

This could be an interesting read for you (if you don't already know it): http://higherorderfun.com/blog/2012/05/ ... atformers/
c-sanchez
Posts: 118
Joined: Dec 06, 2012 0:38

Re: Yet Another Platformer

Postby c-sanchez » Nov 04, 2019 20:42

Platform is probably my favorite videogame genre, my two favorite are Castlevania and Megaman /Megaman X series.
The last ones I've played are AM2R, Cave Story, Axion Verge, The Mummy Demastered, Momodora: Reverie Under the Moonlight, Timespinner, Ghost 1.0, Iconoclasts, maybe some others? haha, I like really this genre :P
Now I'm playing Hollow Knight, I didn't find it very interesting at first glance, but it ended up being one of the ones I liked the most.

I would like view something nice with your engine :)
paul doe
Posts: 939
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Yet Another Platformer

Postby paul doe » Nov 04, 2019 20:56

sero wrote:... Combat would primarily be ranged like in Metroid and Abuse with mouse aiming and camera focus being an engine feature.
...


c-sanchez wrote:...
Platform is probably my favorite videogame genre, my two favorite are Castlevania and Megaman /Megaman X series.
...

Nice to see there's people here that appreciates good platform games ;)
sero
Posts: 25
Joined: Mar 06, 2018 13:26
Location: USA

Re: Yet Another Platformer

Postby sero » Nov 04, 2019 22:07

badidea wrote:http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

Thanks for sharing this webpage. Having taken a look at it I suppose the structure I'm going for is a combination of Smooth Tile Based with hit boxes like in MegaMan and Vectorial like in Braid. Looks like the second half of the article is about movement Nice! That's what I'm working on next.

I've made some changes to how the keyboard and mouse work. There is also image scaling for higher resolutions. The character is now able to jump in a crude manner. GitHub has been updated.

Code: Select all

type udt_IMAGE_OLD_HEADER field = 1
   BPP : 3 as ushort
   W : 13 as ushort
   H as ushort
end type

type udt_IMAGE field = 1
   union
      OLD as udt_IMAGE_OLD_HEADER
      OLD_TYPE as ulong
   end union
   BPP as long
   W as ulong
   H as ulong
   PITCH as ulong
   RESERVED( 1 to 12 ) as ubyte
end type

type udt_MOUSE
   X as integer
   Y as integer
   W as integer
   B as integer
   PREVIOUS_B as integer
   CLIP as integer
   RESULT as long
   
   REGISTER as boolean
end type

type udt_CAMERA
  DIVIDER as single
  WIDTH_HALF as integer
  HEIGHT_HALF as integer
  X as integer
  Y as integer
end type

type udt_FRAME_RATE
  as ubyte fps_cap
  as double fps_resolution
 
  as double frame_timer_previous
 
  as double cycle_timer_difference
  as double cycle_timer_previous
  as double cycle_timer
 
  as ubyte frame_counter_sum
  as ubyte frame_counter
 
  as long sleep_time_default
  as long sleep_time_previous
  as long sleep_time
 
  declare constructor()
  declare sub START()
  declare sub REGULATE()
end type

type udt_CELL
  WALL_Y_TOP( 0 to 1 ) as integer
  WALL_SLOPE_TOP as single
  WALL_Y_BOTTOM( 0 to 1 ) as integer
  WALL_SLOPE_BOTTOM as single
end type

type udt_CHUNK
  CELL( 0 to 19 ) as udt_CELL
end type

type udt_CHARACTER
  CELL_ID as byte
  X as integer
  Y as integer
end type

type udt_DISPLAY
  as integer SOURCE_W
  as integer SOURCE_H
  as udt_IMAGE ptr SOURCE_PTR
  as integer MULTIPLIER
  as integer W
  as integer H
end type

type event field = 1
    type as long
    union
        type
            SCANCODE as long
            ascii as long
        end type
        type
            x as long
            y as long
            dx as long
            dy as long
        end type
        button as long
        z as long
        w as long
    end union
end type

type udt_KEYBOARD
  NUM_KEYS as ubyte
  KEY_ID( 0 to 5 ) as ubyte
  KEY_STATE( 0 to 5 ) as ubyte
end type

dim shared as udt_FRAME_RATE FRAME_RATE
dim shared as udt_CAMERA CAMERA
dim shared as udt_CHUNK CHUNK( 4 to 6 )
dim shared as udt_CHARACTER CHARACTER
dim shared as udt_MOUSE MOUSE
dim shared as udt_DISPLAY DISPLAY
dim shared as event E
dim shared as udt_KEYBOARD KEYBOARD

declare sub INIT_DISPLAY()
declare sub DESTROY_DISPLAY()
declare sub FLIP_DISPLAY()
declare sub INIT_CHUNK()
declare sub SWAP_CHUNKS( _direction as integer )
declare sub INIT_MOUSE()
declare sub UPDATE_MOUSE()
declare sub INIT_KEYBOARD()
declare sub UPDATE_KEYBOARD()
declare sub INIT_CHARACTER()
declare sub UPDATE_OBJECTS
declare sub INIT_CAMERA()
declare sub UPDATE_CAMERA()

INIT_DISPLAY()
INIT_CHUNK()
INIT_MOUSE()
INIT_KEYBOARD()
INIT_CHARACTER()
INIT_CAMERA()

dim as integer I, J, K
dim as ubyte L, M

FRAME_RATE.START()
do
  UPDATE_KEYBOARD()
  UPDATE_OBJECTS()
   UPDATE_MOUSE()
  UPDATE_CAMERA()
  screenlock
    cls
   
    ' dummy chunk
      for I = 0 to 19
         K = I * 12
         M = L + K
         for J = 0 to 15
            line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + J - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y + ( J * CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP ) )-( ( I * 16 ) - CAMERA.X + J - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y + ( J * CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM ) ), rgb( 255-M, M, M )
         next J
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line DISPLAY.SOURCE_PTR, ( ( ( I + 1 ) * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
      for I = 0 to 19
         K = I * 12
         M = L + K
         for J = 0 to 15
            line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + J, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y + ( J * CHUNK( 5 ).CELL( I ).WALL_SLOPE_TOP ) )-( ( I * 16 ) - CAMERA.X + J, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y + ( J * CHUNK( 5 ).CELL( I ).WALL_SLOPE_BOTTOM ) ), rgb( M, 255-M, M )
         next J
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line DISPLAY.SOURCE_PTR, ( ( ( I + 1 ) * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
      for I = 0 to 19
         K = I * 12
         M = L + K
         for J = 0 to 15
            line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + J + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y + ( J * CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP ) )-( ( I * 16 ) - CAMERA.X + J + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y + ( J * CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM ) ), rgb( M, M, 255-M )
         next J
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line DISPLAY.SOURCE_PTR, ( ( ( I + 1 ) * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 31, 31 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
    '
    ' dummy character
      'console( CHARACTER.CELL_ID )
    line DISPLAY.SOURCE_PTR, ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X - 5, CHARACTER.Y - CAMERA.Y - 7 )-( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X + 5, CHARACTER.Y - CAMERA.Y + 16 ), rgb( 255, 255, 255 ), bf
    circle DISPLAY.SOURCE_PTR, ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X, CHARACTER.Y - CAMERA.Y ), 3, rgb( 255, 0, 0 ), , , , f
       
    draw string DISPLAY.SOURCE_PTR, ( 0, 1 ), "FPS:" & FRAME_RATE.frame_counter_sum, rgb( 255, 127, 0 )
   
    FLIP_DISPLAY()
   
    line DISPLAY.SOURCE_PTR, ( 0, 0 )-( DISPLAY.W - 1, DISPLAY.H - 1 ), rgb( 0, 0, 0), bf
  screenunlock
  L = L + 3
  FRAME_RATE.REGULATE()
loop until( KEYBOARD.KEY_STATE( 0 ) )

DESTROY_DISPLAY()
END

constructor udt_FRAME_RATE()
  fps_cap = 30
  fps_resolution = 1 / fps_cap
 
  sleep_time_default = 1000 / fps_cap
  sleep_time_previous = sleep_time_default
end constructor

sub udt_FRAME_RATE.START()
  cycle_timer_previous = timer
end sub

sub udt_FRAME_RATE.REGULATE()
  frame_counter += 1
 
  cycle_timer = timer
  cycle_timer_difference = cycle_timer - cycle_timer_previous
  if cycle_timer_difference > 1 then
    cycle_timer_previous += 1
    frame_counter_sum = frame_counter
    frame_counter = 0
  end if
 
  sleep_time = sleep_time_previous + ( ( fps_resolution - cycle_timer + frame_timer_previous ) * 1000 )
  frame_timer_previous = cycle_timer
  if sleep_time < 1 then
    sleep_time = 1
  elseif sleep_time > sleep_time_default then
    sleep_time = sleep_time_default
  end if
 
  sleep sleep_time, 1
  sleep_time_previous = sleep_time
end sub

sub INIT_DISPLAY()
  DISPLAY.SOURCE_W = 320
  DISPLAY.SOURCE_H = 180
 
  dim as integer RESOLUTION_LIST( 1 to 12, 0 to 1 )
  for i as integer = 1 to 12
    RESOLUTION_LIST( i, 0 ) = DISPLAY.SOURCE_W * i
    RESOLUTION_LIST( i, 1 ) = DISPLAY.SOURCE_H * i
  next i
 
  dim as integer DESKTOP_W, DESKTOP_H
  screeninfo DESKTOP_W, DESKTOP_H
 
  for j as integer = 12 to 1 step -1
    if ( RESOLUTION_LIST( j, 0 ) < DESKTOP_W ) and _
      ( RESOLUTION_LIST( j, 1 ) < DESKTOP_H ) then
      DISPLAY.W = RESOLUTION_LIST( j, 0 )
      DISPLAY.H = RESOLUTION_LIST( j, 1 )
      DISPLAY.MULTIPLIER = j
      exit for
    end if
  next j
 
  DISPLAY.W = 960
  DISPLAY.H = 540
  DISPLAY.MULTIPLIER = 3
 
  screencontrol 103, "GDI"
  screenres DISPLAY.W, _
            DISPLAY.H, _
            32,, _
            &h04

  DISPLAY.SOURCE_PTR = imagecreate( DISPLAY.SOURCE_W, DISPLAY.SOURCE_H )
  if DISPLAY.SOURCE_PTR = 0 then end
end sub

sub DESTROY_DISPLAY()
  imagedestroy DISPLAY.SOURCE_PTR
  screen 0
end sub

sub FLIP_DISPLAY()
  static as integer scale_counter_x, scale_counter_y
  static as integer scale_step
  static as integer scale_x_step = 0
  static as integer scale_y_step = 0
  static as ulong ptr scale_source_ptr
  static as ulong ptr scale_source_temp_ptr
  static as ulong ptr screen_ptr
 
  scale_step = ( 1 / DISPLAY.MULTIPLIER ) * 65536
  scale_source_ptr = cptr( ulong ptr, DISPLAY.SOURCE_PTR ) + 8
  scale_source_temp_ptr = scale_source_ptr
  screen_ptr = screenptr()
 
   select case DISPLAY.MULTIPLIER
   case is = 1
      put ( 0, 0 ), DISPLAY.SOURCE_PTR, pset
   case is > 1
      for scale_counter_y = 0 to ( DISPLAY.H - 1 )
         scale_source_temp_ptr = scale_source_ptr + ( scale_y_step shr 16 ) * DISPLAY.SOURCE_W
         for scale_counter_x = 0 to ( DISPLAY.W - 1 )
            *screen_ptr = scale_source_temp_ptr[ scale_x_step shr 16 ]
            screen_ptr += 1
            scale_x_step += scale_step
         next scale_counter_x
         scale_y_step += scale_step
         scale_x_step = 0
      next scale_counter_y
      scale_source_ptr = cptr( ulong ptr, DISPLAY.SOURCE_PTR ) + 8
      screen_ptr = screenptr()
      scale_y_step = 0
   case is < 1
      line ( 0, 0 )-( DISPLAY.W - 1, DISPLAY.H - 1 ), rgb( 255, 0, 255 ), bf
   end select
end sub

sub INIT_CHUNK()
  dim as integer I, J
 
   CHUNK( 4 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 4 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 4 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 4 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 4 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 4 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 8
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) + 2
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - 4
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 9 to 10
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 11 to 18
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - 2
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) + 4
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   
   CHUNK( 4 ).CELL( 19 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 4 ).CELL( 19 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 4 ).CELL( 19 ).WALL_SLOPE_TOP = 0
   CHUNK( 4 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 4 ).CELL( 19 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 4 ).CELL( 19 ).WALL_SLOPE_BOTTOM = 0
 
   CHUNK( 5 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 5 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 5 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 5 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 5 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 5 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 19
      CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 5 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 5 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 5 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 5 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I

   CHUNK( 6 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 6 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 6 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 6 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 6 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 6 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 8
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - 1
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) + 6
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 9 to 10
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 11 to 18
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) + 1
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - 6
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   
   CHUNK( 6 ).CELL( 19 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 6 ).CELL( 19 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 6 ).CELL( 19 ).WALL_SLOPE_TOP = 0
   CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 6 ).CELL( 19 ).WALL_SLOPE_BOTTOM = 0
end sub

sub SWAP_CHUNKS( _direction as integer )
  dim as udt_CHUNK buffer
  select case _direction
  case 4
    buffer = CHUNK( 6 )
    CHUNK( 6 ) = CHUNK( 5 )
    CHUNK( 5 ) = CHUNK( 4 )
    CHUNK( 4 ) = buffer
  case 6
    buffer = CHUNK( 4 )
    CHUNK( 4 ) = CHUNK( 5 )
    CHUNK( 5 ) = CHUNK( 6 )
    CHUNK( 6 ) = buffer
  end select
end sub

sub INIT_MOUSE()
   MOUSE.RESULT = getmouse( MOUSE.X, MOUSE.Y, MOUSE.W, MOUSE.B, MOUSE.CLIP )
   MOUSE.PREVIOUS_B = MOUSE.B
end sub

sub UPDATE_MOUSE()
  static as integer tX, tY, tW, tB, tC
 
   MOUSE.PREVIOUS_B = MOUSE.B
   MOUSE.RESULT = getmouse( tX, tY, tW, tB, tC )
  if MOUSE.RESULT = 0 then
    MOUSE.X = tX
    MOUSE.Y = tY
    MOUSE.W = tW
    MOUSE.B = tB
    MOUSE.CLIP = tC
   
      if ( ( MOUSE.B and 1 ) or ( MOUSE.B and 2 ) ) and _
          ( MOUSE.PREVIOUS_B = 0 ) then
         MOUSE.REGISTER = true
      else
         MOUSE.REGISTER = false
      end if
  end if
end sub

sub INIT_KEYBOARD()
  KEYBOARD.NUM_KEYS = 5
  KEYBOARD.KEY_ID( 0 ) = 1    'ESCAPE
  KEYBOARD.KEY_ID( 1 ) = 30  'A
  KEYBOARD.KEY_ID( 2 ) = 32  'D
  KEYBOARD.KEY_ID( 3 ) = 18  'W
  KEYBOARD.KEY_ID( 4 ) = 31  'S
  KEYBOARD.KEY_ID( 5 ) = 57  'SPACEBAR
end sub

sub UPDATE_KEYBOARD()
  static as ubyte I
  while screenevent(@E)
    if E.TYPE = 1 then 'EVENT_KEY_PRESS
      for I = 0 to KEYBOARD.NUM_KEYS
        if E.SCANCODE = KEYBOARD.KEY_ID( I ) then  KEYBOARD.KEY_STATE( I ) = 1
      next I
    elseif E.TYPE = 2 then 'EVENT_KEY_RELEASE
      for I = 0 to KEYBOARD.NUM_KEYS
        if E.SCANCODE = KEYBOARD.KEY_ID( I ) then KEYBOARD.KEY_STATE( I ) = 0
      next I
    end if
  wend
end sub

sub INIT_CHARACTER()
  CHARACTER.CELL_ID = 10
  CHARACTER.X = 0
  CHARACTER.Y = CAMERA.HEIGHT_HALF
  CHARACTER.Y = CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17
end sub

sub UPDATE_OBJECTS()
  if KEYBOARD.KEY_STATE( 1 ) then
    CHARACTER.X = CHARACTER.X - 11
    if CHARACTER.X < 0 then
      CHARACTER.CELL_ID = CHARACTER.CELL_ID - 1
      CHARACTER.X = CHARACTER.X + 16
      if CHARACTER.CELL_ID = -1 then
        CHARACTER.CELL_ID = 19
        SWAP_CHUNKS( 4 )
      end if
    end if
  end if
  if KEYBOARD.KEY_STATE( 2 ) then
    CHARACTER.X = CHARACTER.X + 11
    if CHARACTER.X > 15 then
      CHARACTER.CELL_ID = CHARACTER.CELL_ID + 1
      CHARACTER.X = CHARACTER.X - 16
      if CHARACTER.CELL_ID = 20 then
        CHARACTER.CELL_ID = 0
        SWAP_CHUNKS( 6 )
      end if
    end if
  end if
 
  ' LOL JUMP & GRAVITY
  if KEYBOARD.KEY_STATE( 5 ) then
    CHARACTER.Y = CHARACTER.Y - 16
  end if
  CHARACTER.Y = CHARACTER.Y + 8
  if CHARACTER.Y > CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17 then
    CHARACTER.Y = CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17
  end if
end sub

sub INIT_CAMERA()
  CAMERA.WIDTH_HALF = DISPLAY.W / 2
  CAMERA.HEIGHT_HALF = DISPLAY.H / 2
  CAMERA.DIVIDER = 1.15
end sub

sub UPDATE_CAMERA()
  CAMERA.X = ( ( ( MOUSE.X - CAMERA.WIDTH_HALF ) / CAMERA.DIVIDER ) / DISPLAY.MULTIPLIER )
    CAMERA.X = CAMERA.X + CHARACTER.X + ( ( CHARACTER.CELL_ID - 10 ) * 16 )
  CAMERA.Y = ( ( ( MOUSE.Y - CAMERA.HEIGHT_HALF ) / CAMERA.DIVIDER ) - CAMERA.HEIGHT_HALF ) / DISPLAY.MULTIPLIER
    CAMERA.Y = CAMERA.Y + CHARACTER.Y
end sub
sero
Posts: 25
Joined: Mar 06, 2018 13:26
Location: USA

Re: Yet Another Platformer

Postby sero » Nov 10, 2019 23:37

School has been keeping me busy and most my updates to this project have been minor. However, this current update is worth mentioning because character movement has been improved to include acceleration and jumping. Now the player can get a feel for character movement. The movement system and physics in this demonstration are temporary and will change over time. Also, there is support for higher resolutions using software scaling. Keyboard and mouse routines have been reworked a bit. WASD to move, spacebar to jump, and mouse to look around.

I'm going to take some time to clean up the code before I add to it. My next major goal is to make a more advanced map structure as originally planned. This will include vertical walls and branching pathways. Besides implementation this will stress the existing system so it may be another week or longer before I post an update (fingers crossed). After that is done I'll move my attention toward graphic tiling for the floor, ceiling, and walls. Also, the character will receive a sprite sheet and frame based animation.

GitHub repository => https://github.com/Serogue72/var-engine

Code: Select all

type udt_IMAGE_OLD_HEADER field = 1
   BPP : 3 as ushort
   W : 13 as ushort
   H as ushort
end type

type udt_IMAGE field = 1
   union
      OLD as udt_IMAGE_OLD_HEADER
      OLD_TYPE as ulong
   end union
   BPP as long
   W as ulong
   H as ulong
   PITCH as ulong
   RESERVED( 1 to 12 ) as ubyte
end type

type udt_MOUSE
   X as long
   Y as long
   W as long
   B as long
   PREVIOUS_B as long
   CLIP as long
   RESULT as long
   
   REGISTER as boolean
end type

type udt_CAMERA
  DIVIDER as single
  WIDTH_HALF as long
  HEIGHT_HALF as long
  X as long
  Y as long
end type

type udt_FRAME_RATE
  as ubyte fps_cap
  as double fps_resolution
 
  as double frame_timer_previous
 
  as double cycle_timer_difference
  as double cycle_timer_previous
  as double cycle_timer
 
  as ubyte frame_counter_sum
  as ubyte frame_counter
 
  as long sleep_time_default
  as long sleep_time_previous
  as long sleep_time
 
  declare constructor()
  declare sub START()
  declare sub REGULATE()
end type

type udt_CELL
  WALL_Y_TOP( 0 to 1 ) as long
  WALL_SLOPE_TOP as single
  WALL_Y_BOTTOM( 0 to 1 ) as long
  WALL_SLOPE_BOTTOM as single
end type

type udt_CHUNK
  CELL( 0 to 19 ) as udt_CELL
end type

type udt_CHARACTER
  CELL_ID as byte
  X as long
  Y as long
  H_ACC as single
  H_TH as single
  H_VEL as single
  IS_GROUND as byte
  IS_JUMP as byte
  JUMP_COUNTER_DEFAULT as ubyte
  JUMP_COUNTER as ubyte
  JUMP_TH as single
  GRAVITY_ACC as single
  GRAVITY_TH as single
  V_VEL as single
end type

type udt_FONT
  as udt_IMAGE ptr FONT_PTR
  as long W
  as long H
end type

type udt_DISPLAY
  as long SOURCE_W
  as long SOURCE_H
  as udt_IMAGE ptr SOURCE_PTR
  as long MULTIPLIER
  as long W
  as long H
  as long CURSOR_X
  as long CURSOR_Y
end type

type event field = 1
    type as long
    union
        type
            SCANCODE as long
            ascii as long
        end type
        type
            x as long
            y as long
            dx as long
            dy as long
        end type
        button as long
        z as long
        w as long
    end union
end type

type udt_KEYBOARD
  NUM_KEYS as ubyte
  KEY_ID( 0 to 5 ) as ubyte
  KEY_STATE( 0 to 5 ) as ubyte
end type

dim shared as udt_FRAME_RATE FRAME_RATE
dim shared as udt_CAMERA CAMERA
dim shared as udt_CHUNK CHUNK( 4 to 6 )
dim shared as udt_CHARACTER CHARACTER
dim shared as udt_MOUSE MOUSE
dim shared as udt_DISPLAY DISPLAY
dim shared as event E
dim shared as udt_KEYBOARD KEYBOARD

declare sub INIT_DISPLAY()
declare sub DESTROY_DISPLAY()
declare sub FLIP_DISPLAY()
declare sub INIT_CHUNK()
declare sub SWAP_CHUNKS( _direction as integer )
declare sub INIT_MOUSE()
declare sub UPDATE_MOUSE()
declare sub INIT_KEYBOARD()
declare sub UPDATE_KEYBOARD()
declare sub INIT_CHARACTER()
declare sub UPDATE_OBJECTS
declare sub INIT_CAMERA()
declare sub UPDATE_CAMERA()

INIT_DISPLAY()
INIT_CHUNK()
INIT_MOUSE()
INIT_KEYBOARD()
INIT_CHARACTER()
INIT_CAMERA()

dim as integer I, J

randomize, 3
FRAME_RATE.START()
do
  UPDATE_KEYBOARD()
  UPDATE_OBJECTS()
   UPDATE_MOUSE()
  UPDATE_CAMERA()
  screenlock
    cls
   
      for I = 0 to 19
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 - 320, CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 - 320, CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
      for I = 0 to 19
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1, CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1, CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
      for I = 0 to 19
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 + 320, CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CAMERA.Y ), rgb( 31, 31, 255 )
         line DISPLAY.SOURCE_PTR, ( ( I * 16 ) - CAMERA.X + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - CAMERA.Y )-( ( ( I + 1 ) * 16 ) - CAMERA.X - 1 + 320, CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CAMERA.Y ), rgb( 31, 255, 31 )
      next I
   
    line DISPLAY.SOURCE_PTR, ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X, CHARACTER.Y - CAMERA.Y )-( DISPLAY.CURSOR_X, DISPLAY.CURSOR_Y ), RGB( 255, 191, 0 )
    line DISPLAY.SOURCE_PTR, ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X - 5, CHARACTER.Y - CAMERA.Y - 7 )-( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X + 5, CHARACTER.Y - CAMERA.Y + 16 ), rgb( 255, 255, 255 ), bf
    circle DISPLAY.SOURCE_PTR, ( ( CHARACTER.CELL_ID * 16 ) + CHARACTER.X - CAMERA.X, CHARACTER.Y - CAMERA.Y ), 3, rgb( 255, 0, 0 ), , , , f
   
    draw string DISPLAY.SOURCE_PTR, ( 1, 2 ), "FPS:" & FRAME_RATE.frame_counter_sum, rgb( 255, 127, 0 )
    draw string DISPLAY.SOURCE_PTR, ( 1, 14 ), "VERTICAL:" & cast( byte, CHARACTER.V_VEL ), rgb( 255, 127, 0 )
    if CHARACTER.IS_JUMP then draw string DISPLAY.SOURCE_PTR, ( 1, 26 ), "JUMP", rgb( 255, 127, 0 )
   
    FLIP_DISPLAY()
   
    line DISPLAY.SOURCE_PTR, ( 0, 0 )-( DISPLAY.W - 1, DISPLAY.H - 1 ), rgb( 0, 0, 0), bf
  screenunlock
  FRAME_RATE.REGULATE()
loop until( KEYBOARD.KEY_STATE( 0 ) )

DESTROY_DISPLAY()

constructor udt_FRAME_RATE()
  fps_cap = 30
  fps_resolution = 1 / fps_cap
 
  sleep_time_default = 1000 / fps_cap
  sleep_time_previous = sleep_time_default
end constructor

sub udt_FRAME_RATE.START()
  cycle_timer_previous = timer
end sub

sub udt_FRAME_RATE.REGULATE()
  frame_counter += 1
 
  cycle_timer = timer
  cycle_timer_difference = cycle_timer - cycle_timer_previous
  if cycle_timer_difference > 1 then
    cycle_timer_previous += 1
    frame_counter_sum = frame_counter
    frame_counter = 0
  end if
 
  sleep_time = sleep_time_previous + ( ( fps_resolution - cycle_timer + frame_timer_previous ) * 1000 )
  frame_timer_previous = cycle_timer
  if sleep_time < 1 then
    sleep_time = 1
  elseif sleep_time > sleep_time_default then
    sleep_time = sleep_time_default
  end if
 
  sleep sleep_time, 1
  sleep_time_previous = sleep_time
end sub

sub INIT_DISPLAY()
  DISPLAY.SOURCE_W = 320
  DISPLAY.SOURCE_H = 180
 
  dim as integer RESOLUTION_LIST( 1 to 12, 0 to 1 )
  for i as integer = 1 to 12
    RESOLUTION_LIST( i, 0 ) = DISPLAY.SOURCE_W * i
    RESOLUTION_LIST( i, 1 ) = DISPLAY.SOURCE_H * i
  next i
 
  dim as integer DESKTOP_W, DESKTOP_H
  screeninfo DESKTOP_W, DESKTOP_H
 
  for j as integer = 12 to 1 step -1
    if ( RESOLUTION_LIST( j, 0 ) < DESKTOP_W ) and _
      ( RESOLUTION_LIST( j, 1 ) < DESKTOP_H ) then
      DISPLAY.W = RESOLUTION_LIST( j, 0 )
      DISPLAY.H = RESOLUTION_LIST( j, 1 )
      DISPLAY.MULTIPLIER = j
      exit for
    end if
  next j
 
  DISPLAY.W = 640
  DISPLAY.H = 360
  DISPLAY.MULTIPLIER = 2
 
  screencontrol 103, "GDI"
  screenres DISPLAY.W, _
            DISPLAY.H, _
            32,, _
            &h04

  DISPLAY.SOURCE_PTR = imagecreate( DISPLAY.SOURCE_W, DISPLAY.SOURCE_H )
  if DISPLAY.SOURCE_PTR = 0 then end
end sub

sub DESTROY_DISPLAY()
  imagedestroy DISPLAY.SOURCE_PTR
  screen 0
end sub

sub FLIP_DISPLAY()
  static as integer scale_counter_x, scale_counter_y
  static as integer scale_step
  static as integer scale_x_step = 0
  static as integer scale_y_step = 0
  static as ulong ptr scale_source_ptr
  static as ulong ptr scale_source_temp_ptr
  static as ulong ptr screen_ptr
 
  scale_step = ( 1 / DISPLAY.MULTIPLIER ) * 65536
  scale_source_ptr = cptr( ulong ptr, DISPLAY.SOURCE_PTR ) + 8
  scale_source_temp_ptr = scale_source_ptr
  screen_ptr = screenptr()
 
   select case DISPLAY.MULTIPLIER
   case is = 1
      put ( 0, 0 ), DISPLAY.SOURCE_PTR, pset
   case is > 1
      for scale_counter_y = 0 to ( DISPLAY.H - 1 )
         scale_source_temp_ptr = scale_source_ptr + ( scale_y_step shr 16 ) * DISPLAY.SOURCE_W
         for scale_counter_x = 0 to ( DISPLAY.W - 1 )
            *screen_ptr = scale_source_temp_ptr[ scale_x_step shr 16 ]
            screen_ptr += 1
            scale_x_step += scale_step
         next scale_counter_x
         scale_y_step += scale_step
         scale_x_step = 0
      next scale_counter_y
      scale_source_ptr = cptr( ulong ptr, DISPLAY.SOURCE_PTR ) + 8
      screen_ptr = screenptr()
      scale_y_step = 0
   case is < 1
      line ( 0, 0 )-( DISPLAY.W - 1, DISPLAY.H - 1 ), rgb( 255, 0, 255 ), bf
   end select
end sub

sub INIT_CHUNK()
  dim as integer I, J
 
   CHUNK( 4 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 4 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 4 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 4 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 4 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 4 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 8
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) + 2
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - 4
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 9 to 10
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 11 to 18
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) - 2
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 4 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) + 4
      CHUNK( 4 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 4 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   
   CHUNK( 4 ).CELL( 19 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 4 ).CELL( 19 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 4 ).CELL( 19 ).WALL_SLOPE_TOP = 0
   CHUNK( 4 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 4 ).CELL( 19 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 4 ).CELL( 19 ).WALL_SLOPE_BOTTOM = 0
 
   CHUNK( 5 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 5 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 5 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 5 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 5 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 5 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 19
      CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 5 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 5 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 5 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 5 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 5 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 5 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I

   CHUNK( 6 ).CELL( 0 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 6 ).CELL( 0 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 6 ).CELL( 0 ).WALL_SLOPE_TOP = 0
   CHUNK( 6 ).CELL( 0 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 6 ).CELL( 0 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 6 ).CELL( 0 ).WALL_SLOPE_BOTTOM = 0

   for I = 1 to 8
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) - 1
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) + 6
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 9 to 10
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 )
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 )
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   for I = 11 to 18
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_TOP( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) + 1
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_TOP = ( CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_TOP( 0 ) ) / 16
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) = CHUNK( 6 ).CELL( I - 1 ).WALL_Y_BOTTOM( 1 )
      CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) = CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) - 6
      CHUNK( 6 ).CELL( I ).WALL_SLOPE_BOTTOM = ( CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 1 ) - CHUNK( 6 ).CELL( I ).WALL_Y_BOTTOM( 0 ) ) / 16
   next I
   
   CHUNK( 6 ).CELL( 19 ).WALL_Y_TOP( 0 ) = 64
   CHUNK( 6 ).CELL( 19 ).WALL_Y_TOP( 1 ) = 64
   CHUNK( 6 ).CELL( 19 ).WALL_SLOPE_TOP = 0
   CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 0 ) = 175
   CHUNK( 6 ).CELL( 19 ).WALL_Y_BOTTOM( 1 ) = 175
   CHUNK( 6 ).CELL( 19 ).WALL_SLOPE_BOTTOM = 0
end sub

sub SWAP_CHUNKS( _direction as integer )
  dim as udt_CHUNK buffer
  select case _direction
  case 4
    buffer = CHUNK( 6 )
    CHUNK( 6 ) = CHUNK( 5 )
    CHUNK( 5 ) = CHUNK( 4 )
    CHUNK( 4 ) = buffer
  case 6
    buffer = CHUNK( 4 )
    CHUNK( 4 ) = CHUNK( 5 )
    CHUNK( 5 ) = CHUNK( 6 )
    CHUNK( 6 ) = buffer
  end select
end sub

sub INIT_MOUSE()
   MOUSE.RESULT = getmouse( MOUSE.X, MOUSE.Y, MOUSE.W, MOUSE.B, MOUSE.CLIP )
   MOUSE.PREVIOUS_B = MOUSE.B
end sub

sub UPDATE_MOUSE()
  static as integer tX, tY, tW, tB, tC
 
   MOUSE.PREVIOUS_B = MOUSE.B
   MOUSE.RESULT = getmouse( tX, tY, tW, tB, tC )
  if MOUSE.RESULT = 0 then
    MOUSE.X = tX
    MOUSE.Y = tY
    MOUSE.W = tW
    MOUSE.B = tB
    MOUSE.CLIP = tC
   
      if ( ( MOUSE.B and 1 ) or ( MOUSE.B and 2 ) ) and _
          ( MOUSE.PREVIOUS_B = 0 ) then
         MOUSE.REGISTER = true
      else
         MOUSE.REGISTER = false
      end if
  end if
  DISPLAY.CURSOR_X = MOUSE.X / DISPLAY.MULTIPLIER
  DISPLAY.CURSOR_Y = MOUSE.Y / DISPLAY.MULTIPLIER
end sub

sub INIT_KEYBOARD()
  KEYBOARD.NUM_KEYS = 5
  KEYBOARD.KEY_ID( 0 ) = 1    'ESCAPE
  KEYBOARD.KEY_ID( 1 ) = 30  'A
  KEYBOARD.KEY_ID( 2 ) = 32  'D
  KEYBOARD.KEY_ID( 3 ) = 18  'W
  KEYBOARD.KEY_ID( 4 ) = 31  'S
  KEYBOARD.KEY_ID( 5 ) = 57  'SPACEBAR
end sub

sub UPDATE_KEYBOARD()
  static as ubyte I
  while screenevent(@E)
    if E.TYPE = 1 then 'EVENT_KEY_PRESS
      for I = 0 to KEYBOARD.NUM_KEYS
        if E.SCANCODE = KEYBOARD.KEY_ID( I ) then  KEYBOARD.KEY_STATE( I ) = 1
      next I
    elseif E.TYPE = 2 then 'EVENT_KEY_RELEASE
      for I = 0 to KEYBOARD.NUM_KEYS
        if E.SCANCODE = KEYBOARD.KEY_ID( I ) then KEYBOARD.KEY_STATE( I ) = 0
      next I
    end if
  wend
end sub

sub INIT_CHARACTER()
  CHARACTER.CELL_ID = 10
  CHARACTER.X = 0
  CHARACTER.Y = CAMERA.HEIGHT_HALF
  CHARACTER.Y = CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17
  CHARACTER.H_ACC = 2.667
  CHARACTER.H_TH = 7
  CHARACTER.H_VEL = 0
  CHARACTER.IS_GROUND = 1
  CHARACTER.IS_JUMP = 0
  CHARACTER.JUMP_COUNTER_DEFAULT = 11
  CHARACTER.JUMP_COUNTER = CHARACTER.JUMP_COUNTER_DEFAULT
  CHARACTER.JUMP_TH = -7
  CHARACTER.GRAVITY_ACC = 1.334
  CHARACTER.GRAVITY_TH = 7
  CHARACTER.V_VEL = 0
end sub

sub UPDATE_OBJECTS()
  if KEYBOARD.KEY_STATE( 1 ) and KEYBOARD.KEY_STATE( 2 ) then
    ' CHANGE NOTHING
  elseif KEYBOARD.KEY_STATE( 1 ) then
    CHARACTER.H_VEL = CHARACTER.H_VEL - CHARACTER.H_ACC
    if CHARACTER.H_VEL < -CHARACTER.H_TH then CHARACTER.H_VEL = -CHARACTER.H_TH
  elseif KEYBOARD.KEY_STATE( 2 ) then
    CHARACTER.H_VEL = CHARACTER.H_VEL + CHARACTER.H_ACC
    if CHARACTER.H_VEL > CHARACTER.H_TH then CHARACTER.H_VEL = CHARACTER.H_TH
  else
    select case CHARACTER.H_VEL
    case 0
     
    case is > 0
      CHARACTER.H_VEL = CHARACTER.H_VEL - CHARACTER.H_ACC
      if CHARACTER.H_VEL < 0 then CHARACTER.H_VEL = 0
    case else
      CHARACTER.H_VEL = CHARACTER.H_VEL + CHARACTER.H_ACC
      if CHARACTER.H_VEL > 0 then CHARACTER.H_VEL = 0
    end select
  end if

  CHARACTER.X = CHARACTER.X + CHARACTER.H_VEL

  if CHARACTER.X < 0 then
    CHARACTER.CELL_ID = CHARACTER.CELL_ID - 1
    CHARACTER.X = CHARACTER.X + 16
    if CHARACTER.CELL_ID = -1 then
      CHARACTER.CELL_ID = 19
      SWAP_CHUNKS( 4 )
    end if
  end if
  if CHARACTER.X > 15 then
    CHARACTER.CELL_ID = CHARACTER.CELL_ID + 1
    CHARACTER.X = CHARACTER.X - 16
    if CHARACTER.CELL_ID = 20 then
      CHARACTER.CELL_ID = 0
      SWAP_CHUNKS( 6 )
    end if
  end if

  if KEYBOARD.KEY_STATE( 5 ) then
    if CHARACTER.IS_GROUND = 1 then
      CHARACTER.IS_GROUND = 0
      CHARACTER.IS_JUMP = 1
      CHARACTER.JUMP_COUNTER = CHARACTER.JUMP_COUNTER_DEFAULT
      CHARACTER.V_VEL = CHARACTER.JUMP_TH
    else
      if CHARACTER.IS_JUMP = 1 then
        CHARACTER.JUMP_COUNTER -= 1
      else
        CHARACTER.V_VEL += CHARACTER.GRAVITY_ACC
      end if
    end if
    if CHARACTER.JUMP_COUNTER = 0 then
      CHARACTER.JUMP_COUNTER = CHARACTER.JUMP_COUNTER_DEFAULT
      CHARACTER.IS_JUMP = 0
    end if
  else
    CHARACTER.IS_JUMP = 0
    if CHARACTER.IS_GROUND = 0 then
      CHARACTER.V_VEL += CHARACTER.GRAVITY_ACC
    else
      CHARACTER.V_VEL += CHARACTER.GRAVITY_ACC
    end if
    CHARACTER.JUMP_COUNTER = CHARACTER.JUMP_COUNTER_DEFAULT
  end if
 
  if CHARACTER.V_VEL > CHARACTER.GRAVITY_TH then CHARACTER.V_VEL = CHARACTER.GRAVITY_TH
  CHARACTER.Y = CHARACTER.Y + CHARACTER.V_VEL
  if CHARACTER.Y > CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17 then
    CHARACTER.Y = CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_BOTTOM( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_BOTTOM ) - 17
    CHARACTER.IS_GROUND = 1
    CHARACTER.IS_JUMP = 0
  end if
  if CHARACTER.Y < CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_TOP( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_TOP ) + 8 then
    CHARACTER.Y = CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_Y_TOP( 0 ) + ( CHARACTER.X * CHUNK( 5 ).CELL( CHARACTER.CELL_ID ).WALL_SLOPE_TOP ) + 8
    CHARACTER.V_VEL = 0
    CHARACTER.IS_JUMP = 0
  end if
end sub
sub INIT_CAMERA()
  CAMERA.WIDTH_HALF = DISPLAY.W / 2
  CAMERA.HEIGHT_HALF = DISPLAY.H / 2
  CAMERA.DIVIDER = 1.15
end sub

sub UPDATE_CAMERA()
  CAMERA.X = ( ( ( MOUSE.X - CAMERA.WIDTH_HALF ) / CAMERA.DIVIDER ) / DISPLAY.MULTIPLIER )
    CAMERA.X = CAMERA.X + CHARACTER.X + ( ( CHARACTER.CELL_ID - 10 ) * 16 )
  CAMERA.Y = ( ( ( MOUSE.Y - CAMERA.HEIGHT_HALF ) / CAMERA.DIVIDER ) - CAMERA.HEIGHT_HALF ) / DISPLAY.MULTIPLIER
    CAMERA.Y = CAMERA.Y + CHARACTER.Y
end sub
paul doe
Posts: 939
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Yet Another Platformer

Postby paul doe » Nov 11, 2019 20:13

@sero: looking nice so far! Ah, they don't make them like Abuse anymore, don't they? Did you, by any chance, toyed with the Abuse level editor? Or its Lisp code?
sero
Posts: 25
Joined: Mar 06, 2018 13:26
Location: USA

Re: Yet Another Platformer

Postby sero » Nov 11, 2019 23:51

paul doe wrote:Did you, by any chance, toyed with the Abuse level editor? Or its Lisp code?

The reason I know of Abuse is because I had a demo of it on my old Macintosh computer back when it first came out. This game provided a keyboard + mouse combination that I'd never encountered before. This combination that has become so standard in first person shooters works well in 2d. At the time I was still playing first person shooters with the keyboard only. Doom, Duke Nukem 3d, and Marathon were perfectly fine games without the mouse. Abuse was the game that initiated me into mouse look. Half Life was what eventually fully converted me. I remember my young self looking into the map editor being awed and confused. I don't remember anything about LISP code...

@paul - If Abuse really is your jam then maybe you've heard of Butcher? https://www.gog.com/game/butcher
paul doe
Posts: 939
Joined: Jul 25, 2017 17:22
Location: Argentina

Re: Yet Another Platformer

Postby paul doe » Nov 12, 2019 21:30

sero wrote:The reason I know of Abuse is because I had a demo of it on my old Macintosh computer back when it first came out. This game provided a keyboard + mouse combination that I'd never encountered before. ...

Indeed, it was a novelty at that time (circa 1995). Along with the engine's lighting system.
sero wrote:...
This combination that has become so standard in first person shooters works well in 2d. At the time I was still playing first person shooters with the keyboard only. Doom, Duke Nukem 3d, and Marathon were perfectly fine games without the mouse. Abuse was the game that initiated me into mouse look. Half Life was what eventually fully converted me.
...

Yes, most modern games eventually adopted the scheme. Pity they didn't adopted the concept of 'fun' along with it.
sero wrote:...
I remember my young self looking into the map editor being awed and confused. I don't remember anything about LISP code...
...

The game engine was coded (mostly; there were some precompiled sections) in Lisp, and the registered version came with full source code available (another uncommon practice at the time). The editor made full use of that, and used the concept of 'links' (which were all those gray lines you saw crisscrossing the screen). If you didn't managed to make some levels, you can do so now (there's a Win32 port of the game, totally free and authorized by the original authors), and redefine the concept of 'amazing'. Might give you quite a few ideas for the editor for your engine.
sero wrote:...
@paul - If Abuse really is your jam then maybe you've heard of Butcher? https://www.gog.com/game/butcher

No, I hadn't. Will have a look at it. Been ages since I buyed something from GoG (my last purchase was Planescape Torment, which I missed back in the day; came bundled with Tyrian 2000)

Return to “Game Dev”

Who is online

Users browsing this forum: No registered users and 2 guests