Ceibal Jam/Juegos: Difference between revisions
No edit summary |
|||
(35 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
<noinclude>{{GoogleTrans-es | en =show | bg =show | zh-CN =show | zh-TW =show | hr =show | cs =show | da =show | nl =show | fi =show | fr =show | de =show | el =show | hi =show | it =show | ja =show | ko =show | no =show | pl =show | pt =show | ro =show | ru =show | sv =show}}</noinclude> |
<noinclude>{{GoogleTrans-es | en =show | bg =show | zh-CN =show | zh-TW =show | hr =show | cs =show | da =show | nl =show | fi =show | fr =show | de =show | el =show | hi =show | it =show | ja =show | ko =show | no =show | pl =show | pt =show | ro =show | ru =show | sv =show}}</noinclude> |
||
[[Image:Caibal-jam-rollogo.png]] |
|||
Como anda |
|||
= Ceibal Rol = |
|||
Ceibal rol es un proyecto comunitario de Ceibal-Jam en el que todos podemos participar, creando, diseñando, programando... |
|||
El objetivo es lograr un potente motor de alto nivel para facilitar a maestros y docentes a crear juegos a través de esta plataforma. |
|||
== Requerimientos == |
|||
* Python 2.5 |
|||
** PyGame |
|||
* Perspectiva isometrica/ortogonal en 2D. |
|||
* Mantener documentación en esta wiki. |
|||
* Licenciar a través de GPL v2 o equivalente. http://es.wikipedia.org/wiki/GNU |
|||
== Análisis y Diseño == |
|||
=== Introducción al análisis === |
|||
A pesar de que las técnicas en que se basara el diseño son muy antiguas o mejor dicho clásicas, es justo ahí de donde radica la belleza de utilizarlas, son muy probadas y demostraron ser casos de éxito en un pasado y lo serán ahora. |
|||
El código ejemplo propuesto aquí sera inicialmente meta-código, esperamos a futuro implementar código en python |
El código ejemplo propuesto aquí sera inicialmente meta-código, esperamos a futuro implementar código en python |
||
Creemos que es la forma de ejemplificar lo mas posible su claridad para toda la gama de voluntarios sean idóneos a la programación informática o no. |
Creemos que es la forma de ejemplificar lo mas posible su claridad para toda la gama de voluntarios sean idóneos a la programación informática o no. |
||
=== Abstracciones === |
=== Abstracciones === |
||
Partiendo desde el requerimiento de desarrollar un motor capaz de desplegar desde una perspectiva isometrica/ortogonal, nuestro argumento es justificar el uso de coordenadas enteras y limitar los cálculos flotantes(float, etc...) por que estos |
Partiendo desde el requerimiento de desarrollar un motor capaz de desplegar desde una perspectiva isometrica/ortogonal con python en una XO, nuestro argumento es justificar el uso de coordenadas enteras y limitar los cálculos flotantes(float, etc...) por que estos agregarían una carga extra a los procesos y demoraría los cálculos mas importantes del juego en si como serian la interacción continua, eventos y un flujo dinámico de información ínter-comunicada entre diferentes XO, el factor principal por ahora sera actualizar la información de el entorno <universo> y sus relaciones con otras entidades dentro del juego. |
||
=== Mapas |
=== Universo Mapas, Niveles y sus Entidades === |
||
Crear las fronteras de adonde puede ir cada jugador es primordial para llegar a algo. Necesitamos un limite para concentrarnos en su implementación. |
Crear las fronteras de adonde puede ir cada jugador es primordial para llegar a algo. Necesitamos un limite para concentrarnos en su implementación. |
||
La representación de nuestro universo se limitara a un vector y su representación en un array |
La representación de nuestro universo se limitara a un vector y su representación en un array bidimensional. |
||
Las ventajas en velocidad y trato de información sin necesidad de grandes complejidades se denotan por su forma. |
Las ventajas en velocidad y trato de información sin necesidad de grandes complejidades se denotan por su forma. |
||
* Se ve muy bien y además podemos compactar mucha información. |
|||
* Son rápidos si son utilizados con datos nativos. |
|||
* Nos permite reutilizar herramientas echas para tales fines (editar mapas de caracteres o archivo como niveles de juego) o directamente desarrollarlas nosotros. |
|||
map[x][y] |
map[x][y] |
||
El tipo de información de que hay en ese lugar del mapa estará contenida en un entero sin signo (unsigned int), cada bloque (coordenada) de información vector |
El tipo de información de que hay en ese lugar del mapa estará contenida en un entero sin signo (unsigned int), cada bloque (coordenada) de información vector posición(x, y) tendrá un numero y este representara su imagen. |
||
;pseudo-código |
|||
clase map |
|||
clase Map |
|||
x : entero (sin coma, sin signo) |
x : entero (sin coma, sin signo) |
||
y : entero (sin coma, sin signo) |
y : entero (sin coma, sin signo) |
||
getvalue : (enero) --> este entero representa que dato existe en el vector. |
|||
;Python Code |
|||
# universe.py |
|||
import pygame |
|||
class Map: |
|||
def __init__(self, path): |
|||
self.level = self.loadlevel(path) |
|||
def loadlevel(self,path): |
|||
myfile = file(path, 'rt') |
|||
data = myfile.readlines() |
|||
myfile.close() |
|||
return data |
|||
Supongamos entonces que deseamos crear un mapa / nivel del juego del tamaño 3 x 3 bloques, entonces tendríamos 9 bloques donde cada uno representa un lugar posible o no donde nuestro jugador podría estar. |
Supongamos entonces que deseamos crear un mapa / nivel del juego del tamaño 3 x 3 bloques, entonces tendríamos 9 bloques donde cada uno representa un lugar posible o no donde nuestro jugador podría estar. |
||
Representaremos este mapa con un archivo donde le agregaremos la extensión '*.level'. |
|||
;map1.level |
|||
000 |
|||
010 |
|||
000 |
|||
En definitiva seria un archivo de texto plano en esta fase inicial de análisis pero con esa excepción en vez de la extensión 'txt' usaremos 'level' |
|||
Si lo asignamos como parámetro al constructor de <Map('map1.level')> podríamos capturar cada dato de el archivo accediendo directamente a los valores de retorno. |
|||
map[3][3] |
|||
[0][1][2] |
|||
[0] 0 0 0 |
|||
[1] 0 1 0 |
|||
[2] 0 0 0 |
|||
1 = libre |
|||
0 = obstruido |
|||
map.level[0][0] = 0 |
|||
map.level[1][1] = 1 |
|||
map.level[2][2] = 0 |
|||
Donde cada numero en cada casillero representara de una forma mas amplia el tipo de objeto que estará situado ahí. |
Donde cada numero en cada casillero representara de una forma mas amplia el tipo de objeto que estará situado ahí. |
||
Concentrándonos ahora en un programa que despliegue nuestro mapa desarrollaremos el siguiente código que utiliza nuestra clase <Map()>. |
|||
;test_universe.py |
|||
from universe import Map # importamos desde el modulo universe la clase <Map> |
|||
m = Map('map1.level') # inicializamos una instancia y le asignamos el archivo map1.level |
|||
for i in range(len(m.level)): |
|||
print |
|||
for j in range(len(m.level[0])-1): |
|||
print m.level[i][j], |
|||
print m.level |
|||
;shell |
|||
> python test_universe.py |
|||
0 0 0 |
|||
0 1 0 |
|||
0 0 0 ['000\n', '010\n', '000'] |
|||
>_ |
|||
Extendamos un poco nuestra tabla de posibles valores para nuestro mapa/nivel con el limite 1024. |
Extendamos un poco nuestra tabla de posibles valores para nuestro mapa/nivel con el limite 1024. |
||
Line 70: | Line 98: | ||
El motivo de el gran rango de posibles tipos de objetos en cada valor se debe a que fácilmente podríamos crear a futuro una extensión en caracteres o códigos donde el rango se aumentaría potencialmente facilitando mas recursos. |
El motivo de el gran rango de posibles tipos de objetos en cada valor se debe a que fácilmente podríamos crear a futuro una extensión en caracteres o códigos donde el rango se aumentaría potencialmente facilitando mas recursos. |
||
Además también la sincronización del juego tendrá en cuenta estos valores para crear una simulación fluida, el usuario captara como si todo sucediera al mismo instante aunque no sera así en realidad. |
|||
Por ahora nos limitaremos a utilizar 1024 atajos a diferentes representaciones en nuestro juego. |
Por ahora nos limitaremos a utilizar 1024 atajos a diferentes representaciones en nuestro juego. |
||
Line 75: | Line 105: | ||
Ahora concentrémonos en el orden de cada objeto, donde 0 es vació del '1' al '200' inclusive tendremos obstáculos, entonces en estos lugares no se podrá ni mover ni estar nuestro personaje, es ahí donde nos encontramos con una propiedad para cada rango de valores. |
Ahora concentrémonos en el orden de cada objeto, donde 0 es vació del '1' al '200' inclusive tendremos obstáculos, entonces en estos lugares no se podrá ni mover ni estar nuestro personaje, es ahí donde nos encontramos con una propiedad para cada rango de valores. |
||
"caminable" o "no caminable"... suena un poco extraño pero utilizaremos un valor boolean (verdadero / falso) y le pondremos un nombre en ingles porque queda mas lindo, walkable. |
"caminable" o "no caminable" mejor dicho "caminable = si" o "caminable = no"... suena un poco extraño pero utilizaremos un valor boolean (verdadero / falso) y le pondremos un nombre en ingles porque queda mas lindo, walkable = true / false. |
||
Como es notable cada valor necesita un campo externo donde definirse, por ello |
Como es notable cada valor necesita un campo externo donde definirse, por ello a partir de ahora nos referiremos estos elementos como sprite, un sprite es simplemente un dibujo de algo, un personaje un objeto u cualquier cosa, en este caso serán objetos donde el personaje (otro sprite) no pueda moverse, entonces definamos estos objetos gráficos(sprite). |
||
clase floor sub-clase sprite |
clase floor sub-clase sprite |
||
+ id : entero # representa el valor del bloque que representa. |
|||
+ walklable : (true or false) |
+ walklable : (true or false) |
||
Ahora ya establecida una propiedad (walkable) podremos concentrarnos en el jugador que las recorre. |
|||
donde getpos devuelve un valor de vector posición y mover(xy) aumenta o disminuye su valor de referencia en el mapa. |
|||
;pseudo-codigo |
|||
clase player() sub-clase sprite |
|||
x |
|||
y |
|||
+ getpos(self) : (x,y) |
|||
- move((+/-x),(+/-y)) : null |
|||
;python code |
|||
import pygame |
|||
class player: |
|||
def __init__(): |
|||
self.pos = (px,py) |
|||
Como denotamos no podemos sobrescribir valores dentro de nuestro vector bi-dimensional mapa, por motivos claros, estaríamos borrando información importante de su estructura, entonces crearemos la capa de objetos-entidades y objetos-items para su posterior implementación. |
|||
sera entonces una capa superior imaginaria a la del mapa, por ahora sera una 'p' para facilitar su representación. |
|||
aunque p = alt+80 no tomaremos como referencia su valor en el proyecto. |
|||
0 = null |
|||
1 = floor |
|||
@ = player |
|||
0123456789 0123456789 |
|||
map = 0 0000000000 player = 0 |
|||
1 0001111110 1 |
|||
2 0111111110 2 |
|||
3 0111111110 3 p(5,6) |
|||
4 0000111110 4 |
|||
5 0000000000 5 |
|||
entonces si hacemos una llamada a la función de la clase player getpos(self) retornaría un valor igual a (renglón 3, columna 5) |
|||
... |
|||
Ahora crearemos un constructor de mapas en la clase map, se llamara 'mapfactory' y construye un mapa... |
|||
clase map |
|||
x : entero (sin coma, sin signo) |
|||
y : entero (sin coma, sin signo) |
|||
+ mapfactory() : map[][] # constructor de mapas |
|||
+ getvalue(map[x][y]) : entero |
|||
=== Diseño general del motor del juego === |
|||
Juego GTA |
|||
== Desarrollo == |
== Desarrollo == |
||
=== Programación Orientada a objetos en Python === |
|||
==== Herencia ==== |
|||
==== Polimorfismo ==== |
|||
==== Sobrecarga de funciones ==== |
|||
=== Hello PyGame === |
|||
<strong>hellopygame.py</strong><br> |
|||
import pygame |
|||
from pygame.locals import * |
|||
from sys import exit |
|||
map_img = 'map.png'pablo |
|||
[]]seba |
|||
player_img = 'player.png' |
|||
pygame.init() |
|||
screen = pygame.display.set_mode((640, 480)) |
|||
pygame.display.set_caption("Hello, World!") |
|||
map = pygame.image.load( map_img).convert_alpha() |
|||
player = pygame.image.load(player_img).convert_alpha() |
|||
while True: |
|||
for event in pygame.event.get(): |
|||
if event.type == QUIT: |
|||
exit() |
|||
screen.blit(map, (0,0)) |
|||
x, y = pygame.mouse.get_pos() |
|||
x-= player.get_width() / 2 |
|||
y-= player.get_height() / 2 |
|||
screen.blit(player, (x, y)) |
|||
pygame.display.update() |
|||
== Texto de titular == |
|||
=== Surface === |
|||
lipikhc k8¡[imwzasegj7[ |
|||
¡'lyhdsctjpñ0''9ouyhweqwdqrui0¡[[+ñmdqa |
|||
=== Sprites === |
|||
==== Animación ==== |
|||
=== Modulos del proyecto === |
|||
lluvia de ideas por ahora... |
|||
<strong>CROLCore: Motor principal del juego</strong> |
|||
* GameScene |
|||
* GameObjects |
|||
<strong>CROLUniverse: Clases universe</strong> |
|||
* floors |
|||
* items |
|||
* |
|||
<strong>CROLEntity: Clases entity</strong> |
|||
* Player |
|||
* NPC |
|||
<strong>CROLGui: Interfaces de usuario generales (Interface inicial)</strong> |
|||
* Menu |
|||
* Labels |
|||
* Buttons |
|||
* etc |
|||
<strong>CROLEnviroment: Eventos Fisica y sonido</strong> |
|||
* Mouse |
|||
* Keys |
|||
* Audio |
|||
==== Recursos ==== |
|||
<strong> The spriters resource </strong> <br> |
|||
http://www.spriters-resource.com/ |
|||
<strong> GSA (Game Sprite Archives) </strong> <br> |
|||
http://www.fattyboy.com/ |
|||
<strong> Reiner`s Tilesets </strong> <br> |
|||
http://reinerstileset.4players.de/englisch.html |
|||
=== Herramientas === |
=== Herramientas === |
||
<strong> Tiled a generic tile map editor </strong> <br> |
|||
http://mapeditor.org/ |
http://mapeditor.org/ |
||
== Pruebas == |
== Pruebas == |
||
=== Emulación del Entorno === |
|||
*[[Sugar on Ubuntu Linux]] |
|||
=== Desarrollando un "Activity" para las pruebas en las XO === |
|||
*[[Creating an Activity]] |
|||
*[[Activity tutorial]] |
|||
*[[Activity bundles]] |
|||
*[[Sugar Activity Builder]] |
|||
*[[Hacking Sugar]] |
Latest revision as of 14:32, 1 June 2011
GoogleTrans-es -English -български -中文(中国大陆) -中文(臺灣) -hrvatski -čeština -dansk -Nederlands -suomi -français -Deutsch -Ελληνικά -हिन्दी -italiano -日本語 -한국어 -norsk -polski -português -română -русский -svenska
Como anda
El código ejemplo propuesto aquí sera inicialmente meta-código, esperamos a futuro implementar código en python
Creemos que es la forma de ejemplificar lo mas posible su claridad para toda la gama de voluntarios sean idóneos a la programación informática o no.
Abstracciones
Partiendo desde el requerimiento de desarrollar un motor capaz de desplegar desde una perspectiva isometrica/ortogonal con python en una XO, nuestro argumento es justificar el uso de coordenadas enteras y limitar los cálculos flotantes(float, etc...) por que estos agregarían una carga extra a los procesos y demoraría los cálculos mas importantes del juego en si como serian la interacción continua, eventos y un flujo dinámico de información ínter-comunicada entre diferentes XO, el factor principal por ahora sera actualizar la información de el entorno <universo> y sus relaciones con otras entidades dentro del juego.
Universo Mapas, Niveles y sus Entidades
Crear las fronteras de adonde puede ir cada jugador es primordial para llegar a algo. Necesitamos un limite para concentrarnos en su implementación.
La representación de nuestro universo se limitara a un vector y su representación en un array bidimensional. Las ventajas en velocidad y trato de información sin necesidad de grandes complejidades se denotan por su forma.
- Se ve muy bien y además podemos compactar mucha información.
- Son rápidos si son utilizados con datos nativos.
- Nos permite reutilizar herramientas echas para tales fines (editar mapas de caracteres o archivo como niveles de juego) o directamente desarrollarlas nosotros.
map[x][y]
El tipo de información de que hay en ese lugar del mapa estará contenida en un entero sin signo (unsigned int), cada bloque (coordenada) de información vector posición(x, y) tendrá un numero y este representara su imagen.
- pseudo-código
clase Map x : entero (sin coma, sin signo) y : entero (sin coma, sin signo)
- Python Code
# universe.py import pygame class Map: def __init__(self, path): self.level = self.loadlevel(path) def loadlevel(self,path): myfile = file(path, 'rt') data = myfile.readlines() myfile.close() return data
Supongamos entonces que deseamos crear un mapa / nivel del juego del tamaño 3 x 3 bloques, entonces tendríamos 9 bloques donde cada uno representa un lugar posible o no donde nuestro jugador podría estar.
Representaremos este mapa con un archivo donde le agregaremos la extensión '*.level'.
- map1.level
000 010 000
En definitiva seria un archivo de texto plano en esta fase inicial de análisis pero con esa excepción en vez de la extensión 'txt' usaremos 'level'
Si lo asignamos como parámetro al constructor de <Map('map1.level')> podríamos capturar cada dato de el archivo accediendo directamente a los valores de retorno.
[0][1][2] [0] 0 0 0 [1] 0 1 0 [2] 0 0 0 1 = libre 0 = obstruido
map.level[0][0] = 0 map.level[1][1] = 1 map.level[2][2] = 0
Donde cada numero en cada casillero representara de una forma mas amplia el tipo de objeto que estará situado ahí. Concentrándonos ahora en un programa que despliegue nuestro mapa desarrollaremos el siguiente código que utiliza nuestra clase <Map()>.
- test_universe.py
from universe import Map # importamos desde el modulo universe la clase <Map> m = Map('map1.level') # inicializamos una instancia y le asignamos el archivo map1.level for i in range(len(m.level)): print for j in range(len(m.level[0])-1): print m.level[i][j], print m.level
- shell
> python test_universe.py 0 0 0 0 1 0 0 0 0 ['000\n', '010\n', '000'] >_
Extendamos un poco nuestra tabla de posibles valores para nuestro mapa/nivel con el limite 1024.
desde hasta descripción --------------------------------------------------- 0 vació 1 <= 200 obstáculos 201 <= 400 pisos 401 <= 600 players/jugadores. 601 <= 800 objetos/items. 801 <= 1024 eventos ---------------------------------------------------
El motivo de el gran rango de posibles tipos de objetos en cada valor se debe a que fácilmente podríamos crear a futuro una extensión en caracteres o códigos donde el rango se aumentaría potencialmente facilitando mas recursos.
Además también la sincronización del juego tendrá en cuenta estos valores para crear una simulación fluida, el usuario captara como si todo sucediera al mismo instante aunque no sera así en realidad.
Por ahora nos limitaremos a utilizar 1024 atajos a diferentes representaciones en nuestro juego.
Ahora concentrémonos en el orden de cada objeto, donde 0 es vació del '1' al '200' inclusive tendremos obstáculos, entonces en estos lugares no se podrá ni mover ni estar nuestro personaje, es ahí donde nos encontramos con una propiedad para cada rango de valores.
"caminable" o "no caminable" mejor dicho "caminable = si" o "caminable = no"... suena un poco extraño pero utilizaremos un valor boolean (verdadero / falso) y le pondremos un nombre en ingles porque queda mas lindo, walkable = true / false.
Como es notable cada valor necesita un campo externo donde definirse, por ello a partir de ahora nos referiremos estos elementos como sprite, un sprite es simplemente un dibujo de algo, un personaje un objeto u cualquier cosa, en este caso serán objetos donde el personaje (otro sprite) no pueda moverse, entonces definamos estos objetos gráficos(sprite).
clase floor sub-clase sprite + id : entero # representa el valor del bloque que representa. + walklable : (true or false)
Ahora ya establecida una propiedad (walkable) podremos concentrarnos en el jugador que las recorre. donde getpos devuelve un valor de vector posición y mover(xy) aumenta o disminuye su valor de referencia en el mapa.
- pseudo-codigo
clase player() sub-clase sprite x y + getpos(self) : (x,y) - move((+/-x),(+/-y)) : null
- python code
import pygame class player: def __init__(): self.pos = (px,py)
Como denotamos no podemos sobrescribir valores dentro de nuestro vector bi-dimensional mapa, por motivos claros, estaríamos borrando información importante de su estructura, entonces crearemos la capa de objetos-entidades y objetos-items para su posterior implementación.
sera entonces una capa superior imaginaria a la del mapa, por ahora sera una 'p' para facilitar su representación. aunque p = alt+80 no tomaremos como referencia su valor en el proyecto.
0 = null 1 = floor @ = player 0123456789 0123456789 map = 0 0000000000 player = 0 1 0001111110 1 2 0111111110 2 3 0111111110 3 p(5,6) 4 0000111110 4 5 0000000000 5
entonces si hacemos una llamada a la función de la clase player getpos(self) retornaría un valor igual a (renglón 3, columna 5)
...
Ahora crearemos un constructor de mapas en la clase map, se llamara 'mapfactory' y construye un mapa...
clase map x : entero (sin coma, sin signo) y : entero (sin coma, sin signo)
+ mapfactory() : map[][] # constructor de mapas + getvalue(map[x][y]) : entero
Diseño general del motor del juego
Juego GTA
Desarrollo
Programación Orientada a objetos en Python
Herencia
Polimorfismo
Sobrecarga de funciones
Hello PyGame
hellopygame.py
import pygame from pygame.locals import * from sys import exit map_img = 'map.png'pablo
[]]seba
player_img = 'player.png' pygame.init() screen = pygame.display.set_mode((640, 480)) pygame.display.set_caption("Hello, World!") map = pygame.image.load( map_img).convert_alpha() player = pygame.image.load(player_img).convert_alpha() while True: for event in pygame.event.get(): if event.type == QUIT: exit() screen.blit(map, (0,0)) x, y = pygame.mouse.get_pos() x-= player.get_width() / 2 y-= player.get_height() / 2 screen.blit(player, (x, y)) pygame.display.update()
Texto de titular
Surface
lipikhc k8¡[imwzasegj7[ ¡'lyhdsctjpñ09ouyhweqwdqrui0¡[[+ñmdqa
Sprites
Animación
Modulos del proyecto
lluvia de ideas por ahora...
CROLCore: Motor principal del juego
- GameScene
- GameObjects
CROLUniverse: Clases universe
- floors
- items
CROLEntity: Clases entity
- Player
- NPC
CROLGui: Interfaces de usuario generales (Interface inicial)
- Menu
- Labels
- Buttons
- etc
CROLEnviroment: Eventos Fisica y sonido
- Mouse
- Keys
- Audio
Recursos
The spriters resource
http://www.spriters-resource.com/
GSA (Game Sprite Archives)
http://www.fattyboy.com/
Reiner`s Tilesets
http://reinerstileset.4players.de/englisch.html
Herramientas
Tiled a generic tile map editor
http://mapeditor.org/