Skip to content

Commit 9137c51

Browse files
author
cent5
committed
Week 2 - 1: broken into 4 files
1 parent c675241 commit 9137c51

File tree

4 files changed

+213
-179
lines changed

4 files changed

+213
-179
lines changed

src/common.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import enum
2+
3+
import pygame
4+
from pygame.color import Color
5+
from pygame.surface import Surface
6+
from utils import scale_image
7+
8+
SCREEN_WIDTH: int = 1280
9+
SCREEN_HEIGHT: int = 768
10+
11+
WHITE: Color = Color(255, 255, 255)
12+
RED: Color = Color(255, 0, 0) # Màu Đỏ
13+
BLUE: Color = Color(0, 0, 255) # Màu Xanh
14+
15+
FPS: int = 30 # Số cảnh mỗi giây (frame per second)
16+
17+
# Fonts
18+
pygame.font.init()
19+
FREESANSBOLD_24 = pygame.font.Font("freesansbold.ttf", 24)
20+
FREESANSBOLD_48 = pygame.font.Font("freesansbold.ttf", 48)
21+
22+
# Hình nền:
23+
BACKGROUND_SPRITE: Surface = pygame.image.load("assets/background.png")
24+
BACKGROUND_SPRITE.set_alpha(128)
25+
BACKGROUND_SPRITE = pygame.transform.scale(BACKGROUND_SPRITE, [SCREEN_WIDTH, SCREEN_HEIGHT])
26+
27+
# Game Entities Sprites
28+
PLAYER_SPRITE: Surface = scale_image(pygame.image.load("assets/player.png"), 0.2)
29+
ROBOT_SPRITE: Surface = scale_image(pygame.image.load("assets/robot.png"), 0.08)
30+
DIAMOND_BLUE_SPRITE: Surface = scale_image(pygame.image.load("assets/diamond_blue.png"), 0.02)
31+
DIAMOND_RED_SPRITE: Surface = scale_image(pygame.image.load("assets/diamond_red.png"), 0.02)
32+
TO_MO_SPRITE: Surface = scale_image(pygame.image.load("assets/to_mo.png"), 0.2)
33+
34+
35+
class EntityType(enum.Enum):
36+
PLAYER = enum.auto()
37+
ROBOT = enum.auto()
38+
DIAMOND_BLUE = enum.auto()
39+
DIAMOND_RED = enum.auto()
40+
41+
42+
class GameState(enum.Enum):
43+
RUNNING = enum.auto()
44+
WON = enum.auto()
45+
LOST = enum.auto()

src/entities.py

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
from typing import Optional
2+
3+
import pygame
4+
from pygame.surface import Surface
5+
6+
from common import (
7+
BLUE,
8+
FREESANSBOLD_24,
9+
FREESANSBOLD_48,
10+
RED,
11+
SCREEN_HEIGHT,
12+
SCREEN_WIDTH,
13+
GameState,
14+
)
15+
16+
17+
class Player:
18+
def __init__(self, x: int, y: int, image: Surface) -> None:
19+
self.x = x
20+
self.y = y
21+
self.image = image
22+
23+
def _move(self, dx: int, dy: int):
24+
new_x = self.x + dx
25+
new_y = self.y + dy
26+
27+
if 0 < new_x < SCREEN_WIDTH - self.image.get_width():
28+
self.x = new_x
29+
if 0 < new_y < SCREEN_HEIGHT - self.image.get_height():
30+
self.y = new_y
31+
32+
def update(self) -> None:
33+
pressed = pygame.key.get_pressed()
34+
if pressed[pygame.K_UP] or pressed[pygame.K_w]:
35+
self._move(0, -10)
36+
if pressed[pygame.K_DOWN] or pressed[pygame.K_s]:
37+
self._move(0, 10)
38+
if pressed[pygame.K_LEFT] or pressed[pygame.K_a]:
39+
self._move(-10, 0)
40+
if pressed[pygame.K_RIGHT] or pressed[pygame.K_d]:
41+
self._move(10, 0)
42+
43+
def render(self, screen: Surface) -> None:
44+
screen.blit(self.image, (self.x, self.y))
45+
46+
47+
class Robot:
48+
def __init__(self, x: int, y: int, image: Surface, x_heading: int, y_heading: int) -> None:
49+
self.x = x
50+
self.y = y
51+
self.image = image
52+
self.x_heading = x_heading
53+
self.y_heading = y_heading
54+
55+
def update(self):
56+
self.x = self.x + self.x_heading
57+
self.y = self.y + self.y_heading
58+
59+
if self.x > SCREEN_WIDTH - self.image.get_width():
60+
self.x_heading = -self.x_heading
61+
if self.x < 0:
62+
self.x_heading = -self.x_heading
63+
if self.y > SCREEN_HEIGHT - self.image.get_height():
64+
self.y_heading = -self.y_heading
65+
if self.y < 0:
66+
self.y_heading = -self.y_heading
67+
68+
def render(self, screen: Surface) -> None:
69+
screen.blit(self.image, (self.x, self.y))
70+
71+
72+
class NPC:
73+
def __init__(self, x: int, y: int, image: Surface) -> None:
74+
self.x = x
75+
self.y = y
76+
self.image = image
77+
78+
def render(self, screen: Surface) -> None:
79+
screen.blit(self.image, (self.x, self.y))
80+
81+
82+
class GameItem:
83+
def __init__(self, x: int, y: int, image: Surface) -> None:
84+
self.x = x
85+
self.y = y
86+
self.image = image
87+
self.hidden = False
88+
89+
def set_hidden(self):
90+
self.hidden = True
91+
92+
def render(self, screen: Surface) -> None:
93+
if not self.hidden:
94+
screen.blit(self.image, (self.x, self.y))
95+
96+
97+
class GameStatus:
98+
def __init__(self) -> None:
99+
self.score: int = 0
100+
self.state: GameState = GameState.RUNNING
101+
102+
def update_state(self, state: GameState) -> None:
103+
self.state = state
104+
105+
def update_score(self, delta: int) -> None:
106+
self.score += delta
107+
108+
def render(self, screen: Surface) -> None:
109+
# Score Text Render on Top Left Corner
110+
score_text = FREESANSBOLD_24.render("Score: %d" % self.score, True, BLUE)
111+
screen.blit(score_text, (10, 10))
112+
113+
# Status Text Render in Middle of Screen
114+
status_text = None
115+
if self.state == GameState.WON:
116+
status_text = FREESANSBOLD_48.render("YOU WON!!", True, RED)
117+
elif self.state == GameState.LOST:
118+
status_text = FREESANSBOLD_48.render("YOU LOST!!", True, RED)
119+
120+
if status_text:
121+
position = (
122+
SCREEN_WIDTH // 2 - status_text.get_width() // 2,
123+
SCREEN_HEIGHT // 2 - status_text.get_height() // 2,
124+
)
125+
126+
screen.blit(status_text, position)
127+
128+
def is_running(self):
129+
return self.state == GameState.RUNNING

src/main.py

Lines changed: 17 additions & 179 deletions
Original file line numberDiff line numberDiff line change
@@ -1,188 +1,26 @@
1-
import enum
2-
from typing import List, Optional, Tuple
1+
from typing import List
32

43
import pygame
5-
from pygame import Color
4+
from entities import NPC, GameItem, GameStatus, Player, Robot
65
from pygame.surface import Surface
6+
from utils import overlap
7+
8+
from common import (
9+
BACKGROUND_SPRITE,
10+
DIAMOND_BLUE_SPRITE,
11+
DIAMOND_RED_SPRITE,
12+
FPS,
13+
PLAYER_SPRITE,
14+
ROBOT_SPRITE,
15+
SCREEN_HEIGHT,
16+
SCREEN_WIDTH,
17+
TO_MO_SPRITE,
18+
WHITE,
19+
GameState,
20+
)
721

822
pygame.init()
923

10-
SCREEN_WIDTH: int = 1280
11-
SCREEN_HEIGHT: int = 768
12-
13-
WHITE: Color = Color(255, 255, 255)
14-
RED: Color = Color(255, 0, 0) # Màu Đỏ
15-
BLUE: Color = Color(0, 0, 255) # Màu Xanh
16-
17-
FPS: int = 30 # Số cảnh mỗi giây (frame per second)
18-
19-
# Fonts
20-
pygame.font.init()
21-
FREESANSBOLD_24 = pygame.font.Font("freesansbold.ttf", 24)
22-
FREESANSBOLD_48 = pygame.font.Font("freesansbold.ttf", 48)
23-
24-
# Hình nền:
25-
BACKGROUND_SPRITE: Surface = pygame.image.load("assets/background.png")
26-
BACKGROUND_SPRITE.set_alpha(128)
27-
BACKGROUND_SPRITE = pygame.transform.scale(BACKGROUND_SPRITE, [SCREEN_WIDTH, SCREEN_HEIGHT])
28-
29-
30-
# Hàm tiện ích (utility)
31-
def scale_image(image: Surface, scale: float) -> Surface:
32-
"""Resizes image by a factor of input arg `scale`."""
33-
new_dimension: Tuple[int, int] = (
34-
int(image.get_width() * scale),
35-
int(image.get_height() * scale),
36-
)
37-
return pygame.transform.scale(image, new_dimension)
38-
39-
40-
# Game Entities Sprites
41-
PLAYER_SPRITE: Surface = scale_image(pygame.image.load("assets/player.png"), 0.2)
42-
ROBOT_SPRITE: Surface = scale_image(pygame.image.load("assets/robot.png"), 0.08)
43-
DIAMOND_BLUE_SPRITE: Surface = scale_image(pygame.image.load("assets/diamond_blue.png"), 0.02)
44-
DIAMOND_RED_SPRITE: Surface = scale_image(pygame.image.load("assets/diamond_red.png"), 0.02)
45-
TO_MO_SPRITE: Surface = scale_image(pygame.image.load("assets/to_mo.png"), 0.2)
46-
47-
48-
# Hàm tiện ích (utility)
49-
def overlap(x1: int, y1: int, image1: Surface, x2: int, y2: int, image2: Surface) -> bool:
50-
"""Returns True if 2 items overlap."""
51-
mask1 = pygame.mask.from_surface(image1)
52-
mask2 = pygame.mask.from_surface(image2)
53-
offset_x = x2 - x1
54-
offset_y = y2 - y1
55-
return bool(mask1.overlap(mask2, (offset_x, offset_y)))
56-
57-
58-
class EntityType(enum.Enum):
59-
PLAYER = enum.auto()
60-
ROBOT = enum.auto()
61-
DIAMOND_BLUE = enum.auto()
62-
DIAMOND_RED = enum.auto()
63-
64-
65-
class GameState(enum.Enum):
66-
RUNNING = enum.auto()
67-
WON = enum.auto()
68-
LOST = enum.auto()
69-
70-
71-
class Player:
72-
def __init__(self, x: int, y: int, image: Surface) -> None:
73-
self.x = x
74-
self.y = y
75-
self.image = image
76-
77-
def _move(self, dx: int, dy: int):
78-
new_x = self.x + dx
79-
new_y = self.y + dy
80-
81-
if 0 < new_x < SCREEN_WIDTH - self.image.get_width():
82-
self.x = new_x
83-
if 0 < new_y < SCREEN_HEIGHT - self.image.get_height():
84-
self.y = new_y
85-
86-
def update(self) -> None:
87-
pressed = pygame.key.get_pressed()
88-
if pressed[pygame.K_UP] or pressed[pygame.K_w]:
89-
self._move(0, -10)
90-
if pressed[pygame.K_DOWN] or pressed[pygame.K_s]:
91-
self._move(0, 10)
92-
if pressed[pygame.K_LEFT] or pressed[pygame.K_a]:
93-
self._move(-10, 0)
94-
if pressed[pygame.K_RIGHT] or pressed[pygame.K_d]:
95-
self._move(10, 0)
96-
97-
def render(self, screen: Surface) -> None:
98-
screen.blit(self.image, (self.x, self.y))
99-
100-
101-
class Robot:
102-
def __init__(self, x: int, y: int, image: Surface, x_heading: int, y_heading: int) -> None:
103-
self.x = x
104-
self.y = y
105-
self.image = image
106-
self.x_heading = x_heading
107-
self.y_heading = y_heading
108-
109-
def update(self):
110-
self.x = self.x + self.x_heading
111-
self.y = self.y + self.y_heading
112-
113-
if self.x > SCREEN_WIDTH - self.image.get_width():
114-
self.x_heading = -self.x_heading
115-
if self.x < 0:
116-
self.x_heading = -self.x_heading
117-
if self.y > SCREEN_HEIGHT - self.image.get_height():
118-
self.y_heading = -self.y_heading
119-
if self.y < 0:
120-
self.y_heading = -self.y_heading
121-
122-
def render(self, screen: Surface) -> None:
123-
screen.blit(self.image, (self.x, self.y))
124-
125-
126-
class NPC:
127-
def __init__(self, x: int, y: int, image: Surface) -> None:
128-
self.x = x
129-
self.y = y
130-
self.image = image
131-
132-
def render(self, screen: Surface) -> None:
133-
screen.blit(self.image, (self.x, self.y))
134-
135-
136-
class GameItem:
137-
def __init__(self, x: int, y: int, image: Surface) -> None:
138-
self.x = x
139-
self.y = y
140-
self.image = image
141-
self.hidden = False
142-
143-
def set_hidden(self):
144-
self.hidden = True
145-
146-
def render(self, screen: Surface) -> None:
147-
if not self.hidden:
148-
screen.blit(self.image, (self.x, self.y))
149-
150-
151-
class GameStatus:
152-
def __init__(self) -> None:
153-
self.score: int = 0
154-
self.state: GameState = GameState.RUNNING
155-
156-
def update_state(self, state: GameState) -> None:
157-
self.state = state
158-
159-
def update_score(self, delta: int) -> None:
160-
self.score += delta
161-
162-
def render(self, screen: Surface) -> None:
163-
# Score Text Render on Top Left Corner
164-
score_text = FREESANSBOLD_24.render("Score: %d" % self.score, True, BLUE)
165-
screen.blit(score_text, (10, 10))
166-
167-
# Status Text Render in Middle of Screen
168-
status_text = None
169-
if self.state == GameState.WON:
170-
status_text = FREESANSBOLD_48.render("YOU WON!!", True, RED)
171-
elif self.state == GameState.LOST:
172-
status_text = FREESANSBOLD_48.render("YOU LOST!!", True, RED)
173-
174-
if status_text:
175-
position = (
176-
SCREEN_WIDTH // 2 - status_text.get_width() // 2,
177-
SCREEN_HEIGHT // 2 - status_text.get_height() // 2,
178-
)
179-
180-
screen.blit(status_text, position)
181-
182-
def is_running(self):
183-
return self.state == GameState.RUNNING
184-
185-
18624
screen: Surface = pygame.display.set_mode([SCREEN_WIDTH, SCREEN_HEIGHT])
18725
clock = pygame.time.Clock()
18826

0 commit comments

Comments
 (0)