mirror of
https://github.com/csd4ni3l/logical-signals.git
synced 2026-01-01 12:33:46 +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:
43
game/play.py
43
game/play.py
@@ -2,7 +2,7 @@ import arcade, arcade.gui, random, datetime, os, json
|
|||||||
|
|
||||||
from datetime import datetime
|
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.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
|
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
|
elif self.gate_type == "INPUT": # dont set INPUT to None
|
||||||
pass
|
pass
|
||||||
elif self.gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.input) == 1:
|
elif self.gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.input) == 1:
|
||||||
|
if self.input[0].value is not None:
|
||||||
self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value()))
|
self.value = int(LOGICAL_GATES[self.gate_type](self.input[0].calculate_value()))
|
||||||
elif len(self.input) == 2:
|
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
|
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:
|
else:
|
||||||
self.value = None
|
self.value = None
|
||||||
|
|
||||||
@@ -64,8 +70,6 @@ class Game(arcade.gui.UIView):
|
|||||||
self.selected_input = None
|
self.selected_input = None
|
||||||
self.selected_output = 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.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)
|
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:
|
if not "completed_levels" in self.data:
|
||||||
self.data["completed_levels"] = []
|
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):
|
def screenshot(self):
|
||||||
self.tools_box.visible = False
|
self.tools_box.visible = False
|
||||||
self.tools_box._requires_render = True
|
self.tools_box._requires_render = True
|
||||||
@@ -219,9 +226,11 @@ class Game(arcade.gui.UIView):
|
|||||||
if gate_id == self.selected_output:
|
if gate_id == self.selected_output:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
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:
|
if self.gates[gate_id].gate_type not in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 2:
|
||||||
return
|
return
|
||||||
elif self.gates[gate_id].gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 1:
|
|
||||||
|
if self.gates[gate_id].gate_type in SINGLE_INPUT_LOGICAL_GATES and len(self.gates[gate_id].input) == 1:
|
||||||
return
|
return
|
||||||
|
|
||||||
self.selected_input = gate_id
|
self.selected_input = gate_id
|
||||||
@@ -243,14 +252,14 @@ class Game(arcade.gui.UIView):
|
|||||||
|
|
||||||
self.evaluate()
|
self.evaluate()
|
||||||
|
|
||||||
def on_event(self, event):
|
def on_mouse_press(self, x, y, button, modifiers):
|
||||||
arcade.gui.UIManager.on_event(self.ui, event)
|
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 button == arcade.MOUSE_BUTTON_RIGHT:
|
||||||
if event.button == arcade.MOUSE_BUTTON_RIGHT:
|
|
||||||
for i in range(len(self.bezier_points) - 1, -1, -1):
|
for i in range(len(self.bezier_points) - 1, -1, -1):
|
||||||
for point in self.bezier_points[i]:
|
for point in self.bezier_points[i]:
|
||||||
if event.pos.distance(point) < 5:
|
if world_vec.distance(point) < 5:
|
||||||
self.gates[self.connections[i][0]].output = None
|
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]].input.remove(self.gates[self.connections[i][0]])
|
||||||
self.gates[self.connections[i][1]].calculate_value()
|
self.gates[self.connections[i][1]].calculate_value()
|
||||||
@@ -259,23 +268,23 @@ class Game(arcade.gui.UIView):
|
|||||||
self.bezier_points.pop(i)
|
self.bezier_points.pop(i)
|
||||||
break
|
break
|
||||||
|
|
||||||
elif event.button == arcade.MOUSE_BUTTON_LEFT:
|
elif button == arcade.MOUSE_BUTTON_LEFT:
|
||||||
for gate in self.gates:
|
for gate in self.gates:
|
||||||
if gate.rect.point_in_rect((event.x, event.y)):
|
if gate.rect.point_in_rect((world_vec.x, world_vec.y)):
|
||||||
x = gate.center_x - event.x
|
width_x = gate.center_x - world_vec.x
|
||||||
if abs(x) < 58:
|
if abs(width_x) < 58:
|
||||||
self.dragged_gate = gate
|
self.dragged_gate = gate
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if x > 0:
|
if width_x > 0:
|
||||||
self.select_input(gate.id)
|
self.select_input(gate.id)
|
||||||
else:
|
else:
|
||||||
self.select_output(gate.id)
|
self.select_output(gate.id)
|
||||||
|
|
||||||
def on_mouse_drag(self, x, y, dx, dy, _buttons, _modifiers):
|
def on_mouse_drag(self, x, y, dx, dy, _buttons, _modifiers):
|
||||||
if self.dragged_gate is not None:
|
if self.dragged_gate is not None:
|
||||||
self.dragged_gate.center_x += dx
|
self.dragged_gate.center_x += dx / self.camera.zoom
|
||||||
self.dragged_gate.center_y += dy
|
self.dragged_gate.center_y += dy / self.camera.zoom
|
||||||
|
|
||||||
def on_mouse_release(self, x, y, button, modifiers):
|
def on_mouse_release(self, x, y, button, modifiers):
|
||||||
self.dragged_gate = None
|
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:
|
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)
|
- 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
|
- 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
|
- You have to connect the nodes in a way to meet the required result
|
||||||
|
|
||||||
Logical Gates explanation:
|
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
|
- OR: Returns 1 if any inputs are 1, otherwise 0
|
||||||
- NAND: Returns 1 if any inputs are 0, otherwise 0
|
- NAND: Returns 1 if any inputs are 0, otherwise 0
|
||||||
- NOR: Returns 1 if both inputs are 0, otherwise 0
|
- NOR: Returns 1 if all inputs are 0, otherwise 0
|
||||||
- XOR: Returns 1 if inputs are different, otherwise 0
|
- XOR: Returns 1 if atleast 1 input is different, otherwise 0
|
||||||
- XNOR: Returns 1 if inputs are the same, otherwise 0
|
- XNOR: Returns 1 if all inputs are the same, otherwise 0
|
||||||
""", multiline=True, font_size=24), anchor_x="center", anchor_y="center")
|
""", 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)
|
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
|
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):
|
def generate_task_text(level):
|
||||||
text = "Task: You need to use "
|
text = "Task: You need to use "
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user