├── pyxel ├── pyxelrogue │ ├── src │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ └── equippable.py │ │ ├── requirements.txt │ │ ├── menu_background.png │ │ ├── equipment_types.py │ │ ├── render_order.py │ │ ├── exceptions.py │ │ ├── render_functions.py │ │ ├── color.py │ │ └── tile_types.py │ ├── part10 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ └── fighter.py │ │ ├── menu_background.png │ │ ├── render_order.py │ │ ├── exceptions.py │ │ ├── render_functions.py │ │ ├── color.py │ │ ├── tile_types.py │ │ ├── entity_factories.py │ │ └── engine.py │ ├── part11 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ └── fighter.py │ │ ├── menu_background.png │ │ ├── render_order.py │ │ ├── exceptions.py │ │ ├── entity_factories.py │ │ ├── render_functions.py │ │ ├── color.py │ │ └── tile_types.py │ ├── part12 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ └── fighter.py │ │ ├── menu_background.png │ │ ├── render_order.py │ │ ├── exceptions.py │ │ ├── entity_factories.py │ │ ├── render_functions.py │ │ ├── color.py │ │ └── tile_types.py │ ├── part13 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ └── equippable.py │ │ ├── menu_background.png │ │ ├── equipment_types.py │ │ ├── render_order.py │ │ ├── exceptions.py │ │ ├── render_functions.py │ │ ├── color.py │ │ └── tile_types.py │ ├── part6 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ └── fighter.py │ │ ├── render_order.py │ │ ├── entity_factories.py │ │ ├── main.py │ │ ├── tile_types.py │ │ └── engine.py │ ├── part7 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ └── fighter.py │ │ ├── render_order.py │ │ ├── color.py │ │ ├── entity_factories.py │ │ ├── tile_types.py │ │ ├── render_functions.py │ │ ├── main.py │ │ └── engine.py │ ├── part8 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ ├── consumable.py │ │ │ └── fighter.py │ │ ├── exceptions.py │ │ ├── render_order.py │ │ ├── color.py │ │ ├── entity_factories.py │ │ ├── render_functions.py │ │ ├── tile_types.py │ │ ├── engine.py │ │ └── main.py │ ├── part9 │ │ ├── components │ │ │ ├── __init__.py │ │ │ ├── base_component.py │ │ │ ├── inventory.py │ │ │ └── fighter.py │ │ ├── exceptions.py │ │ ├── render_order.py │ │ ├── color.py │ │ ├── render_functions.py │ │ ├── tile_types.py │ │ ├── entity_factories.py │ │ ├── engine.py │ │ └── main.py │ ├── screenshots │ │ ├── pyxelrogue01.gif │ │ ├── pyxelrogue02.gif │ │ ├── pyxelrogue03.gif │ │ ├── pyxelrogue04.gif │ │ ├── pyxelrogue05.gif │ │ ├── pyxelrogue06.gif │ │ ├── pyxelrogue07.gif │ │ ├── pyxelrogue08.gif │ │ ├── pyxelrogue09.gif │ │ ├── pyxelrogue10.gif │ │ ├── pyxelrogue11.gif │ │ ├── pyxelrogue12.gif │ │ └── pyxelrogue13.gif │ ├── part1 │ │ ├── actions.py │ │ ├── input_handlers.py │ │ └── main.py │ ├── part2 │ │ ├── actions.py │ │ ├── entity.py │ │ ├── game_map.py │ │ ├── input_handlers.py │ │ ├── main.py │ │ ├── engine.py │ │ └── tile_types.py │ ├── part3 │ │ ├── actions.py │ │ ├── entity.py │ │ ├── game_map.py │ │ ├── input_handlers.py │ │ ├── engine.py │ │ ├── tile_types.py │ │ └── main.py │ ├── part5 │ │ ├── entity_factories.py │ │ ├── input_handlers.py │ │ ├── entity.py │ │ ├── main.py │ │ ├── tile_types.py │ │ ├── engine.py │ │ └── game_map.py │ └── part4 │ │ ├── entity.py │ │ ├── input_handlers.py │ │ ├── actions.py │ │ ├── main.py │ │ ├── game_map.py │ │ ├── tile_types.py │ │ └── engine.py ├── aclm │ ├── aclm.pyxapp │ ├── screenshots │ │ ├── aclm01.gif │ │ ├── aclm02.gif │ │ └── aclm03.gif │ └── README.md ├── nixie │ ├── Nixie.pyxapp │ ├── Nixie.pyxres │ ├── screenshots │ │ └── Nixie01.gif │ ├── README.md │ └── Nixie.py ├── outrun │ ├── outrun.pyxapp │ ├── screenshots │ │ ├── outrun01.gif │ │ └── outrun02.gif │ └── README.md ├── frogger │ ├── frogger.pyxapp │ ├── screenshots │ │ ├── frogger01.gif │ │ └── frogger02.gif │ └── README.md ├── mahjong │ ├── mahjong.pyxapp │ ├── mahjong.pyxres │ ├── screenshots │ │ └── mahjong01.png │ ├── README.md │ └── mahjong.py ├── pinball │ ├── Pinball.pyxapp │ ├── Pinball.pyxres │ ├── screenshots │ │ ├── Pinball01.gif │ │ ├── Pinball02.gif │ │ ├── Pinball03.gif │ │ └── Pinball04.gif │ └── README.md ├── galaxian │ ├── galaxian.pyxapp │ ├── galaxian.pyxres │ ├── screenshots │ │ └── galaxian01.gif │ ├── README.md │ └── galaxian.py ├── hanafuda │ ├── hanafuda.pyxapp │ ├── hanafuda.pyxres │ ├── screenshots │ │ └── hanafuda01.png │ ├── README.md │ └── hanafuda.py ├── sombrero │ ├── sombrero.pyxapp │ ├── screenshots │ │ ├── sombrero01.png │ │ ├── sombrero02.png │ │ └── sombrero03.png │ ├── README.md │ └── sombrero.py ├── sheep │ ├── screenshots │ │ └── sheep01.gif │ ├── Grass.py │ ├── README.md │ ├── Sheep.py │ └── SheepAndGrass.py ├── tennis │ ├── screenshots │ │ └── tennis01.gif │ ├── README.md │ ├── Ball.py │ └── App.py ├── autorace │ ├── screenshots │ │ └── autorace01.gif │ ├── README.md │ ├── basic.py │ └── autorace.py ├── asteroids │ ├── screenshots │ │ └── asteroids01.gif │ ├── README.md │ ├── Bullet.py │ ├── Ship.py │ ├── Vec.py │ └── Rock.py ├── pyxel2d │ └── README.md ├── pyxelchip8 │ └── README.md └── doc │ ├── 230409_PyxelNote.md │ └── 220217_PyxelNote.md ├── hsp ├── ball │ ├── ball.hsp │ └── screenshots │ │ └── hsp01.png ├── mandel │ ├── mandel.hsp │ ├── mandel2.hsp │ └── screenshots │ │ ├── hsp02.png │ │ └── hsp03.png └── doc │ └── 200724_HspNote.md ├── haskell └── asteroids │ ├── Asteroids.hs │ ├── screenshots │ ├── asteroids00.png │ ├── asteroids01.png │ └── asteroids02.png │ ├── README.md │ └── LICENSE └── research ├── 99_00_NoteOnGames.md ├── 02_00_VideoGameHistory.md ├── 99_01_NoteOnGames2017.md ├── 02_07_HistoryOfAthena.md ├── 99_03_NoteOnGames2019.md ├── 01_03_AsteroidsNote.md ├── 03_00_VideoGameCollecting.md └── 01_02_PinballNote.md /pyxel/pyxelrogue/src/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/components/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /hsp/ball/ball.hsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/hsp/ball/ball.hsp -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/requirements.txt: -------------------------------------------------------------------------------- 1 | tcod>=11.13 2 | numpy>=1.18 3 | pyxel>=1.9.18 4 | -------------------------------------------------------------------------------- /hsp/mandel/mandel.hsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/hsp/mandel/mandel.hsp -------------------------------------------------------------------------------- /hsp/mandel/mandel2.hsp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/hsp/mandel/mandel2.hsp -------------------------------------------------------------------------------- /pyxel/aclm/aclm.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/aclm/aclm.pyxapp -------------------------------------------------------------------------------- /pyxel/nixie/Nixie.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/nixie/Nixie.pyxapp -------------------------------------------------------------------------------- /pyxel/nixie/Nixie.pyxres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/nixie/Nixie.pyxres -------------------------------------------------------------------------------- /pyxel/outrun/outrun.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/outrun/outrun.pyxapp -------------------------------------------------------------------------------- /pyxel/frogger/frogger.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/frogger/frogger.pyxapp -------------------------------------------------------------------------------- /pyxel/mahjong/mahjong.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/mahjong/mahjong.pyxapp -------------------------------------------------------------------------------- /pyxel/mahjong/mahjong.pyxres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/mahjong/mahjong.pyxres -------------------------------------------------------------------------------- /pyxel/pinball/Pinball.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pinball/Pinball.pyxapp -------------------------------------------------------------------------------- /pyxel/pinball/Pinball.pyxres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pinball/Pinball.pyxres -------------------------------------------------------------------------------- /haskell/asteroids/Asteroids.hs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/haskell/asteroids/Asteroids.hs -------------------------------------------------------------------------------- /hsp/ball/screenshots/hsp01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/hsp/ball/screenshots/hsp01.png -------------------------------------------------------------------------------- /hsp/mandel/screenshots/hsp02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/hsp/mandel/screenshots/hsp02.png -------------------------------------------------------------------------------- /hsp/mandel/screenshots/hsp03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/hsp/mandel/screenshots/hsp03.png -------------------------------------------------------------------------------- /pyxel/galaxian/galaxian.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/galaxian/galaxian.pyxapp -------------------------------------------------------------------------------- /pyxel/galaxian/galaxian.pyxres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/galaxian/galaxian.pyxres -------------------------------------------------------------------------------- /pyxel/hanafuda/hanafuda.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/hanafuda/hanafuda.pyxapp -------------------------------------------------------------------------------- /pyxel/hanafuda/hanafuda.pyxres: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/hanafuda/hanafuda.pyxres -------------------------------------------------------------------------------- /pyxel/sombrero/sombrero.pyxapp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/sombrero/sombrero.pyxapp -------------------------------------------------------------------------------- /pyxel/aclm/screenshots/aclm01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/aclm/screenshots/aclm01.gif -------------------------------------------------------------------------------- /pyxel/aclm/screenshots/aclm02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/aclm/screenshots/aclm02.gif -------------------------------------------------------------------------------- /pyxel/aclm/screenshots/aclm03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/aclm/screenshots/aclm03.gif -------------------------------------------------------------------------------- /pyxel/nixie/screenshots/Nixie01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/nixie/screenshots/Nixie01.gif -------------------------------------------------------------------------------- /pyxel/outrun/screenshots/outrun01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/outrun/screenshots/outrun01.gif -------------------------------------------------------------------------------- /pyxel/outrun/screenshots/outrun02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/outrun/screenshots/outrun02.gif -------------------------------------------------------------------------------- /pyxel/sheep/screenshots/sheep01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/sheep/screenshots/sheep01.gif -------------------------------------------------------------------------------- /pyxel/tennis/screenshots/tennis01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/tennis/screenshots/tennis01.gif -------------------------------------------------------------------------------- /pyxel/frogger/screenshots/frogger01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/frogger/screenshots/frogger01.gif -------------------------------------------------------------------------------- /pyxel/frogger/screenshots/frogger02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/frogger/screenshots/frogger02.gif -------------------------------------------------------------------------------- /pyxel/mahjong/screenshots/mahjong01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/mahjong/screenshots/mahjong01.png -------------------------------------------------------------------------------- /pyxel/pinball/screenshots/Pinball01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pinball/screenshots/Pinball01.gif -------------------------------------------------------------------------------- /pyxel/pinball/screenshots/Pinball02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pinball/screenshots/Pinball02.gif -------------------------------------------------------------------------------- /pyxel/pinball/screenshots/Pinball03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pinball/screenshots/Pinball03.gif -------------------------------------------------------------------------------- /pyxel/pinball/screenshots/Pinball04.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pinball/screenshots/Pinball04.gif -------------------------------------------------------------------------------- /pyxel/autorace/screenshots/autorace01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/autorace/screenshots/autorace01.gif -------------------------------------------------------------------------------- /pyxel/galaxian/screenshots/galaxian01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/galaxian/screenshots/galaxian01.gif -------------------------------------------------------------------------------- /pyxel/hanafuda/screenshots/hanafuda01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/hanafuda/screenshots/hanafuda01.png -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/menu_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/src/menu_background.png -------------------------------------------------------------------------------- /pyxel/sombrero/screenshots/sombrero01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/sombrero/screenshots/sombrero01.png -------------------------------------------------------------------------------- /pyxel/sombrero/screenshots/sombrero02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/sombrero/screenshots/sombrero02.png -------------------------------------------------------------------------------- /pyxel/sombrero/screenshots/sombrero03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/sombrero/screenshots/sombrero03.png -------------------------------------------------------------------------------- /pyxel/asteroids/screenshots/asteroids01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/asteroids/screenshots/asteroids01.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/menu_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/part10/menu_background.png -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/menu_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/part11/menu_background.png -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/menu_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/part12/menu_background.png -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/menu_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/part13/menu_background.png -------------------------------------------------------------------------------- /haskell/asteroids/screenshots/asteroids00.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/haskell/asteroids/screenshots/asteroids00.png -------------------------------------------------------------------------------- /haskell/asteroids/screenshots/asteroids01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/haskell/asteroids/screenshots/asteroids01.png -------------------------------------------------------------------------------- /haskell/asteroids/screenshots/asteroids02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/haskell/asteroids/screenshots/asteroids02.png -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue01.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue01.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue02.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue03.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue03.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue04.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue04.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue05.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue05.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue06.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue06.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue07.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue07.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue08.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue08.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue09.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue09.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue10.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue11.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue12.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/screenshots/pyxelrogue13.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jay-kumogata/RetroGames/HEAD/pyxel/pyxelrogue/screenshots/pyxelrogue13.gif -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | -------------------------------------------------------------------------------- /pyxel/pyxel2d/README.md: -------------------------------------------------------------------------------- 1 | # Pyxel2D 2 | 3 | ## Introduction 4 | 5 | Pyxel2D is a physics engine that runs on Pyxel/Python. 6 | Moved to [a new repository](https://github.com/jay-kumogata/Pyxel2D). 7 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/equipment_types.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class EquipmentType(Enum): 5 | WEAPON = auto() 6 | ARMOR = auto() 7 | 8 | # end of equipment_types.py 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/equipment_types.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class EquipmentType(Enum): 5 | WEAPON = auto() 6 | ARMOR = auto() 7 | 8 | # end of equipment_types.py 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | -------------------------------------------------------------------------------- /pyxel/pyxelchip8/README.md: -------------------------------------------------------------------------------- 1 | # PyxelChip8 2 | 3 | ## Introduction 4 | 5 | PyxelChip8 is a CHIP-8/SUPER-CHIP emulator that runs on Pyxel/Python library. 6 | Moved to [a new repository](https://github.com/jay-kumogata/PyxelChip8). 7 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/render_order.py: -------------------------------------------------------------------------------- 1 | from enum import auto, Enum 2 | 3 | 4 | class RenderOrder(Enum): 5 | CORPSE = auto() 6 | ITEM = auto() 7 | ACTOR = auto() 8 | 9 | # end of render_order.py 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part1/actions.py: -------------------------------------------------------------------------------- 1 | class Action: 2 | pass 3 | 4 | 5 | class EscapeAction(Action): 6 | pass 7 | 8 | 9 | class MovementAction(Action): 10 | def __init__(self, dx: int, dy: int): 11 | super().__init__() 12 | 13 | self.dx = dx 14 | self.dy = dy 15 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | 7 | class QuitWithoutSaving(SystemExit): 8 | """Can be raised to exit the game without automatically saving.""" 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | 7 | class QuitWithoutSaving(SystemExit): 8 | """Can be raised to exit the game without automatically saving.""" 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | 7 | class QuitWithoutSaving(SystemExit): 8 | """Can be raised to exit the game without automatically saving.""" 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | 7 | class QuitWithoutSaving(SystemExit): 8 | """Can be raised to exit the game without automatically saving.""" 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/exceptions.py: -------------------------------------------------------------------------------- 1 | class Impossible(Exception): 2 | """Exception raised when an action is impossible to be performed. 3 | 4 | The reason is given as the exception message. 5 | """ 6 | 7 | class QuitWithoutSaving(SystemExit): 8 | """Can be raised to exit the game without automatically saving.""" 9 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/actions.py: -------------------------------------------------------------------------------- 1 | class Action: 2 | pass 3 | 4 | 5 | class EscapeAction(Action): 6 | pass 7 | 8 | 9 | class MovementAction(Action): 10 | def __init__(self, dx: int, dy: int): 11 | super().__init__() 12 | 13 | self.dx = dx 14 | self.dy = dy 15 | 16 | # end of actions.py 17 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/actions.py: -------------------------------------------------------------------------------- 1 | class Action: 2 | pass 3 | 4 | 5 | class EscapeAction(Action): 6 | pass 7 | 8 | 9 | class MovementAction(Action): 10 | def __init__(self, dx: int, dy: int): 11 | super().__init__() 12 | 13 | self.dx = dx 14 | self.dy = dy 15 | 16 | # end of actions.py 17 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/entity_factories.py: -------------------------------------------------------------------------------- 1 | from entity import Entity 2 | 3 | player = Entity(char="@", color=7, name="Player", blocks_movement=True) 4 | 5 | orc = Entity(char="o", color=14, name="Orc", blocks_movement=True) 6 | troll = Entity(char="T", color=15, name="Troll", blocks_movement=True) 7 | 8 | # end of entity_factories.py 9 | 10 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/color.py: -------------------------------------------------------------------------------- 1 | white = 7 2 | black = 0 3 | 4 | player_atk = 12 5 | enemy_atk = 13 6 | 7 | player_die = 14 8 | enemy_die = 15 9 | 10 | welcome_text = 6 11 | 12 | bar_text = white 13 | bar_filled = 11 14 | bar_empty = 8 15 | 16 | # キャラクタドット数(Pyxel組込フォント) 17 | chr_x = 4 18 | chr_y = 5 19 | 20 | # end of color.py 21 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | 9 | 10 | class BaseComponent: 11 | entity: Entity # Owning entity instance. 12 | 13 | @property 14 | def engine(self) -> Engine: 15 | return self.entity.gamemap.engine 16 | 17 | # end of base_component.py 18 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | 9 | 10 | class BaseComponent: 11 | entity: Entity # Owning entity instance. 12 | 13 | @property 14 | def engine(self) -> Engine: 15 | return self.entity.gamemap.engine 16 | 17 | # end of base_component.py 18 | -------------------------------------------------------------------------------- /pyxel/galaxian/README.md: -------------------------------------------------------------------------------- 1 | # Galaxian 2 | 3 | ## Introduction 4 | 5 | It is a demo of Galaxian. 6 | 7 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/galaxian/screenshots/galaxian01.gif) 8 | 9 | ## How to Run 10 | 11 | Please execute the following from the Pyxel (version 2.2.10) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.galaxian.galaxian). 13 | 14 | > python galaxian.py 15 | 16 | ## Remarks 17 | -------------------------------------------------------------------------------- /pyxel/hanafuda/README.md: -------------------------------------------------------------------------------- 1 | # Hanafuda Koi-Koi 2 | 3 | ## Introduction 4 | 5 | It is a demo of Hanafuda Koi-Koi (Japanese card game). 6 | 7 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/hanafuda/screenshots/hanafuda01.png) 8 | 9 | ## How to Run 10 | 11 | Please execute the following from the Pyxel (version 1.9.18) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.hanafuda.hanafuda). 13 | 14 | > python hanafuda.py 15 | 16 | ## Remarks 17 | -------------------------------------------------------------------------------- /pyxel/mahjong/README.md: -------------------------------------------------------------------------------- 1 | # Mahjong 2 | 3 | ## Introduction 4 | 5 | It is a demo of Mahjong (Chinese table game). 6 | 7 | 8 | 9 | ## How to Run 10 | 11 | Please execute the following from the Pyxel (version 2.2.10) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.mahjong.mahjong). 13 | 14 | > python mahjong.py 15 | 16 | ## Remarks 17 | -------------------------------------------------------------------------------- /research/99_00_NoteOnGames.md: -------------------------------------------------------------------------------- 1 | # 99_ゲーム雑記 2 | 3 | ## はじめに 4 | 5 | ゲーム(レトロゲーム含む)について,Twitter等で呟いた内容をまとめます. 6 | 時系列で未整理の内容です. 7 | 8 | - [01_ゲーム雑記2017](99_01_NoteOnGames2017.md) 9 | - [01_ゲーム雑記2018](99_02_NoteOnGames2018.md) 10 | - [01_ゲーム雑記2019](99_03_NoteOnGames2019.md) 11 | - [01_ゲーム雑記2020](99_04_NoteOnGames2020.md) 12 | - [01_ゲーム雑記2021](99_05_NoteOnGames2021.md) 13 | - [01_ゲーム雑記2022](99_06_NoteOnGames2022.md) 14 | - [01_ゲーム雑記2023](99_07_NoteOnGames2023.md) 15 | - [01_ゲーム雑記2024](99_08_NoteOnGames2024.md) 16 | 17 | 以上 18 | -------------------------------------------------------------------------------- /pyxel/sheep/Grass.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | class Grass: 4 | 5 | def __init__(self, x, y, sz): 6 | self.x = x 7 | self.y = y 8 | self.energy = 20 # この牧草を食べたときに得られる体力 9 | self.eaten = False # まだ食べられていない状態 10 | self.sz = sz 11 | 12 | def update(self): 13 | if self.eaten: 14 | pyxel.rect(self.x, self.y, self.sz, self.sz, 4) # 茶 15 | else: 16 | pyxel.rect(self.x, self.y, self.sz, self.sz, 3) # 緑 17 | 18 | # End of Grass.py 19 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/entity.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | class Entity: 4 | """ 5 | A generic object to represent players, enemies, items, etc. 6 | """ 7 | def __init__(self, x: int, y: int, char: str, color: int): 8 | self.x = x 9 | self.y = y 10 | self.char = char 11 | self.color = color 12 | 13 | def move(self, dx: int, dy: int) -> None: 14 | # Move the entity by a given amount 15 | self.x += dx 16 | self.y += dy 17 | 18 | # end of entity.py 19 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/entity.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | class Entity: 4 | """ 5 | A generic object to represent players, enemies, items, etc. 6 | """ 7 | def __init__(self, x: int, y: int, char: str, color: int): 8 | self.x = x 9 | self.y = y 10 | self.char = char 11 | self.color = color 12 | 13 | def move(self, dx: int, dy: int) -> None: 14 | # Move the entity by a given amount 15 | self.x += dx 16 | self.y += dy 17 | 18 | # end of entity.py 19 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/entity.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | class Entity: 4 | """ 5 | A generic object to represent players, enemies, items, etc. 6 | """ 7 | def __init__(self, x: int, y: int, char: str, color: int): 8 | self.x = x 9 | self.y = y 10 | self.char = char 11 | self.color = color 12 | 13 | def move(self, dx: int, dy: int) -> None: 14 | # Move the entity by a given amount 15 | self.x += dx 16 | self.y += dy 17 | 18 | # end of entity.py 19 | -------------------------------------------------------------------------------- /pyxel/sombrero/README.md: -------------------------------------------------------------------------------- 1 | # Mexican hat (sombrero) demo 2 | 3 | ## Introduction 4 | 5 | It is a demo of Mexican hat (sombrero) graphics. 6 | 7 | 8 | 9 | ## How to Run 10 | 11 | Please execute the following from the Pyxel (version 2.0.13) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.sombrero.sombrero&packages=numpy). 13 | 14 | > python sombrero.py 15 | 16 | ## Remarks 17 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/components/base_component.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | from game_map import GameMap 9 | 10 | class BaseComponent: 11 | parent: Entity # Owning entity instance. 12 | 13 | @property 14 | def gamemap(self) -> GameMap: 15 | return self.parent.gamemap 16 | 17 | @property 18 | def engine(self) -> Engine: 19 | return self.gamemap.engine 20 | 21 | # end of base_component.py 22 | -------------------------------------------------------------------------------- /pyxel/sheep/README.md: -------------------------------------------------------------------------------- 1 | # Eating sheep program 2 | 3 | ## Introduction 4 | 5 | I ported the "Eating sheep program" introduced 6 | in a book ["Math Adventures with Python"](https://nostarch.com/mathadventures) to Pyxel. 7 | It is a simulation of sheep moving while eating grass. 8 | When there is no more grass to eat, they will be taken to heaven. 9 | 10 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/sheep/screenshots/sheep01.gif) 11 | 12 | ## How to Run 13 | 14 | Please execute the following from the Pyxel (version 2.0.13) environment. 15 | 16 | > python SheepAndGrass.py 17 | 18 | ## Remarks 19 | -------------------------------------------------------------------------------- /pyxel/outrun/README.md: -------------------------------------------------------------------------------- 1 | # Outrun for Pyxel/Python 2 | 3 | ## Introduction 4 | 5 | It is a Outrun(Sega/1986) demo. 6 | 7 | 8 | 9 | ## How to Play 10 | 11 | Please execute the following from the Pyxel (version 2.2.10) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.outrun.outrun). 13 | 14 | > python outrun.py 15 | 16 | ## Remarks 17 | 18 | [Simple OutRun in pseudo 3D](https://zenn.dev/sdkfz181tiger/articles/5b96fc307510a3) has been converted into Pyxel/Python using Grok4. 19 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | white = 7 4 | black = 0 5 | 6 | player_atk = 12 7 | enemy_atk = 13 8 | 9 | player_die = 14 10 | enemy_die = 15 11 | 12 | invalid = 9 13 | impossible = 10 14 | error = 2 15 | 16 | welcome_text = 6 17 | health_recovered = 3 18 | 19 | bar_text = white 20 | bar_filled = 11 21 | bar_empty = 8 22 | 23 | # キャラクタドット数(Pyxel組込フォント) 24 | chr_x = 4 25 | chr_y = 5 26 | 27 | # Pyxel向けヘルパー関数 28 | def rect(x: int, y: int, w: int, h: int, col: int): 29 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 30 | 31 | def text(x: int, y: int, s: str, col: int): 32 | pyxel.text(x*chr_x, y*chr_y, s, col) 33 | 34 | # end of color.py 35 | -------------------------------------------------------------------------------- /pyxel/asteroids/README.md: -------------------------------------------------------------------------------- 1 | # Asteroids in Pyxel/Python 2 | 3 | ## Introduction 4 | 5 | I ported Asteroids, which was implemented in Haskell, to Pyxel/Python. 6 | 7 | 8 | 9 | ## How to run 10 | 11 | > python Asteroids.py 12 | 13 | ## How to Play 14 | 15 | You rotate your ship with [Left] and [Right] keys, 16 | and shoot a bullet with [Space] key and split the meteorite. 17 | Small meteorites are extinguished. 18 | If you hit a meteorite, the game is over. 19 | You can replay with [Enter] key. 20 | If you split the meteorite, you will get 100 points, 21 | and if you eliminate it, you will get 500 points. 22 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components.fighter import Fighter 3 | from entity import Actor 4 | 5 | player = Actor( 6 | char="@", 7 | color=7, 8 | name="Player", 9 | ai_cls=HostileEnemy, 10 | fighter=Fighter(hp=30, defense=2, power=5), 11 | ) 12 | 13 | orc = Actor( 14 | char="o", 15 | color=8, 16 | name="Orc", 17 | ai_cls=HostileEnemy, 18 | fighter=Fighter(hp=10, defense=0, power=3), 19 | ) 20 | troll = Actor( 21 | char="T", 22 | color=9, 23 | name="Troll", 24 | ai_cls=HostileEnemy, 25 | fighter=Fighter(hp=16, defense=1, power=4), 26 | ) 27 | 28 | # end of entity_factories.py 29 | 30 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components.fighter import Fighter 3 | from entity import Actor 4 | 5 | player = Actor( 6 | char="@", 7 | color=7, 8 | name="Player", 9 | ai_cls=HostileEnemy, 10 | fighter=Fighter(hp=30, defense=2, power=5), 11 | ) 12 | 13 | orc = Actor( 14 | char="o", 15 | color=8, 16 | name="Orc", 17 | ai_cls=HostileEnemy, 18 | fighter=Fighter(hp=10, defense=0, power=3), 19 | ) 20 | troll = Actor( 21 | char="T", 22 | color=9, 23 | name="Troll", 24 | ai_cls=HostileEnemy, 25 | fighter=Fighter(hp=16, defense=1, power=4), 26 | ) 27 | 28 | # end of entity_factories.py 29 | 30 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/game_map.py: -------------------------------------------------------------------------------- 1 | import numpy as np # type: ignore 2 | import pyxel 3 | 4 | import tile_types 5 | 6 | class GameMap: 7 | def __init__(self, width: int, height: int): 8 | self.width, self.height = width, height 9 | self.tiles = np.full((width, height), fill_value=tile_types.wall, order="F") 10 | 11 | def in_bounds(self, x: int, y: int) -> bool: 12 | """Return True if x and y are inside of the bounds of this map.""" 13 | return 0 <= x < self.width and 0 <= y < self.height 14 | 15 | def render(self) -> None: 16 | for x in range(self.width): 17 | for y in range(self.height): 18 | pyxel.pset(x,y,self.tiles["dark"][x,y]["fg"]) 19 | 20 | # end of game_map.py 21 | -------------------------------------------------------------------------------- /pyxel/frogger/README.md: -------------------------------------------------------------------------------- 1 | # Frogger for Pyxel/Python 2 | 3 | ## Introduction 4 | 5 | It is a Frogger(Konami/1981) clone. 6 | 7 | 8 | 9 | ## How to Play 10 | 11 | Please execute the following from the Pyxel (version 2.2.10) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.frogger.frogger). 13 | 14 | > python frogger.py 15 | 16 | ## How to Controll 17 | 18 | Use the [up] / [down] / [left] / [right] key to move up / down / left / right. 19 | 20 | ## Remarks 21 | 22 | [Basic Frogger](https://gist.github.com/straker/82a4368849cbd441b05bd6a044f2b2d3) has been converted into Pyxel/Python using Grok3. 23 | -------------------------------------------------------------------------------- /pyxel/pinball/README.md: -------------------------------------------------------------------------------- 1 | # Pinball 2 | 3 | ## Introduction 4 | 5 | I ported Mr. Isidor's [Pinball Pong](https://www.lexaloffle.com/bbs/?tid=28488) to Pyxel/Python. 6 | It's a pinball game, or rather, a combination of pinball and Atari's Breakout. 7 | 8 | 9 | 10 | ## How to Run 11 | 12 | Please execute the following from the Pyxel (version 1.9.18) environment. 13 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.pinball.Pinball). 14 | 15 | > python Pinball.py 16 | 17 | ## How to Control 18 | 19 | - [right-arrow]: Flip the right flippers 20 | - [left-arrow]: Flip the left flippers 21 | - [SPACE]: Start game again 22 | -------------------------------------------------------------------------------- /pyxel/nixie/README.md: -------------------------------------------------------------------------------- 1 | # Nixie tube clock 2 | 3 | ## Introduction 4 | 5 | It is a demo of the Nixie tube clock. 6 | 7 | ![](https://github.com/jay-kumogata/RetroGames/raw/main/pyxel/nixie/screenshots/Nixie01.gif) 8 | 9 | ## How to Run 10 | 11 | Please execute the following from the Pyxel (version 1.7.1) environment. 12 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.nixie.Nixie). 13 | 14 | > python Nixie.py 15 | 16 | ## Remarks 17 | 18 | I started making Nixie tube clocks with Pyxel. 19 | First, I drew a dot picture of a Nixie tube, but it looks like a toy. 20 | I had an LED calculator that runs an LED check (count up) when the power is turned off and on, but I remembered that. 21 | It is delicate whether to make this continuation. 22 | -------------------------------------------------------------------------------- /pyxel/asteroids/Bullet.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | from Vec import * 3 | 4 | class Bullet(): 5 | def __init__(self, p : Vec, v : Vec, a : int): 6 | # 弾情報Bulletは,座標Vec,速度Velocity,年齢Ageから構成. 7 | self.p = p 8 | self.v = v 9 | self.a = a 10 | self.l = True # 生死フラグ 11 | 12 | def update(self, timeStep : float): 13 | 14 | # 50サイクルで消滅 15 | if self.a > 50: 16 | self.l = False 17 | # timeStep分移動 18 | else: 19 | self.p = self.p.add(self.v.mul(timeStep)) 20 | self.p = self.p.restoreToScreen() 21 | self.a += timeStep 22 | 23 | def draw(self): 24 | # 弾を表示 25 | pyxel.circb(self.p.x+160, self.p.y+160, 1, 7) 26 | 27 | # End of Bullet.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part1/input_handlers.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | import pyxel 3 | from actions import Action, EscapeAction, MovementAction 4 | 5 | class EventHandler: 6 | def dispatch(self) -> Optional[Action]: 7 | action = None 8 | if pyxel.btnp(pyxel.KEY_UP): 9 | action = MovementAction(dx=0, dy=-1) 10 | elif pyxel.btnp(pyxel.KEY_DOWN): 11 | action = MovementAction(dx=0, dy=1) 12 | elif pyxel.btnp(pyxel.KEY_LEFT): 13 | action = MovementAction(dx=-1, dy=0) 14 | elif pyxel.btnp(pyxel.KEY_RIGHT): 15 | action = MovementAction(dx=1, dy=0) 16 | 17 | elif pyxel.btnp(pyxel.KEY_ESCAPE): 18 | action = EscapeAction() 19 | 20 | # No valid key was pressed 21 | return action 22 | -------------------------------------------------------------------------------- /pyxel/autorace/README.md: -------------------------------------------------------------------------------- 1 | # Autorace 2 | 3 | ## Introduction 4 | 5 | I ported Miss Harumi Takahasi's [Autorace(one screen software)](https://archive.org/details/Fm-7Fm-8/page/n173/mode/2up) to Pyxel/Python. 6 | The original was published in [FM-7 FM-8 Harumi's Game Library](https://archive.org/details/Fm-7Fm-8/). 7 | This is a game where you operate your car and avoid obstacles. 8 | It is extremely difficult. 9 | 10 | 11 | 12 | ## How to Run 13 | 14 | Please execute the following from the Pyxel (version 2.0.0) environment. 15 | 16 | > python autorace.py 17 | 18 | ## How to Control 19 | 20 | - [Right]: Move car to the right 21 | - [Left]: Move car to the left 22 | - [S\]: Replay the game 23 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/game_map.py: -------------------------------------------------------------------------------- 1 | import numpy as np # type: ignore 2 | import pyxel 3 | 4 | import tile_types 5 | 6 | class GameMap: 7 | def __init__(self, width: int, height: int): 8 | self.width, self.height = width, height 9 | self.tiles = np.full((width, height), fill_value=tile_types.floor, order="F") 10 | 11 | self.tiles[30:33, 22] = tile_types.wall 12 | 13 | def in_bounds(self, x: int, y: int) -> bool: 14 | """Return True if x and y are inside of the bounds of this map.""" 15 | return 0 <= x < self.width and 0 <= y < self.height 16 | 17 | def render(self) -> None: 18 | for x in range(self.width): 19 | for y in range(self.height): 20 | pyxel.pset(x,y,self.tiles["dark"][x,y]["fg"]) 21 | 22 | # end of game_map.py 23 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/input_handlers.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | import pyxel 3 | from actions import Action, EscapeAction, MovementAction 4 | 5 | class EventHandler: 6 | def dispatch(self) -> Optional[Action]: 7 | action = None 8 | if pyxel.btnp(pyxel.KEY_UP): 9 | action = MovementAction(dx=0, dy=-1) 10 | elif pyxel.btnp(pyxel.KEY_DOWN): 11 | action = MovementAction(dx=0, dy=1) 12 | elif pyxel.btnp(pyxel.KEY_LEFT): 13 | action = MovementAction(dx=-1, dy=0) 14 | elif pyxel.btnp(pyxel.KEY_RIGHT): 15 | action = MovementAction(dx=1, dy=0) 16 | 17 | elif pyxel.btnp(pyxel.KEY_ESCAPE): 18 | action = EscapeAction() 19 | 20 | # No valid key was pressed 21 | return action 22 | 23 | # end of input_handlers.py 24 | -------------------------------------------------------------------------------- /pyxel/tennis/README.md: -------------------------------------------------------------------------------- 1 | # Tennis-for-Two 2 | 3 | ## Introduction 4 | 5 | Tennis-for-Two is a sports video game that simulates a game of tennis, 6 | and was one of the first games developed in the early history of video games. 7 | 8 | 9 | 10 | ## How to Play 11 | 12 | Please execute the following from the Pyxel (version 2.2.10) environment. 13 | 14 | > python App.py 15 | 16 | ## How to Controll 17 | 18 | ### Player #1 19 | 20 | - [W] / [S]: Turn volume #1 to left / right 21 | - [D]: Hit a ball 22 | 23 | ### Player #2 24 | 25 | - [UP] / [DOWN]: Turn volume #2 to left / right 26 | - [LEFT]: Hit a ball 27 | 28 | ## Remarks 29 | 30 | I also ported the processing program, [Tennis For Two](https://openprocessing.org/sketch/9892/), into Pyxel/Python. 31 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/input_handlers.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | import pyxel 3 | from actions import Action, EscapeAction, MovementAction 4 | 5 | class EventHandler: 6 | def dispatch(self) -> Optional[Action]: 7 | action = None 8 | 9 | if pyxel.btnp(pyxel.KEY_UP): 10 | action = MovementAction(dx=0, dy=-1) 11 | elif pyxel.btnp(pyxel.KEY_DOWN): 12 | action = MovementAction(dx=0, dy=1) 13 | elif pyxel.btnp(pyxel.KEY_LEFT): 14 | action = MovementAction(dx=-1, dy=0) 15 | elif pyxel.btnp(pyxel.KEY_RIGHT): 16 | action = MovementAction(dx=1, dy=0) 17 | 18 | elif pyxel.btnp(pyxel.KEY_ESCAPE): 19 | action = EscapeAction() 20 | 21 | # No valid key was pressed 22 | return action 23 | 24 | # end of input_handlers.py 25 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/components/inventory.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import List, TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | 7 | if TYPE_CHECKING: 8 | from entity import Actor, Item 9 | 10 | 11 | class Inventory(BaseComponent): 12 | parent: Actor 13 | 14 | def __init__(self, capacity: int): 15 | self.capacity = capacity 16 | self.items: List[Item] = [] 17 | 18 | def drop(self, item: Item) -> None: 19 | """ 20 | Removes an item from the inventory and restores it to the game map, at the player's current location. 21 | """ 22 | self.items.remove(item) 23 | item.place(self.parent.x, self.parent.y, self.gamemap) 24 | 25 | self.engine.message_log.add_message(f"You dropped the {item.name}.") 26 | 27 | # end of inventory.py 28 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/input_handlers.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | import pyxel 3 | from actions import Action, EscapeAction, MovementAction 4 | 5 | class EventHandler: 6 | def dispatch(self) -> Optional[Action]: 7 | # メモ: 何も押されていない場合はNoneを返却 8 | action = None 9 | 10 | if pyxel.btnp(pyxel.KEY_UP): 11 | action = MovementAction(dx=0, dy=-1) 12 | elif pyxel.btnp(pyxel.KEY_DOWN): 13 | action = MovementAction(dx=0, dy=1) 14 | elif pyxel.btnp(pyxel.KEY_LEFT): 15 | action = MovementAction(dx=-1, dy=0) 16 | elif pyxel.btnp(pyxel.KEY_RIGHT): 17 | action = MovementAction(dx=1, dy=0) 18 | 19 | elif pyxel.btnp(pyxel.KEY_ESCAPE): 20 | action = EscapeAction() 21 | 22 | # No valid key was pressed 23 | return action 24 | 25 | # end of input_handlers.py 26 | -------------------------------------------------------------------------------- /research/02_00_VideoGameHistory.md: -------------------------------------------------------------------------------- 1 | # 02_ゲーム史研究 2 | 3 | ## はじめに 4 | 5 | ゲームの歴史を調べるテーマです. 6 | 7 | - サブテーマリスト 8 | - [01_進化論的アプローチ](https://github.com/jay-kumogata/RetroGames/blob/main/research/02_01_EvolutionaryApproach.md): いかにゲーム作品が進化したかを進化論(生物学)のアナロジーで研究(→比較的主流派) 9 | - [02_産業論的アプローチ](https://github.com/jay-kumogata/RetroGames/blob/main/research/02_02_IndustrialApproach.md): いかにゲーム産業が発展したかを産業論として研究 10 | - 例: スペースインベーダーが進化してギャラクシアンが開発等 11 | - [03_ゲームマシンアーカイブ](https://github.com/jay-kumogata/RetroGames/blob/main/research/02_03_GMANote.md): GM誌を年代別に調査 12 | - [04_海外ゲーム史研究](https://github.com/jay-kumogata/RetroGames/blob/main/research/02_04_WesternGames.md): 海外のゲーム史を調査 13 | - 05_野球ゲーム史研究: 野球のゲーム史を調査(→野球にスポットをあてるのは個人的な理由) 14 | - 06_影響論: ゲームをすることでどんな影響がでるか(→厳密には歴史ではない) 15 | - 例: 子供が狂暴になる等 16 | - [07_社史編纂](https://github.com/jay-kumogata/RetroGames/blob/main/research/02_07_HistoryOfAthena.md): アテナ社 17 | 18 | 以上 -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | white = 7 4 | black = 0 5 | red = 8 6 | 7 | player_atk = 12 8 | enemy_atk = 13 9 | 10 | player_die = 14 11 | enemy_die = 15 12 | needs_target = 5 13 | status_effect_applied = 6 14 | 15 | invalid = 9 16 | impossible = 10 17 | error = 2 18 | 19 | welcome_text = 6 20 | health_recovered = 3 21 | 22 | bar_text = white 23 | bar_filled = 11 24 | bar_empty = 8 25 | 26 | # メモ: 以下、色(color)とは直接関係ないコード(Pyxel関連) 27 | 28 | # メモ: 組込フォントのドット数(4x5) 29 | chr_x = 4 30 | chr_y = 5 31 | 32 | # メモ: ヘルパー関数 33 | def rect(x: int, y: int, w: int, h: int, col: int): 34 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 35 | 36 | def rectb(x: int, y: int, w: int, h: int, col: int): 37 | pyxel.rectb(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 38 | 39 | def text(x: int, y: int, s: str, col: int): 40 | pyxel.text(x*chr_x, y*chr_y, s, col) 41 | 42 | # end of color.py 43 | -------------------------------------------------------------------------------- /pyxel/mahjong/mahjong.py: -------------------------------------------------------------------------------- 1 | # 2 | # 麻雀デモ 3 | # まぐち氏作の「mahjong! #アイロンビーズ #ドット絵 #麻雀 #mahjong」を参考にしました. 4 | # https://x.com/maguchi_tweet/status/876398803732934657 5 | # 6 | # Feb 07, 2025 ver.1 (first release) 7 | # 8 | # -*- coding: utf-8 -*- 9 | import pyxel 10 | import random 11 | 12 | class Mahjong: 13 | def __init__( self ): 14 | pyxel.init( 96, 96, title="Mahjong", fps=20) 15 | pyxel.load( "mahjong.pyxres") 16 | pyxel.run(self.update, self.draw) 17 | 18 | def update( self ): 19 | """NONE""" 20 | 21 | def draw( self ): 22 | pyxel.cls(3) 23 | 24 | for m in range(4): 25 | for n in range(9): 26 | self.draw_pi(m, n, n*9+7, m*11+26) 27 | 28 | # m: 種類(0:字牌, 1:索子, 2:筒子, 3:萬子) 29 | # n: 順番(数牌:0~8, 字牌: 0~6) 30 | def draw_pi( self, m, n, x, y): 31 | pyxel.blt( x, y, 0, n*8, m*16, 8, 10 ) 32 | 33 | # Main 34 | Mahjong() 35 | 36 | # End of mahjong.py 37 | -------------------------------------------------------------------------------- /pyxel/doc/230409_PyxelNote.md: -------------------------------------------------------------------------------- 1 | ## Pyxelによるゲーム開発記(2023年編) 2 | 3 | ### はじめに 4 | 5 | レトロゲームエンジン [Pyxel](https://github.com/kitao/pyxel) によるゲーム開発の記録です. 6 | 7 | ### 2023-04-09 8 | 9 | 数式でアートが作れるなら,数式で遊びが作れるのだろうか.と考えながら散歩しました.多分できないです. 10 | 数式でできるのは,シミュレーションまでです.それを遊びにするのは,ホモ・ルーデンスである我々ということになります. 11 | 12 | 例えば,月面着陸船の挙動を数式で表して,それを月面着陸シミュレーションにすることはできます. 13 | でも,それを訓練と思うか,遊びと思うかは,あくまで我々ということです. 14 | そもそも,数式でアートが作れるというのも,数式でシミュレーション(もしくは単なる模様)が作れるだけです. 15 | それを美しいと思うのは我々なんだなと思います. 16 | 何を芸術と思うか,何を遊びと考えるか,ということを,他の人と共有できれば,それらは芸術や遊びとして成立するのでしょう. 17 | 数式で遊びが作れるか,という問いについて,少し考えてみました. 18 | 19 | ### 2023-04-22 20 | 21 | Pyxelでゲーム🎮作れる人,尊敬します. 22 | いくらやっても,模擬器と謎のデモしかできないです. 23 | あの16色でドットが打てる人は,職人ですね. 24 | 25 | ### 2023-11-26 26 | 27 | 夏頃に花札を作ろうと思い,ドットを置きました. 28 | 完成が遠いので,とりあえず,48枚の花札を表示するデモを作ってみました. 29 | matt氏作の [Hanafuda Koi-Koi (Japanese card game)](https://www.lexaloffle.com/bbs/?tid=2421) を参考にしています. 30 | 31 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/hanafuda/screenshots/hanafuda01.png) 32 | 33 | 以上 34 | -------------------------------------------------------------------------------- /haskell/asteroids/README.md: -------------------------------------------------------------------------------- 1 | # Asteroids in Haskell 2 | 3 | ## Introduction 4 | 5 | I came up with the mysterious question of whether a game can be made with mathematical formulas. 6 | In the past, I've researched the haskell implementation of an old game called Asteroids. 7 | The shape of the meteorite has been slightly improved and left as it is. 8 | Here, I think that this topic will be done privately. 9 | And if you get tired of it again, leave it alone. 10 | 11 | 12 | 13 | ## How to run 14 | 15 | > stack install gloss 16 | > stack ghc Asteroids.hs 17 | > ./Asteroids.exe 18 | 19 | ## How to Play 20 | 21 | Left-click to shoot a bullet and split the meteorite. 22 | Small meteorites are extinguished. 23 | If you hit a meteorite, the game is over. 24 | Right click to replay. 25 | If you split the meteorite, you will get 100 points, 26 | and if you eliminate it, you will get 500 points. 27 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components.consumable import HealingConsumable 3 | from components.fighter import Fighter 4 | from components.inventory import Inventory 5 | from entity import Actor, Item 6 | 7 | player = Actor( 8 | char="@", 9 | color=7, 10 | name="Player", 11 | ai_cls=HostileEnemy, 12 | fighter=Fighter(hp=30, defense=2, power=5), 13 | inventory=Inventory(capacity=26), 14 | ) 15 | 16 | orc = Actor( 17 | char="o", 18 | color=8, 19 | name="Orc", 20 | ai_cls=HostileEnemy, 21 | fighter=Fighter(hp=10, defense=0, power=3), 22 | inventory=Inventory(capacity=0), 23 | ) 24 | troll = Actor( 25 | char="T", 26 | color=9, 27 | name="Troll", 28 | ai_cls=HostileEnemy, 29 | fighter=Fighter(hp=16, defense=1, power=4), 30 | inventory=Inventory(capacity=0), 31 | ) 32 | 33 | health_potion = Item( 34 | char="!", 35 | color=11, 36 | name="Health Potion", 37 | consumable=HealingConsumable(amount=4), 38 | ) 39 | 40 | # end of entity_factories.py 41 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/input_handlers.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | import tcod.event 4 | import pyxel 5 | 6 | from actions import Action, BumpAction, EscapeAction 7 | 8 | class EventHandler: 9 | def dispatch(self) -> Optional[Action]: 10 | # メモ: 何も押されていない場合はNoneを返却 11 | action = None 12 | 13 | if pyxel.btnp(pyxel.KEY_UP): 14 | #action = MovementAction(dx=0, dy=-1) 15 | action = BumpAction(dx=0, dy=-1) 16 | elif pyxel.btnp(pyxel.KEY_DOWN): 17 | #action = MovementAction(dx=0, dy=1) 18 | action = BumpAction(dx=0, dy=1) 19 | elif pyxel.btnp(pyxel.KEY_LEFT): 20 | #action = MovementAction(dx=-1, dy=0) 21 | action = BumpAction(dx=-1, dy=0) 22 | elif pyxel.btnp(pyxel.KEY_RIGHT): 23 | #action = MovementAction(dx=1, dy=0) 24 | action = BumpAction(dx=1, dy=0) 25 | 26 | elif pyxel.btnp(pyxel.KEY_ESCAPE): 27 | action = EscapeAction() 28 | 29 | # No valid key was pressed 30 | return action 31 | 32 | # end of input_handlers.py 33 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part1/main.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | from actions import EscapeAction, MovementAction 4 | from input_handlers import EventHandler 5 | 6 | def main() -> None: 7 | global player_x, player_y, event_handler 8 | 9 | screen_width = 80 10 | screen_height = 50 11 | 12 | player_x = int(screen_width / 2) 13 | player_y = int(screen_height / 2) 14 | 15 | event_handler = EventHandler() 16 | 17 | pyxel.init( 18 | screen_width, 19 | screen_height, 20 | title="Yet Another Roguelike Tutorial", 21 | fps=30 22 | ) 23 | pyxel.run(update, draw) 24 | 25 | def update(): 26 | global player_x, player_y, event_handler 27 | 28 | action = event_handler.dispatch() 29 | 30 | if action is None: 31 | return 32 | 33 | if isinstance(action, MovementAction): 34 | player_x += action.dx 35 | player_y += action.dy 36 | 37 | elif isinstance(action, MovementAction): 38 | raise SystemExit() 39 | 40 | def draw(): 41 | pyxel.cls(1) 42 | pyxel.pset(player_x,player_y,7) 43 | 44 | if __name__ == "__main__": 45 | main() 46 | -------------------------------------------------------------------------------- /haskell/asteroids/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Niko Heikkilä 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /pyxel/hanafuda/hanafuda.py: -------------------------------------------------------------------------------- 1 | # 2 | # 花札デモ 3 | # matt氏作の「Hanafuda Koi-Koi(Japanese card game)」を参考にしました. 4 | # https://www.lexaloffle.com/bbs/?tid=2421 5 | # 6 | # Nov 26, 2023 ver.1 (first release) 7 | # 8 | # -*- coding: utf-8 -*- 9 | import pyxel 10 | 11 | class Hanafuda: 12 | def __init__( self ): 13 | # Pyxel初期化 14 | pyxel.init( 128, 128, title="Hanafuda", fps=20) 15 | pyxel.load("hanafuda.pyxres") 16 | pyxel.run(self.update,self.draw) 17 | 18 | def update( self ): 19 | """NONE""" 20 | 21 | def draw( self ): 22 | pyxel.cls(1) 23 | 24 | # 全ての花札を表示(デモ) 25 | for i in range(48): 26 | m = int( i / 4 ) 27 | n = int( i % 4 ) 28 | x = int( i % 8 )*15 29 | y = int( i / 8 )*19 30 | self.draw_hanafuda( m, n, x+4, y+8) 31 | 32 | # 花札表示 33 | # m: 花(0..11), n: 札(0..3) 34 | # x: x座標(0..113), y座標(0..109) 35 | def draw_hanafuda( self, m, n, x, y ): 36 | pyxel.rectb( x, y, 14, 18, 4 ) 37 | pyxel.blt( x+1, y+1, 0, n*16, m*16, 12, 16 ) 38 | 39 | # Main 40 | Hanafuda() 41 | 42 | # End of Hanafuda.py 43 | -------------------------------------------------------------------------------- /pyxel/doc/220217_PyxelNote.md: -------------------------------------------------------------------------------- 1 | ## Pyxelによるゲーム開発記 2 | 3 | ### はじめに 4 | 5 | レトロゲームエンジン[Pyxel](https://github.com/kitao/pyxel)によるゲーム開発の記録です. 6 | 7 | ### 2022-02-17 8 | 9 | お夜寝から目が覚めたので,pyxel環境を整えました. 10 | 11 | - python: 3.8.9 12 | - pip: 22.0.3 13 | - pyxel: 1.6.9 14 | 15 | pyLodeRunnerを動かそうとしたら,すでに消えていました. 16 | 権利的にNGだったのかもしれません. 17 | シューティングゲームのサンプルは無事に動きました. 18 | 19 | ### 2022-02-19 20 | 21 | ブックオフから帰宅して,もろもろ掃除とかして,この前に動かしたシューティングのサンプルソースコードを読みました. 22 | pythonと2Dゲームの知識があれば,比較的すらすらと読めるかもしれません. 23 | 350行位だったので,そんなに苦労せずに理解できました. 24 | ただ普通に何か作ってもつまらないので,少し考えます. 25 | 26 | ### 2022-02-20 27 | 28 | pyxel 1.6.9だと若干構文が変わっています. 29 | 30 | % pyxel edit *.pyxres 31 | % pyxel copy_examples 32 | 33 | [Asteroids](https://github.com/timbledum/asteroids)の実装がGitにあったので,動かしてみました. 34 | ロジックをpythonで書く必要があるので,Pyxelでの開発はあまり気分が盛り上がらないです. 35 | 36 | ### 2022-04-03 37 | 38 | Pyxelを少し練習しました.pngファイルが読み込めるみたいです.なにか作ってみようかなと考えています. 39 | 40 | ### 2022-07-20 41 | 42 | Pyxelで,ニキシー管時計を作りはじめました. 43 | まず,ニキシー管のドット絵を描いてみましたが,少しおもちゃっぽい感じの仕上がりです. 44 | 電源をOFF/ONすると,LEDチェック(カウントアップ)が走るLED電卓を持っていたのですが,そのことを思い出しました. 45 | この続きを作るかは微妙です. 46 | 47 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/nixie/screenshots/Nixie01.gif) 48 | 49 | 以上 50 | -------------------------------------------------------------------------------- /pyxel/aclm/README.md: -------------------------------------------------------------------------------- 1 | # ACLM 2 | 3 | ## Introduction 4 | 5 | I ported Mr. Wingman's [ACLM](https://archive.org/details/micom-basic-magazine-issue-16-october-1983/page/n92/mode/1up) to Pyxel/Python. 6 | The original was published in [Mycom Basic Magazine (October 1983 issue)](https://archive.org/details/micom-basic-magazine-issue-16-october-1983/). 7 | This is a game where you operate my aircraft (red) and defeat enemy aircraft (blue) by hitting them vertically and horizontally. 8 | Since it is extremely difficult, I have changed the rules to say that if my aircraft collides with the enemy aircraft, it will be 'a tie' instead of 'a loss.' 9 | Also, the original version seems to have a scene 2 in which they attack a city. 10 | 11 | 12 | 13 | ## How to Run 14 | 15 | Please execute the following from the Pyxel (version 1.7.0) environment. 16 | Or you can play [here](https://kitao.github.io/pyxel/wasm/launcher/?run=jay-kumogata.RetroGames.pyxel.aclm.aclm). 17 | 18 | > python aclm.py 19 | 20 | ## How to Control 21 | 22 | - [right-arrow]: Rotate my aircraft to the right 23 | - [left-arrow]: Rotate my aircraft to the left 24 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/main.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | from engine import Engine 4 | from entity import Entity 5 | from game_map import GameMap 6 | from input_handlers import EventHandler 7 | 8 | def main() -> None: 9 | global engine 10 | 11 | screen_width = 80 12 | screen_height = 50 13 | 14 | map_width = 80 15 | map_height = 50 16 | 17 | event_handler = EventHandler() 18 | 19 | player = Entity(int(screen_width / 2), int(screen_height / 2), "@", 7) 20 | npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), "@", 10) 21 | entities = {npc, player} 22 | 23 | game_map = GameMap(map_width, map_height) 24 | 25 | engine = Engine(entities=entities, event_handler=event_handler, game_map=game_map, player=player) 26 | 27 | pyxel.init( 28 | screen_width, 29 | screen_height, 30 | title="Yet Another Roguelike Tutorial", 31 | fps=30 32 | ) 33 | pyxel.run(update, draw) 34 | 35 | def update(): 36 | global engine 37 | engine.handle_events() 38 | 39 | def draw(): 40 | global engine 41 | engine.render() 42 | 43 | if __name__ == "__main__": 44 | main() 45 | 46 | # end of main.py 47 | -------------------------------------------------------------------------------- /research/99_01_NoteOnGames2017.md: -------------------------------------------------------------------------------- 1 | # 99_ゲーム雑記: 01_ゲーム雑記2017 2 | 3 | ## twitterより 4 | 5 | ### 2017-01-22 6 | 7 | あそぶ!ゲーム展にて,[「ゼビウス」製作チームメンバの対談](http://channel2.skipcity.jp/popup/?md=mus_asbgmtn2xvszdnk_960x540&mw=560&mh=315)が配信中です.「スクロールするゲームで,(コナミのスクランブルのように)上下を撃ち分けるゲームが流行る」というマーケティングの情報で開発したという逸話が面白いです.必見です. 8 | 9 | ### 2017-02-05 10 | 11 | [MAMEプロジェクト](https://www.mamedev.org/)も,20年ですか.消え行くものをエミュレーションという技術で必死に保存しようとする英雄的な活動は,後世にまで語り継がれるでしょう.そして,本当に多くの貢献者により,この活動が支えられているのだと知り,頭が上がりません. 12 | 13 | 14 | 15 | ### 2017-04-19 16 | 17 | [Lode Runner](https://tozaigames.co.jp/products/loderunner_history/),懐かしいです. 18 | 19 | ![](https://tozaigames.co.jp/products/loderunner_history/images/img_01.png) 20 | 21 | ### 2017-04-28 22 | 23 | 昔のゲーム機の復刻ブームですが,次はスーファミという噂があるみたいです. 24 | 米国では,今年発売のようです. 25 | 26 | ### 2017-04-29 27 | 28 | 古い機械についてつぶやきます.エレクトロニクス企業の繁栄と衰退に興味があります. 29 | I'll tweet about old machines. And I'm interested in prosperity and decline of electronics companies. 30 | 31 | ### 2017-12-18 32 | 33 | [ファイナルファンタジー30周年](http://www.finalfantasy.jp/30th/)です. 34 | 結局,ファミコンで,FinalFantasy1/2/3,ワンダースワンで,FinalFantasy1/2/4,プレステで,FinalFantasy7,しかやっていません. 35 | 36 | ![](https://www.jp.square-enix.com/company/ja/news/images/FF30th_logo_yoko_RGB_web.gif) 37 | 38 | 以上 -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/engine.py: -------------------------------------------------------------------------------- 1 | from typing import Set, Iterable, Any 2 | 3 | import pyxel 4 | 5 | from actions import EscapeAction, MovementAction 6 | from entity import Entity 7 | from game_map import GameMap 8 | from input_handlers import EventHandler 9 | 10 | class Engine: 11 | def __init__(self, entities: Set[Entity], event_handler: EventHandler, game_map: GameMap, player: Entity): 12 | self.entities = entities 13 | self.event_handler = event_handler 14 | self.game_map = game_map 15 | self.player = player 16 | 17 | def handle_events(self) -> None: 18 | action = self.event_handler.dispatch() 19 | 20 | if action is None: 21 | return 22 | 23 | if isinstance(action, MovementAction): 24 | if self.game_map.tiles["walkable"][self.player.x + action.dx, self.player.y + action.dy]: 25 | self.player.move(dx=action.dx, dy=action.dy) 26 | 27 | elif isinstance(action, EscapeAction): 28 | raise SystemExit() 29 | 30 | def render(self) -> None: 31 | pyxel.cls(1) 32 | self.game_map.render() 33 | for entity in self.entities: 34 | pyxel.pset(entity.x, entity.y, entity.color) 35 | 36 | # end of engine.py 37 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/engine.py: -------------------------------------------------------------------------------- 1 | from typing import Set, Iterable, Any 2 | 3 | import pyxel 4 | 5 | from actions import EscapeAction, MovementAction 6 | from entity import Entity 7 | from game_map import GameMap 8 | from input_handlers import EventHandler 9 | 10 | class Engine: 11 | def __init__(self, entities: Set[Entity], event_handler: EventHandler, game_map: GameMap, player: Entity): 12 | self.entities = entities 13 | self.event_handler = event_handler 14 | self.game_map = game_map 15 | self.player = player 16 | 17 | def handle_events(self) -> None: 18 | action = self.event_handler.dispatch() 19 | 20 | if action is None: 21 | return 22 | 23 | if isinstance(action, MovementAction): 24 | if self.game_map.tiles["walkable"][self.player.x + action.dx, self.player.y + action.dy]: 25 | self.player.move(dx=action.dx, dy=action.dy) 26 | 27 | elif isinstance(action, EscapeAction): 28 | raise SystemExit() 29 | 30 | def render(self) -> None: 31 | pyxel.cls(1) 32 | self.game_map.render() 33 | for entity in self.entities: 34 | pyxel.pset(entity.x, entity.y, entity.color) 35 | 36 | # end of engine.py 37 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/entity.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import copy 4 | from typing import Tuple, TypeVar, TYPE_CHECKING 5 | 6 | if TYPE_CHECKING: 7 | from game_map import GameMap 8 | 9 | T = TypeVar("T", bound="Entity") 10 | 11 | class Entity: 12 | """ 13 | A generic object to represent players, enemies, items, etc. 14 | """ 15 | def __init__( 16 | self, 17 | x: int = 0, 18 | y: int = 0, 19 | char: str = "?", 20 | color: int = 7, # 白 21 | name: str = "", 22 | blocks_movement: bool = False, 23 | ): 24 | self.x = x 25 | self.y = y 26 | self.char = char 27 | self.color = color 28 | self.name = name 29 | self.blocks_movement = blocks_movement 30 | 31 | def spawn(self: T, gamemap: GameMap, x: int, y: int) -> T: 32 | """Spawn a copy of this instance at the given location.""" 33 | clone = copy.deepcopy(self) 34 | clone.x = x 35 | clone.y = y 36 | gamemap.entities.add(clone) 37 | return clone 38 | 39 | def move(self, dx: int, dy: int) -> None: 40 | # Move the entity by a given amount 41 | self.x += dx 42 | self.y += dy 43 | 44 | # end of entity.py 45 | -------------------------------------------------------------------------------- /pyxel/asteroids/Ship.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | from Vec import * 3 | 4 | class Ship(): 5 | # 船情報Shipは,座標Vec,速度Velocityから構成. 6 | def __init__(self, p : Vec, v : Vec): 7 | self.p = p 8 | self.v = v 9 | self.s = [[0, -4], [-2, 4], [2, 4], [0, -4]] 10 | self.r = math.pi / 2 11 | 12 | def update(self, timeStep : float): 13 | # 弾を発射したら反動で動く 14 | self.p = self.p.add(self.v.mul(timeStep)) 15 | self.p = self.p.restoreToScreen() 16 | 17 | # 回転 18 | if pyxel.btn(pyxel.KEY_LEFT): 19 | self.r -= math.pi / 8 20 | elif pyxel.btn(pyxel.KEY_RIGHT): 21 | self.r += math.pi / 8 22 | 23 | if self.r < 0: 24 | self.r += 2 * math.pi 25 | elif self.r > 2 * math.pi: 26 | self.r -= 2 * math.pi 27 | 28 | def draw(self): 29 | a = [] 30 | for b in self.s: 31 | a.append(Vec(b[0],b[1]).rotateV(self.r)) 32 | 33 | for n in range(len(self.s)-1): 34 | pyxel.line( self.p.x+a[n].x+160, 35 | self.p.y+a[n].y+160, 36 | self.p.x+a[n+1].x+160, 37 | self.p.y+a[n+1].y+160, 38 | 7 ) 39 | 40 | # End of Ship.py 41 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ] 21 | ) 22 | 23 | 24 | def new_tile( 25 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 26 | walkable: int, 27 | transparent: int, 28 | dark: Tuple[int, int, int] 29 | ) -> np.ndarray: 30 | """Helper function for defining individual tile types """ 31 | return np.array((walkable, transparent, dark), dtype=tile_dt) 32 | 33 | floor = new_tile( 34 | walkable=True, transparent=True, dark=(ord(" "), 5, 1), 35 | ) 36 | wall = new_tile( 37 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), 38 | ) 39 | 40 | # end of tile_types.py 41 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part2/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type compatible with Console.tiles_rgb. 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint. 9 | ("fg", np.int32), # 3 unsigned bytes, for RGB colors. 10 | ("bg", np.int32), 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ] 21 | ) 22 | 23 | 24 | def new_tile( 25 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 26 | walkable: int, 27 | transparent: int, 28 | dark: Tuple[int, int, int] 29 | ) -> np.ndarray: 30 | """Helper function for defining individual tile types """ 31 | return np.array((walkable, transparent, dark), dtype=tile_dt) 32 | 33 | floor = new_tile( 34 | walkable=True, transparent=True, dark=(ord(" "), 5, 1), 35 | ) 36 | wall = new_tile( 37 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), 38 | ) 39 | 40 | # end of tile_types.py 41 | -------------------------------------------------------------------------------- /pyxel/tennis/Ball.py: -------------------------------------------------------------------------------- 1 | # generated by Grok3 2 | 3 | import pyxel 4 | 5 | class Ball: 6 | def __init__(self, p_pos_x, p_pos_y): 7 | self.pos_x = self.prev_pos_x = p_pos_x 8 | self.pos_y = self.prev_pos_y = p_pos_y 9 | self.vel_x = 0 10 | self.vel_y = 0 11 | 12 | def update(self, p_gravity): 13 | self.prev_pos_x = self.pos_x 14 | self.prev_pos_y = self.pos_y 15 | self.vel_y += p_gravity 16 | self.pos_x += self.vel_x 17 | self.pos_y += self.vel_y 18 | 19 | def draw(self): 20 | # 線を描画 21 | pyxel.line(self.prev_pos_x, self.prev_pos_y, self.pos_x, self.pos_y, 14) 22 | # 点を描画 23 | pyxel.pset(self.pos_x, self.pos_y, 14) 24 | 25 | def bounce_floor(self, p_bounce): 26 | self.vel_y = -self.vel_y * p_bounce 27 | 28 | def bounce_fence(self, p_bounce): 29 | self.vel_x = -self.vel_x * p_bounce 30 | 31 | def set_speed(self, p_vel_x, p_vel_y): 32 | self.vel_x = p_vel_x 33 | self.vel_y = p_vel_y 34 | 35 | def set_position(self, p_pos_x, p_pos_y): 36 | self.pos_x = p_pos_x 37 | self.pos_y = p_pos_y 38 | 39 | def set_prev_position(self, p_pos_x, p_pos_y): 40 | self.prev_pos_x = p_pos_x 41 | self.prev_pos_y = p_pos_y 42 | 43 | # End of Ball.py 44 | -------------------------------------------------------------------------------- /pyxel/autorace/basic.py: -------------------------------------------------------------------------------- 1 | # 2 | # 「昔のBASICゲームをPythonに移植するためのライブラリ」 3 | # 4 | # Jun 14, 2024 ver.1 (autorace.py対応) 5 | # 6 | # -*- coding: utf-8 -*- 7 | import numpy as np 8 | 9 | # 仮想画面 10 | class screen: 11 | def __init__( 12 | self, width: int, height: int 13 | ): 14 | # 初期化(仮想画面) 15 | self.width, self.height = width, height 16 | self.ch = np.full((width, height), ord(' ')) 17 | self.fg = np.full((width, height), 7) 18 | 19 | # 画面表示(X座標,Y座標,キャラクタ,色属性) 20 | def poke(self, x: int, y: int, c: int, a: int): 21 | self.ch[x,y] = c 22 | self.fg[x,y] = a 23 | 24 | # 画面情報(X座標,Y座標,キャラクタ/色属性) 25 | def peek(self, x: int, y: int, f: bool): 26 | if f: 27 | return self.ch[x,y] 28 | else: 29 | return self.fg[x,y] 30 | 31 | # 画面スクロール 32 | def scroll(self): 33 | for w in range(self.width): 34 | for h in range(self.height-1): 35 | self.ch[w,h] = self.ch[w,h+1] 36 | self.fg[w,h] = self.fg[w,h+1] 37 | 38 | # 文字列を画面に表示(X座標,Y座標,文字列,色属性) 39 | def print(self, x:int, y:int, s: str, a:int): 40 | l = list(s) 41 | for n in range(len(l)): 42 | self.poke(x,y,ord(l[n]),a) 43 | x+=1 44 | 45 | # end of basic.py 46 | -------------------------------------------------------------------------------- /research/02_07_HistoryOfAthena.md: -------------------------------------------------------------------------------- 1 | # 02_ゲーム史研究: 07_社史編纂: アテナ(Athena) 2 | 3 | |属性|属性値| 4 | |---|--| 5 | |社名|株式会社アテナ| 6 | |本社所在地|〒162-0067 東京都新宿区富久町8-26(2013年12月11日時点)| 7 | |設立|1987年7月| 8 | |代表者|中村栄氏(2013年12月11日時点)| 9 | |売上高|2億82百万円(2005年3月期)| 10 | 11 | ## 沿革 12 | 13 | |日付|出来事| 14 | |---|------| 15 | |1987年7月|会社設立(代表:中村栄氏)| 16 | |2013年12月11日|東京地方裁判所にて,破産手続きの開始決定(破産管財人:古田茂弁護士)| 17 | 18 | ## タイトル一覧 19 | 20 | ### 極シリーズ 21 | 22 | |発売日|ハード|ジャンル|タイトル名| 23 | |-----|-----|-------|---------| 24 | |1993年6月11日|SFC|テーブル|プロ麻雀 極| 25 | |1994年7月20日|SFC|テーブル|プロ麻雀 極II| 26 | |1994年12月22日|GB|テーブル|プロ麻雀 極GB| 27 | |1995年6月30日|SFC|テーブル|プロ麻雀 極III| 28 | |1996年1月12日|SS|テーブル|プロ麻雀 極S| 29 | |1996年8月30日|PS1|テーブル|プロ麻雀 極PLUS| 30 | |1997年11月10日|Win|テーブル|プロ麻雀 極 for Windows| 31 | |1997年11月21日|N64|テーブル|プロ麻雀 極64| 32 | |1998年12月10日|PS|テーブル|プロ麻雀 極PLUSII| 33 | |1999年3月19日|GBC|テーブル|プロ麻雀 極GBII| 34 | |1999年10月7日|WS|テーブル|プロ麻雀 極 for WonderSwan| 35 | |1999年10月28日|PS|テーブル|プロ麻雀 極 天元戦編| 36 | |1999年12月2日|PS|テーブル|井出洋介の麻雀教室 〜プロ麻雀 極シリーズ 初級編〜| 37 | |2000年3月30日|DC|テーブル|プロ麻雀 極D| 38 | |2000年8月31日|PS2|テーブル|プロ麻雀 極NEXT| 39 | |2001年8月10日|GBA|テーブル|極 麻雀デラックス 未来戦士21| 40 | |2001年10月26日|Win|テーブル|プロ麻雀 極 天元戦編 for Windows| 41 | |2002年8月9日|GC|テーブル|極 麻雀DXII -The 4th MONDO21Cup Competition-| 42 | |2003年12月18日|PS2|テーブル|極 麻雀DX2 -The 4th MONDO21Cup Competition-| 43 | |2007年8月3日|Win|テーブル|プロ麻雀 極 NEXT for Windows Vista対応| 44 | 45 | 以上 -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/components/equippable.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | from equipment_types import EquipmentType 7 | 8 | if TYPE_CHECKING: 9 | from entity import Item 10 | 11 | 12 | class Equippable(BaseComponent): 13 | parent: Item 14 | 15 | def __init__( 16 | self, 17 | equipment_type: EquipmentType, 18 | power_bonus: int = 0, 19 | defense_bonus: int = 0, 20 | ): 21 | self.equipment_type = equipment_type 22 | 23 | self.power_bonus = power_bonus 24 | self.defense_bonus = defense_bonus 25 | 26 | 27 | class Dagger(Equippable): 28 | def __init__(self) -> None: 29 | super().__init__(equipment_type=EquipmentType.WEAPON, power_bonus=2) 30 | 31 | 32 | class Sword(Equippable): 33 | def __init__(self) -> None: 34 | super().__init__(equipment_type=EquipmentType.WEAPON, power_bonus=4) 35 | 36 | 37 | class LeatherArmor(Equippable): 38 | def __init__(self) -> None: 39 | super().__init__(equipment_type=EquipmentType.ARMOR, defense_bonus=1) 40 | 41 | 42 | class ChainMail(Equippable): 43 | def __init__(self) -> None: 44 | super().__init__(equipment_type=EquipmentType.ARMOR, defense_bonus=3) 45 | 46 | # end of equippable.py 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/components/equippable.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | from equipment_types import EquipmentType 7 | 8 | if TYPE_CHECKING: 9 | from entity import Item 10 | 11 | 12 | class Equippable(BaseComponent): 13 | parent: Item 14 | 15 | def __init__( 16 | self, 17 | equipment_type: EquipmentType, 18 | power_bonus: int = 0, 19 | defense_bonus: int = 0, 20 | ): 21 | self.equipment_type = equipment_type 22 | 23 | self.power_bonus = power_bonus 24 | self.defense_bonus = defense_bonus 25 | 26 | 27 | class Dagger(Equippable): 28 | def __init__(self) -> None: 29 | super().__init__(equipment_type=EquipmentType.WEAPON, power_bonus=2) 30 | 31 | 32 | class Sword(Equippable): 33 | def __init__(self) -> None: 34 | super().__init__(equipment_type=EquipmentType.WEAPON, power_bonus=4) 35 | 36 | 37 | class LeatherArmor(Equippable): 38 | def __init__(self) -> None: 39 | super().__init__(equipment_type=EquipmentType.ARMOR, defense_bonus=1) 40 | 41 | 42 | class ChainMail(Equippable): 43 | def __init__(self) -> None: 44 | super().__init__(equipment_type=EquipmentType.ARMOR, defense_bonus=3) 45 | 46 | # end of equippable.py 47 | -------------------------------------------------------------------------------- /pyxel/asteroids/Vec.py: -------------------------------------------------------------------------------- 1 | import math 2 | 3 | # 2D座標を扱う関数ライブラリ 4 | class Vec(): 5 | def __init__(self, x : float, y: float): 6 | self.x = x 7 | self.y = y 8 | 9 | # ベクトル加減算 10 | def sub(self, p): 11 | return Vec(self.x - p.x, self.y - p.y) 12 | def add(self, p): 13 | return Vec(self.x + p.x, self.y + p.y) 14 | 15 | # ベクトル乗算 16 | def mul(self, s): 17 | return Vec(s * self.x, s * self.y) 18 | 19 | # ベクトル正規化 20 | def norm(self): 21 | m = self.magV() 22 | return Vec(self.x/m, self.y/m) 23 | 24 | # ベクトル長 25 | def magV(self): 26 | return math.sqrt(self.x ** 2 + self.y ** 2) 27 | 28 | # ベクトル長(制限あり) 29 | def limitMag(self, n): 30 | if self.magV() > n: return (self.norm()).mul(n) 31 | else: return self 32 | 33 | # ベクトル回転 34 | def rotateV(self, r): 35 | return Vec( 36 | self.x * math.cos(r) - self.y * math.sin(r), 37 | self.x * math.sin(r) + self.y * math.cos(r) 38 | ) 39 | 40 | # 画面外に出たら反対から出現(トーラス化) 41 | def restoreToScreen(self): 42 | return Vec( 43 | self.cycleCoordinates(self.x), 44 | self.cycleCoordinates(self.y), 45 | ) 46 | 47 | # 同上 48 | def cycleCoordinates(self, x): 49 | if x < -160: return 320+x 50 | elif x > 160: return x-320 51 | else: return x 52 | 53 | # End of Vec.py 54 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/actions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | if TYPE_CHECKING: 6 | from engine import Engine 7 | from entity import Entity 8 | 9 | 10 | class Action: 11 | def perform(self, engine: Engine, entity: Entity) -> None: 12 | """Perform this action with the objects needed to determine its scope. 13 | 14 | `engine` is the scope this action is being performed in. 15 | 16 | `entity` is the object performing the action. 17 | 18 | This method must be overridden by Action subclasses. 19 | """ 20 | raise NotImplementedError() 21 | 22 | 23 | class EscapeAction(Action): 24 | def perform(self, engine: Engine, entity: Entity) -> None: 25 | raise SystemExit() 26 | 27 | 28 | class MovementAction(Action): 29 | def __init__(self, dx: int, dy: int): 30 | super().__init__() 31 | 32 | self.dx = dx 33 | self.dy = dy 34 | 35 | def perform(self, engine: Engine, entity: Entity) -> None: 36 | dest_x = entity.x + self.dx 37 | dest_y = entity.y + self.dy 38 | 39 | if not engine.game_map.in_bounds(dest_x, dest_y): 40 | return # Destination is out of bounds. 41 | if not engine.game_map.tiles["walkable"][dest_x, dest_y]: 42 | return # Destination is blocked by a tile. 43 | 44 | entity.move(self.dx, self.dy) 45 | 46 | # end of actions.py 47 | -------------------------------------------------------------------------------- /pyxel/nixie/Nixie.py: -------------------------------------------------------------------------------- 1 | # Nixie Tube Clock v0.1: Nixie Tube Clock in Pyxel/Python 2 | # Copyright (c) 2022 Kumogata Computing Laboratory. 3 | # All Rights Reserved. 4 | 5 | import pyxel 6 | 7 | class Nixie: 8 | 9 | # Variables 10 | f1 = 0 11 | f2 = 1 12 | f3 = 2 13 | f4 = 3 14 | 15 | # Constructor 16 | def __init__( self ): 17 | pyxel.init( 128, 64, title="Nixie Tube Clock v0.1", fps=20) 18 | pyxel.load("Nixie.pyxres") 19 | pyxel.run(self.update,self.draw) 20 | 21 | def update( self ): 22 | # do nothing 23 | """NONE""" 24 | self.f1 = pyxel.frame_count % 10000 // 1000 25 | self.f2 = pyxel.frame_count % 1000 // 100 26 | self.f3 = pyxel.frame_count % 100 // 10 27 | self.f4 = pyxel.frame_count % 10 28 | 29 | def draw( self ): 30 | pyxel.cls(0) 31 | pyxel.blt(32, 16, 0, 0, 0, 16, 32) # tube #1 32 | pyxel.blt(48, 16, 0, 0, 0, 16, 32) # tube #2 33 | pyxel.blt(64, 16, 0, 0, 0, 16, 32) # tube #3 34 | pyxel.blt(80, 16, 0, 0, 0, 16, 32) # tube #4 35 | 36 | pyxel.blt(32, 24, 0, self.f1*16, 48, 16, 16) # figure #1 37 | pyxel.blt(48, 24, 0, self.f2*16, 48, 16, 16) # figure #2 38 | pyxel.blt(64, 24, 0, self.f3*16, 48, 16, 16) # figure #3 39 | pyxel.blt(80, 24, 0, self.f4*16, 48, 16, 16) # figure #4 40 | 41 | # Main 42 | Nixie() 43 | 44 | # End of Nixie.py 45 | 46 | 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_names_at_mouse_location( 37 | x: int, y: int, engine: Engine 38 | ) -> None: 39 | mouse_x, mouse_y = engine.mouse_location 40 | 41 | names_at_mouse_location = get_names_at_location( 42 | x=mouse_x, y=mouse_y, game_map=engine.game_map 43 | ) 44 | 45 | color.text(x, y, names_at_mouse_location, 7) 46 | 47 | # end of render_functions.py 48 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_names_at_mouse_location( 37 | x: int, y: int, engine: Engine 38 | ) -> None: 39 | mouse_x, mouse_y = engine.mouse_location 40 | 41 | names_at_mouse_location = get_names_at_location( 42 | x=mouse_x, y=mouse_y, game_map=engine.game_map 43 | ) 44 | 45 | color.text(x, y, names_at_mouse_location, 7) 46 | 47 | # end of render_functions.py 48 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_names_at_mouse_location( 37 | x: int, y: int, engine: Engine 38 | ) -> None: 39 | mouse_x, mouse_y = engine.mouse_location 40 | 41 | names_at_mouse_location = get_names_at_location( 42 | x=mouse_x, y=mouse_y, game_map=engine.game_map 43 | ) 44 | 45 | color.text(x, y, names_at_mouse_location, 7) 46 | 47 | # end of render_functions.py 48 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/main.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import pyxel 4 | 5 | from engine import Engine 6 | import entity_factories 7 | from procgen import generate_dungeon 8 | 9 | def main() -> None: 10 | global engine 11 | 12 | screen_width = 80 13 | screen_height = 50 14 | 15 | map_width = 80 16 | map_height = 45 17 | 18 | room_max_size = 10 19 | room_min_size = 6 20 | max_rooms = 30 21 | max_monsters_per_room = 2 22 | 23 | player = copy.deepcopy(entity_factories.player) 24 | engine = Engine(player=player) 25 | 26 | engine.game_map = generate_dungeon( 27 | max_rooms=max_rooms, 28 | room_min_size=room_min_size, 29 | room_max_size=room_max_size, 30 | map_width=map_width, 31 | map_height=map_height, 32 | max_monsters_per_room=max_monsters_per_room, 33 | engine=engine, 34 | ) 35 | engine.update_fov() 36 | 37 | 38 | # Pyxel初期化 39 | pyxel.init( 40 | screen_width, 41 | screen_height, 42 | title="Yet Another Roguelike Tutorial", 43 | fps=30 44 | ) 45 | pyxel.run(update, draw) 46 | 47 | def update(): 48 | # メモ: イベントハンドラを呼ぶ 49 | global engine 50 | engine.event_handler.handle_events() 51 | 52 | def draw(): 53 | # メモ: 画面描画ルーチンを呼ぶ 54 | global engine 55 | engine.render() 56 | 57 | if __name__ == "__main__": 58 | main() 59 | 60 | # end of main.py 61 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | # メモ: パレット(pyxel既定) 4 | 5 | black = 0 6 | dark_blue = 1 7 | purple = 2 8 | green = 3 9 | brown = 4 10 | blue = 5 11 | light_purple = 6 12 | white = 7 13 | red = 8 14 | amber = 9 15 | yellow = 10 16 | light_green = 11 17 | light_blue = 12 18 | gray = 13 19 | pink = 14 20 | beige = 15 21 | 22 | player_atk = light_blue 23 | enemy_atk = gray 24 | 25 | player_die = pink 26 | enemy_die = beige 27 | needs_target = blue 28 | status_effect_applied = light_purple 29 | 30 | invalid = amber 31 | impossible = yellow 32 | error = purple 33 | 34 | welcome_text = light_purple 35 | health_recovered = green 36 | 37 | bar_text = white 38 | bar_filled = light_green 39 | bar_empty = red 40 | 41 | menu_title = yellow 42 | menu_text = white 43 | 44 | # メモ: 以下、色(color)とは直接関係ないコード(Pyxel関連) 45 | 46 | # メモ: コンソールサイズ(80x50) 47 | width = 80 48 | height = 50 49 | 50 | # メモ: 組込フォントのドット数(4x5) 51 | chr_x = 4 52 | chr_y = 5 53 | 54 | # メモ: ヘルパー関数 55 | def rect(x: int, y: int, w: int, h: int, col: int): 56 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 57 | 58 | def rectb(x: int, y: int, w: int, h: int, col: int): 59 | pyxel.rectb(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 60 | 61 | def text(x: int, y: int, s: str, col: int): 62 | pyxel.text(x*chr_x, y*chr_y, s, col) 63 | 64 | # テキストを中央に表示 65 | def textc(x: int, y: int, s: str, col: int): 66 | pyxel.text((x - len(s) // 2)*chr_x, y*chr_y, s, col) 67 | 68 | # end of color.py 69 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part3/main.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | from engine import Engine 4 | from entity import Entity 5 | from input_handlers import EventHandler 6 | from procgen import generate_dungeon 7 | 8 | def main() -> None: 9 | global engine 10 | 11 | screen_width = 80 12 | screen_height = 50 13 | 14 | map_width = 80 15 | map_height = 45 16 | 17 | room_max_size = 10 18 | room_min_size = 6 19 | max_rooms = 30 20 | 21 | event_handler = EventHandler() 22 | 23 | player = Entity(int(screen_width / 2), int(screen_height / 2), "@", 7) 24 | npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), "@", 10) 25 | entities = {npc, player} 26 | 27 | game_map = generate_dungeon( 28 | max_rooms=max_rooms, 29 | room_min_size=room_min_size, 30 | room_max_size=room_max_size, 31 | map_width=map_width, 32 | map_height=map_height, 33 | player=player 34 | ) 35 | 36 | engine = Engine(entities=entities, event_handler=event_handler, game_map=game_map, player=player) 37 | 38 | pyxel.init( 39 | screen_width, 40 | screen_height, 41 | title="Yet Another Roguelike Tutorial", 42 | fps=30 43 | ) 44 | pyxel.run(update, draw) 45 | 46 | def update(): 47 | global engine 48 | engine.handle_events() 49 | 50 | def draw(): 51 | global engine 52 | engine.render() 53 | 54 | if __name__ == "__main__": 55 | main() 56 | 57 | # end of main.py 58 | -------------------------------------------------------------------------------- /pyxel/sheep/Sheep.py: -------------------------------------------------------------------------------- 1 | import random 2 | import pyxel 3 | 4 | class Sheep: 5 | def __init__(self, x, y): 6 | self.p = None # 参照元 7 | self.x = x # x座標 8 | self.y = y # y座標 9 | self.sz = 2 # 大きさ 10 | self.energy = 20 # 体力 11 | self.col = random.randint( 6, 15 ) # 色 12 | 13 | def update(self): 14 | # 羊がランダムに動き回るようにする 15 | move = 1 # 任意の方向に移動するときの最大距離 16 | self.energy -= 1 17 | if self.energy <= 0: 18 | self.p.sheepList.remove(self) 19 | self.x += random.randint( -move, move ) 20 | self.y += random.randint( -move, move ) 21 | 22 | # Asteroids式の「丸め」 23 | if self.x >= self.p.width: 24 | self.x %= self.p.width 25 | if self.y >= self.p.height: 26 | self.y %= self.p.height 27 | if self.x < 0: 28 | self.x += self.p.width 29 | if self.y < 0: 30 | self.y += self.p.height 31 | 32 | # grassListの中から牧草区画を見つける 33 | xscl = int(self.x / self.p.patchSize) 34 | yscl = int(self.y / self.p.patchSize) 35 | 36 | grass = self.p.grassList[xscl * self.p.rows_of_grass + yscl] 37 | if not grass.eaten: 38 | self.energy += grass.energy 39 | grass.eaten = True 40 | 41 | pyxel.circ(self.x,self.y,self.sz,self.col) 42 | 43 | # End of Sheep.py 44 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | from components.base_component import BaseComponent 6 | from input_handlers import GameOverEventHandler 7 | from render_order import RenderOrder 8 | 9 | if TYPE_CHECKING: 10 | from entity import Actor 11 | 12 | class Fighter(BaseComponent): 13 | entity: Actor 14 | 15 | def __init__(self, hp: int, defense: int, power: int): 16 | self.max_hp = hp 17 | self._hp = hp 18 | self.defense = defense 19 | self.power = power 20 | 21 | @property 22 | def hp(self) -> int: 23 | return self._hp 24 | 25 | @hp.setter 26 | def hp(self, value: int) -> None: 27 | self._hp = max(0, min(value, self.max_hp)) 28 | if self._hp == 0 and self.entity.ai: 29 | self.die() 30 | 31 | def die(self) -> None: 32 | if self.engine.player is self.entity: 33 | death_message = "You died!" 34 | self.engine.event_handler = GameOverEventHandler(self.engine) 35 | else: 36 | death_message = f"{self.entity.name} is dead!" 37 | 38 | self.entity.char = "%" 39 | self.entity.color = 2 40 | self.entity.blocks_movement = False 41 | self.entity.ai = None 42 | self.entity.name = f"remains of {self.entity.name}" 43 | self.entity.render_order = RenderOrder.CORPSE 44 | 45 | print(death_message) 46 | 47 | # end of fighter.py 48 | -------------------------------------------------------------------------------- /pyxel/asteroids/Rock.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | from Vec import * 3 | 4 | class Rock(): 5 | def __init__(self, p : Vec, s : float, v : Vec): 6 | # 岩情報Rockは,座標Vec,サイズSize,速度Velocityから構成. 7 | self.p = p 8 | self.s = s 9 | self.v = v 10 | self.l = True 11 | 12 | # 岩形状 13 | self.r = [[+0.7, +0.5], 14 | [-0.1, +0.8], 15 | [-0.7, +0.6], 16 | [-0.9, -0.1], 17 | [-0.7, -0.9], 18 | [+0.0, -0.7], 19 | [+0.6, -0.8], 20 | [+0.9, -0.2], 21 | [+0.5, +0.1], 22 | [+0.7, +0.5]] 23 | 24 | # 座標pが,岩Rockに衝突したか否かを返却. 25 | # 岩座標rpから岩サイズsだけ離れた領域(円)に,座標pが含まれるか否かを返却. 26 | def collidesWith(self, p : Vec): 27 | rp = self.p 28 | rp = rp.sub(p) 29 | rp = rp.magV() 30 | return rp < self.s 31 | 32 | # 時間timeStep分だけ位置を更新. 33 | # 岩に弾が当たって,岩のサイズが7の場合は,ここに含まれる. 34 | def update(self, timeStep : float): 35 | self.p = self.p.add(self.v.mul(timeStep)) 36 | self.p = self.p.restoreToScreen() 37 | 38 | # 岩を描画 39 | def draw(self): 40 | for n in range(len(self.r)-1): 41 | pyxel.line( self.p.x+self.r[n][0]*self.s+160, 42 | self.p.y+self.r[n][1]*self.s+160, 43 | self.p.x+self.r[n+1][0]*self.s+160, 44 | self.p.y+self.r[n+1][1]*self.s+160, 45 | 7 ) 46 | 47 | # End of Rock.py 48 | -------------------------------------------------------------------------------- /hsp/doc/200724_HspNote.md: -------------------------------------------------------------------------------- 1 | ## HSPによる開発記 2 | 3 | ### 2020-07-25 4 | 5 | 昨日くらいから,hot soup proccessorという言語処理系に手を出しています.昔遊んだBASICのゲームを移植してみました.基本は仮想画面を作って,画面表示と当たり判定を同時にやることにしました.画面のちらつきも昔っぽいです.命令も大体分かったので,もう少し書いてみようかなと思います. 6 | 7 | ### 2020-10-18 8 | 9 | 雑誌 I/O 1976年11月号(創刊号)のp.28に掲載されていた「パーソナル・コンピュータで立体の等高線を得る」という記事を発見しました.BASICで球体を描くプログラムがあったので,HSPに移植してみました.ちなみに,記事を書かれたのは,ASCII創業者の西和彦氏です.最初は,I/Oで記事を書かれていたという歴史があるのですね. 10 | 11 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/hsp/ball/screenshots/hsp01.png) 12 | 13 | ### 2020-10-23 14 | 15 | あるホームページに掲載されていた「 マンデルブロート集合」という記事[1]を発見しました.マンデルブロート集合を描くプログラムがあったので,HSPに移植してみました. 16 | 17 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/hsp/mandel/screenshots/hsp02.png) 18 | 19 | 記事を書かれたのは,井村誠司氏です.高校の数学教師をされていた方のようです. 20 | - [1] http://imura.la.coocan.jp/40FractalCG/Mandel/mandel.html 21 | 22 | ### 2020-10-24 23 | 24 | 青色と黄色のグラデーションで表示すると,森田和郎氏の名作アルフォスっぽい仕上がりになりました. 25 | 26 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/hsp/mandel/screenshots/hsp03.png) 27 | 28 | ### 2021-01-08 29 | 30 | 非常にどうでもいいお知らせですが,昨年書いたHSPスクリプトをGitHubに上げました.リポジトリ名は,Gamesですが,ゲームではありません.2021年は,巣籠りで作業できるかもしれません.#HSP3 31 | 32 | ### 2021-01-09 33 | 34 | GitHub(*2)上にHSPスクリプトを公開しました.HSPスクリプトエディタに読み込んでいただければ,動作するはずです.version 3.5.1を利用しています.健康のために,プライベートではコードを極力書かないよう心がけています.が,2021年は少し書くかもしれません.#HSP3 35 | - (*2) https://github.com/jay-kumogata/RetroGames 36 | 37 | ### 2021-05-20 38 | 39 | 日本語を少し直しました.ですます調に統一しました. 40 | 41 | ___ 42 | Copyright (c) 2020-2021 Kumogata Jay. All Rights Reserved. 43 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/main.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import pyxel 4 | 5 | from engine import Engine 6 | import entity_factories 7 | from input_handlers import EventHandler 8 | from procgen import generate_dungeon 9 | 10 | def main() -> None: 11 | global engine 12 | 13 | screen_width = 80 14 | screen_height = 50 15 | 16 | map_width = 80 17 | map_height = 45 18 | 19 | room_max_size = 10 20 | room_min_size = 6 21 | max_rooms = 30 22 | max_monsters_per_room = 2 23 | 24 | event_handler = EventHandler() 25 | 26 | player = copy.deepcopy(entity_factories.player) 27 | 28 | game_map = generate_dungeon( 29 | max_rooms=max_rooms, 30 | room_min_size=room_min_size, 31 | room_max_size=room_max_size, 32 | map_width=map_width, 33 | map_height=map_height, 34 | max_monsters_per_room=max_monsters_per_room, 35 | player=player 36 | ) 37 | 38 | engine = Engine(event_handler=event_handler, game_map=game_map, player=player) 39 | 40 | # メモ: Pyxel初期化 41 | pyxel.init( 42 | screen_width, 43 | screen_height, 44 | title="Yet Another Roguelike Tutorial", 45 | fps=30 46 | ) 47 | pyxel.run(update, draw) 48 | 49 | def update(): 50 | # メモ: イベントハンドラ(キー操作)を呼ぶ 51 | global engine 52 | engine.handle_events() 53 | 54 | def draw(): 55 | # メモ: 画面描画ルーチンを呼ぶ 56 | global engine 57 | engine.render() 58 | 59 | if __name__ == "__main__": 60 | main() 61 | 62 | # end of main.py 63 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 21 | ] 22 | ) 23 | 24 | 25 | def new_tile( 26 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 27 | walkable: int, 28 | transparent: int, 29 | dark: Tuple[int, int, int], 30 | light: Tuple[int, int, int] 31 | ) -> np.ndarray: 32 | """Helper function for defining individual tile types """ 33 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 34 | 35 | # SHROUD represents unexplored, unseen tiles 36 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 37 | 38 | floor = new_tile( 39 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 40 | ) 41 | wall = new_tile( 42 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 43 | ) 44 | 45 | # end of tile_types.py 46 | -------------------------------------------------------------------------------- /pyxel/sombrero/sombrero.py: -------------------------------------------------------------------------------- 1 | # 2 | # 「ソンブレロ(メキシカンハット)デモ」 3 | # 「瞬時に拡散!古いパソコンでメキシカンハットが蘇った日」を参考にしました 4 | # cf. https://togetter.com/li/2390318 5 | # 6 | # Jun 25, 2024 ver.1 (Pyxelによる実装) 7 | # Jun 26, 2024 ver.2 (SuperChip8模擬) 8 | # 9 | # -*- coding: utf-8 -*- 10 | import math 11 | import pyxel 12 | import random 13 | import numpy as np 14 | 15 | def init(): 16 | global d,dr 17 | 18 | d=np.full((160), 100) 19 | dr = math.pi / 180 20 | 21 | def update(): 22 | global d,dr 23 | """ NONE """ 24 | return 25 | 26 | # 画面描画 27 | def draw(): 28 | global d,dr 29 | 30 | for y in range(-180,180,6): 31 | for x in range(-180,180,4): 32 | r=dr*math.sqrt(x*x+y*y) 33 | z=100*math.cos(r)-30*math.cos(3*r) 34 | sx=int(80+x/3-y/6) 35 | sy=int(40-y/6-z/4) 36 | if sx<0 or sx>=160: continue 37 | if d[sx]<=sy: continue 38 | zz=int((z+100)*0.035)+1 39 | c=0 40 | if zz==1 or zz==3 or zz==5 or zz==7: c += 2 41 | if zz==2 or zz==3 or zz>=6: c += 4 42 | if zz>=4: c += 8 43 | pyxel.pset(sx*2,sy*2,c) 44 | #pyxel.pset(sx,sy,c) 45 | #if c>0: pyxel.pset(sx*128/160,sy*64/100,7) 46 | d[sx]=sy 47 | 48 | # 初期化 49 | init() 50 | pyxel.init( 320, 200, title="sombrero", fps=20 ) 51 | #pyxel.init( 160, 100, title="sombrero", fps=20 ) 52 | #pyxel.init( 128, 64, title="sombrero", fps=20 ) 53 | pyxel.cls(0) 54 | pyxel.run(update, draw) 55 | 56 | # end of sombrero.py 57 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/main.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | from engine import Engine 4 | from entity import Entity 5 | from input_handlers import EventHandler 6 | from procgen import generate_dungeon 7 | 8 | def main() -> None: 9 | global engine 10 | 11 | screen_width = 80 12 | screen_height = 50 13 | 14 | map_width = 80 15 | map_height = 45 16 | 17 | room_max_size = 10 18 | room_min_size = 6 19 | max_rooms = 30 20 | 21 | event_handler = EventHandler() 22 | 23 | player = Entity(int(screen_width / 2), int(screen_height / 2), "@", 7) 24 | npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), "@", 10) 25 | entities = {npc, player} 26 | 27 | game_map = generate_dungeon( 28 | max_rooms=max_rooms, 29 | room_min_size=room_min_size, 30 | room_max_size=room_max_size, 31 | map_width=map_width, 32 | map_height=map_height, 33 | player=player 34 | ) 35 | 36 | engine = Engine(entities=entities, event_handler=event_handler, game_map=game_map, player=player) 37 | 38 | pyxel.init( 39 | screen_width, 40 | screen_height, 41 | title="Yet Another Roguelike Tutorial", 42 | fps=30 43 | ) 44 | pyxel.run(update, draw) 45 | 46 | def update(): 47 | # メモ: イベントハンドラ(キー操作)を呼ぶ 48 | global engine 49 | engine.handle_events() 50 | 51 | def draw(): 52 | # メモ: 画面描画ルーチンを呼ぶ 53 | global engine 54 | engine.render() 55 | 56 | if __name__ == "__main__": 57 | main() 58 | 59 | # end of main.py 60 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/game_map.py: -------------------------------------------------------------------------------- 1 | import numpy as np # type: ignore 2 | import pyxel 3 | 4 | import tile_types 5 | 6 | class GameMap: 7 | def __init__(self, width: int, height: int): 8 | self.width, self.height = width, height 9 | self.tiles = np.full((width, height), fill_value=tile_types.wall, order="F") 10 | 11 | self.visible = np.full((width, height), fill_value=False, order="F") # Tiles the player can currently see 12 | self.explored = np.full((width, height), fill_value=False, order="F") # Tiles the player has seen before 13 | 14 | def in_bounds(self, x: int, y: int) -> bool: 15 | """Return True if x and y are inside of the bounds of this map.""" 16 | return 0 <= x < self.width and 0 <= y < self.height 17 | 18 | def render(self) -> None: 19 | """ 20 | Renders the map. 21 | 22 | If a tile is in the "visible" array, then draw it with the "light" colors. 23 | If it isn't, but it's in the "explored" array, then draw it with the "dark" colors. 24 | Otherwise, the default is "SHROUD". 25 | """ 26 | 27 | # メモ: pyxel対応のため、愚直に表示(現時点では点描) 28 | for x in range(self.width): 29 | for y in range(self.height): 30 | if self.visible[x][y]: 31 | pyxel.pset(x,y,self.tiles["light"][x,y]["fg"]) 32 | elif self.explored[x][y]: 33 | pyxel.pset(x,y,self.tiles["dark"][x,y]["fg"]) 34 | else: 35 | pyxel.pset(x,y,tile_types.SHROUD["fg"]) 36 | 37 | # end of game_map.py 38 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/tile_types.py: -------------------------------------------------------------------------------- 1 | # 2024/04/25 2 | 3 | from typing import Tuple 4 | 5 | import numpy as np # type: ignore 6 | 7 | # Tile graphics structured type 8 | graphic_dt = np.dtype( 9 | [ 10 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 11 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 12 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 13 | ] 14 | ) 15 | 16 | # Tile struct used for statically defined tile data. 17 | tile_dt = np.dtype( 18 | [ 19 | ("walkable", np.bool_), # True if this tile can be walked over. 20 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 21 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 22 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 23 | ] 24 | ) 25 | 26 | 27 | def new_tile( 28 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 29 | walkable: int, 30 | transparent: int, 31 | dark: Tuple[int, int, int], 32 | light: Tuple[int, int, int] 33 | ) -> np.ndarray: 34 | """Helper function for defining individual tile types """ 35 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 36 | 37 | # SHROUD represents unexplored, unseen tiles 38 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 39 | 40 | floor = new_tile( 41 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 42 | ) 43 | wall = new_tile( 44 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 45 | ) 46 | 47 | # end of tile_types.py 48 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 21 | ] 22 | ) 23 | 24 | 25 | def new_tile( 26 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 27 | walkable: int, 28 | transparent: int, 29 | dark: Tuple[int, int, int], 30 | light: Tuple[int, int, int] 31 | ) -> np.ndarray: 32 | """Helper function for defining individual tile types """ 33 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 34 | 35 | # SHROUD represents unexplored, unseen tiles 36 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 37 | 38 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 39 | floor = new_tile( 40 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 41 | ) 42 | wall = new_tile( 43 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 44 | ) 45 | 46 | # end of tile_types.py 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 21 | ] 22 | ) 23 | 24 | 25 | def new_tile( 26 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 27 | walkable: int, 28 | transparent: int, 29 | dark: Tuple[int, int, int], 30 | light: Tuple[int, int, int] 31 | ) -> np.ndarray: 32 | """Helper function for defining individual tile types """ 33 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 34 | 35 | # SHROUD represents unexplored, unseen tiles 36 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 37 | 38 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 39 | floor = new_tile( 40 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 41 | ) 42 | wall = new_tile( 43 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 44 | ) 45 | 46 | # end of tile_types.py 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 21 | ] 22 | ) 23 | 24 | 25 | def new_tile( 26 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 27 | walkable: int, 28 | transparent: int, 29 | dark: Tuple[int, int, int], 30 | light: Tuple[int, int, int] 31 | ) -> np.ndarray: 32 | """Helper function for defining individual tile types """ 33 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 34 | 35 | # SHROUD represents unexplored, unseen tiles 36 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 37 | 38 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 39 | floor = new_tile( 40 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 41 | ) 42 | wall = new_tile( 43 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 44 | ) 45 | 46 | # end of tile_types.py 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 21 | ] 22 | ) 23 | 24 | 25 | def new_tile( 26 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 27 | walkable: int, 28 | transparent: int, 29 | dark: Tuple[int, int, int], 30 | light: Tuple[int, int, int] 31 | ) -> np.ndarray: 32 | """Helper function for defining individual tile types """ 33 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 34 | 35 | # SHROUD represents unexplored, unseen tiles 36 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 37 | 38 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 39 | floor = new_tile( 40 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 41 | ) 42 | wall = new_tile( 43 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 44 | ) 45 | 46 | # end of tile_types.py 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | 5 | # Tile graphics structured type 6 | graphic_dt = np.dtype( 7 | [ 8 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 9 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 10 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 11 | ] 12 | ) 13 | 14 | # Tile struct used for statically defined tile data. 15 | tile_dt = np.dtype( 16 | [ 17 | ("walkable", np.bool_), # True if this tile can be walked over. 18 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 19 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 20 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 21 | ] 22 | ) 23 | 24 | 25 | def new_tile( 26 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 27 | walkable: int, 28 | transparent: int, 29 | dark: Tuple[int, int, int], 30 | light: Tuple[int, int, int] 31 | ) -> np.ndarray: 32 | """Helper function for defining individual tile types """ 33 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 34 | 35 | # SHROUD represents unexplored, unseen tiles 36 | SHROUD = np.array((ord(" "), 0, 7), dtype=graphic_dt) 37 | 38 | # メモ: 床と壁において, 光が当たっていない場合(dark)と当たっている場合(light)の情報 39 | floor = new_tile( 40 | walkable=True, transparent=True, dark=(ord(" "), 12, 1), light=(ord(" "), 10, 11), 41 | ) 42 | wall = new_tile( 43 | walkable=False, transparent=False, dark=(ord(" "), 1, 2), light=(ord(" "), 9, 13), 44 | ) 45 | 46 | # end of tile_types.py 47 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | pyxel.rect(0*color.chr_x, 45*color.chr_y, total_width*color.chr_x, 1*color.chr_y, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | pyxel.rect( 33 | 0*color.chr_x, 45*color.chr_y, bar_width*color.chr_x, 1*color.chr_y, color.bar_filled 34 | ) 35 | 36 | pyxel.text(1*color.chr_x, 45*color.chr_y, f"HP: {current_value}/{maximum_value}", color.bar_text) 37 | 38 | def render_names_at_mouse_location( 39 | x: int, y: int, engine: Engine 40 | ) -> None: 41 | mouse_x, mouse_y = engine.mouse_location 42 | 43 | names_at_mouse_location = get_names_at_location( 44 | x=mouse_x, y=mouse_y, game_map=engine.game_map 45 | ) 46 | 47 | pyxel.text(x*color.chr_x, y*color.chr_y, names_at_mouse_location, 7) 48 | 49 | # end of render_functions.py 50 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components import consumable 3 | from components.fighter import Fighter 4 | from components.inventory import Inventory 5 | from entity import Actor, Item 6 | 7 | player = Actor( 8 | char="@", 9 | color=7, 10 | name="Player", 11 | ai_cls=HostileEnemy, 12 | fighter=Fighter(hp=30, defense=2, power=5), 13 | inventory=Inventory(capacity=26), 14 | ) 15 | 16 | orc = Actor( 17 | char="o", 18 | color=8, 19 | name="Orc", 20 | ai_cls=HostileEnemy, 21 | fighter=Fighter(hp=10, defense=0, power=3), 22 | inventory=Inventory(capacity=0), 23 | ) 24 | troll = Actor( 25 | char="T", 26 | color=9, 27 | name="Troll", 28 | ai_cls=HostileEnemy, 29 | fighter=Fighter(hp=16, defense=1, power=4), 30 | inventory=Inventory(capacity=0), 31 | ) 32 | 33 | confusion_scroll = Item( 34 | char="~", 35 | color=13, 36 | name="Confusion Scroll", 37 | consumable=consumable.ConfusionConsumable(number_of_turns=10), 38 | ) 39 | health_potion = Item( 40 | char="!", 41 | color=11, 42 | name="Health Potion", 43 | consumable=consumable.HealingConsumable(amount=4), 44 | ) 45 | lightning_scroll = Item( 46 | char="~", 47 | color=12, 48 | name="Lightning Scroll", 49 | consumable=consumable.LightningDamageConsumable(damage=20, maximum_range=5), 50 | ) 51 | fireball_scroll = Item( 52 | char="~", 53 | color=8, 54 | name="Fireball Scroll", 55 | consumable=consumable.FireballDamageConsumable(damage=12, radius=3), 56 | ) 57 | 58 | # end of entity_factories.py 59 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components import consumable 3 | from components.fighter import Fighter 4 | from components.inventory import Inventory 5 | from entity import Actor, Item 6 | 7 | player = Actor( 8 | char="@", 9 | color=7, 10 | name="Player", 11 | ai_cls=HostileEnemy, 12 | fighter=Fighter(hp=30, defense=2, power=5), 13 | inventory=Inventory(capacity=26), 14 | ) 15 | 16 | orc = Actor( 17 | char="o", 18 | color=8, 19 | name="Orc", 20 | ai_cls=HostileEnemy, 21 | fighter=Fighter(hp=10, defense=0, power=3), 22 | inventory=Inventory(capacity=0), 23 | ) 24 | troll = Actor( 25 | char="T", 26 | color=9, 27 | name="Troll", 28 | ai_cls=HostileEnemy, 29 | fighter=Fighter(hp=16, defense=1, power=4), 30 | inventory=Inventory(capacity=0), 31 | ) 32 | 33 | confusion_scroll = Item( 34 | char="~", 35 | color=13, 36 | name="Confusion Scroll", 37 | consumable=consumable.ConfusionConsumable(number_of_turns=10), 38 | ) 39 | health_potion = Item( 40 | char="!", 41 | color=11, 42 | name="Health Potion", 43 | consumable=consumable.HealingConsumable(amount=4), 44 | ) 45 | lightning_scroll = Item( 46 | char="~", 47 | color=12, 48 | name="Lightning Scroll", 49 | consumable=consumable.LightningDamageConsumable(damage=20, maximum_range=5), 50 | ) 51 | fireball_scroll = Item( 52 | char="~", 53 | color=8, 54 | name="Fireball Scroll", 55 | consumable=consumable.FireballDamageConsumable(damage=12, radius=3), 56 | ) 57 | 58 | # end of entity_factories.py 59 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part6/engine.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pyxel 6 | 7 | from tcod.context import Context 8 | from tcod.console import Console 9 | from tcod.map import compute_fov 10 | 11 | from input_handlers import MainGameEventHandler 12 | 13 | if TYPE_CHECKING: 14 | from entity import Entity 15 | from game_map import GameMap 16 | from input_handlers import EventHandler 17 | 18 | class Engine: 19 | game_map: GameMap 20 | 21 | def __init__(self, player: Entity): 22 | self.event_handler: EventHandler = MainGameEventHandler(self) 23 | self.player = player 24 | 25 | def handle_enemy_turns(self) -> None: 26 | for entity in set(self.game_map.actors) - {self.player}: 27 | if entity.ai: 28 | entity.ai.perform() 29 | 30 | def update_fov(self) -> None: 31 | """Recompute the visible area based on the players point of view.""" 32 | self.game_map.visible[:] = compute_fov( 33 | self.game_map.tiles["transparent"], 34 | (self.player.x, self.player.y), 35 | radius=8, 36 | ) 37 | # If a tile is "visible" it should be added to "explored". 38 | self.game_map.explored |= self.game_map.visible 39 | 40 | def render(self) -> None: 41 | pyxel.cls(0) 42 | self.game_map.render() 43 | 44 | #console.print( 45 | # x=1, 46 | # y=47, 47 | # string=f"HP: {self.player.fighter.hp}/{self.player.fighter.max_hp}", 48 | #) 49 | pyxel.line(1,47,6,47,7) # TODO: HitPoint表示(キャラ表示に変更時に) 50 | 51 | # end of engine.py 52 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/main.py: -------------------------------------------------------------------------------- 1 | import copy 2 | 3 | import pyxel 4 | 5 | import color 6 | from engine import Engine 7 | import entity_factories 8 | from procgen import generate_dungeon 9 | 10 | def main() -> None: 11 | global engine 12 | 13 | screen_width = 80 14 | screen_height = 50 15 | 16 | map_width = 80 17 | map_height = 43 18 | 19 | room_max_size = 10 20 | room_min_size = 6 21 | max_rooms = 30 22 | max_monsters_per_room = 2 23 | 24 | player = copy.deepcopy(entity_factories.player) 25 | engine = Engine(player=player) 26 | 27 | engine.game_map = generate_dungeon( 28 | max_rooms=max_rooms, 29 | room_min_size=room_min_size, 30 | room_max_size=room_max_size, 31 | map_width=map_width, 32 | map_height=map_height, 33 | max_monsters_per_room=max_monsters_per_room, 34 | engine=engine, 35 | ) 36 | engine.update_fov() 37 | 38 | engine.message_log.add_message( 39 | "Hello and welcome, adventurer, to yet another dungeon!", color.welcome_text 40 | ) 41 | 42 | # Pyxel初期化 43 | pyxel.init( 44 | screen_width * color.chr_x, 45 | screen_height * color.chr_y, 46 | title="Yet Another Roguelike Tutorial", 47 | fps=30 48 | ) 49 | pyxel.mouse(True) # メモ: マウスを表示 50 | pyxel.run(update, draw) 51 | 52 | def draw(): 53 | # メモ: 画面描画ルーチンを呼ぶ 54 | global engine 55 | pyxel.cls(0) 56 | engine.event_handler.on_render() 57 | 58 | def update(): 59 | # メモ: イベントハンドラを呼ぶ 60 | global engine 61 | engine.event_handler.handle_events() 62 | 63 | if __name__ == "__main__": 64 | main() 65 | 66 | # end of main.py 67 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | from components.base_component import BaseComponent 7 | from input_handlers import GameOverEventHandler 8 | from render_order import RenderOrder 9 | 10 | if TYPE_CHECKING: 11 | from entity import Actor 12 | 13 | class Fighter(BaseComponent): 14 | entity: Actor 15 | 16 | def __init__(self, hp: int, defense: int, power: int): 17 | self.max_hp = hp 18 | self._hp = hp 19 | self.defense = defense 20 | self.power = power 21 | 22 | @property 23 | def hp(self) -> int: 24 | return self._hp 25 | 26 | @hp.setter 27 | def hp(self, value: int) -> None: 28 | self._hp = max(0, min(value, self.max_hp)) 29 | if self._hp == 0 and self.entity.ai: 30 | self.die() 31 | 32 | def die(self) -> None: 33 | if self.engine.player is self.entity: 34 | death_message = "You died!" 35 | death_message_color = color.player_die 36 | self.engine.event_handler = GameOverEventHandler(self.engine) 37 | else: 38 | death_message = f"{self.entity.name} is dead!" 39 | death_message_color = color.enemy_die 40 | 41 | self.entity.char = "%" 42 | self.entity.color = 2 43 | self.entity.blocks_movement = False 44 | self.entity.ai = None 45 | self.entity.name = f"remains of {self.entity.name}" 46 | self.entity.render_order = RenderOrder.CORPSE 47 | 48 | self.engine.message_log.add_message(death_message, death_message_color) 49 | 50 | # end of fighter.py 51 | -------------------------------------------------------------------------------- /pyxel/sheep/SheepAndGrass.py: -------------------------------------------------------------------------------- 1 | # 2 | # Pyxelを使った「食事をする羊のプログラム」 3 | # 書籍「Pythonではじめる数学の冒険―プログラミングで図解する代数、幾何学、三角関数」を参考にしました. 4 | # https://www.oreilly.co.jp/books/9784873119304/ 5 | # 6 | # Apr 19, 2024 ver.1 (Pyxelへ移植) 7 | # 8 | # -*- coding: utf-8 -*- 9 | import random 10 | import pyxel 11 | from Sheep import * 12 | from Grass import * 13 | 14 | class SheepAndGrass: 15 | 16 | def __init__( self ): 17 | 18 | # ウィンドウサイズ 19 | self.width = 128 20 | self.height = 128 21 | 22 | self.sheepList = [] # 羊用のリスト 23 | self.grassList = [] # 牧草用のリスト 24 | self.patchSize = 4 # 牧草の1区画の大きさ 25 | self.rows_of_grass = int( self.height / self.patchSize) 26 | 27 | # 羊を作る 28 | for n in range(20): 29 | sheep = Sheep(random.randint(0, self.width),random.randint(0, self.height)) 30 | sheep.p = self 31 | self.sheepList.append(sheep) 32 | 33 | # 牧草を作る 34 | for x in range(0, self.width, self.patchSize): 35 | for y in range(0, self.height, self.patchSize): 36 | self.grassList.append(Grass(x, y, self.patchSize)) 37 | 38 | # Pyxel初期化 39 | pyxel.init( self.width, self.height, title="SheepAndGrass", fps=10) 40 | pyxel.run(self.update, self.draw) 41 | 42 | def update(self): 43 | """NONE""" 44 | def draw(self): 45 | pyxel.cls(1) 46 | 47 | # 先に牧草を更新 48 | for grass in self.grassList: 49 | grass.update() 50 | 51 | # 続いて羊を更新 52 | for sheep in self.sheepList: 53 | sheep.update() 54 | 55 | # Main 56 | SheepAndGrass() 57 | 58 | # End of SheepAndGrass.py 59 | 60 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/engine.py: -------------------------------------------------------------------------------- 1 | from typing import Iterable, Any 2 | 3 | import pyxel 4 | from tcod.map import compute_fov 5 | 6 | from actions import EscapeAction, MovementAction 7 | from entity import Entity 8 | from game_map import GameMap 9 | from input_handlers import EventHandler 10 | 11 | class Engine: 12 | def __init__(self, event_handler: EventHandler, game_map: GameMap, player: Entity): 13 | self.event_handler = event_handler 14 | self.game_map = game_map 15 | self.player = player 16 | self.update_fov() 17 | 18 | def handle_enemy_turns(self) -> None: 19 | for entity in self.game_map.entities - {self.player}: 20 | print(f'The {entity.name} wonders when it will get to take a real turn.') 21 | 22 | def handle_events(self) -> None: 23 | # メモ: pyxel対応として、直接キーバッファを監視するように変更 24 | action = self.event_handler.dispatch() 25 | 26 | if action is None: 27 | return 28 | 29 | action.perform(self, self.player) 30 | self.handle_enemy_turns() 31 | self.update_fov() # Update the FOV before the players next action. 32 | 33 | def update_fov(self) -> None: 34 | """Recompute the visible area based on the players point of view.""" 35 | self.game_map.visible[:] = compute_fov( 36 | self.game_map.tiles["transparent"], 37 | (self.player.x, self.player.y), 38 | radius=8, 39 | ) 40 | # If a tile is "visible" it should be added to "explored". 41 | self.game_map.explored |= self.game_map.visible 42 | 43 | 44 | def render(self) -> None: 45 | pyxel.cls(0) 46 | self.game_map.render() 47 | 48 | # end of engine.py 49 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part4/engine.py: -------------------------------------------------------------------------------- 1 | from typing import Set, Iterable, Any 2 | 3 | import pyxel 4 | from tcod.map import compute_fov 5 | 6 | from actions import EscapeAction, MovementAction 7 | from entity import Entity 8 | from game_map import GameMap 9 | from input_handlers import EventHandler 10 | 11 | class Engine: 12 | def __init__(self, entities: Set[Entity], event_handler: EventHandler, game_map: GameMap, player: Entity): 13 | self.entities = entities 14 | self.event_handler = event_handler 15 | self.game_map = game_map 16 | self.player = player 17 | self.update_fov() 18 | 19 | def handle_events(self) -> None: 20 | # メモ: pyxel対応として、直接キーバッファを監視するように変更 21 | action = self.event_handler.dispatch() 22 | 23 | if action is None: 24 | return 25 | 26 | action.perform(self, self.player) 27 | 28 | self.update_fov() # Update the FOV before the players next action. 29 | 30 | def update_fov(self) -> None: 31 | """Recompute the visible area based on the players point of view.""" 32 | self.game_map.visible[:] = compute_fov( 33 | self.game_map.tiles["transparent"], 34 | (self.player.x, self.player.y), 35 | radius=8, 36 | ) 37 | # If a tile is "visible" it should be added to "explored". 38 | self.game_map.explored |= self.game_map.visible 39 | 40 | 41 | def render(self) -> None: 42 | pyxel.cls(0) 43 | self.game_map.render() 44 | for entity in self.entities: 45 | # Only print entities that are in the FOV 46 | if self.game_map.visible[entity.x, entity.y]: 47 | pyxel.pset(entity.x, entity.y, entity.color) 48 | 49 | # end of engine.py 50 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components import consumable 3 | from components.fighter import Fighter 4 | from components.inventory import Inventory 5 | from components.level import Level 6 | from entity import Actor, Item 7 | 8 | player = Actor( 9 | char="@", 10 | color=7, 11 | name="Player", 12 | ai_cls=HostileEnemy, 13 | fighter=Fighter(hp=30, defense=2, power=5), 14 | inventory=Inventory(capacity=26), 15 | level=Level(level_up_base=200), 16 | ) 17 | 18 | orc = Actor( 19 | char="o", 20 | color=8, 21 | name="Orc", 22 | ai_cls=HostileEnemy, 23 | fighter=Fighter(hp=10, defense=0, power=3), 24 | inventory=Inventory(capacity=0), 25 | level=Level(xp_given=35), 26 | ) 27 | troll = Actor( 28 | char="T", 29 | color=9, 30 | name="Troll", 31 | ai_cls=HostileEnemy, 32 | fighter=Fighter(hp=16, defense=1, power=4), 33 | inventory=Inventory(capacity=0), 34 | level=Level(xp_given=100), 35 | ) 36 | 37 | confusion_scroll = Item( 38 | char="~", 39 | color=13, 40 | name="Confusion Scroll", 41 | consumable=consumable.ConfusionConsumable(number_of_turns=10), 42 | ) 43 | health_potion = Item( 44 | char="!", 45 | color=11, 46 | name="Health Potion", 47 | consumable=consumable.HealingConsumable(amount=4), 48 | ) 49 | lightning_scroll = Item( 50 | char="~", 51 | color=12, 52 | name="Lightning Scroll", 53 | consumable=consumable.LightningDamageConsumable(damage=20, maximum_range=5), 54 | ) 55 | fireball_scroll = Item( 56 | char="~", 57 | color=8, 58 | name="Fireball Scroll", 59 | consumable=consumable.FireballDamageConsumable(damage=12, radius=3), 60 | ) 61 | 62 | # end of entity_factories.py 63 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/entity_factories.py: -------------------------------------------------------------------------------- 1 | from components.ai import HostileEnemy 2 | from components import consumable 3 | from components.fighter import Fighter 4 | from components.inventory import Inventory 5 | from components.level import Level 6 | from entity import Actor, Item 7 | 8 | player = Actor( 9 | char="@", 10 | color=7, 11 | name="Player", 12 | ai_cls=HostileEnemy, 13 | fighter=Fighter(hp=30, defense=2, power=5), 14 | inventory=Inventory(capacity=26), 15 | level=Level(level_up_base=200), 16 | ) 17 | 18 | orc = Actor( 19 | char="o", 20 | color=8, 21 | name="Orc", 22 | ai_cls=HostileEnemy, 23 | fighter=Fighter(hp=10, defense=0, power=3), 24 | inventory=Inventory(capacity=0), 25 | level=Level(xp_given=35), 26 | ) 27 | troll = Actor( 28 | char="T", 29 | color=9, 30 | name="Troll", 31 | ai_cls=HostileEnemy, 32 | fighter=Fighter(hp=16, defense=1, power=4), 33 | inventory=Inventory(capacity=0), 34 | level=Level(xp_given=100), 35 | ) 36 | 37 | confusion_scroll = Item( 38 | char="~", 39 | color=13, 40 | name="Confusion Scroll", 41 | consumable=consumable.ConfusionConsumable(number_of_turns=10), 42 | ) 43 | health_potion = Item( 44 | char="!", 45 | color=11, 46 | name="Health Potion", 47 | consumable=consumable.HealingConsumable(amount=4), 48 | ) 49 | lightning_scroll = Item( 50 | char="~", 51 | color=12, 52 | name="Lightning Scroll", 53 | consumable=consumable.LightningDamageConsumable(damage=20, maximum_range=5), 54 | ) 55 | fireball_scroll = Item( 56 | char="~", 57 | color=8, 58 | name="Fireball Scroll", 59 | consumable=consumable.FireballDamageConsumable(damage=12, radius=3), 60 | ) 61 | 62 | # end of entity_factories.py 63 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Tuple, TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_dungeon_level( 37 | dungeon_level: int, location: Tuple[int, int] 38 | ) -> None: 39 | """ 40 | Render the level the player is currently on, at the given location. 41 | """ 42 | x, y = location 43 | 44 | color.text(x, y, f"Dungeon level: {dungeon_level}", color.white) 45 | 46 | def render_names_at_mouse_location( 47 | x: int, y: int, engine: Engine 48 | ) -> None: 49 | mouse_x, mouse_y = engine.mouse_location 50 | 51 | names_at_mouse_location = get_names_at_location( 52 | x=mouse_x, y=mouse_y, game_map=engine.game_map 53 | ) 54 | 55 | color.text(x, y, names_at_mouse_location, color.white) 56 | 57 | # end of render_functions.py 58 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Tuple, TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_dungeon_level( 37 | dungeon_level: int, location: Tuple[int, int] 38 | ) -> None: 39 | """ 40 | Render the level the player is currently on, at the given location. 41 | """ 42 | x, y = location 43 | 44 | color.text(x, y, f"Dungeon level: {dungeon_level}", color.white) 45 | 46 | def render_names_at_mouse_location( 47 | x: int, y: int, engine: Engine 48 | ) -> None: 49 | mouse_x, mouse_y = engine.mouse_location 50 | 51 | names_at_mouse_location = get_names_at_location( 52 | x=mouse_x, y=mouse_y, game_map=engine.game_map 53 | ) 54 | 55 | color.text(x, y, names_at_mouse_location, color.white) 56 | 57 | # end of render_functions.py 58 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Tuple, TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_dungeon_level( 37 | dungeon_level: int, location: Tuple[int, int] 38 | ) -> None: 39 | """ 40 | Render the level the player is currently on, at the given location. 41 | """ 42 | x, y = location 43 | 44 | color.text(x, y, f"Dungeon level: {dungeon_level}", color.white) 45 | 46 | def render_names_at_mouse_location( 47 | x: int, y: int, engine: Engine 48 | ) -> None: 49 | mouse_x, mouse_y = engine.mouse_location 50 | 51 | names_at_mouse_location = get_names_at_location( 52 | x=mouse_x, y=mouse_y, game_map=engine.game_map 53 | ) 54 | 55 | color.text(x, y, names_at_mouse_location, color.white) 56 | 57 | # end of render_functions.py 58 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/render_functions.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Tuple, TYPE_CHECKING 4 | 5 | import color 6 | import pyxel 7 | 8 | if TYPE_CHECKING: 9 | from tcod import Console 10 | from engine import Engine 11 | from game_map import GameMap 12 | 13 | 14 | def get_names_at_location(x: int, y: int, game_map: GameMap) -> str: 15 | if not game_map.in_bounds(x, y) or not game_map.visible[x, y]: 16 | return "" 17 | 18 | names = ", ".join( 19 | entity.name for entity in game_map.entities if entity.x == x and entity.y == y 20 | ) 21 | 22 | return names.capitalize() 23 | 24 | def render_bar( 25 | current_value: int, maximum_value: int, total_width: int 26 | ) -> None: 27 | bar_width = int(float(current_value) / maximum_value * total_width) 28 | 29 | color.rect(0, 45, total_width, 1, color.bar_empty) 30 | 31 | if bar_width > 0: 32 | color.rect( 0, 45, bar_width, 1, color.bar_filled) 33 | 34 | color.text(1, 45, f"HP: {current_value}/{maximum_value}", color.bar_text) 35 | 36 | def render_dungeon_level( 37 | dungeon_level: int, location: Tuple[int, int] 38 | ) -> None: 39 | """ 40 | Render the level the player is currently on, at the given location. 41 | """ 42 | x, y = location 43 | 44 | color.text(x, y, f"Dungeon level: {dungeon_level}", color.white) 45 | 46 | def render_names_at_mouse_location( 47 | x: int, y: int, engine: Engine 48 | ) -> None: 49 | mouse_x, mouse_y = engine.mouse_location 50 | 51 | names_at_mouse_location = get_names_at_location( 52 | x=mouse_x, y=mouse_y, game_map=engine.game_map 53 | ) 54 | 55 | color.text(x, y, names_at_mouse_location, color.white) 56 | 57 | # end of render_functions.py 58 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | # メモ: パレット(pyxel既定) 4 | 5 | black = 0 6 | dark_blue = 1 7 | purple = 2 8 | green = 3 9 | brown = 4 10 | blue = 5 11 | light_purple = 6 12 | white = 7 13 | red = 8 14 | amber = 9 15 | yellow = 10 16 | light_green = 11 17 | light_blue = 12 18 | gray = 13 19 | pink = 14 20 | beige = 15 21 | 22 | player_atk = light_blue 23 | enemy_atk = gray 24 | 25 | player_die = pink 26 | enemy_die = beige 27 | needs_target = blue 28 | status_effect_applied = light_purple 29 | descend = light_purple 30 | 31 | invalid = amber 32 | impossible = yellow 33 | error = purple 34 | 35 | welcome_text = light_purple 36 | health_recovered = green 37 | 38 | bar_text = white 39 | bar_filled = light_green 40 | bar_empty = red 41 | 42 | menu_title = yellow 43 | menu_text = white 44 | 45 | # メモ: 以下、色(color)とは直接関係ないコード(Pyxel関連) 46 | 47 | # メモ: コンソールサイズ(80x50) 48 | width = 80 49 | height = 50 50 | 51 | # メモ: 組込フォントのドット数(4x5) 52 | chr_x = 4 53 | chr_y = 5 54 | 55 | # メモ: ヘルパー関数 56 | def rect(x: int, y: int, w: int, h: int, col: int): 57 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 58 | 59 | def rectb(x: int, y: int, w: int, h: int, col: int): 60 | pyxel.rectb(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 61 | 62 | def text(x: int, y: int, s: str, col: int): 63 | pyxel.text(x*chr_x, y*chr_y, s, col) 64 | 65 | # テキストを中央に表示 66 | def textc(x: int, y: int, s: str, col: int): 67 | pyxel.text((x - len(s) // 2)*chr_x, y*chr_y, s, col) 68 | 69 | # 背景色を指定してテキストを表示 70 | def textbg(x: int, y: int, s: str, fg: int, bg: int): 71 | rect(x, y, len(s), 1, bg) 72 | text(x ,y, s, fg) 73 | 74 | # 背景色を指定してテキストを中央に表示 75 | def textcbg(x: int, y: int, s: str, fg: int, bg: int): 76 | rect(x - len(s) // 2, y, len(s), 1, bg) 77 | textc(x ,y, s, fg) 78 | 79 | # end of color.py 80 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | # メモ: パレット(pyxel既定) 4 | 5 | black = 0 6 | dark_blue = 1 7 | purple = 2 8 | green = 3 9 | brown = 4 10 | blue = 5 11 | light_purple = 6 12 | white = 7 13 | red = 8 14 | amber = 9 15 | yellow = 10 16 | light_green = 11 17 | light_blue = 12 18 | gray = 13 19 | pink = 14 20 | beige = 15 21 | 22 | player_atk = light_blue 23 | enemy_atk = gray 24 | 25 | player_die = pink 26 | enemy_die = beige 27 | needs_target = blue 28 | status_effect_applied = light_purple 29 | descend = light_purple 30 | 31 | invalid = amber 32 | impossible = yellow 33 | error = purple 34 | 35 | welcome_text = light_purple 36 | health_recovered = green 37 | 38 | bar_text = white 39 | bar_filled = light_green 40 | bar_empty = red 41 | 42 | menu_title = yellow 43 | menu_text = white 44 | 45 | # メモ: 以下、色(color)とは直接関係ないコード(Pyxel関連) 46 | 47 | # メモ: コンソールサイズ(80x50) 48 | width = 80 49 | height = 50 50 | 51 | # メモ: 組込フォントのドット数(4x5) 52 | chr_x = 4 53 | chr_y = 5 54 | 55 | # メモ: ヘルパー関数 56 | def rect(x: int, y: int, w: int, h: int, col: int): 57 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 58 | 59 | def rectb(x: int, y: int, w: int, h: int, col: int): 60 | pyxel.rectb(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 61 | 62 | def text(x: int, y: int, s: str, col: int): 63 | pyxel.text(x*chr_x, y*chr_y, s, col) 64 | 65 | # テキストを中央に表示 66 | def textc(x: int, y: int, s: str, col: int): 67 | pyxel.text((x - len(s) // 2)*chr_x, y*chr_y, s, col) 68 | 69 | # 背景色を指定してテキストを表示 70 | def textbg(x: int, y: int, s: str, fg: int, bg: int): 71 | rect(x, y, len(s), 1, bg) 72 | text(x ,y, s, fg) 73 | 74 | # 背景色を指定してテキストを中央に表示 75 | def textcbg(x: int, y: int, s: str, fg: int, bg: int): 76 | rect(x - len(s) // 2, y, len(s), 1, bg) 77 | textc(x ,y, s, fg) 78 | 79 | # end of color.py 80 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | # メモ: パレット(pyxel既定) 4 | 5 | black = 0 6 | dark_blue = 1 7 | purple = 2 8 | green = 3 9 | brown = 4 10 | blue = 5 11 | light_purple = 6 12 | white = 7 13 | red = 8 14 | amber = 9 15 | yellow = 10 16 | light_green = 11 17 | light_blue = 12 18 | gray = 13 19 | pink = 14 20 | beige = 15 21 | 22 | player_atk = light_blue 23 | enemy_atk = gray 24 | 25 | player_die = pink 26 | enemy_die = beige 27 | needs_target = blue 28 | status_effect_applied = light_purple 29 | descend = light_purple 30 | 31 | invalid = amber 32 | impossible = yellow 33 | error = purple 34 | 35 | welcome_text = light_purple 36 | health_recovered = green 37 | 38 | bar_text = white 39 | bar_filled = light_green 40 | bar_empty = red 41 | 42 | menu_title = yellow 43 | menu_text = white 44 | 45 | # メモ: 以下、色(color)とは直接関係ないコード(Pyxel関連) 46 | 47 | # メモ: コンソールサイズ(80x50) 48 | width = 80 49 | height = 50 50 | 51 | # メモ: 組込フォントのドット数(4x5) 52 | chr_x = 4 53 | chr_y = 5 54 | 55 | # メモ: ヘルパー関数 56 | def rect(x: int, y: int, w: int, h: int, col: int): 57 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 58 | 59 | def rectb(x: int, y: int, w: int, h: int, col: int): 60 | pyxel.rectb(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 61 | 62 | def text(x: int, y: int, s: str, col: int): 63 | pyxel.text(x*chr_x, y*chr_y, s, col) 64 | 65 | # テキストを中央に表示 66 | def textc(x: int, y: int, s: str, col: int): 67 | pyxel.text((x - len(s) // 2)*chr_x, y*chr_y, s, col) 68 | 69 | # 背景色を指定してテキストを表示 70 | def textbg(x: int, y: int, s: str, fg: int, bg: int): 71 | rect(x, y, len(s), 1, bg) 72 | text(x ,y, s, fg) 73 | 74 | # 背景色を指定してテキストを中央に表示 75 | def textcbg(x: int, y: int, s: str, fg: int, bg: int): 76 | rect(x - len(s) // 2, y, len(s), 1, bg) 77 | textc(x ,y, s, fg) 78 | 79 | # end of color.py 80 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/color.py: -------------------------------------------------------------------------------- 1 | import pyxel 2 | 3 | # メモ: パレット(pyxel既定) 4 | 5 | black = 0 6 | dark_blue = 1 7 | purple = 2 8 | green = 3 9 | brown = 4 10 | blue = 5 11 | light_purple = 6 12 | white = 7 13 | red = 8 14 | amber = 9 15 | yellow = 10 16 | light_green = 11 17 | light_blue = 12 18 | gray = 13 19 | pink = 14 20 | beige = 15 21 | 22 | player_atk = light_blue 23 | enemy_atk = gray 24 | 25 | player_die = pink 26 | enemy_die = beige 27 | needs_target = blue 28 | status_effect_applied = light_purple 29 | descend = light_purple 30 | 31 | invalid = amber 32 | impossible = yellow 33 | error = purple 34 | 35 | welcome_text = light_purple 36 | health_recovered = green 37 | 38 | bar_text = white 39 | bar_filled = light_green 40 | bar_empty = red 41 | 42 | menu_title = yellow 43 | menu_text = white 44 | 45 | # メモ: 以下、色(color)とは直接関係ないコード(Pyxel関連) 46 | 47 | # メモ: コンソールサイズ(80x50) 48 | width = 80 49 | height = 50 50 | 51 | # メモ: 組込フォントのドット数(4x5) 52 | chr_x = 4 53 | chr_y = 5 54 | 55 | # メモ: ヘルパー関数 56 | def rect(x: int, y: int, w: int, h: int, col: int): 57 | pyxel.rect(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 58 | 59 | def rectb(x: int, y: int, w: int, h: int, col: int): 60 | pyxel.rectb(x*chr_x, y*chr_y, w*chr_x, h*chr_y, col) 61 | 62 | def text(x: int, y: int, s: str, col: int): 63 | pyxel.text(x*chr_x, y*chr_y, s, col) 64 | 65 | # テキストを中央に表示 66 | def textc(x: int, y: int, s: str, col: int): 67 | pyxel.text((x - len(s) // 2)*chr_x, y*chr_y, s, col) 68 | 69 | # 背景色を指定してテキストを表示 70 | def textbg(x: int, y: int, s: str, fg: int, bg: int): 71 | rect(x, y, len(s), 1, bg) 72 | text(x ,y, s, fg) 73 | 74 | # 背景色を指定してテキストを中央に表示 75 | def textcbg(x: int, y: int, s: str, fg: int, bg: int): 76 | rect(x - len(s) // 2, y, len(s), 1, bg) 77 | textc(x ,y, s, fg) 78 | 79 | # end of color.py 80 | -------------------------------------------------------------------------------- /research/99_03_NoteOnGames2019.md: -------------------------------------------------------------------------------- 1 | # 99_ゲーム雑記: 03_ゲーム雑記2019 2 | 3 | ## twitterより 4 | 5 | ### 2019-09-15 6 | 7 | NHK連続テレビ小説「なつぞら」を見て思ったのですが,20年後ぐらいには,セガの小玉理恵子さんを主役にしたシリーズが作られるかもしれません.そして,ラストシーンは,GDCでのPioneer Award授賞式です. 8 | 9 | ### 2019-10-19 10 | 11 | Z80です. 12 | 13 | ### 2019-10-20 14 | 15 | アレクセイパジトノフ氏.すっかりアメリカ人になりました.ゲームボーイを首からかけています. 16 | テトリスといえば,ゲームボーイです. 17 | 18 | ### 2019-10-22 19 | 20 | Nintendo Switchの出来損ないみたいなゲーム機です.君の名はという感じです. 21 | Atariがゲーム機出すとか言ってたから,それでしょうか.今日分かったのですが,現行の天皇制は,エミュレーションです. 22 | 23 | ダビスタというゲームが大好きで,最近またDSでプレイしています. 24 | 牝馬は,引退直前までレースに出走させられるのですが,引退後は,繁殖牝馬として,優秀な仔馬を生むことをもとめられます. 25 | その様子は,キャリアウーマンとしてバリバリ仕事をしていたのに,次の日から優秀な子供を産み育てることをもとめられ,運命に翻弄される若い母親の姿に重なって見えます. 26 | (こんなツイートを本日するのには,本当に大意はありません.ただ,ふと想起されただけです.) 27 | 28 | MZ80Kも,Mac SEとPETに並んで立派です.最初に,確か秋葉原だったと思うけど,MZ80Kでゲームが動いているのを見て,なんとも言えない興奮を覚えた記憶があります.エミュレータを作っていて,最初に画面が再現された時の興奮に似ています. 29 | 30 | ### 2019-10-23 31 | 32 | Evercadeというのは,英国のレトロゲームを作る企業みたいです.Atariとか,Namcoとか,InterPlayとか,DataEastとかのレトロゲームを専用ゲーム機で出している企業とのことです.InterPlayというのは,海外でPCゲームを出していた企業みたいです.知りませんでした. 33 | 34 | ### 2019-10-30 35 | 36 | 宮本茂氏が,文化功労者になりました.当然と言えば当然です.これからゲーム分野の受賞者が増えそうです. 37 | 世間的にもそろそろということで,機が熟したのでしょうか.セガ関係者としては,鈴木裕氏,中裕司氏は,次の候補かもしれません. 38 | 39 | _(2023-10-29) その後,ゲーム部門としては,作曲家のすぎやまこういち氏が,受賞されています._ 40 | 41 | 去年の11/3に,『紫綬褒章は,「学術芸術上の発明改良創作に関し事績著明なる者」に授与されるのに,ゲームクリエータに受賞者はいませんでした.ゲームは芸術の域には至っていないということでしょうか.宮本茂さんは,フランスの勲章を受けています.「寺尾聡さんに紫綬褒章あげるのであれば,宮本茂さんにあげないといけません.」と言っていたら,ある方に「政治家にでもなったらどうですか.」と言われました.でも,公約が「宮本茂さんに勲章をあげる」というのも,ちょっと志が低い気がしたので諦めました.』と呟いていました. 42 | 43 | ロードランナーと言えば,これだと個人的には思います. 44 | 45 | ### 2019-12-09 46 | 47 | どうしても,「東亜プラン」というと,究極タイガーなのですね.個人的には,飛翔鮫が大好きです. 48 | 川崎の九龍城がなくなり,できなくなりました.タイガーヘリと究極タイガーは,PS1版を持ってるから,いつでもできます. 49 | 東亜プランシューティングバトル1です. 50 | 51 | 以前はワンダースワンを持っていました.壊れたから,2台目を買いました.2台目も壊れたので,あきらめました. 52 | 最近は,中古でも売ってるのをあまり見かけなくなりました. 53 | 54 | 以上 55 | -------------------------------------------------------------------------------- /research/01_03_AsteroidsNote.md: -------------------------------------------------------------------------------- 1 | # 01_ゲーム製作: 03_アステロイド開発記 2 | 3 | つぶやきながら,アステロイドを開発する記録です. 4 | 5 | ## アステロイド開発記(2024年編) 6 | 7 | ### 2024-07-12 8 | 9 | 過去に開発した 10 | [Asteroids in Haskell](https://github.com/jay-kumogata/RetroGames/tree/main/haskell/asteroids) 11 | を,Pyxel/Pythonに移植してみることにしました. 12 | 13 | 14 | 15 | ### 2024-07-13 16 | 17 | Asteroids開発の続報です.本日の進捗は,以下の通りです. 18 | 19 | - Vecクラス(旧PointInSpaceクラス)を実装 20 | - Rockクラスを実装 21 | 22 | ### 2024-07-14 23 | 24 | Asteroids開発の続報です.本日の進捗は,以下の通りです. 25 | 26 | - Shipクラスを実装 27 | - Bulletクラスを実装 28 | - Asteroidsクラスを実装(未完了) 29 | 30 | ### 2024-07-20 31 | 32 | Asteroids開発の続報です.本日の進捗は,以下の通りです. 33 | 34 | - Asteroidsクラスを実装(未完了) 35 | - 弾発射処理 36 | - 岩分裂処理 37 | 38 | ### 2024-07-21 39 | 40 | Asteroids開発の続報です.本日の進捗は,以下の通りです. 41 | 42 | - Asteroidsクラスを実装(未完了) 43 | - 自機当り判定処理 44 | - ゲームオーバー処理 45 | 46 | ### 2024-07-25 47 | 48 | Haskellみたいな関数型は,関数適用が多く,コードが横長になり,Pythonみたいな逐次型は,コードが縦長になる傾向があります. 49 | 50 | ### 2024-07-27 51 | 52 | Asteroids開発の続報です.本日の進捗は,以下の通りです. 53 | 54 | - Asteroidsクラスを実装 55 | - 点数表示処理 56 | 57 | ### 2024-09-02 58 | 59 | Asteroids開発の続報です.本日の進捗は,以下の通りです. 60 | 61 | - コメントを修正 62 | - Asteroidsクラスを修正 63 | - 弾を撃ったら,自機も動くように変更(作用反作用の法則) 64 | 65 | ### 2024-09-23 66 | 67 | Asteroids開発の続報です.ビデオゲームとしては,一旦完成です. 68 | 69 | 70 | 71 | ### 2024-12-25 72 | 73 | 秋頃に,Haskellで書いたAsteroidsを,Pyxel/Pythonに移植しました. 74 | Githubの方には,[ソースコード](https://github.com/jay-kumogata/RetroGames/tree/main/pyxel/asteroids)を公開しましたが,Xには投稿していませんでした. 75 | Haskellでは関数適用を繰り返す処理も,Pythonだと逐次的な処理になり,楽しい移植作業でした. 76 | 77 | 78 | 79 | 以上 80 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/components/consumable.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Optional, TYPE_CHECKING 4 | 5 | import actions 6 | import color 7 | import components.inventory 8 | from components.base_component import BaseComponent 9 | from exceptions import Impossible 10 | 11 | if TYPE_CHECKING: 12 | from entity import Actor, Item 13 | 14 | 15 | class Consumable(BaseComponent): 16 | parent: Item 17 | 18 | def get_action(self, consumer: Actor) -> Optional[actions.Action]: 19 | """Try to return the action for this item.""" 20 | return actions.ItemAction(consumer, self.parent) 21 | 22 | def activate(self, action: actions.ItemAction) -> None: 23 | """Invoke this items ability. 24 | 25 | `action` is the context for this activation. 26 | """ 27 | raise NotImplementedError() 28 | 29 | def consume(self) -> None: 30 | """Remove the consumed item from its containing inventory.""" 31 | entity = self.parent 32 | inventory = entity.parent 33 | if isinstance(inventory, components.inventory.Inventory): 34 | inventory.items.remove(entity) 35 | 36 | 37 | class HealingConsumable(Consumable): 38 | def __init__(self, amount: int): 39 | self.amount = amount 40 | 41 | def activate(self, action: actions.ItemAction) -> None: 42 | consumer = action.entity 43 | amount_recovered = consumer.fighter.heal(self.amount) 44 | 45 | if amount_recovered > 0: 46 | self.engine.message_log.add_message( 47 | f"You consume the {self.parent.name}, and recover {amount_recovered} HP!", 48 | color.health_recovered, 49 | ) 50 | self.consume() 51 | else: 52 | raise Impossible(f"Your health is already full.") 53 | 54 | # end of consumable.py 55 | -------------------------------------------------------------------------------- /pyxel/tennis/App.py: -------------------------------------------------------------------------------- 1 | # generated by Grok3 2 | 3 | import pyxel 4 | from TennisEngine import * 5 | 6 | class App: 7 | W = 0 8 | S = 1 9 | D = 2 10 | Up = 3 11 | Down = 4 12 | Left = 5 13 | 14 | def __init__(self): 15 | # 画面サイズをサイズ (256, 256) に合わせる 16 | pyxel.init(256,256) 17 | # TennisEngine を初期化(バッファサイズとして 256x256 を指定) 18 | self.my_engine = TennisEngine(256, 256) 19 | self.keys = [False] * 6 # W, S, D, Up, Down, Left 20 | # 画像の読み込み(frame.png と overlay.png が必要) 21 | #pyxel.images[0].load(0, 0, "frame.png") # イメージバンク 0 に frame.png 22 | #pyxel.images[1].load(0, 0, "overlay.png") # イメージバンク 1 に overlay.png 23 | # キーイベントを登録 24 | pyxel.run(self.update, self.draw) 25 | 26 | def update(self): 27 | # キー入力の処理 28 | self.keys[self.W] = pyxel.btn(pyxel.KEY_W) 29 | self.keys[self.S] = pyxel.btn(pyxel.KEY_S) 30 | self.keys[self.D] = pyxel.btn(pyxel.KEY_D) 31 | self.keys[self.Up] = pyxel.btn(pyxel.KEY_UP) 32 | self.keys[self.Down] = pyxel.btn(pyxel.KEY_DOWN) 33 | self.keys[self.Left] = pyxel.btn(pyxel.KEY_LEFT) 34 | 35 | # スペースキーでヒット 36 | if pyxel.btnp(pyxel.KEY_SPACE): 37 | self.my_engine.hit() 38 | 39 | # 'i' キーでスクリーンショット保存 40 | if pyxel.btnp(pyxel.KEY_I): 41 | pyxel.save("pic{:03d}.png".format(pyxel.frame_count)) 42 | 43 | # ゲームエンジンの更新 44 | self.my_engine.update(self.keys) 45 | 46 | def draw(self): 47 | # 背景をクリア(黒) 48 | pyxel.cls(0) 49 | # ゲームエンジンの描画 50 | self.my_engine.draw() 51 | # バッファを画面に描画(0, 0 のオフセットで 256x256 の領域) 52 | pyxel.blt(0, 0, 0, 0, 0, 256, 256, colkey=0) 53 | # フレーム画像の描画 54 | pyxel.blt(0, 0, 0, 0, 0, 256, 256, colkey=0) 55 | # オーバーレイ画像の描画(ADD ブレンドを模倣) 56 | pyxel.blt(0, 0, 1, 0, 0, 256, 256, colkey=0) 57 | 58 | App() 59 | 60 | # App.py 61 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part7/engine.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pyxel 6 | 7 | from tcod.context import Context 8 | from tcod.console import Console 9 | from tcod.map import compute_fov 10 | 11 | from input_handlers import MainGameEventHandler 12 | from message_log import MessageLog 13 | from render_functions import render_bar, render_names_at_mouse_location 14 | 15 | if TYPE_CHECKING: 16 | from entity import Entity 17 | from game_map import GameMap 18 | from input_handlers import EventHandler 19 | 20 | class Engine: 21 | game_map: GameMap 22 | 23 | def __init__(self, player: Entity): 24 | self.event_handler: EventHandler = MainGameEventHandler(self) 25 | self.message_log = MessageLog() 26 | self.mouse_location = (0, 0) 27 | self.player = player 28 | 29 | def handle_enemy_turns(self) -> None: 30 | for entity in set(self.game_map.actors) - {self.player}: 31 | if entity.ai: 32 | entity.ai.perform() 33 | 34 | def update_fov(self) -> None: 35 | """Recompute the visible area based on the players point of view.""" 36 | self.game_map.visible[:] = compute_fov( 37 | self.game_map.tiles["transparent"], 38 | (self.player.x, self.player.y), 39 | radius=8, 40 | ) 41 | # If a tile is "visible" it should be added to "explored". 42 | self.game_map.explored |= self.game_map.visible 43 | 44 | def render(self) -> None: 45 | self.game_map.render() 46 | self.message_log.render(x=21, y=45, width=40, height=5) 47 | 48 | render_bar( 49 | current_value=self.player.fighter.hp, 50 | maximum_value=self.player.fighter.max_hp, 51 | total_width=20, 52 | ) 53 | 54 | render_names_at_mouse_location(x=21, y=44, engine=self) 55 | 56 | # end of engine.py 57 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/src/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | import color 5 | 6 | # Tile graphics structured type 7 | graphic_dt = np.dtype( 8 | [ 9 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 10 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 11 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 12 | ] 13 | ) 14 | 15 | # Tile struct used for statically defined tile data. 16 | tile_dt = np.dtype( 17 | [ 18 | ("walkable", np.bool_), # True if this tile can be walked over. 19 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 20 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 21 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 22 | ] 23 | ) 24 | 25 | 26 | def new_tile( 27 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 28 | walkable: int, 29 | transparent: int, 30 | dark: Tuple[int, int, int], 31 | light: Tuple[int, int, int] 32 | ) -> np.ndarray: 33 | """Helper function for defining individual tile types """ 34 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 35 | 36 | # SHROUD represents unexplored, unseen tiles 37 | SHROUD = np.array((ord(" "), color.white, color.black), dtype=graphic_dt) 38 | 39 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 40 | floor = new_tile( 41 | walkable=True, 42 | transparent=True, 43 | dark=(ord(" "), color.white, color.light_blue), 44 | light=(ord(" "), color.white, color.yellow), 45 | ) 46 | wall = new_tile( 47 | walkable=False, 48 | transparent=False, 49 | dark=(ord(" "), color.white, color.dark_blue), 50 | light=(ord(" "), color.white, color.amber), 51 | ) 52 | down_stairs = new_tile( 53 | walkable=True, 54 | transparent=True, 55 | dark=(ord(">"), color.dark_blue, color.blue), 56 | light=(ord(">"), color.white, color.yellow), 57 | ) 58 | 59 | # end of tile_types.py 60 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | import color 5 | 6 | # Tile graphics structured type 7 | graphic_dt = np.dtype( 8 | [ 9 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 10 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 11 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 12 | ] 13 | ) 14 | 15 | # Tile struct used for statically defined tile data. 16 | tile_dt = np.dtype( 17 | [ 18 | ("walkable", np.bool_), # True if this tile can be walked over. 19 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 20 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 21 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 22 | ] 23 | ) 24 | 25 | 26 | def new_tile( 27 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 28 | walkable: int, 29 | transparent: int, 30 | dark: Tuple[int, int, int], 31 | light: Tuple[int, int, int] 32 | ) -> np.ndarray: 33 | """Helper function for defining individual tile types """ 34 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 35 | 36 | # SHROUD represents unexplored, unseen tiles 37 | SHROUD = np.array((ord(" "), color.white, color.black), dtype=graphic_dt) 38 | 39 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 40 | floor = new_tile( 41 | walkable=True, 42 | transparent=True, 43 | dark=(ord(" "), color.white, color.light_blue), 44 | light=(ord(" "), color.white, color.yellow), 45 | ) 46 | wall = new_tile( 47 | walkable=False, 48 | transparent=False, 49 | dark=(ord(" "), color.white, color.dark_blue), 50 | light=(ord(" "), color.white, color.amber), 51 | ) 52 | down_stairs = new_tile( 53 | walkable=True, 54 | transparent=True, 55 | dark=(ord(">"), color.dark_blue, color.blue), 56 | light=(ord(">"), color.white, color.yellow), 57 | ) 58 | 59 | # end of tile_types.py 60 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | import color 5 | 6 | # Tile graphics structured type 7 | graphic_dt = np.dtype( 8 | [ 9 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 10 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 11 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 12 | ] 13 | ) 14 | 15 | # Tile struct used for statically defined tile data. 16 | tile_dt = np.dtype( 17 | [ 18 | ("walkable", np.bool_), # True if this tile can be walked over. 19 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 20 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 21 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 22 | ] 23 | ) 24 | 25 | 26 | def new_tile( 27 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 28 | walkable: int, 29 | transparent: int, 30 | dark: Tuple[int, int, int], 31 | light: Tuple[int, int, int] 32 | ) -> np.ndarray: 33 | """Helper function for defining individual tile types """ 34 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 35 | 36 | # SHROUD represents unexplored, unseen tiles 37 | SHROUD = np.array((ord(" "), color.white, color.black), dtype=graphic_dt) 38 | 39 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 40 | floor = new_tile( 41 | walkable=True, 42 | transparent=True, 43 | dark=(ord(" "), color.white, color.light_blue), 44 | light=(ord(" "), color.white, color.yellow), 45 | ) 46 | wall = new_tile( 47 | walkable=False, 48 | transparent=False, 49 | dark=(ord(" "), color.white, color.dark_blue), 50 | light=(ord(" "), color.white, color.amber), 51 | ) 52 | down_stairs = new_tile( 53 | walkable=True, 54 | transparent=True, 55 | dark=(ord(">"), color.dark_blue, color.blue), 56 | light=(ord(">"), color.white, color.yellow), 57 | ) 58 | 59 | # end of tile_types.py 60 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part13/tile_types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple 2 | 3 | import numpy as np # type: ignore 4 | import color 5 | 6 | # Tile graphics structured type 7 | graphic_dt = np.dtype( 8 | [ 9 | ("ch", np.int32), # Unicode codepoint.(未使用: キャラクタコード) 10 | ("fg", np.int32), # 文字色(Pyxelでの色情報) 11 | ("bg", np.int32), # 背景色(Pyxelでの色情報) 12 | ] 13 | ) 14 | 15 | # Tile struct used for statically defined tile data. 16 | tile_dt = np.dtype( 17 | [ 18 | ("walkable", np.bool_), # True if this tile can be walked over. 19 | ("transparent", np.bool_), # True if this tile doesn't block FOV. 20 | ("dark", graphic_dt), # Graphics for when this tile is not in FOV. 21 | ("light", graphic_dt), # Graphics for when the tile is in FOV. 22 | ] 23 | ) 24 | 25 | 26 | def new_tile( 27 | *, # Enforce the use of keywords, so that parameter order doesn't matter. 28 | walkable: int, 29 | transparent: int, 30 | dark: Tuple[int, int, int], 31 | light: Tuple[int, int, int] 32 | ) -> np.ndarray: 33 | """Helper function for defining individual tile types """ 34 | return np.array((walkable, transparent, dark, light), dtype=tile_dt) 35 | 36 | # SHROUD represents unexplored, unseen tiles 37 | SHROUD = np.array((ord(" "), color.white, color.black), dtype=graphic_dt) 38 | 39 | # メモ: 床と壁において,光が当たっていない場合(dark)と当たっている場合(light)の情報 40 | floor = new_tile( 41 | walkable=True, 42 | transparent=True, 43 | dark=(ord(" "), color.white, color.light_blue), 44 | light=(ord(" "), color.white, color.yellow), 45 | ) 46 | wall = new_tile( 47 | walkable=False, 48 | transparent=False, 49 | dark=(ord(" "), color.white, color.dark_blue), 50 | light=(ord(" "), color.white, color.amber), 51 | ) 52 | down_stairs = new_tile( 53 | walkable=True, 54 | transparent=True, 55 | dark=(ord(">"), color.dark_blue, color.blue), 56 | light=(ord(">"), color.white, color.yellow), 57 | ) 58 | 59 | # end of tile_types.py 60 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/engine.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pyxel 6 | 7 | from tcod.map import compute_fov 8 | 9 | import exceptions 10 | from input_handlers import MainGameEventHandler 11 | from message_log import MessageLog 12 | from render_functions import render_bar, render_names_at_mouse_location 13 | 14 | if TYPE_CHECKING: 15 | from entity import Entity 16 | from game_map import GameMap 17 | from input_handlers import EventHandler 18 | 19 | class Engine: 20 | game_map: GameMap 21 | 22 | def __init__(self, player: Entity): 23 | self.event_handler: EventHandler = MainGameEventHandler(self) 24 | self.message_log = MessageLog() 25 | self.mouse_location = (0, 0) 26 | self.player = player 27 | 28 | def handle_enemy_turns(self) -> None: 29 | for entity in set(self.game_map.actors) - {self.player}: 30 | if entity.ai: 31 | try: 32 | entity.ai.perform() 33 | except exceptions.Impossible: 34 | pass # Ignore impossible action exceptions from AI. 35 | 36 | def update_fov(self) -> None: 37 | """Recompute the visible area based on the players point of view.""" 38 | self.game_map.visible[:] = compute_fov( 39 | self.game_map.tiles["transparent"], 40 | (self.player.x, self.player.y), 41 | radius=8, 42 | ) 43 | # If a tile is "visible" it should be added to "explored". 44 | self.game_map.explored |= self.game_map.visible 45 | 46 | def render(self) -> None: 47 | self.game_map.render() 48 | self.message_log.render(x=21, y=45, width=40, height=5) 49 | 50 | render_bar( 51 | current_value=self.player.fighter.hp, 52 | maximum_value=self.player.fighter.max_hp, 53 | total_width=20, 54 | ) 55 | 56 | render_names_at_mouse_location(x=21, y=44, engine=self) 57 | 58 | # end of engine.py 59 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/engine.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import pyxel 6 | 7 | from tcod.map import compute_fov 8 | 9 | import exceptions 10 | from input_handlers import MainGameEventHandler 11 | from message_log import MessageLog 12 | from render_functions import render_bar, render_names_at_mouse_location 13 | 14 | if TYPE_CHECKING: 15 | from entity import Entity 16 | from game_map import GameMap 17 | from input_handlers import EventHandler 18 | 19 | class Engine: 20 | game_map: GameMap 21 | 22 | def __init__(self, player: Entity): 23 | self.event_handler: EventHandler = MainGameEventHandler(self) 24 | self.message_log = MessageLog() 25 | self.mouse_location = (0, 0) 26 | self.player = player 27 | 28 | def handle_enemy_turns(self) -> None: 29 | for entity in set(self.game_map.actors) - {self.player}: 30 | if entity.ai: 31 | try: 32 | entity.ai.perform() 33 | except exceptions.Impossible: 34 | pass # Ignore impossible action exceptions from AI. 35 | 36 | def update_fov(self) -> None: 37 | """Recompute the visible area based on the players point of view.""" 38 | self.game_map.visible[:] = compute_fov( 39 | self.game_map.tiles["transparent"], 40 | (self.player.x, self.player.y), 41 | radius=8, 42 | ) 43 | # If a tile is "visible" it should be added to "explored". 44 | self.game_map.explored |= self.game_map.visible 45 | 46 | def render(self) -> None: 47 | self.game_map.render() 48 | self.message_log.render(x=21, y=45, width=40, height=5) 49 | 50 | render_bar( 51 | current_value=self.player.fighter.hp, 52 | maximum_value=self.player.fighter.max_hp, 53 | total_width=20, 54 | ) 55 | 56 | render_names_at_mouse_location(x=21, y=44, engine=self) 57 | 58 | # end of engine.py 59 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/main.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import traceback 3 | 4 | import pyxel 5 | 6 | import color 7 | from engine import Engine 8 | import entity_factories 9 | from procgen import generate_dungeon 10 | 11 | def main() -> None: 12 | global engine 13 | 14 | screen_width = 80 15 | screen_height = 50 16 | 17 | map_width = 80 18 | map_height = 43 19 | 20 | room_max_size = 10 21 | room_min_size = 6 22 | max_rooms = 30 23 | max_monsters_per_room = 2 24 | max_items_per_room = 2 25 | 26 | player = copy.deepcopy(entity_factories.player) 27 | engine = Engine(player=player) 28 | 29 | engine.game_map = generate_dungeon( 30 | max_rooms=max_rooms, 31 | room_min_size=room_min_size, 32 | room_max_size=room_max_size, 33 | map_width=map_width, 34 | map_height=map_height, 35 | max_monsters_per_room=max_monsters_per_room, 36 | max_items_per_room=max_items_per_room, 37 | engine=engine, 38 | ) 39 | engine.update_fov() 40 | 41 | engine.message_log.add_message( 42 | "Hello and welcome, adventurer, to yet another dungeon!", color.welcome_text 43 | ) 44 | 45 | # Pyxel初期化 46 | pyxel.init( 47 | screen_width * color.chr_x, 48 | screen_height * color.chr_y, 49 | title="Yet Another Roguelike Tutorial", 50 | fps=30 51 | ) 52 | pyxel.mouse(True) # メモ: マウスを表示 53 | pyxel.run(update, draw) 54 | 55 | def draw(): 56 | # メモ: 画面描画ルーチンを呼ぶ 57 | global engine 58 | pyxel.cls(0) 59 | engine.event_handler.on_render() 60 | 61 | def update(): 62 | # メモ: イベントハンドラを呼ぶ 63 | global engine 64 | 65 | try: 66 | engine.event_handler.handle_events() 67 | except Exception: # Handle exceptions in game. 68 | traceback.print_exc() # Print error to stderr. 69 | # Then print the error to the message log. 70 | engine.message_log.add_message(traceback.format_exc(), color.error) 71 | 72 | if __name__ == "__main__": 73 | main() 74 | 75 | # end of main.py 76 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/main.py: -------------------------------------------------------------------------------- 1 | import copy 2 | import traceback 3 | 4 | import pyxel 5 | 6 | import color 7 | from engine import Engine 8 | import entity_factories 9 | from procgen import generate_dungeon 10 | 11 | def main() -> None: 12 | global engine 13 | 14 | screen_width = 80 15 | screen_height = 50 16 | 17 | map_width = 80 18 | map_height = 43 19 | 20 | room_max_size = 10 21 | room_min_size = 6 22 | max_rooms = 30 23 | max_monsters_per_room = 2 24 | max_items_per_room = 2 25 | 26 | player = copy.deepcopy(entity_factories.player) 27 | engine = Engine(player=player) 28 | 29 | engine.game_map = generate_dungeon( 30 | max_rooms=max_rooms, 31 | room_min_size=room_min_size, 32 | room_max_size=room_max_size, 33 | map_width=map_width, 34 | map_height=map_height, 35 | max_monsters_per_room=max_monsters_per_room, 36 | max_items_per_room=max_items_per_room, 37 | engine=engine, 38 | ) 39 | engine.update_fov() 40 | 41 | engine.message_log.add_message( 42 | "Hello and welcome, adventurer, to yet another dungeon!", color.welcome_text 43 | ) 44 | 45 | # Pyxel初期化 46 | pyxel.init( 47 | screen_width * color.chr_x, 48 | screen_height * color.chr_y, 49 | title="Yet Another Roguelike Tutorial", 50 | fps=30 51 | ) 52 | pyxel.mouse(True) # メモ: マウスを表示 53 | pyxel.run(update, draw) 54 | 55 | def draw(): 56 | # メモ: 画面描画ルーチンを呼ぶ 57 | global engine 58 | pyxel.cls(0) 59 | engine.event_handler.on_render() 60 | 61 | def update(): 62 | # メモ: イベントハンドラを呼ぶ 63 | global engine 64 | 65 | try: 66 | engine.event_handler.handle_events() 67 | except Exception: # Handle exceptions in game. 68 | traceback.print_exc() # Print error to stderr. 69 | # Then print the error to the message log. 70 | engine.message_log.add_message(traceback.format_exc(), color.error) 71 | 72 | if __name__ == "__main__": 73 | main() 74 | 75 | # end of main.py 76 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | from components.base_component import BaseComponent 7 | from render_order import RenderOrder 8 | 9 | if TYPE_CHECKING: 10 | from entity import Actor 11 | 12 | class Fighter(BaseComponent): 13 | parent: Actor 14 | 15 | def __init__(self, hp: int, defense: int, power: int): 16 | self.max_hp = hp 17 | self._hp = hp 18 | self.defense = defense 19 | self.power = power 20 | 21 | @property 22 | def hp(self) -> int: 23 | return self._hp 24 | 25 | @hp.setter 26 | def hp(self, value: int) -> None: 27 | self._hp = max(0, min(value, self.max_hp)) 28 | if self._hp == 0 and self.parent.ai: 29 | self.die() 30 | 31 | def die(self) -> None: 32 | if self.engine.player is self.parent: 33 | death_message = "You died!" 34 | death_message_color = color.player_die 35 | else: 36 | death_message = f"{self.parent.name} is dead!" 37 | death_message_color = color.enemy_die 38 | 39 | self.parent.char = "%" 40 | self.parent.color = 2 41 | self.parent.blocks_movement = False 42 | self.parent.ai = None 43 | self.parent.name = f"remains of {self.parent.name}" 44 | self.parent.render_order = RenderOrder.CORPSE 45 | 46 | self.engine.message_log.add_message(death_message, death_message_color) 47 | 48 | def heal(self, amount: int) -> int: 49 | if self.hp == self.max_hp: 50 | return 0 51 | 52 | new_hp_value = self.hp + amount 53 | 54 | if new_hp_value > self.max_hp: 55 | new_hp_value = self.max_hp 56 | 57 | amount_recovered = new_hp_value - self.hp 58 | 59 | self.hp = new_hp_value 60 | 61 | return amount_recovered 62 | 63 | def take_damage(self, amount: int) -> None: 64 | self.hp -= amount 65 | 66 | # end of fighter.py 67 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part10/engine.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | import lzma 4 | import pickle 5 | from typing import TYPE_CHECKING 6 | 7 | import pyxel 8 | from tcod.map import compute_fov 9 | 10 | import exceptions 11 | from message_log import MessageLog 12 | from render_functions import render_bar, render_names_at_mouse_location 13 | 14 | if TYPE_CHECKING: 15 | from entity import Entity 16 | from game_map import GameMap 17 | 18 | class Engine: 19 | game_map: GameMap 20 | 21 | def __init__(self, player: Entity): 22 | self.message_log = MessageLog() 23 | self.mouse_location = (0, 0) 24 | self.player = player 25 | 26 | def handle_enemy_turns(self) -> None: 27 | for entity in set(self.game_map.actors) - {self.player}: 28 | if entity.ai: 29 | try: 30 | entity.ai.perform() 31 | except exceptions.Impossible: 32 | pass # Ignore impossible action exceptions from AI. 33 | 34 | def update_fov(self) -> None: 35 | """Recompute the visible area based on the players point of view.""" 36 | self.game_map.visible[:] = compute_fov( 37 | self.game_map.tiles["transparent"], 38 | (self.player.x, self.player.y), 39 | radius=8, 40 | ) 41 | # If a tile is "visible" it should be added to "explored". 42 | self.game_map.explored |= self.game_map.visible 43 | 44 | def render(self) -> None: 45 | self.game_map.render() 46 | self.message_log.render(x=21, y=45, width=40, height=5) 47 | 48 | render_bar( 49 | current_value=self.player.fighter.hp, 50 | maximum_value=self.player.fighter.max_hp, 51 | total_width=20, 52 | ) 53 | 54 | render_names_at_mouse_location(x=21, y=44, engine=self) 55 | 56 | def save_as(self, filename: str) -> None: 57 | """Save this Engine instance as a compressed file.""" 58 | save_data = lzma.compress(pickle.dumps(self)) 59 | with open(filename, "wb") as f: 60 | f.write(save_data) 61 | 62 | # end of engine.py 63 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part11/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | from components.base_component import BaseComponent 7 | from render_order import RenderOrder 8 | 9 | if TYPE_CHECKING: 10 | from entity import Actor 11 | 12 | class Fighter(BaseComponent): 13 | parent: Actor 14 | 15 | def __init__(self, hp: int, defense: int, power: int): 16 | self.max_hp = hp 17 | self._hp = hp 18 | self.defense = defense 19 | self.power = power 20 | 21 | @property 22 | def hp(self) -> int: 23 | return self._hp 24 | 25 | @hp.setter 26 | def hp(self, value: int) -> None: 27 | self._hp = max(0, min(value, self.max_hp)) 28 | if self._hp == 0 and self.parent.ai: 29 | self.die() 30 | 31 | def die(self) -> None: 32 | if self.engine.player is self.parent: 33 | death_message = "You died!" 34 | death_message_color = color.player_die 35 | else: 36 | death_message = f"{self.parent.name} is dead!" 37 | death_message_color = color.enemy_die 38 | 39 | self.parent.char = "%" 40 | self.parent.color = 2 41 | self.parent.blocks_movement = False 42 | self.parent.ai = None 43 | self.parent.name = f"remains of {self.parent.name}" 44 | self.parent.render_order = RenderOrder.CORPSE 45 | 46 | self.engine.message_log.add_message(death_message, death_message_color) 47 | 48 | self.engine.player.level.add_xp(self.parent.level.xp_given) 49 | 50 | def heal(self, amount: int) -> int: 51 | if self.hp == self.max_hp: 52 | return 0 53 | 54 | new_hp_value = self.hp + amount 55 | 56 | if new_hp_value > self.max_hp: 57 | new_hp_value = self.max_hp 58 | 59 | amount_recovered = new_hp_value - self.hp 60 | 61 | self.hp = new_hp_value 62 | 63 | return amount_recovered 64 | 65 | def take_damage(self, amount: int) -> None: 66 | self.hp -= amount 67 | 68 | # end of fighter.py 69 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part12/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | from components.base_component import BaseComponent 7 | from render_order import RenderOrder 8 | 9 | if TYPE_CHECKING: 10 | from entity import Actor 11 | 12 | class Fighter(BaseComponent): 13 | parent: Actor 14 | 15 | def __init__(self, hp: int, defense: int, power: int): 16 | self.max_hp = hp 17 | self._hp = hp 18 | self.defense = defense 19 | self.power = power 20 | 21 | @property 22 | def hp(self) -> int: 23 | return self._hp 24 | 25 | @hp.setter 26 | def hp(self, value: int) -> None: 27 | self._hp = max(0, min(value, self.max_hp)) 28 | if self._hp == 0 and self.parent.ai: 29 | self.die() 30 | 31 | def die(self) -> None: 32 | if self.engine.player is self.parent: 33 | death_message = "You died!" 34 | death_message_color = color.player_die 35 | else: 36 | death_message = f"{self.parent.name} is dead!" 37 | death_message_color = color.enemy_die 38 | 39 | self.parent.char = "%" 40 | self.parent.color = 2 41 | self.parent.blocks_movement = False 42 | self.parent.ai = None 43 | self.parent.name = f"remains of {self.parent.name}" 44 | self.parent.render_order = RenderOrder.CORPSE 45 | 46 | self.engine.message_log.add_message(death_message, death_message_color) 47 | 48 | self.engine.player.level.add_xp(self.parent.level.xp_given) 49 | 50 | def heal(self, amount: int) -> int: 51 | if self.hp == self.max_hp: 52 | return 0 53 | 54 | new_hp_value = self.hp + amount 55 | 56 | if new_hp_value > self.max_hp: 57 | new_hp_value = self.max_hp 58 | 59 | amount_recovered = new_hp_value - self.hp 60 | 61 | self.hp = new_hp_value 62 | 63 | return amount_recovered 64 | 65 | def take_damage(self, amount: int) -> None: 66 | self.hp -= amount 67 | 68 | # end of fighter.py 69 | -------------------------------------------------------------------------------- /research/03_00_VideoGameCollecting.md: -------------------------------------------------------------------------------- 1 | # 03_ビデオゲーム収集記 2 | 3 | ## はじめに 4 | 5 | ビデオゲームを収集する記録です. 6 | 7 | - サブテーマリスト 8 | - [01_収集リスト](03_01_CollectionList.md): 収集したビデオゲームをリスト化 9 | - [02_メガドラミニ研究](03_02_MegadriveMini.md): ビデオゲーム復刻事例として研究 10 | - [03_Final Fantasy研究](03_03_FinalFantasy.md): 代表的なJRPGとして研究 11 | - [04_PlayStation5研究](03_04_PlayStation5.md): PlayStation5を購入するまでの記録 12 | - [05_NintendoSwitch2研究](03_05_NintendoSwitchNote.md): NintendoSwitch2を購入するまでの記録 13 | - [06_パルワールド研究記](03_06_PalWorldNote.md): ビデオゲームの模倣事例として研究 14 | 15 | ### 2021-12-12 16 | 17 | ここ3年位,長年の夢だったビデオゲーム収集をしました. 18 | 他の人に比べたら,全然収集できなかったと思います. 19 | 収集という概念は広いが,僕は文化財の保護だと考えていました. 20 | 2000年以降は,国立国会図書館に納本されることを考えると,それ以前を中心に収集しようと考えていました. 21 | ただ,単に収集するのは,誰でもできるかなと思うようになりました. 22 | 僕は,プログラミングの能力を使って,過去のゲームを復刻していくのがよいのではないでしょうか. 23 | 24 | ### 2022-05-06 25 | 26 | コンプリート達成者リストを作成しました. 27 | 28 | |対象|範囲|総数|達成者|達成日|備考| 29 | |---|---|---|----|-----|---| 30 | |ファミコン|ROM/箱説有|1053|SOMARI氏(@smr_an_fami)|2021/03/11|https://twitter.com/smr_an_fami/status/1381250946735300610| 31 | |ファミコン|ROM/箱説有|1053|コーナー氏(@corner_mask)|2021/07/18|https://twitter.com/corner_mask/status/1416650529850085377| 32 | |PlayStation|-|3289|灼栗(しゃっくり)氏(@heat_maroon)|2021/10/12|https://twitter.com/heat_maroon/status/1447808515846721537| 33 | |PlayStation VITA|通常版/ベスト版|955|マルヒゲヤ氏(@maruhigeya61)|2022/05/02|https://twitter.com/maruhigeya61/status/1521809952750604290| 34 | 35 | ### 2022-05-25 36 | 37 | 先日NHKで九州国立博物館(九博)の舞台裏というTV番組を視聴しました. 38 | 美術品の修復について紹介していました. 39 | 虫食いされた古文書は,和紙で修復まではするのですが,新たに文字は書き込みません. 40 | 新たに文字を書き込むと別作品になってしまうのが理由です. 41 | また,100年後には和紙の張替が必要になるので,その作業を繰り返すそうです. 42 | 43 | レトロゲームの修復でも参考になります.今後は心がけたいです. 44 | 45 | - 説明書が折れていた場合,極力しわを伸ばして保管 46 | - 説明書が破れていた場合,セロテープで補修しない(時間を経た時にどうなるかわからない) 47 | - ケースが割れていた場合,安易に新しいケースに交換しない 48 | - 同じ作品を2個購入して,綺麗な状態の1個を作らない(「ニコイチ化」しない) 49 | 50 | ### 2024-07-07 51 | 52 | ビデオゲームの文化財としての保存においても,希少でも人気がある(高価な)タイトルは,今後も保存される可能性が高いです. 53 | そのため,私個人の活動としては,希少で人気がない(安価な)タイトルこそ,購入するように心がけています. 54 | 55 | ### 2025-05-11 56 | 57 | たまたま立ち寄ったbookoffで,ナムコミュージアムvol.5があったので,クーポンを使って購入しました. 58 | vol.1からvol.4は,新品を買ったので,vol.1からvol.5までは揃いました. 59 | 当時,vol.5も買おうと思っていたのですが,色々忙しくて,買いそびれたのです. 60 | 30年の時を越えて,一歩前進しました. 61 | 62 | 以上 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part8/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | from components.base_component import BaseComponent 7 | from input_handlers import GameOverEventHandler 8 | from render_order import RenderOrder 9 | 10 | if TYPE_CHECKING: 11 | from entity import Actor 12 | 13 | class Fighter(BaseComponent): 14 | parent: Actor 15 | 16 | def __init__(self, hp: int, defense: int, power: int): 17 | self.max_hp = hp 18 | self._hp = hp 19 | self.defense = defense 20 | self.power = power 21 | 22 | @property 23 | def hp(self) -> int: 24 | return self._hp 25 | 26 | @hp.setter 27 | def hp(self, value: int) -> None: 28 | self._hp = max(0, min(value, self.max_hp)) 29 | if self._hp == 0 and self.parent.ai: 30 | self.die() 31 | 32 | def die(self) -> None: 33 | if self.engine.player is self.parent: 34 | death_message = "You died!" 35 | death_message_color = color.player_die 36 | self.engine.event_handler = GameOverEventHandler(self.engine) 37 | else: 38 | death_message = f"{self.parent.name} is dead!" 39 | death_message_color = color.enemy_die 40 | 41 | self.parent.char = "%" 42 | self.parent.color = 2 43 | self.parent.blocks_movement = False 44 | self.parent.ai = None 45 | self.parent.name = f"remains of {self.parent.name}" 46 | self.parent.render_order = RenderOrder.CORPSE 47 | 48 | self.engine.message_log.add_message(death_message, death_message_color) 49 | 50 | def heal(self, amount: int) -> int: 51 | if self.hp == self.max_hp: 52 | return 0 53 | 54 | new_hp_value = self.hp + amount 55 | 56 | if new_hp_value > self.max_hp: 57 | new_hp_value = self.max_hp 58 | 59 | amount_recovered = new_hp_value - self.hp 60 | 61 | self.hp = new_hp_value 62 | 63 | return amount_recovered 64 | 65 | def take_damage(self, amount: int) -> None: 66 | self.hp -= amount 67 | 68 | # end of fighter.py 69 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part9/components/fighter.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import TYPE_CHECKING 4 | 5 | import color 6 | from components.base_component import BaseComponent 7 | from input_handlers import GameOverEventHandler 8 | from render_order import RenderOrder 9 | 10 | if TYPE_CHECKING: 11 | from entity import Actor 12 | 13 | class Fighter(BaseComponent): 14 | parent: Actor 15 | 16 | def __init__(self, hp: int, defense: int, power: int): 17 | self.max_hp = hp 18 | self._hp = hp 19 | self.defense = defense 20 | self.power = power 21 | 22 | @property 23 | def hp(self) -> int: 24 | return self._hp 25 | 26 | @hp.setter 27 | def hp(self, value: int) -> None: 28 | self._hp = max(0, min(value, self.max_hp)) 29 | if self._hp == 0 and self.parent.ai: 30 | self.die() 31 | 32 | def die(self) -> None: 33 | if self.engine.player is self.parent: 34 | death_message = "You died!" 35 | death_message_color = color.player_die 36 | self.engine.event_handler = GameOverEventHandler(self.engine) 37 | else: 38 | death_message = f"{self.parent.name} is dead!" 39 | death_message_color = color.enemy_die 40 | 41 | self.parent.char = "%" 42 | self.parent.color = 2 43 | self.parent.blocks_movement = False 44 | self.parent.ai = None 45 | self.parent.name = f"remains of {self.parent.name}" 46 | self.parent.render_order = RenderOrder.CORPSE 47 | 48 | self.engine.message_log.add_message(death_message, death_message_color) 49 | 50 | def heal(self, amount: int) -> int: 51 | if self.hp == self.max_hp: 52 | return 0 53 | 54 | new_hp_value = self.hp + amount 55 | 56 | if new_hp_value > self.max_hp: 57 | new_hp_value = self.max_hp 58 | 59 | amount_recovered = new_hp_value - self.hp 60 | 61 | self.hp = new_hp_value 62 | 63 | return amount_recovered 64 | 65 | def take_damage(self, amount: int) -> None: 66 | self.hp -= amount 67 | 68 | # end of fighter.py 69 | -------------------------------------------------------------------------------- /pyxel/galaxian/galaxian.py: -------------------------------------------------------------------------------- 1 | # ランダムな大きさの3種類の敵が回転しながら落ちてくるプログラム 2 | 3 | import pyxel 4 | 5 | # 敵を表現するクラス 6 | class Enemy: 7 | def __init__(self, x, y, size, type, rotate_speed, fall_speed, scale): 8 | self.x = x 9 | self.y = y 10 | self.size = size 11 | self.type = type 12 | self.rotate_speed = rotate_speed 13 | self.fall_speed = fall_speed 14 | self.scale = scale 15 | self.rotate = 0 16 | 17 | # 敵を動かす 18 | def update(self): 19 | self.rotate += self.rotate_speed 20 | self.y += self.fall_speed 21 | if self.y > 256: # 画面外に出たら上に戻る 22 | self.x = pyxel.rndi(-self.size//8, 256//8) * 8 23 | #self.y = pyxel.rndi(-256//8, 0) * 8 24 | self.y = -self.size 25 | 26 | # 敵を描画 27 | def draw(self): 28 | pyxel.blt( 29 | self.x, self.y, 30 | # 対応するイメージバンクの番号、x座標、y座標、横サイズ、縦サイズ、透明色 31 | 0, self.type * (self.size+4), 0, self.size, self.size, 0, 32 | # 回転角度(ラジアンでなく度:Degree)、拡大率(1より小さいときは縮小) 33 | self.rotate, self.scale) 34 | 35 | class App: 36 | def __init__(self): 37 | pyxel.init(256, 256, title="Galaxian", capture_scale=1) 38 | self.enemy_size = 12 39 | 40 | # イメージバンク0の座標 (0, 0)に画像ファイルを読み込む 41 | pyxel.load("galaxian.pyxres") 42 | 43 | # 複数の敵を初期化 44 | self.enemyflakes = [ 45 | Enemy( 46 | x = pyxel.rndi(-self.enemy_size//4, 256//4) * 4, 47 | y = pyxel.rndi(-256//8, 0) * 8, 48 | size = self.enemy_size, 49 | type = pyxel.rndi(0, 2), # 3種類ある敵のどれか 50 | fall_speed = pyxel.rndf(0.6, 1.0), 51 | rotate_speed = pyxel.rndf(-3, 3), 52 | scale = pyxel.rndf(1.5, 2.4) # 画像の表示倍率 53 | ) 54 | for _ in range(24) 55 | ] 56 | 57 | pyxel.run(self.update, self.draw) 58 | 59 | def update(self): 60 | # 全ての敵を更新 61 | for flake in self.enemyflakes: 62 | flake.update() 63 | 64 | def draw(self): 65 | pyxel.cls(1) 66 | # 全ての敵を描画 67 | for flake in self.enemyflakes: 68 | flake.draw() 69 | 70 | App() 71 | -------------------------------------------------------------------------------- /pyxel/autorace/autorace.py: -------------------------------------------------------------------------------- 1 | # 2 | # 「オートレース(1画面ソフト) 」 3 | # 高橋はるみ氏作の「オートレース(1画面ソフト) 」を参考にしました. 4 | # cf. 高橋はるみ:「FM-7 FM-8 はるみのゲーム・ライブラリー」, 株式会社ナツメ社, 1983年. 5 | # 6 | # Jun 14, 2024 ver.1 (Pyxelによる実装) 7 | # 8 | # -*- coding: utf-8 -*- 9 | import pyxel 10 | import random 11 | import basic 12 | 13 | width = 40 14 | height = 20 15 | chr_x = 4 16 | chr_y = 5 17 | 18 | def init(): 19 | global st,s, x, i 20 | 21 | # 0:遊戯中 1:終了 22 | st = 0 23 | 24 | # 画面初期化(10行目),画面クリア(12行目) 25 | s = basic.screen(width, height) 26 | # 車位置初期化(12行目) 27 | x = 2 28 | # カウンタ初期化,Beep音初期化(14行目) 29 | i = 0 30 | 31 | # メインループ 32 | def update(): 33 | global st, s, x, i 34 | 35 | # 遊戯中 36 | if st == 0: 37 | # 車消去,Beep音(16行目) 38 | s.print(x,4," ",7) 39 | pyxel.play(0,0) 40 | # キー入力チェック,左移動(17行目) 41 | if pyxel.btnp(pyxel.KEY_LEFT) and x > 1: x -= 1 42 | # キー入力チェック,左移動(18行目) 43 | if pyxel.btnp(pyxel.KEY_RIGHT) and x < 4: x += 1 44 | # 車衝突チェック(19行目) 45 | if s.peek(x,5,True) > ord(' '): 46 | # 終了 47 | st = 1 48 | return 49 | # 道路表示(20行目) 50 | s.print(0,19,"| |",1) 51 | # 最下段に文字が表示されると自動的に縦スクロール(BASIC仕様) 52 | s.scroll() 53 | # 車表示(21行目) 54 | s.print(x,4,"U",2) 55 | # 障害物表示(22行目) 56 | s.print(random.randint(1,4),18,"+",3) 57 | # ゴール表示(23行目) 58 | if i == 186: 59 | s.print(0,18,"-GOAL-",4) 60 | # カウントアップ(24行目) 61 | i += 1 62 | 63 | # 終了 64 | elif st == 1: 65 | # ゲームオーバ,スコア表示(30行目) 66 | s.print(9,9,"**** GAME OVER ****",8) 67 | s.print(13,11,f"[:SCORE {i}]",9) 68 | 69 | # キー入力チェック,再ゲーム(31行目) 70 | if pyxel.btnp(pyxel.KEY_S): 71 | # 再ゲーム 72 | init() 73 | 74 | # 画面描画 75 | def draw(): 76 | global st, s, x, i 77 | 78 | pyxel.cls(0) 79 | for w in range(s.width): 80 | for h in range(s.height): 81 | pyxel.text(w*4,h*5,chr(s.peek(w,h,True)), s.peek(w,h,False)) 82 | 83 | # 初期化 84 | init() 85 | pyxel.init( width*chr_x, height*chr_y, title="autorace", fps=5 ) 86 | pyxel.sounds[0].set("a2","p","6","n",2) 87 | pyxel.run(update, draw) 88 | 89 | # end of autorace.py 90 | -------------------------------------------------------------------------------- /pyxel/pyxelrogue/part5/game_map.py: -------------------------------------------------------------------------------- 1 | from __future__ import annotations 2 | 3 | from typing import Iterable, Optional, TYPE_CHECKING 4 | 5 | import numpy as np # type: ignore 6 | from tcod.console import Console 7 | import pyxel 8 | 9 | import tile_types 10 | 11 | if TYPE_CHECKING: 12 | from entity import Entity 13 | 14 | class GameMap: 15 | def __init__(self, width: int, height: int, entities: Iterable[Entity] = ()): 16 | self.width, self.height = width, height 17 | self.entities = set(entities) 18 | self.tiles = np.full((width, height), fill_value=tile_types.wall, order="F") 19 | 20 | self.visible = np.full((width, height), fill_value=False, order="F") # Tiles the player can currently see 21 | self.explored = np.full((width, height), fill_value=False, order="F") # Tiles the player has seen before 22 | 23 | def get_blocking_entity_at_location(self, location_x: int, location_y: int) -> Optional[Entity]: 24 | for entity in self.entities: 25 | if entity.blocks_movement and entity.x == location_x and entity.y == location_y: 26 | return entity 27 | 28 | return None 29 | 30 | def in_bounds(self, x: int, y: int) -> bool: 31 | """Return True if x and y are inside of the bounds of this map.""" 32 | return 0 <= x < self.width and 0 <= y < self.height 33 | 34 | def render(self) -> None: 35 | """ 36 | Renders the map. 37 | 38 | If a tile is in the "visible" array, then draw it with the "light" colors. 39 | If it isn't, but it's in the "explored" array, then draw it with the "dark" colors. 40 | Otherwise, the default is "SHROUD". 41 | """ 42 | 43 | # メモ: pyxel対応のため、愚直に表示(現時点では点描) 44 | for x in range(self.width): 45 | for y in range(self.height): 46 | if self.visible[x][y]: 47 | pyxel.pset(x,y,self.tiles["light"][x,y]["fg"]) 48 | elif self.explored[x][y]: 49 | pyxel.pset(x,y,self.tiles["dark"][x,y]["fg"]) 50 | else: 51 | pyxel.pset(x,y,tile_types.SHROUD["fg"]) 52 | 53 | for entity in self.entities: 54 | # Only print entities that are in the FOV 55 | if self.visible[entity.x, entity.y]: 56 | pyxel.pset(entity.x, entity.y, entity.color) 57 | 58 | # end of game_map.py 59 | -------------------------------------------------------------------------------- /research/01_02_PinballNote.md: -------------------------------------------------------------------------------- 1 | # 01_ゲーム製作: 02_ピンボール開発記 2 | 3 | つぶやきながら,ピンボールを開発する日記です. 4 | 5 | ## ピンボール開発記 6 | 7 | ### 2022-08-07 8 | 9 | 最近,ピンボールを作りたくなっているけど,いまさらなので,やめようかなと考えています. 10 | ただ,「車輪の再発見」という言葉あるけど,「再発見」しないと本当には理解できないと思います. 11 | モノ作りってそういうものです.これは,ビジネススクールでは教えてくれないことです. 12 | 13 | ### 2023-04-28 14 | 15 | 年初から,ピンボールを作りたいと思い,数日前から作りはじめました. 16 | PICO-8実装を写経するという手法です. 17 | Isidor氏の [Pinball Pong](https://www.lexaloffle.com/bbs/?tid=28488) を写経しました. 18 | ピンボールというか,ピンボールとブロック崩しが融合したゲームです. 19 | オリジナルはランダム要素が強かったので,シミュレーション要素を強めに変更しています. 20 | 21 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/pinball/screenshots/Pinball01.gif) 22 | 23 | ### 2023-04-30 24 | 25 | 画面上部の障害物,画面左右のバー(5点),ゲームオーバー処理を追加しました. 26 | キャラクタも立体感が出るように描き直しました. 27 | [コード](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/pinball) は,多少リファクタリングしました. 28 | 小学生の時に,PC-8001mkIIで作ったブロック崩しを思い出します. 29 | あれから40年位経過したけど,やっていることに進歩がないですね. 30 | 31 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/pinball/screenshots/Pinball02.gif) 32 | 33 | ### 2023-07-16 34 | 35 | 昔は,ピンボールとブロック崩しが合体したゲームが結構あったらしいです. 36 | ナムコのボムビーとか,キューティーキューとかです. 37 | 結構作ってみると,フリッパーの処理が難しくて,パドルだと簡単に作れることがわかります. 38 | 39 | ### 2023-07-17 40 | 41 | Isidor氏の [Pinball Pong](https://www.lexaloffle.com/bbs/?tid=28488)をPyxel に移植してみました. 42 | ピンボールとポンを組み合わせたようなゲームです. 43 | 春頃に作って公開するのを忘れていました. 44 | 任天堂ピンボールのツイートを見て,思い出しました. 45 | #Pyxel #Pinball 46 | 47 | ### 2023-07-18 48 | 49 | Pyxelで動作するPinball Pong🕹️の [ソースリスト](https://github.com/jay-kumogata/RetroGames/tree/main/pyxel/pinball) 📁を公開しました. 50 | #Pyxel #Pinball 51 | 52 | ### 2023-10-23 53 | 54 | 週末に,春頃に作ってたPinball Pongを少し直しました. 55 | Pongということで,パドルでボールを跳ね返すゲームだったのを,Pinballらしく,フリッパーを付けました. 56 | しかも,デザインの都合で,ダブルフリッパーです. 57 | 各アイテムの位置決めが結構大変で,いい感じにするのに時間がかかりました. 58 | 59 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/pinball/screenshots/Pinball03.gif) 60 | 61 | ### 2023-11-09 62 | 63 | Pyxelで動作するPinball🕹️の [ソースリスト](https://github.com/jay-kumogata/RetroGames/tree/main/pyxel/pinball) 📁を公開しました. 64 | #Pyxel #Pinball 65 | 66 | ### 2023-11-17 67 | 68 | Pinballの続きです.フリッパーを追加したのはよかったのですが,ボールの動きが不自然なままでした. 69 | そこで,重力加速度を大きめにして,フリッパーの速度に応じて,ボールが上がるように修正しました. 70 | 物理シミュレーションっぽい感じにはなりましたが,ビデオゲームとして面白いかは不明です. 71 | 72 | ![](https://github.com/jay-kumogata/RetroGames/blob/main/pyxel/pinball/screenshots/Pinball04.gif) 73 | 74 | ### 2023-11-18 75 | 76 | 小学生の頃に,コリントゲームをヒントに木製のピンボールを作ったことがあります. 77 | その時は,全然完成しませんでした. 78 | 約45年の時を超えて,ようやくピンボールが完成しました. 79 | 80 | 以上 81 | --------------------------------------------------------------------------------