mirror of
https://github.com/LucasKalil-Programador/sand-box-python.git
synced 2026-07-04 16:32:58 -03:00
Projeto iniciado e finalizado
This commit is contained in:
commit
eda1f9f891
10 changed files with 565 additions and 0 deletions
185
.gitignore
vendored
Normal file
185
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,185 @@
|
||||||
|
# Created by .ignore support plugin (hsz.mobi)
|
||||||
|
### Python template
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
.hypothesis/
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
local_settings.py
|
||||||
|
|
||||||
|
# Flask stuff:
|
||||||
|
instance/
|
||||||
|
.webassets-cache
|
||||||
|
|
||||||
|
# Scrapy stuff:
|
||||||
|
.scrapy
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
|
|
||||||
|
# IPython Notebook
|
||||||
|
.ipynb_checkpoints
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# celery beat schedule file
|
||||||
|
celerybeat-schedule
|
||||||
|
|
||||||
|
# dotenv
|
||||||
|
.env
|
||||||
|
|
||||||
|
# virtualenv
|
||||||
|
venv/
|
||||||
|
ENV/
|
||||||
|
|
||||||
|
# Spyder project settings
|
||||||
|
.spyderproject
|
||||||
|
|
||||||
|
# Rope project settings
|
||||||
|
.ropeproject
|
||||||
|
### VirtualEnv template
|
||||||
|
# Virtualenv
|
||||||
|
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
|
||||||
|
[Bb]in
|
||||||
|
[Ii]nclude
|
||||||
|
[Ll]ib
|
||||||
|
[Ll]ib64
|
||||||
|
[Ll]ocal
|
||||||
|
[Ss]cripts
|
||||||
|
pyvenv.cfg
|
||||||
|
.venv
|
||||||
|
pip-selfcheck.json
|
||||||
|
|
||||||
|
### JetBrains template
|
||||||
|
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
|
||||||
|
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
|
||||||
|
|
||||||
|
# User-specific stuff
|
||||||
|
.idea/**/workspace.xml
|
||||||
|
.idea/**/tasks.xml
|
||||||
|
.idea/**/usage.statistics.xml
|
||||||
|
.idea/**/dictionaries
|
||||||
|
.idea/**/shelf
|
||||||
|
|
||||||
|
# AWS User-specific
|
||||||
|
.idea/**/aws.xml
|
||||||
|
|
||||||
|
# Generated files
|
||||||
|
.idea/**/contentModel.xml
|
||||||
|
|
||||||
|
# Sensitive or high-churn files
|
||||||
|
.idea/**/dataSources/
|
||||||
|
.idea/**/dataSources.ids
|
||||||
|
.idea/**/dataSources.local.xml
|
||||||
|
.idea/**/sqlDataSources.xml
|
||||||
|
.idea/**/dynamic.xml
|
||||||
|
.idea/**/uiDesigner.xml
|
||||||
|
.idea/**/dbnavigator.xml
|
||||||
|
|
||||||
|
# Gradle
|
||||||
|
.idea/**/gradle.xml
|
||||||
|
.idea/**/libraries
|
||||||
|
|
||||||
|
# Gradle and Maven with auto-import
|
||||||
|
# When using Gradle or Maven with auto-import, you should exclude module files,
|
||||||
|
# since they will be recreated, and may cause churn. Uncomment if using
|
||||||
|
# auto-import.
|
||||||
|
# .idea/artifacts
|
||||||
|
# .idea/compiler.xml
|
||||||
|
# .idea/jarRepositories.xml
|
||||||
|
# .idea/modules.xml
|
||||||
|
# .idea/*.iml
|
||||||
|
# .idea/modules
|
||||||
|
# *.iml
|
||||||
|
# *.ipr
|
||||||
|
|
||||||
|
# CMake
|
||||||
|
cmake-build-*/
|
||||||
|
|
||||||
|
# Mongo Explorer plugin
|
||||||
|
.idea/**/mongoSettings.xml
|
||||||
|
|
||||||
|
# File-based project format
|
||||||
|
*.iws
|
||||||
|
|
||||||
|
# IntelliJ
|
||||||
|
out/
|
||||||
|
|
||||||
|
# mpeltonen/sbt-idea plugin
|
||||||
|
.idea_modules/
|
||||||
|
|
||||||
|
# JIRA plugin
|
||||||
|
atlassian-ide-plugin.xml
|
||||||
|
|
||||||
|
# Cursive Clojure plugin
|
||||||
|
.idea/replstate.xml
|
||||||
|
|
||||||
|
# SonarLint plugin
|
||||||
|
.idea/sonarlint/
|
||||||
|
|
||||||
|
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||||
|
com_crashlytics_export_strings.xml
|
||||||
|
crashlytics.properties
|
||||||
|
crashlytics-build.properties
|
||||||
|
fabric.properties
|
||||||
|
|
||||||
|
# Editor-based Rest Client
|
||||||
|
.idea/httpRequests
|
||||||
|
|
||||||
|
# Android studio 3.1+ serialized cache file
|
||||||
|
.idea/caches/build_file_checksums.ser
|
||||||
|
|
||||||
|
# idea folder, uncomment if you don't need it
|
||||||
|
# .idea
|
||||||
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
10
.idea/SandBoxPyGame.iml
generated
Normal file
10
.idea/SandBoxPyGame.iml
generated
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/.venv" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="jdk" jdkName="Python 3.12 (SandBoxPyGame)" jdkType="Python SDK" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
7
.idea/misc.xml
generated
Normal file
7
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Black">
|
||||||
|
<option name="sdkName" value="Python 3.12 (SandBoxPyGame)" />
|
||||||
|
</component>
|
||||||
|
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12 (SandBoxPyGame)" project-jdk-type="Python SDK" />
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/SandBoxPyGame.iml" filepath="$PROJECT_DIR$/.idea/SandBoxPyGame.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
190
SandBox.py
Normal file
190
SandBox.py
Normal file
|
|
@ -0,0 +1,190 @@
|
||||||
|
import random
|
||||||
|
from enum import Enum
|
||||||
|
import pygame
|
||||||
|
import numpy as np
|
||||||
|
from numba import njit
|
||||||
|
|
||||||
|
|
||||||
|
class Types(Enum):
|
||||||
|
BG = (0, 0, 0, 0, 0)
|
||||||
|
SAND = (203, 189, 147, 1, 0)
|
||||||
|
WATER = (28, 163, 236, 2, 0)
|
||||||
|
STONE = (115, 112, 112, 3, 0)
|
||||||
|
VACUUM = (20, 20, 20, 4, 0)
|
||||||
|
CLONER = (108, 60, 12, 5, 0)
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def run_physics(data, size):
|
||||||
|
if random.random() > 0.5:
|
||||||
|
data = data[::-1]
|
||||||
|
|
||||||
|
for x in range(len(data)):
|
||||||
|
skip_y = False
|
||||||
|
for y in range(len(data[x])):
|
||||||
|
if skip_y or y + 1 >= size[1]:
|
||||||
|
skip_y = False
|
||||||
|
elif data[x, y, 3] == Types.SAND.value[3]:
|
||||||
|
skip_y = sand_physics(data, size, x, y)
|
||||||
|
elif data[x, y, 3] == Types.WATER.value[3]:
|
||||||
|
skip_y = water_physics(data, size, x, y)
|
||||||
|
elif data[x, y, 3] == Types.VACUUM.value[3]:
|
||||||
|
skip_y = vacuum_physics(data, size, x, y)
|
||||||
|
elif data[x, y, 3] == Types.CLONER.value[3]:
|
||||||
|
skip_y = cloner_physics(data, size, x, y)
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def cloner_physics(data, size, x, y):
|
||||||
|
adjacent = ((x - 1, y), (x, y - 1), (x + 1, y), (x, y + 1))
|
||||||
|
type_id = data[x, y, 4]
|
||||||
|
for adj_x, adj_y in adjacent:
|
||||||
|
if adj_x < 0 or adj_y < 0 or adj_x >= size[0] or adj_y >= size[1]:
|
||||||
|
continue
|
||||||
|
if type_id == Types.BG.value[3]:
|
||||||
|
if data[adj_x, adj_y, 3] not in (Types.CLONER.value[3], Types.BG.value[3], Types.VACUUM.value[3]):
|
||||||
|
data[x, y, 4] = data[adj_x, adj_y, 3]
|
||||||
|
else:
|
||||||
|
if data[adj_x, adj_y, 3] == Types.BG.value[3]:
|
||||||
|
type_b = Types.BG
|
||||||
|
if data[x, y, 4] == Types.SAND.value[3]:
|
||||||
|
type_b = Types.SAND
|
||||||
|
elif data[x, y, 4] == Types.WATER.value[3]:
|
||||||
|
type_b = Types.WATER
|
||||||
|
elif data[x, y, 4] == Types.STONE.value[3]:
|
||||||
|
type_b = Types.STONE
|
||||||
|
|
||||||
|
if type_b.value[3] in (Types.SAND.value[3], Types.WATER.value[3], Types.STONE.value[3]):
|
||||||
|
spawn_pixel(data, adj_x, adj_y, color=type_b.value, cmod=10)
|
||||||
|
elif type_b.value[3] in (Types.BG.value[3], Types.VACUUM.value[3], Types.CLONER.value[3]):
|
||||||
|
spawn_pixel(data, adj_x, adj_y, color=type_b.value)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def vacuum_physics(data, size, x, y):
|
||||||
|
adjacent = ((x - 1, y), (x, y - 1), (x + 1, y), (x, y + 1))
|
||||||
|
for adj_x, adj_y in adjacent:
|
||||||
|
if adj_x < 0 or adj_y < 0 or adj_x >= size[0] or adj_y >= size[1]:
|
||||||
|
continue
|
||||||
|
if data[adj_x, adj_y, 3] not in (Types.VACUUM.value[3], Types.BG.value[3]):
|
||||||
|
spawn_pixel(data, adj_x, adj_y, color=Types.BG.value)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def sand_physics(data, size, x, y):
|
||||||
|
# region Gravity
|
||||||
|
if data[x, y + 1, 3] == Types.BG.value[3]:
|
||||||
|
data[x, y + 1] = data[x, y]
|
||||||
|
data[x, y] = Types.BG.value
|
||||||
|
return True
|
||||||
|
# endregion Gravity
|
||||||
|
# region Drop down left or right
|
||||||
|
random_side = -1 if random.random() > 0.5 else 1
|
||||||
|
if x + random_side < 0 or x + random_side >= size[0]:
|
||||||
|
random_side *= -1
|
||||||
|
|
||||||
|
if data[x + random_side, y + 1, 3] in (Types.BG.value[3], Types.WATER.value[3]):
|
||||||
|
data[x + random_side, y + 1], data[x, y] = data[x, y], data[x + random_side, y + 1].copy()
|
||||||
|
return False
|
||||||
|
|
||||||
|
random_side *= -1
|
||||||
|
if x + random_side < 0 or x + random_side >= size[0]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
if data[x + random_side * -1, y + 1, 3] in (Types.BG.value[3], Types.WATER.value[3]):
|
||||||
|
data[x + random_side * -1, y + 1], data[x, y] = data[x, y], data[x + random_side * -1, y + 1].copy()
|
||||||
|
return False
|
||||||
|
# endregion Drop down left or right
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def water_physics(data, size, x, y):
|
||||||
|
# region Gravity
|
||||||
|
if data[x, y + 1, 3] == Types.BG.value[3]:
|
||||||
|
data[x, y + 1], data[x, y] = data[x, y], Types.BG.value
|
||||||
|
return True
|
||||||
|
# endregion Gravity
|
||||||
|
# region Drop down left or Right
|
||||||
|
random_side = -1 if random.random() > 0.5 else 1
|
||||||
|
if x + random_side < 0 or x + random_side >= size[0]:
|
||||||
|
random_side *= -1
|
||||||
|
|
||||||
|
if data[x + random_side, y + 1, 3] == Types.BG.value[3]:
|
||||||
|
data[x + random_side, y + 1], data[x, y] = data[x, y], Types.BG.value
|
||||||
|
return False
|
||||||
|
# endregion Drop down left or Right
|
||||||
|
# region Sand fall over water
|
||||||
|
if y - 1 > 0 and data[x, y - 1, 3] == Types.SAND.value[3]:
|
||||||
|
data[x, y - 1], data[x, y] = data[x, y], data[x, y - 1].copy()
|
||||||
|
return True
|
||||||
|
# endregion Sand fall over water
|
||||||
|
# region Moving horizontal
|
||||||
|
max_steps = size[0]
|
||||||
|
if data[x, y + 1][3] != Types.BG.value[3]:
|
||||||
|
for new_x in range(x + 1, min(x + max_steps, size[0])):
|
||||||
|
if data[new_x, y, 3] == Types.BG.value[3]:
|
||||||
|
if data[new_x, y + 1, 3] == Types.BG.value[3]:
|
||||||
|
data[new_x, y], data[x, y] = data[x, y], Types.BG.value
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
for new_x in range(x - 1, max(x - max_steps, 0), -1):
|
||||||
|
if data[new_x, y, 3] == Types.BG.value[3]:
|
||||||
|
if data[new_x, y + 1, 3] == Types.BG.value[3]:
|
||||||
|
data[new_x, y], data[x, y] = data[x, y], Types.BG.value
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
# endregion Moving horizontal
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def spawn_pixel(data, x, y, color=Types.BG.value, cmod=0):
|
||||||
|
color = (color[0] + random.randint(-cmod, cmod),
|
||||||
|
color[1] + random.randint(-cmod, cmod),
|
||||||
|
color[2] + random.randint(-cmod, cmod),
|
||||||
|
color[3], color[4])
|
||||||
|
data[x, y] = color
|
||||||
|
|
||||||
|
|
||||||
|
@njit
|
||||||
|
def spawn(data, size, center, radius, type_b=Types.BG):
|
||||||
|
for x in range(center[0] - radius, center[0] + radius):
|
||||||
|
for y in range(center[1] - radius, center[1] + radius):
|
||||||
|
if y < 0 or x < 0 or y >= size[1] or x >= size[0]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if (y - center[1]) ** 2 + (x - center[0]) ** 2 <= radius ** 2 and data[x, y, 3] != type_b.value[3]:
|
||||||
|
if type_b.value[3] in (Types.SAND.value[3], Types.WATER.value[3], Types.STONE.value[3]):
|
||||||
|
spawn_pixel(data, x, y, color=type_b.value, cmod=10)
|
||||||
|
elif type_b.value[3] in (Types.BG.value[3], Types.VACUUM.value[3], Types.CLONER.value[3]):
|
||||||
|
spawn_pixel(data, x, y, color=type_b.value)
|
||||||
|
|
||||||
|
|
||||||
|
class SandBox:
|
||||||
|
def __init__(self, size: tuple[int, int]):
|
||||||
|
self.__size = size
|
||||||
|
self.__data: np.ndarray = np.empty(0)
|
||||||
|
self.reset()
|
||||||
|
self.__surface = pygame.Surface(size)
|
||||||
|
self.update_surface()
|
||||||
|
|
||||||
|
def spawn(self, center, radius, type_b=Types.BG):
|
||||||
|
spawn(self.__data, self.__size, center, radius, type_b)
|
||||||
|
|
||||||
|
def run_physics(self):
|
||||||
|
run_physics(self.__data, self.__size)
|
||||||
|
|
||||||
|
def reset(self):
|
||||||
|
self.__data = np.full((self.__size[0], self.__size[1], 5), Types.BG.value, dtype=np.uint8)
|
||||||
|
|
||||||
|
def update_surface(self):
|
||||||
|
pygame.surfarray.blit_array(self.__surface, self.__data[:, :, :3])
|
||||||
|
|
||||||
|
def get_surface(self):
|
||||||
|
self.update_surface()
|
||||||
|
return self.__surface
|
||||||
150
main.py
Normal file
150
main.py
Normal file
|
|
@ -0,0 +1,150 @@
|
||||||
|
import random
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
|
||||||
|
import pygame
|
||||||
|
import sys
|
||||||
|
import SandBox
|
||||||
|
|
||||||
|
|
||||||
|
def handle_actions(keys_pressed: dict[any, bool], on_key_click):
|
||||||
|
for event in pygame.event.get():
|
||||||
|
if event.type == pygame.QUIT:
|
||||||
|
pygame.quit()
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
if event.type == pygame.KEYDOWN:
|
||||||
|
keys_pressed[event.key] = True
|
||||||
|
elif event.type == pygame.KEYUP:
|
||||||
|
if keys_pressed.get(event.key, False):
|
||||||
|
keys_pressed[event.key] = False
|
||||||
|
on_key_click(event)
|
||||||
|
|
||||||
|
|
||||||
|
class Game:
|
||||||
|
def __init__(self, size=(160, 160), scale=4.0, fps=60, font_size=30, test_mode=False):
|
||||||
|
# Start variables
|
||||||
|
self.performance_str = None
|
||||||
|
self.size, self.scale, self.fps = size, scale, fps
|
||||||
|
self.selected_item, self.spawn_radius = SandBox.Types.SAND, 10
|
||||||
|
self.screen_size = (self.size[0] * self.scale, self.size[1] * self.scale)
|
||||||
|
self.test_mode, self.performance_data, self.performance_str = test_mode, {}, ""
|
||||||
|
self.paused = False
|
||||||
|
self.keys_pressed = {}
|
||||||
|
|
||||||
|
# Start
|
||||||
|
self.sandBox = SandBox.SandBox(self.size)
|
||||||
|
|
||||||
|
# Start pygame
|
||||||
|
pygame.init()
|
||||||
|
self.screen = pygame.display.set_mode(self.screen_size, pygame.RESIZABLE)
|
||||||
|
pygame.display.set_caption("Sand box game")
|
||||||
|
|
||||||
|
# Start pygame utils
|
||||||
|
self.font = pygame.font.Font(None, font_size)
|
||||||
|
self.fps_clock = pygame.time.Clock()
|
||||||
|
|
||||||
|
def handle_key_inputs(self, event):
|
||||||
|
key_to_item = {
|
||||||
|
pygame.K_1: SandBox.Types.BG,
|
||||||
|
pygame.K_2: SandBox.Types.SAND,
|
||||||
|
pygame.K_3: SandBox.Types.WATER,
|
||||||
|
pygame.K_4: SandBox.Types.STONE,
|
||||||
|
pygame.K_5: SandBox.Types.VACUUM,
|
||||||
|
pygame.K_6: SandBox.Types.CLONER,
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.key == pygame.K_KP_PLUS and self.spawn_radius < min(self.size[0], self.size[1]):
|
||||||
|
self.spawn_radius += 10 if pygame.key.get_pressed()[pygame.K_LCTRL] else 1
|
||||||
|
elif event.key == pygame.K_KP_MINUS and self.spawn_radius > 1:
|
||||||
|
self.spawn_radius -= 10 if pygame.key.get_pressed()[pygame.K_LCTRL] else 1
|
||||||
|
elif event.key == pygame.K_p:
|
||||||
|
self.paused = not self.paused
|
||||||
|
elif event.key == pygame.K_r:
|
||||||
|
self.performance_data = {}
|
||||||
|
self.selected_item = SandBox.Types.SAND
|
||||||
|
self.spawn_radius = 10
|
||||||
|
self.sandBox.reset()
|
||||||
|
elif event.key in key_to_item:
|
||||||
|
for key, item in key_to_item.items():
|
||||||
|
if key == event.key:
|
||||||
|
self.selected_item = item
|
||||||
|
break
|
||||||
|
|
||||||
|
def handle_mouse_inputs(self):
|
||||||
|
buttons_pressed = pygame.mouse.get_pressed()
|
||||||
|
mouse_pos = pygame.mouse.get_pos()
|
||||||
|
if buttons_pressed[0]:
|
||||||
|
pos = (int(mouse_pos[0] / self.scale), int(mouse_pos[1] / self.scale))
|
||||||
|
self.sandBox.spawn(pos, self.spawn_radius, type_b=self.selected_item)
|
||||||
|
|
||||||
|
def perform_random_spawn(self):
|
||||||
|
type_b = random.choice(list(SandBox.Types))
|
||||||
|
x, y = random.randint(0, self.size[0]), random.randint(0, self.size[1])
|
||||||
|
self.sandBox.spawn((x, y), self.spawn_radius, type_b)
|
||||||
|
|
||||||
|
def performance_monitor(self):
|
||||||
|
current_fps = int(self.fps_clock.get_fps())
|
||||||
|
if current_fps in self.performance_data:
|
||||||
|
self.performance_data[current_fps] = self.performance_data[current_fps] + 1
|
||||||
|
else:
|
||||||
|
self.performance_data[current_fps] = 1
|
||||||
|
|
||||||
|
fps_sum, occurrences_count = 0, 0
|
||||||
|
for fps, count in self.performance_data.items():
|
||||||
|
occurrences_count += count
|
||||||
|
fps_sum += count * fps
|
||||||
|
sorted_keys = sorted(self.performance_data.keys())
|
||||||
|
self.performance_str = f"MIN: {sorted_keys[0]}, MAX: {sorted_keys[-1]}, AVG: {fps_sum // occurrences_count}"
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.__loading()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
handle_actions(self.keys_pressed, self.handle_key_inputs)
|
||||||
|
self.handle_mouse_inputs()
|
||||||
|
|
||||||
|
if self.test_mode and not self.paused:
|
||||||
|
self.performance_monitor()
|
||||||
|
self.perform_random_spawn()
|
||||||
|
|
||||||
|
self.__render_sand_box()
|
||||||
|
self.__render_gui()
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
self.fps_clock.tick(self.fps)
|
||||||
|
|
||||||
|
def __loading(self):
|
||||||
|
# First run to force numba compilation
|
||||||
|
thread1 = threading.Thread(target=self.sandBox.spawn, args=((0, 0), 10))
|
||||||
|
thread2 = threading.Thread(target=self.sandBox.run_physics)
|
||||||
|
thread1.start()
|
||||||
|
thread2.start()
|
||||||
|
while thread1.is_alive() or thread2.is_alive():
|
||||||
|
for i in range(4):
|
||||||
|
self.__render_message("Loading" + "".ljust(i, "."), (50, 255, 50))
|
||||||
|
time.sleep(.25)
|
||||||
|
|
||||||
|
def __render_message(self, text="", color=(0, 0, 0)):
|
||||||
|
fps_text = self.font.render(text, True, color)
|
||||||
|
self.screen.fill((0, 0, 0))
|
||||||
|
self.screen.blit(fps_text, (5, 5))
|
||||||
|
pygame.display.flip()
|
||||||
|
|
||||||
|
def __render_sand_box(self):
|
||||||
|
if not self.paused:
|
||||||
|
self.sandBox.run_physics()
|
||||||
|
sb_surface = pygame.transform.scale(self.sandBox.get_surface(), self.screen_size)
|
||||||
|
self.screen.blit(sb_surface, (0, 0))
|
||||||
|
|
||||||
|
def __render_gui(self):
|
||||||
|
fps_str = f'Item: {self.selected_item.name}, Pencil size: {self.spawn_radius}, Fps: {int(self.fps_clock.get_fps())} '
|
||||||
|
if self.test_mode:
|
||||||
|
fps_str += self.performance_str
|
||||||
|
fps_text = self.font.render(fps_str, True, (50, 255, 50))
|
||||||
|
self.screen.blit(fps_text, (5, 5))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
game = Game(size=(1000, 1000), fps=300, scale=1, test_mode=True)
|
||||||
|
game.run()
|
||||||
0
readme.md
Normal file
0
readme.md
Normal file
Loading…
Add table
Add a link
Reference in a new issue