Python Forum
creating an object at another objects position
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
creating an object at another objects position
#1
i want to create a small block to be a 'laser' and fire it from the canvas image im using as a ship. i've already created a list to append to and a ttl for the laser i even created the Laser class, but getting it to appear is not working like i thought it should.
with laser.lasers.append() ive tried .append(self), .append(Laser) , .append(Laser(p[0],p[1],dx,dy)) i just dont know how to get it rolling.


from tkinter import *
from PIL import ImageTk,Image
import time
window_height = 400
window_width = 720

r =Tk()

canvas=Canvas(r,width=window_width, height=window_height)
bg=PhotoImage(file="./nightsky.png")
bg1= canvas.create_image(0,0,anchor=NW,image=bg)
canvas.pack()

class Laser:
    lasers = []
    def __init__(self,x,y,xv,yv):
        self.id = canvas.create_rectangle(10,10,24,24, fill = "red")
        self.lasers.append(self) 
        self.ttl = 100
        self.speed = 5
        self.dx = 1
        self.dy = 0

    def update(self,dx,dy):
        if self.ttl == 0:
            canvas.delete(self.id)
            self.lasers.remove(self)
            return
        self.ttl =-1
        canvas.move(self.id, x*self.speed, y*self.speed)

class ship:
    def __init__(self,x,y,xv,yv):
        self.x = x
        self.y = y
        self.img = PhotoImage(file="./8bitship.png")
        self.id = canvas.create_image(0,0,anchor=NW,image=self.img)
        self.dx = 1
        self.dy = 0
        self.img_width = self.img.width()
        self.img_height = self.img.height()
        self.xv = 0
        self.yv = 0
    
   
    def move(self,x,y):
        p = canvas.coords(self.id)
        print(p)
        if p[0] <= 0 : x = 1
        if p[0] + self.img_width > window_width : x = -1
        if p[1] <=0 : y = 1
        if p[1] + self.img_height > window_height : y = -1
        canvas.move(self.id,x,y)

   
    def fire(self,x,y,xv,yv):
        p = canvas.coords(self.id)
        print("fire")
    
        Laser.lasers.append(Laser)

                                                             
mship = ship(0,0,0,0)

r.bind("<Right>", lambda e: mship.move(x=8,y=0))
r.bind("<Left>",lambda e: mship.move(x=-8,y=0))
r.bind("<Up>",lambda e: mship.move(x=0,y=-8))
r.bind("<Down>", lambda e: mship.move(x=0,y=8))
r.bind("<space>", lambda e: mship.fire(0,0,0,0))


for laser in Laser.lasers:
    laser.update()
    r.update()
    r.mainloop()
    time.sleep(0.05)
    
r.update()
r.mainloop()
Reply
#2
What is the laser?
Reply
#3
lasers the list or Laser the class instance?
the forloop laser was a mistake it was changed to,

while True:
    r.mainloop()
    r.update()
    for Laser in Laser.lasers:
        Laser.update()
        time.sleep(0.05)
Reply
#4
You cannot do this:
while True:
    r.mainloop()
    r.update()
    for Laser in Laser.lasers:
        Laser.update()
        time.sleep(0.05)
mainloop is a blocking function call. It will never return. You will never call r.update() and you will never call any of your laser update code.

If you want to make a game you are much better off starting with PyGame or some something similar.
Reply
#5
i am not trying to make a game. im trying to understand the mechanics behind why this works.
a friend of mine is also trying to explain this to me and he got it to work lickety-split.

the keybinding and objects is really what i am after here, but if you dont know how to get it done thats ok too.
Reply
#6
PyGame can be used for more than games. It is designed to make it easier to write applications where the user interacts with a highly dynamic application. Most GUI applications are completely event driven. The user clicks a button or does something and the software responds. Other than responding to user events the software is idle. Between the two are applications that are mostly event driven, but may also have a timer that periodically fires an event. This last may be what you are looking for.

If I was writing the application in Qt I would use a QTimer. For tkinter I would see if I could do what I need with after().

You haven't answered my question. What is laser? When you see your program in your mind, what does laser do?
Reply
#7
I didn’t mean for my last statement to seem sarcastic, I should have worded it as, if I am not supposed to do this with Tkinter that is fine, I am also interested in pygame, I just don’t understand how a friend of mine got it done. (He doesn’t have the time to explain everything to me).
but I finally got it.
And laser is a instance of the Laser it stores the update method in each instance and that can be iterated Over with a for loop. At least that’s how I understood it.

def fire(self):
    p = canvas.coords(self.id)
    Laser(p[0],p[3],self.dx,self.dy
while True:
    r.mainloop()
    r.update()
    for laser in Laser.lasers:
        laser.update()
        time.sleep(.1)
Reply
#8
I was having a tough time understanding the lasers. Took the name too literally and expected a line that grows in length and didn't see how your rectangles would ever do something like that. But your lasers are projectiles which is fairly easy. The thing you are missing is the after() method.
import math
import tkinter as tk
import random

window_height = 400
window_width = 720

class Laser:
    instances = []
    colors = ('red', 'yellow', 'blue', 'orange', 'green', 'purple', 'pink', 'brown', 'grey')

    @classmethod
    def update(cls):
        """Move all the lasers.  Remove offscreen lasers"""
        cls.instances = [laser for laser in cls.instances if laser.move()]

    def __init__(self, x, y, dx, dy):
        self.id = canvas.create_line(x, y, x, y, width=3, fill=random.choice(self.colors))
        self.x = x
        self.y = y
        self.dx = dx
        self.dy = dy
        self.length = 0
        self.instances.append(self)

    def move(self):
        """Update laser position.  Return True if visible"""
        self.length = min(30, self.length+1)
        self.x += self.dx
        self.y += self.dy
        x = self.x - self.length * self.dx
        y = self.y - self.length * self.dy
        if 0 <= x <= window_width and 0 <= y <= window_height:
            canvas.coords(self.id, int(x), int(y), int(self.x), int(self.y))
            return True
        canvas.delete(self.id)
        return False

def update_lasers():
    """Periodically update the lasers"""
    Laser.update()
    root.after(10, update_lasers)

def fire(*args):
    """Fire a rainbow starburst of lasers"""
    step = random.randint(1, 60)
    for angle in range(step//2, 360, step):
        angle = math.radians(angle)
        Laser(360, 200, math.sin(angle), math.cos(angle))

root = tk.Tk()
canvas = tk.Canvas(root, width=window_width, height=window_height)
canvas.pack()
root.bind("<space>", fire)
update_lasers()
root.mainloop()
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020