Create screen scroll with Pythonista + scene

This time, I created a 2D action scrolling process with Pythonista + scene.

Program overview

Scroll the screen when the character moves. When you move to the edge of the screen, stop scrolling so that you can move freely.

Implemented processing

The implemented processing is the following two. ・ Screen scroll ・ Screen edge processing

Screen scroll

It is a process to scroll the screen when the character moves. While scrolling, the character's position remains the same, and scrolling is expressed by moving the background and items in the opposite direction of the character's movement.

Pythonista_scroll.png

The code is as follows. Add to the update () method.

python



def update(self):
	g = gravity()
	x = self.player.position.x
	y = self.player.position.y
	#Left and right movement
	if abs(g.x) > 0.05:
		max_speed = 40
		self.update_position(max_speed)
	else:
		self.player.texture = standing_texture
		self.walk_step = -1
		
def update_position(self, max_speed):
	g = gravity()
	x = self.player.position.x
	y = self.player.position.y
	distance = g.x * max_speed 
		
	x = self.size.w/2
	self.player.position = (x, y)
	for t in self.tiles:
		t['tile1'].position = (t['tile1'].position.x - distance, t['tile1'].position.y)
		t['tile2'].position = (t['tile2'].position.x - distance, t['tile2'].position.y)
	for item in self.items:
		item.position = (item.position.x - distance, item.position.y)
	for item in self.stars:
		item.position = (item.position.x - distance, item.position.y)
	for item in self.mushrooms:
		item.position = (item.position.x - distance, item.position.y)

Screen edge processing

If you do not prepare a border, the character will move endlessly to a position without a background, so a border is required at the edge of the screen.

When you reach the edge of the screen, stop scrolling and switch to moving the character. Scroll again when you move away from the edge of the screen.

The code is as follows. Judge "whether the character is at the edge of the screen" and if it is at the edge, interrupt scrolling and switch to moving the character.

python



def update(self):
	g = gravity()
	x = self.player.position.x
	y = self.player.position.y
	#Left and right movement
	if abs(g.x) > 0.05:
		max_speed = 40
		self.update_position(max_speed)
	else:
		self.player.texture = standing_texture
		self.walk_step = -1
		
def update_position(self, max_speed):
	g = gravity()
	x = self.player.position.x
	y = self.player.position.y
	distance = g.x * max_speed 
#Add from here--------------------------------------------------------------------------
	self.move_count = max(0, min(self.move_count + distance, self.stage_size))
	if self.move_count < self.size.w/2 or self.move_count >= self.stage_size - self.size.w/2:
		self.player.x_scale = cmp(g.x, 0)
		step = int(self.player.position.x / 40) % 2
		if step != self.walk_step:
			self.player.texture = walk_textures[step]
			self.walk_step = step
		#Left and right movement
		x = max(0, min(self.size.w, x + distance))
		self.player.position = (x, y)
	else:
#Add up to here--------------------------------------------------------------------------
		x = self.size.w/2
		self.player.position = (x, y)
		for t in self.tiles:
			t['tile1'].position = (t['tile1'].position.x - distance, t['tile1'].position.y)
			t['tile2'].position = (t['tile2'].position.x - distance, t['tile2'].position.y)
		for item in self.items:
			item.position = (item.position.x - distance, item.position.y)
		for item in self.stars:
			item.position = (item.position.x - distance, item.position.y)
		for item in self.mushrooms:
			item.position = (item.position.x - distance, item.position.y)

Task

  1. Jumping at the edge of the screen may warp to the center of the screen.
  2. The walking animation stops because the scrolling character is not treated as moving.

Full code

I will omit the explanation of the processing that is not related to scrolling.

python



# coding: utf-8

from scene import *
from sound import *

def cmp(a, b):
	return ((b > a) - (b < a))
	
	
standing_texture = Texture('emj:Ghost')
walk_textures = [Texture('emj:Ghost'), Texture('emj:Ghost')]

class Game (Scene):
	def setup(self):
		#Background settings
		self.background_color = '#004f82'
		ground = Node(parent=self)
		x = 0
		#Ground height
		self.base_height = 50
		self.stage_size = self.size.w * 5
		#Background settings
		self.tiles = []
		while x <= self.stage_size + 128:
			tile1 = SpriteNode('plf:Ground_GrassHalf_mid', position=(x - 50, self.base_height))
			ground.add_child(tile1)
			
			tile2 = SpriteNode('plf:Ground_GrassCenter', position=(x - 50, self.base_height-32))
			ground.add_child(tile2)
			x += 64
			self.tiles.append(
				{
					'tile1' : tile1,
					'tile2' : tile2
				}
			)
			
		#Player initial settings
		self.player_height = self.base_height + 32
		self.player = SpriteNode('emj:Ghost')
		self.player.anchor_point = (0.5, 0)
		self.player.position = (self.size.w/2, self.player_height)
		self.add_child(self.player)
		#Jump button initial settings
		self.jump = 'ready'
		self.jump_button = SpriteNode('emj:Blue_Circle', position=(320,50))
		self.add_child(self.jump_button)
		#Initial setting of attack button
		self.attack_button = SpriteNode('emj:Blue_Circle', position=(250,50), color='red')
		self.add_child(self.attack_button)
		
		self.bullet = SpriteNode('shp:sun')
		self.bullet.position = -1000, -1000
		self.add_child(self.bullet)
		
		mushroom = SpriteNode('emj:Mushroom')
		mushroom.anchor_point = (0.5, 0)
		mushroom.position = (self.size.w * 3, self.player_height)
		self.add_child(mushroom)
		self.mushrooms = [mushroom]
		
		star = SpriteNode('plc:Star')
		star.anchor_point = (0.5, 0)
		star.position = (self.size.w + self.size.w/2, self.player_height + 300)
		self.add_child(star)
		self.stars = [star]
		
		self.items = []
		for i in range(0, 5):
			for j in range(0,2):
				item = SpriteNode('plf:HudCoin')
				item.anchor_point = (0.5, 0)
				item.position = (self.size.w + 80 + i * 50, self.player_height + 100 + 60 * j)
				self.add_child(item)
				self.items.append(item)
		self.charge = False
		self.power = 0
		self.disp_lock = False
		self.move_count = self.size.w/2
		
		score_font = ('Futura', 40)
		self.score_label = LabelNode('0', score_font, parent=self)
		# The label is centered horizontally near the top of the screen:
		self.score_label.position = (self.size.w/2, self.size.h - 70)
		# The score should appear on top of everything else, so we set the `z_position` attribute here. The default `z_position` is 0.0, so using 1.0 is enough to make it appear on top of the other objects.
		self.score_label.z_position = 1
		self.score = 0
		self.walk_step = -1
		
		
	def update(self):
		g = gravity()
		x = self.player.position.x
		y = self.player.position.y
		#Left and right movement
		if abs(g.x) > 0.05:
			max_speed = 40
			self.update_position(max_speed)
		else:
			self.player.texture = standing_texture
			self.walk_step = -1
		self.check_jump(x,y)
		if self.charge and self.power < 100:
			self.power += 1
			
		for item in self.mushrooms:
			item.position = (item.position.x -1, item.position.y)
		#collision detection
		self.check_item_hit(self.mushrooms, score=500)
		self.check_item_hit(self.items)
		self.check_item_hit(self.stars, score=1500)
		
		
	def update_position(self, max_speed):
		g = gravity()
		x = self.player.position.x
		y = self.player.position.y
		distance = g.x * max_speed 
		
		self.move_count = max(0, min(self.move_count + distance, self.stage_size))
		if self.move_count < self.size.w/2 or self.move_count >= self.stage_size - self.size.w/2:
			self.player.x_scale = cmp(g.x, 0)
			step = int(self.player.position.x / 40) % 2
			if step != self.walk_step:
				self.player.texture = walk_textures[step]
				self.walk_step = step
			#Left and right movement
			x = max(0, min(self.size.w, x + distance))
			self.player.position = (x, y)
		else:
			x = self.size.w/2
			self.player.position = (x, y)
			for t in self.tiles:
				t['tile1'].position = (t['tile1'].position.x - distance, t['tile1'].position.y)
				t['tile2'].position = (t['tile2'].position.x - distance, t['tile2'].position.y)
			for item in self.items:
				item.position = (item.position.x - distance, item.position.y)
			for item in self.stars:
				item.position = (item.position.x - distance, item.position.y)
			for item in self.mushrooms:
				item.position = (item.position.x - distance, item.position.y)
		
	def touch_began(self, touch):
		self.power = 0
		self.charge = True
		
	def touch_ended(self, touch):
		#Get the tapped position
		touch_loc = self.point_from_scene(touch.location)
		#Jump if the tapped position is a button
		if touch_loc in self.jump_button.frame:
			if self.jump == 'ready':
				play_effect('game:Boing_1')
				self.jump = 'up'
		if touch_loc in self.attack_button.frame:
			if self.jump == 'ready':
				x, y = self.player.position
				self.bullet.position = x, y + 50
				move = Action.move_to(x, self.player_height +1000, 0.5 ,TIMING_LINEAR)
				self.bullet.run_action(move)
				
	def check_jump(self, x, y):
		#Processing when ascending
		if self.jump == 'up':
			max_height = 180 + self.power
			up_speed = 10
			y = max(self.player_height, min(self.size.h, y + up_speed))
			self.player.position = (x, y)
			if y > max_height + self.player_height:
				self.jump = 'down'
				
		#Processing when falling
		if self.jump == 'down':
			down_speed = 10
			y = max(self.player_height, min(self.size.h, y - down_speed))
			self.player.position = (x, y)
			if y == self.player_height:
				self.jump = 'ready'
				self.charge = False
				
				
	#collision detection
	def check_item_hit(self, items, score=100):
		#If it matches vertically and horizontally, add the score and delete the item
		for item in items:
			if abs(self.player.position.x - item.position.x) < 30 and abs(self.player.position.y - item.position.y) < 30:
				item.remove_from_parent()
				self.score += score
				items.remove(item)
				self.score_label.text = str(self.score)
			if abs(self.bullet.position.x - item.position.x) < 30 and abs(self.bullet.position.y - item.position.y) < 30:
				item.remove_from_parent()
				self.score += score
				items.remove(item)
				self.score_label.text = str(self.score)
				
if __name__ == '__main__':
	run(Game(), PORTRAIT, show_fps=True)

Execution example (gif animation)

How to use Pythonista is also summarized in the blog. Actions other than scrolling the above code are explained on the blog. Summary of how to use Pythonista

Recommended Posts

Create screen scroll with Pythonista + scene
Create an update screen with Django Updateview
Play with Pythonista UI implementation [Screen elements]
Create games with Pygame
Create filter with scipy
[Python] Create a file & folder path specification screen with tkinter
[Python] Create a screen for HTTP status code 403/404/500 with Django
Create an environment with virtualenv
Create Cloud TPU with tf-nightly
Create an API with Django
Create / search / create table with PynamoDB
Create 3d gif with python3
Create graph with plotly button
Create a homepage with django
Screen switching / screen transition with Tkinter
Create Image Viewer with Tkinter
Bidirectional file transfer with Pythonista 3
Create custom rules with ElastAlert
Create patent map with Streamlit
Create a Django login screen
Create a heatmap with pyqtgraph
Create a directory with python
Create xlsx file with XlsxWriter
Split screen into 3 with keyhac