Can I check collide_widget using a list? - kivy

I am trying to make a game where you can move a character around screen and I had it so that if my character ran into a picture of a tree, the character would stop moving. After getting this to work, What I tried to do was change the code so instead of just using the tree widget, I wanted to iterate through a list of widgets, so that if my character runs into any of these, character stops moving. What's strange is that it works when I have only one widget in the list. I can also put list[0] or list[1] in my code and when my character will stop when encountering those widgets. But again, if I have more than one widget in the list and try to iterate through the list, it does not work, my character does not stop when encountering any of the widgets.
I'm wondering what I did wrong or how to fix this. Ultimately I want it so that if my character runs into any of the images in the list, the character will stop moving.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.label import Label
from kivy.uix.behaviors import ButtonBehavior
from kivy.core.audio import SoundLoader
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import FallOutTransition
from kivy.clock import Clock
from kivy.graphics import Color
gamelayout = FloatLayout(size=(300, 300))
bglayout = FloatLayout()
characterselectionlayout = GridLayout(cols=2)
class Game(Screen):
class Bg(Image):
def __init__(self, **kwargs):
super(Bg, self).__init__(**kwargs)
self.allow_stretch = True
self.size_hint = (None, None)
self.size = (1440, 1440)
class Npcs(Image):
def __init__(self, **kwargs):
super(Npcs, self).__init__(**kwargs)
self.allow_stretch=True
class MoveableImage(Image):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(None, self)
if not self._keyboard:
return
self._keyboard.bind(on_key_down=self.on_keyboard_down)
self._keyboard.bind(on_key_up=self.on_keyboard_up)
self.y = (Window.height/2.1)
self.app = App.get_running_app()
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'left':
self.source = 'selectionscreen/left.zip'
self.anim_delay=.20
if self.x < (Window.width * .25):
bglayout.x += 4
else:
for i in listofwidgets:
if self.collide_widget(i):
self.x -=0
else:
self.x -=6
elif keycode[1] == 'right':
self.source ='selectionscreen/right.zip'
self.anim_delay=.20
if self.x > (Window.width * .70):
bglayout.x -= 4
else:
for i in listofwidgets:
if self.collide_widget(i):
self.x += 0
else:
self.x += 6
else:
return False
return True
class gameApp(App):
def build(self):
global sm
sm = ScreenManager()
game = Game(name='game')
sm.add_widget(game)
global listofobject
listofobject = []
hero = MoveableImage(source='selectionscreen/right1.png', size_hint=(None,None), allow_stretch = False, size=(40, 65))
self.tree = Npcs(source='selectionscreen/tree.zip', allow_stretch=False, size_hint=(None,None), pos_hint={'x':.20, 'y':.30}, size=(50, 50), pos=(300, 300))
self.testdude = Npcs(source='selectionscreen/testdude.png', allow_stretch=False, size_hint=(None,None), pos_hint={'x':.60, 'y':.70}, size=(100, 124), pos=(800, 900))
listofwidgets.append(self.tree)
listofwidgets.append(self.testdude)
self.background=Bg(source='selectionscreen/background12.png', pos_hint={'x':0, 'y':0})
bglayout.add_widget(self.background)
bglayout.add_widget(self.tree)
bglayout.add_widget(self.testdude)
gamelayout.add_widget(bglayout)
gamelayout.add_widget(hero)
game.add_widget(gamelayout)
return sm
if __name__ == '__main__':
gameApp().run()

To answer your overall question...yes, there's no reason you shouldn't be able to.
Tracking down your problem will need more code though...at the moment your snippet doesn't make sense, because list isn't defined anywhere. Could you maybe post a short example that runs, or at least the full code you're using?
As a side note, list is not a good variable name because it overrides the list class instantiator which can be annoying or actively buggy later.

Related

How to put texture on a sphere With Qt3D and PySide6?

I am trying to put a texture on a sphere using PyQt3D with PySide6, but I am struggling. I have tried a lot of things, but the documentation is not precise at all about the classes and the methods that are supposed to be used.
Here is my attempt (the earthmap1k.jpg texture comes from here):
import sys
from PySide6.QtCore import QUrl
from PySide6.QtGui import QGuiApplication, QVector3D
from PySide6.Qt3DCore import Qt3DCore
from PySide6.Qt3DExtras import Qt3DExtras
from PySide6.Qt3DRender import Qt3DRender
class Window(Qt3DExtras.Qt3DWindow):
def __init__(self):
super().__init__()
# Camera
self.camera().lens().setPerspectiveProjection(80, 16 / 9, 0.1, 1000)
self.camera().setPosition(QVector3D(2, 0, 0))
self.camera().setViewCenter(QVector3D(0, 0, 0))
# Root entity
self.rootEntity = Qt3DCore.QEntity()
# Charger les images de texture
self.material = Qt3DExtras.QDiffuseSpecularMaterial(self.rootEntity)
diffuseTexture = Qt3DRender.QTextureImage()
diffuseUrl = QUrl('earthmap1k.jpg')
diffuseTexture.setSource(diffuseUrl)
self.material.setDiffuse(diffuseTexture)
# Sphere
self.sphereEntity = Qt3DCore.QEntity(self.rootEntity)
self.sphereMesh = Qt3DExtras.QSphereMesh()
self.sphereEntity.addComponent(self.sphereMesh)
self.sphereEntity.addComponent(self.material)
self.setRootEntity(self.rootEntity)
if __name__ == '__main__':
app = QGuiApplication(sys.argv)
view = Window()
view.show()
sys.exit(app.exec())
This is not working, but I have no idea why at the moment. I want to use QDiffuseSpecularMaterial() because i will add other textures (specular and normal) later, and QDiffuseSpecularMapMaterial() is supposed to be deprecated, and is not working better.

How can I get camera scrolling to work in Lua (using the PlayDate SDK)?

I have three issues with my PlayDate game, one big, two small:
#1 (small): I can't get camera scrolling to work;
#2 (small): I can't figure out how to not get circles to generate inside of eachother;
#3 (big): I have NO IDEA how to make a menu screen and have it change the songs (I haven't added the songs yet, I'm still writing them)
Here's my code:
import "CoreLibs/graphics"
import "CoreLibs/object"
import "CoreLibs/sprites"
import "CoreLibs/nineslice"
import "CoreLibs/timer"
import "CoreLibs/frameTimer"
import "config"
import "core/definitions"
import "core/cotton/all"
import "scripts/index"
import "core/lieb/all"
import "core/CoreGame"
bpm = 60
lastX = math.random(80, 320)
lastY = math.random(80, 160)
circles = {}
tf = playdate.geometry.affineTransform.new()
local circles = {}
local count = 0
function addCircle()
tf:rotate(math.random(360))
x, y = (tf * playdate.geometry.point.new(80, 0)):unpack()
x += lastX
y += lastY
local new_circle = playdate.graphics.drawCircleAtPoint(x, y, 40)
count = count + 1
table.insert(circles, new_circle)
lastX = x
lastY = y
playdate.graphics.setDrawOffset(x, y)
end
beatTimer = playdate.timer.performAfterDelay(60000 / bpm, addCircle)
beatTimer.repeats = true
function playdate.update()
playdate.timer.updateTimers()
end
For the menu, I know I should use grid view, but I don't know how to make things happen when something is selected, and different things when something else is selected.
For the scrolling, I want it so that you're always seeing the circles and they never go off screen, so I'm trying to change the camera's origin point to where the circles are, but it's not working.
And finally, #2 is pretty self explanatory.

How do I force a FloatLayout to keep the same dimensions as the image inside it when window size changes using Kivy?

I have an image of a chessboard added to a FloatLayout. The chessboard resizes just fine, but the layout always shows beyond the borders of the chessboard image. The background of the FloatLayout is green so I can see it.
The app opens with window maximized & no matter how I adjust the layout with size_hint when I restore the window to default size (not maximized) some part of the layout is showing.
Is there a way to make the layout always be the same size as the image inside it when it auto-resizes when the window is resized manually with the mouse or by the maximize button?
Here is my code:
from kivy.config import Config
Config.set('graphics', 'resizable', True)
Config.set('graphics', 'window_state', 'maximized')
Config.write()
import kivy
from kivy.app import App
from kivy.uix.image import Image
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout
from kivy.graphics import Color, Rectangle
kivy.require('2.0.0')
class DraggableArea(FloatLayout): # FloatLayout
def __init__(self, **kwargs):
super(DraggableArea, self).__init__(**kwargs)
self.size_hint = (.547, .89)
self.layout_size_not_retrieved = True
self.initial_updated_layout_size = None
with self.canvas.before:
Color(0, 1, 0, 1)
self.rect = Rectangle(size=(200, 200),
pos=(300, 200))
def update_rect(instance, value):
instance.rect.pos = instance.pos
instance.rect.size = instance.size
if self.layout_size_not_retrieved:
if self.rect.size[0] > 100:
self.initial_updated_layout_size = self.rect.size
self.add_widget(
Image(source="./data/images/chess-pieces/DarkerGreenGreyChessBoard.png", pos=self.rect.pos,
size_hint=(1, 1), keep_ratio=True, allow_stretch=True))
self.add_widget(
MoveableImage(source="./data/images/chess-pieces/WhiteQueen57.png",
pos=self.rect.pos))
self.layout_size_not_retrieved = False
self.bind(pos=update_rect, size=update_rect)
class MoveableImage(DragBehavior, Image):
def __init__(self, **kwargs):
super(MoveableImage, self).__init__(**kwargs)
self.drag_timeout = 10000000
self.drag_distance = 0
self.drag_rectangle = [self.x, self.y, self.width, self.height]
self.size_hint = (.1, .1)
self.keep_ratio = True
self.allow_stretch = True
def on_pos(self, *args):
self.drag_rectangle = [self.x, self.y, self.width, self.height]
def on_size(self, *args):
self.drag_rectangle = [self.x, self.y, self.width, self.height]
class egGameApp(App):
def build(self):
c = DraggableArea()
c.pos = (40, 40)
return c
if __name__ == '__main__':
egGameApp().run()
You're giving two set of contradictory instructions to DraggableArea, it cannot obey the instruction to maintain it size relative to the window size while also instructed to maintain it size relative it inner child
Either you set the aspect ratio to False by setting keep_ratio=False, or scale the image relative to the window size while maintain the image aspect ratio and then set the DraggableArea size relative to the image texture. If you're going for the later approach the you might also want to reset the position of DraggableArea to pos_hint to center_y: 0.5 to vertically center it.

Kivy instantiating widgets dynamically and based on mouse click

I am new to kivy. I am trying to create a simple application which works on detecting mouse click and draws a circle based on the co-ordinates of the mouse. The below code is able to do it.
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Ellipse, Color
from random import random
class MyAppleWidget(Widget):
def on_touch_down(self, touch):
with self.canvas:
Color(random(), 1, 1, 1)
d = 30.0
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
class MyAppleApp(App):
def build(self):
return MyAppleWidget()
if __name__ == "__main__":
MyAppleApp().run()
Kivy file -- dummy file to pop up a circle at the begining
<MyAppleWidget>:
canvas:
Color:
rgb: random(), 1,1
Ellipse:
pos: root.center
size: 10, 10
I was wondering if there was a way to shift the code in the touch function to be shifted to the kivy file.. meaning.. can I define the canvas and drawing instruction in the kivy file and pass the touch points of the mouse while creating the widget dynamically. More like using the kivy file definition to create the circle widget based on the touch point co-ordinate. I tried with dynamic classes etc. but haven't been able to arrive at a solution. Any help would be appreciated.
This can be achieved like below:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
APP_KV = """
#:import random random
#:import Ellipse kivy.graphics.Ellipse
#:import Color kivy.graphics.Color
<MyAppleWidget>:
d: 30.0
on_touch_down:
self.collide_point(*args[1].pos)
self.canvas.add(Color(random.random(), 1, 1))
self.canvas.add(Ellipse(pos=(args[1].pos[0] - self.d / 2, args[1].pos[1] - self.d / 2), size=(self.d, self.d)))
"""
class MyAppleWidget(Widget):
pass
class MyAppleApp(App):
def build(self):
self.root = Builder.load_string(APP_KV)
return MyAppleWidget()
if __name__ == "__main__":
MyAppleApp().run()

Python kivy placing buttons/labels in different places using float layout

i am new to kivy, until now ive only used tkinter, however i want to create a app for android, so now ive moved to kivy.
i've seen that widgets works totally different in kivy, anyway i simply want to place labels and buttons on a screen, i've done this with other layouts but its said that a float layout is kinda like tkinter's .place()..... so i thought that this might work but unfortunately i just can't seem to find out how to place something at my choice on the screen. Here is the program on which i want to add the buttons and labels:
from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
class MyPaintWidget(Widget):
Window.clearcolor = (1, 1, 1, 1)
def on_touch_down(self, touch):
color = (0,0,0)
with self.canvas:
Color(*color, mode='hsv')
d = 10
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
touch.ud['line'] = Line(points=(touch.x, touch.y),width=5)
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
def build(self):
parent = Widget()
self.painter = MyPaintWidget()
clearbtn = Button(text='Clear')
clearbtn.bind(on_release=self.clear_canvas)
parent.add_widget(self.painter)
parent.add_widget(clearbtn)
return parent
def clear_canvas(self, obj):
self.painter.canvas.clear()
MyPaintApp().run()
this creates a drawing screen, what i want is a sort of simulated 'contract' on which the user can sighn, but i can't figure out how to place the buttons and labels at my choice.
this question was already answered by zeeMonkeez:
Your example does not use FloatLayout. Have you looked at the documentation and played with the examples?
so for anybody who have the same problem heres the answer:
from random import random
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.graphics import Color, Ellipse, Line
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
class MyPaintWidget(Widget):
Window.clearcolor = (1, 1, 1, 1)
def on_touch_down(self, touch):
color = (0,0,0)
with self.canvas:
Color(*color, mode='hsv')
d = 3
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
touch.ud['line'] = Line(points=(touch.x, touch.y),width=1.5)
def on_touch_move(self, touch):
touch.ud['line'].points += [touch.x, touch.y]
class MyPaintApp(App):
def build(self):
parent = FloatLayout()
self.painter = MyPaintWidget()
a_button = Button(text = 'A button',pos=(20,20),size_hint=(.25,.25))
entry_name = TextInput()
parent.add_widget(self.painter)
parent.add_widget(a_button)
return parent
def clear_canvas(self, obj):
self.painter.canvas.clear()
MyPaintApp().run()

Resources