.. index:: 
	single: 2D ゲームエンジン; はじめに

====================================
デモプロジェクト - 2D ゲームエンジン
====================================

シンプルな 2D ゲームエンジンの作成を通じて、多種多様なプログラミングパラダイムをプロジェクトで併用する方法を学びます。

これでデスクトップ、またはモバイル用 2D ゲームを作成できます。

.. index:: 
	pair: 2D ゲームエンジン; プロジェクトの階層

プロジェクトの階層
==================

このような階層をプロジェクトで使用しています。

* ゲームの階層 (宣言型プログラミング)
* ゲームエンジンのクラス (オブジェクト指向プログラミングのパラダイム)
* グラフィックスライブラリへのインタフェース (手続き型プログラミング)
* グラフィックスライブラリへのバインディング (RingAllegro と RingLibSDL)

.. index:: 
	pair: 2D ゲームエンジン; グラフィックスライブラリのバインディング

グラフィックスライブラリのバインディング
========================================

Allegro ゲームプログラミング・ライブラリ用の RingAllegro と
LibSDL ゲームプログラミング・ライブラリ用の RingLibSDL があります。

RingAllegro と RingLibSDL は Ring コード生成器の支援により
C による拡張機能として作成されています。

RingAllegro と RingLibSDL はシンプルな設定ファイルを記述した後に生成される
10,000 行以上の C コードからなります (コード生成器による処理)。

RingAllegro と RingLibSDL の設定ファイルで関数名、構造体情報、および定数を決定後、
この設定ファイルを生成器で処理して C コードと
Ring コードから読み込み可能なライブラリを生成します。

RingAllegro と RingLibSDL の使用は同一関数を有する C コードから
Allegro および LibSDL の使用と非常に類似していますが Ring の機能で構築できます。

* RingAllegro のソースコード : https://github.com/ring-lang/ring/tree/master/extensions/ringallegro
* RingLibSDL のソースコード : https://github.com/ring-lang/ring/tree/master/extensions/ringsdl

.. index:: 
	pair: 2D ゲームエンジン; グラフィックスライブラリへのインタフェース

グラフィックスライブラリへのインタフェース
==========================================

この階層には gl_allegro.ring および gl_libsdl.ring があります。

グラフィックスライブラリとの相互作用により、ライブラリ間で同一関数を使えます。

この階層は RingAllegro と RingLibSDL の詳細と差異を吸収します。

同一関数で Allegro と LibSDL を何時でも切り替えて使えます。

なぜですか？

Allegro は非常に単純明快であり Windows, Linux および macOS 用の 2D ゲームを手軽に作成できます。

Ring 1.0 から Allegro へ対応しました。

また LibSDL は非常に強力かつ普及しており、モバイル開発では非常に簡単に使えます。

Ring 1.1 から LibSDL へ対応しているため、モバイル用のゲームを手軽に作成できます。

.. note:: このライブラリだけで、デスクトップとモバイル開発ができます。

* gl_allegro.ring のソースコード : https://github.com/ring-lang/ring/blob/master/ringlibs/gameengine/gl_allegro.ring
* gl_libsdl.ring のソースコード : https://github.com/ring-lang/ring/blob/master/ringlibs/gameengine/gl_libsdl.ring

.. index:: 
	pair: 2D ゲームエンジン; ゲームエンジンのクラス

ゲームエンジンのクラス
======================

このクラスがエンジンにあります。

* GameBase クラス
* Resources クラス
* Game クラス
* GameObject クラス
* Sprite クラス
* Text クラス
* Animate クラス
* Sound クラス
* Map クラス

* ソースコード : https://github.com/ring-lang/ring/blob/master/ringlibs/gameengine/gameengine.ring

.. index:: 
	pair: 2D ゲームエンジン; ゲームの階層

ゲームの階層
============

この階層では、ゲームエンジンのクラスを使用してゲームを作成します。

宣言型プログラミングでクラスの設計を行っています。

このクラスをゲームで使用しています。

* Game クラス
* Sprite クラス
* Text クラス
* Animate クラス
* Sound クラス
* Map クラス

.. note:: エンジンに実装されている上記以外のクラスは、エンジンの内部処理用です。

三種類のゲームと用例を紹介します:

* Stars Fighter ゲーム
* Flappy Bird 3000 ゲーム
* Super Man 2016 ゲーム

.. index:: 
	pair: 2D ゲームエンジン; Game クラス

Game クラス
===========

この表はクラスの属性です。

============	=================================================================================
属性 			説明
============	=================================================================================
FPS 			数値により毎秒ごとの draw() メソッドの呼び出し回数を決定します。
FixedFPS 		数値により毎秒ごとの animate() メソッドの呼び出し回数を決定します。
Title 			文字列によりゲームのウィンドウタイトルを決定します。
aObjects 		ゲーム内の全てのオブジェクトを有するリストです。
shutdown	 	True/False 値によりゲームのループを終了します。
============	=================================================================================

この表はクラスのメソッドです。

================	=================================================================================
メソッド 			説明
================	=================================================================================
refresh() 			オブジェクトを削除します。
settitle(cTitle) 	文字列による仮引数でウィンドウのタイトルを設定します。
shutdown() 			アプリケーションを閉じます。
find(cName)		オブジェクト名でオブジェクトを検索します。
remove(nID)		オブジェクト ID でオブジェクトを削除します。
================	=================================================================================

この表はクラスで定義されているキーワードのグループです。

================	=================================================================================
キーワード			説明
================	=================================================================================
sprite 				新しい Sprite オブジェクトを作成後に Game オブジェクトへ追加します。
text 				新しい Text オブジェクトを作成後に Game オブジェクトへ追加します。
animate 			新しい Animate オブジェクトを作成後に Game オブジェクトへ追加します。
sound 				新しい Sound オブジェクトを作成後に Game オブジェクトへ追加します。
map 				新しい Map オブジェクトを作成後に Game オブジェクトへ追加します。
================	=================================================================================

.. index:: 
	pair: 2D ゲームエンジン; GameObject クラス

GameObject クラス
=================

この表はクラスの属性です。

============	=====================================================================================
属性 			説明
============	=====================================================================================
enabled 		True/False によりオブジェクトの状態 (活動または休止) を決定します
x 				オブジェクトの x 位置を数値で決定します。
y 				オブジェクトの y 位置を数値で決定します。
width 			オブジェクトの幅を数値で決定します。
height 			オブジェクトの高さを数値で決定します。
nIndex			数値によりオブジェクトの ID を決定します。
name			文字列によりオブジェクト名を決定します。
animate 		True/False によりオブジェクトのアニメーションを行うかどうか決定します。
move 			True/False によりキーボードでオブジェクトの画像を移動するかどうか決定します。
Scaled 			True/False によりオブジェクトの画像の寸法を変更するかどうか決定します。
draw 			オブジェクトの描画時に呼び出される関数です。
state 			オブジェクトのアニメーションで呼び出される関数です。
keypress	 	キーが押し下げられた時に呼び出される関数です。
mouse 			マウスイベント発生時に呼び出される関数です。 
============	=====================================================================================

この表はクラスのメソッドです。

==============================	================================================================
メソッド 						説明
==============================	================================================================
keyboard(oGame,nkey) 			キーボードイベントを返します。
mouse(oGame,nType,aMouseList) 	マウスイベントを確認します。
rgb(r,g,b)					 	RGB (赤色、緑色、および青色) 値で新しい色を返します。
==============================	================================================================

.. index:: 
	pair: 2D ゲームエンジン; Sprite クラス

Sprite クラス
=============

親クラス : GameObject クラス

この表はクラスの属性です。

============	=================================================================================
属性 			説明
============	=================================================================================
image 			画像ファイル名を文字列で決定します。
point 			数値によりオブジェクトにおける自動移動の制限を決定します。
direction 		数値により移動方向を決定します。
nstep 			数値により移動中の増分または減分を決定します。
type		 	数値によりゲームでのオブジェクトの種類を決定します (オプション扱い)。
transparent 	True/False の値により画像の透過を決定します。
============	=================================================================================

この表はクラスのメソッドです。

================	=================================================================================
メソッド 			説明
================	=================================================================================
Draw(oGame) 		オブジェクトを描画します。
================	=================================================================================

.. index:: 
	pair: 2D ゲームエンジン; Text クラス

Text クラス
===========

親クラス : Sprite クラス

この表はクラスの属性です。

============	=================================================================================
属性 			説明
============	=================================================================================
size 			数値によりフォントの寸法を決定します。
font 			文字列によりフォントのファイル名を決定します。
text 			文字列により表示されるテキストを決定します。
color 			数値により色を決定します。
============	=================================================================================

この表はクラスのメソッドです。

================	=================================================================================
メソッド 			説明
================	=================================================================================
Draw(oGame)		 	オブジェクトを描画します。
================	=================================================================================


.. index:: 
	pair: 2D ゲームエンジン; Animate クラス

Animate クラス
==============

親クラス : Sprite クラス

この表はクラスの属性です。

============	=================================================================================
属性 			説明
============	=================================================================================
frames 			数値によりフレーム数を決定します。
frame 			数値により有効なフレームを決定します。
framewidth	 	数値によりフレームの幅を決定します。
animate 		True/False によりアニメーションの使用を決定します。
scaled 			True/False により画像の尺度変更を決定します。
============	=================================================================================

この表はクラスのメソッドです。

================	=================================================================================
メソッド 			説明
================	=================================================================================
Draw(oGame) 		オブジェクトを描画します。
================	=================================================================================

.. index:: 
	pair: 2D ゲームエンジン; Sound クラス

Sound クラス
============

親クラス : GameObject クラス

この表はクラスの属性です。

============	=================================================================================
属性 			説明
============	=================================================================================
file		 	音声ファイル名を文字列で決定します。
once		 	True/False によりファイルを一回またはループ再生するかどうかを決定します。
============	=================================================================================

この表はクラスのメソッドです。

================	=================================================================================
メソッド 			説明
================	=================================================================================
playsound() 		音声ファイルを再生します。
================	=================================================================================

.. index:: 
	pair: 2D ゲームエンジン; Map クラス

Map クラス
==========

親クラス : Sprite クラス

この表はクラスの属性です。

============	=================================================================================
属性 			説明
============	=================================================================================
aMap 			数値でマップの中身をリストで決定します。
aImages 		マップの各番号で使用されている画像をリストで決定します。
BlockWidth 		ブロックの幅を数値で決定します (デフォルト = 32)。
BlockHeight 	ブロックの高さを数値で決定します (デフォルト = 32)。
Animate 		アニメーションの状態を True/False で決定します。
============	=================================================================================

この表はクラスのメソッドです。

================	=================================================================================
メソッド 			説明
================	=================================================================================
getvalue(x,y) 		項目の値でマップの可視部分を返します。
================	=================================================================================

.. index:: 
	pair: 2D ゲームエンジン; ゲームエンジンの用法 - ゲームウィンドウの作成

ゲームエンジンの用法 - ゲームウィンドウの作成
=============================================

.. code-block:: ring

	Load "gameengine.ring"	# ゲームエンジンへ制御権を与えます。

	func main		# ゲームエンジンから呼び出されます。

		oGame = New Game	# Game オブジェクトの作成
		{
			title = "My First Game"
		}			# イベントループの開始

.. note:: この命令でゲームエンジンに制御権を委譲します。よって、グローバル変数の定義は "gameengine.ring" を読み込む前に行う必要があります。

スクリーンショット:

.. image:: gameengineshot1.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; テキストの描画

ゲームエンジンの用法 - テキストの描画
=====================================

.. code-block:: ring

	Load "gameengine.ring"	# ゲームエンジンへ制御権を与えます。

	func main		# ゲームエンジンから呼び出されます。

		oGame = New Game	# Game オブジェクトの作成
		{
			title = "My First Game"
			text {
				x = 10	y=50
				animate = false
				size = 20
				file = "fonts/pirulen.ttf"
				text = "game development using ring is very fun!"
				color = rgb(0,0,0)	
			}
		}		# イベントループの開始


スクリーンショット:

.. image:: gameengineshot2.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; テキストの移動

ゲームエンジンの用法 - テキストの移動
=========================================

.. code-block:: ring

	Load "gameengine.ring"	# ゲームエンジンへ制御権を与えます。

	func main		# ゲームエンジンから呼び出されます。

		oGame = New Game	# Game オブジェクトの作成
		{
			title = "My First Game"
			text {
				x = 10	y=50
				animate = false
				size = 20
				file = "fonts/pirulen.ttf"
				text = "game development using ring is very fun!"
				color = rgb(0,0,0)	# 配色 = 黒色
			}
			text {
				x = 10	y=150
				# アニメーション部分 =================================
				animate = true			# アニメーションの使用
				direction = GE_DIRECTION_INCVERTICAL	# y の増分
				point = 400		 	# y=400 になるまで継続
				nStep = 3			# 毎回 y+= 3 を行う
				#=====================================================
				size = 20
				file = "fonts/pirulen.ttf"
				text = "welcome to the real world!"
				color = rgb(0,0,255)		# 配色 = 青色
			}
		}					# イベントループの開始

スクリーンショット:

.. image:: gameengineshot3.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; 音声の再生

ゲームエンジンの用法 - 音声の再生
=====================================

.. code-block:: ring

	Load "gameengine.ring"	# ゲームエンジンへ制御権を与えます。

	func main		# ゲームエンジンから呼び出されます。

		oGame = New Game	# Game オブジェクトの作成
		{
			title = "My First Game"
			text {
				x = 10	y=50
				animate = false
				size = 20
				file = "fonts/pirulen.ttf"
				text = "game development using ring is very fun!"
				color = rgb(0,0,0)	# 配色 = 黒色
			}
			text {
				x = 10	y=150
				# アニメーション部分 ======================================
				animate = true				# アニメーションの使用
				direction = GE_DIRECTION_INCVERTICAL	# y の増分
				point = 400	 	# y=400 になるまで継続
				nStep = 3		# 毎回 y+= 3 を行う
				#==========================================================
				size = 20
				file = "fonts/pirulen.ttf"
				text = "welcome to the real world!"
				color = rgb(0,0,255)	# 配色 = 青色
			}
			Sound {					# 音声の再生
				file = "sound/music1.wav"	# イベントループの開始
			}		
		}					# イベントループの開始

.. index:: 
	pair: 2D ゲームエンジン; アニメーション

ゲームエンジンの用法 - アニメーション
=========================================

.. code-block:: ring

	Load "gameengine.ring"	# ゲームエンジンへ制御権を与えます。

	func main          	# ゲームエンジンから呼び出されます。

	  oGame = New Game      # Game オブジェクトの作成
	  {
		title = "My First Game"

		animate {
		  file = "images/fire.png"
		  x = 100
		  y = 200
		  framewidth = 40
		  height = 42
		  nStep = 3      # ディレイで使用
		  transparent = true
		  state = func oGame,oSelf {  # エンジンの各フレームで呼び出されます
			oSelf {
			  nStep--
			  if nStep = 0
				nStep = 3
				if frame < 13      # 13 フレームから構成されるアニメーション
				  frame++   # 次のフレームへ移動
				else
				  oGame.remove(oself.nIndex)   # オブジェクトの削除
				ok
			  ok
			}
		  }
		 }    
		

	  }          # イベントループの開始


.. image:: gameengineshot5.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; アニメーションと関数

ゲームエンジンの用法 - アニメーションと関数
===============================================

.. code-block:: ring

	Load "gameengine.ring"	# ゲームエンジンへ制御権を与えます。

	func main          	# ゲームエンジンから呼び出されます。

	  oGame = New Game      # Game オブジェクトの作成
	  {
		title = "My First Game"
		for x = 70 to 700 step 50
		  for y = 70 to 500 step 50
			showfire(oGame,x,y)
		  next
		next

	  }          # イベントループの開始

	func showfire oGame,nX,nY
	  oGame {
		animate {
		  file = "images/fire.png"
		  x = nX
		  y = nY
		  framewidth = 40
		  height = 42
		  nStep = 3      # ディレイで使用
		  transparent = true
		  state = func oGame,oSelf {  # エンジンの各フレームで呼び出されます
			oSelf {
			  nStep--
			  if nStep = 0
				nStep = 3
				if frame < 13      # 13 フレームから構成されるアニメーション
				  frame++   # 次のフレームへ移動
				else
				  frame=1
				ok
			  ok
			}
		  }
		 }  
	  }

.. image:: gameengineshot6.png
	:alt: スクリーンショット


.. index:: 
	pair: 2D ゲームエンジン; キーボードによる自動移動

ゲームエンジンの用法 - スプライト - キーボードによる自動移動
============================================================

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"
			sprite
			{
				type = GE_TYPE_PLAYER		# 用法
				x=400 y=400 width=100 height=100
				file = "images/player.png"	
				transparent = true			
				Animate=false 
				Move=true 	# キーボードの矢印キーで移動できます。
				Scaled=true
			}
		}					# イベントループの開始

.. image:: gameengineshot7.png
	:alt: スクリーンショット


.. index:: 
	pair: 2D ゲームエンジン; スプライト - キー入力イベント

ゲームエンジンの用法 - スプライト - キー入力イベント
====================================================

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"
			sprite
			{
				type = GE_TYPE_PLAYER		# 用法
				x=400 y=400 width=100 height=100
				file = "images/player.png"	
				transparent = true			
				Animate=false 
				Move=false			# カスタム移動
				Scaled=true
				keypress = func oGame,oSelf,nKey {
					oSelf { 
						Switch nKey	
						on KEY_LEFT	
							x -= 10			
						on KEY_RIGHT
							x += 10
						on KEY_UP
							y -= 10
						on KEY_DOWN
							y += 10
						off
					}
				}
			}
		}					# イベントループの開始

.. index:: 
	pair: 2D ゲームエンジン; スプライト - マウスイベント

ゲームエンジンの用法 - スプライト - マウスイベント
======================================================

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"
			sprite
			{
				type = GE_TYPE_PLAYER		# 用法
				x=400 y=400 width=100 height=100
				file = "images/player.png"	
				transparent = true			
				Animate=false 
				Move=false			# カスタム移動
				Scaled=true
				keypress = func oGame,oSelf,nKey {
					oSelf { 
						Switch nKey	
						on KEY_LEFT	
							x -= 10			
						on KEY_RIGHT
							x += 10
						on KEY_UP
							y -= 10
						on KEY_DOWN
							y += 10
						off
					}
				}
				mouse = func oGame,oSelf,nType,aMouseList {
					if nType = GE_MOUSE_UP
						oSelf {
							x = aMouseList[GE_MOUSE_X]
							y = aMouseList[GE_MOUSE_Y]
						}
					ok
				}
			}
		}					# イベントループの開始

.. index:: 
	pair: 2D ゲームエンジン; スプライト - ステートイベント

ゲームエンジンの用法 - スプライト - ステートイベント
========================================================

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"
			sprite
			{
				type = GE_TYPE_PLAYER		# 用法
				x=400 y=400 width=100 height=100
				file = "images/player.png"	
				transparent = true			
				Animate=false 
				Move=false			# カスタム移動
				Scaled=true
				keypress = func oGame,oSelf,nKey {
					oSelf { 
						Switch nKey	
						on KEY_LEFT	
							x -= 10			
						on KEY_RIGHT
							x += 10
						on KEY_UP
							y -= 10
						on KEY_DOWN
							y += 10
						off
					}
				}
				mouse = func oGame,oSelf,nType,aMouseList {
					if nType = GE_MOUSE_UP
						oSelf {
							x = aMouseList[GE_MOUSE_X]
							y = aMouseList[GE_MOUSE_Y]
						}
					ok
				}
				state = func oGame,oSelf {
					oself {
						if x < 0 x = 0 ok
						if y < 0 y = 0 ok
						if x > ogame.width-width  
							x= ogame.width - width ok
						if y > ogame.height-height 
							y=ogame.height - height ok
					}
				}
			}
		}					# イベントループの開始


.. index:: 
	pair: 2D ゲームエンジン; アニメーション - イベント

ゲームエンジンの用法 - アニメーション - イベント
====================================================

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"

			animate {

				file = "images/fbbird.png"
				x = 10
				y = 10
				framewidth = 20
				scaled = true
				height = 50
				width = 50
				nStep = 3
				transparent = true

				state = func oGame,oSelf {
					oSelf {

						# アニメーション
							nStep--
							if nStep = 0
								nStep = 3
								if frame < 3
									frame++
								else
									frame=1
								ok
							ok

						# 下へ移動
							y += 3
							if y > 550 y=550 ok

					}

				}

				keypress = func ogame,oself,nKey {
					oself {
						if nkey = key_space
							y -= 55
							if y<=0 y=0 ok
						ok
					}
				}

				mouse = func ogame,oself,nType,aMouseList {
					if nType = GE_MOUSE_UP
						cFunc = oself.keypress
						call cFunc(oGame,oSelf,Key_Space)
					ok
				}
			}
		}					# イベントループの開始

スクリーンショット:

.. image:: gameengineshot11.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; マップ


ゲームエンジンの用法 - マップ
=================================

.. code-block:: ring

	Load "gameengine.ring"        # ゲームエンジンへ制御権を与えます。

	func main          # ゲームエンジンから呼び出されます。

	oGame = New Game      # Game オブジェクトの作成
	{
	  title = "My First Game"

	  Map {

		blockwidth = 80
		blockheight = 80

		aMap = [
			[0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
			[0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
			[0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0],
			[0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0],
			[0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0],
			[0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
			[0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
			[0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
		]

		aImages = ["images/fbwall.png",
			 "images/fbwallup.png",
			 "images/fbwalldown.png"]

		state = func oGame,oSelf {
		  oSelf {
			x -= 3
			if x < - 2100  x = 0  ok
		  }
		}

	  }
	}          # イベントループの開始


スクリーンショット:

.. image:: gameengineshot12.png
	:alt: スクリーンショット


.. index:: 
	pair: 2D ゲームエンジン; マップイベント

ゲームエンジンの用法 - マップイベント
=========================================

.. code-block:: ring

	Load "gameengine.ring"        # ゲームエンジンへ制御権を与えます。

	func main          # ゲームエンジンから呼び出されます。

	  oGame = New Game      # Game オブジェクトの作成
	  {
		title = "My First Game"

		Map {

		  blockwidth = 80
		  blockheight = 80

		  aMap = [
			   [0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0],
			  [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
			  [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
			  [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
		  ]

		  aImages = ["images/fbwall.png",
				 "images/fbwallup.png",
				 "images/fbwalldown.png"]

		  state = func oGame,oSelf {
			oSelf {
			  x -= 3
			  if x < - 2100  x = 0  ok
			}
		  }

		  mouse = func ogame,oself,nType,aMouseList {
			if nType = GE_MOUSE_UP
			  oSelf {
				mX = aMouseList[GE_MOUSE_X]
				mY = aMouseList[GE_MOUSE_Y]
				nValue = GetValue(mX,mY)
				nRow = GetRow(mX,mY)
				nCol = GetCol(mX,mY)
				Switch nValue
				On 1  aMap[nRow][nCol] = 0
				On 2  aMap[nRow][nCol] = 0
				On 3  aMap[nRow][nCol] = 0
				On 0  aMap[nRow][nCol] = 1
				Off
			  }
			ok
		  }

		}
	  }          # イベントループの開始

スクリーンショット:

.. image:: gameengineshot13.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; オブジェクトと描画処理

ゲームエンジンの用法 - オブジェクトと描画処理
=============================================

GameObject クラスからオブジェクトを作成するには、 Object キーワード (ゲームエンジンで定義済み) を使用します。

用例:

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"
			Object {
				x = 0 y=300 width = 200 height=200
				draw = func oGame,oSelf {
					oSelf {
						for t = 1 to 210
							gl_draw_circle(x,y,t,
							gl_map_rgb(t*random(255),
							t*2,t*3),1)
						next
					}
				}
				state = func oGame,oSelf {
					oSelf { 
						if x <= 800 
							x+= 3 
						else
							x=0
						ok
					}
				}
				keypress = func oGame,oSelf,nKey {
					oSelf { 
						Switch nKey	
						on KEY_LEFT	
							x -= 10			
						on KEY_RIGHT
							x += 10
						on KEY_UP
							y -= 10
						on KEY_DOWN
							y += 10
						off
					}
				}
			}

		}					# イベントループの開始

スクリーンショット:

.. image:: gameengineshot14.png
	:alt: スクリーンショット

用例:

.. code-block:: ring

	Load "gameengine.ring"				# ゲームエンジンへ制御権を与えます。

	func main					# ゲームエンジンから呼び出されます。

		oGame = New Game			# Game オブジェクトの作成
		{
			title = "My First Game"
			Object {
				x = 400 y=300 width = 200 height=200
				draw = func oGame,oSelf {
					oSelf {
						for t = 1 to 210
							gl_draw_rectangle(x+t,y+t,
							x+t*2,y+t*2,
							gl_map_rgb(t*random(255),
							t*2,t*3),1)
							gl_draw_rectangle(x+t*2,y+t*2,
							x-t*2,y-t*2,
							gl_map_rgb(t*random(255),
							t*2,t*3),1)
						next
					}
				}
				keypress = func oGame,oSelf,nKey {
					oSelf { 
						Switch nKey	
						on KEY_LEFT	
							x -= 10			
						on KEY_RIGHT
							x += 10
						on KEY_UP
							y -= 10
						on KEY_DOWN
							y += 10
						off
					}
				}
			}

		}					# イベントループの開始


スクリーンショット:

.. image:: gameengineshot15.png
	:alt: スクリーンショット

.. index:: 
	pair: 2D ゲームエンジン; Stars Fighter ゲーム

Stars Fighter ゲーム
====================

Stars Fighter ゲームのソースコード

.. code-block:: ring

	# Ring 標準ライブラリ
	# 2D ゲームエンジン
	# 2016, Mahmoud Fayed <msfclipper@yahoo.com>

	oGameState = NULL

	load "gameengine.ring"

	func main

	  oGame = New Game

	  while true

		  oGameState = new GameState

		  oGame {
			title = "Stars Fighter!"
			sprite
			{
			  file = "images/menu1.jpg"
			  x = 0 y=0 width=800 height = 600 scaled = true animate = false
			  keypress = func ogame,oself,nKey {
				if nkey = key_esc or nKey = GE_AC_BACK
				  ogame.shutdown()
				but nKey = key_space
				  oGameState.startplay=true
				  ogame.shutdown=true
				ok
			  }
			  mouse = func ogame,oself,nType,aMouseList {
				if nType = GE_MOUSE_UP
				  oGameState.startplay=true
				  ogame.shutdown=true
				ok
			  }
			}
			text {
			  animate = false
			  size = 35
			  file = "fonts/pirulen.ttf"
			  text = "Stars Fighter"
			  x = 10  y=50
			}
			text {
			  animate = false
			  size = 25
			  file = "fonts/pirulen.ttf"
			  text = "Version 1.0"
			  x = 80  y=100
			}
			text {
			  animate = false
			  size = 16
			  file = "fonts/pirulen.ttf"
			  text = "(C) 2016, Mahmoud Fayed"
			  x = 45  y=140
			}

			text {
			  animate = false
			  size = 25
			  file = "fonts/pirulen.ttf"
			  text = "Press Space to start"
			  x = 190  y=470
			}
			text {
			  animate = false
			  size = 20
			  file = "fonts/pirulen.ttf"
			  text = "Press Esc to Exit"
			  x = 260  y=510
			}
			Sound {
			  file = "sound/music1.wav"
			}
		  }

		  if oGameState.startplay
			oGame.refresh()
			playstart(oGame)
			oGame.refresh()
		  ok

	  end

	func playstart oGame

	  oSound = New Sound {
		file = "sound/music2.wav"
	  }

	  while true
		play(oGame)
		if ogame.shutdown = true and oGameState.value = 0
		  exit
		ok
		ogame.refresh()
	  end

	  oSound.Delete()

	func play oGame

	  oGame
	  {
		FPS = 60
		FixedFPS = 120
		title = "Stars Fighter!"
		sprite
		{
		  file = "images/stars.jpg"
		  x = 0
		  y = 0
		  point = -370
		  direction = ge_direction_dec
		  type = ge_type_background
		  state = func ogame,oself {
			  oself {
				if x < -350
				  direction = ge_direction_inc
				  point = 370
				but x = 0 and direction = ge_direction_inc
				  direction = ge_direction_dec
				  point = -370
				ok
			  }
			}
		}
		sprite
		{
		  file = "images/player.png"
		  transparent = true
		  type = ge_type_player
		  x = 400 y =400 width=100 height=100
		  animate=false move=true Scaled=true
		  mouse = func ogame,oself,nType,aMouseList {

			if not ( aMouseList[GE_MOUSE_X] >= oSelf.x and 
					 aMouseList[GE_MOUSE_X] <= oSelf.x+oSelf.width and
					 aMouseList[GE_MOUSE_Y] >= oself.y and 
					 aMouseList[GE_MOUSE_Y] <= oSelf.y+oSelf.height )

			  if nType = GE_MOUSE_DOWN
				if aMouseList[1] < oSelf.X  # 左
				  oSelf.X -= 100
				else
				  oSelf.X += 100
				ok
				if aMouseList[2] < oSelf.Y  # 上
				  oSelf.Y -= 100
				else
				  oSelf.Y += 100
				ok
			  ok

			else
			  if nType = GE_MOUSE_UP
				cFunc = oself.keypress
				call cFunc(oGame,oSelf,Key_Space)
			  ok
			ok
		  }
		  keypress = func oGame,oself,nkey {
			if nkey = key_space
			  ogame {
				sprite {
				  type = ge_type_fire
				  file  = "images/rocket.png"
				  transparent = true
					x = oself.x + 30
				  y = oself.y - 30
				  width = 30
				  height = 30
				  point = -30
				  nstep = 20
				  direction = ge_direction_decvertical
				  state = func oGame,oSelf {
					for x in oGame.aObjects
					  if x.type = ge_type_enemy
						if oself.x >= x.x and oself.y >= x.y and
						  oself.x <= x.x + x.width and
						  oself.y <= x.y + x.height
						  showfire(oGame,x.x+40,x.y+40)
						  ogame.remove(x.nindex)
						  oGameState.score+=10
						  oGameState.enemies--
						  checkwin(oGame)
						  exit
						ok
					  ok
					next
				  }
				}
			  }
			but nkey = key_esc or nKey = GE_AC_BACK ogame.shutdown()
			ok
		  }
		  state = func oGame,oSelf {
			oself {
			  if x < 0 x = 0 ok
			  if y < 0 y = 0 ok
			  if x > ogame.screen_w-width  x= ogame.screen_w - width ok
			  if y > ogame.screen_h-height y=ogame.screen_h-height ok
			}
		  }
		}
		for g = 1 to oGameState.enemies
		  sprite
		  {
			type = ge_type_enemy
			file = "images/enemy.png"
			transparent = true
			x = g*random(50) y =g width=100 height=100
			animate=true Scaled=true
			direction = ge_direction_random
			state = func oGame,oSelf {
			  oself {
				if x < 0 x = 0 ok
				if y < 0 y = 0 ok
				if x > ogame.screen_w-width  x= ogame.screen_w - width ok
				if y > ogame.screen_h-height y=ogame.screen_h-height ok
			  }
			  if random(100) = 1
				ogame {
				  sprite {
					type = ge_type_fire
					file  = "images/rocket2.png"
					transparent = true
					x = oself.x + 30
					y = oself.y + oself.height+ 30
					width = 30
					height = 30
					point = ogame.screen_h+30
					nstep = 10
					direction = ge_direction_incvertical
					state = func oGame,oSelf {
					  x =  oGame.aObjects[oGameState.playerindex]
					  if oself.x >= x.x and oself.y >= x.y and
						 oself.x <= x.x + x.width and
						 oself.y <= x.y + x.height
						 if oGameState.value > 0
						   oGameState.value-=10
						 ok
						 ogame.remove(oself.nindex)
						 checkgameover(oGame)
					  ok
					}
				  }
				}
			  ok
			}
		  }
		next
		text {
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Destroy All Enemies!"
		  nstep = 3
		  color = GE_COLOR_GREEN
		  x = 100  y=50
		  direction = ge_direction_incvertical
		  point = 500
		}
		text {
		  animate = false
		  point = 400
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Score : " + oGameState.score
		  x = 500  y=10
		  state = func oGame,oSelf { oSelf { text = "Score : " + oGameState.score } }
		}
		text {
		  animate = false
		  point = 400
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Energy : " + oGameState.value
		  x = 500  y=50
		  state = func oGame,oSelf { oSelf { text = "Energy : " + oGameState.value } }
		}
		text {
		  animate = false
		  point = 400
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Level : " + oGameState.level
		  x = 500  y=90
		}
	  }


	func checkwin ogame
	  if oGameState.gameresult  return ok
	  if oGameState.enemies = 0
		oGameState.gameresult = true
		oGame {
		  if oGameState.level < 30
		  text {
			point = 400
			size = 30
			file = "fonts/pirulen.ttf"
			text = "Level Completed!"
			nStep = 3
			x = 500  y=10
			state = func ogame,oself {
			  if oself.y >= 400
				ogame.shutdown = true
				oGameState.level++
				oGameState.enemies = oGameState.level
				oGameState.gameresult = false
			  ok
			}
		  }
		  else
		  text {
			point = 400
			size = 30
			nStep = 3
			file = "fonts/pirulen.ttf"
			text = "You Win !!!"
			x = 500  y=10
			state = func ogame,oself {
			  if oself.y >= 400
				ogame.shutdown = true
				oGameState.value = 0
			  ok
			}
		  }
		  ok
		}
	  ok

	func checkgameover ogame
	  if oGameState.gameresult  return ok
	  if oGameState.value <= 0
		oGameState.gameresult = true
		oGame {
		  text {
			point = 400
			size = 30
			nStep = 3
			file = "fonts/pirulen.ttf"
			text = "Game Over !!!"
			x = 500  y=10
			state = func ogame,oself {
			  if oself.y >= 400
				ogame.shutdown = true
			  ok
			}
		  }
		}
		showfire(oGame,oGame.aObjects[oGameState.PlayerIndex].x+40,
				 oGame.aObjects[oGameState.PlayerIndex].y+40)
		oGame.aObjects[oGameState.PlayerIndex].enabled = false
		oGame.remove(oGameState.PlayerIndex)
	  ok


	func showfire oGame,nX,nY
	  oGame {
		animate {
		  file = "images/fire.png"
		  x = nX
		  y = nY
		  framewidth = 40
		  height = 42
		  nStep = 3
		  transparent = true
		  state = func oGame,oSelf {
			oSelf {
			  nStep--
			  if nStep = 0
				nStep = 3
				if frame < 13
				  frame++
				else
				  frame=1
				  oGame.remove(oself.nIndex)
				ok
			  ok
			}
		  }
		}
	  }


	class gamestate
	  score = 0
	  level = 1
	  enemies = 1
	  value = 100
	  playerindex = 2
	  gameresult = false
	  startplay=false

スクリーンショット:

.. image:: starsfighter.png
	:alt: Stars Fighter


.. index:: 
	pair: 2D ゲームエンジン; Flappy Bird 3000 ゲーム

Flappy Bird 3000 ゲーム
=======================

Flappy Bird 3000 ゲームのソースコード

.. code-block:: ring

	# Ring 標準ライブラリ
	# 2D ゲームエンジン
	# 2016, Mahmoud Fayed <msfclipper@yahoo.com>

	oGameState = NULL

	Load "gameengine.ring"

	func main

	  oGame = New Game  


	  while true

		oGameState = New GameState

		oGame {
		  title = "Flappy Bird 3000"
		  sprite
		  {
			file = "images/fbback.png"
			x = 0 y=0 width=800 height = 600 scaled = true animate = false
			keypress = func ogame,oself,nKey {
			  if nkey = key_esc or nKey = GE_AC_BACK
				ogame.shutdown()
			  but nKey = key_space
				oGameState.startplay=true
				ogame.shutdown=true
			  ok
			}
			mouse = func ogame,oself,nType,aMouseList {
			  if nType = GE_MOUSE_UP
				cFunc = oself.keypress
				call cFunc(oGame,oSelf,Key_Space)
			  ok
			}
		  }
		  text {
			animate = false
			size = 35
			file = "fonts/pirulen.ttf"
			text = "Flappy Bird 3000"
			x = 150  y=50
		  }
		  text {
			animate = false
			size = 25
			file = "fonts/pirulen.ttf"
			text = "Version 1.0"
			x = 280  y=100
		  }
		  text {
			animate = false
			size = 16
			file = "fonts/pirulen.ttf"
			text = "(C) 2016, Mahmoud Fayed"
			x = 245  y=140
		  }

		  text {
			animate = false
			size = 25
			file = "fonts/pirulen.ttf"
			text = "To Win Get Score = 3000"
			x = 150  y=270
		  }

		  text {
			animate = false
			size = 25
			file = "fonts/pirulen.ttf"
			text = "Press Space to start"
			x = 190  y=470
		  }
		  text {
			animate = false
			size = 20
			file = "fonts/pirulen.ttf"
			text = "Press Esc to Exit"
			x = 260  y=510
		  }

		  animate {
			file = "images/fbbird.png"
			x = 200
			y = 200
			framewidth = 20
			scaled = true
			height = 50
			width = 50
			nStep = 3
			transparent = true
			animate = true
			direction = ge_direction_random
			state = func oGame,oSelf {
			  oSelf {
				nStep--
				if nStep = 0
				  nStep = 3
				  if frame < 3
					frame++
				  else
					frame=1
				  ok
				ok
				if x <= 0 x=0 ok
				if y <= 0 y=0 ok
				if x >= 750 x= 750 ok
				if y > 550 y=550 ok
			  }
			}
		  }

		  Sound {
			file = "sound/music2.wav"
		  }
		}
		if oGameState.startplay
		  oGame.refresh()
		  playstart(oGame)
		  oGame.refresh()
		ok

	  end


	func playstart oGame

	  oGame {
		FPS = 60
		FixedFPS = 120
		Title = "Flappy Bird 3000"
		Sprite {
		  file = "images/fbback.png"
		  x = 0 y=0 width=800 height = 600 scaled = true animate = false
		  keypress = func ogame,oself,nKey {
			if nkey = key_esc or nKey = GE_AC_BACK
			  ogame.shutdown()
			ok
		  }
		}

		Map {
		  blockwidth = 80
		  blockheight = 80
		  aMap = [
			   [0,0,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,3,0,0,0,1,0,0,0,1,0,0,0],
			  [0,0,0,0,0,0,0,0,0,3,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,3,0,0,0],
			  [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
			  [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0],
			  [0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0]
			]
		  newmap(aMap)
		  aImages = ["images/fbwall.png","images/fbwallup.png",
			  "images/fbwalldown.png"]
		  state = func oGame,oSelf {
			if oGameState.gameresult = false
			  px = oGame.aObjects[3].x
			  py = oGame.aObjects[3].y
			  oSelf {
				x -=  3
				if x < - 2100
				  x = 0
				  newmap(aMap)
				ok
				nCol =  getcol(px,0)
				if nCol=11 or nCol=15 or nCol=19 or nCol=23 or nCol=27
				  if nCol != oGameState.lastcol
					oGameState.lastcol = nCol
					oGameState.Score += 100
					oGame { Sound {
					  once = true
					  file = "sound/sfx_point.wav"
					} }
					checkwin(oGame)
				  ok
				ok
			  }
			  if  oSelf.getvalue(px+40,py) != 0 or
				  oSelf.getvalue(px+40,py+40) != 0 or
				  oSelf.getvalue(px,py) != 0 or
				  oSelf.getvalue(px,py+40) != 0
				oGameState.gameresult = true
				oGame {
				  text {
					point = 550
					size = 30
					nStep = 3
					file = "fonts/pirulen.ttf"
					text = "Game Over !!!"
					x = 500  y=10
					state = func ogame,oself {
					  if oself.y >= 550
						  ogame.shutdown = true
					  ok
						if oself.y = 90
						ogame {
						  Sound {
							once = true
							file = "sound/sfx_die.wav"
						  }
						}
					  ok
					}
				  }
				  Sound {
					once = true
					file = "sound/sfx_hit.wav"
				  }
				}
			  ok
			ok
		  }
		}

		animate {
		  file = "images/fbbird.png"
		  x = 10
		  y = 10
		  framewidth = 20
		  scaled = true
		  height = 50
		  width = 50
		  nStep = 3
		  transparent = true
		  state = func oGame,oSelf {
			oSelf {
			  nStep--
			  if nStep = 0
				nStep = 3
				if frame < 3
				  frame++
				else
				  frame=1
				ok
			  ok
			}

			if not oGameState.playerwin
			  oGameState.down --
			  if oGameState.down = 0
				oGameState.down = 3
				oself {
				  y += 25
				  if y > 550 y=550 ok
				}
			  ok
			ok

		  }
		  keypress = func ogame,oself,nKey {
			if oGameState.gameresult = false
			  oself {
				if nkey = key_space
				  y -= 55
				  oGameState.down = 60
				  if y<=0 y=0 ok
				ok
			  }
			ok
		  }
		  mouse = func ogame,oself,nType,aMouseList {
			if nType = GE_MOUSE_UP
			  cFunc = oself.keypress
			  call cFunc(oGame,oSelf,Key_Space)
			ok
		  }
		}

		text {
		  animate = false
		  point = 400
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Score : " + oGameState.score
		  x = 500  y=10
		  state = func oGame,oSelf {
			oSelf { text = "Score : " + oGameState.score }
		  }
		}

	  }

	func newmap aMap
	  aV = [
	  [1,1,3,0,0,2,1,1],
	  [1,3,0,0,0,2,1,1],
	  [1,1,1,3,0,2,1,1],
	  [1,1,1,3,0,0,0,0],
	  [0,0,0,0,2,1,1,1],
	  [0,0,2,1,1,1,1,1],
	  [0,0,0,2,1,1,1,1],
	  [1,1,1,3,0,2,1,1],
	  [1,1,1,1,1,3,0,0],
	  [3,0,0,2,1,1,1,1],
	  [3,0,0,2,3,0,0,2]
	  ]
	  for x = 10 to 24 step 4
		aVar = aV[ (random(10)+1) ]
		for y = 1 to 8
		  aMap[y][x] = aVar[y]
		next
	  next

	func checkwin ogame
	  if oGameState.score = 3000
		oGameState.gameresult = true
		oGameState.playerwin = true
		oGame {
		  text {
			point = 400
			size = 30
			nStep = 3
			file = "fonts/pirulen.ttf"
			text = "You Win !!!"
			x = 500  y=10
			state = func ogame,oself {
			  if oself.y >= 400
				ogame.shutdown = true
				oGameState.value = 0
			  ok
			}
		  }
		}
	  ok

	Class GameState
	  down = 3
	  gameresult = false
	  Score = 0
	  startplay=false
	  lastcol = 0
	  playerwin = false

スクリーンショット:

.. image:: flappybird.png
	:alt: Flappy Bird 300


.. index:: 
	pair: 2D ゲームエンジン; Super Man 2016 ゲーム

Super Man 2016 ゲーム
=====================

Super Man 2016 ゲームのソースコード

.. code-block:: ring

	# Ring 標準ライブラリ
	# 2D ゲームエンジン
	# 2016, Mahmoud Fayed <msfclipper@yahoo.com>

	oGameState = NULL

	Load "gameengine.ring"

	func main

	  oGame = New Game

	  while true

		oGameState = new GameState

		oGame {
		  title = "Super Man 2016"
		  sprite
		  {
			file = "images/superman.jpg"
			x = 0 y=0 width=800 height = 600 scaled = true animate = false
			keypress = func ogame,oself,nKey {
			  if nkey = key_esc or nKey = GE_AC_BACK
				ogame.shutdown()
			  but nKey = key_space
				oGameState.startplay=true
				ogame.shutdown=true
			  ok
			}
			mouse = func ogame,oself,nType,aMouseList {    
			  if nType = GE_MOUSE_UP
				oGameState.startplay=true 
				ogame.shutdown=true 
			  ok
			}
			state = func ogame,oself {
			  oself {
				if x > -500
				  x-=1
				  y-=1
				  width +=1
				  height +=4
				ok
			  }
			}
		  }
		  text {
			animate = false
			size = 35
			file = "fonts/pirulen.ttf"
			text = "Super Man 2016"
			x = 20  y=30
		  }
		  text {
			animate = false
			size = 25
			file = "fonts/pirulen.ttf"
			text = "Version 1.0"
			x = 20  y=80
		  }
		  text {
			animate = false
			size = 16
			file = "fonts/pirulen.ttf"
			text = "(C) 2016, Mahmoud Fayed"
			x = 20  y=120
		  }

		  text {
			animate = false
			size = 25
			file = "fonts/pirulen.ttf"
			text = "Press Space to start"
			x = 190  y=470
		  }
		  text {
			animate = false
			size = 20
			file = "fonts/pirulen.ttf"
			text = "Press Esc to Exit"
			x = 260  y=510
		  }

		  animate {
			file = "images/superman.png"
			x = 200
			y = 200
			framewidth = 68
			scaled = true
			height = 86
			width = 60
			nStep = 10
			transparent = true
			animate = true
			direction = ge_direction_random
			state = func oGame,oSelf {
			  oSelf {
				nStep--
				if nStep = 0
				  nStep = 10
				  if frame < 1
					frame++
				  else
					frame=1
				  ok
				ok
				if x <= 0 x=0 ok
				if y <= 0 y=0 ok
				if x >= 750 x= 750 ok
				if y > 550 y=550 ok
			  }
			}
		  }

		  Sound {
			file = "sound/music2.wav"
		  }
		}
		if oGameState.startplay
		  oGame.refresh()
		  playstart(oGame)
		  oGame.refresh()
		ok

	  end


	func playstart oGame

	  oGame {
		FPS = 60
		FixedFPS = 15
		Title = "Super Man 2016"
		Sprite {
		  file = "images/supermancity.jpg"
		  x = 0 y=0 width=800 height = 600 scaled = true animate = false
		}
		Map {
		  blockwidth = 80
		  blockheight = 80
		  aMap = [
			  [0,0,0,4,4,4,0,0,0,1,0,0,0,1,4,4,0,1,0,0,0,0,4,4,0,1,4,
	4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,1,0,0,0,1,0,0,0,1,0,3,3,3,5,3,3,3,3,0],
			  [0,0,4,0,4,0,4,0,0,1,0,0,0,3,4,4,4,1,0,0,0,0,4,4,0,1,4,
	4,4,0,0,4,4,4,4,4,4,4,4,4,4,4,4,1,4,1,0,0,0,1,0,0,0,1,0,4,4,4,4,4,4,4,4,0],
			  [0,0,0,4,4,4,0,0,0,1,0,0,0,4,4,4,4,1,0,0,0,0,0,0,0,3,4,
	4,4,0,0,4,0,0,0,0,0,0,4,2,0,0,4,1,4,1,4,2,4,1,0,2,0,1,0,4,4,4,4,4,4,4,4,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,4,4,4,4,4,4,4,4,1,0,0,4,1,4,1,4,1,4,1,0,1,0,1,0,2,2,2,2,2,2,2,2,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,
	0,0,0,0,2,0,0,0,0,0,2,0,3,0,0,0,1,4,1,4,1,4,1,0,1,0,1,0,1,0,0,0,0,0,0,0,0],
			  [0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,1,0,0,0,2,0,0,0,0,0,
	0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,1,4,3,4,1,4,3,0,1,0,3,0,1,0,0,0,0,0,0,0,0],
			  [0,0,2,0,0,2,0,0,2,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,
	0,0,0,0,1,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0],
			  [0,0,1,0,0,1,0,0,1,3,0,0,0,1,0,0,0,3,0,0,0,1,0,0,0,0,0,
	0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0]
			]
		  aImages = ["images/smwall.png","images/smwallup.png",
			  "images/smwalldown.png","images/smstar.png",
			  "images/smkey.png","images/smstar2.png"]
		}

		sprite {
		  type = ge_type_enemy
		  animate = false
		  file  = "images/smhome.png"
		  x = 5000
		  y = 400
		  width = 290
		  height = 200
		  transparent = true

		  state = func oGame,oSelf {
			oself {
			  x = 5000 +  oGame.aObjects[2].x
			  if x < 0 or x > SCREEN_W return ok
			}
			if oGameState.gameresult or oGameState.DoorKey = false  return ok
			if oGame.aObjects[oGameState.playerindex].x > oself.x + 100 and
			  oGame.aObjects[oGameState.playerindex].y > oself.y + 50
			  oGameState.gameresult = true
			  oGame {
				sprite {
				  file = "images/smwin.jpg"
				  x=0 y=0 width=800 height=600
				  scaled = true animate=false
				  state = func ogame,oself {
					oself {
					  x-=5
					  y-=5
					  width +=10
					  height +=10
					  if x = -300
						ogame.shutdown = true
					  ok
					}
				  }
				}
			  }
			ok
		  }

		}

		animate {
		  file = "images/superman.png"
		  x = 0
		  y = 0
		  framewidth = 60
		  scaled = true
		  height = 86
		  width = 60
		  nStep = 3
		  transparent = true
		  state = func oGame,oSelf {

			checkstarskeycol(oGame,oSelf)

			if not oGameState.playerwin
				oself {
				  file = "images/superman.png"
				  height = 86
				  width = 60
				  for t=1 to 8
					if checkwall2(oGame,oSelf,0,5,[2,1])
					  y += 5
					else
					  exit
					ok
				  next
				  if y > 500 y=500 ok
				}
			ok

		  }
		  keypress = func ogame,oself,nKey {
			if oGameState.gameresult = false

			  oself {
				if nkey = key_up  and checkwall(oGame,oSelf,0,-40)
				  oGameState.value -= 1
				  checkgameover(oGame)
				  file = "images/supermanup.png"
				  height = 123
				  dotransparent()
				  y -= 40
				  oGameState.down = 10
				  if y<=0 y=0 ok
				but nkey = key_down and checkwall(oGame,oSelf,0,40)
				  file = "images/supermandown.png"
				  dotransparent()
				  y += 40
				  if y>=500 y=500 ok
				but nKey = key_right and checkwall(oGame,oSelf,10,0)
				  file = "images/supermanright.png"
				  dotransparent()
				  x += 10
				  if x >= 440
					if oGame.aObjects[2].x > -4500
					  oGame.aObjects[2].x -= 50
					  callenemystate(oGame)
					else
					  if x <= 750
						if  checkwall(oGame,oSelf,10,0)
						  x += 10
						ok
					  else
						if  checkwall(oGame,oSelf,-10,0)
						  x -= 10
						ok
					  ok
					  return
					ok
					x=400
				  ok
				but nKey = key_left and checkwall(oGame,oSelf,-10,0)
				  file = "images/supermanleft.png"
				  dotransparent()
				  x -= 10
				  if x <= 0
					x += 10
					if oGame.aObjects[2].x != 0
					  oGame.aObjects[2].x += 50
					  callenemystate(oGame)
					  x += 50
					ok
				  ok
				but nkey = key_esc or nKey = GE_AC_BACK
				  ogame.shutdown()
				ok
			  }
			ok
		  }
		  mouse = func ogame,oself,nType,aMouseList {  
			if nType = GE_MOUSE_DOWN
			  oGameState.moveplayer = TRUE
			But nType = GE_MOUSE_UP
			  oGameState.moveplayer = FALSE
			ok
			if oGameState.moveplayer = TRUE
			  if aMouseList[GE_MOUSE_X] < oSelf.X  # 左
				cFunc = oself.keypress  
				call cFunc(oGame,oSelf,Key_left)
			  else
				cFunc = oself.keypress  
				call cFunc(oGame,oSelf,Key_right)
			  ok
			  if aMouseList[GE_MOUSE_Y] < oSelf.Y  # 上
				cFunc = oself.keypress  
				call cFunc(oGame,oSelf,Key_up)
			  else
				cFunc = oself.keypress  
				call cFunc(oGame,oSelf,Key_down)
			  ok
			ok        
		  }
		}

		addenemy(oGame,600)
		addenemy(oGame,900)
		addenemy(oGame,1550)
		addenemy(oGame,2350)
		addenemy(oGame,3350)
		addenemy(oGame,3500)
		addenemy(oGame,3670)
		addenemy(oGame,3840)

		text {
		  animate = false
		  point = 400
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Score : " + oGameState.score
		  x = 500  y=0
		  state = func oGame,oSelf {
			oSelf { text = "Score : " + oGameState.score }
		  }
		}

		text {
		  animate = false
		  point = 400
		  size = 30
		  file = "fonts/pirulen.ttf"
		  text = "Energy : " + oGameState.value
		  x = 10  y=0
		  state = func oGame,oSelf { oSelf { text = "Energy : " + oGameState.value } }
		}
	  }


	func inlist nValue,aList
	  for x in aList
		if x = nValue
		  return true
		ok
	  next
	  return false

	func checkwall oGame,oself,diffx,diffy
	  alist = [1,2,3]
	  return checkwall2(oGame,oself,diffx,diffy,aList)

	func checkwall2 oGame,oself,diffx,diffy,aList
	  xPos = oSelf.x + diffx
	  yPos = oSelf.y + diffy
	  nValue = oGame.aObjects[2].getvalue(xPos,yPos)
	  nValue = inlist(nValue,aList)
	  nValue = not nValue
	  if nValue = 0 return nValue ok

	  xPos = oSelf.x + diffx
	  yPos = oSelf.y + diffy + oSelf.height
	  nValue = oGame.aObjects[2].getvalue(xPos,yPos)
	  nValue = inlist(nValue,aList)
	  nValue = not nValue
	  if nValue = 0 return nValue ok

	  xPos = oSelf.x + diffx + oSelf.width
	  yPos = oSelf.y + diffy
	  nValue = oGame.aObjects[2].getvalue(xPos,yPos)
	  nValue = inlist(nValue,aList)
	  nValue = not nValue
	  if nValue = 0 return nValue ok

	  xPos = oSelf.x + diffx + oSelf.width
	  yPos = oSelf.y + diffy + oSelf.height
	  nValue = oGame.aObjects[2].getvalue(xPos,yPos)
	  nValue = inlist(nValue,aList)
	  nValue = not nValue
	  if nValue = 0 return nValue ok

	  return nValue

	func checkopenwall oGame
	  if oGameState.score = 900
		oGame.aObjects[2].aMap[3][10] = 3
		oGame.aObjects[2].aMap[4][10] = 0
		oGame.aObjects[2].aMap[5][10] = 0
		oGame.aObjects[2].aMap[6][10] = 0
		oGame.aObjects[2].aMap[7][10] = 0
		oGame.aObjects[2].aMap[8][10] = 0
	  but oGameState.score = 1800
		oGame.aObjects[2].aMap[3][18] = 3
		oGame.aObjects[2].aMap[4][18] = 0
		oGame.aObjects[2].aMap[5][18] = 0
		oGame.aObjects[2].aMap[6][18] = 0
		oGame.aObjects[2].aMap[7][18] = 0
		oGame.aObjects[2].aMap[8][18] = 0
	  but oGameState.score = 5500
		oGame.aObjects[2].aMap[1][44] = 0
		oGame.aObjects[2].aMap[2][44] = 0
		oGame.aObjects[2].aMap[3][44] = 2
	  ok


	func checkgameover ogame
	  if oGameState.gameresult  return ok
	  if oGameState.value <= 0
		oGameState.value = 0
		oGameState.gameresult = true
		oGame {
		  text {
			point = 400
			size = 30
			nStep = 9
			file = "fonts/pirulen.ttf"
			text = "Game Over !!!"
			x = 500  y=10
			state = func ogame,oself {
			  if oself.y >= 400
				ogame.shutdown = true
			  ok
			}
		  }
		}
		showfire(oGame,oGame.aObjects[oGameState.PlayerIndex].x+40,
			 oGame.aObjects[oGameState.PlayerIndex].y+40)
		oGame.aObjects[oGameState.PlayerIndex].enabled = false
		oGame.remove(oGameState.PlayerIndex)
	  ok


	func showfire oGame,nX,nY
	  oGame {
		animate {
		  file = "images/fire.png"
		  x = nX
		  y = nY
		  framewidth = 40
		  height = 42
		  nStep = 3
		  transparent = true
		  state = func oGame,oSelf {
			oSelf {
			  nStep--
			  if nStep = 0
				nStep = 3
				if frame < 13
				  frame++
				else
				  frame=1
				  oGame.remove(oself.nIndex)
				ok
			  ok
			}
		  }
		}
	  }

	func addenemy oGame,xPos
	  oGame {
		lbraceend = false
		sprite {
			type = ge_type_enemy
			file = "images/smenemy.png"
			transparent = true
			x = xPos y =10 width=100 height=100
			animate=true Scaled=true
			direction = GE_DIRECTION_NOMOVE
			temp = xPos
			state = func oGame,oSelf {
			  oself {
				x = oSelf.temp +  oGame.aObjects[2].x
				if y < 0 y = 0 ok
				if y > 100 y=100 ok
				if x > SCREEN_W or x < 0 return ok
			  }

			  if random(10) = 1
				if oGameState.gameresult return ok
				ogame {
				  sprite {
					type = ge_type_fire
					file  = "images/smrocket.png"
					scaled  = true
					transparent = true
					x = oself.x + 30
					y = oself.y + oself.height+ 30
					width = 30
					height = 30
					point = ogame.screen_h+30
					nstep = 30
					direction = ge_direction_incvertical
					xvalue =  oGame.aObjects[2].x
					temp = oself.x + 30 - xvalue
					state = func oGame,oSelf {
					  oself { x = oSelf.temp +  oGame.aObjects[2].x  }
					  x =  oGame.aObjects[oGameState.playerindex]
					  if oself.x >= x.x and oself.y >= x.y and
						 oself.x <= x.x + x.width and
						 oself.y <= x.y + x.height
						 if oGameState.value > 0
						   oGameState.value-=1000
						 ok
						 ogame.remove(oself.nindex)
						 checkgameover(oGame)
					  ok
					}
				  }
				}
			  ok
			}
		  }
	  }
	  ogame.lbraceend = true


	func checkstarskey oGame,oSelf,nValue,nRow,nCol
	  switch nValue
		on 4
		  oGame.aObjects[2].aMap[nRow][nCol] = 6
		  oGameState.Score += 100
		  checkopenwall(oGame)
		  oGame { Sound {
			once = true
			file = "sound/sfx_point.wav"
		  } }
		on 5
		  oGame.aObjects[2].aMap[nRow][nCol] = 0
		  oGameState.DoorKey = true
		  oGameState.Score += 500
		  checkopenwall(oGame)
		  oGame { Sound {
			once = true
			file = "sound/sfx_point.wav"
		  } }
	  off

	func checkstarskeycol oGame,oSelf
	  nValue = oGame.aObjects[2].getvalue(oSelf.x,oSelf.y)
	  nRow = oGame.aObjects[2].getrow(oSelf.x,oSelf.y)
	  nCol = oGame.aObjects[2].getcol(oSelf.x,oSelf.y)
	  checkstarskey(oGame,oSelf,nValue,nRow,nCol)

	  nValue = oGame.aObjects[2].getvalue(oSelf.x+oSelf.width,oSelf.y+oSelf.height)
	  nRow = oGame.aObjects[2].getrow(oSelf.x+oSelf.width,oSelf.y+oSelf.height)
	  nCol = oGame.aObjects[2].getcol(oSelf.x+oSelf.width,oSelf.y+oSelf.height)
	  checkstarskey(oGame,oSelf,nValue,nRow,nCol)

	  nValue = oGame.aObjects[2].getvalue(oSelf.x+oSelf.width,oSelf.y)
	  nRow = oGame.aObjects[2].getrow(oSelf.x+oSelf.width,oSelf.y)
	  nCol = oGame.aObjects[2].getcol(oSelf.x+oSelf.width,oSelf.y)
	  checkstarskey(oGame,oSelf,nValue,nRow,nCol)

	  nValue = oGame.aObjects[2].getvalue(oSelf.x,oSelf.y+oSelf.height)
	  nRow = oGame.aObjects[2].getrow(oSelf.x,oSelf.y+oSelf.height)
	  nCol = oGame.aObjects[2].getcol(oSelf.x,oSelf.y+oSelf.height)
	  checkstarskey(oGame,oSelf,nValue,nRow,nCol)

	func callenemystate oGame
	  for t in oGame.aObjects
		t {
		  if type = GE_TYPE_ENEMY
			call state(oGame,t)
		  ok
		}
	  next

	Class GameState

	  down = 3
	  gameresult = false
	  Score = 0
	  startplay=false
	  lastcol = 0
	  playerwin = false
	  DoorKey = false
	  playerindex = 4
	  value = 1000
	  moveplayer = false

スクリーンショット:

.. image:: superman.png
	:alt: Super Man 2016


