Posts: 21
Threads: 3
Joined: Oct 2017
Nov-13-2017, 07:23 PM
(This post was last modified: Nov-13-2017, 07:38 PM by hammza.)
(Nov-13-2017, 01:46 PM)heiner55 Wrote: This needs big changes.
A class for the ship and a class for the bullet.
Each class take care of the position x and y and has a draw/update function.
Then you need a function which is called every 1/100s.
This function calls all updates functions from your ship and from many bullets.
You should google for ping pong. If you understand ping pong,
you can also code your game.
See https://gist.github.com/calebrob6/4022622
Thank for your advice
(Nov-13-2017, 05:16 PM)Windspar Wrote: here an example
import tkinter as tk
SCREEN = 600, 400
class Bullet:
def __init__(self, canvas, x, y, tk_fill, movement):
self.bullet = canvas.create_oval(x -3 , y - 3, x + 3, y + 3, fill=tk_fill)
self.movement = movement
def move(self, canvas):
canvas.move(self.bullet, self.movement[0], self.movement[1])
class App(tk.Frame):
def __init__(self, master):
# put canvas in frame so you can have other goodies
tk.Frame.__init__(self, master)
self.pack()
self.canvas = tk.Canvas(self, width=SCREEN[0], height=SCREEN[1])
self.canvas.pack()
self.bullets = []# store bullets
self.tick_loop() # start the tick loop
self.ship = self.create_ship(300, 370, "blue")
master.bind("<Left>", self.go_left)
master.bind("<Right>", self.go_right)
master.bind("<Up>", self.go_up)
master.bind("<Down>", self.go_down)
master.bind("<space>", self.space_key)
def create_ship(self, x, y, tk_fill):
return self.canvas.create_polygon(x, y, x - 20, y + 30, x + 20, y + 30, fill=tk_fill)
def tick_loop(self):
remove_list =
for enum, bullet in enumerate(self.bullets):
if self.canvas.coords(bullet.bullet)[1] < 0:
remove_list.append(enum)
self.canvas.delete(bullet.bullet)
else:
bullet.move(self.canvas)
for index in remove_list:
self.bullets.pop(index)
# framerate per seconds 1000/30 = 30 frames roughly
self.after(int(1000/30), self.tick_loop)
def go_left(self, event):
self.canvas.move(self.ship, -5, 0)
self.canvas.update()
def go_right(self, event):
self.canvas.move(self.ship, 5, 0)
self.canvas.update()
def go_up(self, event):
self.canvas.move(self.ship, 0, -5)
self.canvas.update()
def go_down(self, event):
self.canvas.move(self.ship, 0, 5)
self.canvas.update()
def space_key(self, event=0):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
# just having shoot straight up
self.bullets.append(Bullet(self.canvas, x, y, "blue", (0, -10)))
def main():
root = tk.Tk()
app = App(root)
app.mainloop()
if __name__ == '__main__':
main() Don't like how keypress working but here it is.
Would be easier in pygame or pysfml.
fix poping bug. popping bug so far has no effect on above good. Just added little more stuff.
import tkinter as tk
SCREEN = 600, 400
class Bullet:
def __init__(self, canvas, x, y, tk_fill, movement):
self.bullet = canvas.create_oval(x -3 , y - 3, x + 3, y + 3, fill=tk_fill)
self.movement = movement
def move(self, canvas):
canvas.move(self.bullet, self.movement[0], self.movement[1])
class App(tk.Frame):
def __init__(self, master):
# put canvas in frame so you can have other goodies
tk.Frame.__init__(self, master)
self.pack()
self.canvas = tk.Canvas(self, width=SCREEN[0], height=SCREEN[1])
self.canvas.pack()
self.bullets = [] # store bullets
self.tick_loop() # start the tick loop
self.ship = self.create_ship(300, 370, "blue")
master.bind("<Left>", self.go_left)
master.bind("<Right>", self.go_right)
master.bind("<Up>", self.go_up)
master.bind("<Down>", self.go_down)
master.bind("<space>", self.space_key)
master.bind("<b>", self.go_b)
master.bind("<v>", self.go_v)
def create_ship(self, x, y, tk_fill):
return self.canvas.create_polygon(x, y, x - 20, y + 30, x + 20, y + 30, fill=tk_fill)
def tick_loop(self):
remove_list = []
for enum, bullet in enumerate(self.bullets):
coords = self.canvas.coords(bullet.bullet)
if coords[1] < 0 or coords[0] < 0 or coords[2] > SCREEN[0]:
remove_list.append(enum)
self.canvas.delete(bullet.bullet)
else:
bullet.move(self.canvas)
# fix poping bug
for enum, index in enumerate(remove_list):
self.bullets.pop(index - enum)
# framerate per seconds 1000/30 = 30 frames roughly
self.after(int(1000/30), self.tick_loop)
def go_left(self, event):
self.canvas.move(self.ship, -5, 0)
self.canvas.update()
def go_right(self, event):
self.canvas.move(self.ship, 5, 0)
self.canvas.update()
def go_up(self, event):
self.canvas.move(self.ship, 0, -5)
self.canvas.update()
def go_down(self, event):
self.canvas.move(self.ship, 0, 5)
self.canvas.update()
def space_key(self, event=0):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
# just having shoot straight up
self.bullets.append(Bullet(self.canvas, x, y, "blue", (0, -10)))
# spread shooting
def go_b(self, event):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "red", (0, -8)))
#left
self.bullets.append(Bullet(self.canvas, x, y, "red", (-8, 0)))
#right
self.bullets.append(Bullet(self.canvas, x, y, "red", (8, 0)))
# triple shoot striaght up
def go_v(self, event):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x - 50, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x + 50, y, "green", (0, -5)))
def main():
root = tk.Tk()
app = App(root)
app.mainloop()
if __name__ == '__main__':
main()
That's a great help from you, thank you very much for the codes
Please can you tell me where did learned all this, or do you know any tutorials or books that help begginers to reach this advanced levels.
(Nov-13-2017, 01:01 PM)metulburr Wrote: Quote:What i want is how to make it shoot like (space invaders), I don't know how to use coords, and I didn't found any good tutorial or explanation.
Thats because no one uses tkinter to make games. There is a better library to handle that kind of software and it called pygame. In fact, we have a tutorial on how to make a ship shoot like space invaders on this forum. Tkinter is a GUI library mainly for building window form apps.
Thank you for your advice
I know about pygame, but I don't want to use it
I want to learn how to use pure python with less libraries, just the important ones like tkinter canvas and built in functions.
I want to learn how to make games just like old style was, with functions.
Posts: 5,151
Threads: 396
Joined: Sep 2016
Nov-13-2017, 08:52 PM
(This post was last modified: Nov-13-2017, 08:53 PM by metulburr.)
Quote:I want to learn how to use pure python with less libraries
You are actually not using pure python as tkinter is not apart of the standard library. Only Windows comes packaged with tkinter and you can even opt out of installing it in the python installer. Linux you have to install it like any other 3rd party lib. If you compile python on windows, tkinter is not apart of it.
The first paragraph briefly explains this
https://docs.python.org/3.6/library/tkinter.html
So you are already using a 3rd party module. Its just the build you installed, already has that 3rd party library with it.
Recommended Tutorials:
Posts: 544
Threads: 15
Joined: Oct 2016
Nov-13-2017, 09:11 PM
(This post was last modified: Nov-13-2017, 09:37 PM by Windspar.)
Quote:I want to learn how to make games just like old style was, with functions.
Almost all program language have some type of structures. Python and old style is not going to work.
Python has built in polymorph. Almost all python is object base. An modern programming helps reduce size of code.
Take classes. Add a namespace to object and create many different objects quickly. Methods are just function wrap in a class. You always could check out assembly code for old programming.
linux nasm assembly example
Quote:; nasm hello asm
; nasm -f elf hello.asm
; ld -m elf_i386 hello.o -o hello
SECTION .data
msg db 'Hello World!', 0Ah
msg2 db 'Hello, brave new world!', 0Ah
SECTION .text
global _start
_start:
mov edx, 13
mov ecx, msg
mov ebx, 1 ; stdout
mov eax, 4 ; system write
int 80h
mov ebx, msg2
mov eax, ebx
; count char in string
nextchar:
cmp byte [eax], 0
jz finished
inc eax
jmp nextchar
finished:
sub eax, ebx
mov edx, eax
mov ecx, msg2
mov ebx, 1 ; stdout
mov eax, 4 ; system write
int 80h
; exit call
mov ebx, 0
mov eax, 1
int 80h in python
print("Hello World!")
print("Hello, brave new world!") Quote:Please can you tell me where did learned all this, or do you know any tutorials or books that help begginers to reach this advanced levels.
I learn by making little programs.
Testing one thing to death.
learn by runtime errors.
using print(dir(on object)) to see there variables and methods and builtins
read docs and code
There is no magic formula to making programs.
nothing but commands and pushing and altering numbers around.
strings are nothing but numbers.
I don't call this advance stuff. Just basic python.
99 percent of computer problems exists between chair and keyboard.
Posts: 606
Threads: 3
Joined: Nov 2016
Posts: 544
Threads: 15
Joined: Oct 2016
Found no solution to tkinter annoying keypress. Just compare tkinter vs pysfml.
Here pysfml example. I would recommend pygame because of better docs.
from sfml import sf
class Bullet:
def __init__(self, x, y, color, movement):
self.bullet = sf.CircleShape(3, 18)
self.bullet.position = x, y
self.bullet.fill_color = color
self.movement = movement
def move(self, speed):
vector = (self.movement[0] * speed + self.bullet.position.x,
self.movement[1] * speed + self.bullet.position.y)
self.bullet.position = vector
class App:
def __init__(self):
self.window = sf.RenderWindow(sf.VideoMode(600, 400), "Invaders")
self.bullets = []
self.create_ship(300, 370, sf.Color(0,0,200))
def create_ship(self, x, y, color):
self.ship = sf.ConvexShape(3)
self.ship.set_point(0, (0, 0))
self.ship.set_point(1, (-20, 30))
self.ship.set_point(2, ( 20, 30))
self.ship.fill_color = color
self.ship.position = x, y
def loop(self):
clock = sf.Clock()
bullet_clock = sf.Clock()
while self.window.is_open:
for event in self.window.events:
if event.type == sf.Event.CLOSED:
self.window.close()
elif event.type == sf.Event.KEY_PRESSED:
if sf.Keyboard.is_key_pressed(sf.Keyboard.ESCAPE):
self.window.close()
# create bullets
if sf.Keyboard.is_key_pressed(sf.Keyboard.SPACE):
# keeps bullet at steady intervals
if bullet_clock.elapsed_time.milliseconds > 300:
bullet_clock.restart()
vector = self.ship.position
self.bullets.append(Bullet(vector.x, vector.y, sf.Color(0,0,200), (0,-2)))
# movement, speed keeps movement steady
speed = 100 * clock.elapsed_time.seconds
if sf.Keyboard.is_key_pressed(sf.Keyboard.LEFT):
self.ship.move((-speed, 0))
elif sf.Keyboard.is_key_pressed(sf.Keyboard.RIGHT):
self.ship.move((speed, 0))
elif sf.Keyboard.is_key_pressed(sf.Keyboard.UP):
self.ship.move((0, -speed))
elif sf.Keyboard.is_key_pressed(sf.Keyboard.DOWN):
self.ship.move((0, speed))
self.window.clear()
# draw bullets
bullet_remove = []
for enum, bullet in enumerate(self.bullets):
if bullet.bullet.position.y < 0:
bullet_remove.append(enum)
else:
bullet.move(speed)
self.window.draw(bullet.bullet)
for enum, index in enumerate(bullet_remove):
self.bullets.pop(index - enum)
self.window.draw(self.ship)
self.window.display()
clock.restart()
sf.sleep(sf.milliseconds(5))
def main():
app = App()
app.loop()
if __name__ == '__main__':
main()
99 percent of computer problems exists between chair and keyboard.
Posts: 544
Threads: 15
Joined: Oct 2016
here a pygame example
import pygame
pygame.init()
SCREEN = 600, 400
class Bullet:
def __init__(self, x, y, color, movement):
self.position = [x - movement[0], y - movement[1]]
self.color = color
self.movement = movement
def blit(self, surface):
self.position[0] += self.movement[0]
self.position[1] += self.movement[1]
position = int(self.position[0]), int(self.position[1])
pygame.draw.circle(surface, self.color, position, 3)
class Ship:
def __init__(self, x, y, color, pointlist):
self.position = [x, y]
self.pointlist = pointlist
self.color = color
def move(self, x, y):
self.position[0] += x
self.position[1] += y
def blit(self, surface):
points = []
for point in self.pointlist:
points.append((self.position[0] + point[0], self.position[1] + point[1]))
pygame.draw.polygon(surface, self.color, points)
class Pauser:
def __init__(self, length):
self.length = length
self.last_tick = 0
def elaspe(self, ticks):
if ticks > self.last_tick + self.length:
self.last_tick = ticks
return True
return False
class App:
def __init__(self):
pygame.display.set_caption("Invaders")
# create are screen. Your main surface
self.screen = pygame.display.set_mode(SCREEN)
# create a clock for framerate control
self.clock = pygame.time.Clock()
self.bullets = []
self.bullets_pauser = Pauser(300)
self.ship = Ship(300, 370, (0,0,200), ((0,0), (-20,30), (20,30)))
def loop(self):
running = True
self.ticks = 0
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
last_ticks = self.ticks
self.ticks = pygame.time.get_ticks()
speed = (self.ticks - last_ticks) * 0.05
# grab all keys return True if pressed
key_press = pygame.key.get_pressed()
# creaate bullets
if key_press[pygame.K_SPACE]:
# shoot bullets in intervals
if self.bullets_pauser.elaspe(self.ticks):
x, y = self.ship.position
self.bullets.append(Bullet(x, y, (0,0,200), (0,-10)))
# ship movement
ship_speed = speed * 3
if key_press[pygame.K_LEFT]:
self.ship.move(-ship_speed, 0)
elif key_press[pygame.K_RIGHT]:
self.ship.move(ship_speed, 0)
elif key_press[pygame.K_UP]:
self.ship.move(0, -ship_speed)
elif key_press[pygame.K_DOWN]:
self.ship.move(0, ship_speed)
# clear screen
self.screen.fill((0,0,0))
# blits bullets
remove_list = []
for enum, bullet in enumerate(self.bullets):
if bullet.position[1] < 0:
remove_list.append(enum)
else:
bullet.blit(self.screen)
for enum, index in enumerate(remove_list):
self.bullets.pop(index - enum)
self.ship.blit(self.screen)
pygame.display.flip()
# frame per seconds
self.clock.tick(30)
def main():
app = App()
app.loop()
pygame.quit()
if __name__ == '__main__':
main()
99 percent of computer problems exists between chair and keyboard.
Posts: 5,151
Threads: 396
Joined: Sep 2016
Nov-14-2017, 09:23 PM
(This post was last modified: Nov-14-2017, 09:24 PM by metulburr.)
if you remove the elif, to have all if, you can do two angles at the same time making it more "natural" feeling
(Nov-14-2017, 08:40 PM)Windspar Wrote: here a pygame example
import pygame
pygame.init()
SCREEN = 600, 400
class Bullet:
def __init__(self, x, y, color, movement):
self.position = [x - movement[0], y - movement[1]]
self.color = color
self.movement = movement
def blit(self, surface):
self.position[0] += self.movement[0]
self.position[1] += self.movement[1]
position = int(self.position[0]), int(self.position[1])
pygame.draw.circle(surface, self.color, position, 3)
class Ship:
def __init__(self, x, y, color, pointlist):
self.position = [x, y]
self.pointlist = pointlist
self.color = color
def move(self, x, y):
self.position[0] += x
self.position[1] += y
def blit(self, surface):
points = []
for point in self.pointlist:
points.append((self.position[0] + point[0], self.position[1] + point[1]))
pygame.draw.polygon(surface, self.color, points)
class Pauser:
def __init__(self, length):
self.length = length
self.last_tick = 0
def elaspe(self, ticks):
if ticks > self.last_tick + self.length:
self.last_tick = ticks
return True
return False
class App:
def __init__(self):
pygame.display.set_caption("Invaders")
# create are screen. Your main surface
self.screen = pygame.display.set_mode(SCREEN)
# create a clock for framerate control
self.clock = pygame.time.Clock()
self.bullets = []
self.bullets_pauser = Pauser(300)
self.ship = Ship(300, 370, (0,0,200), ((0,0), (-20,30), (20,30)))
def loop(self):
running = True
self.ticks = 0
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
last_ticks = self.ticks
self.ticks = pygame.time.get_ticks()
speed = (self.ticks - last_ticks) * 0.05
# grab all keys return True if pressed
key_press = pygame.key.get_pressed()
# creaate bullets
if key_press[pygame.K_SPACE]:
# shoot bullets in intervals
if self.bullets_pauser.elaspe(self.ticks):
x, y = self.ship.position
self.bullets.append(Bullet(x, y, (0,0,200), (0,-10)))
# ship movement
ship_speed = speed * 3
if key_press[pygame.K_LEFT]:
self.ship.move(-ship_speed, 0)
if key_press[pygame.K_RIGHT]:
self.ship.move(ship_speed, 0)
if key_press[pygame.K_UP]:
self.ship.move(0, -ship_speed)
if key_press[pygame.K_DOWN]:
self.ship.move(0, ship_speed)
# clear screen
self.screen.fill((0,0,0))
# blits bullets
remove_list = []
for enum, bullet in enumerate(self.bullets):
if bullet.position[1] < 0:
remove_list.append(enum)
else:
bullet.blit(self.screen)
for enum, index in enumerate(remove_list):
self.bullets.pop(index - enum)
self.ship.blit(self.screen)
pygame.display.flip()
# frame per seconds
self.clock.tick(30)
def main():
app = App()
app.loop()
pygame.quit()
if __name__ == '__main__':
main()
Recommended Tutorials:
Posts: 544
Threads: 15
Joined: Oct 2016
@ metulburr yeah for some reason i thought showing how it works in tkinter would be better. Instead showing what possible with pygame and pysfml. Still looking for a way to do it in tkinter. If there one. Unless it a linux side problem.
@ hammza
Hope this help to show you has basic this is. Added more comments.
Anything you think is still advanced let me know. I show you how basic it is.
import tkinter as tk
# this makes a tuple (600, 400). tuples can be index
SCREEN = 600, 400
# Object
class Bullet:
# movement takes a tuple (x, y)
def __init__(self, canvas, x, y, tk_fill, movement):
self.bullet = canvas.create_oval(x -3 , y - 3, x + 3, y + 3, fill=tk_fill)
self.movement = movement
#object method. self refers to object
def move(self, canvas):
canvas.move(self.bullet, self.movement[0], self.movement[1])
class App(tk.Frame):
def __init__(self, master):
# put canvas in frame so you can have other goodies
# this is from inheriting tk.Frame and calls __init__.
# so the App gains all variables and methods from tk.Frame
tk.Frame.__init__(self, master)
self.pack()
# self.canvas is an object variable
self.canvas = tk.Canvas(self, width=SCREEN[0], height=SCREEN[1])
self.canvas.pack()
# just a python list
self.bullets = [] # store bullets
# calls method. App.tick_loop(object)
self.tick_loop() # start the tick loop
# calls method. object.ship = App.create_ship(object, 300, 370, "blue")
self.ship = self.create_ship(300, 370, "blue")
master.bind("<Left>", self.go_left)
master.bind("<Right>", self.go_right)
master.bind("<Up>", self.go_up)
master.bind("<Down>", self.go_down)
master.bind("<space>", self.space_key)
master.bind("<b>", self.go_b)
master.bind("<v>", self.go_v)
def create_ship(self, x, y, tk_fill):
return self.canvas.create_polygon(x, y, x - 20, y + 30, x + 20, y + 30, fill=tk_fill)
def tick_loop(self):
remove_list = []
# upacking iterable [(0, object(Bullet)), (1, object(Bullet)), etc]
for enum, bullet in enumerate(self.bullets):
coords = self.canvas.coords(bullet.bullet)
if coords[1] < 0 or coords[0] < 0 or coords[2] > SCREEN[0]:
remove_list.append(enum)
self.canvas.delete(bullet.bullet)
else:
bullet.move(self.canvas)
# fix popping bug
for enum, index in enumerate(remove_list):
self.bullets.pop(index - enum)
# framerate per seconds 1000/30 = 30 frames roughly
self.after(int(1000/30), self.tick_loop)
def go_left(self, event):
self.canvas.move(self.ship, -5, 0)
self.canvas.update()
def go_right(self, event):
self.canvas.move(self.ship, 5, 0)
self.canvas.update()
def go_up(self, event):
self.canvas.move(self.ship, 0, -5)
self.canvas.update()
def go_down(self, event):
self.canvas.move(self.ship, 0, 5)
self.canvas.update()
def space_key(self, event=0):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
# just having shoot straight up
self.bullets.append(Bullet(self.canvas, x, y, "blue", (0, -10)))
# spread shooting
def go_b(self, event):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "red", (0, -8)))
#left
self.bullets.append(Bullet(self.canvas, x, y, "red", (-8, 0)))
#right
self.bullets.append(Bullet(self.canvas, x, y, "red", (8, 0)))
# triple shoot striaght up
def go_v(self, event):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x - 50, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x + 50, y, "green", (0, -5)))
def main():
root = tk.Tk()
app = App(root)
app.mainloop()
# __name__ only equals '__main__' if it is execute
# if import then it equals module name
if __name__ == '__main__':
main()
99 percent of computer problems exists between chair and keyboard.
Posts: 544
Threads: 15
Joined: Oct 2016
Nov-18-2017, 02:50 AM
(This post was last modified: Nov-18-2017, 02:54 AM by Windspar.)
Okay figure out how to make tkinter keypress work smoothly. Enjoy!
import tkinter as tk
# this makes a tuple (600, 400). tuples can be index
SCREEN = 600, 400
class Pauser:
def __init__(self, length):
self.length = length
self.last_tick = 0
def elaspe(self, ticks):
if ticks > self.last_tick + self.length:
self.last_tick = ticks
return True
return False
def update(self, ticks):
self.last_tick = ticks
# Object
class Bullet:
# movement takes a tuple (x, y)
def __init__(self, canvas, x, y, tk_fill, movement):
self.bullet = canvas.create_oval(x -3 , y - 3, x + 3, y + 3, fill=tk_fill)
self.movement = movement
#object method. self refers to object
def move(self, canvas):
canvas.move(self.bullet, self.movement[0], self.movement[1])
class App(tk.Frame):
def __init__(self, master):
# put canvas in frame so you can have other goodies
# this is from inheriting tk.Frame and calls __init__.
# so the App gains all variables and methods from tk.Frame
tk.Frame.__init__(self, master)
self.pack()
# self.canvas is an object variable
self.canvas = tk.Canvas(self, width=SCREEN[0], height=SCREEN[1])
self.canvas.pack()
# just a python list
self.bullets = # store bullets
# how fast a bullet can shoot
self.shoot_pauser = Pauser(12)
self.triple_pauser = Pauser(30)
self.spread_pauser = Pauser(25)
# storing keys to dict
self.keys_press = {}
# need to slow shooting
self.ticks = 0
# calls method. object.ship = App.create_ship(object, 300, 370, "blue")
self.ship = self.create_ship(300, 370, "blue")
self.speed = 5
# calls method. App.tick_loop(object)
self.tick_loop() # start the tick loop
print("Keys Press:", self.keys_press)
self.bind_all('<KeyPress>', self.go_press)
self.bind_all('<KeyRelease>', self.go_release)
def create_ship(self, x, y, tk_fill):
return self.canvas.create_polygon(x, y, x - 20, y + 30, x + 20, y + 30, fill=tk_fill)
def tick_loop(self):
remove_list =
# upacking iterable [(0, object(Bullet)), (1, object(Bullet)), etc]
for enum, bullet in enumerate(self.bullets):
coords = self.canvas.coords(bullet.bullet)
if coords[1] < 0 or coords[0] < 0 or coords[2] > SCREEN[0]:
remove_list.append(enum)
self.canvas.delete(bullet.bullet)
else:
bullet.move(self.canvas)
# NEW moving player
if self.keys_press.get('Left', False):
self.canvas.move(self.ship, -self.speed, 0)
if self.keys_press.get('Right', False):
self.canvas.move(self.ship, self.speed, 0)
if self.keys_press.get('Up', False):
self.canvas.move(self.ship, 0, -self.speed)
if self.keys_press.get('Down', False):
self.canvas.move(self.ship, 0, self.speed)
if self.keys_press.get('space', False):
if self.shoot_pauser.elaspe(self.ticks):
self.spread_pauser.update(self.ticks)
self.triple_pauser.update(self.ticks)
self.shoot()
if self.keys_press.get('b', False):
if self.spread_pauser.elaspe(self.ticks):
self.shoot_pauser.update(self.ticks)
self.triple_pauser.update(self.ticks)
self.spread_shot()
if self.keys_press.get('v', False):
if self.triple_pauser.elaspe(self.ticks):
self.shoot_pauser.update(self.ticks)
self.spread_pauser.update(self.ticks)
self.triple_shot()
# fix popping bug
for enum, index in enumerate(remove_list):
self.bullets.pop(index - enum)
# framerate per seconds 1000/30 = 30 frames roughly
self.ticks += 1
self.after(int(1000/30), self.tick_loop)
def go_press(self, event):
self.keys_press[event.keysym] = True
def go_release(self, event):
self.keys_press[event.keysym] = False
def shoot(self):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
# just having shoot straight up
self.bullets.append(Bullet(self.canvas, x, y, "blue", (0, -10)))
# spread shooting
def spread_shot(self):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "red", (0, -8)))
#left
self.bullets.append(Bullet(self.canvas, x, y, "red", (-8, 0)))
#right
self.bullets.append(Bullet(self.canvas, x, y, "red", (8, 0)))
# triple shot striaght up
def triple_shot(self):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x - 50, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x + 50, y, "green", (0, -5)))
def main():
root = tk.Tk()
app = App(root)
app.mainloop()
# __name__ only equals '__main__' if it is execute
# if import then it equals module name
if __name__ == '__main__':
main()
99 percent of computer problems exists between chair and keyboard.
Posts: 21
Threads: 3
Joined: Oct 2017
Dec-06-2017, 01:13 PM
(This post was last modified: Dec-06-2017, 01:19 PM by hammza.)
(Nov-18-2017, 02:50 AM)Windspar Wrote: Okay figure out how to make tkinter keypress work smoothly. Enjoy!
import tkinter as tk
# this makes a tuple (600, 400). tuples can be index
SCREEN = 600, 400
class Pauser:
def __init__(self, length):
self.length = length
self.last_tick = 0
def elaspe(self, ticks):
if ticks > self.last_tick + self.length:
self.last_tick = ticks
return True
return False
def update(self, ticks):
self.last_tick = ticks
# Object
class Bullet:
# movement takes a tuple (x, y)
def __init__(self, canvas, x, y, tk_fill, movement):
self.bullet = canvas.create_oval(x -3 , y - 3, x + 3, y + 3, fill=tk_fill)
self.movement = movement
#object method. self refers to object
def move(self, canvas):
canvas.move(self.bullet, self.movement[0], self.movement[1])
class App(tk.Frame):
def __init__(self, master):
# put canvas in frame so you can have other goodies
# this is from inheriting tk.Frame and calls __init__.
# so the App gains all variables and methods from tk.Frame
tk.Frame.__init__(self, master)
self.pack()
# self.canvas is an object variable
self.canvas = tk.Canvas(self, width=SCREEN[0], height=SCREEN[1])
self.canvas.pack()
# just a python list
self.bullets = # store bullets
# how fast a bullet can shoot
self.shoot_pauser = Pauser(12)
self.triple_pauser = Pauser(30)
self.spread_pauser = Pauser(25)
# storing keys to dict
self.keys_press = {}
# need to slow shooting
self.ticks = 0
# calls method. object.ship = App.create_ship(object, 300, 370, "blue")
self.ship = self.create_ship(300, 370, "blue")
self.speed = 5
# calls method. App.tick_loop(object)
self.tick_loop() # start the tick loop
print("Keys Press:", self.keys_press)
self.bind_all('<KeyPress>', self.go_press)
self.bind_all('<KeyRelease>', self.go_release)
def create_ship(self, x, y, tk_fill):
return self.canvas.create_polygon(x, y, x - 20, y + 30, x + 20, y + 30, fill=tk_fill)
def tick_loop(self):
remove_list =
# upacking iterable [(0, object(Bullet)), (1, object(Bullet)), etc]
for enum, bullet in enumerate(self.bullets):
coords = self.canvas.coords(bullet.bullet)
if coords[1] < 0 or coords[0] < 0 or coords[2] > SCREEN[0]:
remove_list.append(enum)
self.canvas.delete(bullet.bullet)
else:
bullet.move(self.canvas)
# NEW moving player
if self.keys_press.get('Left', False):
self.canvas.move(self.ship, -self.speed, 0)
if self.keys_press.get('Right', False):
self.canvas.move(self.ship, self.speed, 0)
if self.keys_press.get('Up', False):
self.canvas.move(self.ship, 0, -self.speed)
if self.keys_press.get('Down', False):
self.canvas.move(self.ship, 0, self.speed)
if self.keys_press.get('space', False):
if self.shoot_pauser.elaspe(self.ticks):
self.spread_pauser.update(self.ticks)
self.triple_pauser.update(self.ticks)
self.shoot()
if self.keys_press.get('b', False):
if self.spread_pauser.elaspe(self.ticks):
self.shoot_pauser.update(self.ticks)
self.triple_pauser.update(self.ticks)
self.spread_shot()
if self.keys_press.get('v', False):
if self.triple_pauser.elaspe(self.ticks):
self.shoot_pauser.update(self.ticks)
self.spread_pauser.update(self.ticks)
self.triple_shot()
# fix popping bug
for enum, index in enumerate(remove_list):
self.bullets.pop(index - enum)
# framerate per seconds 1000/30 = 30 frames roughly
self.ticks += 1
self.after(int(1000/30), self.tick_loop)
def go_press(self, event):
self.keys_press[event.keysym] = True
def go_release(self, event):
self.keys_press[event.keysym] = False
def shoot(self):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
# just having shoot straight up
self.bullets.append(Bullet(self.canvas, x, y, "blue", (0, -10)))
# spread shooting
def spread_shot(self):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "red", (0, -8)))
#left
self.bullets.append(Bullet(self.canvas, x, y, "red", (-8, 0)))
#right
self.bullets.append(Bullet(self.canvas, x, y, "red", (8, 0)))
# triple shot striaght up
def triple_shot(self):
# only want the first two coords
x, y = self.canvas.coords(self.ship)[:2]
#up
self.bullets.append(Bullet(self.canvas, x, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x - 50, y, "green", (0, -5)))
self.bullets.append(Bullet(self.canvas, x + 50, y, "green", (0, -5)))
def main():
root = tk.Tk()
app = App(root)
app.mainloop()
# __name__ only equals '__main__' if it is execute
# if import then it equals module name
if __name__ == '__main__':
main()
Thank you very mush Windspar
Iam sorry, I was busy last weeks
The last code is just perfect, and exactly what I was looking for, just pure code without pygame or any game library.
So making games with only tkinter and canvas is possible
I hope I can reach your level programming man
I worked on the background and the Land, but I don't know how to make it work simultaneously
I think I should use threading but I didn't find a good tutorial explains it easily .
I'll put the code sooner .
|