doric-engine/Making a Wargame.ipynb

1189 lines
37 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We want to make a turn-based strategy game, based on a **hexagonal grid**.\n",
"\n",
"Wait, how do we even lay out a hexagonal grid in kivy?\n",
"\n",
" http://playtechs.blogspot.com/2007/04/hex-grids.html\n",
" \n",
" Also\n",
" \n",
" http://gamedev.stackexchange.com/questions/15881/hexagonal-grid-tiles-tutorials\n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Ignore device orientation."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's lay out a grid. First we need to draw hexagons. Clone gamecamp. change the object names.\n",
"Can we lay out the basic screen?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" DebugLabel:\n",
" text: 'Main map'\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" DebugLabel:\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" DebugLabel:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%file main.py\n",
"from kivy.app import App\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" pass\n",
"\n",
"\n",
"class StrategyGameApp(App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"#!python main.py"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's make a gridlayout in the game area, and give it a label so we can refer to it from our code. We are going to build a rectangular grid"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" main_map: _main_map\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" cols: 10\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" DebugLabel:\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" DebugLabel:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's hook to that from code. We will do this in `__init__` in our main StrategyGame class. Let's make a loop to add buttons to the root widget. We will use properties in the kv file to determine how many rows/cols to add. We will also need to refer to various objects in the widget hierarchy in the code."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can refer to the top-level object (non-indented) as `root` in the kv file, but it we want to refer to conveniently elsewhere in the code, we need to use an id.\n",
"\n",
"`id: _game`\n",
"\n",
"and then from any widget we want to refer to it, we do a \n",
"\n",
"`game: _game`\n",
"\n",
"We'll use this to access the number of regions to layout in the grid via `map_cols` and `map_rows` from the main game widget. \n",
"\n",
"Fill in grids: it fills it in by default, left to right, top to bottom, and give them coordinate references. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" id: _game\n",
" main_map: _main_map\n",
" map_rows: 10\n",
" map_cols: 10\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" game: _game\n",
" cols: root.map_cols\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" DebugLabel:\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" DebugLabel:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# %load main.py\n",
"from kivy.app import App\n",
"from kivy import properties\n",
"from kivy.uix import button\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" main_map = properties.ObjectProperty(None)\n",
" map_rows = properties.NumericProperty(0)\n",
" map_cols = properties.NumericProperty(0)\n",
"\n",
" def __init__(self, **kwargs):\n",
" super(StrategyGame, self).__init__(**kwargs)\n",
"\n",
" number_of_regions = self.map_rows * self.map_cols\n",
" for region in xrange(0, number_of_regions):\n",
" row = region / self.map_cols\n",
" col = region % self.map_cols\n",
" self.main_map.add_widget(button.Button(text='({}, {})'.format(row, col)))\n",
"\n",
"\n",
"class StrategyGameApp(App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We draw alternating rows with the patterns:\n",
"```\n",
"/ \\\n",
"| |\n",
"| |\n",
"```\n",
"and\n",
"```\n",
"\\ /\n",
" |\n",
" |\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" id: _game\n",
" main_map: _main_map\n",
" map_rows: 10\n",
" map_cols: 10\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" game: _game\n",
" cols: root.map_cols\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" DebugLabel:\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" DebugLabel:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file main.py\n",
"from kivy.app import App\n",
"from kivy import properties\n",
"from kivy.uix import button\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" main_map = properties.ObjectProperty(None)\n",
" map_rows = properties.NumericProperty(0)\n",
" map_cols = properties.NumericProperty(0)\n",
"\n",
" def __init__(self, **kwargs):\n",
" super(StrategyGame, self).__init__(**kwargs)\n",
"\n",
" number_of_regions = self.map_rows * self.map_cols\n",
" for region in xrange(0, number_of_regions):\n",
" row = region / self.map_cols\n",
" col = region % self.map_cols\n",
" self.main_map.add_widget(button.Button(text='({}, {})'.format(row, col)))\n",
"\n",
"\n",
"class StrategyGameApp(App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Wait, that doesn't draw where we think it should.'"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file main.py\n",
"import collections\n",
"\n",
"from kivy.app import App\n",
"from kivy import properties\n",
"from kivy import graphics\n",
"from kivy.uix import label\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"\n",
"\n",
"MapCoords = collections.namedtuple('MapCoords', ['row', 'col'])\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" main_map = properties.ObjectProperty(None)\n",
" map_rows = properties.NumericProperty(0)\n",
" map_cols = properties.NumericProperty(0)\n",
"\n",
" def __init__(self, **kwargs):\n",
" super(StrategyGame, self).__init__(**kwargs)\n",
"\n",
" number_of_regions = self.map_rows * self.map_cols\n",
" for region in xrange(0, number_of_regions):\n",
" row = region / self.map_cols\n",
" col = region % self.map_cols\n",
" self.main_map.add_widget(HexMapCell(row=row, col=col))\n",
"\n",
"\n",
"class HexMapCell(label.Label):\n",
" def __init__(self, row=0, col=0, **kwargs):\n",
" self.region_in_map = MapCoords(row, col)\n",
" super(HexMapCell, self).__init__(**kwargs)\n",
" self.draw_hex_edge()\n",
"\n",
" def draw_hex_edge(self):\n",
" edge = ''\n",
" if self.region_in_map.col % 2 == 0:\n",
" row_mod = self.region_in_map.row % 6\n",
" if row_mod == 0:\n",
" edge = 'BU'\n",
" with self.canvas:\n",
" graphics.Color(1, 1, 1, 1)\n",
" graphics.Line(points=[self.x, self.y, self.width + self.x, self.height + self.y])\n",
" elif row_mod in (1, 2):\n",
" edge = 'L '\n",
" elif row_mod == 3:\n",
" edge = 'TD'\n",
" elif row_mod in (4, 5):\n",
" edge = ' R'\n",
" else:\n",
" row_mod = self.region_in_map.row % 6\n",
" if row_mod == 0:\n",
" edge = 'TD'\n",
" elif row_mod in (1, 2):\n",
" edge = ' R'\n",
" elif row_mod == 3:\n",
" edge = 'BU'\n",
" elif row_mod in (4, 5):\n",
" edge = 'L '\n",
"\n",
" self.text = edge\n",
"\n",
"class StrategyGameApp(App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%file main.py\n",
"from kivy.app import App\n",
"from kivy.uix.gridlayout import GridLayout\n",
"from kivy.lang import Builder\n",
"from kivy.properties import NumericProperty\n",
"\n",
"class HelloWorld(GridLayout):\n",
" cols = NumericProperty(4)\n",
" def __init__(self, **kw):\n",
" super(HelloWorld, self).__init__(**kw)\n",
" self.add_widget(self.BU())\n",
" self.add_widget(self.TD())\n",
" self.add_widget(self.BU())\n",
" self.add_widget(self.TD())\n",
"\n",
" def BU(self):\n",
" return Builder.load_string('''\n",
"Label:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.y, self.right, self.top)\n",
" width: 2''')\n",
"\n",
" def TD(self):\n",
" return Builder.load_string('''\n",
"Label:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.top, self.right, self.y)\n",
" width: 2''')\n",
"\n",
" def L(self):\n",
" return Builder.load_string('''\n",
"Label:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.y, self.x, self.top)\n",
" width: 2''')\n",
"\n",
" def R(self):\n",
" return Builder.load_string('''\n",
"Label:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.right, self.y, self.right, self.top)\n",
" width: 2''')\n",
"\n",
"\n",
"class HelloWorldApp(App):\n",
" def build(self):\n",
" return HelloWorld()\n",
"\n",
"if __name__ == '__main__':\n",
" HelloWorldApp().run()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"# %load strategygame.kv\n",
"\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" id: _game\n",
" main_map: _main_map\n",
" map_rows: 10\n",
" map_cols: 10\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" game: _game\n",
" cols: root.map_cols\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" DebugLabel:\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" DebugLabel:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Trying to draw the hexmap\n",
"\n",
"We tried adding the ability to style our widgets for to draw the Hexmap using lines like this\n",
"\n",
" BU: /\n",
" TD: \\\n",
" L: |\n",
" R: |\n",
"We get hexs now, but we need to figure out how to do the aspect ratio properly now...for a spiky top, we need each grid widget to have aspec ratio $$\\sqrt{3}\\cdot height = width$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" id: _game\n",
" main_map: _main_map\n",
" map_rows: 10\n",
" map_cols: 10\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" game: _game\n",
" cols: root.map_cols\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" DebugLabel:\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" DebugLabel:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33\n",
"\n",
"<BU>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.y, self.right, self.top)\n",
" width: 2\n",
"<TD>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.top, self.right, self.y)\n",
" width: 2\n",
"<L>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.y, self.x, self.top)\n",
" width: 2\n",
"<R>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.right, self.y, self.right, self.top)\n",
" width: 2"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%file main.py\n",
"import collections\n",
"\n",
"from kivy.app import App\n",
"from kivy import properties\n",
"from kivy import graphics\n",
"from kivy.uix import label\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"import math\n",
"\n",
"MapCoords = collections.namedtuple('MapCoords', ['row', 'col'])\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" main_map = properties.ObjectProperty(None)\n",
" map_rows = properties.NumericProperty(0)\n",
" map_cols = properties.NumericProperty(0)\n",
"\n",
" def __init__(self, **kwargs):\n",
" super(StrategyGame, self).__init__(**kwargs)\n",
"\n",
" number_of_regions = self.map_rows * self.map_cols\n",
" for region in xrange(0, number_of_regions):\n",
" row = region / self.map_cols\n",
" col = region % self.map_cols\n",
" self.main_map.add_widget(self.pick_hex_cell(row=row, col=col))\n",
"\n",
"\n",
" def pick_hex_cell(self, row, col):\n",
" row_mod = row % 6\n",
" if col % 2 == 0:\n",
" if row_mod == 0:\n",
" return BU()\n",
" elif row_mod in (1, 2):\n",
" return L()\n",
" elif row_mod == 3:\n",
" return TD()\n",
" elif row_mod in (4, 5):\n",
" return R()\n",
" else:\n",
" if row_mod == 0:\n",
" return TD()\n",
" elif row_mod in (1, 2):\n",
" return R()\n",
" elif row_mod == 3:\n",
" return BU()\n",
" elif row_mod in (4, 5):\n",
" return L()\n",
"\n",
"\n",
"class HexMapCell(label.Label):\n",
" def __init__(self, row=0, col=0, **kwargs):\n",
" self.region_in_map = MapCoords(row, col)\n",
" super(HexMapCell, self).__init__(**kwargs)\n",
"\n",
"class BU(HexMapCell):\n",
" pass\n",
"class TD(HexMapCell):\n",
" pass\n",
"class L(HexMapCell):\n",
" pass\n",
"class R(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class StrategyGameApp(App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": false
},
"source": [
"Replaced the debug labels and coloured the status and minimap two different ways. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"#:import math math\n",
"\n",
"<StrategyGame>:\n",
" id: _game\n",
" main_map: _main_map\n",
" map_rows: 30\n",
" map_cols: 10\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" game: _game\n",
" cols: root.map_cols\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" Label:\n",
" id: _stats\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" canvas.before:\n",
" Color:\n",
" rgba: .49, .49, .81, 1\n",
" Rectangle:\n",
" pos: _stats.pos\n",
" size: _stats.size\n",
" Button:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33\n",
" background_color: .75, .71, .99, 1\n",
"\n",
"\n",
"<BU>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.y, self.right, self.top)\n",
" width: 2\n",
"<TD>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.top, self.right, self.y)\n",
" width: 2\n",
"<L>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.x, self.y, self.x, self.top)\n",
" width: 2\n",
"<R>:\n",
" canvas:\n",
" Color:\n",
" rgba: (1,1,1,1)\n",
" Line:\n",
" points: (self.right, self.y, self.right, self.top)\n",
" width: 2\n",
"\n",
"<HexMapCell>:\n",
" size_hint: 1, None\n",
" height: self.width / math.sqrt(3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file main.py\n",
"import collections\n",
"import random\n",
"\n",
"from kivy import app, properties\n",
"from kivy.uix import button, label\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"\n",
"MapCoords = collections.namedtuple('MapCoords', ['row', 'col'])\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" main_map = properties.ObjectProperty(None)\n",
" map_rows = properties.NumericProperty(0)\n",
" map_cols = properties.NumericProperty(0)\n",
"\n",
" def __init__(self, **kwargs):\n",
" super(StrategyGame, self).__init__(**kwargs)\n",
"\n",
" number_of_regions = self.map_rows * self.map_cols\n",
" for region in xrange(0, number_of_regions):\n",
" row = region / self.map_cols\n",
" col = region % self.map_cols\n",
"\n",
" # Add hex cells to make up the map.\n",
" hex_cell = self.pick_hex_cell(row=row, col=col)\n",
" self.main_map.add_widget(hex_cell)\n",
"\n",
" # Add overlay conditionally.\n",
" if (row % 6 == 2 and col % 2 == 0) or (row % 6 == 5 and col % 2 == 1):\n",
" print('({}, {})'.format(row, col))\n",
" self.add_widget(HexMapControlCell(hex_bind=hex_cell))\n",
"\n",
" @staticmethod\n",
" def pick_hex_cell(row, col):\n",
" row_mod = row % 6\n",
" if col % 2 == 0:\n",
" if row_mod == 0:\n",
" return BU()\n",
" elif row_mod in (1, 2):\n",
" return L()\n",
" elif row_mod == 3:\n",
" return TD()\n",
" elif row_mod in (4, 5):\n",
" return R()\n",
" else:\n",
" if row_mod == 0:\n",
" return TD()\n",
" elif row_mod in (1, 2):\n",
" return R()\n",
" elif row_mod == 3:\n",
" return BU()\n",
" elif row_mod in (4, 5):\n",
" return L()\n",
"\n",
"\n",
"class HexMapCell(label.Label):\n",
" def __init__(self, row=0, col=0, **kwargs):\n",
" super(HexMapCell, self).__init__(**kwargs)\n",
" self.coords = MapCoords(row, col)\n",
"\n",
"\n",
"class BU(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class TD(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class L(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class R(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class HexMapControlCell(button.Button):\n",
" def __init__(self, hex_bind=None, **kwargs):\n",
" super(HexMapControlCell, self).__init__(**kwargs)\n",
" self.hex_bind = hex_bind\n",
" self.background_color = random.random(), random.random(), random.random(), 1\n",
" self.bind(pos=self.reposition_control_cell, size=self.resize_control_cell)\n",
" self.text = '({}, {})'.format(self.hex_bind.coords.row, self.hex_bind.coords.col)\n",
"\n",
" def reposition_control_cell(self, obj, value):\n",
" self.pos = self.hex_bind.pos\n",
"\n",
" def resize_control_cell(self, obj, value):\n",
" self.height = self.hex_bind.height * 2\n",
" self.width = self.hex_bind.width * 2\n",
"\n",
"\n",
"class StrategyGameApp(app.App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Warning** if you run this your will get an error!!"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"We should probably have a viewer and a hexagon map underneath!!\n",
"\n",
"But not for now...let's make an overlay of boxes...and label them with an \"offset-r)\n",
"\n",
"Hmmmm....overlay...is...having...issues. \n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%%file strategygame.kv\n",
"#:import math math\n",
"#:include debug.kv\n",
"\n",
"<StrategyGame>:\n",
" id: _game\n",
" main_map: _main_map\n",
" map_rows: 30\n",
" map_cols: 10\n",
" BoxLayout:\n",
" orientation: 'horizontal'\n",
" GridLayout:\n",
" id: _main_map\n",
" game: _game\n",
" cols: root.map_cols\n",
" size_hint: .75, 1\n",
" BoxLayout:\n",
" orientation: 'vertical'\n",
" size_hint: .25, 1\n",
" Label:\n",
" id: _stats\n",
" text: 'status'\n",
" size_hint: 1, .66\n",
" canvas.before:\n",
" Color:\n",
" rgba: .49, .49, .81, 1\n",
" Rectangle:\n",
" pos: _stats.pos\n",
" size: _stats.size\n",
" Button:\n",
" text: 'mini-map'\n",
" size_hint: 1, .33\n",
" background_color: .75, .71, .99, 1\n",
"\n",
"<Hex@Label>:\n",
" pos_hint: {'center_x':.5, 'center_y':.5}\n",
" canvas.after:\n",
" Color:\n",
" rgba: 1,1,1,1\n",
" Ellipse:\n",
" segments: 6\n",
" pos: self.pos\n",
" size: min(self.width, self.height), min(self.width, self.height)\n",
"\n",
"<HexMapCell>:\n",
" size_hint: 1, None\n",
" height: self.width / math.sqrt(3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"%%file main.py\n",
"import collections\n",
"import random\n",
"import math\n",
"from kivy import app, properties\n",
"from kivy.uix import button, label\n",
"from kivy.uix.floatlayout import FloatLayout\n",
"from kivy.graphics import Color, Ellipse, Line\n",
"from kivy.logger import Logger\n",
"\n",
"MapCoords = collections.namedtuple('MapCoords', ['row', 'col'])\n",
"\n",
"\n",
"class StrategyGame(FloatLayout):\n",
" main_map = properties.ObjectProperty(None)\n",
" map_rows = properties.NumericProperty(0)\n",
" map_cols = properties.NumericProperty(0)\n",
"\n",
" def __init__(self, **kwargs):\n",
" super(StrategyGame, self).__init__(**kwargs)\n",
"\n",
" number_of_regions = self.map_rows * self.map_cols\n",
" for region in xrange(0, number_of_regions):\n",
" row = region / self.map_cols\n",
" col = region % self.map_cols\n",
"\n",
" # Add hex cells to make up the map.\n",
" hex_cell = self.pick_hex_cell(row=row, col=col)\n",
" self.main_map.add_widget(hex_cell)\n",
"\n",
" # Add overlay conditionally.\n",
" if (row % 6 == 1 and col % 2 == 1) or (row % 6 == 4 and col % 2 == 0):\n",
" print('({}, {})'.format(row, col))\n",
" #radius = math.sqrt(hex_cell.width**2 + hex_cell.height**2)\n",
" radius = 2*hex_cell.height\n",
" with hex_cell.canvas.after:\n",
" Color(1,0,1,1)\n",
" hex_cell.ell = Line(circle=(hex_cell.x, hex_cell.y,radius, 0, 360, 6), width=2)\n",
" hex_cell.bind(pos=hex_cell.update_pos, size=hex_cell.update_pos)\n",
"\n",
"\n",
" @staticmethod\n",
" def pick_hex_cell(row, col):\n",
" row_mod = row % 6\n",
" if col % 2 == 0:\n",
" if row_mod == 0:\n",
" return BU()\n",
" elif row_mod in (1, 2):\n",
" return L()\n",
" elif row_mod == 3:\n",
" return TD()\n",
" elif row_mod in (4, 5):\n",
" return R()\n",
" else:\n",
" if row_mod == 0:\n",
" return TD()\n",
" elif row_mod in (1, 2):\n",
" return R()\n",
" elif row_mod == 3:\n",
" return BU()\n",
" elif row_mod in (4, 5):\n",
" return L()\n",
"\n",
"\n",
"\n",
"class HexMapCell(label.Label):\n",
" def __init__(self, row=0, col=0, **kwargs):\n",
" super(HexMapCell, self).__init__(**kwargs)\n",
" self.coords = MapCoords(row, col)\n",
"\n",
" def update_pos(self, instance, value):\n",
" Logger.info(\"StratGame: {}\".format(instance))\n",
" #radius = math.sqrt(self.width**2 + self.height**2)\n",
" radius = 2*self.height\n",
" self.ell.circle = (self.x, self.y, radius, 0, 360, 6)\n",
"\n",
"\n",
"\n",
"class BU(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class TD(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class L(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"class R(HexMapCell):\n",
" pass\n",
"\n",
"\n",
"\n",
"class HexMapControlCell(button.Button):\n",
" def __init__(self, hex_bind=None, **kwargs):\n",
" super(HexMapControlCell, self).__init__(**kwargs)\n",
" self.hex_bind = hex_bind\n",
" self.background_color = random.random(), random.random(), random.random(), 1\n",
" self.bind(pos=self.reposition_control_cell, size=self.resize_control_cell)\n",
" self.text = '({}, {})'.format(self.hex_bind.coords.row, self.hex_bind.coords.col)\n",
"\n",
" def reposition_control_cell(self, obj, value):\n",
" self.pos = self.hex_bind.pos\n",
"\n",
" def resize_control_cell(self, obj, value):\n",
" self.height = self.hex_bind.height * 2\n",
" self.width = self.hex_bind.width * 2\n",
"\n",
"\n",
"class StrategyGameApp(app.App):\n",
" def build(self):\n",
" return StrategyGame()\n",
"\n",
"if __name__ == '__main__':\n",
" StrategyGameApp().run()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What did we learn? \n",
"\n",
"* angle 0 appears to be straight up for a circle or ellipse\n",
"* The radius of the hexagon is $2*height$ for a pointed top hexagon, and for flat top, the radius of the hexagon is $2*width$\n",
"* Make sure you fix the aspect ratio of the rectangles you're basing things now\n",
"* segments are inscribed **inside** the circle\n",
"* tiling problems are hard!!! get a mathematician.\n",
"* there is a utility for hex codes for colours\n",
"* draw the hexagon using a Line with a circle to make an outline instead of an Ellipse\n",
"\n",
"Cleaned some stuff up and added colours to the hexagons. "
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Test out the hexmap conversion code"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": false
},
"outputs": [
{
"ename": "TypeError",
"evalue": "must be type, not classobj",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-5-45811acccccf>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mfoo\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mHexMapCell\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mhex_cell\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mHexMapCell\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m9\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m4\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m/Users/amywooding/python-code/gamecamp/foo.py\u001b[0m in \u001b[0;36m__init__\u001b[0;34m(self, row, col, **kwargs)\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;32mclass\u001b[0m \u001b[0mHexMapCell\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mObject\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 8\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0m__init__\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mself\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mrow\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcol\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 9\u001b[0;31m \u001b[0;31m#super(HexMapCell, self).__init__(**kwargs)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 10\u001b[0m \u001b[0mself\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcoords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mMapCoords\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrow\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcol\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0;31m## set the cube coordinates of the hexagon\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mTypeError\u001b[0m: must be type, not classobj"
]
}
],
"source": [
"from foo import HexMapCell\n",
"hex_cell = HexMapCell(9, 4)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.11"
}
},
"nbformat": 4,
"nbformat_minor": 0
}