Speed function doesn't change the turtles position regardless of any parameters I put in - turtle-graphics

The program I made has two turtles one being the user(player) and the other being player 2 which are run through a function called checkcollision which determines if the turtles intersect thus moving the second turtle to a random position of -250,250 for its x and y coordinates. The problem however is I want the second turtle(non user) to move in a straight line across the screen and I set it to 2 and I also tried setting it to normal and such all not making the turtle move.
import turtle
import random
wn = turtle.Screen()
wn.setup(width = 450, height = 450)
player = turtle.Turtle()
player2 = turtle.Turtle()
def up():
y = player.ycor()
y = y + 5
player.sety(y)
if y>=310:
player.sety(y-15)
checkcollision(player,player2)
def down():
y = player.ycor()
y = y - 5
player.sety(y)
if y<-310:
player.sety(y+15)
checkcollision(player,player2)
def left():
x = player.xcor()
x = x - 5
player.setx(x)
if x<=-625:
player.setx(x+15)
checkcollision(player,player2)
def right():
x = player.xcor()
x = x + 5
player.setx(x)
if x>=625:
player.setx(x-15)
checkcollision(player,player2)
player.penup()
player.setpos(0,0)
player.showturtle()
player.shape("square")
wn.bgcolor("green")
player2.shape("turtle")
player2.penup()
player2.setpos(300,300)
player2.showturtle()
player2.setheading(-100)
player2.speed(2)
turtle.listen()
turtle.onkeypress(up,"Up")
turtle.onkeypress(left,"Left")
turtle.onkeypress(right,"Right")
turtle.onkeypress(down, "Down")
def checkcollision(t1,t2):
if abs(t1.xcor() - t2.xcor()) < 10 and abs(t1.ycor() - t2.ycor()) < 10:
player2.setpos(random.randint(-250,250), random.randint(-250,250))
checkcollision(player,player2)

Your code has multiple problems and I'm surprised it runs at all as presented above. (It should just fall through the bottom of the code, close the turtle window and return to the console.) For example, it doesn't seem to understand it's own coordinate system -- the x coordinates go from -425 to +425 but we're testing if the turtle's x coordinate is <= -625. Below is my rework to address your question and these other issues:
from turtle import Screen, Turtle
from random import randint
def up():
y = player.ycor() + 5
if y < 200:
player.sety(y)
checkcollision()
def down():
y = player.ycor() - 5
if y > -200:
player.sety(y)
checkcollision()
def left():
x = player.xcor() - 5
if x > -200:
player.setx(x)
checkcollision()
def right():
x = player.xcor() + 5
if x < 200:
player.setx(x)
checkcollision()
def checkcollision():
if player.distance(player2) < 20:
player2.setpos(randint(-200, 200), randint(-200, 200))
screen = Screen()
screen.setup(width=450, height=450)
screen.bgcolor('green')
player = Turtle()
player.shape('square')
player.speed('fastest')
player.penup()
player2 = Turtle()
player2.shape('square')
player2.speed('slowest')
player2.color('yellow')
player2.penup()
checkcollision()
screen.onkeypress(up, 'Up')
screen.onkeypress(left, 'Left')
screen.onkeypress(right, 'Right')
screen.onkeypress(down, 'Down')
screen.listen()
screen.mainloop()

Related

How do I optimize this code so that it executes faster (max ~5 mins)?

I am trying to make a program in turtle that creates a Lyapunov fractal. However, as using timeit shows, this should take around 3 hours to complete, 1.5 if I compromise resolution (N).
import turtle as t; from math import log; from timeit import default_timer as dt
t.setup(2000,1000,0); swid=t.window_width(); shei=t.window_height(); t.up(); t.ht(); t.tracer(False); t.colormode(255); t.bgcolor('pink')
def lyapunov(seq,xmin,xmax,ymin,ymax,N,tico):
truseq=str(bin(seq))[2:]
for x in range(-swid//2+2,swid//2-2):
tx=(x*(xmax-xmin))/swid+(xmax+xmin)/2
if x==-swid//2+2:
startt=dt()
for y in range(-shei//2+11,shei//2-1):
t.goto(x,y); ty=(y*(ymax-ymin))/shei+(ymax+ymin)/2; lex=0; xn=prevxn=0.5
for n in range(1,N+1):
if truseq[n%len(truseq)]=='0': rn=tx
else: rn=ty
xn=rn*prevxn*(1-prevxn)
prevxn=xn
if xn!=1: lex+=(1/N)*log(abs(rn*(1-2*xn)))
if lex>0: t.pencolor(0,0,min(int(lex*tico),255))
else: t.pencolor(max(255+int(lex*tico),0),max(255+int(lex*tico),0),0)
t.dot(size=1); t.update()
if x==-swid//2+2:
endt=dt()
print(f'Estimated total time: {(endt-startt)*(swid-5)} secs')
#Example: lyapunov(2,2.0,4.0,2.0,4.0,10000,100)
I attempted to use yield but I couldn't figure out where it should go.
On my slower machine, I was only able to test with a tiny N (e.g. 10) but I was able to speed up the code about 350 times. (Though this will be clearly lower as N increases.) There are two problems with your use of update(). The first is you call it too often -- you should outdent it from the y loop to the x loop so it's only called once on each vertical pass. Second, the dot() operator forces an automatic update() so you get no advantage from using tracer(). Replace dot() with some other method of drawing a pixel and you'll get back the advantage of using tracer() and update(). (As long as you move update() out of innermost loop as I noted.)
My rework of your code where I tried out these, and other, changes:
from turtle import Screen, Turtle
from math import log
from timeit import default_timer
def lyapunov(seq, xmin, xmax, ymin, ymax, N, tico):
xdif = xmax - xmin
ydif = ymax - ymin
truseq = str(bin(seq))[2:]
for x in range(2 - swid_2, swid_2 - 2):
if x == 2 - swid_2:
startt = default_timer()
tx = x * xdif / swid + xdif/2
for y in range(11 - shei_2, shei_2 - 1):
ty = y * ydif / shei + ydif/2
lex = 0
xn = prevxn = 0.5
for n in range(1, N+1):
rn = tx if truseq[n % len(truseq)] == '0' else ty
xn = rn * prevxn * (1 - prevxn)
prevxn = xn
if xn != 1:
lex += 1/N * log(abs(rn * (1 - xn*2)))
if lex > 0:
turtle.pencolor(0, 0, min(int(lex * tico), 255))
else:
lex_tico = max(int(lex * tico) + 255, 0)
turtle.pencolor(lex_tico, lex_tico, 0)
turtle.goto(x, y)
turtle.pendown()
turtle.penup()
screen.update()
if x == 2 - swid_2:
endt = default_timer()
print(f'Estimated total time: {(endt - startt) * (swid - 5)} secs')
screen = Screen()
screen.setup(2000, 1000, startx=0)
screen.bgcolor('pink')
screen.colormode(255)
screen.tracer(False)
swid = screen.window_width()
shei = screen.window_height()
swid_2 = swid//2
shei_2 = shei//2
turtle = Turtle()
turtle.hideturtle()
turtle.penup()
turtle.setheading(90)
lyapunov(2, 2.0, 4.0, 2.0, 4.0, 10, 100)
screen.exitonclick()

I am trying to create an object AllBalls in my Playstate but when ever i try to initialize the object i get an error

In my playstatue I create an instance if my object as such
function PlayState:enter(params)
self.paddle = params.paddle
self.bricks = params.bricks
self.health = params.health
self.score = params.score
self.highScores = params.highScores
self.level = params.level
self.recoverPoints = 5000
self.extendPoints = 7000
-- give ball random starting velocity
self.inPlayBalls= AllBalls(params.ball)
self.inPlayBalls[1].dx = math.random(-200, 200)
self.inPlayBalls[1].dy = math.random(-50, -60)
end
the AllBalls class is a simple class which goes as such
AllBalls = Class{}
function AllBalls:init(p)
self.ball=p
self.inPlayBalls={self.ball}
end
function AllBalls:update(dt,target)
for k, ball in pairs(self.inPlayBalls) do
ball:update(dt)
if ball:collides(target) then
-- raise ball above paddle in case it goes below it, then reverse dy
ball.y = target.y - 8
ball.dy = -target.dy
--
-- tweak angle of bounce based on where it hits the paddle
--
-- if we hit the paddle on its left side while moving left...
if ball.x < target.x + (target.width / 2) and target.dx < 0 then
ball.dx = -50 + -(8 * (target.x + target.width / 2 - ball.x))
-- else if we hit the paddle on its right side while moving right...
elseif ball.x > target.x + (target.width / 2) and target.dx > 0 then
ball.dx = 50 + (8 * math.abs(target.x + target.width / 2 - ball.x))
end
gSounds['paddle-hit']:play()
end
if math.abs(ball.dy) < 150 then
ball.dy = ball.dy * 1.02
end
if ball.remove then
table.remove(self.AllBalls, k)
end
end
end
function AllBalls:collides(target)
for k, ball in pairs(self.inPlayBalls) do
if ball:collides(target) then
if ball.x + 2 < brick.x and ball.dx > 0 then
-- flip x velocity and reset position outside of brick
ball.dx = -ball.dx
ball.x = brick.x - 8
-- right edge; only check if we're moving left, , and offset the check by a couple of pixels
-- so that flush corner hits register as Y flips, not X flips
elseif ball.x + 6 > brick.x + brick.width and ball.dx < 0 then
-- flip x velocity and reset position outside of brick
ball.dx = -ball.dx
ball.x = brick.x + 32
-- top edge if no X collisions, always check
elseif ball.y < brick.y then
-- flip y velocity and reset position outside of brick
ball.dy = -ball.dy
ball.y = brick.y - 8
-- bottom edge if no X collisions or top collision, last possibility
else
-- flip y velocity and reset position outside of brick
ball.dy = -ball.dy
ball.y = brick.y + 16
end
end
end
end
function AllBalls:add(ball)
local newBall=Ball(ball.skin)
newBall.x=ball.x
newBall.dx=math.random(-200,200)
newBall.y=ball.y
newBall.dy=ball.dy
table.insert(self.inPlayBalls, newBall)
end
function AllBalls:out()
for k, ball in pairs(self.inPlayBalls) do
if ball.y >= VIRTUAL_HEIGHT then
ball.remove=true
end
end
end
when ever i enter the playstate I get the following error
src/states/PlayStatue.lua:37 attempt to index nil value
I am new to Lua as a whole and i probably made a silly mistake that i couldn't find so any help would be appricated
The problem likely comes from this assignment
self.inPlayBalls= AllBalls(params.ball)
From looking at your GitHub, inPlayBalls is an attribute of an AllBalls instance. That means you would have to create your AllBalls instance first, then get the attribute to assign it to a variable, such as in the following:
self.allBalls = AllBalls(params.ball)
self.inPlayBalls = self.allBalls.inPlayBalls

How to use bounding box in Love2d?

I've been using some extremely bulky code to detect collision between simple objects, and I've heard about bounding boxes. I can't find any tutorials on how to use it, so I'm asking about how to use it. Here is how I detect collision:
function platform.collision()
if player.x + player.width / 2 <= platform.x + platform.width and
player.x + player.width / 2 >= platform.x and
player.y + player.height <= platform.y + platform.height and
player.y + player.height >= platform.y then
The MDN has a rather concise article on 2D collision detection. Being the MDN, the examples are in javascript, but are easily translated to, and applicable in, any language - including Lua.
Let's take a look:
Axis-Aligned Bounding Box
One of the simpler forms of collision detection is between two rectangles that are axis aligned — meaning no rotation. The algorithm works by ensuring there is no gap between any of the 4 sides of the rectangles. Any gap means a collision does not exist.
Their example, translated to Lua:
local rect1 = { x = 5, y = 5, width = 50, height = 50 }
local rect2 = { x = 20, y = 10, width = 10, height = 10 }
if
rect1.x < rect2.x + rect2.width and
rect1.x + rect1.width > rect2.x and
rect1.y < rect2.y + rect2.height and
rect1.height + rect1.y > rect2.y
then
-- collision detected!
end
-- filling in the values =>
if
5 < 30 and
55 > 20 and
5 < 20 and
55 > 10
then
-- collision detected!
end
A live example, again in JavaScript, demonstrates this well.
Here's a quick (and imperfect) Love2D example you can throw into a main.lua and play around with.
local function rect (x, y, w, h, color)
return { x = x, y = y, width = w, height = h, color = color }
end
local function draw_rect (rect)
love.graphics.setColor(unpack(rect.color))
love.graphics.rectangle('fill', rect.x, rect.y,
rect.width, rect.height)
end
local function collides (one, two)
return (
one.x < two.x + two.width and
one.x + one.width > two.x and
one.y < two.y + two.height and
one.y + one.height > two.y
)
end
local kp = love.keyboard.isDown
local red = { 255, 0, 0, 255 }
local green = { 0, 255, 0, 255 }
local blue = { 0, 0, 255, 255 }
local dim1 = rect(5, 5, 50, 50, red)
local dim2 = rect(20, 10, 60, 40, green)
function love.update ()
if kp('up') then
dim2.y = dim2.y - 1
end
if kp('down') then
dim2.y = dim2.y + 1
end
if kp('left') then
dim2.x = dim2.x - 1
end
if kp('right') then
dim2.x = dim2.x + 1
end
dim2.color = collides(dim1, dim2) and green or blue
end
function love.draw ()
draw_rect(dim1)
draw_rect(dim2)
end
Oka explained it very well. This works for everything rectangular, not rotated and axis aligned. And you even already did it that way. This is great for buttons and the like!
But what I like doing is using (invisible) circles around objects and see if these collide. This works for everything where height is about the same as the width (which is the case for many sidescrolling platformers or top-down RPGs).
It's quite handy if you want to have the object centered at the current position. And it's especially helpful to simulate a finger on a touchscreen device, because a finger is quite a bit bigger than a mouse cursor. ;)
Here's an example on how to use this method. You can copy it as an actual game, it'll work.
--[[ Some initial default settings. ]]
function love.load()
settings = {
mouseHitbox = 5, -- A diameter around the mouse cursor.
-- For a finger (thouchscreen) this could be bigger!
}
objects = {
[1] = {
x = 250, -- Initial X position of object.
y = 200, -- Initial Y position of object.
hitbox = 100, -- A diameter around the CENTER of the object.
isHit = false -- A flag for when the object has been hit.
},
[2] = {
x = 400,
y = 250,
hitbox = 250,
isHit = false
}
}
end
--[[ This is the actual function to detect collision between two objects. ]]
function collisionDetected(x1,y1,x2,y2,d1,d2)
-- Uses the x and y coordinates of two different points along with a diameter around them.
-- As long as these two diameters collide/overlap, this function returns true!
-- If d1 and/or d2 is missing, use the a default diameter of 1 instead.
local d1 = d1 or 1
local d2 = d2 or 1
local delta_x = x2 - x1
local delta_y = y2 - y1
local delta_d = (d1 / 2) + (d2 / 2)
if ( delta_x^2 + delta_y^2 < delta_d^2 ) then
return true
end
end
--[[ Now, some LÖVE functions to give the collisionDetection() some context. ]]
function love.draw()
for i=1,#objects do -- Loop through all objects and draw them.
if ( objects[i].isHit ) then
love.graphics.setColor(255, 0, 0) -- If an object is hit, it will flash red for a frame.
objects[i].isHit = false
else
love.graphics.setColor(255, 255, 255)
end
love.graphics.circle("line", objects[i].x, objects[i].y, objects[i].hitbox/2)
end
end
-- You can use the following to check, if any object has been clicked on (or tapped on a touch screen device).
function love.mousepressed(x,y,button)
if ( button == 1 ) then
local i = objectIsHit(x,y) -- Check, if an object has been hit.
if ( i ) then
-- The object number 'i' has been hit. Do something with this information!
objects[i].isHit = true
end
end
end
function objectIsHit(x,y)
for i=1,#objects do -- Loop through all objects and see, if one of them has been hit.
if ( collisionDetected(x, y, objects[i].x, objects[i].y, settings.mouseHitbox, objects[i].hitbox) ) then
return i -- This object has been hit!
end
end
end
-- For the sake of completeness: You can use something like the following to check, if the objects themselves collide.
-- This would come in handy, if the objects would move around the screen and then bounce from each other, for example.
function love.update(dt)
if ( collisionDetected(objects[1].x, objects[1].y, objects[2].x, objects[2].y, objects[1].hitbox, objects[2].hitbox) ) then
-- The objects collided. Do something with this information!
end
end
As you can see, the collisionDetection() function is quite easy and intuitive to use.
Hopefully I could give you some more insight. And have fun with LÖVE 2D! :)

Love2d drawing grid and manipulating it i have few problems

Hello i made grid code but it doesn't look like how i wanted to, i want to to be will look like down there i tried a lot but i wasn't able to find right formula to do that
Here is my code
function love.load()
num = 32-- how many cell are going to be in each axis
w = 20
h = 20
color = {128, 128, 128}
backgroundcolor = {192, 192, 192}
end
function love.update(dt)
end
function love.draw()
for y = 1, num do
for x = 1, num do
if (x + y)%2 == 0 then
love.graphics.setColor(unpack(color))
else
love.graphics.setColor(unpack(backgroundcolor))
end
love.graphics.rectangle("fill", (x - 1)*w ,(y - 1)*h, w, h)
end
end
end
Result:
I want to achieve this each cell is 16 x 16.
Note: I don't want to use 2 x 2 cell i need 32 x 32 of them that is the problem i am facing right now.

Lua Separation Steering algorithm groups overlapping rooms into one corner

I'm trying to implement a dungeon generation algorithm (presented here and demo-ed here ) that involves generating a random number of cells that overlap each other. The cells then are pushed apart/separated and then connected. Now, the original poster/author described that he is using a Separation Steering Algorithm in order to uniformly distribute the cells over an area. I haven't had much experience with flocking algorithm and/or separation steering behavior, thus I turned to google for an explanation (and found this ). My implementation (based on the article last mentioned) is as follows:
function pdg:_computeSeparation(_agent)
local neighbours = 0
local rtWidth = #self._rooms
local v =
{
x = self._rooms[_agent].startX,
y = self._rooms[_agent].startY,
--velocity = 1,
}
for i = 1, rtWidth do
if _agent ~= i then
local distance = math.dist(self._rooms[_agent].startX,
self._rooms[_agent].startY,
self._rooms[i].startX,
self._rooms[i].startY)
if distance < 12 then
--print("Separating agent: ".._agent.." from agent: "..i.."")
v.x = (v.x + self._rooms[_agent].startX - self._rooms[i].startX) * distance
v.y = (v.y + self._rooms[_agent].startY - self._rooms[i].startY) * distance
neighbours = neighbours + 1
end
end
end
if neighbours == 0 then
return v
else
v.x = v.x / neighbours
v.y = v.y / neighbours
v.x = v.x * -1
v.y = v.y * -1
pdg:_normalize(v, 1)
return v
end
end
self._rooms is a table that contains the original X and Y position of the Room in the grid, along with it's width and height (endX, endY).
The problem is that, instead of tiddly arranging the cells on the grid, it takes the overlapping cells and moves them into an area that goes from 1,1 to distance+2, distance+2 (as seen in my video [youtube])
I'm trying to understand why this is happening.
In case it's needed, here I parse the grid table, separate and fill the cells after the separation:
function pdg:separate( )
if #self._rooms > 0 then
--print("NR ROOMS: "..#self._rooms.."")
-- reset the map to empty
for x = 1, self._pdgMapWidth do
for y = 1, self._pdgMapHeight do
self._pdgMap[x][y] = 4
end
end
-- now, we separate the rooms
local numRooms = #self._rooms
for i = 1, numRooms do
local v = pdg:_computeSeparation(i)
--we adjust the x and y positions of the items in the room table
self._rooms[i].startX = v.x
self._rooms[i].startY = v.y
--self._rooms[i].endX = v.x + self._rooms[i].endX
--self._rooms[i].endY = v.y + self._rooms[i].endY
end
-- we render them again
for i = 1, numRooms do
local px = math.abs( math.floor(self._rooms[i].startX) )
local py = math.abs( math.floor(self._rooms[i].startY) )
for k = self.rectMinWidth, self._rooms[i].endX do
for v = self.rectMinHeight, self._rooms[i].endY do
print("PX IS AT: "..px.." and k is: "..k.." and their sum is: "..px+k.."")
print("PY IS AT: "..py.." and v is: "..v.." and their sum is: "..py+v.."")
if k == self.rectMinWidth or
v == self.rectMinHeight or
k == self._rooms[i].endX or
v == self._rooms[i].endY then
self._pdgMap[px+k][py+v] = 1
else
self._pdgMap[px+k][py+v] = 2
end
end
end
end
end
I have implemented this generation algorithm as well, and I came across more or less the same issue. All of my rectangles ended up in the topleft corner.
My problem was that I was normalizing velocity vectors with zero length. If you normalize those, you divide by zero, resulting in NaN.
You can fix this by simply performing a check whether your velocity's length is zero before using it in any further calculations.
I hope this helps!
Uhm I know it's an old question, but I noticed something and maybe it can be useful to somebody, so...
I think there's a problem here:
v.x = (v.x + self._rooms[_agent].startX - self._rooms[i].startX) * distance
v.y = (v.y + self._rooms[_agent].startY - self._rooms[i].startY) * distance
Why do you multiply these equations by the distance?
"(self._rooms[_agent].startX - self._rooms[i].startX)" already contains the (squared) distance!
Plus, multiplying everything by "distance" you modify your previous results stored in v!
If at least you put the "v.x" outside the bracket, the result would just be higher, the normalize function will fix it. Although that's some useless calculation...
By the way I'm pretty sure the code should be like:
v.x = v.x + (self._rooms[_agent].startX - self._rooms[i].startX)
v.y = v.y + (self._rooms[_agent].startY - self._rooms[i].startY)
I'll make an example. Imagine you have your main agent in (0,0) and three neighbours in (0,-2), (-2,0) and (0,2). A separation steering behaviour would move the main agent toward the X axis, at a normalized direction of (1,0).
Let's focus only on the Y component of the result vector.
The math should be something like this:
--Iteration 1
v.y = 0 + ( 0 + 2 )
--Iteration 2
v.y = 2 + ( 0 - 0 )
--Iteration 3
v.y = 2 + ( 0 - 2 )
--Result
v.y = 0
Which is consistent with our theory.
This is what your code do:
(note that the distance is always 2)
--Iteration 1
v.y = ( 0 + 0 + 2 ) * 2
--Iteration 2
v.y = ( 4 + 0 - 0 ) * 2
--Iteration 3
v.y = ( 8 + 0 - 2 ) * 2
--Result
v.y = 12
And if I got the separation steering behaviour right this can't be correct.

Resources