To much gap between last commit
Im now working next on shoorting for turret Added new sand map and new cannon tower images aswell as function to play animations, showing range, placing turrets on allowed tiles for towers Buy and cancel button to buy towers
|
After Width: | Height: | Size: 214 B |
|
After Width: | Height: | Size: 219 B |
|
After Width: | Height: | Size: 226 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 232 B |
|
After Width: | Height: | Size: 218 B |
|
After Width: | Height: | Size: 220 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 237 B |
|
After Width: | Height: | Size: 202 B |
|
After Width: | Height: | Size: 222 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 170 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 225 B |
|
After Width: | Height: | Size: 231 B |
|
After Width: | Height: | Size: 228 B |
|
After Width: | Height: | Size: 236 B |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 165 B |
|
After Width: | Height: | Size: 169 B |
|
After Width: | Height: | Size: 242 B |
|
After Width: | Height: | Size: 168 B |
|
After Width: | Height: | Size: 243 B |
|
After Width: | Height: | Size: 155 B |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 142 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 152 B |
@@ -18,7 +18,7 @@ class Editor():
|
||||
|
||||
self.manager = pgi.UIManager(self.screen.get_size(), "assets/theme/editor_theme.json")
|
||||
|
||||
self.map = 'test'
|
||||
self.map = 'desert'
|
||||
self.path = 'assets/maps/' + str(self.map) + '.json'
|
||||
|
||||
try:
|
||||
@@ -30,7 +30,8 @@ class Editor():
|
||||
|
||||
self.assets = {
|
||||
"base": load_images("/tiles/test"),
|
||||
"jungle": load_images("/tiles/jungle")
|
||||
"jungle": load_images("/tiles/jungle"),
|
||||
"desert": load_images('/tiles/desert')
|
||||
}
|
||||
|
||||
self.tile_list = list(self.assets)
|
||||
|
||||
@@ -2,7 +2,7 @@ import pygame as pg
|
||||
|
||||
class Camera():
|
||||
def __init__(self):
|
||||
self.zoom = 1
|
||||
self.zoom = 2
|
||||
self.offset = pg.math.Vector2(0, 0)
|
||||
|
||||
def world_to_screen(self, pos):
|
||||
@@ -24,3 +24,14 @@ class Camera():
|
||||
def change_zoom(self, amount):
|
||||
self.zoom += amount
|
||||
self.zoom = max(0.5, min(self.zoom, 4.0))
|
||||
|
||||
|
||||
def zoom_offset(self, screen_pos, zoom_factor):
|
||||
world_before = self.screen_to_world(screen_pos)
|
||||
|
||||
self.change_zoom(zoom_factor)
|
||||
|
||||
world_after = self.screen_to_world(screen_pos)
|
||||
|
||||
self.offset.x += world_before[0] - world_after[0]
|
||||
self.offset.y += world_before[1] - world_after[1]
|
||||
@@ -1,17 +1,18 @@
|
||||
from game.util import *
|
||||
import pygame as pg
|
||||
import math
|
||||
|
||||
class Enemy(pg.sprite.Group):
|
||||
def __init__(self, game, speed, health):
|
||||
super().__init__()
|
||||
self.game = game
|
||||
self.waypoints = self.game.tilemap.waypoints
|
||||
print(self.waypoints)
|
||||
|
||||
self.speed = speed
|
||||
self.angle = 0
|
||||
self.health = health
|
||||
|
||||
self.image = self.game.assets['enemy']
|
||||
self.image = pg.transform.rotate(self.game.assets['enemy'].copy(), self.angle)
|
||||
self.rect = self.image.get_rect()
|
||||
|
||||
self.pos = pg.Vector2(
|
||||
@@ -23,12 +24,16 @@ class Enemy(pg.sprite.Group):
|
||||
self.rect.center = self.pos
|
||||
|
||||
def update(self):
|
||||
self.move()
|
||||
self.rotate()
|
||||
|
||||
def move(self):
|
||||
if self.target_index >= len(self.waypoints):
|
||||
return
|
||||
|
||||
tile_size = self.game.tilemap.tile_size
|
||||
|
||||
target = pg.Vector2(
|
||||
self.target = pg.Vector2(
|
||||
tile_to_pixel(
|
||||
self.waypoints[self.target_index],
|
||||
tile_size,
|
||||
@@ -36,16 +41,22 @@ class Enemy(pg.sprite.Group):
|
||||
)
|
||||
)
|
||||
|
||||
direction = target - self.pos
|
||||
direction = self.target - self.pos
|
||||
distance = direction.length()
|
||||
|
||||
if distance <= self.speed:
|
||||
self.pos = target
|
||||
self.pos = self.target
|
||||
self.target_index += 1
|
||||
else:
|
||||
direction = direction.normalize()
|
||||
self.pos += direction * self.speed
|
||||
|
||||
def rotate(self):
|
||||
dist = self.target - self.pos
|
||||
|
||||
self.angle = math.degrees(math.atan2(-dist[1], dist[0]))
|
||||
self.image = pg.transform.rotate(self.game.assets['enemy'].copy(), self.angle)
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.center = self.pos
|
||||
|
||||
def render(self, surf, camera):
|
||||
|
||||
@@ -23,18 +23,15 @@ class Game:
|
||||
"assets/theme/theme.json"
|
||||
)
|
||||
self.tilemap = Tilemap(self)
|
||||
self.map = 'test'
|
||||
self.path = 'assets/maps/' + str(self.map) + '.json'
|
||||
|
||||
try:
|
||||
self.tilemap.load(self.path)
|
||||
except FileNotFoundError:
|
||||
print('File not Found')
|
||||
print(self.tilemap.waypoints)
|
||||
self.assets={
|
||||
"base": load_images('/tiles/test'),
|
||||
"jungle": load_images('/tiles/jungle'),
|
||||
"enemy": load_image('/entities/enemies/sand_monster.png')
|
||||
"desert": load_images('/tiles/desert'),
|
||||
"enemy": load_image('/entities/enemies/enemy.png'),
|
||||
"cannon": load_image('/entities/towers/cannon/shoot/0.png'),
|
||||
"red_cannon": load_image('/entities/towers/cannon/red_cannon.png'),
|
||||
"cannon/shoot": Animation(load_images('/entities/towers/cannon/shoot'), 10, False)
|
||||
}
|
||||
|
||||
self.screens = {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from game.screens.base_screen import BaseScreen
|
||||
from game.enemy import Enemy
|
||||
from game.camera import Camera
|
||||
from game.tower import Tower, TowerGroup
|
||||
from game.util import *
|
||||
import pygame as pg
|
||||
import pygame_gui as pgi
|
||||
@@ -15,19 +16,99 @@ class GamePlay(BaseScreen):
|
||||
# self.map_surface = pg.surface.Surface((self.game_surface.get_width()/self.tile_multiplicator,self.game_surface.get_height()/self.tile_multiplicator))
|
||||
|
||||
self.camera = Camera()
|
||||
self.center = (self.game_surface.get_width() /2, self.game_surface.get_height() /2)
|
||||
self.movment = [False, False, False, False]
|
||||
self.selected = None
|
||||
self.notunselect = True
|
||||
|
||||
self.map = 'test'
|
||||
self.map = 'desert'
|
||||
self.path = 'assets/maps/' + str(self.map) + '.json'
|
||||
|
||||
self.enemy = Enemy(self.game, 0.5, 100)
|
||||
|
||||
try:
|
||||
self.game.tilemap.load(self.path)
|
||||
except FileNotFoundError:
|
||||
print('File not Found')
|
||||
|
||||
self.enemy_group = pg.sprite.Group()
|
||||
self.tower_group = TowerGroup()
|
||||
|
||||
self.enemy = Enemy(self.game, 0.5, 100)
|
||||
|
||||
self.buy_button = pgi.elements.UIButton(
|
||||
relative_rect=pg.Rect(
|
||||
self.width - 200,
|
||||
self.height -250,
|
||||
150,
|
||||
50
|
||||
),
|
||||
|
||||
text="Buy Tower",
|
||||
manager=self.game.ui_manager
|
||||
)
|
||||
self.cancel_button = pgi.elements.UIButton(
|
||||
relative_rect=pg.Rect(
|
||||
self.width - 200,
|
||||
self.height -175,
|
||||
150,
|
||||
50
|
||||
),
|
||||
|
||||
text="Cancel",
|
||||
manager=self.game.ui_manager
|
||||
)
|
||||
self.buy_button.hide()
|
||||
self.cancel_button.hide()
|
||||
self.bought = False
|
||||
self.elements = [
|
||||
self.buy_button,
|
||||
self.cancel_button
|
||||
]
|
||||
|
||||
def process_event(self, event):
|
||||
#calculate tile position from mouse position
|
||||
self.mpos = pg.mouse.get_pos()
|
||||
game_rect = self.game_surface.get_rect(topleft=(0, self.height / 6))
|
||||
|
||||
if game_rect.collidepoint(self.mpos):
|
||||
local_mpos = (
|
||||
self.mpos[0] - game_rect.x,
|
||||
self.mpos[1] - game_rect.y
|
||||
)
|
||||
|
||||
world_pos = self.camera.screen_to_world(local_mpos)
|
||||
self.tile_pos_decimal = pixel_to_tile(world_pos, self.game.tilemap.tile_size)
|
||||
self.tile_pos = (int(self.tile_pos_decimal[0]), int(self.tile_pos_decimal[1]))
|
||||
else:
|
||||
self.tile_pos = None
|
||||
|
||||
if event.type == pgi.UI_BUTTON_PRESSED:
|
||||
if event.ui_element == self.buy_button:
|
||||
self.bought = True
|
||||
# self.tower = Tower(self.game, self.mpos, self.tile_pos, 'cannon')
|
||||
if event.ui_element == self.cancel_button:
|
||||
self.bought = False
|
||||
|
||||
self.tile_pos = (int(self.tile_pos_decimal[0]), int(self.tile_pos_decimal[1]))
|
||||
if event.type == pg.MOUSEBUTTONDOWN:
|
||||
if self.tile_pos is not None:
|
||||
if event.button == 1:
|
||||
self.selected = self.select_turret(self.tile_pos)
|
||||
self.clear_selection()
|
||||
if self.selected is not None:
|
||||
print(f'selected: {self.selected}')
|
||||
self.selected.selected = True
|
||||
print(f'{self.selected}')
|
||||
if self.bought:
|
||||
if self.game.tilemap.placeable(self.tile_pos):
|
||||
if not any(tower.tile_pos == self.tile_pos for tower in self.tower_group):
|
||||
tower = Tower(self.game, self.mpos, self.tile_pos, 'cannon', 40)
|
||||
self.tower_group.add(tower)
|
||||
self.bought = False
|
||||
if event.button == 3:
|
||||
for tower in self.tower_group:
|
||||
if tower.tile_pos == self.tile_pos:
|
||||
tower.kill()
|
||||
|
||||
if event.type == pg.KEYDOWN:
|
||||
if event.key == pg.K_a:
|
||||
self.movment[0] = True
|
||||
@@ -39,9 +120,9 @@ class GamePlay(BaseScreen):
|
||||
self.movment[3] = True
|
||||
|
||||
if event.key == pg.K_q:
|
||||
self.camera.change_zoom(-0.25)
|
||||
self.camera.zoom_offset(self.center, -0.25)
|
||||
if event.key == pg.K_e:
|
||||
self.camera.change_zoom(0.25)
|
||||
self.camera.zoom_offset(self.center ,0.25)
|
||||
if event.type == pg.KEYUP:
|
||||
if event.key == pg.K_a:
|
||||
self.movment[0] = False
|
||||
@@ -54,6 +135,7 @@ class GamePlay(BaseScreen):
|
||||
|
||||
def update(self, dt):
|
||||
self.enemy.update()
|
||||
self.tower_group.update("sigma")
|
||||
|
||||
self.camera.move((self.movment[1] - self.movment[0]) * 2, (self.movment[3] - self.movment[2]) * 2)
|
||||
|
||||
@@ -64,7 +146,26 @@ class GamePlay(BaseScreen):
|
||||
self.game.tilemap.render_game(self.game_surface, self.camera)
|
||||
|
||||
self.enemy.render(self.game_surface, self.camera)
|
||||
self.tower_group.render(self.game_surface, self.camera)
|
||||
|
||||
if self.bought:
|
||||
if self.game.tilemap.placeable(self.tile_pos):
|
||||
self.game_surface.blit(pg.transform.scale2x(self.game.assets["cannon"]), (self.mpos[0] - (self.game.tilemap.tile_size //2), self.mpos[1] - (self.game.tilemap.tile_size //2 + self.height/6)))
|
||||
else:
|
||||
self.game_surface.blit(pg.transform.scale2x(self.game.assets["red_cannon"]), (self.mpos[0] - (self.game.tilemap.tile_size //2), self.mpos[1] - (self.game.tilemap.tile_size //2 + self.height/6)))
|
||||
|
||||
# self.game_surface.blit(pg.transform.scale(self.map_surface, self.game_surface.get_size()))
|
||||
|
||||
surface.blit(self.game_surface, (0, self.height/6))
|
||||
|
||||
# if self.bought:
|
||||
# self.game_surface.blit(pg.transform.scale2x(self.game.assets["cannon"]), (self.mpos[0] - (self.game.tilemap.tile_size //2), self.mpos[1] - (self.game.tilemap.tile_size //2)))
|
||||
|
||||
def select_turret(self, tile_pos):
|
||||
for tower in self.tower_group:
|
||||
if (tile_pos[0], tile_pos[1]) == (tower.tile_pos[0], tower.tile_pos[1]):
|
||||
return tower
|
||||
|
||||
def clear_selection(self):
|
||||
for tower in self.tower_group:
|
||||
tower.selected = False
|
||||
@@ -70,7 +70,6 @@ class MainMenu(BaseScreen):
|
||||
if event.type == pgi.UI_BUTTON_PRESSED:
|
||||
|
||||
if event.ui_element == self.play_button:
|
||||
|
||||
# Zum Gameplay wechseln
|
||||
self.game.change_screen("game")
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ class Tilemap:
|
||||
self.offgrid_tiles = []
|
||||
self.waypoints=[]
|
||||
|
||||
self.tower_placeable = [{"type": "desert", "variant": 0}]
|
||||
|
||||
def save(self, path):
|
||||
f = open(path, 'w')
|
||||
json.dump({'tilemap': self.tilemap, 'tile_size': self.tile_size, 'waypoints': self.waypoints}, f)
|
||||
@@ -27,6 +29,17 @@ class Tilemap:
|
||||
self.tile_size = map_data['tile_size']
|
||||
self.waypoints = map_data['waypoints']
|
||||
|
||||
def placeable(self, tile_pos):
|
||||
str_tile_pos = f'{tile_pos[0]};{tile_pos[1]}'
|
||||
if str_tile_pos not in self.tilemap:
|
||||
return False
|
||||
|
||||
tile = self.tilemap[str_tile_pos]
|
||||
for ti in self.tower_placeable:
|
||||
if tile['type'] == ti['type'] and tile['variant'] == ti['variant']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def render(self, surf, offset=(0, 0)):
|
||||
for x in range(offset[0] // self.tile_size, (offset[0] + surf.get_width()) // self.tile_size + 1):
|
||||
for y in range(offset[1] // self.tile_size, (offset[1] + surf.get_height()) // self.tile_size + 1):
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import pygame as pg
|
||||
from game.util import *
|
||||
|
||||
class Tower(pg.sprite.Sprite):
|
||||
def __init__(self, game, pos, tile_pos, type, range, level=1):
|
||||
super().__init__()
|
||||
self.game = game
|
||||
self.type = type
|
||||
self.image = self.game.assets[type]
|
||||
self.rect = self.image.get_rect()
|
||||
self.rect.center = pos
|
||||
|
||||
self.range = range
|
||||
self.selected = False
|
||||
|
||||
self.pos = pos
|
||||
self.tile_pos = tile_pos
|
||||
self.level = level
|
||||
self.action = ""
|
||||
self.set_action('shoot')
|
||||
|
||||
def update(self, enemies):
|
||||
self.animation.update()
|
||||
|
||||
def set_action(self, action):
|
||||
if action != self.action:
|
||||
self.action = action
|
||||
self.animation = self.game.assets[self.type + '/' + self.action].copy()
|
||||
|
||||
def render(self, surf, camera):
|
||||
screen_pos = camera.world_to_screen(pg.Vector2(
|
||||
tile_to_pixel(self.tile_pos, self.game.tilemap.tile_size, True)
|
||||
))
|
||||
|
||||
anim_img = self.animation.img()
|
||||
scaled_image = pg.transform.scale(
|
||||
anim_img,
|
||||
(
|
||||
int(anim_img.get_width() * camera.zoom),
|
||||
int(anim_img.get_height() * camera.zoom)
|
||||
)
|
||||
)
|
||||
|
||||
rect = scaled_image.get_rect(center=screen_pos)
|
||||
|
||||
if self.selected:
|
||||
scaled_range = int(self.range * camera.zoom)
|
||||
range_surf = pg.Surface((scaled_range * 2, scaled_range * 2), pg.SRCALPHA)
|
||||
pg.draw.circle(range_surf, (200, 200, 200, 100), (scaled_range, scaled_range), scaled_range)
|
||||
range_rect = range_surf.get_rect(center=screen_pos)
|
||||
surf.blit(range_surf, range_rect)
|
||||
|
||||
surf.blit(scaled_image, rect)
|
||||
|
||||
class TowerGroup(pg.sprite.Group):
|
||||
def render(self, surf, camera):
|
||||
for tower in self.sprites():
|
||||
tower.render(surf, camera)
|
||||
|
||||
def update(self, enemies):
|
||||
for tower in self.sprites():
|
||||
tower.update(enemies)
|
||||
@@ -26,3 +26,31 @@ def tile_to_pixel(waypoint, tile_size, center=False):
|
||||
waypoint[0] * tile_size,
|
||||
waypoint[1] * tile_size
|
||||
)
|
||||
|
||||
def pixel_to_tile(waypoint, tile_size):
|
||||
return (
|
||||
waypoint[0] / tile_size,
|
||||
waypoint[1] / tile_size
|
||||
)
|
||||
|
||||
class Animation:
|
||||
def __init__(self, images, img_dur=5, loop=True):
|
||||
self.images = images
|
||||
self.loop = loop
|
||||
self.img_duration = img_dur
|
||||
self.done = False
|
||||
self.frame = 0
|
||||
|
||||
def copy(self):
|
||||
return Animation(self.images, self.img_duration, self.loop)
|
||||
|
||||
def update(self):
|
||||
if self.loop:
|
||||
self.frame = (self.frame + 1) % (self.img_duration * len(self.images))
|
||||
else:
|
||||
self.frame = min(self.frame + 1, self.img_duration * len(self.images))
|
||||
if self.frame >= self.img_duration * len(self.images) - 1:
|
||||
self.done = True
|
||||
|
||||
def img(self):
|
||||
return self.images[int(self.frame / self.img_duration) - 1]
|
||||