Basic 2D fighting game

Show off your project created with Hollywood
Post Reply
g0blin
Posts: 77
Joined: Tue Oct 04, 2011 9:06 am

Basic 2D fighting game

Post by g0blin »

Hello to everybody,

this is my first post on this forum. Some of you already know me; for all the others, here's my short story:
- I've been an Amigan since the nineties (A2000HD which, unfortunately, I used very little);
- re-joined the Community a couple of years ago (now running Sam440ep-flex @800, AmigaOS4.1.2 ... soon upgrading);
- now member of just-reborn ATO (Amiga Translators' Organization) Italy;
- currently learning how to code in Hollywood.

I've written a small 2D game featuring Sub-Zero (MKIII versions) against the Bouncing Ball. The code is for non commercial use only, so i believe all graphics is used (and shall be used) in a "Fair way" (check also this web link for more infos http://www.bghq.com/copyright_info.php ).

Nonetheless, I'd like to have administrator clearance before posting graphics and music.

For the moment, here is the code.

Please note that the code is working but still needs adjusting, since it crashes a lot due to sprite conflict.

Gianluca aka g0blin

Code: Select all

/****************************************************************
**                                                             **
** Name:        Sub-Zero vs Amiga                              **
** Author:      Gianluca Girelli                               **
** Version:     1.3                                            **
** Date:        31.08.2011                                     **
** Interpreter: Hollywood 4.5                                  **
** Licence:     Hollywood initial coding demo                  **
** Function:    This is my first real try on Hollywood coding. **
**              The purpose is learning the basics and deal    **
**              with sprites.                                  **
**                                                             **
** History:                                                    **
**                                                             **
** 1.3  (31.08.11)                                             **
** - now implementing intro, main menu and credits routine.    **
**                                                             **
** 1.2  (20.07.11)                                             **
** - now implementing basic end-game routine when either       **
**   life counter reaches 0. Animations have been fixed using  **
**   custom frame grabber routine. At this stage, anyway, game **
**   is still a proof of concept.                              **
**                                                             **
** 1.1  (05.07.11)                                             **
** - uses nested If-ElseIf statements to avoid sprite problems **
** - Collision() command inserted to detect combat in progress **
** - introduces sprites flipping if fighters get back-to-back  **
**                                                             **
** 1.0: (22.06.11)                                             **
** - initial release                                           **
**                                                             **
****************************************************************/

@APPTITLE       "Sub-Zero vs Amiga"
@APPAUTHOR      "Gianluca Girelli"
@APPCOPYRIGHT   "Freeware - Graphics copyrights remain of original authors."
@APPVERSION     "$VER: 1.3 (31.08.2011)"
@APPDESCRIPTION "Simple fighting game featuring Sub-Zero from MKIII."

@VERSION 4,5
@INCLUDE "company-intro.hws"

@DISPLAY 1, { Title = "'Sub-Zero vs Amiga' - Made on Amiga with Hollywood by g0blin",
	 X=#CENTER, Y=#CENTER, Width=790, Height=506, HidePointer=True,
	 Sizeable=True, ScaleMode=#SCALEMODE_AUTO }
@SCREEN {Mode = "Ask", Width = 790, Height = 506}

@BRUSH 1, "fighting-stance.png", {Transparency=$0000ff}  ; 648x129 
@BRUSH 2, "forward.png", {LoadAlpha = True}          ; 576X133
@BRUSH 3, "punch.png", {LoadAlpha = True}        ; 864X137
@BRUSH 4, "dizzy.png", {Transparency =$ffffff}       ; 480X128
@BRUSH 5, "kick.png", {LoadAlpha=True}       ; 696x132
@BRUSH 6, "fight.png", {Transparency = $8a030e}
@BRUSH 7, "opponent.png", {Transparency = #BLACK}    ; 380X38
@BRUSH 8, "cemetery.png"                     ; 1185X253
@BRUSH 9, "victory.png", {LoadAlpha = True}         ; 40X169
@BRUSH 10, "game_lost.png", {LoadAlpha = True}      ; 129x29
@BRUSH 11, "red_boing_ball.png", {Transparency = #BLACK}
@BRUSH 12, "finish-him.png", {Transparency = $770602}
@BRUSH 20, "title.jpg"
@BRUSH 21, "intro2.png"
@BRUSH 22, "versus.png", {LoadAlpha=True} 
@BRUSH 30, "lifebar1.png", {Transparency = #BLACK} ; green lifebar
@BRUSH 31, "lifebar2.png", {Transparency = #BLACK} ; red lifebar
@BRUSH 40, "font.png", {Transparency=$0000c0}  ; 242x287
@BRUSH 41, "credits.jpg"
@BRUSH 42, "menu_entry1.png", {Transparency = #BLACK}
@BRUSH 43, "menu_entry2.png", {Transparency = #BLACK}
@BRUSH 44, "menu_entry3.png", {Transparency = #BLACK}
@BRUSH 45, "menu_entry4.png", {Transparency = #BLACK}
@BRUSH 46, "arena_thepit.jpg"

CopyBrush(30, 32)
CopyBrush(31, 33)
FlipBrush(32, True)
FlipBrush(33, True)

CreateSprite(1, #BRUSH, 1, 72, 129, 9, 9)  ; Sub-Zero fighting stance
CreateSprite(2, #BRUSH, 2, 64, 130, 9, 9)  ; Sub-Zero walking
CreateSprite(3, #BRUSH, 3, 96, 137, 9, 9)  ; Sub-Zero punching
CreateSprite(4, #BRUSH, 4, 60, 128, 8, 8)  ; Sub-Zero dizzy
CreateSprite(5, #BRUSH, 5, 116, 132, 6, 6) ; Sub-Zero kick 
CreateSprite(6, #BRUSH, 6, 166, 41, 1, 1)  ; fight sign
CreateSprite(7, #BRUSH, 7, 38, 38, 10, 10) ; opponent
CreateSprite(9, #BRUSH, 9, 40, 169, 1, 1)  ; Sub-Zero victory pose
CreateSprite(10, #BRUSH, 10, 129, 29, 1, 1)  ; Sub-Zero defeated pose
CreateSprite(11, #BRUSH, 11, 64, 70, 7, 7) ; menu pointer/final opponent
CreateSprite(12, #BRUSH, 12, 244, 34, 1, 1)  ; fight sign
ScaleSprite(1, 144, 258)
ScaleSprite(2, 128, 260)
ScaleSprite(3, 192, 274)
ScaleSprite(4, 120, 256)
ScaleSprite(5, 232, 266)
ScaleSprite(7, 76, 76)
ScaleSprite(9, 80, 338)
ScaleSprite(10, 258, 58)
ScaleBrush(8, 2370, 506)
ScaleBrush(46, 1100, #KEEPASPRAT)

@SAMPLE 1, "bounce.wav"  ; bounce sound
@SAMPLE 2, "Attack1.wav"  ; Sub-Zero punching
@SAMPLE 3, "Attack6.wav"  ; Sub-Zero kicking
@SAMPLE 4,"Hurt2.wav"
@MUSIC 1, "ending_theme.mp3" 
@MUSIC 2, "reptile.mp3"
@MUSIC 3, "Run Rabbit Junk.mp3"

Const #LEVELS=2
Const #MAXLEVELS=3
level=1
 
Function p_InitGameVars()  
    EscapeQuit(False)   ; disable ESC key as program terminator
    f = 1
    fr =1
    fk =1
    sub_x = 0       ; current Sub-Zero x position
    sub_y = 506-270 ; current Sub-Zero y position
    X = 600         ; current opponent x position
    Y = 506-90      ; current opponent y position
    sprite_on_screen=1
    idle=True   ; Sub-Zero is in fighting stance
    walking=False   ; he's neither walking ....
    punching=False  ; ... nor punching ....
    kicking= False  ; ... nor kicking ...
    VX = 3.5     ; x velocity (constant 3.5/-3.5)
    VY = 3       ; y velocity (dynamic)
    Flip = False
    player_counter = 340  ; life counters
    boing_counter = 340
    scrollx = 250
    a = 0       ; Switch-Case fighting stance
    menutext$={"PLAY", "CREDITS", "CONTROLS", "QUIT"}
    creditstext$={"SUB ZERO VS BOING BALL", " ", 
		  "WRITTEN IN HOLLYWOOD", " ", 
		  "ORIGINAL CODE", "GIANLUCA GIRELLI", " ", 
		  "USING CODE BY", "ANDREAS FALKENHAHN", " ", 
		  "GRAPHICS FROM MK III", " ", 
		  "SOUND FX FROM TEKKEN", " ",
		  "MUSIC FROM MK OST", " ",
		  "ADDITIONAL MUSIC FROM", "GHOST IN THE SHELL SAC", 
		  " ", " ", "FOR NON COMMERCIAL USE ONLY"}
    menuy={100, 200, 300, 400} 
    selection=-1 ; menu selector
    text_pointer=21 ; points to first "text sprite" in list
EndFunction

Function p_GameIntro()
    PlayMusic(1)
    DisplayBrush(20, #CENTER, #CENTER)
    Wait(150)
EndFunction

Function p_Timers()
	For Local i=1 To 4 Do StartTimer(i)
EndFunction

Function p_TextToSprite(text$, sprite_number)
; convert a text string in a sprite to be used in menu or credits routine
	Local x_pos=y_pos=drawpos=0
	CreateBrush(50, 700, 24)
	SelectBrush(50)
	For pos=0 To StrLen(text$)-1
		Local char=Asc(MidStr(text$, pos, 1))
		If char>64 And char<75
			x_pos=(char-65)*24
			y_pos=0
		ElseIf char>74 And char<85
			x_pos=(char-75)*24
			y_pos=23
		ElseIf char=32
			x_pos=0
			y_pos=250
		Else
			x_pos=(char-85)*24
			y_pos=46
		EndIf
		DisplayBrushPart(40, x_pos, y_pos, drawpos, 0, 24, 23)
		drawpos=drawpos+24
	Next 
	EndSelect()
	CropBrush(50, 0, 0, drawpos, 24)
	SetBrushTransparency(50, #BLACK)
	drawpos=0
	If sprite_number=25 Or sprite_number=30 Or sprite_number=33
		 ReplaceColors(50, {$F8F8F8, #RED, $808080, #YELLOW})
	Else
		 ReplaceColors(50, {$F8F8F8, #YELLOW})
	EndIf
	CreateSprite(sprite_number, #BRUSH, 50)
	FreeBrush(50)
EndFunction 

Function p_SetUpTextGfx()	
	For  i=21 To 24 Do p_TextToSprite(menutext$[i-21], i)
	For  i=25 To 45 Do p_TextToSprite(creditstext$[i-25], i)
EndFunction

Function p_DisplayGameGfx()
; displays and updates in-game graphics
    If player_counter<=20 Then player_counter=20
    If boing_counter<=20 Then boing_counter=20
    DisplayBrushPart(8,scrollx,0,0,0,790,506) ; scrolling background
    DisplayBrush(31, #LEFT, #TOP)
    DisplayBrush(33, #RIGHT, #TOP)
    DisplayBrushPart(30, 0, 0, #LEFT, #TOP, player_counter, 41)
    DisplayBrushPart(32, 0, 0, #RIGHT, #TOP, boing_counter, 41)
EndFunction

Function p_DisplayControls()
; simple screen which shows in-game controls
	Cls
	Repeat
		If GetTimer(4) > 75
			If f > 8 
				f =1
			Else
				f = f + 1
			EndIf
			DisplaySprite(1, 0, #CENTER, f)
			StartTimer(4) 
		EndIf 
		For Local k=42 To 45
			DisplayBrush(k, 200, menuy[k-42])
		Next
		WaitTimer(1, 40)
	Until IsKeyDown("ESC")
	RemoveSprite(1)
	DisplaySprite(9, 25, #CENTER)
	Wait(100)
	p_PrepareMenu()
EndFunction 

Function p_Credits()
; play end-game rolling credits and music
	PlayMusic(3)
	Local scroll_y=506
	Local x = {} 
	Local speed=1
	For Local i=25 To 45
		x[i]=GetAttribute(#SPRITE, i, #ATTRWIDTH)
	Next 
	RemoveSprites()
	Cls 
	DisplayBrush(41, #CENTER, #CENTER)
	Repeat
	    For Local i=25 To 45 Do DisplaySprite(i, (GetAttribute(#DISPLAY, 0, #ATTRWIDTH)-x[i])\2, scroll_y+50*(i-25))
	    scroll_y=scroll_y-speed
	    If scroll_y<(-1000) Then scroll_y=550
	    WaitTimer(1, 40)
	Until IsKeyDown("ESC")
	p_PrepareMenu()
	StopMusic(3)
EndFunction 
   
Function p_SetUpGameGfx()
; sets up in-game graphics
    DisplayBrushPart(8,scrollx,0,0,0,790,506) ; scrolling background
    DisplayBrush(31, #LEFT, #TOP)	; display fully depleted life bars ..
    DisplayBrush(33, #RIGHT, #TOP)
    DisplayBrush(30, #LEFT, #TOP)	;  .. and overlay them with green bars
    DisplayBrush(32, #RIGHT, #TOP)
EndFunction

Function p_MoveAndAnimateOpponent()
    X = X + VX
    Y = Y + VY
    ; bounce up now!
    If Y >= 420
	VY = -Rnd(3) - 5
	bounceup = True
	;PlaySample(1)
    EndIf
    ; and fall down!
    If VY >= 0 And bounceup = True
	VY = Rnd(4)
	bounceup = False
    EndIf
    ; bounce against right border!
    If X >= 714
	VX = -3.5
	;PlaySample(1) ;, {pitch=16000})
    EndIf
    ; bounce against left border!
    If X < 2
	VX = 3.5
	;PlaySample(1);, {pitch=16000})
    EndIf
    ; dynamic velocity
    VY = VY + 0.1
    DisplaySprite(7, X, Y)
EndFunction

Function p_GameOver()
    RemoveSprites()
    DisplaySprite(10, #CENTER, 430)
    Wait(200)
    gameover=True
EndFunction 

/*Function p_GameOver(); old routine
   RemoveSprites()
   If boing_counter<=0 
	 DisplaySprite(9, 380, 150)
   ElseIf player_counter<=0
	 DisplaySprite(10, #CENTER, 430)
   EndIf
   Wait(200)
   End
EndFunction */ 

Function p_NextLevel()
;transition to next level:
;   - change opponent
;   - if #MAXLEVELS then p_Credits()
	RemoveSprites()
	level=level+1
	DisplaySprite(9, 380, 150)
	Wait(200)
	If level=#MAXLEVELS 
		p_Credits()
	Else 
		FreeBrush(32)
		CopyBrush(30,32)
		FlipBrush(32, True)
		p_InitGame()
	EndIf
EndFunction

Function p_ReadPlayerInput()
    If IsKeyDown("LEFT") And scrollx > 0
	scrollx = scrollx - 2
	If sub_x > 0 Then sub_x = sub_x - 2
	a = 1
    ElseIf IsKeyDown("RIGHT") And scrollx < 1400
	scrollx = scrollx + 2
	If sub_x < 790-128 Then sub_x = sub_x + 2
	a = 2
    ElseIf IsKeyDown("a") Or IsKeyDown("A") 
	a = 3
    ElseIf IsKeyDown("x") Or IsKeyDown("X")
	a=4
    EndIf 
EndFunction 

Function p_FlipFighters(sprite)
    If (X<sub_x) And flip=False   ;flip sprites if ball is behind fighter
	RemoveSprite(sprite)
	FlipSprite(sprite, True)
	flip=True 
    EndIf 
    If (X>sub_x) And flip=True   ;flip sprites back
	RemoveSprite(sprite)
	FlipSprite(sprite, True)
	flip=False 
    EndIf
EndFunction 

Function p_MoveAndAnimatePlayer()
	Switch a
	Case 1:                 ; Sub-Zero walking backward
		 If idle 
			 RemoveSprite(1)
			 idle = False 
			walking=True 
		 EndIf
		 If punching 
			RemoveSprite(3)
			punching = False 
			walking=True 
		 EndIf
		 ; switch frames every 80ms
		 If GetTimer(2) > 80
			 If fr < 1 
			    fr = 9
			 Else
			    fr = fr - 1
			 EndIf
			 DisplaySprite(2, sub_x, sub_y, fr)
			 StartTimer(2)
		EndIf 
		sprite_on_screen=2
	Case 2:                 ; Sub-Zero walking forward
		walking=True
		sprite_on_screen=2
		If idle 
			RemoveSprite(1)
			idle = False 
		EndIf
		If punching 
			RemoveSprite(3)
			punching = False 
		EndIf 
		If kicking 
			RemoveSprite(5)
			kicking = False 
		EndIf
		; switch frames every 80ms
		If GetTimer(2) > 80
			If fr > 8 
			   fr =1
			Else
			   fr = fr + 1
			EndIf
			DisplaySprite(sprite_on_screen, sub_x, sub_y, fr)
			StartTimer(2)
		EndIf
		If Collision(#SPRITE, 7, sprite_on_screen)=True
			If IsSamplePlaying(4)=False Then PlaySample(4)
			sub_x=sub_x - 30
			VX=(-VX)*1.2
			player_counter=player_counter-50
			If player_counter<=20 Then player_counter=19
		EndIf 
	Case 3:                 ; Sub-Zero punching
		punching = True 
		If IsSamplePlaying(2)=False Then PlaySample(2)
		If idle 
			RemoveSprite(1)
			idle = False
		EndIf
		If walking
			RemoveSprite(2)
			walking = False
		EndIf 
		; switch frames every 38ms
		If GetTimer(2) > 38
			If fr > 8 
			   fr =1
			Else
			   fr = fr + 1
			EndIf
			DisplaySprite(3, sub_x, sub_y-10, fr)       
			StartTimer(2)
		EndIf
		If Collision(#SPRITE, 7, 3) = True 
			VX=(-VX)*2
			boing_counter=boing_counter-20
			If boing_counter<=20 Then boing_counter=20
			CropBrush(32, 20, 0, boing_counter, 41)
		EndIf 
	Case 4:                 ; Sub-Zero kicking
		kicking = True 
		If IsSamplePlaying(3)=False Then PlaySample(3)
		If idle 
			RemoveSprite(1)
			idle = False
		EndIf
		If walking
			RemoveSprite(2)
			walking = False
		EndIf 
		If punching
			RemoveSprite(3)
			punching = False
		EndIf
		; switch frames every 45ms
		If GetTimer(3) > 45
			If fk > 5 
			   fk =1
			Else
			   fk = fk + 1
			EndIf
			DisplaySprite(5, sub_x, sub_y-10, fk)       
			StartTimer(3)
		EndIf
		If Collision(#SPRITE, 7, 5) = True 
			VX=(-VX)*2
			boing_counter=boing_counter-20
			If boing_counter<=20 Then boing_counter=19
			;CropBrush(32, 20, 0, boing_counter, 41)
		EndIf 
	Default
		; switch frames every 110ms
		If GetTimer(4) > 75
			If f > 8 
			   f =1
			Else
			   f = f + 1
			EndIf
			If idle = False Then idle = True
			If punching
				RemoveSprite(3)
				punching = False 
			EndIf
			If walking
				RemoveSprite(2)
				walking = False 
			EndIf 
			If kicking
				RemoveSprite(5)
				kicking = False 
			EndIf
			If player_counter<=20 
				If f=9 Then f=1 ; because of frame number difference between dizzy and fighting stance
				DisplaySprite(4, sub_x, sub_y,f)    ; Sub-Zero dizzy
				DisplaySprite(12, #CENTER, 200)
				If Collision(#SPRITE, 7, 4) = True Then p_GameOver()
			Else	
				DisplaySprite(1, sub_x, sub_y,f)    ; Sub-Zero fighting stance
			EndIf 
			If boing_counter<=20 Then p_NextLevel() ; 
			StartTimer(4)
		EndIf
	EndSwitch
	a=0
EndFunction 

Function p_CleanUp()		;not really needed, but a good programming habit
	For Local i=1 To 11 
		If i=6 Then Continue ; check if we really have a sprite or a brush
		FreeSprite(i)
		FreeBrush(i)
	Next
	menutext$=Nil		; a little help to the garbage collector
	creditstext$=Nil
	menuy=Nil 
EndFunction 

Function p_InitGame()
	Cls 
	p_InitGameVars()
	p_SetUpGameGfx()
	DisplaySprite(7, X, Y)
	DisplaySprite(1, sub_x, sub_y, f)
	DisplaySprite(6, #CENTER, #CENTER)
	Wait(100)
	RemoveSprite(6)
EndFunction 

Function p_Game()
; game main loop
	PlayMusic(2)
	waskeydown=False
	gameover=False
	p_InitGame()
	Repeat
		If IsKeyDown("ESC")
			gameover=True
			waskeydown=True
		EndIf
		p_ReadPlayerInput()
		p_DisplayGameGfx()
		p_MoveAndAnimatePlayer()
		p_MoveAndAnimateOpponent()
		p_FlipFighters(sprite_on_screen)
		WaitTimer(1, 40)
	Until gameover Or IsKeyDown("ESC")
	StopMusic(2)
	p_PrepareMenu()
EndFunction

Function p_PrepareMenu()
	Cls 
	DisplayBrush(22, 50, #CENTER)
	For Local k=21 To 24
		DisplaySprite(k, 350, menuy[k-21])
	Next
EndFunction 

Function p_MainMenu()
	Local y=0
	Local scroll=0
	Local pan_right=True 
	p_PrepareMenu()
	If IsMusicPlaying(1)=False Then StartMusic(1)
	Repeat 
		If waskeydown=True 	
			Wait(10)
			waskeydown=False
		EndIf
		If IsKeyDown("DOWN")
			y=y+1
			If y>3 Then y=0
			waskeydown=True 
		ElseIf IsKeyDown("UP")
			y=y-1
			If y<0 Then y=3
			waskeydown=True 
		EndIf
			
		; switch frames every 50ms
		If GetTimer(2) > 50
			If fr > 6 
				fr =1
			Else
				fr = fr + 1
			EndIf
			DisplaySprite(11, 550, menuy[y]-30, fr)
			DisplayBrushPart(46, scroll ,0,0,0,790,506) ; scrolling background
			DisplayBrush(22, 50, #BOTTOM)
			If pan_right Then scroll=scroll+1 Else scroll=scroll-1
			If scroll>370 Then pan_right=False
			If scroll<5 Then pan_right=True 
			StartTimer(2)
		EndIf 
		If IsKeyDown("RETURN")
			Switch y
			Case 0:
				p_Game() ;play
			Case 1:
				P_Credits() ;credits
			Case 2:
				p_DisplayControls() ;display controls
			Case 3:
				;p_CleanUp()
				End
			EndSwitch 
		EndIf 
		WaitTimer(1, 1000/50)
	Forever 
	If IsMusicPlaying(1) Then StopMusic(1)
EndFunction


/* Begin program  */

p_CompanyIntro() 
p_GameIntro()
p_Timers()
p_InitGameVars()
p_SetUpTextGfx()

p_MainMenu()

/* End program */
User avatar
Juan Carlos
Posts: 889
Joined: Mon Sep 06, 2010 1:02 pm

Re: Basic 2D fighting game

Post by Juan Carlos »

Welcome to this forum and congratulations for choosed the Sam and Amiga OS4, and congratulations for your Hollywood code, with patience and time with Hollywood all is possible, games, programs, etc., only that this forum is any death without source codes as there is others programming forums of Java, C, etc.
g0blin
Posts: 77
Joined: Tue Oct 04, 2011 9:06 am

Re: Basic 2D fighting game

Post by g0blin »

@Juan Carlos

Thanks for your wellcome message.

I'd made further adjustments and code seems to crash less now.
I'll post a new version soon, hopefully fully working.

g0blin
Post Reply