예제 #1
0
    def setup(self):
        print ("game setting up...")

        self.messages = MessageLog()
        self._add_message("Welcome to your doom!")

        print ("setting up world...")
        self.world = World(self.window.width, self.window.height)

        spawnCoord = self._pick_random_spawn_coords(level=0)

        print ("setting up player...")
        self.player = Player(x=spawnCoord[0], y=spawnCoord[1])
        self._entities.append(self.player)

        print ("player is created!")

        itemIds = item_config.level_items[0]
        for itemId in itemIds:
            if itemId in item_config.item_types:
                item = item_config.item_types[itemId]
                itemSpawnCoord = self._pick_random_spawn_coords(level=0)
                item["x"] = itemSpawnCoord[0]
                item["y"] = itemSpawnCoord[1]
                item["level"] = itemSpawnCoord[2]
                itemInstance = Item(**item)
                self._entities.append(itemInstance)
                self._itemsData[itemSpawnCoord] = itemInstance
                itemIds = item_config.level_items[0]

        enemyTuples = enemy_config.level_enemies[0]
        for enemyTuple in enemyTuples:
            if enemyTuple[0] in enemy_config.enemy_types:
                enemy = enemy_config.enemy_types[enemyTuple[0]]
                for i in range(enemyTuple[1]):
                    enemyCoord = self._pick_random_spawn_coords(
                                                        level=0,
                                                        inRoomRequired=False)
                    enemy["x"] = enemyCoord[0]
                    enemy["y"] = enemyCoord[1]
                    enemy["level"] = enemyCoord[2]
                    enemyInstance = Enemy(**enemy)
                    self._entities.append(enemyInstance)
                    #self._enemiesData[enemyCoord] = enemyInstance


        self._generate_fov()

        # The first view in the game will be the GameMapView
        self.switch_view_class(GameMapView)

        return True
예제 #2
0
class GameController(Controller):
    batch = pyglet.graphics.Batch()

    def __init__(self, *args, **kwargs):
        super(GameController, self).__init__(*args, **kwargs)

        self.world = None
        self.player = None

        self._visibleMapSprites = {}
        self._itemsData = {}
        self._litCoords = []
        self._memoryCoords = []
        self._entities = []

        pyglet.clock.schedule_interval(self._decay_torches, 10)
        pyglet.clock.schedule_interval(self._enemy_ai, 1)

    def update(self, dt):
        pass

    def setup(self):
        print ("game setting up...")

        self.messages = MessageLog()
        self._add_message("Welcome to your doom!")

        print ("setting up world...")
        self.world = World(self.window.width, self.window.height)

        spawnCoord = self._pick_random_spawn_coords(level=0)

        print ("setting up player...")
        self.player = Player(x=spawnCoord[0], y=spawnCoord[1])
        self._entities.append(self.player)

        print ("player is created!")

        itemIds = item_config.level_items[0]
        for itemId in itemIds:
            if itemId in item_config.item_types:
                item = item_config.item_types[itemId]
                itemSpawnCoord = self._pick_random_spawn_coords(level=0)
                item["x"] = itemSpawnCoord[0]
                item["y"] = itemSpawnCoord[1]
                item["level"] = itemSpawnCoord[2]
                itemInstance = Item(**item)
                self._entities.append(itemInstance)
                self._itemsData[itemSpawnCoord] = itemInstance
                itemIds = item_config.level_items[0]

        enemyTuples = enemy_config.level_enemies[0]
        for enemyTuple in enemyTuples:
            if enemyTuple[0] in enemy_config.enemy_types:
                enemy = enemy_config.enemy_types[enemyTuple[0]]
                for i in range(enemyTuple[1]):
                    enemyCoord = self._pick_random_spawn_coords(
                                                        level=0,
                                                        inRoomRequired=False)
                    enemy["x"] = enemyCoord[0]
                    enemy["y"] = enemyCoord[1]
                    enemy["level"] = enemyCoord[2]
                    enemyInstance = Enemy(**enemy)
                    self._entities.append(enemyInstance)
                    #self._enemiesData[enemyCoord] = enemyInstance


        self._generate_fov()

        # The first view in the game will be the GameMapView
        self.switch_view_class(GameMapView)

        return True

    def _decay_torches(self, dt):
        for item in self._entities:
            if item.name == "Torch":
                if item.lightLevel > 0:
                    item.lightLevel -= 1

    def _enemy_ai(self, dt):
        for entity in self._entities:
            if entity.__class__.__name__ == "Enemy":
                j = 0
                while True:
                    j += 1
                    dx, dy, distance = utils.compare_coords(
                        entity.get_coords(),
                        self.player.get_coords()
                        )
                    if distance < 400:
                        axis = random.choice([(dx, 0, 180), (dy, 90, 270)])
                        if axis[0] > 0:
                            direction = axis[1]
                        else:
                            direction = axis[2]

                    else:
                        direction = random.choice([0, 90, 180, 270])
                    completed = self._move_entity(entity, direction)
                    if completed:
                        break
                    if j >= 4:
                        break


    def _move_entity(self, entity, angle):
        currentCoords = (entity.x, entity.y, entity.level)
        coords = self._new_entity_pos(currentCoords, angle)
        if not self._return_collision(coords):
            entity.move(coords)
            entity.change_angle(angle)
            return True
        return False

    def _add_message(self, message):
        self.messages.add(str(message))
        if self.current_view:
            self.current_view.refresh_message_hud()

    def _pick_random_spawn_coords(self, level=0, inRoomRequired=True):
        cSW = self.world.chunksWide * self.world.cs
        cSH = self.world.chunksHigh * self.world.cs
        maxLoop = cSW * cSH
        j = 0
        while True:
            j += 1

            coordX = random.randint(3,cSW-2)
            coordY = random.randint(3,cSH-2)
            spawnCoord = (coordX*self.world.ss, coordY*self.world.ss, level)
            if spawnCoord in self.world.mapTileData:
                tileData = self.world.mapTileData[spawnCoord]
                if inRoomRequired:
                    if tileData["roomFloorTile"]:
                        break
                else:
                    if not tileData["collisionTile"]:
                        break

            if j >= maxLoop:
                spawnCoord = (256,256,level)
                break
        return spawnCoord

    def _new_entity_angle(self, currentAngle, modifier):
        newAngle = (currentAngle + modifier) % 360
        return newAngle

    def _new_entity_pos(self, coords, angle):
        x, y, z = coords[0], coords[1], coords[2]
        ss = self.world.ss
        if angle == 0:
            x += ss
        elif angle == 90:
            y += ss
        elif angle == 180:
            x -= ss
        elif angle == 270:
            y -= ss
        return (x, y, z)

    def _return_collision(self, coord):
        if coord in self.world.mapTileData:
            return self.world.mapTileData[coord]['collisionTile']
        return True

    def _return_is_lit(self, coord):
        return coord in self._litCoords

    def _set_lit(self,coord):
        if coord in self.world.mapTileData:
            self._litCoords.append(coord)

    def _cast_light(self, cx, cy, row, start, end, radius, xx, xy, yx, yy, id):
        if start < end:
            return

        ss = self.world.ss
        z = self.player.level
        radiusSquared = radius * radius
        for j in range(row, radius+1):
            dx, dy = -j-1, -j
            blocked = False
            while dx <=0:
                dx += 1
                x, y = (cx + ((dx*xx+dy*xy)*ss), cy + ((dx * yx + dy * yy)*ss))
                lSlope, rSlope = (dx-0.5)/(dy+0.5), (dx+0.5)/(dy-0.5)
                if start <  rSlope:
                    continue
                elif end > lSlope:
                    break
                else:
                    if dx*dx + dy*dy < radiusSquared:
                        self._set_lit((x, y, z))
                    if blocked:
                        if self._return_collision((x, y, z)):
                            newStart = rSlope
                            continue
                        else:
                            blocked = False
                            start = newStart
                    else:
                        if self._return_collision((x, y, z)) and j < radius:
                            blocked = True
                            self._cast_light( cx,cy,j+1,start,lSlope,radius,
                                             xx,xy,yx,yy, id+1)
                            newStart = rSlope
            if blocked:
                break

    def _generate_fov(self):
        self._litCoords = []
        entityCoords = {}
        for entity in self._entities:
            entityPosition = entity.get_coords()

            if entity.lightLevel <= 0:
                entityCoords[entityPosition] = entity
                print (entityPosition)
            else:
                entity.sprite = pyglet.sprite.Sprite(
                    entity.spriteImg,
                    x=entity.x,
                    y=entity.y,
                    batch=self.batch,
                    group=entity.group
                    )

                visionSections = 8
                lightLevel = entity.lightLevel
                multi = [
                        [1, 0, 0,-1,-1, 0, 0, 1],
                        [0, 1,-1, 0, 0,-1, 1, 0],
                        [0, 1, 1, 0, 0,-1,-1, 0],
                        [1, 0, 0, 1,-1, 0, 0,-1],
                        ]

                inRoom = self.world.mapTileData[entityPosition]["roomTile"]
                if not inRoom and entity.__class__.__name__ == "Player":
                    visionSections = 2
                    lightLevel = int(entity.lightLevel//1.6)
                    if entity.angle == 0:
                        multi = [[0, 0], [-1, -1], [1, -1], [0, 0]]
                    elif entity.angle == 90:
                        multi = [[-1, 1], [0, 0], [0, 0], [-1, -1]]
                    elif entity.angle == 180:
                        multi = [[0, 0], [1, 1], [-1, 1], [0, 0]]
                    else:
                        multi = [[1, -1], [0, 0], [0, 0], [1, 1]]

                for section in range(visionSections):
                    self._cast_light(
                                     entityPosition[0],
                                     entityPosition[1],
                                     1,
                                     1.0,
                                     0.0,
                                     lightLevel,
                                     multi[0][section],
                                     multi[1][section],
                                     multi[2][section],
                                     multi[3][section],
                                     0
                                     )

                self._litCoords.append(entityPosition)

        for coord in self._litCoords:
            tileData = None
            if coord in self.world.mapTileData:
                tileData = self.world.mapTileData[coord]
                group = self.world.group
            if coord in entityCoords:
                entity = entityCoords[coord]
                group = entity.group
                tileData = entity.__dict__

            if tileData:
                spriteData = pyglet.sprite.Sprite(
                                            img=tileData["spriteImg"],
                                            x=coord[0],
                                            y=coord[1],
                                            batch=self.batch,
                                            group=group
                                            )
                self._visibleMapSprites[coord] = spriteData

        memoryCoords = self._visibleMapSprites.keys() - self._litCoords

        for tileCoord in memoryCoords:
            if tileCoord in self._visibleMapSprites:
                tile = self._visibleMapSprites[tileCoord]
                tile.opacity = 20


        # # Python 2.7   iteritems()
        # for key, tileData in self.world.mapTileData.items():
        #     self._visibleMapSprites.append(
        #                                    pyglet.sprite.Sprite(
        #                                         img=tileData["sprite"],
        #                                         x=key[0],
        #                                         y=key[1],
        #                                         batch=self.batch,
        #                                         group=self.world.group
        #                                         )
        #                                    )

    def _update_tile_hud_data(self):
        tileInfrontData, tileOnData = self.get_tile_hud_data()
        self.current_view.tileInfrontData.text = "In Front:  {}".format(tileInfrontData['name'])
        self.current_view.tileOnData.text = "Standing On:  {}".format(tileOnData['name'])

    def get_map_size(self):
        width = self.world.chunksWide * self.world.cs * self.world.ss
        height = self.world.chunksHigh * self.world.cs * self.world.ss
        return width, height

    def get_message_hud_size(self):
        mapSize = self.get_map_size()
        return mapSize[0], self.window.height - mapSize[1]

    def get_player_info_hud_coords(self):
        mapSize = self.get_map_size()
        sectionHeight = self.window.height//3

        startX = mapSize[0]
        stopX = self.window.width

        startY = self.window.height - sectionHeight
        stopY = self.window.height

        return startX, startY, stopX, stopY

    def get_health_hud_coords(self):
        mapSize = self.get_map_size()
        sectionHeight = self.window.height//3

        startX = mapSize[0]
        stopX = self.window.width

        startY = sectionHeight
        stopY = sectionHeight * 2

        return startX, startY, stopX, stopY

    def get_map_info_hud_coords(self):
        mapSize = self.get_map_size()
        sectionHeight = self.window.height//3

        startX = mapSize[0]
        stopX = self.window.width

        startY = 0
        stopY = sectionHeight

        return startX, startY, stopX, stopY

    def get_messages(self, limit):
        return self.messages.latest(limit)

    def get_tile_hud_data(self):
        tileInFrontData = None
        tileOnData = None
        playerCoords = self.player.get_coords()
        playerAngle = self.player.angle

        tileCoords = list(playerCoords)

        if playerAngle == 0:
            tileCoords[0] += self.world.ss
        elif playerAngle == 90:
            tileCoords[1] += self.world.ss
        elif playerAngle == 180:
            tileCoords[0] -= self.world.ss
        else:
            tileCoords[1] -= self.world.ss

        inFrontCoord = tuple(tileCoords)

        if inFrontCoord in  self.world.mapTileData:
            tileInFrontData = self.world.mapTileData[inFrontCoord]
        if playerCoords in  self.world.mapTileData:
            tileOnData = self.world.mapTileData[playerCoords]

        return tileInFrontData, tileOnData

    def move_player(self, angle):
        completed = self._move_entity(self.player, angle)
        if completed:
            self._generate_fov()
            self._update_tile_hud_data()

    def change_player_angle(self, modifier):
        newAngle = self._new_entity_angle(self.player.angle, modifier)
        self.player.change_angle(newAngle)
        self._generate_fov()
        self._update_tile_hud_data()

    def open_door(self):
        ss = CONFIG['spriteSize']
        (x,y,z) = self.player.sprite.x, self.player.sprite.y, self.player.level
        coordOptions = [(x+ss, y, z), (x-ss, y, z), (x, y+ss, z), (x, y-ss, z)]
        for coord in coordOptions:
            if coord in self.world.mapTileData:
                tileData = self.world.mapTileData[coord]
                if tileData['name'] == self.world.doorClosed[0]:
                    tileData['spriteImg'] = self.world.doorOpen[1]
                    tileData['name'] = self.world.doorOpen[0]
                    tileData['collisionTile'] = False
                    self._generate_fov()
                    self._add_message("You opened the door!")
                    self._update_tile_hud_data()

    def close_door(self):
        ss = CONFIG['spriteSize']
        (x,y,z) = self.player.sprite.x, self.player.sprite.y, self.player.level
        coordOptions = [(x+ss, y, z), (x-ss, y, z), (x, y+ss, z), (x, y-ss, z)]
        for coord in coordOptions:
            if coord in self.world.mapTileData:
                tileData = self.world.mapTileData[coord]
                if tileData['name'] == self.world.doorOpen[0]:
                    tileData['spriteImg'] = self.world.doorClosed[1]
                    tileData['name'] = self.world.doorClosed[0]
                    tileData['collisionTile'] = True
                    self._generate_fov()
                    self._add_message("You closed the door!")
                    self._update_tile_hud_data()

    def pickup_item(self):
        thereIsRoom = True
        coords = self.player.get_coords()
        if coords in self._itemsData:
            item = self._itemsData[coords]
            if item.weight <= self.player.strength:
                backpack = self.player.backpack
                if (backpack.weight + item.weight) <= backpack.maxWeight:
                    if item not in backpack:
                        thereIsRoom = backpack.capacity > len(backpack)
                    if thereIsRoom:
                        item.sprite.batch = None
                        backpack.add(item)
                        del self._itemsData[coords]
                        self._entities.remove(item)
                        self._add_message("You picked up a {}!".format(item.name))
                        self._update_tile_hud_data()


    def drop_item(self):
        coords = self.player.get_coords()
        backpack = self.player.backpack
        if backpack.activeItem:
            item = backpack.activeItem
            item.move(coords)
            item.lightLevel = item.maxLightLevel
            print (item.maxLightLevel, item.lightLevel)
            item.sprite.batch = self.batch
            backpack.remove(item)
            self._itemsData[coords] = item
            self._entities.append(item)
            self._add_message("You dropped up a {}!".format(item.name))
            self._update_tile_hud_data()

    def push_handlers(self):
        if self.setup():
            # If self.setup() did complete add the Game handlers to the stack.
            self.window.push_handlers(self)
        else:
            # If not switch back to the MainMenuController
            self.switch_controller_class(MainMenuController)