Currently I am trying to use commands to tell a turtle to draw the characters "S," "3," and "5" using the turtle module - without using the command turtle.write. Currently my code looks like:
import turtle
def halfcircle(parts=360, line=1, direction=1):
for x in range(parts//2):
turtle.forward(line)
turtle.left(360/parts * direction)
turtle.tracer(False)
for x in range(2):
halfcircle(20, 360/30, 1)
halfcircle(20, 360/30, -1)
turtle.update()
But the loop is never ending. Additionally, I am unable to incorporate linear and nonlinear lines into one character in order to draw a 5 or 3. Any help would be much appreciated.
Before I could actually check this out, I had to add an extra line of turtle.exitonclick() to the script to prevent it from disappearing from my screen as soon as I ran it.
From what I'm seeing, it doesn't appear to actually be never ending. The turtle draws four half-circle shapes then stops. When you say never ending, do you mean that it's repeating more than you wanted/expected? Or are you calling this code somewhere else and it's really never stopping in some other part?
If you just mean that it's drawing too many half-circles (4, when you want 2 to make an S), that's because of the 2 in your for-loop for x in range(2): that for-loop has two half-circles in it, so when the loop runs twice (because of range(2)), you get 2 * 2 = 4 half-circles. [BTW, as a convention, we generally use a single underscore _ to indicate "throw-away" variables. You'll see that the var x does not actually get used in your for-loop, it's just necessary to state some var for the for-loop syntax. A lot of Python programmers just write for _ in range(2) as a way of saying, "Don't pay attention to this var, it's not going to get used."]
So if you change the for-loop from range(2) to being range(1), you get a single pair of half-circles and the program halts on this image:
Which, admittedly, is not a great S shape, but it's getting there. In general, drawing symbols is hard. I think a really good S is probably the hardest one. I think the easiest might be a 5? The best approach to figuring out how to code symbols is to draw it very large and very carefully on graph paper, then break it down into its component parts. Let's use 5 as an example, working from bottom to top:
A curved section, maybe half-circle, maybe more like 2/3's of a circle, maybe more of an ellipse, kinda hard to be certain.
A straight line going (mostly) up (or maybe just a hair to the right)
A straight line going directly right, a little longer than the previous line
Then, with that series of motions in mind, create code to draw each piece on its own. Once you've done that, just have the turtle draw the first piece, then immediately draw the next, then the next. You'll have to figure out how to reset the turtle's direction between pieces, but other than that, you'll have a 5! It's not so much that you want to have nonlinear and linear segments together, as a single symbol is created by drawing one segment after another, and you just write code that draws the specific segment one at a time.
Related
I'm a human trying to make an animated musical keyboard type thing so keystrokes play noises and flash pretty colors on screen that make ape brain happy. I don't want to bore you too much, that's all you really need to know to get what's going on. I think? Let me know.
Point is, I want to make the rectangle that flashes colors on keypress, fade back to gray on key release. I figured I'd do this with time, having a list of colors, iterate through them in steps back to gray setting the rectangle's fill to each with canvas.itemconfig with a like 0.01-second delay after each step. But the rectangle behaves as it did before I added the flair: key-press, cyan, key-release, gray. No animation. I tried lengthening the steps to 1 second (looong, but on purpose to see if I was just missing something; the same cyan shade stuck for 4 steps' worth of time, it should have iterated), and setting the rectangle color in the final step to an ugly magenta. The magenta stuck obviously because I never bothered changing it until another keypress cyanned it again. So why aren't the shades iterating. Also, feel free to call your band The Iterating Shades.
My code, slimmed down as much as possible:
# Blah blah blah, setup, but here's the key release handler (The part *I think* that's messing crap up).
def key_release(e):
if (e.char == 'q'):
for i in ["#0088dd", "#005e99", "#002841", "#2e2e2e"]:
canvas.itemconfig(rect, fill=i)
time.sleep(0.04)
canvas.itemconfig(kaq, fill="gray20")
elif (e.char == 'e'):
for i in ["#ff9500", "#9e5d00", "#523000", "#2e2e2e"]:
canvas.itemconfig(rect, fill=i)
time.sleep(0.04)
canvas.itemconfig(kae, fill="gray20")
time.sleep(0.04)
There. Short(?) code, and I didn't blab on too long. All's well that ends well!
Got any ideas? Fixes? Solutions? Pitchforks to throw? Let me know, with a healthy amount of thanks from me to you. I hope this glitch is just not me being silly! Have a great day! And let me know too if you need more code-- but some people are big on Minimum Reproducible Examples, so I kept it short here.
Edit. The answer below does not work. Sorry Jason, not your fault!!
My new code looks like this, but does the same thing. I had to declare a global variable called blue_step and have the method reference it because I was having trouble figuring out how to use .after() with arguments ... but that's beside the point. Anyway:
# ...
def cycle_blue():
global blue_step, rect
canvas.itemconfig(rect, fill=["#0088dd", "#005e99", "#002841", "#2e2e2e"][blue_step])
# ...
def key_release(e):
global blue_step
blue_step = 0
if (e.char == 'q'):
# for i in ["#0088dd", "#005e99", "#002841", "#2e2e2e"]:
# canvas.itemconfig(rect, fill=i)
# time.sleep(0.04)
for i in range(0, 3):
canvas.after(400, cycle_blue)
blue_step += 1
# ...
Any help?
Previous thoughts
According to #jasonharper:
The only thing that time.sleep() accomplishes in a Tkinter program is to
lock up the GUI completely. Delays and event-driven programming don't get
along very well - the proper approach is to use .after() to schedule the
next step of your animation a little bit into the future, and then return to
the mainloop.
I'll try this method and update in a few days. It may not work, but I'll mark this correct until then. Thank you, #jasonharper.
Edit: I cannot mark correct for two days.
I want Python to kind of ignore a statement that is unlikely to be called in a function that is often called.
I do not have a formal education in programming, so please excuse my lackluster ability to desribe things. I will try to explain the concept by example.
Say I am writing a video game, first-person shooter, drawing 60 frames per second.
In the settings menu, the user can select whether or not to display the name of other players above their head. If they disable this, I store this value as showplayernames = False.
Then in my drawing function that outputs the graphics I have:
def draw():
#code that draws the graphics on screen
if showplayernames:
#code that draws the name of players on screen
I call this function 60 times a second, but there is absolutely no point for checking if showplayernames is True 60 times a second. It will not change that often, in fact I could make this a kind of "constant" during play by preventing it to change. If showplayernames is False, then the third and fourth lines of the code are completely redundant, but they are executed nevertheless. The computer isn't smart enough to know it can ignore it, and there is a performance difference: reading a value and then checking if it is false takes time.
I could write two copies of the game (or at least the draw() function), one with only the first two lines when the user selects not to show names in the settings, and another without the if statement, and then run the appropriate one.
def draw_with_names():
#code that draws the graphics on screen
#code that draws the name of players on screen
def draw_without_names():
#code that draws the graphics on screen
Although looping through either of these 60 times a second is more efficient than running draw() ,this is obviously not the way to go. There are dozens of settings like this.
So how do software and game designers implement these kind of "software-wide" settings efficiently?
I'm not a game developer, but here's one option. Create a list of function pointers and add or remove from the list based on settings. Example:
def draw_player_names():
# Code to overlay names
def draw_fps():
# Code to overlay fps
def draw():
# Main code to draw a frame of the game
# Hold all the functions to call
optional_funcs = []
if showplayernames: optional_funcs.append(draw_player_names)
if show_fps: optional_funcs.append(draw_fps)
# Main game loop
while True:
draw()
for f in optional_funcs: f()
This can be extended for any number of functions/options.
not an game designer, but here is my voice.
You could store settings inside json file next to you python, but then you need to cover reading, getting right values etc.
You could use Environment variables to store value but that would end up using still "if" in the code.
Game designers use triggers and events to get things done, and on the lowest level I would assume those things also use if's.
system-wide-settings will in the end be used with if's
You could use overwrites based on event/trigger and use "same" draw function in both times but that only complicates code, and we all know to "keep it simple".
Sorry if this is not the answer you were looking for.
As Matthias said, you shouldn't really bother about this kind of optimization. Look at these two very silly functions:
def lot_of_ifs(settings):
#do something
a=2**10
b=2**10
c=2**10
for setting in settings:
if setting:
#do something more
a=2**10
b=2**10
c=2**10
def no_ifs():
#do something
a=2**10
b=2**10
c=2**10
timeit("lot_of_ifs([0,0,0,0,0])", globals=globals())
0.2630380000000514
timeit("no_ifs()", globals=globals())
0.10232830000040849
The cost of creating a list, looping over it, and executing five ifs is about 0.16 seconds for one million iterations, or 160 nanoseconds per iteration, while at 60 fps you have 16.6 million nanoseconds to execute your code.
I have a python program using turtle to make the game "Snake". It is fully functional. At this point I'm adding in .gif images to spruce it up.
The problem arises when I'm trying to use a custom shape as the head of the snake. If I use a basic shape from turtle like "triangle" or "arrow" it works fine. It turns correctly and is printed over the first body segment as intended. When I change it to my custom image, the problem is that it is printed out under the first body segment and cannot turn.
Sample of controls
if direction == "up":
if snake_direction != "down":
snake_direction = "up"
head_stamper.setheading(90)
Stampers used to make numerous sections, and a head over the first segment.
for segment in snake:
stamper.goto(segment[0], segment[1]) #These are the body segments, they work fine.
stamper.stamp()
head_stamper.goto(new_head)
Showing both stampers here.
# Stamper for each body section
stamper = turtle.Turtle()
stamper.shape(bod_segment)
stamper.shapesize(25 / 20)
stamper.penup()
# Special stamper just for the snake's head.
head_stamper = turtle.Turtle()
# head_stamper has no issues when I make the shape "arrow" or "triangle", etc.
head_stamper.shape(head_segment)
stamper.shapesize(25 / 20)
head_stamper.penup()
I think this is all the code relevant to the problem.
When I change it to my custom image, the problem is that it is printed
out under the first body segment and cannot turn.
As far as not turning, this is addressed in the Python turtle documentation of register_shape() aka addshape():
Note: Image shapes do not rotate when turning the turtle, so they do
not display the heading of the turtle!
As far as the overlap problem, I can only guess. Generally the rule in turtle is the last thing that moved is on top. So turning your generic head shape lands it on top, but since your image shape doesn't actually turn, it winds up on the bottom. Again, just a guess.
I don't know what the right words are to ask my question, so please excuse the extra detail below. I am as much asking for the right words/concepts as for an answer to the specific question.
I'm trying to put a simple console in front of a script of mine using curses in Python. I want the console to look relatively familiar and have key shortcuts for 3 commands (Load, Exit, Continue). To highlight which key is the hotkey for an action, I wanted that letter to be in a different colour. (e.g. Exit with hotkey being the x). I figure this must be made up of 3 "addstr" commands- write the first letter in normal ("E"), then the x with a colour attribute, then "it" in normal colour again.
I thought that because I do this 3 times, and maybe more in future screens, I should make a function to do it for me to see if that works. What I can't figure out though, is how to edit the screen without hardcoding the function to the variable name. I want to be able to call the function in a number of different windows. I thought at first I could just pass the screen's variable into my function but that doesn't seem right.
Here is my pseudo code I started working on:
def keyString(menuString,fastChar,highlight,startX,startY,cScreen):
#menuString is the word that has a letter to bring to attention
#fastChar is the character that will be in a different colour
#highlight is binary value to determine which colour pair to use
#definition expects 'h' and 'n' to be colour pairs
#startX and startY are the beginning cursor positions
#cScreen would be global screen variable
fCidx = menuString.find(fastChar) #index of the character to highlight
fXadj = startX + fCidx #set the x position for character to highlight
sHx = fXadj + 1 #set the x position for the remainder of the string
fH = menuString[0:fCidx] #Slice the first half of the string
sH = menuString[(fCidx+1):] #slice the remainder of the string
if highlight:
txtColor = h
else:
txtColor = n
cScreen.addstr(startY,startX,fH,txtColor)
cScreen.addstr(startY,fXadj,fastChar)
cScreen.addstr(startY,sHx,sH,txtColor)
return cScreen
Please ignore the awful variable names..I was getting tired of typing and started shorthanding. I realise that I didn't need to worry about explicitly stating x,y coords because the cursor position is remembered. So a lot of that can be cut out. I'm not asking for someone to fix my function. I just don't have a concept of how to have a function that will write out a word using different colours for different characters. I could probably stick a "global screen" in the function and only use it for editing "screen", but then (for example) I wouldn't be able to use the function for "screen2".
If it helps anyone searching in the future, I found that I can use Windows (curses.newwin) and those can be fed into, and returned from functions.
So for example, if the above code was in a file called "curse_tools.py":
import curses
import curse_tools
def Main(screen):
curses.init_pair(1,curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(2,curses.COLOR_BLACK, curses.COLOR_GREEN)
n = curses.color_pair(1)
h = curses.color_pair(2)
curse_tools.n = n
curse_tools.h = h
try:
screen.border(0)
box1 = curses.newwin(20, 20, 5, 5)
box1.box()
box1=curse_tools.keyString("Exit","x",False,1,1,box1)
screen.refresh()
box1.refresh()
screen.getch()
finally:
curses.endwin()
curses.wrapper(Main)
This code would work. I'm going to re-write my original code because I learned a lot along the way but maybe a future beginner will somehow come across this question so I thought I'd post the 'solution'. Although I still don't know the right words.
Most of the code in this post came from Why won't my curses box draw? (in case it looks familiar)
Been struggling with this for a couple of days, hard to find code examples on the net.
I'm making a topdown game and having trouble getting the player to move on key press. At the moment i'm using add_force or add_impulse to move the player in a direction, but the player doesn't stop.
I've read about using surface friction between the space and the player to simulate friction and here is how it's done in the tank.c demo.
However I don't understand the API enough to port this code from chipmunk into pymunk.
cpConstraint *pivot = cpSpaceAddConstraint(space, cpPivotJointNew2(tankControlBody, tankBody, cpvzero, cpvzero));
So far, I have something that looks like this:
class Player(PhysicalObject):
BASE_SPEED = 5
VISIBLE_RANGE = 400
def __init__(self, image, position, world, movementType=None):
PhysicalObject.__init__(self, image, position, world)
self.mass = 100
self.CreateBody()
self.controlBody = pymunk.Body(pymunk.inf, pymunk.inf)
self.joint = pymunk.PivotJoint(self.body, self.controlBody, (0,0))
self.joint.max_force = 100
self.joint.bias_coef = 0
world.space.add(self.joint)
I don't know how to add the constraint of the space/player to the space.
(Need someone with 1500+ rep to create a pymunk tag for this question).
Joe crossposted the question to the Chipmunk/pymunk forum, and it got a couple of more answers there. http://www.slembcke.net/forums/viewtopic.php?f=1&t=1450&start=0&st=0&sk=t&sd=a
Ive pasted/edited in parts of my answer from the forum below:
#As pymunk is python and not C, the constructor to PivotJoint is defined as
def __init__(self, a, b, *args):
pass
#and the straight conversion from c to python is
pivot1 = PivotJoint(tankControlBody, tankBody, Vec2d.zero(), Vec2d.zero())
# but ofc it works equally well with 0 tuples instead of the zero() methods:
pivot2 = PivotJoint(tankControlBody, tankBody, (0,0), (0,0))
mySpace.add(pivot1, pivot2)
Depending on if you send in one or two arguments to args, it will either use the cpPivotJointNew or cpPivotJointNew2 method in the C interface to create the joint. The difference between these two methods is that cpPivotJointNew want one pivot point as argument, and the cpPivotJointNew2 want two anchor points. So, if you send in one Vec2d pymunk will use cpPivotJointNew, but if you send in two Vec2d it will use cpPivotJointNew2.
Full PivotJoint constructor documentation is here: PivotJoint constructor docs
I'm not familiar with either system you've mentioned, but some basic game ideas that may relate are:
If you add a force (or impulse) which affects movement, for the entity to stop, you must also take it away. In my games if I had a function AddImpulse()/AddForce() I would have a corresponding one such as Apply_Friction() which would reverse the effect by however much you want (based on terrain?) until movespeed is zero or less. I personally wouldn't bother with this method for movement unless needed for gameplay since it can add more computations that its worth each update.
There should be some way to track KeyPressed and/or KeyPosition and then using those x/y coordinates are incrememnted based on player speed. Without knowing what you've tried or how much the API does for you, it's hard to really say more.
Hope this helps. If this is stuff you already knew kindly ignore it.