Reputation:
I'm new to Python and I need some help. How do I make it so a function executes after 2 or more key presses? I'm trying to make a game using turtle similar to Minicraft (a 2D top-down action game) where you can use materials you get from stone and wood to craft a variety of different items. The code isn't finished yet.
Code I need help with:
stone = turtle.Turtle()
stone.shape("circle")
stone.color("gray")
stone.penup()
stone.setposition(-220, 180)
stone.shapesize(stretch_wid=2, stretch_len=3)
def stonebreak():
stone = turtle.Turtle ()
stone.shape ("circle")
stone.color ("gray")
stone.penup ()
stone.setposition (-220, 180)
stone.shapesize (stretch_wid=2, stretch_len=3)
stone.speed("slow")
stone.hideturtle()
stone = 0
stone += 9
stonestring = "Stone: %s" % stone
penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
penstone1.clear()
penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
if isCollision(player, stone):
wn.onkeypress(stonebreak, "space")
stone.hideturtle()
Full code:
import turtle
import random
import math
import time
turtle.tracer(5)
score = 0
# Turtles
wn = turtle.Screen()
wn.tracer(0)
wn.bgcolor("black")
wn.title("Catcher")
wn.setup(800, 600)
penwood1 = turtle.Turtle()
penwood1.penup()
penwood1.color("white")
penwood1.hideturtle()
penwood1.goto(-280, 275)
wood = 0
woodstring = "Wood: %s" %wood
penwood1.write(woodstring, False, align ="left", font = ("system", 15, "normal"))
penstone1 = turtle.Turtle()
penstone1.penup()
penstone1.color("white")
penstone1.hideturtle()
penstone1.goto(-200, 275)
stone = 0
stonestring = "Stone: %s" %stone
penstone1.write(stonestring, False, align ="left", font = ("system", 15, "normal"))
player = turtle. Turtle()
player.hideturtle()
player.color("white")
player.shape("triangle")
player.penup()
player.setheading(180)
player.setposition(180, 0)
player.showturtle()
player.penup()
player.speed(0)
pen = turtle.Turtle()
pen.color("white")
pen.shape("circle")
pen.hideturtle()
pen.penup()
pen.setposition(360, 275)
pen.pendown()
pen.setposition(360, -275)
pen.setposition(-360, -275)
pen.setposition(-360, 275)
pen.setposition(360, 275)
pen.shapesize(stretch_wid=3, stretch_len=3)
pen1 = turtle.Turtle()
pen1.color("white")
pen1.shape("circle")
pen1.hideturtle()
pen1.penup()
pen1.goto(-360, 275)
scorestring = "Score: %s" %score
pen1.write(scorestring, False, align = "left", font = ("system", 15, "normal"))
tree = turtle.Turtle()
tree.shape("circle")
tree.color("green")
tree.penup()
tree.setposition(200, 140)
stone1 = turtle.Turtle ()
stone1.shape ("circle")
stone1.color ("gray")
stone1.penup ()
stone1.setposition (-200, 140)
stone1.shapesize (stretch_wid=2, stretch_len=3)
stone1.speed ("slow")
stone = turtle.Turtle()
stone.shape("circle")
stone.color("gray")
stone.penup()
stone.setposition(-220, 180)
stone.shapesize(stretch_wid=2, stretch_len=3)
# ______________________________________________________
treedown = turtle.Turtle()
treedown.shape("circle")
treedown.color("green")
treedown.penup()
treedown.setposition(-250, -140)
# Movement features
def pleft():
player.setheading(180)
x = player.xcor()
x -= 20
if x < -360:
x = - 360
player.setx(x)
def pright():
player.setheading(0)
x = player.xcor()
x += 20
if x > 360:
x = + 360
player.setx(x)
def pdown():
player.setheading(270)
y = player.ycor()
y -= 20
if y < -275:
y = - 275
player.sety(y)
def pup():
player.setheading(90)
y = player.ycor()
y += 20
if y > 275:
y = + 275
player.sety(y)
wn.listen()
wn.onkeypress(pleft, "Left")
wn.onkeypress(pright, "Right")
wn.onkeypress(pup, "Up")
wn.onkeypress(pdown, "Down")
while True:
wn.update()
def treebreak():
tree.speed("slow")
tree.hideturtle()
wood = 0
wood += 2
woodstring = "Wood: %s" % wood
penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))
penwood1.clear()
penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))
def treebbreak():
treedown.speed ("slow")
treedown.hideturtle ()
wood = 2
wood += 3
woodstring = "Wood: %s" % wood
penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))
penwood1.clear ()
penwood1.write (woodstring, False, align="left", font=("system", 15, "normal"))
if player.xcor () == -240 and player.ycor () == -140:
wn.onkeypress (treebbreak, "space")
if player.xcor() == 180 and player.ycor() == 140:
wn.onkeypress(treebreak, "space")
if player.xcor() == 200 and player.ycor() == 120:
wn.onkeypress(treebreak, "space")
if player.xcor() == 200 and player.ycor() == 160:
wn.onkeypress(treebreak, "space")
if player.xcor() == 221 and player.ycor() == 141:
wn.onkeypress(treebreak, "space")
def isCollision(t1, t2):
distance = math.sqrt(math.pow(t1.xcor()-t2.xcor(),2)+math.pow(t1.ycor()-t2.ycor(),2))
if distance < 25:
return True
else:
return False
def stonebreak():
stone = turtle.Turtle ()
stone.shape ("circle")
stone.color ("gray")
stone.penup ()
stone.setposition (-220, 180)
stone.shapesize (stretch_wid=2, stretch_len=3)
stone.speed("slow")
stone.hideturtle()
stone = 0
stone += 9
stonestring = "Stone: %s" % stone
penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
penstone1.clear()
penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
if isCollision(player, stone):
wn.onkeypress(stonebreak, "space")
stone.hideturtle()
def stone1break():
stone1 = turtle.Turtle ()
stone1.shape ("circle")
stone1.color ("gray")
stone1.penup ()
stone1.setposition (-200, 140)
stone1.shapesize (stretch_wid=2, stretch_len=3)
stone1.speed("slow")
stone1.hideturtle()
stone = 0
stone += 9
stonestring = "Stone: %s" % stone
penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
penstone1.clear()
penstone1.write (stonestring, False, align="left", font=("system", 15, "normal"))
if isCollision(player, stone1):
wn.onkeypress(stone1break, "space")
stone1.hideturtle()
wn.mainloop()
I'm trying to make it so you gain the materials after 2 or more hits on the targets.
Upvotes: 1
Views: 163
Reputation: 163
First of all, you shouldn't set onkeypress() event handler every time collision occurs. Try to handle it other way:
def checkCollisions():
if isCollision(player, stone1):
stone1break()
if isCollision(player, stone2):
stone2break()
...
wn.onkeypress(checkCollisions, "space")
This code and all of your function defs you should put before your main (while True:
) loop.
Then, you will need some state of your game objects. Trivial way is to add variables stone1strength=2, stone2strength=2, ..., and decrease them in coresponding stonebreak() function, clearing the stone after its strength goes below 1.
I like your effort very much. It reminds me my first game programming steps. :)
The next step could be rewriting of your code to store your stone objects into a list and iterate them instead of handling tens of stoneX variables...
Upvotes: 2
Reputation: 41905
First, I don't see a problem with setting the onkeypress()
handler every time a collision is detected. Second, your code is a mess! For example, you have two unrelated global variables with the same name, stone
the score value and stone
the turtle:
stone = 0
# ...
stone = turtle.Turtle()
You shape
and shapesize()
the pen
turtle which is never visible anyway. And what's going on here:
wood = 2
wood += 3
which happens multiple times, keeping your scores at fixed values rather than increasing. Trying to detect a turtle on an exact position is futile:
if player.xcor() == 180 and player.ycor() == 140:
As the player moves 20 pixels at a time and this is a floating point plane. And turtle has a distance()
method, no reason to reinvent it.
I believe @BoboDarph's state machine suggestion is a good one. Below is my rework, and simplification, of your code that does something simpler. The first time you touch the stone or the tree, it just changes color. After that, you start to earn points:
from turtle import Screen, Turtle
FONT = ('system', 15, 'normal')
# Movement features
def player_left():
player.setheading(180)
x = player.xcor() - 20
if x < -360:
x = -360
player.setx(x)
def player_right():
player.setheading(0)
x = player.xcor() + 20
if x > 360:
x = + 360
player.setx(x)
def player_down():
player.setheading(270)
y = player.ycor() - 20
if y < -275:
y = - 275
player.sety(y)
def player_up():
player.setheading(90)
y = player.ycor() + 20
if y > 275:
y = + 275
player.sety(y)
def isCollision(t1, t2):
return t1.distance(t2) < 25
def tree_touch():
tree.color('dark green')
tree.touched = True
def tree_break():
global wood
screen.onkeypress(None, 'space')
tree.color('brown')
wood += 2
woodstring = "Wood: %s" % wood
pen_wood.clear()
pen_wood.write(woodstring, align='left', font=FONT)
def stone_touch():
rock.color('gray')
rock.touched = True
def stone_break():
global stone
screen.onkeypress(None, 'space')
rock.color('light gray')
stone += 9
stonestring = "Stone: %s" % stone
pen_stone.clear()
pen_stone.write(stonestring, align='left', font=FONT)
# Turtles
screen = Screen()
screen.setup(800, 600)
screen.bgcolor('black')
screen.title("Catcher")
screen.tracer(0)
pen_wood = Turtle()
pen_wood.hideturtle()
pen_wood.color('white')
pen_wood.penup()
pen_wood.goto(-280, 275)
wood = 0
wood_string = "Wood: %s" %wood
pen_wood.write(wood_string, align='left', font=FONT)
pen_stone = Turtle()
pen_stone.hideturtle()
pen_stone.color('white')
pen_stone.penup()
pen_stone.goto(-200, 275)
stone = 0
stone_string = "Stone: %s" %stone
pen_stone.write(stone_string, align='left', font=FONT)
pen = Turtle()
pen.hideturtle()
pen.shape('circle')
pen.color('white')
pen.penup()
pen.setposition(360, 275)
pen.pendown()
pen.setposition(360, -275)
pen.setposition(-360, -275)
pen.setposition(-360, 275)
pen.setposition(360, 275)
rock = Turtle()
rock.shape('circle')
rock.color('dark gray')
rock.penup()
rock.setposition(-220, 180)
rock.shapesize(stretch_wid=2, stretch_len=3)
rock.touched = False
tree = Turtle()
tree.shape('circle')
tree.color('green')
tree.penup()
tree.setposition(200, 140)
tree.touched = False
player = Turtle()
player.hideturtle()
player.shape('triangle')
player.speed('fastest')
player.color('white')
player.setheading(180)
player.penup()
player.setx(180)
player.showturtle()
screen.onkeypress(player_left, 'Left')
screen.onkeypress(player_right, 'Right')
screen.onkeypress(player_up, 'Up')
screen.onkeypress(player_down, 'Down')
screen.listen()
while True:
if isCollision(player, tree):
if tree.touched:
screen.onkeypress(tree_break, "space")
else:
screen.onkeypress(tree_touch, "space")
elif isCollision(player, rock):
if rock.touched:
screen.onkeypress(stone_break, "space")
else:
screen.onkeypress(stone_touch, "space")
else:
screen.onkeypress(None, "space")
screen.update()
screen.mainloop() # never reached
TODO
Gracefully incorporate multiple trees and stones.
Change the fixed value 25
in isCollision()
to a value calculated
based on the shapesize()
of the object.
Replace the while True:
loop with a function and timed event.
Upvotes: 0