mirror of
https://github.com/csd4ni3l/logical-signals.git
synced 2025-11-05 04:58:09 +01:00
Add zooming (took a long time due to screen to world coordinates), multi input gates for DIY mode
This commit is contained in:
79
game/play.py
79
game/play.py
@@ -2,7 +2,7 @@ import arcade, arcade.gui, random, datetime, os, json
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
from utils.utils import cubic_bezier_points, get_gate_port_position, generate_task_text
|
||||
from utils.utils import cubic_bezier_points, get_gate_port_position, generate_task_text, multi_gate
|
||||
from utils.constants import button_style, dropdown_style, LOGICAL_GATES, LEVELS, SINGLE_INPUT_LOGICAL_GATES
|
||||
from utils.preload import button_texture, button_hovered_texture, logic_gate_textures
|
||||
|
||||
@@ -28,9 +28,15 @@ class LogicalGate(arcade.Sprite):
|
||||
elif self.gate_type == "INPUT": # dont set INPUT to None
|
||||
pass
|
||||
elif self.gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.input) == 1:
|
||||
self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value()))
|
||||
elif len(self.input) == 2:
|
||||
self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value(), self.input[1].calculate_value())) # have to convert to int cause it might return boolean
|
||||
if self.input[0].value is not None:
|
||||
self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value()))
|
||||
else:
|
||||
self.value = None
|
||||
elif len(self.input) > 1:
|
||||
if len(self.input) == 2:
|
||||
self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value(), self.input[1].calculate_value())) # have to convert to int cause it might return boolean
|
||||
else:
|
||||
self.value = multi_gate([input.calculate_value() for input in self.input], LOGICAL_GATES[self.gate_type])
|
||||
else:
|
||||
self.value = None
|
||||
|
||||
@@ -64,8 +70,6 @@ class Game(arcade.gui.UIView):
|
||||
self.selected_input = None
|
||||
self.selected_output = None
|
||||
|
||||
self.ui.on_event = self.on_event
|
||||
|
||||
self.anchor = self.add_widget(arcade.gui.UIAnchorLayout(size_hint=(1, 1)))
|
||||
self.tools_box = self.anchor.add(arcade.gui.UIBoxLayout(space_between=5), anchor_x="right", anchor_y="bottom", align_x=-5, align_y=20)
|
||||
|
||||
@@ -115,6 +119,9 @@ class Game(arcade.gui.UIView):
|
||||
if not "completed_levels" in self.data:
|
||||
self.data["completed_levels"] = []
|
||||
|
||||
def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
|
||||
self.camera.zoom += scroll_y * 0.1
|
||||
|
||||
def screenshot(self):
|
||||
self.tools_box.visible = False
|
||||
self.tools_box._requires_render = True
|
||||
@@ -219,9 +226,11 @@ class Game(arcade.gui.UIView):
|
||||
if gate_id == self.selected_output:
|
||||
return
|
||||
|
||||
if self.gates[gate_id].gate_type not in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 2:
|
||||
return
|
||||
elif self.gates[gate_id].gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 1:
|
||||
if self.level_num != -1:
|
||||
if self.gates[gate_id].gate_type not in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 2:
|
||||
return
|
||||
|
||||
if self.gates[gate_id].gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 1:
|
||||
return
|
||||
|
||||
self.selected_input = gate_id
|
||||
@@ -243,39 +252,39 @@ class Game(arcade.gui.UIView):
|
||||
|
||||
self.evaluate()
|
||||
|
||||
def on_event(self, event):
|
||||
arcade.gui.UIManager.on_event(self.ui, event)
|
||||
def on_mouse_press(self, x, y, button, modifiers):
|
||||
unprojected_vec = self.camera.unproject((x, y))
|
||||
world_vec = arcade.math.Vec2(unprojected_vec.x, unprojected_vec.y)
|
||||
|
||||
if isinstance(event, arcade.gui.UIMousePressEvent):
|
||||
if event.button == arcade.MOUSE_BUTTON_RIGHT:
|
||||
for i in range(len(self.bezier_points) - 1, -1, -1):
|
||||
for point in self.bezier_points[i]:
|
||||
if event.pos.distance(point) < 5:
|
||||
self.gates[self.connections[i][0]].output = None
|
||||
self.gates[self.connections[i][1]].input.remove(self.gates[self.connections[i][0]])
|
||||
self.gates[self.connections[i][1]].calculate_value()
|
||||
if button == arcade.MOUSE_BUTTON_RIGHT:
|
||||
for i in range(len(self.bezier_points) - 1, -1, -1):
|
||||
for point in self.bezier_points[i]:
|
||||
if world_vec.distance(point) < 5:
|
||||
self.gates[self.connections[i][0]].output = None
|
||||
self.gates[self.connections[i][1]].input.remove(self.gates[self.connections[i][0]])
|
||||
self.gates[self.connections[i][1]].calculate_value()
|
||||
|
||||
self.connections.pop(i)
|
||||
self.bezier_points.pop(i)
|
||||
break
|
||||
self.connections.pop(i)
|
||||
self.bezier_points.pop(i)
|
||||
break
|
||||
|
||||
elif event.button == arcade.MOUSE_BUTTON_LEFT:
|
||||
for gate in self.gates:
|
||||
if gate.rect.point_in_rect((event.x, event.y)):
|
||||
x = gate.center_x - event.x
|
||||
if abs(x) < 58:
|
||||
self.dragged_gate = gate
|
||||
break
|
||||
elif button == arcade.MOUSE_BUTTON_LEFT:
|
||||
for gate in self.gates:
|
||||
if gate.rect.point_in_rect((world_vec.x, world_vec.y)):
|
||||
width_x = gate.center_x - world_vec.x
|
||||
if abs(width_x) < 58:
|
||||
self.dragged_gate = gate
|
||||
break
|
||||
else:
|
||||
if width_x > 0:
|
||||
self.select_input(gate.id)
|
||||
else:
|
||||
if x > 0:
|
||||
self.select_input(gate.id)
|
||||
else:
|
||||
self.select_output(gate.id)
|
||||
self.select_output(gate.id)
|
||||
|
||||
def on_mouse_drag(self, x, y, dx, dy, _buttons, _modifiers):
|
||||
if self.dragged_gate is not None:
|
||||
self.dragged_gate.center_x += dx
|
||||
self.dragged_gate.center_y += dy
|
||||
self.dragged_gate.center_x += dx / self.camera.zoom
|
||||
self.dragged_gate.center_y += dy / self.camera.zoom
|
||||
|
||||
def on_mouse_release(self, x, y, button, modifiers):
|
||||
self.dragged_gate = None
|
||||
|
||||
@@ -16,16 +16,17 @@ class Tutorial(arcade.gui.UIView):
|
||||
self.instructions_label = self.anchor.add(arcade.gui.UILabel(text="""How to play:
|
||||
- You can move gates by dragging their buttons (not the plus ones)
|
||||
- To create connections, click on the + buttons, left is the input, right is the output
|
||||
- A node has to have 2 inputs(Except the OUTPUT node), but only 1 output
|
||||
- On levels, a node has to have 2 inputs(Except the OUTPUT and NOT node), but only 1 output
|
||||
- On DIY mode, a node can have more than 2 inputs, except for OUTPUT and NOT
|
||||
- You have to connect the nodes in a way to meet the required result
|
||||
|
||||
Logical Gates explanation:
|
||||
- AND: Returns 1 if both inputs are 1, otherwise 0
|
||||
- AND: Returns 1 if all inputs are 1, otherwise 0
|
||||
- OR: Returns 1 if any inputs are 1, otherwise 0
|
||||
- NAND: Returns 1 if any inputs are 0, otherwise 0
|
||||
- NOR: Returns 1 if both inputs are 0, otherwise 0
|
||||
- XOR: Returns 1 if inputs are different, otherwise 0
|
||||
- XNOR: Returns 1 if inputs are the same, otherwise 0
|
||||
- NOR: Returns 1 if all inputs are 0, otherwise 0
|
||||
- XOR: Returns 1 if atleast 1 input is different, otherwise 0
|
||||
- XNOR: Returns 1 if all inputs are the same, otherwise 0
|
||||
""", multiline=True, font_size=24), anchor_x="center", anchor_y="center")
|
||||
|
||||
self.back_button = arcade.gui.UITextureButton(texture=button_texture, texture_hovered=button_hovered_texture, text='<--', style=button_style, width=100, height=50)
|
||||
|
||||
@@ -4,6 +4,14 @@ from utils.constants import menu_background_color
|
||||
|
||||
import pyglet.display
|
||||
|
||||
def multi_gate(values, func):
|
||||
value = values[0]
|
||||
|
||||
for new_value in values[1:]:
|
||||
value = func(value, new_value)
|
||||
|
||||
return value
|
||||
|
||||
def generate_task_text(level):
|
||||
text = "Task: You need to use "
|
||||
|
||||
|
||||
Reference in New Issue
Block a user