'----------------------------------------------------------------
'   TITLE: 2D Platformer Demo
'   AUTHOR: n00b
'   DATE: Nov 20, 2025
'
'   DESCRIPTION: Simple 2D Platformer Game Demo
'
'----------------------------------------------------------------

Include "nirvana.bas"

title$ = "Nirvana2D Template"
w = 640
h = 480
fullscreen = FALSE
vsync = TRUE

'Open a graphics window
OpenWindow( title$, w, h, fullscreen, vsync )

'Load Nirvana Stage
Nirvana_LoadStage("stage1", 0, 0, w, h)

'Vector for storing camera position
Dim camera_position As Nirvana_Vector2D

'Variable for storing camera move speed
cam_speed = 4

'Get the layer index that nirvana stores the sprite layer in
sprite_layer_index = Nirvana_GetLayerIndex("sprite_layer")

'Get the sprite layer canvas
sprite_canvas = Nirvana_GetLayerCanvasID(sprite_layer_index)

'Get the sprite index which is how nirvana refers to the sprite
graizor_index = Nirvana_GetLayerSpriteIndex(sprite_layer_index, "Graizor")

'Get the sprite id that RCBasic uses to reference the sprite
graizor_id = Nirvana_GetSpriteID(graizor_index)
detached_id = Nirvana_GetDetachedSpriteID(graizor_index)

'Need to be on sprite canvas to operate on sprite
Canvas(sprite_canvas)
SetGravity2D(0, 70)
SetSpriteSolid(detached_id, TRUE)

graizor_move_speed = 120
graizor_jump_force = 380


speed = 0
jump_ready = FALSE
jump_force = 0
d_timer = 0

animation_idle_left = Nirvana_GetSpriteAnimationIndex(graizor_index, "Idle_Left")
animation_idle_right = Nirvana_GetSpriteAnimationIndex(graizor_index, "Idle_Right")
animation_walk_left = Nirvana_GetSpriteAnimationIndex(graizor_index, "Walk_Left")
animation_walk_right = Nirvana_GetSpriteAnimationIndex(graizor_index, "Walk_Right")
animation_jump_left = Nirvana_GetSpriteAnimationIndex(graizor_index, "Jump_Left")
animation_jump_right = Nirvana_GetSpriteAnimationIndex(graizor_index, "Jump_Right")

current_animation = GetSpriteAnimation(graizor_id)

'Exit While Loop when ESCAPE is pressed
While Not Key(K_ESCAPE)
	'Get the Current Camera Position
	camera_position = Nirvana_GetStageOffset()
	
	jump_force = 0
	
	'Move camera position Left or Right when arrow keys are pressed
	If Key(K_LEFT) Then
		speed = -1 * graizor_move_speed
	ElseIf Key(K_RIGHT) Then
		speed = graizor_move_speed
	Else
		speed = 0
	End If
	
	'Move camera position Up or Down when arrow keys are pressed
	If Key(K_SPACE) And jump_ready And (Timer() - d_timer) > 300 Then
		jump_force = -1 * graizor_jump_force
		d_timer = Timer()
	End If
	
	start_x = SpriteX(detached_id) + (SpriteWidth(graizor_id)/2)
	start_y = SpriteY(graizor_id)
	end_x = start_x
	end_y = start_y + 66
	num_hits = CastRay2D_All(start_x, SpriteY(detached_id), end_x, end_y)
	
	'Loop through all sprites hit by ray to check if sprite hit the ground
	jump_ready = FALSE
	For i  = 0 To num_hits-1
		Dim hit_id   'This variable will store the sprite_id hit
		Dim n   'This variable will just be used in place of the other parameters in GetRayHit2D() since I don't need those values for what I am doing
		
		'NOTE: Normally, you would want to get the sprite ids for the ground collision shapes but I know that every other sprite other than graizor and detached are ground shapes
		hit_id = -1
		GetRayHit2D(i, hit_id, n, n, n, n)
		
		'We will ignore graizor_id and detached_id
		If hit_id = graizor_id Or hit_id = detached_id Then
			Continue
		End If
		
		If hit_id >= 0 Then
			jump_ready = TRUE
			Exit For
		End If
	Next
	
	
	prev_animation = GetSpriteAnimation(graizor_id)
	
	If jump_ready Then
		If speed < 0 Then
			current_animation = animation_walk_left
		ElseIf speed > 0 Then
			current_animation = animation_walk_right
		Else
			Select Case current_animation
			Case animation_jump_left, animation_walk_left
				current_animation = animation_idle_left
			Case animation_jump_right, animation_walk_right
				current_animation = animation_idle_right
			End Select
		End If
	Else
		If speed < 0 Then
			current_animation = animation_jump_left
		ElseIf speed > 0 Then
			current_animation = animation_jump_right
		Else
			Select Case current_animation
			Case animation_idle_left, animation_walk_left
				current_animation = animation_jump_left
			Case animation_idle_right, animation_walk_right
				current_animation = animation_jump_right
			End Select
		End If
	End If
	
	If current_animation <> prev_animation Then
		SetSpriteAnimation(graizor_id, current_animation, -1)
	End If
	
	Dim vx, vy
	GetSpriteLinearVelocity(detached_id, vx, vy)
	SetSpriteLinearVelocity(detached_id, speed, vy)
	
	
	If jump_force <> 0 Then
		SetSpriteLinearVelocity(detached_id, speed, jump_force)
	End If
	
	Dim ix, iy
	GetSpritePosition(detached_id, ix, iy)
	camera_position.X = Max(0, ix - w/2)
	
	'Set camera to new position
	Nirvana_SetStageOffset(camera_position)

	'This update function must be used for Nirvana Projects
	Nirvana_Update()
Wend
