Game advice - Engine

kanaida

Active Member
Licensed User
Longtime User
Hey guys, I've been working on creating a new game engine in b4a. I've played with AcceleratedSuface library and managed to animate michael jackson from some moonwalker arcade game sprite sheets (lol) at 60fps.

I just had some questions regarding game engines in general.
From what i've figured out so far, I need:

1) something that can play multiple sounds without performance degredation. So far i've used the media player object for bg music. I have no idea how the threading works as far as that goes though because It can play sound while the activity is taking events etc... so I don't know if its on another thread or what.
I just figured I could make an array of media players all the sound effects in the game, loading em all as needed prior to starting a level. Then calling .play as needed. Any input on this is welcome

2) a class to define animations by specifying frame info and frame duration and put those in an array property of a sprite class to be called as needed. The sprite would hold some other info maybe, not quite sure yet lol. So far i load the sprite sheet png, then crop smaller bitmaps out of it, and unload the sprite sheet to save memory. I stick those into the array for quick drawing access from memory.

3) a player/object class to hold co-ordinates and basic object info, and an attributes class that can be added against another set of attributes (such as equipping an item) and add the totals up, or perform attack calculations.

4) some code to handle input

5) a loop for the game to use. I already got this, i'm assuming it's the draw() loop. calculate, then draw over and over.

6) Artwork and music, luckily my girl is an artist, and my cousin a musician :)

if there's anything i'm missing or any comments, please let me know. I've tried to follow a book on android game programming, but it gets a bit complicated. Not sure what the b4a equivalent of making a service for playing sounds in a different thread is for example. The good part is that at least since b4a supports classes now, and useful libraries are already made, it greatly simplifies a lot of my work.

http://www.youtube.com/watch?v=li2cpCMjWuU
 
Last edited:

Informatix

Expert
Licensed User
Longtime User
1) something that can play multiple sounds without performance degredation. So far i've used the media player object for bg music. I have no idea how the threading works as far as that goes though because It can play sound while the activity is taking events etc... so I don't know if its on another thread or what.

It's not suited at all for sounds in a game. The media player should be only used for music. For sounds, you have to use SoundPool (which is used by most Java game engines) or OpenSL. B4A has a library for both.

2) a class to define animations by specifying frame info and frame duration and put those in an array property of a sprite class to be called as needed. The sprite would hold some other info maybe, not quite sure yet lol. So far i load the sprite sheet png, then crop smaller bitmaps out of it, and unload the sprite sheet to save memory. I stick those into the array for quick drawing access from memory.

A better way would be to create and store separate images. That would save some memory (no spritesheet handling) and the time needed to crop the images. Anyway, a class handling a spritesheet would be a good idea if you want to share your work with us. That could be useful to some.

3) a player/object class to hold co-ordinates and basic object info, and an attributes class that can be added against another set of attributes (such as equipping an item) and add the totals up, or perform attack calculations.

This is something closely related to the game to do, so it's difficult to create an all-purposes class. In some games, there's no hit points, lives, armor, etc.
You should let this part to the user of your game engine. For coordinates, however, that can be interesting. Functions to convert world coordinates to screen coordinates, and structures to store them, are required in most games.

4) some code to handle input

My Gesture Detector library should cover most needs for touch actions. For the accelerometer, you'll have to use the Phone library.

5) a loop for the game to use. I already got this, i'm assuming it's the draw() loop. calculate, then draw over and over.

The common loop for games is:
Update (or compute)
Draw

They must be separated because they perform different tasks.
It happens (it's the case in my Acc surf. lib) that the Update function is called more often than the Draw function because drawings take time.
On the contrary, the Draw function should not be called more often than the Update function because it is useless (a complete waste of CPU/GPU time).
If you use AS, all this is already implemented properly.

if there's anything i'm missing or any comments, please let me know. I've tried to follow a book on android game programming, but it gets a bit complicated.
Many things are missing in fact (look at a Java game engine and you'll understand) ;) But creating a basic game engine for B4A is a good idea. GameView is too limited.
 
Upvote 0

kanaida

Active Member
Licensed User
Longtime User
Thanks for the input guys. Here's my sprite classes

Video in action
http://www.youtube.com/watch?v=li2cpCMjWuU

Required Libs:
AcceleratedSurface
Animation (maybe not required for this one)
Reflection
Threading

ANIM_TYPE is a code module, the others are classes.
The last bit of code makes it run :)

Save this sprite sheet as mj_sprites.png and add it to the files in your project
MichaelJackson.png


B4X:
'Class module
'Sprite - By Kanaida
'This represents a Sprite.
'The sprite holds a list of Sprite Animations that it supports,
'The idea is to find by ANIM_TYPE to see if it's supported etc... and get the animation.

Sub Class_Globals
   Dim x,y As Int
   Dim Animations(1) As SpriteAnim
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize
   x=100
   y=100
End Sub

B4X:
'Class module
'SriteAnim - By Kanaida
'Represents a set of frames that make up an animation.
'Has LoadMJ loads a particular animation, this code is probably
'best outside of this class, Possibly a code module ready to load stuff. I was testing it out.
'Currently all the frames in this sheet are not 100% the same size so he'll move around a bit
'when the animation occurs. 
'ToDo: support for ticks per frame and specific offsets per frame for bad spritesheets like this one lol.

Sub Class_Globals
   Dim AnimType As Int
   Dim ParentSprite As Sprite
   Dim SpriteSheetFile As String
   Dim left,top,width,height, FrameCount As Int
   Dim Frames(43) As Bitmap
   Dim IU As AS_ImageUtils
   Dim CurrentFrame As Int = 0
   Dim LoopAnim As Boolean
End Sub

'Initializes the object. You can add parameters to this method if needed.
Public Sub Initialize(Parent As Sprite)
   ParentSprite = Parent
End Sub

Sub LoadMJ()
   AnimType = ANIM_TYPE.ANIM_TYPE_IDLE
   SpriteSheetFile = "mj_sprites.png"
   FrameCount = 43 'Frames in this animation
   left = 0 'left value of animation within sprite sheet
   top = 1292 'top value of animation within sprite sheet
   height = 80 'frame height
   width = 42 'frame width
   LoopAnim = True
   Dim FramesPerRow As Int = 43 'Doesn't do anything now, but later on it will enable wrapping ot the next row if required.
      
   'Load the sprite sheet, this can be a shared resource if many things are on one sheet.
   Dim b As Bitmap = LoadBitmap(File.DirAssets,SpriteSheetFile)
   
   'Crop the frames out the sprite sheet
   For i = 0 To FrameCount-1
   Dim FrameX As Int 
      If i = 0 Then
         FrameX = left
      Else
         FrameX = left+(i*width)
      End If
      
      Frames(i) = IU.Crop(b,FrameX,top,width,height)
   Next
   
   b = Null
End Sub

Sub NextFrame()
   CurrentFrame = CurrentFrame +1
   If CurrentFrame = FrameCount Then
      If LoopAnim Then
         CurrentFrame = 0
      Else
         'Set it to the last frame
         CurrentFrame = FrameCount-1
      End If
      
   End If
End Sub

Sub GetCurrentFrame As Bitmap
      Return Frames(CurrentFrame)
End Sub

B4X:
'Code module
'ANIM_TYPE (ENUM)- By Kanaida
'This is a place where i define all the different types of animations so
'that I can find them later by name etc...

'Subs in this code module will be accessible from all modules.
Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.
   Dim ANIM_TYPE_IDLE = 1
   Dim ANIM_TYPE_WALK_SIDEWAYS = 2
   Dim ANIM_TYPE_RUN_SIDEWAYS = 3
   Dim ANIM_TYPE_ATTACK_WEAK = 4
   Dim ANIM_TYPE_ATTACK_STRONG = 5
End Sub

B4X:
#Region  Activity Attributes 
   #FullScreen: False
   #IncludeTitle: True
#End Region

Sub Process_Globals
   'These global variables will be declared once when the application starts.
   'These variables can be accessed from all modules.

End Sub

Sub Globals
   'These global variables will be redeclared each time the activity is created.
   'These variables can only be accessed from this module.
   Dim mySurface As AcceleratedSurface

   Dim Secs As Double
   Dim OldTime As Long
   Dim FPS, FrameCount As Int
   Dim Sprites(1) As Sprite
   
   Dim IsScaled As Boolean = False
End Sub

Sub Activity_Create(FirstTime As Boolean)
   'Do not forget to load the layout file created with the visual designer. For example:
   mySurface.Initialize("Surface",True)
   Activity.AddView(mySurface, 0, 0, 100%x, 100%y)

   
   Dim spr1 As Sprite
   spr1.Initialize
   Sprites(0) = spr1
   
   Dim anim1 As SpriteAnim
   anim1.Initialize(spr1)
   Sprites(0).Animations(0) = anim1
   
   anim1.LoadMJ
   
   
End Sub

Sub Activity_Resume
   mySurface.StartRegularDraw(80) '60 fps
End Sub

Sub Activity_Pause (UserClosed As Boolean)
   mySurface.StopRegularDraw
End Sub

Sub getSize(V As View, WhatDim As String) As Int
   'Gets the width or height of the given view when the B4A properties are unusable
   Dim r As Reflector
   r.Target = V
   If r.RunMethod("get" & WhatDim) = 0 Then DoEvents
   Return r.RunMethod("get" & WhatDim)
End Sub

Sub Surface_Draw(AC As AS_Canvas)
   'Computes and draws the new position and orientation of each flake
   Secs = mySurface.ElapsedTimeSinceLastDraw / 1000
   For i = 0 To Sprites.Length - 1
      Dim Spr1 As Sprite = Sprites(i)

      If IsScaled =False Then
      IsScaled = True
      
      
      End If
      AC.MatrixSetScale(8,8)
      Spr1.Animations(0).NextFrame
      AC.DrawBitmapWithMatrixAt(Spr1.Animations(0).GetCurrentFrame, Spr1.x,Spr1.y,True)
   Next

   'Computes and displays the FPS value
   If DateTime.Now > OldTime Then
      OldTime = DateTime.Now + 1000
      FPS = FrameCount
      FrameCount = 0
   Else
      FrameCount = FrameCount + 1
   End If
   AC.DrawText("FRAME: " & Spr1.Animations(0).CurrentFrame, 70%x, mySurface.Height - 50dip, Typeface.DEFAULT, 20, Colors.White, AC.ALIGN_LEFT)
   AC.DrawText("FPS: " & FPS, 70%x, mySurface.Height - 25dip, Typeface.DEFAULT, 20, Colors.White, AC.ALIGN_LEFT)
End Sub
 
Last edited:
Upvote 0

kanaida

Active Member
Licensed User
Longtime User
I actually opened up that sheet in Paint.Net and used the magic wand tool to select the background and delete, then save. That will make the green transparent ;)
 
Upvote 0
Top