logo
Google
 
Home

MHEG-5 Invaders Example

This is something I wrote for a bit of fun. It is a space invader influenced application written in MHEG-5. Don't get too excited - it's nothing like the original Space Invaders.

This code demonstrates several techniques that can be applied to writing games in MHEG-5. There is a timer [5001] that moves the invaders every 250ms. Variables are used for holding the visible objects (invaders, base and missile) current position. These are modified on certain Links being fired and the visible position subsequently updated.

IntegerVar 1004 and Link 4004 operate as a loop. This is achieved by the Link firing on TestEvents from the IntegerVar. To start the loop we initialise the loop counter to 0 and generate a True test event like this:

                // Reset the loop counter and activate the X loop
                :SetVariable ( 1004 :GInteger 0 )
                :TestVariable ( 1004 1 :Ginteger 0 )
IntegerVar 1101 contains the number of times to iterate over the loop. The link Action performs the following ElementaryActions
                // Increment loop counter
                :Add ( 1004 1 )

                ...

                // Repeat loop
                :TestVariable ( 1004 3 :GInteger :IndirectRef 1101 )
The Link action triggers itself until all iterations have completed.

ZIP file containing MHEG text notation, ASN.1 notation and graphics:

    Download

Application


// Ian's INVADE application
//
// http://digvid.info/mheg5
//
// Copyright Ian Willis.
//
// Permission is given to distribute this code, providing citation is given
// and this copyright message is left intact.

{:Application
    ( '/startup' 0 )        // Application content reference
    :Items (
        {:Link
            1
            :EventSource 0          // Check this application...
            :EventType IsRunning    // ... for the IsRunning event
            :LinkEffect (
                // Load the scene
                :TransitionTo (( '~/hello.mhg' 0 ) )
            )
        }
    )
    :BackgroundColour '=FF=FF=FF=00'    // White
    :TextCHook 10                       // Default text content hook
    :TextColour '=00=00=00=00'          // Black
    :Font "rec://font/uk1"              // Font to use for text rendering
    :FontAttributes "plain.26.32.0"     // Default font attributes
    :BitmapCHook 4                      // Default bitmap content hook
}

Scene


// Ian's INVADE application
//
// http://digvid.info/mheg5
//
// Copyright Ian Willis.
//
// Permission is given to distribute this code, providing citation is given
// and this copyright message is left intact.

{:Scene
    ( "~/scene1.mheg" 0 )
    :Items (

// Fill background with a white rectangle
        {:Rectangle
            10
            :OrigBoxSize 720 576
            :OrigPosition 0 0
            :OrigLineWidth 0
            :OrigRefFillColour '=ff=ff=ff=00'
        }

// Top banner text
        {:Text
            1
            :OrigContent "Ian's INVADE application (Cancel to quit)"
            :OrigBoxsize 720 40
            :OrigPosition 0 10
            :FontAttributes "plain.24.24.0"
            :HJustification centre
        }

// Link for quitting scene
        {:Link
            2
            :EventSource 0
            :EventType UserInput
            :EventData 16
            :LinkEffect (
                :quit ( ( "~/startup" 0 ) )
            )
        }

// Game over text
        {:Text
            3
            :InitiallyActive False
            :OrigContent "Game Over"
            :OrigBoxsize 720 50
            :OrigPosition 0 250
            :FontAttributes "plain.36.40.0"
            :HJustification centre
            :VJustification centre
        }

// Win/loose text
        {:Text
            4
            :InitiallyActive False
            :OrigContent "You Win"
            :OrigBoxsize 720 50
            :OrigPosition 0 300
            :FontAttributes "plain.36.40.0"
            :HJustification centre
            :VJustification centre
        }

// Play again text
        {:Text
            5
            :OrigContent "Press Green to Start"
            :OrigBoxsize 720 50
            :OrigPosition 0 350
            :FontAttributes "plain.36.40.0"
            :HJustification centre
            :VJustification centre
        }

// Link for starting
// Some of this is not necessary the first time, but will be
// if we restart the game.
        {:Link
            7
            :EventSource 0
            :EventType UserInput
            :EventData 101              // Green button
            :LinkEffect (
                // Hide the text boxes
                :Stop ( 3 )
                :Stop ( 4 )
                :Stop ( 5 )
                :SetData( 4 "You Win")

                // Reset variables
                :SetVariable ( 1001 :GInteger 50 )
                :SetVariable ( 1002 :GInteger 50 )
                :SetVariable ( 1003 :GInteger 10 )
                :SetVariable ( 1004 :GInteger 0 )
                :SetVariable ( 1006 :GObjectRef 3001)
                :SetVariable ( 1007 :GInteger 0 )
                :SetVariable ( 1011 :GInteger 5 )

                :SetVariable ( 11001 :GInteger 20 )

                // Start the invader visibles
                :Run ( 3001 )
                :Run ( 3002 )
                :Run ( 3003 )
                :Run ( 3004 )
                :Run ( 3005 )

                // Start the base
                :SetPosition ( 13001 :IndirectRef 11001 :IndirectRef 11002 )
                :Run ( 13001 )

                // Activate keyboard controls
                :Activate ( 14001 )
                :Activate ( 14002 )
                :Activate ( 14003 )

                // Start the timer
                :SetTimer ( 0 5001 1 )
            )
        }

// Invader X position
        {:IntegerVar
            1001
            :OrigValue 50
        }

// Invader Y position
        {:IntegerVar
            1002
            :OrigValue 50
        }

// Invader X delta
        {:IntegerVar
            1003
            :OrigValue 10
        }

// Invader X loop counter
        {:IntegerVar
            1004
            :OrigValue 0
        }

// Invader object reference
        {:ObjectRefVar
            1006
            :OrigValue :ObjectRef 3001
        }

// Invader X position
        {:IntegerVar
            1007
            :OrigValue 0
        }

// Temporary true if invader is alive
        {:BooleanVar
            1010
            :OrigValue False
        }

// Number of invaders
        {:IntegerVar
            1011
            :OrigValue 5
        }

// Base X position
        {:IntegerVar
            11001
            :OrigValue 20
        }

// CONSTANTS

// Number of invader columns
        {:IntegerVar
            1101
            :OrigValue 5
        }

// Invader min X position
        {:IntegerVar
            1102
            :OrigValue 50
        }

// Invader X spacing
        {:IntegerVar
            1103
            :OrigValue 70
        }

// Invader max X position
        {:IntegerVar
            1104
            :OrigValue 350
        }

// Invader Y step size (also missile step size)
        {:IntegerVar
            1105
            :OrigValue 80
        }

// Constant TRUE
        {:BooleanVar
            1106
            :OrigValue True
        }

// Invader Max Y
        {:IntegerVar
            1107
            :OrigValue 350
        }

// Constant TRUE for moving invaders
        {:BooleanVar
            1108
            :OrigValue True
        }

// Base Y position
        {:IntegerVar
            11002
            :OrigValue 400
        }



// Invader visibles
        {:Bitmap
            3001
            :OrigContent :ContentRef ( "~/inv1.png" )
            :OrigBoxsize 50 50
            :OrigPosition 50 50
        }
        {:Bitmap
            3002
            :OrigContent :ContentRef ( "~/inv1.png" )
            :OrigBoxsize 50 50
            :OrigPosition 120 50
        }
        {:Bitmap
            3003
            :OrigContent :ContentRef ( "~/inv1.png" )
            :OrigBoxsize 50 50
            :OrigPosition 190 50
        }
        {:Bitmap
            3004
            :OrigContent :ContentRef ( "~/inv1.png" )
            :OrigBoxsize 50 50
            :OrigPosition 260 50
        }
        {:Bitmap
            3005
            :OrigContent :ContentRef ( "~/inv1.png" )
            :OrigBoxsize 50 50
            :OrigPosition 330 50
        }

// Main invader timer actions
        {:Link
            4001
            :EventSource 0
            :EventType TimerFired
            :EventData 5001
            :LinkEffect (
                // Reset the timer
                :SetTimer (0 5001 250)
                // Stop any explosion
                :Stop ( 23002 )
                // Increment/decrement the invader X position
                :Add ( 1001 :IndirectRef 1003 )
                // Test for min X position
                :TestVariable ( 1001 4 :GInteger :IndirectRef 1102 )
                // Test for max X position
                :TestVariable ( 1001 6 :GInteger :IndirectRef 1104 )

                // Copy invader X position
                :SetVariable ( 1007 :GInteger :IndirectRef 1001 )
                // Reset the loop counter and activate the X loop
                :SetVariable ( 1004 :GInteger 0 )
                :TestVariable ( 1004 1 :Ginteger 0 )
                // Test whether missile is visible
                :TestVariable ( 21006 1 :GBoolean True )
            )
        }

// Activated when invaders reach either side of the screen
        {:Link
            4002
            :EventSource 1001
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                // Reverse direction
                :Multiply ( 1003 -1 )
                // Move invaders down the screen
                :Add ( 1002 :IndirectRef 1105 )
                :TestVariable ( 1002 6 :GInteger :IndirectRef 1107 )
            )
        }

// Actioned when invaders reach bottom of screen
        {:Link
            4003
            :EventSource 1002
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                // Set invader count to 0 and test it
                :SetData( 4 "You Loose" )
                :SetVariable ( 1011 :GInteger 0 )
                :TestVariable ( 1011 1 :GInteger 0 )
            )
        }

// Invader X loop
        {:Link
            4004
            :EventSource 1004
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                // Increment loop counter
                :Add ( 1004 1 )
                // Set ObjRef to correct object
                :TestVariable (1106 1 :GBoolean True )
                // See if this invader is still alive
                :GetRunningStatus ( :IndirectRef 1006 1010 )
                :TestVariable ( 1010 1 :GBoolean True )
                // Increment X position of next invader
                :Add (1007 :IndirectRef 1103 )
                // Repeat loop
                :TestVariable ( 1004 3 :GInteger :IndirectRef 1101 )
            )
        }

// Actioned when no invaders left
        {:Link
            4005
            :EventSource 1011
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                // Kill the timer
                :SetTimer (0 5001)
                // Stop game visibles
                :Stop ( 3001 )
                :Stop ( 3002 )
                :Stop ( 3003 )
                :Stop ( 3004 )
                :Stop ( 3005 )
                :Stop ( 13001 )
                :Stop ( 23002 )
                // Deactivate keyboard controls
                :Deactivate ( 14001 )
                :Deactivate ( 14002 )
                :Deactivate ( 14003 )
                // Display game over
                :Run ( 3 )
                // Display won/lost
                :Run ( 4 )
                // Display play again
                :Run ( 5 )
                // Activate play again link
                :Activate ( 7 )
            )
        }

// Actioned on each alive invader
// ObjectRef is in 1006
// X position is in 1007
// Y position is in 1002
        {:Link
            4006
            :EventSource 1010
            :EventType TestEvent
            :EventData True
            :LinkEffect (
                // Test for a missile hit
                :TestVariable ( 21001 6 :GInteger :IndirectRef 1007 )
                // Move this invader
                :SetPosition ( :IndirectRef 1006 :IndirectRef 1007 :IndirectRef 1002 )
            )
        }


// Select invader 1 visible
        {:Link
            4101
            :InitiallyActive True
            :EventSource 1106
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :SetVariable (1006 :GObjectRef 3001)
                :Activate ( 4102 )
                :Deactivate ( 4101 )
            )
        }

// Select invader 2 visible
        {:Link
            4102
            :InitiallyActive False
            :EventSource 1106
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :SetVariable (1006 :GObjectRef 3002)
                :Activate ( 4103 )
                :Deactivate ( 4102 )
            )
        }

// Select invader 3 visible
        {:Link
            4103
            :InitiallyActive False
            :EventSource 1106
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :SetVariable (1006 :GObjectRef 3003)
                :Activate ( 4104 )
                :Deactivate ( 4103 )
            )
        }

// Select invader 4 visible
        {:Link
            4104
            :InitiallyActive False
            :EventSource 1106
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :SetVariable (1006 :GObjectRef 3004)
                :Activate ( 4105 )
                :Deactivate ( 4104 )
            )
        }

// Select invader 5 visible
        {:Link
            4105
            :InitiallyActive False
            :EventSource 1106
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :SetVariable (1006 :GObjectRef 3005)
                :Activate ( 4101 )
                :Deactivate ( 4105 )
            )
        }


//////////////////////////////////////////////////////////////////////////////

        {:Bitmap
            13001
            :OrigContent :ContentRef ( "~/base.png" )
            :OrigBoxsize 50 30
            :OrigPosition 20 400
        }

// Left keypress
        {:Link
            14001
            :EventSource 0
            :EventType UserInput
            :EventData 3
            :LinkEffect (
                :Subtract ( 11001 20 )
                :SetPosition ( 13001 :IndirectRef 11001 :IndirectRef 11002 )
            )
        }

// Right keypress
        {:Link
            14002
            :EventSource 0
            :EventType UserInput
            :EventData 4
            :LinkEffect (
                :Add ( 11001 20 )
                :SetPosition ( 13001 :IndirectRef 11001 :IndirectRef 11002 )
            )
        }

// Up keypress
        {:Link
            14003
            :EventSource 0
            :EventType UserInput
            :EventData 1
            :LinkEffect (
                :Deactivate ( 24004 )
                :SetVariable ( 21006 :GBoolean True )
                :SetVariable ( 21001 :GInteger :IndirectRef 11001 )
                :Add ( 21001 20 )
                :SetVariable ( 21002 :GInteger 360 )
                :SetPosition ( 23001 :IndirectRef 21001 :IndirectRef 21002 )
                :Run ( 23001 )
                :SetPosition ( 23001 :IndirectRef 21001 :IndirectRef 21002 )
            )
        }

// Missile X pos
        {:IntegerVar
            21001
            :OrigValue 250
        }

// Missile Y pos
        {:IntegerVar
            21002
            :OrigValue 360
        }

// Temporary comparison variable
        {:IntegerVar
            21003
            :OrigValue 0
        }

// Boolean true if missile is visible
        {:BooleanVar
            21006
            :OrigValue False
        }

// Missile visible
        {:Bitmap
            23001
            :InitiallyActive false
            :OrigContent :ContentRef ( "~/missile.png" )
            :OrigBoxsize 10 30
            :OrigPosition 100 400
        }

// Explosion visible
        {:Bitmap
            23002
            :InitiallyActive false
            :OrigContent :ContentRef ( "~/explode.png" )
            :OrigBoxsize 50 50
            :OrigPosition 100 400
        }

// Link fired by timer if missile is visible
        {:Link
            24001
            :EventSource 21006
            :EventType TestEvent
            :EventData True
            :LinkEffect (
                // Move Missile
                :Subtract ( 21002 20 )
                :SetPosition ( 23001 :IndirectRef 21001 :IndirectRef 21002 )
                // Test for missile Y position = invader y position. Activate
                // 24004 if true.
                :SetVariable ( 21003 :GInteger :IndirectRef 1002 )
                :Add ( 21003 10 )
                :Deactivate ( 24004 )
                :Activate ( 24002 )
                :TestVariable ( 21002 1 :GInteger :IndirectRef 21003 )
                :Add ( 21003 20 )
                :TestVariable ( 21002 1 :GInteger :IndirectRef 21003 )
                :Deactivate (24002)
                // Test for missile off top of screen
                :Activate (24003)
                :TestVariable ( 21002 4 :GInteger 0 )
                :Deactivate (24003)
            )
        }

// Actioned when missile reaches invader Y position
        {:Link
            24002
            :InitiallyActive False
            :EventSource 21002
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :Activate (24004)
            )
        }

// Actioned when missile reaches top of screen
        {:Link
            24003
            :InitiallyActive False
            :EventSource 21002
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :Stop ( 23001 )
                :SetVariable (21006 :GBoolean False )
                :Deactivate (24004)
            )
        }

// Actioned when missile X > invader X
        {:Link
            24004
            :InitiallyActive False
            :EventSource 21001
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                :SetVariable ( 21003 :GInteger :IndirectRef 1007 )
                :Add ( 21003 50 )
                :Activate ( 24005 )
                :TestVariable ( 21003 6 :GInteger :IndirectRef 21001 )
                :Deactivate ( 24005 )
            )
        }

// A HIT!
        {:Link
            24005
            :InitiallyActive False
            :EventSource 21003
            :EventType TestEvent
            :EventData  True
            :LinkEffect (
                // Stop the missile
                :Stop ( 23001 )
                // Stop the invader
                :Stop ( :IndirectRef 1006 )
                // Disable the missile
                :SetVariable ( 21006 :GBoolean False )
                // Disable the hit checking
                :Deactivate ( 24004 )
                // Display the explosion
                :Run ( 23002 )
                :SetPosition ( 23002 :IndirectRef 1007 :IndirectRef 1002 )
                // Decrement invader counter
                :Subtract ( 1011 1 )
                // Test to see if no invaders left
                :TestVariable ( 1011 1 :GInteger 0 )
            )
        }
    )

    :InputEventReg 4
    :SceneCS 720 576
    :MovingCursor True
}

ZIP file containing MHEG text notation, ASN.1 notation and graphics:

    Download

Digital Video
Glossary MPEG Bitrate

Video Editing
Intro

HDTV
Introduction Plasma LCD Projection HDTV Antennas

Freeview
Introduction Aerial Channels Coverage PVR Recording STB Guides TV

Media
VCD SVCD DVD DV

TMPGEnc
Beginners Settings

Encode

Author

MHEG-5

Software

Links

If you have any comments please use the feedback form.
Add to Favourites Privacy Policy
Copyright © 2002-2014 Ian Willis. All rights reserved.