Kos Kos - 2 months ago 15
Python Question

PyGame draw a square inside a square

I'm writing a grid-based game where instances of the Character class can move around using their move(direction) method.

class Character(object): #can move around and do cool stuff
def __init__(self, name, HP, internal_column, internal_row):
self.name = name
self.HP = HP
self.internal_column = internal_column
self.internal_row = internal_row

moves_left = 15
direction = "N"

def move(self, direction): #how characters move around

if self.moves_left == 0:
print("No more moves left")
return

elif direction == "N":
self.internal_row -= 1
self.direction = "N"
elif direction == "W":
self.internal_column -= 1
self.direction = "W"
elif direction == "E":
self.internal_column += 1
self.direction = "E"
elif direction == "S":
self.internal_row += 1
self.direction = "S"

self.moves_left = self.moves_left - 1


The direction variable keeps track of where the character is pointing. I draw the graphics using PyGame:

for row in range(MAPSIZE): # Drawing grid
for column in range(MAPSIZE):
for i in range(0, len(Map.Grid[column][row])):
Color = WHITE

if len(Map.can_move) > 0: # Creating colored area around character showing his move range
if (math.sqrt((Map.can_move[0].internal_column - column)**2 + (Map.can_move[0].internal_row - row)**2)) <= Map.can_move[0].moves_left:

Color = MOVECOLOR

if len(Map.Grid[column][row]) > 1:
Color = RED
if Map.Grid[column][row][i].name == "Tree":
Color = GREEN
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
Color = BROWN

pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,
TILEWIDTH,
TILEHEIGHT])


Here is the full code, where the constants and the Map class are defined:

import random
import pygame
import math

pygame.init()
Clock = pygame.time.Clock()
Screen = pygame.display.set_mode([650, 650])
DONE = False
MAPSIZE = 25 #how many tiles

TILEWIDTH = 20 #pixel size of tile
TILEHEIGHT = 20
TILEMARGIN = 4

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
BROWN = (123, 123, 0)
MOVECOLOR = (150, 250, 150)


KeyLookup = {
pygame.K_LEFT: "W",
pygame.K_RIGHT: "E",
pygame.K_DOWN: "S",
pygame.K_UP: "N"
}

class MapTile(object): #The main class for stationary things that inhabit the grid ... grass, trees, rocks and stuff.
def __init__(self, name, internal_column, internal_row):
self.name = name
self.internal_column = internal_column
self.internal_row = internal_row


class Character(object): #can move around and do cool stuff
def __init__(self, name, HP, internal_column, internal_row):
self.name = name
self.HP = HP
self.internal_column = internal_column
self.internal_row = internal_row

moves_left = 15
direction = "N"

def move(self, direction): #how characters move around
if self.collision_check(direction) == True:
print("Collision")
return
if self.moves_left == 0:
print("No more moves left")
return

elif direction == "N":
self.internal_row -= 1
self.direction = "N"
elif direction == "W":
self.internal_column -= 1
self.direction = "W"
elif direction == "E":
self.internal_column += 1
self.direction = "E"
elif direction == "S":
self.internal_row += 1
self.direction = "S"

self.moves_left = self.moves_left - 1


def collision_check(self, direction):
if direction == "N":
if self.internal_row == 0:
return True
if len(Map.Grid[self.internal_column][(self.internal_row)-1]) > 1:
return True
elif direction == "W":
if self.internal_column == 0:
return True
if len(Map.Grid[self.internal_column-1][(self.internal_row)]) > 1:
return True
elif direction == "E":
if self.internal_column == MAPSIZE-1:
return True
if len(Map.Grid[self.internal_column+1][(self.internal_row)]) > 1:
return True
elif direction == "S":
if self.internal_row == MAPSIZE-1:
return True
if len(Map.Grid[self.internal_column][(self.internal_row)+1]) > 1:
return True

return False

def attack(self, direction):
if self.collision_check(direction) == True:
print("attacked")


class Goblin(Character):
def __init__(self):
Character.__init__(self, "Goblin", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))

def random_move(self):
i = random.randint(0,3)
if i == 0:
self.move("N")
elif i == 1:
self.move("S")
elif i == 2:
self.move("W")
elif i == 3:
self.move("E")

self.moves_left = 10


class Archer(Character):
def __init__(self):
Character.__init__(self, "Archer", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))


class Warrior(Character):
def __init__(self):
Character.__init__(self, "Warrior", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))


class Scout(Character):
def __init__(self):
Character.__init__(self, "Scout", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))


class Rogue(Character):
def __init__(self):
Character.__init__(self, "Rogue", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))


class Wizard(Character):
def __init__(self):
Character.__init__(self, "Wizard", random.randint(15,20), random.randint(0,MAPSIZE-1), random.randint(0,MAPSIZE-1))



class Map(object): #The main class; where the action happens
global MAPSIZE
wild_characters = []
can_move = []
no_moves = []
Grid = []

for row in range(MAPSIZE): # Creating grid
Grid.append([])
for column in range(MAPSIZE):
Grid[row].append([])

for row in range(MAPSIZE): #Filling grid with grass
for column in range(MAPSIZE):
TempTile = MapTile("Grass", column, row)
Grid[column][row].append(TempTile)

for row in range(MAPSIZE): #Putting some rocks near the top
for column in range(MAPSIZE):
TempTile = MapTile("Rock", column, row)
if row == 1:
Grid[column][row].append(TempTile)

for i in range(10): #Trees in random places
random_row = random.randint(0, MAPSIZE - 1)
random_column = random.randint(0, MAPSIZE - 1)
TempTile = MapTile("Tree", random_column, random_row)
Grid[random_column][random_row].append(TempTile)

def generate_hero(self): #Generate a character and place it randomly
random_row = random.randint(0, MAPSIZE - 1)
random_column = random.randint(0, MAPSIZE - 1)
id_number = len(Map.can_move) + random.randint(0,100)
temp_hero = Character(str("Hero " + str(id_number)), 10, random_column, random_row)
self.Grid[random_column][random_row].append(temp_hero)
self.can_move.append(temp_hero)


def generate_goblin(self): #Generate a character and place it randomly
random_row = random.randint(0, MAPSIZE - 1)

random_column = random.randint(0, MAPSIZE - 1)
temp_goblin = Goblin()
self.Grid[random_column][random_row].append(temp_goblin)
Map.wild_characters.append(temp_goblin)

def update(self): #Important function
for column in range(MAPSIZE): #These nested loops go through entire grid
for row in range(MAPSIZE): #They check if any objects internal coordinates
for i in range(len(Map.Grid[column][row])): #disagree with its place on the grid and update it accordingly

if Map.Grid[column][row][i].internal_column != column:
TempChar = Map.Grid[column][row][i]
Map.Grid[column][row].remove(Map.Grid[column][row][i])
Map.Grid[int(TempChar.internal_column)][int(TempChar.internal_row)].append(TempChar)

elif Map.Grid[column][row][i].internal_row != row:
TempChar = Map.Grid[column][row][i]
Map.Grid[column][row].remove(Map.Grid[column][row][i])
Map.Grid[int(TempChar.internal_column)][int(TempChar.internal_row)].append(TempChar)


temparr = Map.no_moves[:]
for characterobject in temparr: #This moves any characters with moves to the can move list
if len(temparr) > 0:
if characterobject.moves_left > 0:
print("character moved from no moves to moves")
Map.can_move.append(characterobject)
Map.no_moves.remove(characterobject)

arr = Map.can_move[:] # copy
for item in arr:
if item.moves_left == 0:
print("character moved from moves to no moves")
Map.can_move.remove(item)
Map.no_moves.append(item)


Map = Map()
Map.generate_hero()

while not DONE: #Main pygame loop

for event in pygame.event.get(): #catching events
if event.type == pygame.QUIT:
DONE = True

elif event.type == pygame.MOUSEBUTTONDOWN:
Pos = pygame.mouse.get_pos()
column = Pos[0] // (TILEWIDTH + TILEMARGIN) #Translating the position of the mouse into rows and columns
row = Pos[1] // (TILEHEIGHT + TILEMARGIN)
print(str(row) + ", " + str(column))

for i in range(len(Map.Grid[column][row])):
print(str(Map.Grid[column][row][i].name)) #print stuff that inhabits that square

elif event.type == pygame.KEYDOWN:

wild_char_arr = Map.wild_characters[:]
for wildcharacter in wild_char_arr:
if wildcharacter.name == "Goblin":
print("Goblin moved")
wildcharacter.random_move()

if event.key == 97: # Keypress: a
print("New turn.")
temparr = Map.no_moves[:]
for item in temparr:
if item.moves_left == 0:
item.moves_left = 15

elif event.key == 115: # Keypress: s
print("Generated hero.")
Map.generate_hero()

elif event.key == 100: # Keypress: d
Map.generate_goblin()
print("Generated goblin.")

elif event.key == 102: # Keypress: f
Map.can_move[0].attack("N")

elif len(Map.can_move) > 0:
Map.can_move[0].move(KeyLookup[event.key])

else:
print("invalid")

Map.update()

Screen.fill(BLACK)



for row in range(MAPSIZE): # Drawing grid
for column in range(MAPSIZE):
for i in range(0, len(Map.Grid[column][row])):
Color = WHITE

if len(Map.can_move) > 0: # Creating colored area around character showing his move range
if (math.sqrt((Map.can_move[0].internal_column - column)**2 + (Map.can_move[0].internal_row - row)**2)) <= Map.can_move[0].moves_left:
Color = MOVECOLOR

if len(Map.Grid[column][row]) > 1:
Color = RED
if Map.Grid[column][row][i].name == "Tree":
Color = GREEN
if str(Map.Grid[column][row][i].__class__.__name__) == "Character":
Color = BROWN

pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN,
(TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,
TILEWIDTH,
TILEHEIGHT])

Clock.tick(60)
pygame.display.flip()


pygame.quit()


The problem I'm having is displaying the character's direction graphically. All I want to do is draw a small, red square inside the character's grid tile on the side they are facing. For example, if they are facing north, the small red square would be on the top side of the character's grid square.

How can I do this?

Kos Kos
Answer

Ended up doing it like this:

    if str(Map.Grid[column][row][i].__class__.__name__) == "Character":     #Drawing the little red square showing character direction
        if Map.Grid[column][row][i].direction == "N":
                Color = RED
            pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 8,
                                     (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN,
                                     TILEWIDTH/4,
                                     TILEHEIGHT/4])
    if str(Map.Grid[column][row][i].__class__.__name__) == "Character": #Drawing the little red square showing character directio
        if Map.Grid[column][row][i].direction == "S":
            Color = RED
            pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 8,
                                     (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 1 ,
                                     TILEWIDTH/4,
                                     TILEHEIGHT/4])
    if str(Map.Grid[column][row][i].__class__.__name__) == "Character": #Drawing the little red square showing character directio
        if Map.Grid[column][row][i].direction == "E":
            Color = RED
            pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN + 15,
                                     (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 8,
                                     TILEWIDTH/4,
                                     TILEHEIGHT/4])
    if str(Map.Grid[column][row][i].__class__.__name__) == "Character": #Drawing the little red square showing character directio
        if Map.Grid[column][row][i].direction == "W":
            Color = RED
            pygame.draw.rect(Screen, Color, [(TILEMARGIN + TILEWIDTH) * column + TILEMARGIN
                                             ,
                                     (TILEMARGIN + TILEHEIGHT) * row + TILEMARGIN*5 - 8 ,
                                     TILEWIDTH/4,
                                     TILEHEIGHT/4])
Comments