CITY FIGHTER
Primitive Shapes
Your mission is simple : Defeat all red enemies and 1 green Boss
Control Keys
-LEFT, RIGHT = move
-SPACE BAR = punch
-R = continue
-ESC = quit
Code:
'==================================================================
'
' CITY FIGHTER
' Primitive Shapes
' Your mission is simple : Defeat all red enemies and 1 green Boss
'
' Control Keys
' -LEFT, RIGHT = move
' -SPACE BAR = punch
' -R = continue
' -ESC = quit
'
'==================================================================
include "sfx.n7"
visible sfx = SFX() 'create an sfx instance
#win32
' Set up the screen resolution
set window "CITY FIGHTER", 800, 600
set redraw off
randomize time()
'Note frequency in the 5th Octave
constant DO = 261.63*2
constant RE = 293.66*2
constant MI = 329.63*2
constant FA = 349.23*2
constant SO = 392.00*2
constant LA = 440.00*2
constant TI = 493.88*2
' Constants
constant gravity = 0.8
constant move_step = 10 ' Distance moved per step
constant knockback_step = 20 ' Distance stepped backward during knockback
constant boundary_left = 50 ' Left boundary
constant boundary_right = 750 ' Right boundary
constant ground_level = 400 ' Ground level
constant attack_width = 50 ' Width of attack hitbox
constant attack_height = 20 ' Height of attack hitbox
constant attack_duration = 10 ' Frames an attack lasts
constant max_health = 200 ' Maximum health for players
' Draw attack (if active)
if attack.timer > 0 then
set color attack.c
draw rect attack.x, attack.y, attack_width, attack_height, true
endif
' Check for game over
handle_game_over()
' Decrement hit timers
if player1_hit_timer > 0 then
player1_hit_timer = player1_hit_timer - 1
endif
if player2_hit_timer > 0 then
player2_hit_timer = player2_hit_timer - 1
endif
fwait 30
redraw
wend
'------------
' FUNCTIONS
'------------
' Restart function
function restart_game()
player1.x = 100
player1.y = ground_level
player1.vy = 0
player1.ground = true
player1.health = max_health
player2.x = 600
player2.y = ground_level
player2.vy = 0
player2.ground = true
player2.health = max_health
attack.timer = 0
computer.moveTimer = 0
computer.attackTimer = 0
player2_resurrections = 3 ' Reset resurrection count
player1_hit_timer = 0 ' Reset hit effect timer for Player 1
player2_hit_timer = 0 ' Reset hit effect timer for Player 2
endfunc
' Handle player movement
function handle_player_movement(player_x, player_y, player_vy, player_on_ground, move_direction, is_computer)
if not is_computer then
' Human player input
if keydown(KEY_UP, true) and player_on_ground then
player_vy = -10 ' Jump
player_on_ground = false
endif
if keydown(KEY_LEFT, true) then
move_direction = -1 ' Move left
elseif keydown(KEY_RIGHT, true) then
move_direction = 1 ' Move right
else
move_direction = 0 ' No movement
endif
else
' computer movement logic
if computer.moveTimer <= 0 then
computer.moveTimer = rnd(30, 60) ' Set a random timer for the next movement decision
if abs(player1.x - player2.x) > 200 then
move_direction = choose(1, -1, 0) ' Move toward Player 1 if far away
else
move_direction = choose(-1, 0, 1) ' Random movement if close
endif
else
computer.moveTimer = computer.moveTimer - 1 ' Decrement timer
endif
endif
' Update position based on direction
if move_direction = -1 then
player_x = max(player_x - move_step, boundary_left) ' Move left
elseif move_direction = 1 then
player_x = min(player_x + move_step, boundary_right - player1.w) ' Move right
endif
return [player_x, player_y, player_vy, player_on_ground, move_direction]
endfunc
' Apply gravity and update positions
function apply_gravity_and_update_positions()
player1.vy = player1.vy + gravity
player2.vy = player2.vy + gravity
player1.y = player1.y + player1.vy
player2.y = player2.y + player2.vy
' Check if players are on the ground
if player1.y >= ground_level then
player1.y = ground_level
player1.vy = 0
player1.ground = true
endif
if player2.y >= ground_level then
player2.y = ground_level
player2.vy = 0
player2.ground = true
endif
endfunc
' Collision detection
function check_collision(x1, y1, w1, h1, x2, y2, w2, h2)
' Check if two rectangles overlap
return x1 < x2 + w2 and x1 + w1 > x2 and y1 < y2 + h2 and y1 + h1 > y2
endfunc
' Draw player and health bar
function draw_player(x, y, w, h, color_body, color_head, health, health_x, health_y, hit_timer)
' Apply hit effect if active
if hit_timer > 0 then
y = y + sin(hit_timer * 10) * 5 ' Oscillate vertically
endif
' Draw player body
set color color_body
draw rect x, y, w, h, true
' Draw player head
set color color_head
draw ellipse x + w / 2, y - 20, 20, 20, true
' Draw health bar
set color color_body
draw rect health_x, health_y, health, 20, true ' Health bar
set color 255, 255, 255 ' White border
draw rect health_x, health_y, max_health, 20 ' Border for health bar
endfunc
' Handle attacks
function handle_attacks()
if stage=1 then impact = 10
if stage=2 then impact = 5
' Handle Player 1 Attacks
if keydown(KEY_SPACE, true) and attack.timer <= 0 then
attack.c = [0, 0, 255] ' Blue for Player 1
attack.timer = attack_duration
attack.x = player1.x + player1.w
attack.y = player1.y + player1.h / 2 - attack_height / 2
if check_collision(attack.x, attack.y, attack_width, attack_height,
player2.x, player2.y, player2.w, player2.h) then
play sound punch1_sfx
player2.health = max(player2.health - impact, 0)
player2.x = min(player2.x + knockback_step,boundary_right-player2.w)' Step Player 2 backward
player2_hit_timer = 10 ' Trigger hit effect for Player 2
endif
endif
' Handle Player 2 computer Attack
if computer.attackTimer <= 0 then
if rnd(1, 100) <= 40 then ' chance to attack
if stage=1 then attack.c = [255, 0, 0] ' Red for Player 2 and stage=1
if stage=2 then attack.c = [0,255,0] ' Green for player 2 and stage=2
attack.timer = attack_duration
attack.x = player2.x - attack_width
attack.y = player2.y + player2.h / 2 - attack_height / 2
if check_collision(attack.x, attack.y, attack_width, attack_height,
player1.x, player1.y, player1.w, player1.h) then
play sound punch2_sfx
player1.health = max(player1.health - 10, 0)
player1.x = max(player1.x - knockback_step,boundary_left) ' Step Player 1 backward
player1_hit_timer = 10 ' Trigger hit effect for Player 1
endif
endif
computer.attackTimer = rnd(0, 60) ' Random cooldown for next attack
else
computer.attackTimer = computer.attackTimer - 1
endif
' Decrement attack timer
if attack.timer > 0 then
attack.timer = attack.timer - 1
endif
endfunc
' Handle game over
function handle_game_over()
if player1.health <= 0 then
write_gameover(0)
do; wait 1; redraw; until keydown(KEY_R, true) ' for R to restart
restart_game()
endif
if player2.health <= 0 and stage=1 then
' Check if Player 2 has remaining resurrections only for stage=1
if player2_resurrections > 0 then
' Resurrect Player 2
player2_resurrections = player2_resurrections - 1
player2.health = max_health ' Restore Player 2's health to 100%
player2.x = 600 ' Reset Player 2's position
player2.y = ground_level
player2.vy = 0
player2.ground = true
' Display a red splash screen
set color 255, 0, 0,100
draw rect 0,0,width(),height(),true
set caret width() / 2, height() / 2
set color 255,255,255
center "Ready, GO !"
center "Press R to continue"
redraw
do;wait 1;until keydown(KEY_R,true) ' Pause briefly to show the message
else
' No more red enemies, goto Boss Level
write_gameover(1)
if stage=1 then
play_sound = true
car_passes = 0
cutscene()
endif
stage=2
' Display a green splash screen
set color 0, 255, 0,100
draw rect 0,0,width(),height(),true
set caret width() / 2, height() / 2
set color 255,255,255
center "Fight the Boss"
center "Press R to continue"
redraw
do; wait 1; redraw; until keydown(KEY_R, true) ' R to restart
restart_game()
endif
endif
if player2.health <= 0 and stage=2 then
write_gameover(1)
' Display a blue splash screen
set color 0, 0, 255,100
draw rect 0,0,width(),height(),true
set caret width() / 2, height() / 2
set color 255,255,255
center "Thank you for playing this game"
center "Press R to restart"
redraw
do; wait 1; redraw; until keydown(KEY_R, true) ' R to restart
stage = 1
restart_game()
endif
endfunc
' Play cutscene animation: Scrolling background and car
function cutscene()
background_offset = 0
car_x = 800 ' Start car off-screen
if stage = 1 then
' Draw ground plane
set color 50, 50, 50
draw rect 0, 500, 800, 100, true
draw_title()
redraw
endif
if play_sound then
Song()
play_sound = false
endif
while car_passes < 5+1
' Clear screen
set color 0, 0, 0
cls
' Scroll background
background_offset = background_offset - 5
if background_offset <= -800 then
background_offset = 0
endif
draw_scrolling_background(background_offset)
' Draw car
draw_car(car_x, ground_level+100)
car_x = car_x - 10 ' Move car left
if car_x <= -100 then
car_x = 800 ' Reset car position
car_passes = car_passes + 1
endif
' Stop car on pass
if car_passes = 5 then
car_x = 800 ' Keep car at the right edge
scrolling = false
break
endif
fwait 60
redraw
wend
endfunc
' Draw ground plane
set color 50, 50, 50
draw rect 0 + offset, 500, 800, 100, true
draw rect 800 + offset, 500, 800, 100, true
endfunc
' Draw car
function draw_car(x, y)
set color 255, 0, 0
draw rect x, y, 180, 30, true ' Body
draw rect x + 10, y - 20, 160, 20, true ' Roof
set color 0, 0, 0
draw ellipse x + 40, y + 30, 20, 20, true ' Left wheel
draw ellipse x + 140, y + 30, 20, 20, true ' Right wheel
PlayTune(3)
endfunc
' Custom choose function
function choose(option1, option2, option3)
options = []
options[0] = option1
options[1] = option2
options[2] = option3
return options[rnd(0, 2)] ' Randomly select one of the three options
endfunc
' Draw background
function draw_background()
' Clear the screen with a black background
set color 0, 0, 0
cls
set color 255,255,255
set caret 50,30 ; wln "Player 1"
set caret 680,30
if stage = 1 then wln "Player 2"
if stage = 2 then wln "BOSS"
' Draw buildings
draw_building( 50, 500, 140, 400)
draw_building(200, 500, 140, 180)
draw_building(350, 500, 140, 300)
draw_building(500, 500, 140, 350)
draw_building(650, 500, 100, 160)
' Draw ground plane
set color 50, 50, 50
draw rect 0, 500, 800, 100, true
' Draw Title
draw_title()
endfunc
' Helper function to draw a building
function draw_building(x, y, w, h)
' Draw rectangular building
set color 100,100,100
draw rect x, y - h, w, h, true
' Add windows
set color 0, 0, 0
for i = 0 to w step 20
for j = 0 to h step 20
draw rect x + i + 5, y - h + j + 5, 10, 10, true
next
next
endfunc
function load_pattern(pattern_data)
' Converts a 2D array of pattern data into a usable format
pattern = []
for i = 0 to sizeof(pattern_data) - 1
pattern[i] = pattern_data[i]
next
return pattern
endfunc
function draw_title()
' Write "City Fighter" using 5x5 patterns
set color 255, 255, 255
' Parameters for the 5x5 grids
cell_size = 10 ' Size of each cell in the grid
spacing = 10 ' Spacing between letters
word_spacing = 50 ' Additional spacing between "City" and "Fighter"
start_x = 50 ' X-coordinate of the top-left corner of the first letter
start_y = 520 ' Y-coordinate of the top-left corner of the first letter
' Array of patterns for "City Fighter"
patterns = [letter.C, letter.I, letter.T, letter.Y,
letter.F, letter.I, letter.G, letter.H, letter.T, letter.E, letter.R]
' Draw all patterns side by side
current_x = start_x
for i = 0 to sizeof(patterns) - 1
' Get the current pattern
pattern = patterns[i]
' Draw the pattern
draw_letter(pattern, current_x, start_y, cell_size)
' Move to the next letter position
current_x = current_x + (5 * cell_size) + spacing
' Add extra spacing between "City" and "Fighter"
if i = len("City")-1 then
current_x = current_x + word_spacing
endif
next
endfunc
function draw_letter(pattern, x, y, cell_size)
set color 255, 255, 255
' Draws a single letter based on its pattern
for row = 0 to 4
for col = 0 to 4
if pattern[row][col] = 1 then
draw rect x + col * cell_size, y + row * cell_size, cell_size, cell_size, true
endif
next
next
endfunc
function write_gameover(x)
' Write Message
set color 255,255,0
set caret width()/2,30
center "Press R to restart the City Fighter"
' Draw ground plane
set color 50, 50, 50
draw rect 0, 500, 800, 100, true
' Parameters for the 5x5 grids
cell_size = 10 ' Size of each cell in the grid
spacing = 10 ' Spacing between letters
word_spacing = 50 ' Additional spacing between "City" and "Fighter"
start_x = 150 ' X-coordinate of the top-left corner of the first letter
start_y = 520 ' Y-coordinate of the top-left corner of the first letter
' Array of patterns for "You Win" and "You Lose"
if x = 1 then
patterns = [letter.Y, letter.O, letter.U, letter.W, letter.I, letter.N]
else
patterns = [letter.Y, letter.O, letter.U, letter.L, letter.O, letter.S, letter.E]
endif
' Draw all patterns side by side
current_x = start_x
for i = 0 to sizeof(patterns) - 1
' Get the current pattern
pattern = patterns[i]
' Draw the pattern
draw_letter(pattern, current_x, start_y, cell_size)
' Move to the next letter position
current_x = current_x + (5 * cell_size) + spacing
' Add extra spacing after "You"
if i = len("You")-1 then
current_x = current_x + word_spacing
endif
next
endfunc
' Mix four different noise frequencies weighted, in a weird way, by the pitch value.
freqs = [
[v: 0, p: sampleRate/500, d: 0, t: 0, w: pitch],
[v: 0, p: sampleRate/1000, d: 0, t: 0, w: pitch^2],
[v: 0, p: sampleRate/2000, d: 0, t: 0, w: pitch^3],
[v: 0, p: sampleRate/8000, d: 0, t: 0, w: pitch^4]]
s = sizeof(freqs)
data = []
vol = 1
fadeOut = fadeOut*duration*sampleRate
fadeOutDelta = 1/(duration*sampleRate - fadeOut)
for i = 0 to duration*sampleRate - 1
v = 0
w = 0
for j = 0 to s - 1; f = freqs[j]
f.t = f.t - 1
if f.t <= 0
f.t = f.p
f.d = ((rnd()*2 - 1) - f.v)/f.p
endif
f.v = f.v + f.d
v = v + f.v*f.w
w = w + f.w
next
data[i] = vol*v/w
if i > fadeOut vol = vol - fadeOutDelta
next
'This function will play sound frequency x at duration b
function Piano(b,x)
'SquareWave(duration,freq,volume)
mytune = sfx.SquareWave(b,x,0.05)
play sound mytune
Pause()
free sound mytune 'release sound from memeory
endfunc
function Song()
Piano(b2,SO);Piano(b1,SO);Piano(b1,SO)
Piano(b2,SO);Piano(b2,MI)
Piano(b2,DO*2);Piano(b1,DO*2);Piano(b1,DO*2)
Piano(b2,TI);Piano(b2,LA)
endfunc
function Pause()
wait 100
endfunc
function Sound(b,x)
mytune = sfx.SquareWave(b,x,0.2)'(duration,frequency, volume)
play sound mytune ; wait 1
free sound mytune 'release sound from memory
endfunc
function PlayTune(i)
select i
case 1 'starting the game's scene
Sound(0.5,261.63);Sound(0.5,293.66);Sound(0.5,329.63)
case 2 'road's boundary
Sound(0.5,329.63*3);Sound(0.5,261.63*3)
case 3 'car's sound effect
Sound(0.05,261.63/2)
endsel
endfunc
Well... it took at least two attempts before I could survive long enough to get to "The Boss"... I definitely have to either strengthen my "firing" hand or somehow improve my reflexes if I am to progress beyond the first Boss.... Very cool game!
This looks very interesting. Unfortunately, I am away from my computer until the weekend, and am very much looking forward to seeing it run then. All the best.... Kevin.
I haven't had the time to play it much yet, only beat one and a half guy up, gotta go to work in some few minutes. But the game is really cool and reminds me of "Urban Champion" on NES. It also made me realise that I haven't added joystick support to n7 yet, so I'll probably do that this weekend.
04-17-2025, 11:37 PM (This post was last modified: 04-17-2025, 11:39 PM by 1micha.elok.)
Joystick Support in N7
Raise your sticks, both old and new,
For Naalaa's joy is built for you.
A language light, yet full of might,
Now dances with the joystick's flight.
By the way, I like "the tallywhacker fighters"
The primitive shapes used in the game are blend of humor and action, offers players an experience that doesn't take itself too seriously, yet delivers gameplay mechanics