mirror of
https://github.com/csd4ni3l/game-of-life.git
synced 2025-11-05 05:58:06 +01:00
Compare commits
12 Commits
6370505320
...
616447707d
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
616447707d | ||
|
|
5c311f60ca | ||
|
|
3c82a74fba | ||
|
|
3cb59bd706 | ||
|
|
309cb0e2c5 | ||
|
|
021c922571 | ||
|
|
88a699bbcd | ||
|
|
189e345f1f | ||
|
|
28f481ce87 | ||
|
|
7441c48f69 | ||
|
|
2588aa3a9d | ||
|
|
fb8d90223f |
94
.github/workflows/main.yml
vendored
94
.github/workflows/main.yml
vendored
@@ -8,7 +8,13 @@ jobs:
|
|||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
include:
|
||||||
|
- os: ubuntu-22.04
|
||||||
|
platform: linux
|
||||||
|
python-version: "3.11"
|
||||||
|
- os: windows-latest
|
||||||
|
platform: windows
|
||||||
|
python-version: "3.11"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Check-out repository
|
- name: Check-out repository
|
||||||
@@ -35,58 +41,78 @@ jobs:
|
|||||||
disable-plugins: tk-inter,dill-compat,eventlet,gevent,pyqt5,pyqt6,pyside2,pyside6,delvewheel,pywebview,matplotlib,spacy,enum-compat,pbr-compat,gevent,pmw-freezer,transformers,upx,kivy,options-nanny,multiprocessing,gi
|
disable-plugins: tk-inter,dill-compat,eventlet,gevent,pyqt5,pyqt6,pyside2,pyside6,delvewheel,pywebview,matplotlib,spacy,enum-compat,pbr-compat,gevent,pmw-freezer,transformers,upx,kivy,options-nanny,multiprocessing,gi
|
||||||
include-data-dir: assets=assets
|
include-data-dir: assets=assets
|
||||||
include-data-files: CREDITS=CREDITS
|
include-data-files: CREDITS=CREDITS
|
||||||
mode: standalone
|
mode: onefile
|
||||||
output-file: GameOfLife
|
output-file: GameOfLife
|
||||||
|
|
||||||
- name: Zip Build Output
|
- name: Locate and rename executable (Linux)
|
||||||
shell: bash
|
if: matrix.os == 'ubuntu-22.04'
|
||||||
run: |
|
run: |
|
||||||
mkdir -p zip_output
|
set -euo pipefail
|
||||||
if [ "${{ runner.os }}" = "Windows" ]; then
|
echo "Searching for built Linux binary..."
|
||||||
powershell.exe -Command "Compress-Archive -Path 'build/run.dist/*' -DestinationPath 'zip_output/GameOfLife-${{ runner.os }}.zip'"
|
# List to help debugging when paths change
|
||||||
else
|
ls -laR . | head -n 500 || true
|
||||||
cd build/run.dist
|
BIN=$(find . -maxdepth 4 -type f -name 'GameOfLife*' -perm -u+x | head -n1 || true)
|
||||||
zip -r "../../zip_output/GameOfLife-${{ runner.os }}.zip" .
|
if [ -z "${BIN}" ]; then
|
||||||
|
echo "ERROR: No Linux binary found after build"
|
||||||
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
echo "Found: ${BIN}"
|
||||||
|
mkdir -p build_output
|
||||||
|
cp "${BIN}" build_output/GameOfLife.bin
|
||||||
|
chmod +x build_output/GameOfLife.bin
|
||||||
|
echo "Executable ready: build_output/GameOfLife.bin"
|
||||||
|
shell: bash
|
||||||
|
|
||||||
- name: Upload Zipped Build Artifact
|
- name: Locate and rename executable (Windows)
|
||||||
|
if: matrix.os == 'windows-latest'
|
||||||
|
run: |
|
||||||
|
Write-Host "Searching for built Windows binary..."
|
||||||
|
Get-ChildItem -Recurse -File -Filter 'GameOfLife*.exe' | Select-Object -First 1 | ForEach-Object {
|
||||||
|
Write-Host ("Found: " + $_.FullName)
|
||||||
|
New-Item -ItemType Directory -Force -Path build_output | Out-Null
|
||||||
|
Copy-Item $_.FullName "build_output\GameOfLife.exe"
|
||||||
|
Write-Host "Executable ready: build_output\GameOfLife.exe"
|
||||||
|
}
|
||||||
|
if (!(Test-Path build_output\GameOfLife.exe)) {
|
||||||
|
Write-Error "ERROR: No Windows binary found after build"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
shell: pwsh
|
||||||
|
|
||||||
|
- name: Upload build artifact
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: GameOfLife-${{ runner.os }}.zip
|
name: ${{ matrix.platform }}
|
||||||
path: zip_output/GameOfLife-${{ runner.os }}.zip
|
path: build_output/GameOfLife.*
|
||||||
|
|
||||||
release:
|
release:
|
||||||
name: Create GitHub Release
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Download All Zipped Builds
|
- name: Download All Build Artifacts
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: downloads
|
path: downloads
|
||||||
|
|
||||||
- name: Delete Old Release (if exists)
|
- name: Create release (if missing) and upload artifacts to tag
|
||||||
continue-on-error: true
|
|
||||||
run: gh release delete latest -y
|
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Delete Git tag (if exists)
|
|
||||||
continue-on-error: true
|
|
||||||
run: |
|
run: |
|
||||||
git push origin :refs/tags/latest
|
set -euo pipefail
|
||||||
git tag -d latest
|
TAG="${{ github.ref_name }}"
|
||||||
|
echo "Target release tag: $TAG"
|
||||||
- name: Recreate Git tag at HEAD
|
if gh release view "$TAG" >/dev/null 2>&1; then
|
||||||
run: |
|
echo "Release $TAG already exists; will upload assets with --clobber"
|
||||||
git tag latest
|
else
|
||||||
git push origin latest
|
gh release create "$TAG" \
|
||||||
|
--title "$TAG" \
|
||||||
- name: Create the new release
|
--notes "Automated build for $TAG"
|
||||||
run: gh release create latest downloads/**/GameOfLife-*.zip --title "Latest Build" --notes "Most recent multi-platform builds of Game Of Life"
|
fi
|
||||||
env:
|
# Upload the executables directly (no zip files)
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
gh release upload "$TAG" downloads/linux/GameOfLife.bin --clobber
|
||||||
|
gh release upload "$TAG" downloads/windows/GameOfLife.exe --clobber
|
||||||
|
|||||||
@@ -76,7 +76,8 @@ class Game(arcade.gui.UIView):
|
|||||||
self.save_button.on_click = lambda event: self.save()
|
self.save_button.on_click = lambda event: self.save()
|
||||||
self.anchor.add(self.save_button, anchor_x="right", anchor_y="bottom", align_x=-5, align_y=5)
|
self.anchor.add(self.save_button, anchor_x="right", anchor_y="bottom", align_x=-5, align_y=5)
|
||||||
|
|
||||||
if self.window.get_controllers():
|
# Check if window has controller support (ControllerWindow has get_controllers, regular Window doesn't)
|
||||||
|
if hasattr(self.window, 'get_controllers') and self.window.get_controllers():
|
||||||
self.spritelist = arcade.SpriteList()
|
self.spritelist = arcade.SpriteList()
|
||||||
self.cursor_sprite = arcade.Sprite(cursor_texture)
|
self.cursor_sprite = arcade.Sprite(cursor_texture)
|
||||||
self.spritelist.append(self.cursor_sprite)
|
self.spritelist.append(self.cursor_sprite)
|
||||||
|
|||||||
38
run.py
38
run.py
@@ -1,8 +1,15 @@
|
|||||||
import pyglet
|
import pyglet
|
||||||
|
|
||||||
|
pyglet.options['shadow_window'] = False # Fix double window issue on Wayland
|
||||||
pyglet.options.debug_gl = False
|
pyglet.options.debug_gl = False
|
||||||
|
|
||||||
import logging, datetime, os, json, sys, arcade
|
import logging, datetime, os, json, sys, arcade, platform
|
||||||
|
|
||||||
|
# Set up paths BEFORE importing modules that load assets
|
||||||
|
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
pyglet.resource.path.append(script_dir)
|
||||||
|
pyglet.font.add_directory(os.path.join(script_dir, 'assets', 'fonts'))
|
||||||
|
|
||||||
|
|
||||||
from utils.utils import get_closest_resolution, print_debug_info, on_exception
|
from utils.utils import get_closest_resolution, print_debug_info, on_exception
|
||||||
from utils.constants import log_dir, menu_background_color
|
from utils.constants import log_dir, menu_background_color
|
||||||
@@ -12,9 +19,6 @@ from arcade.experimental.controller_window import ControllerWindow
|
|||||||
|
|
||||||
sys.excepthook = on_exception
|
sys.excepthook = on_exception
|
||||||
|
|
||||||
pyglet.resource.path.append(os.getcwd())
|
|
||||||
pyglet.font.add_directory('./assets/fonts')
|
|
||||||
|
|
||||||
__builtins__.print = lambda *args, **kwargs: logging.debug(" ".join(map(str, args)))
|
__builtins__.print = lambda *args, **kwargs: logging.debug(" ".join(map(str, args)))
|
||||||
|
|
||||||
if not log_dir in os.listdir():
|
if not log_dir in os.listdir():
|
||||||
@@ -44,6 +48,13 @@ if os.path.exists('settings.json'):
|
|||||||
else:
|
else:
|
||||||
antialiasing = 0
|
antialiasing = 0
|
||||||
|
|
||||||
|
# Wayland workaround (can be overridden with environment variable)
|
||||||
|
if (platform.system() == "Linux" and
|
||||||
|
os.environ.get("WAYLAND_DISPLAY") and
|
||||||
|
not os.environ.get("ARCADE_FORCE_MSAA")):
|
||||||
|
logging.info("Wayland detected - disabling MSAA (set ARCADE_FORCE_MSAA=1 to override)")
|
||||||
|
antialiasing = 0
|
||||||
|
|
||||||
fullscreen = settings['window_mode'] == 'Fullscreen'
|
fullscreen = settings['window_mode'] == 'Fullscreen'
|
||||||
style = arcade.Window.WINDOW_STYLE_BORDERLESS if settings['window_mode'] == 'borderless' else arcade.Window.WINDOW_STYLE_DEFAULT
|
style = arcade.Window.WINDOW_STYLE_BORDERLESS if settings['window_mode'] == 'borderless' else arcade.Window.WINDOW_STYLE_DEFAULT
|
||||||
vsync = settings['vsync']
|
vsync = settings['vsync']
|
||||||
@@ -51,6 +62,14 @@ if os.path.exists('settings.json'):
|
|||||||
else:
|
else:
|
||||||
resolution = get_closest_resolution()
|
resolution = get_closest_resolution()
|
||||||
antialiasing = 4
|
antialiasing = 4
|
||||||
|
|
||||||
|
# Wayland workaround (can be overridden with environment variable)
|
||||||
|
if (platform.system() == "Linux" and
|
||||||
|
os.environ.get("WAYLAND_DISPLAY") and
|
||||||
|
not os.environ.get("ARCADE_FORCE_MSAA")):
|
||||||
|
logging.info("Wayland detected - disabling MSAA (set ARCADE_FORCE_MSAA=1 to override)")
|
||||||
|
antialiasing = 0
|
||||||
|
|
||||||
fullscreen = False
|
fullscreen = False
|
||||||
style = arcade.Window.WINDOW_STYLE_DEFAULT
|
style = arcade.Window.WINDOW_STYLE_DEFAULT
|
||||||
vsync = True
|
vsync = True
|
||||||
@@ -73,8 +92,12 @@ else:
|
|||||||
if settings.get("music", True):
|
if settings.get("music", True):
|
||||||
theme_sound.play(volume=settings.get("music_volume", 50) / 100, loop=True)
|
theme_sound.play(volume=settings.get("music_volume", 50) / 100, loop=True)
|
||||||
|
|
||||||
window = ControllerWindow(width=resolution[0], height=resolution[1], title='Game Of Life', samples=antialiasing, antialiasing=antialiasing > 0, fullscreen=fullscreen, vsync=vsync, resizable=False, style=style)
|
try:
|
||||||
|
window = ControllerWindow(width=resolution[0], height=resolution[1], title='Game Of Life', samples=antialiasing, antialiasing=antialiasing > 0, fullscreen=fullscreen, vsync=vsync, resizable=False, style=style, visible=False)
|
||||||
|
except (FileNotFoundError, PermissionError) as e:
|
||||||
|
logging.warning(f"Controller support unavailable: {e}. Falling back to regular window.")
|
||||||
|
window = arcade.Window(width=resolution[0], height=resolution[1], title='Game Of Life', samples=antialiasing, antialiasing=antialiasing > 0, fullscreen=fullscreen, vsync=vsync, resizable=False, style=style, visible=False)
|
||||||
|
|
||||||
if vsync:
|
if vsync:
|
||||||
window.set_vsync(True)
|
window.set_vsync(True)
|
||||||
display_mode = window.display.get_default_screen().get_mode()
|
display_mode = window.display.get_default_screen().get_mode()
|
||||||
@@ -98,6 +121,9 @@ main = Main()
|
|||||||
|
|
||||||
window.show_view(main)
|
window.show_view(main)
|
||||||
|
|
||||||
|
# Make window visible after all setup is complete (helps prevent double window on Wayland)
|
||||||
|
window.set_visible(True)
|
||||||
|
|
||||||
logging.debug('Game started.')
|
logging.debug('Game started.')
|
||||||
|
|
||||||
arcade.run()
|
arcade.run()
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
import arcade.gui, arcade
|
import arcade.gui, arcade
|
||||||
|
import os
|
||||||
|
|
||||||
button_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture("assets/graphics/button.png"))
|
# Get the directory where this module is located
|
||||||
button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture("assets/graphics/button_hovered.png"))
|
_module_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
cursor_texture = arcade.load_texture("assets/graphics/cursor.png")
|
_assets_dir = os.path.join(os.path.dirname(_module_dir), 'assets')
|
||||||
|
|
||||||
create_sound = arcade.Sound("assets/sound/create.mp3")
|
button_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button.png')))
|
||||||
destroy_sound = arcade.Sound("assets/sound/destroy.mp3")
|
button_hovered_texture = arcade.gui.NinePatchTexture(64 // 4, 64 // 4, 64 // 4, 64 // 4, arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'button_hovered.png')))
|
||||||
theme_sound = arcade.Sound("assets/sound/music.mp3")
|
cursor_texture = arcade.load_texture(os.path.join(_assets_dir, 'graphics', 'cursor.png'))
|
||||||
|
|
||||||
|
create_sound = arcade.Sound(os.path.join(_assets_dir, 'sound', 'create.mp3'))
|
||||||
|
destroy_sound = arcade.Sound(os.path.join(_assets_dir, 'sound', 'destroy.mp3'))
|
||||||
|
theme_sound = arcade.Sound(os.path.join(_assets_dir, 'sound', 'music.mp3'))
|
||||||
Reference in New Issue
Block a user