Skip to content

Commit

Permalink
Merge branch 'main' into feat/genetic-algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
tobiasfremming authored Nov 12, 2024
2 parents cb36493 + 3a33ebb commit a56fcb7
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 77 deletions.
135 changes: 70 additions & 65 deletions agent_parts_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from src.agent_parts.rectangle import Point
from src.agent_parts.creature import Creature

#NOTE_TO_MYSELF: When add limb is clicked it doesn't go away when unpaused
#To do : unclick the only_one_simultaneously_buttons when unpausing

def main():
# Initialize Pygame and Pymunk
Expand All @@ -28,14 +28,15 @@ def main():
pygame.display.set_caption("Pymunk Rectangle Physics")
interface = Interface()

# Track whether different modes are on or off

# Track whether physics is on or off
physics_on = False
make_limb_mode = False
make_motorjoint_mode = False

# Track the physics value
physics_value = 0

def handle_physics():
nonlocal physics_on
nonlocal physics_value
Expand All @@ -62,7 +63,6 @@ def handle_physics():
def make_limb():
nonlocal make_limb_mode
make_limb_mode = not make_limb_mode


limb_button = Button(
text="Add limb",
Expand All @@ -77,11 +77,10 @@ def make_limb():
callback=make_limb
)


make_motorjoint_mode = False
def add_motorjoint():
nonlocal make_motorjoint_mode
make_motorjoint_mode = not make_motorjoint_mode


motorjoint_button = Button(
text="Add joint",
Expand All @@ -97,8 +96,8 @@ def add_motorjoint():
)

interface.add_button(pause_button)
interface.add_button(limb_button)
interface.add_button(motorjoint_button)
interface.add_only_one_simultaneously_buttons(limb_button)
interface.add_only_one_simultaneously_buttons(motorjoint_button)



Expand All @@ -112,23 +111,12 @@ def add_motorjoint():
vision: Vision = Vision(Point(0,0))
creature = Creature(space, vision)

# Add limbs to the creature, placing them above the ground
#limb1 = creature.add_limb(100, 20, (300, 100), mass=1) # Positioned above the ground
#limb2 = creature.add_limb(100, 20, (350, 100), mass=1) # Positioned above the ground
#limb3 = creature.add_limb(110, 20, (400, 100), mass=5)

# Add a motor between limbs
#creature.add_motor(limb1, limb2, (50, 0), (-25, 0), rate=2, tolerance=30)
#creature.add_motor(limb2, limb3, (37, 0), (-23, 0), rate=-2, tolerance=50)

# Add limbs to the creature
limb1 = creature.add_limb(100, 20, (300, 300), mass=1)
limb2 = creature.add_limb(100, 20, (350, 300), mass=3)
limb3 = creature.add_limb(80, 40, (400, 300), mass=5)

# Add motors between limbs
#creature.add_motor(limb1, limb2, (25, 0), (-25, 0), rate=2)
#creature.add_motor(limb2, limb3, (37, 0), (-23, 0), rate=-2)
creature.add_motor_on_limbs(limb1, limb2, (325, 300))
creature.add_motor_on_limbs(limb2, limb3, (375, 300))

Expand All @@ -140,59 +128,81 @@ def add_motorjoint():
# creating rectangles properties
start_pos = None
end_pos = None
limbs = []
limbs_hovered = []

clock = pygame.time.Clock()

running = True
while running:
for event in pygame.event.get():
if event.type == QUIT:
running = False
interface.handle_events(event)

if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
print("Left arrow pressed")
elif event.key == pygame.K_RIGHT:
if event.key == pygame.K_RIGHT:
print("Right arrow pressed")
elif event.key == pygame.K_SPACE:
if event.key == pygame.K_SPACE:
handle_physics()
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_x, mouse_y = event.pos
mouse_pos = (mouse_x, mouse_y)
# List of limbs to make motorjoint on
limbs_hovered = []
# For dragging creature: Check if the mouse is over any limb
if not physics_on and not make_limb_mode and not make_motorjoint_mode:
for limb in creature.limbs:
if limb.contains_point(mouse_pos):
dragging = True
dragged_limb = limb
creature.start_dragging(dragged_limb)
drag_offset = (limb.body.position.x - mouse_x, limb.body.position.y - mouse_y)
limbs_hovered.append(limb)
# For creating rectangles
elif make_limb_mode:
start_pos = mouse_pos
# For creating motorjoint
elif make_motorjoint_mode and len(limbs_hovered) == 2:
limb_1 = limbs_hovered[0]
limb_2 = limbs_hovered[1]
creature.add_motor_on_limbs(limb_1, limb_2, mouse_pos)
limbs_hovered.clear()



active_button = interface.handle_only_one_function(event)

# To make it possible to only click one of the only_one_simultaneously_buttons
if not physics_on and active_button:
if active_button.text == "Add limb":
active_button.is_clicked(event)
print("Limb creation mode activated and motor joint creation mode deactivated")
elif active_button.text == "Add joint":
active_button.is_clicked(event)
print("Motor joint creation mode activated and limb creation mode deactivated")

elif not active_button and not physics_on:
mouse_x, mouse_y = event.pos
mouse_pos = (mouse_x, mouse_y)
# List of limbs to make motorjoint on
limbs_hovered = []
# For dragging creature: Check if the mouse is over any limb
if not make_limb_mode and not make_motorjoint_mode:
for limb in creature.limbs:
if limb.contains_point(mouse_pos):
dragging = True
dragged_limb = limb
creature.start_dragging(dragged_limb)
drag_offset = (limb.body.position.x - mouse_x, limb.body.position.y - mouse_y)
#limbs_hovered.append(limb)
break
# For creating rectangles
elif make_limb_mode:
start_pos = mouse_pos
# For creating motorjoint
if make_motorjoint_mode:
for limb in creature.limbs:
if limb.contains_point(mouse_pos) and limb not in limbs_hovered:
limbs_hovered.append(limb)
print(limbs_hovered)
# Ensure exactly two limbs are selected before creating the motor
if len(limbs_hovered) == 2:
limb_1 = limbs_hovered[0]
limb_2 = limbs_hovered[1]

creature.add_motor_on_limbs(limb_1, limb_2, mouse_pos)
print("Motor joint created between limbs!")
limbs_hovered.clear()
else:
limbs_hovered.clear()

# If Pause button is clicked and any only_one_simultaneously_buttons are active, deactivate the active button
elif not active_button:
if interface.any_active_only_one_simultaneously_buttons_active():
interface.active_button.deactivate()
print("Deactivated all mutually exclusive buttons due to Pause")

elif event.type == MOUSEMOTION and make_limb_mode:
mouse_x, mouse_y = event.pos
mouse_pos = (mouse_x, mouse_y)
end_pos = mouse_pos
if make_motorjoint_mode:
limbs_hovered.clear()
for limb in creature.limbs:
if limb.contains_point(mouse_pos):
limbs_hovered.append(limb)

elif event.type == pygame.MOUSEBUTTONUP:
dragging = False
Expand All @@ -202,9 +212,9 @@ def add_motorjoint():
position = ((start_pos[0] + end_pos[0]) / 2, (start_pos[1] + end_pos[1]) / 2)
limb = creature.add_limb(width, height, position)

# Reset start and end positions
start_pos = None
end_pos = None
# Reset start and end positions
start_pos = None
end_pos = None


space.step(physics_value)
Expand All @@ -221,16 +231,11 @@ def add_motorjoint():

#creature.set_joint_rates([random.random()*2, random.random()*2])
# Render the creature
creature.render(screen)

if not physics_on:
interface.add_button(limb_button)
else:
interface.remove_button(limb_button)
creature.render(screen)
interface.render(screen)



clock.tick(60)

pygame.display.flip()
Expand Down
44 changes: 32 additions & 12 deletions src/interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,18 +56,25 @@ def deactivate(self):
class Interface:
def __init__(self):
"""Initializes the elements in the interface"""
self.buttons: list[Button] = []

self.buttons: list[Button] = [] #for all buttons in the interface
self.active_button = Button
self.only_one_simultaneously_buttons = [] #buttons that can't be active simultaneously


def add_button(self, button: Button) -> Button:
self.buttons.append(button)
return button

def remove_button(self, button: Button) -> Button:
if button in self.buttons:
self.buttons.remove(button)
return button



def remove_only_one_simultaneously_buttons(self, button: Button) -> Button:
if button in self.only_one_simultaneously_buttons:
self.buttons.remove(button)
return button

def render(self, screen):
"""Render all UI elements."""
Expand All @@ -77,19 +84,32 @@ def render(self, screen):
def handle_events(self, event):
"""Handle events for all UI elements."""
for button in self.buttons:
if isinstance(button, Button) and button.is_clicked(event):
self.handle_only_one_function(event, button)
button.is_clicked(event)

def handle_only_one_function(self, event, active_button: Button):
for button in self.buttons:
if button != active_button:
button.deactivate()
active_button.is_clicked(
event
) # This will call the callback if the button is clicked

def is_any_button_clicked(self, event) -> bool:
for button in self.buttons:
if button.is_clicked(event): # If any button is clicked
return True # Return True immediately
return False

def handle_only_one_function(self, event) -> Button|None:
"""Activates only one of the mutually exclusive buttons."""
for button in self.only_one_simultaneously_buttons:
if button.is_clicked(event): # If this button was clicked
self.active_button = button
# Deactivate all other mutually exclusive buttons
for other_button in self.only_one_simultaneously_buttons:
if other_button != button:
other_button.deactivate()
return button # Return the clicked (active) button
return None # No button was clicked

def any_active_only_one_simultaneously_buttons_active(self) -> bool:
return any(button.toggled for button in self.only_one_simultaneously_buttons)






0 comments on commit a56fcb7

Please sign in to comment.