You control the knight in armor, using the w-a-s-d keys.
The only objective is to attack the ants with your torch by pressing the space key.
You can also cheat using the mouse.
Code: Select all
'=======================================================================
' Marabunta
' by Ezekiel Gutierrez
' 2023
'=======================================================================
#include "fbgfx.bi"
#include "GL/gl.bi"
using fb
const SCREEN_WIDTH = 640
const SCREEN_HEIGHT = 360
const SCALING = 2
screenres SCREEN_WIDTH, SCREEN_HEIGHT, 32
screencontrol(SET_GL_2D_MODE, OGL_2D_MANUAL_SYNC)
screencontrol(SET_GL_SCALE, SCALING)
screenres SCREEN_WIDTH, SCREEN_HEIGHT, 32, , 2 or 1
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
const RAD_TO_DEG = 57.29577951308232
const DEG_TO_RAD = 0.017453292519943295769236907684886
const MAX_SPEED = 1.0
dim shared as double cos_table(359)
dim shared as double sin_table(359)
sub generate_lookup_tables()
dim as double angle = 0
for i as long = 0 to 359
cos_table(i) = cos(angle)
sin_table(i) = sin(angle)
angle += DEG_TO_RAD
next i
end sub
generate_lookup_tables()
function get_cos(angle as double) as double
dim as long index = (angle * RAD_TO_DEG) mod 360
while index < 0:index+=360:wend
return cos_table(index)
end function
function get_sin(angle as double) as double
dim as long index = (angle * RAD_TO_DEG) mod 360
while index < 0:index+=360:wend
return sin_table(index)
end function
dim shared as double timval,timevalold
dim shared as long editposit=1
timval=timer:timevalold=timval
dim shared as long frames,fps
dim shared as double prevtime
sub updatefps()
timval=timer
timval-=timevalold
timevalold=timer
timval*=60
'fps counter
frames+=1
if timer-1>prevtime then fps=frames:frames=0:prevtime=timer
'correction limit
if timval<0 then timval=0
if timval>10 then timval=10
end sub
'=======================================================================
' Types
'=======================================================================
type ant_type
x as double
y as double
dx as double
dy as double
squashed as boolean
angle as double
declare sub update(ants() as ant_type, mouse_x as long, mouse_y as long, click as long, byref dead as long, byref score as long)
declare sub render()
end type
type player_type
x as double
y as double
swing_x as double
swing_y as double
angle as double
torch_radius as double
is_swinging as boolean
swing_timer as double
last_direction as long
wiggle_offset as double
wiggle_direc as boolean
declare sub update(ants() as ant_type, mouse_x as long, mouse_y as long, click as long, byref dead as long, byref score as long)
declare sub render()
end type
type level_type
ants(any) as ant_type
player as player_type
dead as long
score as long
num_ants as long=1
dim as long mouse_x, mouse_y, click
declare sub initialize()
declare sub update()
declare sub render()
end type
'=======================================================================
' Routines
'=======================================================================
sub player_type.update(ants() as ant_type, mouse_x as long, mouse_y as long, click as long, byref dead as long, byref score as long)
' Attack ants with space key
if multikey(&H39) andalso swing_timer > 30 then
for i as long = 0 to ubound(ants)
if ants(i).squashed = false then
dim as long ant_dist_x = abs(ants(i).x - x)
dim as long ant_dist_y = abs(ants(i).y - y)
dim as long ant_distance = ant_dist_x * ant_dist_x + ant_dist_y * ant_dist_y
if ant_distance <= 20 * 20 * 8 then
ants(i).squashed = true
score += 1
swap ants(dead), ants(i)
dead += 1
end if
end if
next i
swing_timer = 0
is_swinging = true
end if
swing_timer += 1 * timval
' Move player with WASD keys
if multikey(&H11) then ' W key
y -= 1 * timval
x += wiggle_offset
last_direction = 0
end if
if multikey(&H1F) then ' S key
y += 1 * timval
x += wiggle_offset
last_direction = 1
end if
if multikey(&H1E) then ' A key
x -= 1 * timval
y += wiggle_offset
last_direction = 2
end if
if multikey(&H20) then ' D key
x += 1 * timval
y += wiggle_offset
last_direction = 3
end if
' Collide on screen edges
if x < 0 then x = 0
if x > SCREEN_WIDTH then x = SCREEN_WIDTH
if y < 0 then y = 0
if y > SCREEN_HEIGHT then y = SCREEN_HEIGHT
' Calculate vertical wiggle offset
if wiggle_direc= true then wiggle_offset+=0.1*timval
if wiggle_direc= false then wiggle_offset-=0.1*timval
if wiggle_offset>=0.5 then wiggle_direc=false
if wiggle_offset<=-0.5 then wiggle_direc=true
end sub
sub player_type.render()
if is_swinging=true then
angle += 0.2*timval
select case last_direction
case 0 ' Up
if angle > 1.5 * 3.14159 then angle = 1.5 * 3.14159 -6.28: is_swinging = false
case 1 ' Down
if angle > 3.14159 * 0.5 then angle = 3.14159 *0.5 -6.28: is_swinging = false
case 2 ' Left
if angle > 3.14159 then angle = -3.14159: is_swinging = false
case 3 ' Right
if angle > 2 * 3.14159 then angle = 0: is_swinging = false
end select
end if
swing_x = x + get_cos(angle) * torch_radius
swing_y = y + get_sin(angle) * torch_radius
dim as long torch_color = rgb(255, 200, 0)
dim as long bundle_color = rgb(220, 120, 60)
' Draw torch swinging animation
line (x, y)-(swing_x, swing_y), torch_color, bf
' Draw burning bundle at the end of the torch
circle (swing_x, swing_y), 6, bundle_color, , , , f
' Draw knight in armor
dim as long armor_color = rgb(100, 100, 100)
dim as long helmet_color = rgb(50, 50, 50)
dim as long sword_color = rgb(200, 200, 200)
' Body
circle (x, y), 10, armor_color, , , , f
' Helmet
circle (x, y - 10), 6, helmet_color, , , , f
' Arms
line (x - 8, y - 2)-(x + 8, y - 2), armor_color
' Legs
line (x - 4, y + 6)-(x - 2, y + 12), armor_color
line (x + 4, y + 6)-(x + 2, y + 12), armor_color
' Sword
line (x + 8, y + 6)-(x + 12, y - 2), sword_color
end sub
sub level_type.update()
if dead>num_ants then initialize()
getmouse mouse_x,mouse_y,, click
mouse_x/=SCALING
mouse_y/=SCALING
player.update(ants(),mouse_x,mouse_y,click,dead,score)
for i as long = 0 to ubound(ants)
ants(i).update(ants(),mouse_x,mouse_y,click,dead,score)
next
end sub
sub level_type.render()
' Draw background
line (0, 0)-(SCREEN_WIDTH, SCREEN_HEIGHT), rgb(170, 140, 110) , bf
' Render ants
for i as long = 0 to ubound(ants)
ants(i).render()
next
' Render player
player.render()
' Draw foreground (score and fps)
draw string (0, 0), "Score: " + str(score) + " fps: " + str(fps), rgb(255, 255, 255)
flip
end sub
sub level_type.initialize()
num_ants*=2
if num_ants>20000 then num_ants=20000
redim ants(num_ants)
dead=0
for i as long = 0 to ubound(ants)
ants(i).x = rnd * SCREEN_WIDTH
ants(i).y = rnd * SCREEN_HEIGHT
ants(i).dx = (rnd * 1.00)-(rnd * 1.00)
ants(i).dy = (rnd * 0.30)-(rnd * 0.30)
ants(i).squashed = false
next i
player.x = SCREEN_WIDTH / 2
player.y = SCREEN_HEIGHT / 2
player.angle = 0
player.torch_radius = 20
end sub
sub ant_type.update(ants() as ant_type,mouse_x as long,mouse_y as long,click as long, byref dead as long, byref score as long)
if squashed = false then
if click=1 then
dim as long dist_x = abs(mouse_x - x)
dim as long dist_y = abs(mouse_y - y)
dim as long distance = dist_x * dist_x + dist_y * dist_y
if distance <= 10 * 10 then squashed=true:score+=1:swap ants(dead), this:dead+=1
elseif click=2 then
dim as long dist_x = abs(mouse_x - x)
dim as long dist_y = abs(mouse_y - y)
dim as long distance = dist_x * dist_x + dist_y * dist_y
if distance <= 10 * 10 *10 *10 then squashed=true:score+=1:swap ants(dead), this:dead+=1
end if
x += dx*timval
y += dy*timval
' Bounce off the screen edges
if x<0 then x=0:dx = -dx
if x>SCREEN_WIDTH then x=SCREEN_WIDTH:dx = -dx
if y<0 then y=0:dy = -dy
if y>SCREEN_HEIGHT then y=SCREEN_HEIGHT:dy = -dy
dim as double dist_x
dim as double dist_y
' Apply simple collision avoidance
dim as long endj=ubound(ants)
dim as long active=ubound(ants)-dead
dim as long max_collision=(5000*5000)/(active)
if endj>max_collision then endj=max_collision
if endj>ubound(ants) then endj=ubound(ants)
for j as long = dead to endj
if @this<>@ants(j) then
dist_x = ants(j).x - x
dist_y = ants(j).y - y
if dist_x<10 andalso dist_y<10 then
dim as double distance = (dist_x * dist_x + dist_y * dist_y)
if distance < 2 * 5 * 2 * 5 then
dim as double angle = atan2(dist_y, dist_x)
dx -= get_cos(angle)
dy -= get_sin(angle)
' Limit the maximum speed
dim as double current_speed = dx * dx + dy * dy
if current_speed > MAX_SPEED*MAX_SPEED then
current_speed = sqr(dx * dx + dy * dy)
dx = (dx / current_speed) * MAX_SPEED
dy = (dy / current_speed) * MAX_SPEED
end if
exit for
end if
end if
end if
next j
end if
end sub
sub ant_type.render()
angle = atan2(dy, dx)
dim as long size = 5
dim as long body_color = rgb(20, 10, 10)
dim as long head_color = rgb(90, 0, 0)
dim as long squashed_body_color = rgb(60, 40, 30)
dim as long squashed_head_color = rgb(120, 60, 50)
' Calculate leg positions
dim as double leg_length = size * 1.2
dim as double leg_angle = angle + 3.14 / 4
dim as double leg1_x = x + get_cos(leg_angle) * leg_length
dim as double leg1_y = y + get_sin(leg_angle) * leg_length
dim as double leg2_x = x + get_cos(leg_angle + 3.14 / 2) * leg_length
dim as double leg2_y = y + get_sin(leg_angle + 3.14 / 2) * leg_length
dim as double leg3_x = x + get_cos(leg_angle + 3.14) * leg_length
dim as double leg3_y = y + get_sin(leg_angle + 3.14) * leg_length
dim as double leg4_x = x + get_cos(leg_angle + 3 * 3.14 / 2) * leg_length
dim as double leg4_y = y + get_sin(leg_angle + 3 * 3.14 / 2) * leg_length
if squashed then body_color=squashed_body_color:head_color=squashed_head_color
' Draw ant body
circle (x, y), size, body_color, , , , f
' Draw ant head
circle (x + get_cos(angle) * (size + 2), y + get_sin(angle) * (size + 2)), size * 0.6, head_color, , , , f
' Draw ant legs
line (leg1_x, leg1_y)-(leg1_x + get_cos(angle) * size, leg1_y + get_sin(angle) * size), body_color
line (leg2_x, leg2_y)-(leg2_x + get_cos(angle) * size, leg2_y + get_sin(angle) * size), body_color
line (leg3_x, leg3_y)-(leg3_x + get_cos(angle) * size, leg3_y + get_sin(angle) * size), body_color
line (leg4_x, leg4_y)-(leg4_x + get_cos(angle) * size, leg4_y + get_sin(angle) * size), body_color
end sub
'=======================================================================
' Main
'=======================================================================
dim as level_type level
level.initialize()
do
updatefps()
level.update()
level.render()
sleep 1,1
loop until multikey(1)