enemy collision in ursina - python

i'm making a game in ursina and want to know how i can output something that says its true or false(like in a boolean). because the game that i am making needs collision with entity's. i have looked for a solution but i can't find anything. so people that use ursina please help me here is the code:
from ursina import *
import random
#variables
speed = 0.05
number_of_pokemon = 10
app = Ursina()
#textures
player_texture = load_texture('pokemon orange assets/player.png')
pokemon_texture1 = load_texture('pokemon orange assets/pokemon.png')
pokemon_texture2 = load_texture('pokemon orange assets/pokemon2.png')
pokemon_texture3 = load_texture('pokemon orange assets/pokemon3.png')
grass_texture = load_texture('pokemon orange assets/grass.png')
textbox_texture = load_texture('pokemon orange assets/textbox.png')
missingno_texture = load_texture('pokemon orange assets/missingno.png')
pokemontextures = [pokemon_texture1, pokemon_texture2, pokemon_texture3]
#entitys: pokemon(s), player, textbox, battles
player = Entity(model = 'cube', texture = player_texture, scale = (1,1,0), position =
(0,0,-0.1))
#textbox = Entity(model ='cube', texture = textbox_texture, scale = (5,1,0), position =
(0,-3,0))
#spawns pokemon
number = random.uniform(0,100)
if(number == 100):
for i in range (100):
pokemon = Entity(model ='cube', texture = missingno_texture, scale = (1,2,0),
position = (random.uniform(-10,10),random.uniform(-10,10),random.uniform(-10,10)))
else:
for i in range(number_of_pokemon):
pokemon = Entity(model ='cube', texture = random.choice(pokemontextures), scale = (1.5,1.5,0), position = (random.uniform(-5,5),random.uniform(-4,4),-0.1))
#spawns grass
for y in range(20):
for x in range(20):
grass = Entity(model ='cube', texture = grass_texture, scale = (1,1,0), position = (x - 10,y - 10,0))
#movement
def update():
player.x += held_keys['d'] * speed
player.x -= held_keys['a'] * speed
player.y += held_keys['w'] * speed
player.y -= held_keys['s'] * speed
app.run()

Set a Collider and check if your entity intersects with another one:
player = Entity(model='cube',
texture=player_texture,
scale=(1, 1, 0),
position=(0, 0, -0.1),
collider='box') # <-- do the same for all pokemon entities
hit_info = player.intersects()
if hit_info.hit:
print(hit_info.entity)

Related

How can I restart the game by pressing "r"?

My plans are to restart the game / reset the character to the middle of the map.
import keyboard as kb
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
app = Ursina()
window.fps_counter.enabled = False
player = FirstPersonController()
Sky()
boxes = []
def random_color():
red = random.Random().random() * 20
green = random.Random().random() * 255
blue = random.Random().random() * 20
return color.rgb(red, green, blue)
def add_box(position):
boxes.append(
Button(
parent=scene,
model='cube',
origin=0.5,
color=random_color(),
position=position,
texture='grass'
)
)
for x in range(20):
for y in range(20):
add_box( (x, 0, y) )
def input(key):
for box in boxes:
if box.hovered:
if key == "right mouse down":
add_box(box.position + mouse.normal)
if key == "left mouse down":
boxes.remove(box)
destroy(box)
if kb.is_pressed("escape"):
exit()
if kb.is_pressed("shift"):
player.speed = 15
else:
player.speed = 7
app.run()
I canĀ“t find help for this issue in the whole world of the internet. Please help me.
What do you mean with reset? Reset the hole game or just the player position?
To reset player position you can do something like this:
from ursina import *
app = Ursina()
# Change this to whatever your player is. In your case First person controller
player = Entity(model = 'cube')
player_reset_position = (0,0,0)
def input(key):
if key == 'r':
player.position = player_reset_position
app.run()
Your code with some fixes:
from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
app = Ursina()
window.fps_counter.enabled = False
player = FirstPersonController()
Sky()
boxes = []
def random_color():
red = random.Random().random() * 20
green = random.Random().random() * 255
blue = random.Random().random() * 20
return color.rgb(red, green, blue)
def add_box(position):
boxes.append(
Button(
parent=scene,
model='cube',
origin=0.5,
color=random_color(),
position=position,
texture='grass'
)
)
for x in range(20):
for y in range(20):
add_box((x, 0, y))
player_reset_position = (5,10,5)
def input(key):
for box in boxes:
if box.hovered:
if key == "right mouse down":
add_box(box.position + mouse.normal)
if key == "left mouse down":
boxes.remove(box)
destroy(box)
if key == ("escape"):
exit()
if key == ("shift"):
player.speed = 15
else:
player.speed = 7
if key == 'r':
player.position = player_reset_position
app.run()
I have changed indentation and your input function where you had if kb.is_pressed("escape"): to if key == "escape":

Pygame images glitching + appearing in corner. May be RECT issue? [duplicate]

This question already has an answer here:
How can I move the ball instead of leaving a trail all over the screen in pygame?
(1 answer)
Closed 6 months ago.
Making a simple game that runs itself with ducks eating bread. It works fine but the images "glitch" or blit all over the screen, i have narrowed it down to: whenever a bread is "eaten" a new bread appears and blits all over the screen before settling down
Code in question:
for BreadPos in breadxy:
if (((Ducky.xpos - BreadPos[0]) + (Ducky.ypos - BreadPos[1]))) > -5:
del FoodList[breadxy.index(BreadPos)]
Ducky.hunger += 60
FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
#this line here is supposed to be indented properly but i am seemingly bad at this stack overflow thing.
Here is my code in its entirety:
import pygame
import pygame, sys
from pygame.locals import *
import random
def main():
pygame.init()
(width,height) = (640,640)
clock = pygame.time.Clock()
DISPLAY = pygame.display.set_mode((width,height))
blue= (0,60,200)
DISPLAY.fill(blue)
#pictures and spirtes
DuckPic = pygame.image.load("Duck Sprite.jpg")
DuckPic = pygame.transform.scale(DuckPic, (128, 72))
BreadPic = pygame.image.load("breadpic.jpg")
BreadPic = pygame.transform.scale(BreadPic, (128, 72))
class Food(pygame.sprite.Sprite):
def __init__(self, xpos,ypos):
super().__init__()
self.xpos = xpos
self.ypos = ypos
self.image = BreadPic
self.rect = self.image.get_rect()
FoodList = []
for i in range (10):
FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
class Duck(pygame.sprite.Sprite):
def __init__(self,xpos,ypos,speed,hunger,movement):
super().__init__()
self.xpos = xpos
self.ypos = ypos
self.image = DuckPic
self.rect = self.image.get_rect()
self.speed = speed
self.hunger = hunger
self.movement = movement
Ducks = []
for i in range(1):
Ducks.append(Duck(xpos = random.randint(0, 320), ypos = random.randint(0, 320), speed =(random.randint(1,3)), hunger = 1000, movement = random.randint(1,100)))
###------------ GAME STUFF INSTANCES HAPPENING
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if FoodList == []:
print("ducks ate all the bread")
pygame.quit()
sys.exit()
if Ducks == []:
print("all ducks died")
pygame.quit()
sys.exit()
#display screen then food then ducks
DISPLAY.fill(blue)
breadxy = []
#gets xy pos of all food items
for i,FoodItem, in enumerate(FoodList):
xyList = [FoodItem.xpos , FoodItem.ypos]
breadxy.append(xyList)
for i,Ducky in enumerate(Ducks):
closestlist = [] #reset list of closest breads for all ducks
for count,j in enumerate(breadxy):
closestlist.append(((Ducky.xpos - j[0]) + (Ducky.ypos - j[1])))
#closest list shows a value of how close a duck is to the bread
#where 0 or -1 = best score
indexofBread = closestlist.index(max(closestlist))
print(f"I'm moving to bread {indexofBread} with value of {max(closestlist)} which is at {FoodList[indexofBread].xpos,FoodList[indexofBread].ypos}, my postion is {Ducky.xpos, Ducky.ypos} other values include = {closestlist}")
if True:
#move duck to closest bread
if Ducky.xpos < FoodList[indexofBread].xpos:
Ducky.xpos += 1 * Ducky.speed
if Ducky.xpos > FoodList[indexofBread].xpos:
Ducky.xpos -= 1 * Ducky.speed
if Ducky.ypos > FoodList[indexofBread].ypos:
Ducky.ypos -= 1 * Ducky.speed
if Ducky.ypos< FoodList[indexofBread].ypos:
Ducky.ypos += 1 * Ducky.speed
Ducky.hunger = Ducky.hunger - 1*Ducky.speed
#duck hunger goes down, faster duck looses more hunger
if Ducky.hunger < 0: #if duck at 0 hunger he dies :(
del Ducks[i]
#display the bread
#check for collision thorugh seeing if score is good
for BreadPos in breadxy:
if (((Ducky.xpos - BreadPos[0]) + (Ducky.ypos - BreadPos[1]))) > -5:
del FoodList[breadxy.index(BreadPos)]
Ducky.hunger += 60
FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
#print(len(FoodList))
#print(Ducky.hunger)
for FoodItem in (FoodList):
DISPLAY.blit(FoodItem.image, (FoodItem.xpos, FoodItem.ypos))
#DISPLAY DUCK
DISPLAY.blit(Ducky.image, (Ducky.xpos, Ducky.ypos))
pygame.display.update()
#make the screen
main()
So it looks like the issue is the tracking of the FoodList index via the breadxy list.
The breadxy tracking is an index into FoodList, so the bread that was eaten can be removed from the list. But as soon as the breads are removed, the indexes into the list are no longer correct. The "eating" loop doesn't stop checking after an item is consumed, so theoretically this loop can be repeated multiple times. After the first del(), no index is valid. Sometimes it will crash because the index could be more than the new (shorted) length of the list.
I couldn't work out the distance algorithm!? So I substituted it with a member function on Duck that calculates the Euclidian Distance (straight line distance).
This code seems to work OK. I modified your sprites to use the rect item, rather than relying on xpos and ypos.
#! /usr/bin/env python3
import pygame
import pygame, sys
from pygame.locals import *
import math
import random
def main():
pygame.init()
(width,height) = (640,640)
clock = pygame.time.Clock()
DISPLAY = pygame.display.set_mode((width,height))
blue= (0,60,200)
DISPLAY.fill(blue)
#pictures and spirtes
DuckPic = pygame.image.load("Duck Sprite.png").convert_alpha()
DuckPic = pygame.transform.smoothscale( DuckPic, (128, 72))
BreadPic = pygame.image.load("breadpic.png").convert_alpha()
BreadPic = pygame.transform.smoothscale(BreadPic, (128, 72))
class Food(pygame.sprite.Sprite):
def __init__(self, xpos,ypos):
super().__init__()
self.image = BreadPic
self.rect = self.image.get_rect()
self.rect.topleft = ( xpos, ypos )
self.eaten = False
def eat( self, ate=True ):
self.eaten = ate
def __str__( self ):
value = "Food at (%d,%d)" % ( self.rect.x, self.rect.y )
if ( self.eaten ):
value += " (eaten)"
return value
FoodList = []
for i in range (10):
FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
class Duck(pygame.sprite.Sprite):
def __init__(self,xpos,ypos,speed,hunger,movement):
super().__init__()
self.image = DuckPic
self.rect = self.image.get_rect()
self.rect.topleft = ( xpos, ypos )
self.speed = speed
self.hunger = hunger
self.movement = movement
def distanceTo( self, bread_sprite ):
""" Calculate the distance from us to a FoodItem """
duck_x, duck_y = self.rect.center
bread_x, bread_y = bread_sprite.rect.center
# ref: https://en.wikipedia.org/wiki/Euclidean_distance
x_part = ( bread_x - duck_x )
y_part = ( bread_y - duck_y )
distance = math.sqrt( ( x_part * x_part ) + ( y_part * y_part ) )
return distance
def __str__( self ):
return "Duck at (%d,%d)" % ( self.rect.x, self.rect.y )
Ducks = []
for i in range(1):
Ducks.append(Duck(xpos = random.randint(0, 320), ypos = random.randint(0, 320), speed =(random.randint(1,3)), hunger = 1000, movement = random.randint(1,100)))
###------------ GAME STUFF INSTANCES HAPPENING
while True:
clock.tick(60)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if FoodList == []:
print("ducks ate all the bread")
pygame.quit()
sys.exit()
if Ducks == []:
print("all ducks died")
pygame.quit()
sys.exit()
breadxy = []
for i,Ducky in enumerate(Ducks):
closestlist = [] #reset list of closest breads for all ducks
for bread in FoodList:
# Made a list of breads & their distance
closestlist.append( [ Ducky.distanceTo( bread ), bread ] )
closestlist.sort( key=lambda x : x[0] ) # sort by distance
closest_bread_distance, closest_bread = closestlist[0]
#print(f"I'm moving to bread {closest_bread} with at a distance of {closest_bread_distance}, my postion is {Ducky.rect.x, Ducky.rect.y} all values include = {closestlist}")
if True:
#move duck to closest bread
if Ducky.rect.x < closest_bread.rect.x:
Ducky.rect.x += 1 * Ducky.speed
if Ducky.rect.x > closest_bread.rect.x:
Ducky.rect.x -= 1 * Ducky.speed
if Ducky.rect.y > closest_bread.rect.y:
Ducky.rect.y -= 1 * Ducky.speed
if Ducky.rect.y < closest_bread.rect.y:
Ducky.rect.y += 1 * Ducky.speed
Ducky.hunger = Ducky.hunger - 1*Ducky.speed
#duck hunger goes down, faster duck looses more hunger
if Ducky.hunger < 0: #if duck at 0 hunger he dies :(
del Ducks[i]
#display the bread
#check for collision thorugh seeing if score is good
# we already have the distance to the bread, so just check that
breads_to_add = 0
for distance, bread in closestlist:
if ( distance < 5 ): # pixels
print( "EATING BREAD" )
bread.eat()
breads_to_add += 1
Ducky.hunger += 60
if ( breads_to_add > 0 ):
print( "ATE %d BREADS" % ( breads_to_add ) )
# remove the eaten breads
FoodList = [ b for b in FoodList if ( not b.eaten ) ]
# add some new bread
for i in range( breads_to_add ):
FoodList.append(Food(random.randint(30,600),random.randint(30,600)))
#print(Ducky.hunger)
#make the screen
#display screen then food then ducks
# fill the background
DISPLAY.fill(blue)
# paint the bread
for FoodItem in (FoodList):
DISPLAY.blit(FoodItem.image, (FoodItem.rect.topleft))
# paint the duck
DISPLAY.blit(Ducky.image, (Ducky.rect.topleft))
pygame.display.update()
main()
The issue is with how you defined the collision distance. From your formula (Ducky.xpos - BreadPos[0]) + (Ducky.ypos - BreadPos[1]) > -5, it basically means you want the bread on the upper and left portion of your duck deleted, and consequently all the bread gets crowded at the lower-right portion of the screen.
Because of that issue, a food is randomly generated and blit to screen in 1 frame, but then on the next frame that food is deleted because of your distance formula condition and then another food is randomly generated and blit to screen.
Below is a sample manhattan distance formula. You may also apply pythagorean/euclidian distance formula. Also, if you want to go deeper with pygame, there are built-in collision functions such as colliderect, collidepoint, etc.
for BreadPos in breadxy:
distance = abs(Ducky.xpos - BreadPos[0]) + abs(Ducky.ypos - BreadPos[1])
if distance < 5:
del FoodList[breadxy.index(BreadPos)]
Ducky.hunger += 60
FoodList.append(Food(random.randint(30, 600), random.randint(30, 600)))

Making a main screen in Ursina

I am currently making a game with Ursina and i've been struggling to find a code to make a Main-Starting-Screen to start the game or show controlls.
Here is my game code:
game = Ursina()
ground = Entity(model = "untitled.blend", texture = "Soul Sand.jpg", scale = 400, collider = "mesh")
player = FirstPersonController(model = "player.blend", position = (-6.39844, 148.284, 62.5471),jump_height = 7, jump_duration = 0.5, speed = 10, texture = "Player Texture.jpg", collider = "mesh")
camera.z = None
health_bar = HealthBar(bar_color=color.lime.tint(-.25), roundness=.5, value=100)
def input(key):
if key == "shift":
player.speed = 25
elif key == "control":
player.speed = 10
house = Entity(model = "House.blend", texture = "Tree Texture.jpg", scale = 2, collider = "mesh", position = (0, 146.3, 15))
tree = Entity(model = "Tree.blend", scale = 15, texture = "Tree Texture.jpg", collider = "mesh", position = (15.5488, 140, 55.0674))
game.run()
You could try just displaying a quad model which is a 2d square
Menuback=Entity(model="quad"scale=(10,10))
and just make
Allother entities to .enabled=False
And the menu to true
Create a button
And onclick menuback.enabled =False
And the rest od entities set on true
Here is the ursina docs if u need to look at some stuff
https://www.ursinaengine.org/api_reference.html

Collisions in Visual Python

I'm currently doing a school project that wants 2D pong made in Visual Python. Right now, I've set my current collisions of the 2 paddles at the bottom of the code. When it runs, it decides to go through it and hit the green walls (Which I will change to clear walls later). Even with the paddle no where near the ball, it still detects a "wall" present and bounces off, which I'm pretty sure its creating a massive skinny wall on the x axis where the paddle is, but is stretched vertically. I do not know any other way my teacher taught other than this way. Any help would be greatly appreciated!
from visual import *
# Title Screen
def TitleScreen():
# Display
sceneTest = display(title='Pong', x=0, y=0, width=950,
height=950, center=(5,0,0), background=(1,1,1))
#autoscale
sceneTest.autoscale = False
#Back Wall
wallBack = box(pos = vector(2,0,-2), size=(50,50,0.2), color = color.black)
#Ball
ballPong = box(pos = vector(5,1,0), size=(0.5,0.5,0.01), color = color.white)
#Left Stick
stick1 = box(pos = vector(-6,0,0), size=(0.5, 5, 0.2), color = color.white)
#Right Stick
stick2 = box(pos = vector(16,0,0), size=(0.5, 5, 0.2), color = color.white)
# Title Text
titleScreenText = text(text = "Pong", pos = (5,9, 0), align = "center",
depth = 0.01, height = 1.5, width = 1.5,
color = color.white)
# Start Game
titleScreenText = text(text = "Press E to Start", pos = (-1.5,-8.5, 0),
depth = 0.01, height = 1.5, width = 1.5,
color = color.white)
# Main Loop for starting game
while True:
rate(30)
if sceneTest.kb.keys:
key = sceneTest.kb.getkey()
if key == "e":
sceneTest.delete()
pongGame()
# Main Game Loop
def pongGame():
# Game Display
newDisplay = display(title='Pong', x=0, y=0,width=950,
height=950, center=(5,0,0), background=(1,1,1))
newDisplay.autoscale = False
# BlackWall
wallBack = box(pos = vector(2.5,0,-2), size=(50,50,0.2), color = color.black)
ball2 = box(pos = vector(5,0,0), size=(0.5,0.5,0.5), color = color.white)
# Stick Paddle 1
stick1New = box(pos = vector(-6,0,0), size=(0.5, 5, 0.2), color = color.white)
# Stick Paddle 2
stick2New = box(pos = vector(16,0,0), size=(0.5, 5, 0.2), color = color.white)
#Clear Wall Left Boundary color = color.green) opacity= 0.01
wallClear1 = box(pos=vector(-6.5,0,0), size=(0.2,22,0.3), color = color.green)
#Clear Wall Right Boundary
wallClear2 = box(pos=vector(16.5,0,0), size=(0.2,22,0.3), color = color.green)
# Clear Wall Top Boundary
wallClear3 = box(pos=vector(5,11,0), size=(23,0.2,0.3), color = color.green)
# Clear Bottom Boudary
wallClear4 = box(pos=vector(5,-11,0), size=(23,0.2,0.3), color = color.green)
# Ball Velocity Initial
ball2.velocity = vector(11,0)
deltaT = 0.005
t = 0.0
# Scoreboard
player1Score = 0
player2Score = 0
scoreText = ("{} : {}".format(player1Score, player2Score))
scoreTextDisplay = text(text = scoreText, pos = (5,9, 0), align = "center", depth = 0.1, height = 1.5, width = 1.5, color = color.white)
while True:
# Refresh
rate(100)
# Ball Velocity while Running
t = t + deltaT
ball2.pos = ball2.pos + ball2.velocity*deltaT
##
## # Literal Aimbot
## stick2New.velocity = vector(0,3)
## stick2New.pos = stick2New.pos + stick2New.velocity*deltaT
## stick2New.pos.y = ball2.pos.y
##
# Player 1 Input/Controls
if newDisplay.kb.keys:
keyNew = newDisplay.kb.getkey()
# Moving Up
if keyNew == "w":
stick1New.pos.y = stick1New.pos.y + 0.25
# Moving Down
if keyNew == "s":
stick1New.pos.y = stick1New.pos.y - 0.25
# If ball hits Right wall
if ball2.pos.x > wallClear2.pos.x:
ball2.velocity.x = ball2.velocity.x
player1Score = player1Score + 1
ball2.pos = (5,0,0)
# If ball hits Left wall
if ball2.pos.x < wallClear1.pos.x:
ball2.velocity.x = ball2.velocity.x
player2Score = player2Score + 1
ball2.pos = (5,0,0)
# If the Ball hits the top of the Wall
if ball2.pos.y > wallClear3.pos.y:
ball2.velocity.y = -ball2.velocity.y
# If the Ball hits the bottom of the Wall
if ball2.pos.y < wallClear4.pos.y:
ball2.velocity.y = -ball2.velocity.y
# Collisions Check OLD
# if ball hits right paddle
## if ball2.pos.x < stick2New.pos.x: #or ball2.pos.x > stick2New.pos.x:
## ball2.velocity.x = -ball2.velocity.x
## if ball2.pos.x > (stick2New.pos.x == -6) or ball2.pos.x < (stick2New.pos.x > -6):
## ball2.velocity.x = -ball2.velocity.x
# if ball hits left paddle
if ball2.pos.x < stick1New.pos.x:
ball2.velocity.x = -ball2.velocity.x
if ball2.pos.x > stick2New.pos.x:
ball2.velocity.x = -ball2.velocity.x
TitleScreen()
You do not have any code to check the y coordinate of the ball when checking collisions with the paddles. This will make the paddles appear infinitely tall. You can incorporate some code like if (ball2.pos.x < stick1New.pos.x) and abs(ball2.pos.y-stick1New.pos.y) < 2.5: ball2.velocity.x*=-1; ball2.velocity.y *=-1;

Problem with animating a sprite in pygame

i have a problem with this code, i am a new person with programming and been using the book "how to think like a computer scientist 3rd edition" and he did not solve exercise 2 of chapter 17 this given: "he deliberately left a mistake in the code to animate Duke. If you click on one of the checkerboard squares to the right of Duke, he salutes anyway. Why? Find a one-line solution to the error ", I've tried many forms but I have not succeeded, I leave you all the code and the images that I have used
PS: images must have the name: ball.png and duke_spritesheet.png
import pygame
gravity = 0.025
my_clock = pygame.time.Clock()
class QueenSprite:
def __init__(self, img, target_posn):
self.image = img
self.target_posn = target_posn
(x, y) = target_posn
self.posn = (x, 0) # Start ball at top of its column
self.y_velocity = 0 # with zero initial velocity
def update(self):
self.y_velocity += gravity
(x, y) = self.posn
new_y_pos = y + self.y_velocity
(target_x, target_y) = self.target_posn # Unpack the position
dist_to_go = target_y - new_y_pos # How far to our floor?
if dist_to_go < 0: # Are we under floor?
self.y_velocity = -0.65 * self.y_velocity # Bounce
new_y_pos = target_y + dist_to_go # Move back above floor
self.posn = (x, new_y_pos) # Set our new position.
def draw(self, target_surface): # Same as before.
target_surface.blit(self.image, self.posn)
def contains_point(self, pt):
""" Return True if my sprite rectangle contains point pt """
(my_x, my_y) = self.posn
my_width = self.image.get_width()
my_height = self.image.get_height()
(x, y) = pt
return ( x >= my_x and x < my_x + my_width and
y >= my_y and y < my_y + my_height)
def handle_click(self):
self.y_velocity += -2 # Kick it up
class DukeSprite:
def __init__(self, img, target_posn):
self.image = img
self.posn = target_posn
self.anim_frame_count = 0
self.curr_patch_num = 0
def update(self):
if self.anim_frame_count > 0:
self.anim_frame_count = (self.anim_frame_count + 1 ) % 60
self.curr_patch_num = self.anim_frame_count // 6
def draw(self, target_surface):
patch_rect = (self.curr_patch_num * 50, 0,
50, self.image.get_width())
target_surface.blit(self.image, self.posn, patch_rect)
def contains_point(self, pt):
""" Return True if my sprite rectangle contains pt """
(my_x, my_y) = self.posn
my_width = self.image.get_width()
my_height = self.image.get_height()
(x, y) = pt
return ( x >= my_x and x < my_x + my_width and
y >= my_y and y < my_y + my_height)
def handle_click(self):
if self.anim_frame_count == 0:
self.anim_frame_count = 5
def draw_board(the_board):
""" Draw a chess board with queens, as determined by the the_board. """
pygame.init()
colors = [(255,0,0), (0,0,0)] # Set up colors [red, black]
n = len(the_board) # This is an NxN chess board.
surface_sz = 480 # Proposed physical surface size.
sq_sz = surface_sz // n # sq_sz is length of a square.
surface_sz = n * sq_sz # Adjust to exactly fit n squares.
# Create the surface of (width, height), and its window.
surface = pygame.display.set_mode((surface_sz, surface_sz))
ball = pygame.image.load("ball.png")
# Use an extra offset to centre the ball in its square.
# If the square is too small, offset becomes negative,
# but it will still be centered :-)
ball_offset = (sq_sz-ball.get_width()) // 2
all_sprites = [] # Keep a list of all sprites in the game
# Create a sprite object for each queen, and populate our list.
for (col, row) in enumerate(the_board):
a_queen = QueenSprite(ball,
(col*sq_sz+ball_offset, row*sq_sz+ball_offset))
all_sprites.append(a_queen)
# Load the sprite sheet
duke_sprite_sheet = pygame.image.load("duke_spritesheet.png")
# Instantiate two duke instances, put them on the chessboard
duke1 = DukeSprite(duke_sprite_sheet,(sq_sz*2, 0))
duke2 = DukeSprite(duke_sprite_sheet,(sq_sz*5, sq_sz))
# Add them to the list of sprites which our game loop manages
all_sprites.append(duke1)
all_sprites.append(duke2)
while True:
# Look for an event from keyboard, mouse, etc.
ev = pygame.event.poll()
if ev.type == pygame.QUIT:
break;
if ev.type == pygame.KEYDOWN:
key = ev.dict["key"]
if key == 27: # On Escape key ...
break # leave the game loop.
if key == ord("r"):
colors[0] = (255, 0, 0) # Change to red + black.
elif key == ord("g"):
colors[0] = (0, 255, 0) # Change to green + black.
elif key == ord("b"):
colors[0] = (0, 0, 255) # Change to blue + black.
if ev.type == pygame.MOUSEBUTTONDOWN: # Mouse gone down?
posn_of_click = ev.dict["pos"] # Get the coordinates.
for sprite in all_sprites:
if sprite.contains_point(posn_of_click):
sprite.handle_click()
break
for sprite in all_sprites:
sprite.update()
# Draw a fresh background (a blank chess board)
for row in range(n): # Draw each row of the board.
c_indx = row % 2 # Alternate starting color
for col in range(n): # Run through cols drawing squares
the_square = (col*sq_sz, row*sq_sz, sq_sz, sq_sz)
surface.fill(colors[c_indx], the_square)
# Now flip the color index for the next square
c_indx = (c_indx + 1) % 2
# Ask every sprite to draw itself.
for sprite in all_sprites:
sprite.draw(surface)
my_clock.tick(60) # Waste time so that frame rate becomes 60 fps
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
draw_board([0, 5, 3, 1, 6, 4, 2]) # 7 x 7 to test window size
PS: I think the error is here but it did not succeed
return ( x >= my_x and x + my_width and y >= my_y and y < my_y + my_height)
The issue is caused by the face, that "duke_spritesheet.png" is a sprite sheet. When you define the rectangular region which is covered by the object, then you have to use the width of a single image, rather than the width of the entire sprite sheet:
my_width = self.image.get_width()
my_width = 50
Change this in the method contains_point of the class DukeSprite:
class DukeSprite:
# [...]
def contains_point(self, pt):
""" Return True if my sprite rectangle contains pt """
(my_x, my_y) = self.posn
my_width = 50
my_height = self.image.get_height()
(x, y) = pt
return ( x >= my_x and x < my_x + my_width and
y >= my_y and y < my_y + my_height)

Categories

Resources