Как создать эффект маски в tkinter? - PullRequest
0 голосов
/ 23 июня 2019

Я пытался создать игру и хотел, чтобы в ней был маскирующий эффект, чтобы область, в которой находится персонаж, была видна, но я не смог этого сделать, я подумал о перерисовке полигонов, но это кажется довольно наивным. Если у вас есть обходной путь для этого, пожалуйста, поделитесь им со мной или если в tkinter canvas есть какая-либо функция для этого.

Маскирующий эффект выглядит так: jsfiddle: http://jsfiddle.net/w2t0fq41/

import tkinter as tk
from threading import Thread
from time import sleep
from math import sqrt
from PIL import ImageTk, Image
import random
__author__ = "Avanish"


class Bullet(object):
    def __init__(self, canvas = None, pos = [0, 0], direction = 1):# Direction will be calculated as per degrees
                self.canvas = canvas

    def move(self):
        pass

    def checkCollision(self):
        pass



class Character(object):
    def __init__(self, name = "Player1", canvas = None, pos = [0,0]):
        self.canvas = canvas
        self.name = name
        self.health = 100
        self.pos = pos
        self.image1 = ImageTk.PhotoImage(Image.open('Character1.png').resize((50, 50), Image.ANTIALIAS))
        self.image2 = ImageTk.PhotoImage(Image.open('Character2.png').resize((50, 50), Image.ANTIALIAS))
        #self.sprite = self.canvas.create_oval(pos[0], pos[1], pos[0] + 30, pos[1] + 30, fill = 'white', tag = 'Protagonist')
        self.sprite = self.canvas.create_image(pos[0], pos[1], image = self.image1, tag = 'Protagonist')


        self.legpos = True
        self.canvas.after(300, self.changeImage)
    def move(self, x, y):
        self.canvas.move(self.sprite, x, y)

    def attack(self):
        pass


    def changeImage(self):
        if self.legpos:
            self.canvas.itemconfig(self.sprite, image = self.image2)
            self.legpos = False
        else:
            self.canvas.itemconfig(self.sprite, image = self.image1)
            self.legpos = True

        self.canvas.after(300, self.changeImage)

class Enemy(object):
    def __init__(self, name = "Killer", canvas = None, level = 1):
        self.canvas = canvas
        self.name = name
        self.level = level
        self.pos = []

        self.sprite = self.canvas.create_rectangle(pos[0], pos[1], pos[0] + 50, pos[1] + 50, fill = 'white')

    def move(self, x, y):
        self.canvas.move(self.sprite, x, y)


class Main(tk.Frame):
    def __init__(self, master = None, width = 400, height = 700):
        super().__init__()
        self.master = master
        self.screenwidth = width
        self.screenheight = height
        self.place(x = 0, y = 0, width = width, height = height)
        self.draweverything()
        self.boxchange = 1
        self.mouseMotion()

    def draweverything(self):

        self.canvas = tk.Canvas(master = self, bg = 'black')
        self.canvas.place(x = 0, y = 0, width = self.screenwidth, height = self.screenheight)
        self.drawObstacles()
        self.player = Character(canvas = self.canvas, pos = [50, self.screenheight - 80])

    def drawObstacles(self):
        self.obstacles = []
        for a in range(20):
            x = random.choice(range(5, self.screenwidth - 50, 55))
            y = random.choice(range(5, self.screenheight - 100, 55))

            self.obstacles.append(self.canvas.create_rectangle(x, y, x + 50, y + 50, fill = 'red', tag = 'Box{}'.format(a)))

        self.obstacles = self.obstacles
        print(self.obstacles)

    def updateObstacles(self):
        spritey = self.canvas.coords('Protagonist')[1]

        if spritey <= 400 or spritey <= 350:
            for x in self.obstacles: self.canvas.move(x, 0, self.boxchange)

        for obstacle in self.obstacles:
            y = self.canvas.coords(obstacle)[1]
            if y >= 650:
                self.canvas.delete(obstacle)
                b = random.choice(range(5, 300, 55))
                self.obstacles.append(self.canvas.create_rectangle(5, b, 55, b + 50, fill = 'red'))

        self.canvas.after(15000, self.updateObstacles)

    def moveTowardsMouse(self, x, y):
        spritex, spritey = self.canvas.coords('Protagonist')
        # Code to make sure the player does not go out of the canvas



        if (spritex <= 25 and x < 0) or (spritex >= 375 and x > 0):
            if (spritey <= 350 and y < 0) or (spritey >= 675 and y > 0): pass
            else: self.canvas.move('Protagonist', 0, y)
        elif (spritey <= 350 and y < 0) or (spritey >= 675 and y > 0):
            if (spritex <= 25 and x < 0) or (spritex >= 375 and x > 0): pass
            else: self.canvas.move('Protagonist', x, 0)
        else:self.canvas.move('Protagonist', x, y)

    def mouseMotion(self):
        mx, my = (self.master.winfo_pointerx() - self.master.winfo_rootx()),(self.master.winfo_pointery() - self.master.winfo_rooty())
        x, y = self.canvas.coords('Protagonist')
        dist = sqrt(((mx - x) ** 2) + ((my - y) ** 2))
        speed = 1.0
        movex = ((mx - x) / dist) * speed
        movey = ((my - y) / dist) * speed


        self.moveTowardsMouse(movex, movey)
        self.updateObstacles()
        sleep(.01)
        self.canvas.after(10, self.mouseMotion)




root = tk.Tk()
root.geometry('400x700')
app = Main(master = root)
app.mainloop()

1 Ответ

1 голос
/ 23 июня 2019

Одним из способов имитации эффекта было бы использование Toplevel с wm_attributes, установленным для удаления определенного цвета, а затем наложение изображения.В приведенном ниже примере я использовал изображение кота из вашего jsfiddle и случайный белый фоновый круг, выделенный из здесь .

import tkinter as tk
from PIL import Image, ImageTk

class Gui(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self.geometry("500x500+400+400")
        self.cat = ImageTk.PhotoImage(Image.open("500.jpg")) #your cat image
        tk.Label(self,image=self.cat).pack()
        self.overrideredirect(True)
        self.top_level()

    def top_level(self):
        top = tk.Toplevel()
        top.config(bg="black")
        top.geometry("490x470+400+400")
        self.update_idletasks()
        self.circle = tk.PhotoImage(file="circle.png") #a circle with white as background
        self.circle = self.circle.subsample(7)
        self.circle_effect = tk.Label(top,image=self.circle,bg="black")
        top.wm_attributes("-transparentcolor", "white") #remove color white
        top.transient(self)
        top.bind("<Motion>", self.placement) #
        top.grab_set()
        top.wm_protocol("WM_DELETE_WINDOW",self.destroy)

    def placement(self,event):
        try:
            self.circle_effect.place_forget()
        except tk.TclError:
            pass
        self.circle_effect.place(x=event.x-100, y=event.y-100) #move the label to your cursor location

root = Gui()
root.mainloop()

Вам все еще нужно будет поработать над тем, как обращаться с пользователями, перемещающими окно и т. Д., Но это должно помочь вам начать работу.

...