Moving a tiled surface in a kivy widget - kivy

I'm building a simple game in kivy where I move a player on a map and the map moves consequently to keep the player at the center of the screen.
But, the problem is that the map is composed by individual tiles with individual properties. How can I move all the elements at the same time??
I'm in trouble with that and I can't reach a solution.
This is the portion of code:
'''
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle
from kivy.uix.behaviors import DragBehavior
class MainGame(Widget):
def __init__(self, **kwargs):
super().__init__(**kwargs)
with self.canvas:
Rectangle(source= "stone_tile.png",pos=(220,-300), size=(1000,1000))
Rectangle(source= "grass_tile.png", pos=(0,-400), size=(1000,1000))
class FarIslands(App):
def build(self):
return MainGame()
if __name__ == '__main__':
FarIslands().run()
'''
I need to move the two rectangles at the same time. In the final version there will be hundreds of elements to create a game map.
Maybe, is there a better way, instead using Widget canvas?
Because I need to add other functions to the tiles...

Related

Is there a way to store circle coordinates and move them around in python turtle?

I know it's possible to store polygons in a dictionary since they have definitive coordinates, but is there a way to store the coordinates of a circle into a dictionary and move them around? My program consists of detecting whether a mouse click is within a circle and from there, gets the coordinate of that circle moving it to wherever the user desires with another mouse click (the get.poly function, instead of moving the current circle that I already drew, makes another copy). Below is an incomplete snippet of what I want to do:
def buttonclick(x, y): # detects mouseclick
return pen.goto(x, y)
def check(ctr, pt): # check whether the click is within the circle
if (pt[0] - ctr[0])** 2 + (pt[1] - ctr[1])**2 < 5**2:
return True
if check((0,5), mouseclick coordinates): # if true, move circle to next click
# pen = the circle thats detected
# move circle coordinates to next mouseclick
# break
I tried with the code provided by /u/cdlane as follows and here is what I meant by generating a new copy
pen.goto(0,0)
pen.pd()
pen.begin_poly()
pen.circle(radius)
pen.end_poly()
shape.addcomponent(pen.get_poly(), 'red', 'black')
screen.register_shape('1', shape)
pen = Turtle(shape = '1')
pen.pu()
Function does exactly what I need it to do but using an existing circle instead of generating a new copy.
Rather than fix your implementation, I'm going to suggest a different implementation to achieve what you describe.
The circles themselves will be turtles, and clicking on one will "select" it. Clicking anywhere on the screen after that will move it. However, we don't want turtle.onclick() active at the same time as screen.onclick() since they both will get invoked, causing complications. Below is my two turtle example:
from turtle import Screen, Turtle
from functools import partial
selected = None
def on_screen_click(x, y):
global selected
screen.onclick(None)
selected.goto(x, y)
outline, fill = selected.color()
selected.color(fill, outline)
selected = None
for turtle in screen.turtles():
turtle.onclick(partial(on_turtle_click, turtle))
def on_turtle_click(self, x, y):
global selected
for turtle in screen.turtles():
turtle.onclick(None)
selected = self
outline, fill = selected.color()
selected.color(fill, outline)
# (re)enable screen onclick handler after this function, not during
screen.ontimer(partial(screen.onclick, on_screen_click))
screen = Screen()
turtle_1 = Turtle()
turtle_1.shape('circle')
turtle_1.color('red', 'black')
turtle_1.penup()
turtle_2 = turtle_1.clone()
turtle_2.goto(100, 100)
for turtle in screen.turtles():
turtle.onclick(partial(on_turtle_click, turtle))
screen.mainloop()

how to put a kivy button in the middle? X coordinates not working

I've learnt kivy halfway and I've stopped using it for some time I've forgotten a little so anyway I've made a little project so-called a "Tally Counter" and I've wanted to add a button in the middle and little downwards - I've done it and suddenly the x coordinates were not working - heres the output -
the code -
from kivy.core import window
from kivy.uix.label import Label
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.lang import builder
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.core.window import Window
import os, sys
from kivy.resources import resource_add_path, resource_find
builder.Builder.load_file("tally.kv")
Window.size = (450,600)
class Tally(Widget):
pass
class Count(App):
def build(self):
return Tally()
if __name__ == "__main__":
Count().run()
And last but not least the KV file
<Tally>
BoxLayout:
orientartion:"vertical"
size: root.width,root.height
Button:
text:"Count"
size_hint: (None, None)
height: 70
width: 400
pos_hint: {"center_x":.5,"center_y":.3}
Yet I feel the guilt for forgetting kivy, I'm kind of stupid for asking these questions, I'll ask better questions from now on. I'll try my best.
From the BoxLayout Documentation:
Position hints are partially working, depending on the orientation:
If the orientation is vertical: x, right and center_x will be used.
If the orientation is horizontal: y, top and center_y will be used.
However, you have a typo in your kv file. Try changing:
orientartion:"vertical"
to:
orientation:"vertical"
Refer this three button hope you find your solution from it
# import modules
import kivy
# base Class of your App inherits from the App class.
# app:always refers to the instance of your application
from kivy.app import App
# creates the button in kivy
# if not imported shows the error
from kivy.uix.button import Button
# This layout allows you to set relative coordinates for children.
from kivy.uix.relativelayout import RelativeLayout
# To change the kivy default settings
# we use this module config
from kivy.config import Config
# 0 being off 1 being on as in true / false
# you can use 0 or 1 && True or False
Config.set('graphics', 'resizable', True)
# creating the App class
class Pos_Size_App(App):
def build(self):
# A Relative Layout with a size of (300, 300) is created
rl = RelativeLayout(size =(300, 300))
# creating button
# size of button is 20 % by height and width of layout
# position is 'center_x':.7, 'center_y':.5
b1 = Button(size_hint =(.2, .2),
pos_hint ={'center_x':.7, 'center_y':.5},
text ="pos_hint")
# creating button
# size of button is 20 % by height and 50 % width of layout
b2 = Button(size_hint =(.5, .2),
text ="size_hint")
# creating button
# size of button is 20 % by height and width of layout
# position is 200, 200 from bottom left
b3 = Button( size_hint =(.2, .2),
pos =(200, 200),
text ="pos")
# adding button to widget
rl.add_widget(b1)
rl.add_widget(b2)
rl.add_widget(b3)
# returning widget
return rl
# run the App
if __name__ == "__main__":
Pos_Size_App().run()

Python turtle after drawing , click mouse inside drawing, clear screen and redraw

I am working on using python turtle to draw a circle.when i draw the circle, mouse click inside circle erase, click anywhere in the turtle,redraw it and click again inside again erase. So the process like this :
black screen
1.Click mouse
2.Start drawing circle
3.finish
4.click inside circle
5.clear screen
6.click again anywehre in the screen redraw circle
7.click inside circle clear screen
Thanks
https://i.stack.imgur.com/LR8CH.png
import PositionService
import turtle
t=turtle.Turtle()
ts=tur
tle.Screen()
ts.bgpic("shape_window.png")
t.up()
def get_click(x,y):# get click (x,y)
#if counter == 0:
draw_circle(x,y,"green",80)# draw the circle
print("clicking at ({}, {})".format(x,y))
def draw_circle(x,y,color,rad): # draw the circle
t.goto(x,y)
t.down()
t.circle(80)
t.color("green")
t.up()
t.hideturtle()
#t.home()
def main():
#maybe use global _pen
ts.onclick(get_click) # clicker
#set_position( x,y)?
#is_visible(draw_square)
I think were from the same class. I was also struggling until I realized that they supplied a PositionService.py file. You are supposed to use the functions within that file to help.

Kivy save widget without being drawn results in blank Fbo

I am trying to render some labels over the top of a canvas texture i have previously saved. When i render the widget to an Fbo without drawing it to the screen first i get a blank output. I believe this is replicated in the snippet below, save_file called from on_start writes the file incorrectly, but if the same logic is called from the button press it saves a file of the widget rendered correctly.
Is there a way to render the widget to the Fbo without rendering to the canvas?
Is there an update or draw command i need to call on the widget?
(notshown.texture seems to be None, and adding notshown.canvas.draw() seems to crash with no stacktrace or reason?)
from kivy.app import App
from kivy.factory import Factory
class TestApp(App):
def build(self, *kwargs):
layout = Factory.BoxLayout()
test1 = Factory.Button(text='test1', size_hint=(None,None), size=(200,200))
test1.bind(on_press=self.save_file1)
layout.add_widget(test1)
test2 = Factory.Button(text='test2', size_hint=(None,None), size=(200,200))
test2.bind(on_press=self.save_file2)
layout.add_widget(test2)
return layout
def save_file1(self, widget, value=False):
fbo = Factory.Fbo(size=widget.size, with_stencilbuffer=True)
fbo.add(widget.canvas)
fbo.draw()
fbo.texture.save('C:/Temp/test1.png', flipped=True)
def save_file2(self, widget, value=False):
notshown = Factory.Button(text='notshown', size_hint=(None,None), size=(200,200))
fbo = Factory.Fbo(size=notshown.size, with_stencilbuffer=True)
fbo.add(notshown.canvas)
fbo.draw()
fbo.texture.save('C:/Temp/test2.png', flipped=True)
TestApp().run()
Per John Anderson's input, the issue was not giving the application enough time to render a frame before attempting to save the texture.
Using Clock.schedule_once to await the next frame means that export_to_png or all other uses of the texture of the widget succeed with little to no fuss.
img = Factory.FinalImage(imagedata, size_hint=(None,None), size=imagedata.size)
Clock.schedule_once( lambda x: img.export_to_png(filename=imagename) )

Kivy scatter on desktop with size=Window.size

I am developing an application for Linux desktop using Kivy framework. I am trying to set Scatter size the same as the size of the window.
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.scatter import Scatter
from kivy.graphics import Color, Rectangle
class MyScatter(Scatter):
def __init__(self, *args, **kwargs):
super(MyScatter, self).__init__(*args, **kwargs)
self.size_hint=(None, None)
self.size=(Window.width, Window.height)
with self.canvas:
Color(1, 0, 0)
Rectangle(pos=self.pos, size=(100, 200))
class ScatterApp(App):
def build(self):
return MyScatter()
ScatterApp().run()
When I run the code the scatter immediately reflects my mouse motion and moves rectangle.
When I maximize window it reacts agter I press the button only but also scales and rotates itself as if I used two fingers.
When I use a fixed size (i.e. self.size=(100, 200)) the behavior is identical in both cases and scatter moves after I press the button.
Passing the size as a parameter doesn't change anything.
I don't use kv language.
"Mouse" is touchpad.
Not sure about your mouse problems, but the MyScatter widget will fill the window by default. Your code doesn't reflect the correct size. Try this version:
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.scatter import Scatter
from kivy.graphics import Color, Rectangle
from kivy.clock import Clock
class MyScatter(Scatter):
def __init__(self, *args, **kwargs):
super(MyScatter, self).__init__(*args, **kwargs)
Clock.schedule_once(self.show_size, 0.1)
def show_size(self, *args):
with self.canvas:
Color(1, 0, 0)
Rectangle(pos=self.pos, size=self.size)
class ScatterApp(App):
def build(self):
return MyScatter()
if __name__=="__main__":
ScatterApp().run()

Resources