I'm making a top-down racing game that has local multiplayer. I want each player to have their own view on the screen. The problem I'm having is that it seems you can't change a camera's position within the window. Ideally, I want to be able to have 4 different views of that map (1 for each player). If anyone knows of a way to change the camera's position within the window or a better way to do this, it would be much appreciated.
Here is an example I made which has 2 cameras, one is as big as the window, the other is smaller. I want them to both take up an equal portion of the screen and not overlap each other.
import arcade as arc
from arcade.pymunk_physics_engine import PymunkPhysicsEngine
SCREEN_WIDTH = 700
SCREEN_HEIGHT = 500
LEFT_VIEWPORT_MARGIN = 100
RIGHT_VIEWPORT_MARGIN = 100
TOP_VIEWPORT_MARGIN = 100
BOTTOM_VIEWPORT_MARGIN = 100
PHY_ENGINE = PymunkPhysicsEngine()
class Player(arc.Sprite):
def __init__(self, player_num=0, control="wasd"):
super().__init__()
if player_num == 0:
self.texture = arc.load_texture(":resources:images/space_shooter/playerShip1_orange.png")
elif player_num == 1:
self.texture = arc.load_texture(":resources:images/space_shooter/playerShip1_blue.png")
self.control = control
self.move_up = False
self.move_down = False
self.move_left = False
self.move_right = False
def update(self):
if self.move_up:
PHY_ENGINE.apply_force(self, (0, 1000))
if self.move_down:
PHY_ENGINE.apply_force(self, (0, -1000))
if self.move_right:
PHY_ENGINE.apply_force(self, (1000, 0))
if self.move_left:
PHY_ENGINE.apply_force(self, (-1000, 0))
class GameView(arc.View):
def __init__(self):
super().__init__()
self.width = SCREEN_WIDTH
self.height = SCREEN_HEIGHT
self.scene = None
self.p_cameras = []
self.gui_camera = None
self.camera_info = [[0, 0], [0, 0]]
self.map_width = 10000
self.map_height = 10000
self.players = []
# input stuff
self.w_pressed = False
self.s_pressed = False
self.a_pressed = False
self.d_pressed = False
self.up_pressed = False
self.down_pressed = False
self.left_pressed = False
self.right_pressed = False
self.move_up = False
self.move_down = False
self.move_left = False
self.move_right = False
# game stuff
self.physics_engine = PHY_ENGINE
self.background = arc.load_texture(":resources:images/backgrounds/abstract_1.jpg")
def process_keychange(self):
for player in self.players:
# WASD movement
if player.control == "wasd":
if self.w_pressed:
player.move_up = True
else:
player.move_up = False
if self.s_pressed:
player.move_down = True
else:
player.move_down = False
if self.d_pressed:
player.move_right = True
else:
player.move_right = False
if self.a_pressed:
player.move_left = True
else:
player.move_left = False
# arrow key movement
elif player.control == "arrows":
if self.up_pressed:
player.move_up = True
else:
player.move_up = False
if self.down_pressed:
player.move_down = True
else:
player.move_down = False
if self.right_pressed:
player.move_right = True
else:
player.move_right = False
if self.left_pressed:
player.move_left = True
else:
player.move_left = False
def on_key_press(self, key, modifiers):
if key == arc.key.W:
self.w_pressed = True
if key == arc.key.S:
self.s_pressed = True
if key == arc.key.A:
self.a_pressed = True
if key == arc.key.D:
self.d_pressed = True
if key == arc.key.UP:
self.up_pressed = True
if key == arc.key.DOWN:
self.down_pressed = True
if key == arc.key.LEFT:
self.left_pressed = True
if key == arc.key.RIGHT:
self.right_pressed = True
if key == arc.key.ESCAPE:
arc.exit()
def on_key_release(self, key, modifiers):
if key == arc.key.W:
self.w_pressed = False
if key == arc.key.S:
self.s_pressed = False
if key == arc.key.A:
self.a_pressed = False
if key == arc.key.D:
self.d_pressed = False
if key == arc.key.UP:
self.up_pressed = False
if key == arc.key.DOWN:
self.down_pressed = False
if key == arc.key.LEFT:
self.left_pressed = False
if key == arc.key.RIGHT:
self.right_pressed = False
self.process_keychange()
def on_show_view(self):
arc.set_viewport(0, self.window.width, 0, self.window.height)
self.load_level()
def load_level(self):
self.p_cameras = [arc.Camera(), arc.Camera(viewport_width=500, viewport_height=400)]
self.scene = arc.Scene()
self.scene.add_sprite_list("player")
player1 = Player()
player1.center_y = 200
player1.center_x = 200
self.scene.add_sprite("player", player1)
self.physics_engine.add_sprite(player1, moment_of_inertia=PymunkPhysicsEngine.MOMENT_INF,
collision_type="player", damping=.01)
player2 = Player(player_num=1, control="arrows")
player2.center_y = 300
player2.center_x = 200
self.scene.add_sprite("player", player2)
self.physics_engine.add_sprite(player2, moment_of_inertia=PymunkPhysicsEngine.MOMENT_INF,
collision_type="player", damping=.01)
self.players.append(player1)
self.players.append(player2)
def on_draw(self):
if self.p_cameras is None:
return
for camera in self.p_cameras:
camera.use()
arc.draw_lrwh_rectangle_textured(camera.position.x,
camera.position.y,
camera.viewport_width, camera.viewport_height, self.background)
self.scene.draw()
def center_camera_to_player(self, index=0):
target_player = self.players[index]
camera = self.p_cameras[index]
view_left = self.camera_info[index][0]
view_bottom = self.camera_info[index][1]
# Scroll left
left_boundary = view_left + LEFT_VIEWPORT_MARGIN
if target_player.left < left_boundary:
view_left -= left_boundary - target_player.left
# Scroll right
right_boundary = view_left + self.width - RIGHT_VIEWPORT_MARGIN - (SCREEN_WIDTH - camera.viewport_width)
if target_player.right > right_boundary:
view_left += target_player.right - right_boundary
# Scroll up
top_boundary = view_bottom + self.height - TOP_VIEWPORT_MARGIN - (SCREEN_HEIGHT - camera.viewport_height)
if target_player.top > top_boundary:
view_bottom += target_player.top - top_boundary
# Scroll down
bottom_boundary = view_bottom + BOTTOM_VIEWPORT_MARGIN
if target_player.bottom < bottom_boundary:
view_bottom -= bottom_boundary - target_player.bottom
# keeps camera in left bound of map
if view_left < 0:
view_left = 0
# keeps camera in right bound of map
if (view_left + self.width) > self.map_width:
view_left = self.map_width - self.width
# keeps camera in bottom bound of map
if view_bottom < 0:
view_bottom = 0
# keeps camera in top bound of map
if view_bottom + self.height > self.map_height:
view_bottom = self.map_height - self.height
# Scroll to the proper location
position = view_left, view_bottom
camera.move_to(position, .3)
def on_update(self, delta_time: float):
self.process_keychange()
self.center_camera_to_player(0)
self.center_camera_to_player(1)
self.scene.update()
self.physics_engine.step()
def main():
"""Main function"""
window = arc.Window(SCREEN_WIDTH, SCREEN_HEIGHT)
start_view = GameView()
window.show_view(start_view)
arc.run()
if __name__ == "__main__":
main()